@posthog/wizard 2.32.0 → 2.33.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-Dc0yssCM.js → add-mcp-server-to-clients-Dhq75Hda.js} +5 -5
- package/dist/{add-mcp-server-to-clients-Dc0yssCM.js.map → add-mcp-server-to-clients-Dhq75Hda.js.map} +1 -1
- package/dist/{agent-interface-c7B2JZEd.js → agent-interface-DCeQ5Oiw.js} +6 -6
- package/dist/{agent-interface-c7B2JZEd.js.map → agent-interface-DCeQ5Oiw.js.map} +1 -1
- package/dist/{agent-runner-Am34bBUT.js → agent-runner-BRajaO84.js} +10 -9
- package/dist/{agent-runner-Am34bBUT.js.map → agent-runner-BRajaO84.js.map} +1 -1
- package/dist/{analytics-CBIKy9PZ.js → analytics-CU4o3eF8.js} +3 -3
- package/dist/analytics-CU4o3eF8.js.map +1 -0
- package/dist/{api-Blg3nvvZ.js → api-BBRfHEZ-.js} +3 -3
- package/dist/{api-Blg3nvvZ.js.map → api-BBRfHEZ-.js.map} +1 -1
- package/dist/bin.js +203 -75
- package/dist/bin.js.map +1 -1
- package/dist/ci-install-D-otkGW6.js +113 -0
- package/dist/ci-install-D-otkGW6.js.map +1 -0
- package/dist/{debug-AdvgwKEw.js → debug-BGMe1wP6.js} +2 -2
- package/dist/{debug-AdvgwKEw.js.map → debug-BGMe1wP6.js.map} +1 -1
- package/dist/{debug-cy_jyRb4.js → debug-BewTLNNr.js} +1 -1
- package/dist/{defaults-BNWIWzjc.js → defaults-DII5CAog.js} +1 -1
- package/dist/{defaults-BNWIWzjc.js.map → defaults-DII5CAog.js.map} +1 -1
- package/dist/{environment-B6TW5v9d.js → environment-G41UFzou.js} +3 -3
- package/dist/{environment-B6TW5v9d.js.map → environment-G41UFzou.js.map} +1 -1
- package/dist/{file-utils-8tUk_eEX.js → file-utils-D9InAvZd.js} +2 -2
- package/dist/{file-utils-8tUk_eEX.js.map → file-utils-D9InAvZd.js.map} +1 -1
- package/dist/headless-ui-xjHVVUqe.js +24 -0
- package/dist/headless-ui-xjHVVUqe.js.map +1 -0
- package/dist/{interactive-CApktTrj.js → interactive-D2CKikzz.js} +3 -3
- package/dist/{interactive-CApktTrj.js.map → interactive-D2CKikzz.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-BKcU9yuz.js → mcp-prompt-streaming-FrArGwfv.js} +4 -4
- package/dist/{mcp-prompt-streaming-BKcU9yuz.js.map → mcp-prompt-streaming-FrArGwfv.js.map} +1 -1
- package/dist/{non-interactive-DejTdRTW.js → non-interactive-BXx6Q-D0.js} +2 -2
- package/dist/{non-interactive-DejTdRTW.js.map → non-interactive-BXx6Q-D0.js.map} +1 -1
- package/dist/{package-manager-DBfgSXNn.js → package-manager-D9ojA4jO.js} +2 -2
- package/dist/{package-manager-DBfgSXNn.js.map → package-manager-D9ojA4jO.js.map} +1 -1
- package/dist/{playground-BOg2U1AT.js → playground-Bgtxrusl.js} +7 -5
- package/dist/{playground-BOg2U1AT.js.map → playground-Bgtxrusl.js.map} +1 -1
- package/dist/{posthog-Cr37rnla.js → posthog-DU6JXG00.js} +1 -1
- package/dist/{posthog-Cr37rnla.js.map → posthog-DU6JXG00.js.map} +1 -1
- package/dist/{posthog-integration-gLhOUdPJ.js → posthog-integration-gnC9v4kg.js} +13 -13
- package/dist/{posthog-integration-gLhOUdPJ.js.map → posthog-integration-gnC9v4kg.js.map} +1 -1
- package/dist/{provisioning-DuzclqPB.js → provisioning-C3qglLdc.js} +3 -3
- package/dist/{provisioning-DuzclqPB.js.map → provisioning-C3qglLdc.js.map} +1 -1
- package/dist/{registry-Dbl-5SnO.js → registry-BVrvFTZ0.js} +4 -4
- package/dist/{registry-Dbl-5SnO.js.map → registry-BVrvFTZ0.js.map} +1 -1
- package/dist/{setup-utils-B6wbp3s0.js → setup-utils-CanVlGbX.js} +8 -8
- package/dist/{setup-utils-B6wbp3s0.js.map → setup-utils-CanVlGbX.js.map} +1 -1
- package/dist/smoke-test.sh +25 -0
- package/dist/{start-tui-IoQh-Nhj.js → start-tui-YE7bybIr.js} +17 -16
- package/dist/{start-tui-IoQh-Nhj.js.map → start-tui-YE7bybIr.js.map} +1 -1
- package/dist/{steps-CJrqlHbo.js → steps-N20e4IoE.js} +7 -7
- package/dist/{steps-CJrqlHbo.js.map → steps-N20e4IoE.js.map} +1 -1
- package/dist/store-D15C9YSW.js +763 -0
- package/dist/store-D15C9YSW.js.map +1 -0
- package/dist/{task-stream-BQNSp0qR.js → task-stream-CPjpHFhI.js} +4 -4
- package/dist/{task-stream-BQNSp0qR.js.map → task-stream-CPjpHFhI.js.map} +1 -1
- package/dist/{telemetry-1m0CyTry.js → telemetry-DknCDWP6.js} +3 -3
- package/dist/{telemetry-1m0CyTry.js.map → telemetry-DknCDWP6.js.map} +1 -1
- package/dist/{terminal-BKI4i72f.js → terminal-Cvv0a-7Q.js} +14 -764
- package/dist/terminal-Cvv0a-7Q.js.map +1 -0
- package/dist/{urls-B3JumpLT.js → urls-DrR6F_A3.js} +2 -2
- package/dist/{urls-B3JumpLT.js.map → urls-DrR6F_A3.js.map} +1 -1
- package/dist/{wizard-abort-PqLMKSh1.js → wizard-abort-Cw818xPr.js} +4 -3
- package/dist/{wizard-abort-PqLMKSh1.js.map → wizard-abort-Cw818xPr.js.map} +1 -1
- package/dist/{wizard-abort-D7SzKUgE.js → wizard-abort-DMvS0YXD.js} +1 -1
- package/dist/wizard-session-BKEdX9mO.js +2 -0
- package/dist/{wizard-session-G3VWD6hv.js → wizard-session-CN55LYyZ.js} +9 -2
- package/dist/{wizard-session-G3VWD6hv.js.map → wizard-session-CN55LYyZ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/analytics-CBIKy9PZ.js.map +0 -1
- package/dist/ci-install-51ntd9x5.js +0 -73
- package/dist/ci-install-51ntd9x5.js.map +0 -1
- package/dist/terminal-BKI4i72f.js.map +0 -1
- package/dist/wizard-session-wPJtNl4c.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-Cvv0a-7Q.js","names":["CHROME_ROWS","fs","copyData.pinnedFirstPrompt","copyData.defaultKit","copyData.roleKits","copyData.roleFamilyOverrides","copyData.roleGreetings","copyData.neutralGreeting","copyData.toolFollowUps","copyData.roleFollowUps","copyData.genericFollowUps","copyData.deepDiveFollowUps","copyData.crossSellByRole","copyData.neutralCrossSell","copyData.slackApp"],"sources":["../src/ui/tui/primitives/CardLayout.tsx","../src/ui/tui/primitives/SplitView.tsx","../src/ui/tui/primitives/LoadingBox.tsx","../src/ui/tui/primitives/ProgressList.tsx","../src/ui/tui/hooks/useStdoutDimensions.ts","../src/ui/tui/primitives/GroupedPickerMenu.tsx","../src/ui/tui/primitives/ConfirmationInput.tsx","../src/ui/tui/primitives/Divider.tsx","../src/ui/tui/primitives/ModalOverlay.tsx","../src/ui/tui/primitives/link-helpers.ts","../src/ui/tui/primitives/LinkText.tsx","../src/ui/tui/primitives/LogViewer.tsx","../src/ui/tui/primitives/EventPlanViewer.tsx","../src/ui/tui/components/TitleBar.tsx","../src/ui/tui/primitives/DissolveTransition.tsx","../src/ui/tui/primitives/KeyboardHintsBar.tsx","../src/ui/tui/primitives/ScreenErrorBoundary.tsx","../src/ui/tui/primitives/ScreenContainer.tsx","../src/ui/tui/primitives/TabContainer.tsx","../src/ui/tui/primitives/HNViewer.tsx","../src/ui/tui/primitives/LinesBlock.tsx","../src/ui/tui/primitives/NodeBlock.tsx","../src/ui/tui/primitives/ContentSequencer.tsx","../src/ui/tui/components/LearnCard.tsx","../src/ui/tui/components/TipsCard.tsx","../src/ui/tui/hooks/useTick.ts","../src/ui/tui/components/visualizer/palette.ts","../src/ui/tui/components/visualizer/panel.tsx","../src/ui/tui/components/visualizer/MatrixRain.tsx","../src/ui/tui/components/visualizer/LibraryShelf.tsx","../src/ui/tui/components/visualizer/CrateStack.tsx","../src/ui/tui/components/visualizer/DiffCascade.tsx","../src/ui/tui/components/visualizer/Tumblers.tsx","../src/ui/tui/components/visualizer/DashboardGrid.tsx","../src/ui/tui/components/PhaseVisuals.tsx","../src/ui/tui/components/ServiceHealthList.tsx","../src/ui/tui/screens/doctor/IssueTable.tsx","../src/ui/tui/screens/McpScreen.tsx","../src/lib/mcp-role-prompts.copy.json","../src/lib/mcp-role-prompts.ts","../src/ui/tui/screens/McpSuggestedPromptsScreen.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/layout.ts","../src/ui/tui/screens/audit/AuditChecksViewer/CheckRow.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/DetailRow.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/Legend.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/Header.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/Footer.tsx","../src/ui/tui/screens/audit/AuditChecksViewer/sort.ts","../src/ui/tui/screens/audit/AuditChecksViewer/AuditChecksViewer.tsx","../src/ui/tui/screens/audit/slides/shared.tsx","../src/ui/tui/screens/audit/slides/installation.tsx","../src/ui/tui/screens/audit/slides/identification.tsx","../src/ui/tui/screens/audit/slides/eventCapture.tsx","../src/ui/tui/screens/audit/slides/writeReport.tsx","../src/ui/tui/screens/audit/slides/uploadNotebook.tsx","../src/ui/tui/screens/audit/slides/index.ts","../src/ui/tui/screens/SlackConnectScreen.tsx","../src/ui/tui/screens/OutroScreen.tsx","../src/ui/tui/screens/SkillSourceInfo.tsx","../src/ui/tui/screens/AiOptInRequiredScreen.tsx","../src/ui/tui/terminal.ts"],"sourcesContent":["/**\n * CardLayout — Aligns a single child within available space.\n */\n\nimport { Box } from 'ink';\nimport type { ReactNode } from 'react';\nimport { HAlign, VAlign } from '@ui/tui/styles';\n\ninterface CardLayoutProps {\n hAlign?: HAlign;\n vAlign?: VAlign;\n children: ReactNode;\n}\n\nexport const CardLayout = ({\n hAlign = HAlign.Left,\n vAlign = VAlign.Top,\n children,\n}: CardLayoutProps) => {\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n justifyContent={vAlign}\n alignItems={hAlign}\n >\n {children}\n </Box>\n );\n};\n","/**\n * SplitView — Two-pane horizontal layout: 50/50.\n */\n\nimport { Box } from 'ink';\nimport type { ReactNode } from 'react';\n\ninterface SplitViewProps {\n left: ReactNode;\n right: ReactNode;\n gap?: number;\n}\n\nexport const SplitView = ({ left, right, gap = 2 }: SplitViewProps) => {\n return (\n <Box flexDirection=\"row\" flexGrow={1} flexShrink={1} gap={gap}>\n <Box width=\"50%\" flexDirection=\"column\" overflow=\"hidden\">\n {left}\n </Box>\n <Box width=\"50%\" flexDirection=\"column\" overflow=\"hidden\">\n {right}\n </Box>\n </Box>\n );\n};\n","/**\n * LoadingBox — Spinner with message.\n */\n\nimport { Box, Text } from 'ink';\nimport { Spinner } from '@inkjs/ui';\n\ninterface LoadingBoxProps {\n message: string;\n}\n\nexport const LoadingBox = ({ message }: LoadingBoxProps) => {\n return (\n <Box gap={1}>\n <Spinner />\n <Text>{message}</Text>\n </Box>\n );\n};\n","/**\n * ProgressList — Reusable task checklist with status icons.\n * Extracted from StatusTab logic.\n */\n\nimport { Box, Text } from 'ink';\nimport { Spinner } from '@inkjs/ui';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport { LoadingBox } from './LoadingBox.js';\n\nexport interface ProgressItem {\n label: string;\n activeForm?: string;\n status: 'pending' | 'in_progress' | 'completed' | 'skipped';\n}\n\ninterface ProgressListProps {\n items: ProgressItem[];\n title?: string;\n}\n\nexport const ProgressList = ({ items, title }: ProgressListProps) => {\n const resolved = items.filter(\n (t) => t.status === 'completed' || t.status === 'skipped',\n ).length;\n const total = items.length;\n\n return (\n <Box flexDirection=\"column\">\n {title && (\n <>\n <Text bold>{title}</Text>\n <Text> </Text>\n </>\n )}\n {items.length === 0 && <LoadingBox message=\"Analyzing project...\" />}\n {items.map((item, i) => {\n const skipped = item.status === 'skipped';\n const icon =\n item.status === 'completed'\n ? Icons.squareFilled\n : item.status === 'in_progress'\n ? Icons.triangleRight\n : Icons.squareOpen;\n const color =\n item.status === 'completed'\n ? Colors.success\n : item.status === 'in_progress'\n ? Colors.primary\n : Colors.muted;\n const label = skipped\n ? `${item.label} (skipped)`\n : item.status === 'in_progress' && item.activeForm\n ? item.activeForm\n : item.label;\n\n return (\n <Text key={i}>\n <Text color={color}>{icon}</Text>\n <Text\n dimColor={item.status === 'pending' || skipped}\n strikethrough={skipped}\n >\n {' '}\n {label}\n </Text>\n </Text>\n );\n })}\n {total > 0 && (\n <Box marginTop={1} gap={1}>\n <Spinner />\n <Text dimColor>\n {resolved < total\n ? `Progress: ${resolved}/${total} completed`\n : 'Cleaning up...'}\n </Text>\n </Box>\n )}\n </Box>\n );\n};\n","/**\n * useStdoutDimensions — Returns [columns, rows] and re-renders on terminal resize.\n *\n * Ink's useStdout() does not subscribe to resize events, so layout only updates\n * when something else causes a re-render. This hook listens to the stream's\n * 'resize' event (Node TTY) and updates state so the component re-renders\n * with the new dimensions.\n */\n\nimport { useStdout } from 'ink';\nimport { useState, useEffect } from 'react';\n\nexport function useStdoutDimensions(): [number, number] {\n const { stdout } = useStdout();\n const [size, setSize] = useState<[number, number]>(() => [\n stdout.columns || 80,\n stdout.rows || 24,\n ]);\n\n useEffect(() => {\n const cols = stdout.columns || 80;\n const rows = stdout.rows || 24;\n setSize([cols, rows]);\n\n const stream = stdout as NodeJS.WriteStream & {\n on?(event: string, fn: () => void): void;\n };\n if (typeof stream.on !== 'function') return;\n\n const onResize = () => {\n const c = stdout.columns || 80;\n const r = stdout.rows || 24;\n if (c > 0 && r > 0) setSize([c, r]);\n };\n stream.on('resize', onResize);\n return () => {\n stream.off?.('resize', onResize);\n };\n }, [stdout]);\n\n return size;\n}\n","/**\n * GroupedPickerMenu — Multi-select with category headers.\n *\n * Renders groups of options with bold category labels.\n * Arrow keys navigate selectable items (headers are skipped) and the Confirm\n * button below them; enter toggles the focused option, \"a\" toggles all, and\n * moving onto the Confirm button and pressing enter submits. Space is kept as\n * an undocumented alias for enter. Shares the interaction model with\n * PickerMenu mode=\"multi\".\n *\n * When content exceeds available terminal height, the list scrolls\n * to keep the focused item visible with up/down indicators.\n *\n * Key bindings are declared via useKeyBindings, which auto-registers\n * hints in the KeyboardHintsBar.\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useMemo } from 'react';\nimport { Icons, Colors } from '@ui/tui/styles';\nimport { PromptLabel } from './PromptLabel.js';\nimport { ConfirmButton } from './ConfirmButton.js';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\nimport { useKeyBindings, KeyMatch } from '@ui/tui/hooks/useKeyBindings';\n\ninterface GroupOption {\n value: string;\n label: string;\n hint?: string;\n}\n\ninterface GroupedPickerMenuProps {\n message?: string;\n groups: Record<string, GroupOption[]>;\n initialSelected?: string[];\n onSelect: (values: string[]) => void;\n}\n\ntype Row =\n | { kind: 'header'; label: string }\n | { kind: 'option'; value: string; label: string; hint?: string };\n\n/** Truncate text with \"\\u2026\" if it exceeds maxWidth. */\nfunction truncateWithEllipsis(text: string, maxWidth: number): string {\n if (text.length <= maxWidth) return text;\n return text.slice(0, maxWidth - 1) + '\\u2026';\n}\n\n/** Rows consumed by chrome outside this component (title bar, screen padding, etc.) */\nconst CHROME_OVERHEAD = 10;\n/**\n * Rows used by the prompt label + marginTop before content (hint text moved to\n * KeyboardHintsBar) plus the Confirm button below the list: marginTop (1) +\n * single border top/bottom (2) + button text (1).\n */\nconst MENU_CHROME = 6;\n\n/** Count the visual rows occupied by rows[start..end), accounting for header margins. */\nfunction countVisualRows(rows: Row[], start: number, end: number): number {\n let count = 0;\n for (let i = start; i < end && i < rows.length; i++) {\n if (rows[i].kind === 'header' && i > start) count += 1; // marginTop gap\n count += 1;\n }\n return count;\n}\n\n/** From scrollOffset, find how many flat rows fit in the visual budget. */\nfunction computeVisibleEnd(\n rows: Row[],\n scrollOffset: number,\n budget: number,\n): number {\n let visualCount = 0;\n let i = scrollOffset;\n while (i < rows.length) {\n const cost = rows[i].kind === 'header' && i > scrollOffset ? 2 : 1;\n if (visualCount + cost > budget) break;\n visualCount += cost;\n i++;\n }\n return i;\n}\n\n/** Adjust scroll offset to keep focusedRowIdx visible within the viewport. */\nfunction adjustScrollOffset(\n currentOffset: number,\n focusedRowIdx: number,\n rows: Row[],\n viewportBudget: number,\n): number {\n const visibleEnd = computeVisibleEnd(rows, currentOffset, viewportBudget);\n\n // Already visible\n if (focusedRowIdx >= currentOffset && focusedRowIdx < visibleEnd) {\n return currentOffset;\n }\n\n // Focus moved above viewport — scroll up, including group header if adjacent\n if (focusedRowIdx < currentOffset) {\n let newOffset = focusedRowIdx;\n if (newOffset > 0 && rows[newOffset - 1]?.kind === 'header') {\n newOffset--;\n }\n return Math.max(0, newOffset);\n }\n\n // Focus moved below viewport — scroll down minimally\n let newOffset = currentOffset + 1;\n while (newOffset < rows.length) {\n const end = computeVisibleEnd(rows, newOffset, viewportBudget);\n if (focusedRowIdx < end) break;\n newOffset++;\n }\n return Math.min(newOffset, Math.max(0, rows.length - 1));\n}\n\nexport const GroupedPickerMenu = ({\n message,\n groups,\n initialSelected,\n onSelect,\n}: GroupedPickerMenuProps) => {\n const [termCols, termRows] = useStdoutDimensions();\n\n // Available width for option labels, after subtracting layout chrome:\n // paddingX(2) + marginLeft(2) + option marginLeft(1) + gap(1) + checkbox(2) = 8\n const labelWidth = Math.max(10, Math.min(termCols, 120) - 8);\n\n // Build a flat row list with headers interleaved\n const rows = useMemo<Row[]>(() => {\n const result: Row[] = [];\n for (const [groupName, options] of Object.entries(groups)) {\n result.push({ kind: 'header', label: groupName });\n for (const opt of options) {\n result.push({ kind: 'option', ...opt });\n }\n }\n return result;\n }, [groups]);\n\n // Indices of selectable (non-header) rows\n const selectableIndices = useMemo(\n () =>\n rows.map((r, i) => (r.kind === 'option' ? i : -1)).filter((i) => i >= 0),\n [rows],\n );\n\n // All option values for toggle-all\n const allValues = useMemo(\n () =>\n rows\n .filter((r): r is Row & { kind: 'option' } => r.kind === 'option')\n .map((r) => r.value),\n [rows],\n );\n\n const [focusedSelectable, setFocusedSelectable] = useState(0);\n // When true, the cursor is on the Confirm button rather than an option.\n const [onButton, setOnButton] = useState(false);\n const [selected, setSelected] = useState<Set<string>>(\n () => new Set(initialSelected ?? allValues),\n );\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const focusedRowIdx = selectableIndices[focusedSelectable] ?? 0;\n\n // Viewport budget: how many visual rows can be shown\n const viewportBudget = Math.max(5, termRows - CHROME_OVERHEAD - MENU_CHROME);\n const totalVisual = countVisualRows(rows, 0, rows.length);\n const needsScroll = totalVisual > viewportBudget;\n const effectiveBudget = needsScroll ? viewportBudget - 2 : viewportBudget;\n\n useKeyBindings('grouped-picker', [\n {\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '\\u2191\\u2193',\n action: 'navigate',\n handler: (_input, key) => {\n const last = selectableIndices.length - 1;\n\n // Move focus onto a selectable option, scrolling it into view.\n const moveTo = (target: number) => {\n setOnButton(false);\n setFocusedSelectable(target);\n if (needsScroll) {\n const rowIdx = selectableIndices[target] ?? 0;\n setScrollOffset((prev) =>\n adjustScrollOffset(prev, rowIdx, rows, effectiveBudget),\n );\n }\n };\n\n if (key.upArrow) {\n if (onButton) {\n moveTo(last); // button → bottom of the list\n } else if (focusedSelectable > 0) {\n moveTo(focusedSelectable - 1);\n } else {\n setOnButton(true); // top of the list → button\n }\n }\n if (key.downArrow) {\n if (onButton) {\n moveTo(0); // button → top of the list\n } else if (focusedSelectable < last) {\n moveTo(focusedSelectable + 1);\n } else {\n setOnButton(true); // bottom of the list → button\n }\n }\n },\n },\n {\n match: [KeyMatch.Space, KeyMatch.Return],\n label: 'enter',\n action: 'select',\n handler: () => {\n if (onButton) {\n onSelect([...selected]);\n return;\n }\n const targetRowIdx = selectableIndices[focusedSelectable] ?? 0;\n const row = rows[targetRowIdx];\n if (row?.kind === 'option') {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(row.value)) {\n next.delete(row.value);\n } else {\n next.add(row.value);\n }\n return next;\n });\n }\n },\n },\n {\n match: 'a',\n label: 'a',\n action: 'toggle all',\n priority: 11,\n handler: () => {\n setSelected((prev) => {\n if (prev.size === allValues.length) {\n return new Set();\n }\n return new Set(allValues);\n });\n },\n },\n ]);\n\n // Determine visible slice\n const visibleStart = needsScroll ? scrollOffset : 0;\n const visibleEnd = needsScroll\n ? computeVisibleEnd(rows, visibleStart, effectiveBudget)\n : rows.length;\n const visibleRows = rows.slice(visibleStart, visibleEnd);\n const hiddenAbove = needsScroll\n ? selectableIndices.filter((s) => s < visibleStart).length\n : 0;\n const hiddenBelow = needsScroll\n ? selectableIndices.filter((s) => s >= visibleEnd).length\n : 0;\n\n return (\n <Box flexDirection=\"column\">\n <PromptLabel message={message} />\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n {needsScroll && (\n <Text dimColor>\n {hiddenAbove > 0 ? `\\u2191 ${hiddenAbove} more` : ' '}\n </Text>\n )}\n {visibleRows.map((row, relIdx) => {\n const absIdx = visibleStart + relIdx;\n\n if (row.kind === 'header') {\n return (\n <Box\n key={`h-${absIdx}`}\n marginTop={relIdx > 0 && absIdx > 0 ? 1 : 0}\n >\n <Text bold dimColor>\n {row.label}\n </Text>\n </Box>\n );\n }\n\n const isFocused = !onButton && focusedRowIdx === absIdx;\n const isSelected = selected.has(row.value);\n const checkbox = isSelected ? Icons.squareFilled : Icons.squareOpen;\n const fullLabel = row.hint ? `${row.label} (${row.hint})` : row.label;\n const label = truncateWithEllipsis(fullLabel, labelWidth);\n\n return (\n <Box key={row.value} gap={1} marginLeft={1}>\n <Text\n color={isSelected ? 'white' : Colors.muted}\n dimColor={!isFocused && !isSelected}\n >\n {checkbox}\n </Text>\n <Box flexGrow={1} flexShrink={1} overflow=\"hidden\">\n <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n wrap=\"truncate\"\n >\n {label}\n </Text>\n </Box>\n </Box>\n );\n })}\n {needsScroll && (\n <Text dimColor>\n {hiddenBelow > 0 ? `\\u2193 ${hiddenBelow} more` : ' '}\n </Text>\n )}\n </Box>\n <Box marginTop={1} marginLeft={2}>\n <ConfirmButton focused={onButton} count={selected.size} />\n </Box>\n </Box>\n );\n};\n","/**\n * ConfirmationInput — Continue/cancel prompt.\n * Enter confirms, escape cancels. Arrow keys toggle focus.\n *\n * Key bindings are declared via useKeyBindings, which auto-registers\n * hints in the KeyboardHintsBar.\n */\n\nimport { Box, Text } from 'ink';\nimport { useState } from 'react';\nimport { Icons, Colors } from '@ui/tui/styles';\nimport { PromptLabel } from './PromptLabel.js';\nimport { useKeyBindings, KeyMatch } from '@ui/tui/hooks/useKeyBindings';\n\ninterface ConfirmationInputProps {\n message: string;\n onConfirm: () => void;\n onCancel: () => void;\n confirmLabel?: string;\n cancelLabel?: string;\n}\n\nenum FocusTarget {\n Continue = 'continue',\n Cancel = 'cancel',\n}\n\nexport const ConfirmationInput = ({\n message,\n onConfirm,\n onCancel,\n confirmLabel = 'Continue',\n cancelLabel = 'Cancel',\n}: ConfirmationInputProps) => {\n const [focused, setFocused] = useState<FocusTarget>(FocusTarget.Continue);\n\n useKeyBindings('confirmation', [\n {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'switch',\n handler: () => {\n setFocused((f) =>\n f === FocusTarget.Continue\n ? FocusTarget.Cancel\n : FocusTarget.Continue,\n );\n },\n },\n {\n match: KeyMatch.Return,\n label: 'enter',\n action: 'confirm',\n handler: () => {\n if (focused === FocusTarget.Continue) {\n onConfirm();\n } else {\n onCancel();\n }\n },\n },\n {\n match: KeyMatch.Escape,\n label: 'esc',\n action: 'cancel',\n handler: () => {\n onCancel();\n },\n },\n ]);\n\n return (\n <Box flexDirection=\"column\">\n <PromptLabel message={message} />\n <Box gap={2} marginTop={1} marginLeft={2}>\n <Text\n bold={focused === FocusTarget.Continue}\n color={\n focused === FocusTarget.Continue ? Colors.accent : Colors.muted\n }\n >\n {focused === FocusTarget.Continue ? Icons.triangleSmallRight : ' '}{' '}\n {confirmLabel}\n </Text>\n <Text\n bold={focused === FocusTarget.Cancel}\n color={focused === FocusTarget.Cancel ? Colors.accent : Colors.muted}\n >\n {focused === FocusTarget.Cancel ? Icons.triangleSmallRight : ' '}{' '}\n {cancelLabel}\n </Text>\n </Box>\n </Box>\n );\n};\n","import { Box, Text, measureElement } from 'ink';\nimport { useRef, useState, useEffect } from 'react';\n\ninterface DividerProps {\n dimColor?: boolean;\n char?: string;\n}\n\nexport const Divider = ({ dimColor = true, char = '─' }: DividerProps) => {\n const ref = useRef(null);\n const [width, setWidth] = useState(0);\n\n useEffect(() => {\n if (ref.current) {\n const { width: measured } = measureElement(ref.current);\n setWidth(measured);\n }\n }, []);\n\n return (\n <Box ref={ref} width=\"100%\">\n <Text dimColor={dimColor}>{width > 0 ? char.repeat(width) : ''}</Text>\n </Box>\n );\n};\n","/**\n * ModalOverlay — Reusable centered card for overlay screens.\n *\n * Shared layout for HealthCheckScreen, SettingsOverrideScreen, PortConflictScreen, etc.\n * Provides: centered card with border, title, body, optional feedback, divider, and actions.\n */\n\nimport type { ReactNode } from 'react';\nimport { Box, Text } from 'ink';\nimport { Divider } from './Divider.js';\n\ninterface ModalOverlayProps {\n /** Card border color */\n borderColor: string;\n /** Title text */\n title: string;\n /** Title text color (defaults to borderColor) */\n titleColor?: string;\n /** Card width (default 68) */\n width?: number;\n /** Body content */\n children: ReactNode;\n /** Optional feedback message (shown in yellow above the divider) */\n feedback?: string | null;\n /** Footer content below the divider (typically ConfirmationInput) */\n footer?: ReactNode;\n}\n\nexport const ModalOverlay = ({\n borderColor,\n title,\n titleColor,\n width = 68,\n children,\n feedback,\n footer,\n}: ModalOverlayProps) => {\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={borderColor}\n paddingX={3}\n paddingY={1}\n width={width}\n >\n <Box justifyContent=\"center\" marginBottom={1}>\n <Text color={titleColor ?? borderColor} bold>\n {title}\n </Text>\n </Box>\n\n {children}\n\n {feedback && (\n <Box marginTop={1}>\n <Text color=\"yellow\">{feedback}</Text>\n </Box>\n )}\n\n {footer && (\n <>\n <Box marginY={1}>\n <Divider />\n </Box>\n {footer}\n </>\n )}\n </Box>\n </Box>\n );\n};\n","/**\n * Link-rendering helpers for terminal prompts.\n *\n * Terminals that auto-linkify text scan *visual* lines, so a URL the TUI wraps\n * across lines — or pads with box-border characters — gets a wrong click\n * target: the terminal opens half a URL, or one stitched back together with\n * border glyphs and padding.\n *\n * The fix is an explicit OSC 8 hyperlink: the escape carries the exact target\n * out of band, independent of the visible layout, and Ink's wrap re-emits it on\n * every wrapped line — so the click target stays correct even when the URL\n * wraps to fit the overlay. Each standalone URL gets its own line so the escape\n * brackets exactly one URL. Terminals without OSC 8 support ignore the escape\n * and show the visible text.\n */\n\n// OSC 8 hyperlink escape: ESC ] 8 ; ; <url> BEL <label> ESC ] 8 ; ; BEL.\n// Built from char codes so no raw control bytes live in source.\nconst ESC = String.fromCharCode(0x1b);\nconst BEL = String.fromCharCode(0x07);\nconst OSC_8 = `${ESC}]8;;`;\n\n/** Matches an http(s) URL run (no surrounding whitespace). */\nconst URL_RUN = /https?:\\/\\/[^\\s]+/g;\n\n/** A line whose entire (trimmed) content is a single URL. */\nconst STANDALONE_URL_LINE = /^https?:\\/\\/\\S+$/;\n\n/** Trailing characters that are punctuation around a URL, not part of it. */\nconst TRAILING_PUNCTUATION = /[.,;:!?)\\]}>'\"]+$/;\n\nfunction trimTrailingPunctuation(url: string): string {\n return url.replace(TRAILING_PUNCTUATION, '');\n}\n\n/**\n * Wrap `label` (defaults to the URL) in an OSC 8 hyperlink escape pointing\n * at `url`. Terminals that support OSC 8 make the whole run clickable to the\n * exact `url`; terminals that don't render `label` as plain text.\n */\nexport function osc8Hyperlink(url: string, label: string = url): string {\n return `${OSC_8}${url}${BEL}${label}${OSC_8}${BEL}`;\n}\n\n/** Extract every http(s) URL in `text`, trailing punctuation removed. */\nexport function extractUrls(text: string): string[] {\n const matches = text.match(URL_RUN) ?? [];\n return matches.map(trimTrailingPunctuation);\n}\n\nexport type PromptSegment =\n | { type: 'text'; value: string }\n | { type: 'url'; value: string };\n\n/**\n * Split prompt text into renderable segments, breaking out any line that is\n * *solely* a URL into its own `url` segment. Consecutive non-URL lines stay\n * grouped in one `text` segment (newlines preserved) so paragraph spacing is\n * unchanged. URLs that appear inline within prose are left in the text\n * segment — only standalone-line URLs are special-cased, which is how the\n * wizard's prompts present links a user is meant to open.\n */\nexport function splitPromptIntoSegments(text: string): PromptSegment[] {\n const segments: PromptSegment[] = [];\n let buffer: string[] = [];\n\n const flush = () => {\n if (buffer.length > 0) {\n segments.push({ type: 'text', value: buffer.join('\\n') });\n buffer = [];\n }\n };\n\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (STANDALONE_URL_LINE.test(trimmed)) {\n flush();\n segments.push({ type: 'url', value: trimTrailingPunctuation(trimmed) });\n } else {\n buffer.push(line);\n }\n }\n flush();\n return segments;\n}\n","/**\n * LinkText — renders prompt text with standalone URLs as OSC 8 hyperlinks.\n *\n * Each URL gets its own line, wrapped (`wrap=\"wrap\"`) so the full URL is shown\n * within the overlay instead of truncated — the user can read and select all of\n * it. Ink's wrap (wrap-ansi) re-emits the OSC 8 escape on every wrapped visual\n * line, so the click target stays the exact, full URL no matter where the\n * visible text breaks. A manual selection of a wrapped line still picks up the\n * line break, so for a clean copy `WizardAskScreen` auto-copies a sole URL to\n * the clipboard. Prose renders unchanged.\n *\n * Used by the `wizard_ask` overlay only for programs that opt into rich link\n * rendering (see `PendingQuestion.richLinks`). Other flows are untouched.\n */\nimport { Box, Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport { osc8Hyperlink, splitPromptIntoSegments } from './link-helpers.js';\n\ninterface LinkTextProps {\n text: string;\n}\n\nexport const LinkText = ({ text }: LinkTextProps) => {\n const segments = splitPromptIntoSegments(text);\n return (\n <Box flexDirection=\"column\">\n {segments.map((segment, i) =>\n segment.type === 'url' ? (\n <Text key={i} color={Colors.accent} underline wrap=\"wrap\">\n {osc8Hyperlink(segment.value)}\n </Text>\n ) : (\n <Text key={i}>{segment.value}</Text>\n ),\n )}\n </Box>\n );\n};\n","/**\n * LogViewer — Real-time log tail, pinned to available terminal height.\n * Only renders the last N lines that fit on screen.\n *\n * Reads only the last TAIL_BYTES of the file on each refresh and throttles\n * fs.watch callbacks to one refresh per WATCH_THROTTLE_MS. Without this,\n * fs.readFileSync allocates a string the size of the entire log on every\n * append — during subagent fan-out that's tens of writes per second against\n * a log that grows into the hundreds of MB, producing OOM-grade allocation\n * pressure on V8's heap.\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useEffect } from 'react';\nimport * as fs from 'fs';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\n\n/** Rows consumed by TitleBar + spacer + ScreenContainer padding + status bar +\n * tab bar, with a couple rows of headroom so the tail never crowds the status\n * bar below it. */\nconst CHROME_ROWS = 10;\n\n/** Bytes read from the end of the log per refresh — large enough to contain\n * any practical visible window of lines, small enough to allocate cheaply. */\nconst TAIL_BYTES = 256 * 1024;\n\n/** Minimum gap between watch-triggered refreshes. fs.watch fires on every\n * append */\nconst WATCH_THROTTLE_MS = 250;\n\ninterface LogViewerProps {\n filePath: string;\n /** Fixed visible height. Defaults to terminal rows minus chrome. */\n height?: number;\n}\n\nfunction readTailLines(filePath: string, visibleLines: number): string[] {\n const stat = fs.statSync(filePath);\n if (stat.size === 0) return [];\n const start = Math.max(0, stat.size - TAIL_BYTES);\n const length = stat.size - start;\n const buf = Buffer.alloc(length);\n const fd = fs.openSync(filePath, 'r');\n try {\n fs.readSync(fd, buf, 0, length, start);\n } finally {\n fs.closeSync(fd);\n }\n let text = buf.toString('utf-8');\n if (start > 0) {\n const firstNewline = text.indexOf('\\n');\n if (firstNewline >= 0) text = text.slice(firstNewline + 1);\n }\n return text.split('\\n').slice(-visibleLines);\n}\n\nexport const LogViewer = ({ filePath, height }: LogViewerProps) => {\n const [, rows] = useStdoutDimensions();\n const visibleLines = height ?? Math.max(5, rows - CHROME_ROWS);\n\n const [lines, setLines] = useState<string[]>([]);\n\n useEffect(() => {\n let lastReadAt = 0;\n let pendingTimer: ReturnType<typeof setTimeout> | undefined;\n\n const readTail = () => {\n try {\n setLines(readTailLines(filePath, visibleLines));\n } catch {\n setLines(['(No log file found)']);\n }\n };\n\n const scheduleRead = () => {\n const now = Date.now();\n const elapsed = now - lastReadAt;\n if (elapsed >= WATCH_THROTTLE_MS) {\n lastReadAt = now;\n readTail();\n return;\n }\n if (pendingTimer) return;\n pendingTimer = setTimeout(() => {\n pendingTimer = undefined;\n lastReadAt = Date.now();\n readTail();\n }, WATCH_THROTTLE_MS - elapsed);\n };\n\n readTail();\n lastReadAt = Date.now();\n\n let watcher: fs.FSWatcher | undefined;\n try {\n watcher = fs.watch(filePath, () => scheduleRead());\n } catch {\n const interval = setInterval(() => {\n try {\n fs.accessSync(filePath);\n readTail();\n clearInterval(interval);\n watcher = fs.watch(filePath, () => scheduleRead());\n } catch {\n // Still waiting for the file to appear\n }\n }, 1000);\n\n return () => {\n clearInterval(interval);\n if (pendingTimer) clearTimeout(pendingTimer);\n };\n }\n\n return () => {\n watcher?.close();\n if (pendingTimer) clearTimeout(pendingTimer);\n };\n }, [filePath, visibleLines]);\n\n return (\n <Box flexDirection=\"column\" height={visibleLines}>\n {lines.map((line, i) => (\n <Text key={i} dimColor wrap=\"truncate\">\n {line}\n </Text>\n ))}\n </Box>\n );\n};\n","/**\n * EventPlanViewer — Renders a table of planned analytics events.\n */\n\nimport { Box, Text } from 'ink';\nimport type { PlannedEvent } from '@ui/tui/store';\n\ninterface EventPlanViewerProps {\n events: PlannedEvent[];\n}\n\nexport const EventPlanViewer = ({ events }: EventPlanViewerProps) => {\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text bold>Event plan</Text>\n <Box height={1} />\n {events.map((event) => (\n <Box key={event.name}>\n <Text bold>{event.name}</Text>\n <Text dimColor> {event.description}</Text>\n </Box>\n ))}\n </Box>\n );\n};\n","import { Box, Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\n\nconst FEEDBACK = 'Feedback: wizard@posthog.com ';\nconst FEEDBACK_SHORT = ' wizard@posthog.com ';\n\ninterface TitleBarProps {\n version: string;\n width: number;\n}\n\nexport const TitleBar = ({ version, width }: TitleBarProps) => {\n const fullTitle = ` PostHog Wizard v${version}`;\n const needShort = width < fullTitle.length + FEEDBACK.length;\n const feedback = needShort ? FEEDBACK_SHORT : FEEDBACK;\n const title =\n needShort && fullTitle.length + feedback.length > width\n ? ` Wizard v${version}`\n : fullTitle;\n const gap = Math.max(0, width - title.length - feedback.length);\n const padding = ' '.repeat(gap);\n\n return (\n <Box width={width} overflow=\"hidden\">\n <Text backgroundColor={Colors.accent} color={Colors.titleColor}>\n {title}\n {padding}\n {feedback}\n </Text>\n </Box>\n );\n};\n","/**\n * DissolveTransition — Column-sweep inspired by TTE's Sweep effect.\n *\n * Uses a SequenceEaser (in_out_circ) to activate columns with eased pacing.\n * Each activated column cycles through shade characters (░▒▓█) independently.\n *\n * Out phase: columns sweep, building up shade chars until solid █ (covers old content).\n * In phase: columns sweep in reverse, dissolving █ back through shades to empty (reveals new content).\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useEffect, useRef, type ReactNode } from 'react';\n\n/** Shade characters in build-up order (light → solid). */\nconst SHADES = ['░', '▒', '▓', '█'] as const;\n/** How many ticks each shade character displays before advancing. */\nconst TICKS_PER_SHADE = 2;\n/** Total ticks a column needs to complete its shade cycle. */\nconst SHADE_CYCLE_TICKS = SHADES.length * TICKS_PER_SHADE;\n\nexport type WipeDirection = 'left' | 'right';\n\ninterface DissolveTransitionProps {\n transitionKey: string;\n width: number;\n height: number;\n children: ReactNode;\n direction?: WipeDirection;\n duration?: number;\n}\n\nfunction easeInOutCirc(t: number): number {\n if (t < 0.5) {\n return (1 - Math.sqrt(1 - 4 * t * t)) / 2;\n }\n return (Math.sqrt(1 - (2 * t - 2) ** 2) + 1) / 2;\n}\n\nenum TransitionPhase {\n Idle = 'idle',\n Out = 'out',\n In = 'in',\n}\n\nexport const DissolveTransition = ({\n transitionKey,\n width,\n height,\n children,\n direction = 'left',\n duration = 2,\n}: DissolveTransitionProps) => {\n const [phase, setPhase] = useState<TransitionPhase>(TransitionPhase.Idle);\n const [tick, setTick] = useState(0);\n const [activeDir, setActiveDir] = useState<WipeDirection>(direction);\n const prevKey = useRef(transitionKey);\n const pendingChildren = useRef<ReactNode>(children);\n const [displayChildren, setDisplayChildren] = useState<ReactNode>(children);\n\n // Track when each column was activated (tick number), -1 means not yet.\n const columnActivationTick = useRef<number[]>([]);\n\n useEffect(() => {\n if (transitionKey !== prevKey.current) {\n prevKey.current = transitionKey;\n pendingChildren.current = children;\n setActiveDir(direction);\n setPhase(TransitionPhase.Out);\n setTick(0);\n columnActivationTick.current = new Array(width).fill(-1);\n } else if (phase !== TransitionPhase.Idle) {\n // Terminal resized mid-transition — abort and show new content immediately\n setPhase(TransitionPhase.Idle);\n setDisplayChildren(children);\n } else {\n setDisplayChildren(children);\n }\n }, [transitionKey, children, width, height, phase, direction]);\n\n useEffect(() => {\n if (phase === TransitionPhase.Idle) return;\n\n const timer = setInterval(() => {\n setTick((prev) => prev + 1);\n }, duration);\n\n return () => clearInterval(timer);\n }, [phase, duration]);\n\n // Easer steps = width: roughly one column activates per tick.\n // This keeps the sweep front tight (only a few columns in-flight at once).\n const easerSteps = width;\n\n // A phase ends when the easer has completed AND all columns have finished their shade cycle.\n const maxTicks = easerSteps + SHADE_CYCLE_TICKS;\n\n useEffect(() => {\n if (phase === TransitionPhase.Idle) return;\n if (tick >= maxTicks) {\n if (phase === TransitionPhase.Out) {\n setDisplayChildren(pendingChildren.current);\n setPhase(TransitionPhase.In);\n setTick(0);\n columnActivationTick.current = new Array(width).fill(-1);\n } else {\n setPhase(TransitionPhase.Idle);\n }\n }\n }, [tick, phase, maxTicks, width]);\n\n if (phase === TransitionPhase.Idle) {\n return <>{displayChildren}</>;\n }\n\n // --- SequenceEaser logic ---\n // Map current tick to easer progress (0..1), apply easing,\n // then determine how many columns should be activated.\n const easerProgress = Math.min(tick / easerSteps, 1);\n const easedValue = easeInOutCirc(easerProgress);\n const activatedCount = Math.floor(easedValue * width);\n\n // Build column order based on direction.\n // \"left\" means sweep moves left-to-right; \"right\" means right-to-left.\n // TTE's COLUMN_RIGHT_TO_LEFT activates rightmost first.\n const columnOrder: number[] = [];\n if (activeDir === 'left') {\n for (let c = width - 1; c >= 0; c--) columnOrder.push(c);\n } else {\n for (let c = 0; c < width; c++) columnOrder.push(c);\n }\n\n // Activate columns that should be active but aren't yet.\n for (let i = 0; i < activatedCount && i < columnOrder.length; i++) {\n const col = columnOrder[i];\n if (columnActivationTick.current[col] === -1) {\n columnActivationTick.current[col] = tick;\n }\n }\n\n // --- Render frame ---\n const rows: string[] = [];\n for (let r = 0; r < height; r++) {\n let row = '';\n for (let c = 0; c < width; c++) {\n const activatedAt = columnActivationTick.current[c];\n\n let char: string;\n if (activatedAt === -1) {\n // Not yet activated\n char = phase === TransitionPhase.Out ? ' ' : '█';\n } else {\n // Column is activated — determine shade based on ticks since activation\n const age = tick - activatedAt;\n const shadeIndex = Math.min(\n Math.floor(age / TICKS_PER_SHADE),\n SHADES.length - 1,\n );\n\n if (phase === TransitionPhase.Out) {\n // Building up: ░ → ▒ → ▓ → █\n char = SHADES[shadeIndex];\n } else {\n // Dissolving: █ → ▓ → ▒ → ░ → space\n if (shadeIndex >= SHADES.length - 1 && age >= SHADE_CYCLE_TICKS) {\n char = ' ';\n } else {\n char = SHADES[SHADES.length - 1 - shadeIndex];\n }\n }\n }\n\n row += char;\n }\n rows.push(row);\n }\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {rows.map((row, i) => (\n <Text key={i} dimColor>\n {row}\n </Text>\n ))}\n </Box>\n );\n};\n","/**\n * KeyboardHintsBar — Row showing active keyboard shortcuts.\n *\n * Always reserves its row to prevent layout shift, and always renders the\n * active hints (in dimmed grey text) while a screen has registered them.\n */\n\nimport { Box, Text } from 'ink';\nimport { useKeyboardHintsContext } from '@ui/tui/hooks/useKeyboardHints';\nimport { Colors } from '@ui/tui/styles';\n\nexport const KeyboardHintsBar = () => {\n const { hints } = useKeyboardHintsContext();\n\n return (\n <Box height={1} paddingX={1}>\n {hints.map((hint, i) => (\n <Box\n key={`${hint.label}-${hint.action}`}\n marginRight={i < hints.length - 1 ? 2 : 0}\n >\n <Text bold color={Colors.muted}>\n {hint.label}\n </Text>\n <Text dimColor> {hint.action}</Text>\n </Box>\n ))}\n </Box>\n );\n};\n","/**\n * ScreenErrorBoundary — catches React render errors in screens\n * and routes to the outro screen with an error message.\n *\n * Without this, a screen crash silently hangs the TUI.\n */\n\nimport { Box, Text } from 'ink';\nimport { Component, type ReactNode } from 'react';\nimport type { WizardStore } from '@ui/tui/store';\nimport { OutroKind, RunPhase } from '@lib/wizard-session';\nimport { logToFile } from '@utils/debug';\n\ninterface Props {\n store: WizardStore;\n children: ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class ScreenErrorBoundary extends Component<Props, State> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error): void {\n const { store } = this.props;\n\n // The console.error below is wiped with the alt screen; this survives.\n logToFile('[screen-error-boundary]', error);\n // eslint-disable-next-line no-console\n console.error('[ScreenErrorBoundary]', error.message, error.stack);\n\n // Set error state — the router will resolve to outro\n store.setOutroData({\n kind: OutroKind.Error,\n message: `A screen crashed: ${error.message}`,\n });\n store.setRunPhase(RunPhase.Error);\n }\n\n render(): ReactNode {\n if (this.state.error) {\n // Fallback while the store transition fires\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\" bold>\n Something went wrong.\n </Text>\n <Text dimColor>{this.state.error.message}</Text>\n </Box>\n );\n }\n\n return this.props.children;\n }\n}\n","/**\n * ScreenContainer — Renders TitleBar + routes between screens with transitions.\n * Takes a screens map and renders the one matching store.currentScreen.\n * Horizontal wipe plays on push (left) or pop (right).\n *\n * Each screen is wrapped in a ScreenErrorBoundary so that render crashes\n * route to the outro screen with an error message instead of hanging.\n *\n * Provides KeyboardHintsProvider context. The hints bar is rendered below\n * screen content (inside the transition area) so all screens get it.\n */\n\nimport { Box } from 'ink';\nimport { useSyncExternalStore, type ReactNode } from 'react';\nimport { TitleBar } from '@ui/tui/components/TitleBar';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\nimport { KeyboardHintsProvider } from '@ui/tui/hooks/useKeyboardHints';\nimport { DissolveTransition } from './DissolveTransition.js';\nimport { KeyboardHintsBar } from './KeyboardHintsBar.js';\nimport { ScreenErrorBoundary } from './ScreenErrorBoundary.js';\nimport type { WizardStore } from '@ui/tui/store';\n\nconst MIN_WIDTH = 80;\nexport const MAX_WIDTH = 120;\n\n/** Use terminal width when small so we don't overflow; otherwise clamp to [MIN_WIDTH, MAX_WIDTH]. */\nfunction getContentWidth(terminalColumns: number): number {\n if (terminalColumns < MIN_WIDTH) return terminalColumns;\n return Math.min(MAX_WIDTH, terminalColumns);\n}\n\ninterface ScreenContainerProps {\n store: WizardStore;\n screens: Record<string, ReactNode>;\n}\n\nexport const ScreenContainer = ({ store, screens }: ScreenContainerProps) => {\n const [columns, rows] = useStdoutDimensions();\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const terminalWidth = columns;\n const width = getContentWidth(terminalWidth);\n const contentHeight = Math.max(5, rows - 3);\n const contentAreaWidth = Math.max(10, width - 2);\n const direction = store.lastNavDirection === 'pop' ? 'right' : 'left';\n const activeScreen = screens[store.currentScreen] ?? null;\n\n const inner = (\n <Box flexDirection=\"column\" height={rows} width={width}>\n <TitleBar version={store.version} width={width} />\n <Box height={1} />\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <DissolveTransition\n transitionKey={store.currentScreen}\n width={contentAreaWidth}\n height={contentHeight}\n direction={direction}\n >\n <ScreenErrorBoundary store={store}>\n <Box flexDirection=\"column\" height={contentHeight}>\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n flexShrink={1}\n overflow=\"hidden\"\n >\n {activeScreen}\n </Box>\n <Box height={1} />\n <KeyboardHintsBar />\n </Box>\n </ScreenErrorBoundary>\n </DissolveTransition>\n </Box>\n </Box>\n );\n\n return (\n <Box\n flexDirection=\"column\"\n height={rows}\n width={terminalWidth}\n alignItems=\"center\"\n justifyContent=\"flex-start\"\n >\n <KeyboardHintsProvider>{inner}</KeyboardHintsProvider>\n </Box>\n );\n};\n","/**\n * TabContainer — Self-contained tabbed interface.\n * Absorbs BottomTabBar + StatusPanel functionality.\n *\n * Key bindings are declared via useKeyBindings, which auto-registers\n * hints in the KeyboardHintsBar (rendered by ScreenContainer).\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useMemo, type ReactNode } from 'react';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport {\n useKeyBindings,\n KeyMatch,\n type KeyBinding,\n} from '@ui/tui/hooks/useKeyBindings';\nimport type { WizardStore } from '@ui/tui/store';\nimport { COLLAPSED_COUNT, EXPANDED_COUNT } from '@ui/tui/constants';\n\n// Re-exported so existing importers (e.g. LearnCard) keep their path.\nexport { COLLAPSED_COUNT, EXPANDED_COUNT };\n\nexport interface TabDefinition {\n id: string;\n label: string;\n component: ReactNode;\n}\n\ninterface TabContainerProps {\n tabs: TabDefinition[];\n statusMessage?: string | string[];\n /** Enable expand/collapse on the status box via 's' key */\n expandableStatus?: boolean;\n /** Store reference — required when expandableStatus is true so status state is shared. */\n store?: WizardStore;\n}\n\nexport const TabContainer = ({\n tabs,\n statusMessage,\n expandableStatus = false,\n store,\n}: TabContainerProps) => {\n const [activeTab, setActiveTab] = useState(0);\n // Fallback to local state when no store is provided\n const [localExpanded, setLocalExpanded] = useState(false);\n\n const statusExpanded = store ? store.statusExpanded : localExpanded;\n\n const bindings = useMemo<KeyBinding[]>(() => {\n const b: KeyBinding[] = [\n {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'switch tab',\n handler: (_input, key) => {\n if (key.leftArrow) {\n setActiveTab((prev) => Math.max(0, prev - 1));\n }\n if (key.rightArrow) {\n setActiveTab((prev) => Math.min(tabs.length - 1, prev + 1));\n }\n },\n },\n ];\n if (expandableStatus) {\n b.push({\n match: 's',\n label: 's',\n action: 'toggle status',\n priority: 12,\n handler: () => {\n if (store) {\n store.toggleStatusExpanded();\n } else {\n setLocalExpanded((prev) => !prev);\n }\n },\n });\n }\n return b;\n }, [tabs.length, expandableStatus, store]);\n\n useKeyBindings('tab-container', bindings);\n\n const current = tabs[activeTab];\n\n const allMessages = statusMessage\n ? Array.isArray(statusMessage)\n ? statusMessage\n : [statusMessage]\n : [];\n const visibleCount =\n expandableStatus && statusExpanded ? EXPANDED_COUNT : COLLAPSED_COUNT;\n const visibleMessages = allMessages.slice(-visibleCount);\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {/* Active tab content — overflow hidden so expanded status eats into this area */}\n <Box flexDirection=\"column\" flexGrow={1} flexShrink={1} overflow=\"hidden\">\n {current?.component}\n </Box>\n\n {/* Status bar */}\n {visibleMessages.length > 0 && (\n <Box\n flexDirection=\"column\"\n borderStyle=\"single\"\n borderTop\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={Colors.muted}\n paddingX={1}\n overflow=\"hidden\"\n >\n {visibleMessages.map((msg, i, arr) => {\n const isCurrent = i === arr.length - 1;\n return (\n <Text key={i} color={Colors.muted} dimColor={!isCurrent}>\n {isCurrent ? Icons.diamond : '\\u250A'} {msg}\n </Text>\n );\n })}\n </Box>\n )}\n\n {/* Tab bar — wraps onto extra rows when there are more tabs than\n fit the terminal width, instead of clipping the overflow. */}\n <Box height={1} />\n <Box gap={1} paddingX={1} flexWrap=\"wrap\" flexShrink={0}>\n {tabs.map((tab, i) => (\n <Text\n key={tab.id}\n inverse={i === activeTab}\n color={i === activeTab ? Colors.accent : Colors.muted}\n bold={i === activeTab}\n >\n {` ${tab.label} `}\n </Text>\n ))}\n </Box>\n </Box>\n );\n};\n","/**\n * HNViewer — Top 10 Hacker News stories.\n *\n * Fetches from the HN Firebase API on mount.\n * Each story has a [1]–[0] numeral; typing it opens the HN comments page.\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useEffect } from 'react';\nimport { Colors } from '@ui/tui/styles';\nimport { useKeyBindings } from '@ui/tui/hooks/useKeyBindings';\n\nconst HN_API = 'https://hacker-news.firebaseio.com/v0';\n\ninterface HNStory {\n id: number;\n title: string;\n by: string;\n time: number;\n score: number;\n}\n\nexport const HNViewer = () => {\n const [stories, setStories] = useState<HNStory[]>([]);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n void (async () => {\n try {\n const res = await fetch(`${HN_API}/topstories.json`);\n const ids = (await res.json()) as number[];\n const top10 = ids.slice(0, 10);\n\n const items = await Promise.all(\n top10.map(async (id) => {\n const r = await fetch(`${HN_API}/item/${id}.json`);\n return r.json() as Promise<HNStory>;\n }),\n );\n\n setStories(items);\n } catch {\n // Silently fail — tab just stays empty\n }\n setLoading(false);\n })();\n }, []);\n\n useKeyBindings('hn-viewer', [\n {\n match: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\n label: 'number keys',\n action: 'open story',\n priority: 5,\n handler: (input) => openStory(input, stories),\n },\n ]);\n\n if (loading) {\n return (\n <Box paddingX={1}>\n <Text dimColor>Loading Hacker News...</Text>\n </Box>\n );\n }\n\n if (stories.length === 0) {\n return (\n <Box paddingX={1}>\n <Text dimColor>Could not load Hacker News.</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text bold color={Colors.accent}>\n Hacker News — Top 10\n </Text>\n <Box height={1} />\n {stories.map((story, i) => {\n const key = i === 9 ? '0' : String(i + 1);\n const date = new Date(story.time * 1000);\n const dateStr = date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n });\n\n return (\n <Box key={story.id} flexDirection=\"column\">\n <Box>\n <Text color={Colors.accent} bold>\n [{key}]\n </Text>\n <Text bold> {story.title}</Text>\n </Box>\n <Box marginLeft={4}>\n <Text dimColor>\n {story.score}pts • {story.by}, {dateStr}\n </Text>\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n};\n\nfunction openStory(input: string, stories: HNStory[]): void {\n const num = parseInt(input, 10);\n if (isNaN(num)) return;\n const index = num === 0 ? 9 : num - 1;\n const story = stories[index];\n if (!story) return;\n\n const url = `https://news.ycombinator.com/item?id=${story.id}`;\n void import('child_process').then(({ exec }) => {\n exec(`open \"${url}\" 2>/dev/null || xdg-open \"${url}\" 2>/dev/null`);\n });\n}\n","/**\n * LinesBlock — Reveals ReactNode lines one at a time.\n * Each line can contain colors, bold, ASCII art — any JSX.\n */\n\nimport { Box } from 'ink';\nimport { useState, useEffect, type ReactNode } from 'react';\n\ninterface LinesBlockProps {\n lines: ReactNode[];\n interval: number;\n active: boolean;\n completed: boolean;\n onComplete: () => void;\n /** Max rows this block may occupy. When exceeded, top lines are truncated. */\n maxHeight?: number;\n}\n\nexport const LinesBlock = ({\n lines,\n interval,\n active,\n completed,\n onComplete,\n maxHeight,\n}: LinesBlockProps) => {\n const [revealedCount, setRevealedCount] = useState(0);\n\n // Reveal lines one at a time\n useEffect(() => {\n if (!active || revealedCount >= lines.length) return;\n const timer = setTimeout(\n () => setRevealedCount((c) => c + 1),\n revealedCount === 0 ? 0 : interval,\n );\n return () => clearTimeout(timer);\n }, [active, revealedCount, lines.length, interval]);\n\n // Fire onComplete when all lines revealed\n useEffect(() => {\n if (active && revealedCount >= lines.length) onComplete();\n }, [active, revealedCount, lines.length, onComplete]);\n\n // When maxHeight is set, only show the last maxHeight lines\n const visibleStart =\n maxHeight != null\n ? Math.max(0, (completed ? lines.length : revealedCount) - maxHeight)\n : 0;\n\n return (\n <Box flexDirection=\"column\">\n {lines.map((line, li) => {\n if (completed) {\n if (li < visibleStart) return null;\n return <Box key={li}>{line}</Box>;\n }\n if (li >= revealedCount || li < visibleStart) return null;\n return <Box key={li}>{line}</Box>;\n })}\n </Box>\n );\n};\n","/**\n * NodeBlock — Renders static JSX, fires onComplete immediately.\n * The sequencer's blockInterval handles dwell time.\n */\n\nimport { Text } from 'ink';\nimport { useEffect, type ReactNode } from 'react';\n\ninterface NodeBlockProps {\n content: ReactNode;\n active: boolean;\n completed: boolean;\n onComplete: () => void;\n}\n\nexport const NodeBlock = ({\n content,\n active,\n completed,\n onComplete,\n}: NodeBlockProps) => {\n useEffect(() => {\n if (active) onComplete();\n }, [active, onComplete]);\n\n if (completed) return <Text dimColor>{content}</Text>;\n return <>{content}</>;\n};\n","/**\n * ContentSequencer — Plays content blocks in order.\n *\n * Each block is a self-animating component that fires onComplete() when done.\n * The sequencer waits blockInterval ms between blocks, then advances.\n *\n * Block types:\n * - string → TextBlock (animated text, sugar for { content: '...' })\n * - { content: str } → TextBlock (animated text with per-block overrides)\n * - { content: JSX } → NodeBlock (static JSX)\n * - { type: 'lines' } → LinesBlock (line-by-line reveal)\n * - { type: 'clear' } → ClearBlock (page break — hides all prior blocks)\n */\n\nimport { Box } from 'ink';\nimport {\n useState,\n useCallback,\n useEffect,\n useRef,\n useMemo,\n type ReactNode,\n} from 'react';\nimport { TextBlock, type TextRevealMode } from './TextBlock.js';\nimport { LinesBlock } from './LinesBlock.js';\nimport { NodeBlock } from './NodeBlock.js';\nimport { computeVisibleRange } from './layout-helpers.js';\nimport { isLinesBlock, isClearBlock, isObjectBlock } from './content-types.js';\nexport type {\n ContentBlock,\n ContentObjectBlock,\n ContentLinesBlock,\n ContentClearBlock,\n} from './content-types.js';\nexport { isLinesBlock, isClearBlock, isObjectBlock } from './content-types.js';\n\nimport type { ContentBlock } from './content-types.js';\n\n/** Resolve the pause after a block completes. */\nexport function getBlockPause(\n block: ContentBlock,\n blockInterval: number,\n): number {\n if (typeof block === 'string') return blockInterval;\n return block.pause ?? blockInterval;\n}\n\ninterface ContentSequencerProps {\n blocks: ContentBlock[];\n mode: TextRevealMode;\n /** Row budget for visible content. When set, older blocks are evicted. */\n maxHeight?: number;\n /** Available text width in columns (for height estimation). */\n availableWidth?: number;\n bullet?: ReactNode;\n animationInterval?: number;\n sentenceInterval?: number;\n lineInterval?: number;\n blockInterval?: number;\n /** Delay in ms before the first block appears. */\n startDelay?: number;\n /** Resume from a previously persisted block index. */\n initialBlockIdx?: number;\n /** Called whenever the active block index advances. */\n onBlockChange?: (idx: number) => void;\n /** Called once when the last block completes (after its pause). */\n onSequenceComplete?: () => void;\n}\n\nexport const ContentSequencer = ({\n blocks,\n mode,\n maxHeight,\n availableWidth,\n bullet,\n animationInterval,\n sentenceInterval,\n lineInterval = 200,\n blockInterval = 3200,\n startDelay = 0,\n initialBlockIdx = 0,\n onBlockChange,\n onSequenceComplete,\n}: ContentSequencerProps) => {\n const resuming = initialBlockIdx > 0;\n const [activeIdx, setActiveIdx] = useState(\n resuming ? initialBlockIdx : startDelay > 0 ? -1 : 0,\n );\n const transitionTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Initial delay before first block (skip when resuming)\n useEffect(() => {\n if (resuming || startDelay <= 0 || activeIdx !== -1) return;\n const timer = setTimeout(() => setActiveIdx(0), startDelay);\n return () => clearTimeout(timer);\n }, [startDelay, activeIdx]);\n\n // Compute visible range reactively (re-evaluates on resize, block advance, etc.)\n const [visibleStart, visibleEnd] = useMemo(() => {\n if (activeIdx < 0) return [0, -1] as [number, number];\n if (maxHeight == null || availableWidth == null) {\n return [0, activeIdx] as [number, number];\n }\n return computeVisibleRange(blocks, activeIdx, availableWidth, maxHeight);\n }, [blocks, activeIdx, maxHeight, availableWidth]);\n\n const handleComplete = useCallback(\n (blockIndex: number) => {\n // Only the active block can trigger advancement\n if (blockIndex !== activeIdx) return;\n // Last block — fire sequence-complete after its pause, don't advance\n if (activeIdx >= blocks.length - 1) {\n if (onSequenceComplete && !transitionTimer.current) {\n const pause = getBlockPause(blocks[blockIndex], blockInterval);\n transitionTimer.current = setTimeout(() => {\n transitionTimer.current = null;\n onSequenceComplete();\n }, pause);\n }\n return;\n }\n // Don't double-trigger\n if (transitionTimer.current) return;\n\n const pause = getBlockPause(blocks[blockIndex], blockInterval);\n transitionTimer.current = setTimeout(() => {\n transitionTimer.current = null;\n setActiveIdx((i) => {\n const next = i + 1;\n onBlockChange?.(next);\n return next;\n });\n }, pause);\n },\n [activeIdx, blocks, blockInterval, onBlockChange, onSequenceComplete],\n );\n\n // Find the most recent clear block — nothing before it renders.\n // When the active block IS a clear block, immediately hide all prior content\n // so the pause shows a blank screen (not dim prior text).\n const clearFloor = useMemo(() => {\n if (activeIdx >= 0 && isClearBlock(blocks[activeIdx])) return activeIdx;\n for (let i = activeIdx - 1; i >= 0; i--) {\n if (isClearBlock(blocks[i])) return i + 1;\n }\n return 0;\n }, [blocks, activeIdx]);\n\n return (\n <Box flexDirection=\"column\">\n {blocks.map((block, i) => {\n // Not yet reached\n if (i > activeIdx) return null;\n // Hidden by clear block\n if (i < clearFloor) return null;\n // Completed clear blocks don't render (active ones must mount to fire onComplete)\n if (isClearBlock(block) && i < activeIdx) return null;\n // Evicted by viewport\n if (i < visibleStart || i > visibleEnd) return null;\n\n const active = i === activeIdx;\n const completed = i < activeIdx;\n\n // Completed non-text blocks don't persist by default\n if (completed && isObjectBlock(block)) {\n const isText = typeof block.content === 'string';\n const shouldPersist = block.persist ?? isText;\n if (!shouldPersist) return null;\n }\n\n return (\n <Box key={i} flexDirection=\"column\" marginBottom={1}>\n <BlockRenderer\n block={block}\n active={active}\n completed={completed}\n onComplete={() => handleComplete(i)}\n mode={mode}\n bullet={bullet}\n animationInterval={animationInterval}\n sentenceInterval={sentenceInterval}\n lineInterval={lineInterval}\n maxHeight={maxHeight}\n availableWidth={availableWidth}\n />\n </Box>\n );\n })}\n </Box>\n );\n};\n\ninterface BlockRendererProps {\n block: ContentBlock;\n active: boolean;\n completed: boolean;\n onComplete: () => void;\n mode: TextRevealMode;\n bullet?: ReactNode;\n animationInterval?: number;\n sentenceInterval?: number;\n lineInterval: number;\n maxHeight?: number;\n availableWidth?: number;\n}\n\nconst BlockRenderer = ({\n block,\n active,\n completed,\n onComplete,\n mode,\n bullet,\n animationInterval,\n sentenceInterval,\n lineInterval,\n maxHeight,\n availableWidth,\n}: BlockRendererProps) => {\n // Clear block — completes immediately, renders nothing\n if (isClearBlock(block)) {\n useEffect(() => {\n if (active) onComplete();\n }, [active, onComplete]);\n return null;\n }\n\n // Bare string sugar → TextBlock with sequencer defaults\n if (typeof block === 'string') {\n return (\n <TextBlock\n text={block}\n active={active}\n completed={completed}\n onComplete={onComplete}\n mode={mode}\n bullet={bullet}\n animationInterval={animationInterval}\n sentenceInterval={sentenceInterval}\n maxHeight={maxHeight}\n availableWidth={availableWidth}\n // Bare string sugar always uses the default — to override, use\n // the object form: { content: '...', dimWhenComplete: false }.\n />\n );\n }\n\n // Lines block\n if (isLinesBlock(block)) {\n return (\n <LinesBlock\n lines={block.lines}\n interval={block.interval ?? lineInterval}\n active={active}\n completed={completed}\n onComplete={onComplete}\n maxHeight={maxHeight}\n />\n );\n }\n\n // Object block — dispatch on content type\n if (typeof block.content === 'string') {\n return (\n <TextBlock\n text={block.content}\n active={active}\n completed={completed}\n onComplete={onComplete}\n mode={block.mode ?? mode}\n bullet={bullet}\n animationInterval={block.animationInterval ?? animationInterval}\n sentenceInterval={block.sentenceInterval ?? sentenceInterval}\n maxHeight={maxHeight}\n availableWidth={availableWidth}\n dimWhenComplete={block.dimWhenComplete ?? true}\n />\n );\n }\n\n return (\n <NodeBlock\n content={block.content}\n active={active}\n completed={completed}\n onComplete={onComplete}\n />\n );\n};\n","/**\n * LearnCard — Generic render shell for an animated content deck.\n *\n * Program-owned. Callers pass the script via `blocks`. The script lives\n * under `src/lib/programs/<name>/content/`. The shell handles\n * dimension tracking, status-bar height math, and the `display=\"none\"`\n * clamp on narrow terminals.\n */\n\nimport { Box, Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { WizardStore } from '@ui/tui/store';\nimport { ContentSequencer, TextRevealMode } from '@ui/tui/primitives/index';\nimport type { ContentBlock } from '@ui/tui/primitives/index';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\nimport {\n COLLAPSED_COUNT,\n EXPANDED_COUNT,\n} from '@ui/tui/primitives/TabContainer';\n\n/** Fixed chrome: ScreenContainer (3) + TabContainer tab bar (2) */\nconst FIXED_CHROME = 5;\nconst HEADER_ROWS = 2; // title + spacer\nconst MIN_CONTENT_ROWS = 6;\n\ninterface LearnCardProps {\n store?: WizardStore;\n /** The script to play. Program-owned; see programs/<name>/content/. */\n blocks: ContentBlock[];\n onComplete?: () => void;\n}\n\nexport const LearnCard = ({ store, blocks, onComplete }: LearnCardProps) => {\n const [columns, rows] = useStdoutDimensions();\n\n // Dynamic status bar height: messages + border when present\n const hasStatus = store ? store.statusMessages.length > 0 : false;\n const statusBarRows = hasStatus\n ? (store?.statusExpanded ? EXPANDED_COUNT : COLLAPSED_COUNT) + 1\n : 0;\n\n const contentHeight = rows - FIXED_CHROME - statusBarRows;\n const tooSmall = contentHeight < MIN_CONTENT_ROWS;\n\n const maxHeight = Math.max(1, contentHeight - HEADER_ROWS);\n // Half of clamped content width, minus paddingX on both sides\n const paneWidth = Math.floor((Math.min(120, columns) - 2) / 2) - 2;\n\n // Always render so ContentSequencer stays mounted (preserves activeIdx).\n // When too small, hide visually via display=\"none\".\n return (\n <Box\n flexDirection=\"column\"\n paddingX={1}\n display={tooSmall ? 'none' : 'flex'}\n >\n <Text bold color={Colors.accent}>\n Learn\n </Text>\n <Box height={1} />\n <ContentSequencer\n blocks={blocks}\n mode={TextRevealMode.SentenceBySentence}\n maxHeight={maxHeight}\n availableWidth={paneWidth}\n startDelay={2000}\n initialBlockIdx={store?.learnCardBlockIdx ?? 0}\n onBlockChange={(idx) => store?.setLearnCardBlockIdx(idx)}\n onSequenceComplete={onComplete}\n />\n </Box>\n );\n};\n","/**\n * TipsCard — Shows PostHog tips during the agent run.\n * Reactively shows/hides tips based on discovered features.\n * Supports toggling additional features via key bindings.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport type { WizardStore } from '@ui/tui/store';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport { DiscoveredFeature, AdditionalFeature } from '@lib/wizard-session';\n\n/** A discrete tip shown in the TipsCard during the agent run. */\nexport interface Tip {\n /** Unique identifier */\n id: string;\n /** Title line */\n title: string;\n /** Description shown below the title */\n description: string;\n /** Optional URL shown after the description */\n url?: string;\n /** When provided, the tip is only shown if this returns true */\n visible?: (store: WizardStore) => boolean;\n /** Optional key binding that toggles an AdditionalFeature */\n toggle?: {\n /** The key the user presses (lowercase) */\n key: string;\n /** The additional feature to enqueue */\n feature: AdditionalFeature;\n /** Label shown when toggled on */\n enabledLabel: string;\n /** Prompt shown when not yet toggled */\n prompt: string;\n /** Returns true if already toggled */\n isEnabled: (store: WizardStore) => boolean;\n };\n}\n\n/**\n * The default deck — generic PostHog onboarding tips, shown for any\n * program that doesn't supply its own via `ProgramConfig.getTips`.\n * Program-specific copy (e.g. the self-driving scout/source\n * explainers) lives in that program's content, not here — this stays the\n * neutral fallback.\n */\nexport const DEFAULT_TIPS: Tip[] = [\n {\n id: 'persons',\n title: 'You can also track people and groups with PostHog',\n description:\n \"Events can be associated with the humans who generate them, letting you understand a specific user or customer's situation.\",\n },\n {\n id: 'properties',\n title: 'Get way more detail using properties',\n description:\n 'Events and person records can have any properties you want. Track things like how they found your website, what subscription tier they choose, and much more.',\n },\n {\n id: 'slack',\n title: 'Use PostHog in Slack',\n description:\n 'Connect the PostHog Slack app to analyze data and ship product changes — deploy flags, open PRs, run queries — just by tagging @PostHog:',\n url: 'https://posthog.com/slack',\n },\n {\n id: 'stripe',\n title: 'You can track Stripe revenue with PostHog',\n description: 'Add Stripe as a data source while you wait:',\n url: 'https://app.posthog.com/project/data-warehouse/new-source?kind=Stripe',\n visible: (store) =>\n store.session.discoveredFeatures.includes(DiscoveredFeature.Stripe),\n },\n {\n id: 'llm',\n title: 'PostHog can also help you track your LLM costs',\n description: '',\n visible: (store) =>\n store.session.discoveredFeatures.includes(DiscoveredFeature.LLM),\n toggle: {\n key: 'l',\n feature: AdditionalFeature.LLM,\n enabledLabel: 'LLM analytics setup queued next',\n prompt: 'We detected LLM dependencies in your project.',\n isEnabled: (store) => store.session.llmOptIn,\n },\n },\n];\n\nexport const TipsCard = ({\n store,\n tips = DEFAULT_TIPS,\n}: {\n store: WizardStore;\n tips?: Tip[];\n}) => {\n useInput((input) => {\n for (const tip of tips) {\n if (\n tip.toggle &&\n input.toLowerCase() === tip.toggle.key &&\n (!tip.visible || tip.visible(store)) &&\n !tip.toggle.isEnabled(store)\n ) {\n store.enableFeature(tip.toggle.feature);\n }\n }\n });\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text bold color={Colors.accent}>\n Tips\n </Text>\n <Box height={1} />\n\n {tips\n .filter((tip) => !tip.visible || tip.visible(store))\n .map((tip) => (\n <Box key={tip.id} flexDirection=\"column\" marginBottom={1}>\n <Text>\n <Text color={Colors.accent}>{Icons.diamond} </Text>\n <Text bold>{tip.title}</Text>\n </Text>\n\n {tip.toggle ? (\n tip.toggle.isEnabled(store) ? (\n <Text color={Colors.success}>\n {Icons.check} {tip.toggle.enabledLabel}\n </Text>\n ) : (\n <Text dimColor>\n {tip.toggle.prompt} Press{' '}\n <Text bold color={Colors.accent}>\n {tip.toggle.key.toUpperCase()}\n </Text>{' '}\n to enable.\n </Text>\n )\n ) : (\n <Text dimColor>\n {tip.description}\n {tip.url && (\n <>\n {' '}\n <Text color=\"cyan\">{tip.url}</Text>\n </>\n )}\n </Text>\n )}\n </Box>\n ))}\n </Box>\n );\n};\n","/**\n * useTick — forces a re-render every `intervalMs`. Returns a monotonically\n * increasing counter, which is rarely needed — most callers just want the\n * re-render side effect.\n */\n\nimport { useEffect, useState } from 'react';\n\nexport function useTick(intervalMs: number): number {\n const [tick, setTick] = useState(0);\n useEffect(() => {\n const id = setInterval(() => setTick((t) => t + 1), intervalMs);\n return () => clearInterval(id);\n }, [intervalMs]);\n return tick;\n}\n","/**\n * WizardAmp palette — Matrix-green tones for the wizard's forced-dark canvas.\n */\n\nexport type VisualizerPalette = {\n /** Panel borders, scaffolding, dim glyphs */\n fade: string;\n bright: string;\n mid: string;\n head: string;\n book: readonly string[];\n deleteRed: string;\n upGreen: string;\n};\n\nexport const VISUALIZER_PALETTE: VisualizerPalette = {\n fade: '#0E7A0E',\n bright: '#7CFF7C',\n mid: '#22D622',\n head: '#E6FFE6',\n book: ['#22D622', '#7CFF7C', '#5BE05B', '#A0F0A0', '#36B536'],\n deleteRed: '#D63B22',\n upGreen: '#7CFF7C',\n};\n","/**\n * Shared scaffolding for the phase visuals — Matrix-green color, common\n * VisualProps shape, and the rounded `Panel` shell every visual sits in.\n *\n * Visuals each render their own grid then wrap it in `<Panel>` so phase\n * transitions stay visually continuous.\n */\n\nimport { Box } from 'ink';\nimport type { ReactNode } from 'react';\nimport { VISUALIZER_PALETTE } from './palette';\n\n// The deep, dimmed end of the Matrix code-rain palette. Used as the framing\n// color for every visual (panel border, axis lines, scaffolding glyphs).\nexport const MATRIX_FADE = VISUALIZER_PALETTE.fade;\n\nexport interface VisualProps {\n width: number;\n height: number;\n}\n\nexport const Panel = ({ children }: { children: ReactNode }) => (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={MATRIX_FADE}>\n {children}\n </Box>\n);\n","/**\n * MatrixRain — code-rain visual used for the codebase-scan phase.\n *\n * Independent of the phase orchestrator so it can be reused elsewhere\n * (e.g. standalone in a demo). `bordered` toggles the rounded green frame.\n */\n\nimport { Box, Text } from 'ink';\nimport { useEffect, useRef, useState } from 'react';\nimport { MATRIX_FADE } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\nconst {\n head: MATRIX_HEAD,\n bright: MATRIX_BRIGHT,\n mid: MATRIX_MID,\n} = VISUALIZER_PALETTE;\n\nconst DEFAULT_TICK_MS = 110;\nconst DEFAULT_MAX_TAIL = 7;\n// Half-width katakana + digits + a few symbols — the classic Matrix code\n// rain alphabet, all single-width in monospace terminals.\nconst RAIN_GLYPHS =\n 'ヲァィゥェォャュョッアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン0123456789Z<>=*+:.';\n\ninterface RainColumn {\n headY: number;\n speed: number;\n tail: number;\n glyphs: Map<number, string>;\n dormant: number;\n}\n\nfunction pickGlyph(): string {\n return RAIN_GLYPHS[Math.floor(Math.random() * RAIN_GLYPHS.length)];\n}\n\nfunction makeRainColumn(height: number, maxTail: number): RainColumn {\n return {\n headY: -Math.random() * height,\n speed: 0.3 + Math.random() * 0.9,\n tail: 3 + Math.floor(Math.random() * (maxTail - 2)),\n glyphs: new Map(),\n dormant: Math.floor(Math.random() * 18),\n };\n}\n\nfunction tickRainColumn(\n col: RainColumn,\n height: number,\n maxTail: number,\n): RainColumn {\n if (col.dormant > 0) {\n return { ...col, dormant: col.dormant - 1 };\n }\n const next = col.headY + col.speed;\n if (next > height + col.tail) {\n return makeRainColumn(height, maxTail);\n }\n const glyphs = new Map(col.glyphs);\n for (\n let y = Math.max(0, Math.ceil(col.headY));\n y <= Math.min(Math.floor(next), height - 1);\n y++\n ) {\n glyphs.set(y, pickGlyph());\n }\n // Glyphs in the tail occasionally mutate — gives the \"live data\" twitch.\n if (glyphs.size > 0 && Math.random() < 0.22) {\n const keys = [...glyphs.keys()];\n const k = keys[Math.floor(Math.random() * keys.length)];\n glyphs.set(k, pickGlyph());\n }\n return { ...col, headY: next, glyphs };\n}\n\ninterface MatrixRainProps {\n width: number;\n height: number;\n /** Frame interval in ms. Defaults to 110. */\n tickMs?: number;\n /** Maximum tail length per column. Defaults to 7. */\n maxTail?: number;\n /** Wrap the rain in a rounded border. Defaults to true. */\n bordered?: boolean;\n}\n\nexport const MatrixRain = ({\n width,\n height,\n tickMs = DEFAULT_TICK_MS,\n maxTail = DEFAULT_MAX_TAIL,\n bordered = true,\n}: MatrixRainProps) => {\n const columnsRef = useRef<RainColumn[]>(\n Array.from({ length: width }, () => makeRainColumn(height, maxTail)),\n );\n const [, setTick] = useState(0);\n\n useEffect(() => {\n const interval = setInterval(() => {\n columnsRef.current = columnsRef.current.map((c) =>\n tickRainColumn(c, height, maxTail),\n );\n setTick((t) => t + 1);\n }, tickMs);\n return () => clearInterval(interval);\n }, [height, maxTail, tickMs]);\n\n const columns = columnsRef.current;\n const body = Array.from({ length: height }).map((_, y) => (\n <Box key={y}>\n {columns.map((col, x) => {\n const glyph = col.glyphs.get(y);\n if (!glyph) return <Text key={x}> </Text>;\n const dist = col.headY - y;\n if (dist < 0 || dist > col.tail) return <Text key={x}> </Text>;\n if (dist < 1) {\n return (\n <Text key={x} bold color={MATRIX_HEAD}>\n {glyph}\n </Text>\n );\n }\n if (dist < 2) {\n return (\n <Text key={x} color={MATRIX_BRIGHT}>\n {glyph}\n </Text>\n );\n }\n if (dist < col.tail * 0.55) {\n return (\n <Text key={x} color={MATRIX_MID}>\n {glyph}\n </Text>\n );\n }\n return (\n <Text key={x} color={MATRIX_FADE} dimColor>\n {glyph}\n </Text>\n );\n })}\n </Box>\n ));\n\n if (!bordered) {\n return <Box flexDirection=\"column\">{body}</Box>;\n }\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={MATRIX_FADE}>\n {body}\n </Box>\n );\n};\n","/**\n * LibraryShelf — skill-selection phase.\n *\n * A row of book spines. One spine peels forward each cycle, the chosen\n * title hovers next to it, then it slides home and the next one is picked.\n */\n\nimport { Box, Text } from 'ink';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { MATRIX_FADE, Panel, type VisualProps } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\nconst BOOK_LABELS = [\n 'nx',\n 'rt',\n 'sv',\n 'fl',\n 'jg',\n 'rb',\n 'go',\n 'dj',\n 'fa',\n 'lv',\n 'ts',\n 'py',\n];\nconst BOOK_COLORS = VISUALIZER_PALETTE.book;\n\nexport const LibraryShelf = ({ width, height }: VisualProps) => {\n const tick = useTick(380);\n const bookCount = Math.min(Math.floor((width - 2) / 2), BOOK_LABELS.length);\n // Cycle phases: 0 = at rest, 1 = selecting, 2 = pulled out, 3 = returning.\n const cyclePos = tick % (bookCount * 4);\n const selectedIdx = Math.floor(cyclePos / 4);\n const phase = cyclePos % 4;\n const offset = phase === 0 ? 0 : phase === 1 ? 1 : phase === 2 ? 2 : 1;\n const wobble = phase === 2 && tick % 2 === 0 ? 1 : 0;\n\n const shelfY = Math.floor(height / 2) - 1;\n const rows: string[][] = Array.from({ length: height }, () =>\n new Array(width).fill(' '),\n );\n\n for (let i = 0; i < bookCount; i++) {\n const x = 1 + i * 2;\n const isSelected = i === selectedIdx;\n const shift = isSelected ? offset : 0;\n const wob = isSelected && wobble ? -1 : 0;\n if (x + shift >= width) continue;\n rows[shelfY - 1][x + shift] = '█';\n rows[shelfY][x + shift] = BOOK_LABELS[i][0];\n rows[shelfY + 1][x + shift] = BOOK_LABELS[i][1];\n rows[shelfY + 2 + wob]?.[x + shift] !== undefined &&\n (rows[shelfY + 2 + wob][x + shift] = '█');\n }\n\n // Shelf board underneath\n const boardY = shelfY + 3;\n if (boardY < height) {\n for (let x = 0; x < width; x++) rows[boardY][x] = '─';\n }\n // Floating label next to the selected book\n if (phase === 2) {\n const labelStartX = 1 + selectedIdx * 2 + 4;\n const labelText = BOOK_LABELS[selectedIdx] + '-app';\n for (let c = 0; c < labelText.length && labelStartX + c < width; c++) {\n rows[shelfY][labelStartX + c] = labelText[c];\n }\n if (labelStartX - 1 < width && labelStartX - 1 >= 0) {\n rows[shelfY][labelStartX - 1] = '▶';\n }\n }\n\n return (\n <Panel>\n {rows.map((row, y) => (\n <Box key={y}>\n {row.map((ch, x) => {\n if (ch === ' ') return <Text key={x}> </Text>;\n if (ch === '─') {\n return (\n <Text key={x} color={MATRIX_FADE} dimColor>\n ─\n </Text>\n );\n }\n if (ch === '▶') {\n return (\n <Text key={x} bold color={VISUALIZER_PALETTE.head}>\n ▶\n </Text>\n );\n }\n const booksColor =\n BOOK_COLORS[\n (Math.floor((x - 1) / 2) + 17 * y) % BOOK_COLORS.length\n ];\n const selectedX = 1 + selectedIdx * 2 + offset;\n const isSel = x === selectedX;\n return (\n <Text\n key={x}\n bold={isSel}\n color={isSel ? VISUALIZER_PALETTE.head : booksColor}\n >\n {ch}\n </Text>\n );\n })}\n </Box>\n ))}\n </Panel>\n );\n};\n","/**\n * CrateStack — dependency-install phase.\n *\n * Boxes drop from the top and stack at the bottom. Each new arrival lands\n * with a tiny shake.\n */\n\nimport { Box, Text } from 'ink';\nimport { useRef } from 'react';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { Panel, type VisualProps } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\nconst PACKAGE_NAMES = [\n 'posthog-js',\n 'posthog-py',\n 'posthog-rb',\n 'posthog-go',\n 'posthog-node',\n 'react-ph',\n 'next-ph',\n 'svelte-ph',\n 'ph-mcp',\n 'ph-ai',\n];\n// Crate width is derived from the longest label so names never get sliced.\nconst CRATE_CONTENT_W = Math.max(...PACKAGE_NAMES.map((n) => n.length));\nconst CRATE_W = CRATE_CONTENT_W + 2;\n\ninterface CrateState {\n stack: { label: string; x: number; landedAt: number }[];\n falling: { label: string; x: number; y: number } | null;\n spawnCooldown: number;\n}\n\nexport const CrateStack = ({ width, height }: VisualProps) => {\n const tick = useTick(95);\n const stateRef = useRef<CrateState>({\n stack: [],\n falling: null,\n spawnCooldown: 0,\n });\n\n const state = stateRef.current;\n const crateW = CRATE_W;\n const crateH = 1;\n const floorY = height - 1;\n\n if (state.falling) {\n state.falling.y += 1;\n const collisionStackHeight =\n state.stack.filter((c) => Math.abs(c.x - state.falling!.x) < crateW - 1)\n .length * crateH;\n if (state.falling.y >= floorY - collisionStackHeight) {\n state.stack.push({\n label: state.falling.label,\n x: state.falling.x,\n landedAt: tick,\n });\n state.falling = null;\n state.spawnCooldown = 3;\n }\n } else if (state.spawnCooldown > 0) {\n state.spawnCooldown -= 1;\n } else if (state.stack.length < Math.floor(height / crateH) - 1) {\n state.falling = {\n label: PACKAGE_NAMES[Math.floor(Math.random() * PACKAGE_NAMES.length)],\n x: 2 + Math.floor(Math.random() * Math.max(1, width - crateW - 4)),\n y: -1,\n };\n } else {\n // Stack full — wipe and restart for the next cycle.\n if (tick % 20 === 0) {\n state.stack = [];\n }\n }\n\n const grid: string[][] = Array.from({ length: height }, () =>\n new Array(width).fill(' '),\n );\n const drawCrate = (cx: number, cy: number, label: string, shake: number) => {\n const x = cx + shake;\n if (cy < 0 || cy >= height) return;\n const labelTrimmed = label.slice(0, crateW - 2);\n const padded = `[${labelTrimmed}]`.padEnd(crateW, ' ');\n for (let i = 0; i < crateW && x + i < width; i++) {\n if (x + i >= 0) grid[cy][x + i] = padded[i];\n }\n };\n\n state.stack.forEach((c, idx) => {\n const cy = floorY - idx;\n const shake =\n tick - c.landedAt === 0 ? 1 : tick - c.landedAt === 1 ? -1 : 0;\n drawCrate(c.x, cy, c.label, shake);\n });\n if (state.falling) {\n drawCrate(state.falling.x, state.falling.y, state.falling.label, 0);\n }\n\n return (\n <Panel>\n {grid.map((row, y) => (\n <Box key={y}>\n {row.map((ch, x) => {\n if (ch === ' ') return <Text key={x}> </Text>;\n const isFalling =\n state.falling &&\n y === state.falling.y &&\n Math.abs(x - state.falling.x) < crateW;\n return (\n <Text\n key={x}\n bold={isFalling}\n color={\n isFalling ? VISUALIZER_PALETTE.head : VISUALIZER_PALETTE.mid\n }\n >\n {ch}\n </Text>\n );\n })}\n </Box>\n ))}\n </Panel>\n );\n};\n","/**\n * DiffCascade — code-edits phase.\n *\n * + and - code lines scroll upward continuously. Occasional comment-rewrite\n * gag: a \"// hmm…\" line appears, gets - struck out, then a + replaces it.\n */\n\nimport { Box, Text } from 'ink';\nimport { useRef } from 'react';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { MATRIX_FADE, Panel, type VisualProps } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\nconst CODE_SNIPPETS = [\n \"import posthog from 'posthog-js'\",\n 'posthog.init(KEY, { host: HOST })',\n '<PostHogProvider client={posthog}>',\n ' {children}',\n '</PostHogProvider>',\n \"posthog.capture('page_viewed')\",\n \"posthog.capture('signup_started')\",\n 'posthog.identify(user.id, { email })',\n \"if (process.env.NODE_ENV !== 'test') posthog.init(KEY)\",\n 'export const posthog = new PostHog(KEY)',\n '// TODO: enable replay',\n 'window.posthog = posthog',\n];\n\nconst WHIMSY_COMMENTS = [\n '// hmm — that should be a hook',\n '// wait, refactor incoming',\n '// posthog says hi',\n];\n\ninterface DiffLine {\n sign: '+' | '-' | ' ';\n text: string;\n}\n\nexport const DiffCascade = ({ width, height }: VisualProps) => {\n const tick = useTick(280);\n const linesRef = useRef<DiffLine[]>([]);\n\n if (linesRef.current.length === 0) {\n for (let i = 0; i < height; i++) {\n linesRef.current.push({\n sign: Math.random() < 0.75 ? '+' : '-',\n text: CODE_SNIPPETS[Math.floor(Math.random() * CODE_SNIPPETS.length)],\n });\n }\n }\n // Scroll up by one each tick, push a new line at bottom.\n linesRef.current.shift();\n const whimsy = tick % 23 === 0;\n linesRef.current.push({\n sign: whimsy ? '-' : Math.random() < 0.78 ? '+' : '-',\n text: whimsy\n ? WHIMSY_COMMENTS[Math.floor(Math.random() * WHIMSY_COMMENTS.length)]\n : CODE_SNIPPETS[Math.floor(Math.random() * CODE_SNIPPETS.length)],\n });\n\n const lines = linesRef.current;\n return (\n <Panel>\n {Array.from({ length: height }).map((_, y) => {\n const line = lines[y];\n const cap = width - 2;\n const text = `${line.sign} ${line.text}`.slice(0, cap);\n const color =\n line.sign === '+'\n ? VISUALIZER_PALETTE.mid\n : line.sign === '-'\n ? VISUALIZER_PALETTE.deleteRed\n : MATRIX_FADE;\n return (\n <Box key={y}>\n <Text color={color}>{text.padEnd(cap, ' ')}</Text>\n </Box>\n );\n })}\n </Panel>\n );\n};\n","/**\n * Tumblers — env-setup phase.\n *\n * Pins fall into a lock cylinder one by one; when all six align the bolt\n * pulses green for a beat, then the cycle restarts.\n */\n\nimport { Box, Text } from 'ink';\nimport { useRef } from 'react';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { MATRIX_FADE, Panel, type VisualProps } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\ninterface TumblerState {\n heights: number[]; // settled height per pin, 0 = unset\n current: number; // index of pin currently falling\n fallY: number; // current Y of the falling pin (in rows)\n pulse: number; // pulse counter once all pins land\n}\n\nexport const Tumblers = ({ width, height }: VisualProps) => {\n const tick = useTick(80);\n const pinCount = Math.min(Math.floor((width - 2) / 2), 6);\n const stateRef = useRef<TumblerState>({\n heights: new Array(pinCount).fill(0),\n current: 0,\n fallY: 0,\n pulse: 0,\n });\n const state = stateRef.current;\n\n const cylinderTop = 1;\n const cylinderBottom = height - 2;\n const targetForPin = (i: number) =>\n cylinderBottom - 1 - (i % 3) - Math.floor(i / 2);\n\n if (state.pulse > 0) {\n state.pulse -= 1;\n if (state.pulse === 0) {\n state.heights = new Array(pinCount).fill(0);\n state.current = 0;\n state.fallY = 0;\n }\n } else if (state.current < pinCount) {\n state.fallY += 1;\n if (state.fallY >= targetForPin(state.current)) {\n state.heights[state.current] = targetForPin(state.current);\n state.current += 1;\n state.fallY = cylinderTop;\n }\n } else {\n state.pulse = 14;\n }\n\n const grid: string[][] = Array.from({ length: height }, () =>\n new Array(width).fill(' '),\n );\n // Outer cylinder walls\n for (let y = 0; y < height; y++) {\n grid[y][0] = '│';\n grid[y][width - 1] = '│';\n }\n // Top notches (where pins enter)\n for (let i = 0; i < pinCount; i++) {\n const x = 1 + i * 2 + 1;\n if (x < width) grid[0][x] = '▼';\n }\n // Floor\n for (let x = 1; x < width - 1; x++) grid[height - 1][x] = '─';\n // Settled pins\n for (let i = 0; i < pinCount; i++) {\n const pinX = 1 + i * 2 + 1;\n if (pinX >= width) continue;\n const top = state.heights[i] || cylinderTop;\n for (let y = top; y <= cylinderBottom; y++) {\n grid[y][pinX] = '█';\n }\n }\n // Falling pin\n if (state.pulse === 0 && state.current < pinCount) {\n const pinX = 1 + state.current * 2 + 1;\n if (pinX < width) grid[state.fallY][pinX] = '█';\n }\n\n const pulsing = state.pulse > 0;\n const pulseBright = pulsing && tick % 2 === 0;\n return (\n <Panel>\n {grid.map((row, y) => (\n <Box key={y}>\n {row.map((ch, x) => {\n if (ch === ' ') return <Text key={x}> </Text>;\n if (ch === '│' || ch === '─' || ch === '▼') {\n const c = pulsing\n ? pulseBright\n ? VISUALIZER_PALETTE.bright\n : MATRIX_FADE\n : MATRIX_FADE;\n return (\n <Text key={x} color={c} dimColor={!pulsing}>\n {ch}\n </Text>\n );\n }\n const isFalling =\n state.pulse === 0 &&\n state.current < pinCount &&\n y === state.fallY &&\n x === 1 + state.current * 2 + 1;\n const color = pulsing\n ? pulseBright\n ? VISUALIZER_PALETTE.head\n : VISUALIZER_PALETTE.bright\n : isFalling\n ? VISUALIZER_PALETTE.head\n : VISUALIZER_PALETTE.mid;\n return (\n <Text key={x} bold={pulsing || isFalling} color={color}>\n {ch}\n </Text>\n );\n })}\n </Box>\n ))}\n </Panel>\n );\n};\n","/**\n * DashboardGrid — dashboards phase.\n *\n * 2×2 grid of mini-charts to evoke a real PostHog dashboard. When the area\n * is too small, the layout collapses to 1×2 or 1×1 so something always\n * renders.\n */\n\nimport { Box, Text } from 'ink';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { MATRIX_FADE, Panel, type VisualProps } from './panel';\nimport { VISUALIZER_PALETTE } from './palette';\n\ntype TileKind = 'bars' | 'line' | 'gauge' | 'pulse';\n\nconst DASHBOARD_TILES: Array<{ title: string; kind: TileKind }> = [\n { title: 'Visitors', kind: 'bars' },\n { title: 'Sessions', kind: 'line' },\n { title: 'Revenue', kind: 'gauge' },\n { title: 'Errors', kind: 'pulse' },\n];\n\nconst SPARK_GLYPHS = '▁▂▃▄▅▆▇█';\n\nexport const DashboardGrid = ({ width, height }: VisualProps) => {\n const tick = useTick(220);\n const grid: string[][] = Array.from({ length: height }, () =>\n new Array(width).fill(' '),\n );\n\n // Collapse to fewer cells when there isn't room for a real 2×2.\n const cols = width >= 22 ? 2 : 1;\n const rows = height >= 7 ? 2 : 1;\n const vSplit = cols === 2 ? Math.floor(width / 2) : -1;\n const hSplit = rows === 2 ? Math.floor(height / 2) : -1;\n\n if (vSplit >= 0) {\n for (let y = 0; y < height; y++) grid[y][vSplit] = '│';\n }\n if (hSplit >= 0) {\n for (let x = 0; x < width; x++) grid[hSplit][x] = '─';\n if (vSplit >= 0) grid[hSplit][vSplit] = '┼';\n }\n\n const writeText = (x0: number, y0: number, maxW: number, text: string) => {\n if (y0 < 0 || y0 >= height) return;\n const slice = text.slice(0, Math.max(0, maxW));\n for (let i = 0; i < slice.length; i++) {\n if (x0 + i >= 0 && x0 + i < width) grid[y0][x0 + i] = slice[i];\n }\n };\n\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const tile = DASHBOARD_TILES[r * cols + c];\n const tileX = c === 0 ? 0 : vSplit + 1;\n const tileY = r === 0 ? 0 : hSplit + 1;\n const tileW =\n cols === 2 ? (c === 0 ? vSplit : width - vSplit - 1) : width;\n const tileH =\n rows === 2 ? (r === 0 ? hSplit : height - hSplit - 1) : height;\n\n const innerX = tileX;\n const innerW = Math.max(1, tileW);\n const titleY = tileY;\n const valueY = tileY + tileH - 1;\n const chartY0 = tileY + 1;\n const chartY1 = Math.max(chartY0, valueY - 1);\n const chartH = Math.max(1, chartY1 - chartY0 + 1);\n const seed = (r * cols + c) * 13;\n\n writeText(innerX, titleY, innerW, tile.title);\n renderTile(\n grid,\n tile.kind,\n innerX,\n chartY0,\n innerW,\n chartH,\n tick,\n seed,\n width,\n );\n writeText(innerX, valueY, innerW, tileValue(tile.kind, tick, seed));\n }\n }\n\n return (\n <Panel>\n {grid.map((row, y) => (\n <Box key={y}>\n {row.map((ch, x) => {\n if (ch === ' ') return <Text key={x}> </Text>;\n if (ch === '│' || ch === '─' || ch === '┼') {\n return (\n <Text key={x} color={MATRIX_FADE} dimColor>\n {ch}\n </Text>\n );\n }\n if (SPARK_GLYPHS.includes(ch) || ch === '█') {\n return (\n <Text key={x} color={VISUALIZER_PALETTE.mid}>\n {ch}\n </Text>\n );\n }\n if (ch === '●' || ch === '∙' || ch === '·') {\n const color =\n ch === '●'\n ? VISUALIZER_PALETTE.head\n : ch === '∙'\n ? VISUALIZER_PALETTE.bright\n : VISUALIZER_PALETTE.mid;\n return (\n <Text key={x} bold={ch === '●'} color={color}>\n {ch}\n </Text>\n );\n }\n if (ch === '▲' || ch === '▼') {\n return (\n <Text\n key={x}\n bold\n color={\n ch === '▲'\n ? VISUALIZER_PALETTE.upGreen\n : VISUALIZER_PALETTE.deleteRed\n }\n >\n {ch}\n </Text>\n );\n }\n return (\n <Text key={x} color={VISUALIZER_PALETTE.bright}>\n {ch}\n </Text>\n );\n })}\n </Box>\n ))}\n </Panel>\n );\n};\n\nfunction renderTile(\n grid: string[][],\n kind: TileKind,\n x0: number,\n y0: number,\n w: number,\n h: number,\n tick: number,\n seed: number,\n gridW: number,\n): void {\n const set = (x: number, y: number, ch: string) => {\n if (y < 0 || y >= grid.length) return;\n if (x < 0 || x >= gridW) return;\n grid[y][x] = ch;\n };\n\n if (kind === 'bars') {\n // Vertical bars driven by a slow per-column sine. Most tile feels\n // \"spectrum analyzer\"-y.\n for (let i = 0; i < w; i++) {\n const t = tick * 0.18 + (i + seed) * 0.6;\n const level = 0.55 + 0.35 * Math.sin(t) + 0.1 * Math.sin(t * 2.7);\n const filled = Math.max(0, Math.min(h, Math.round(level * h)));\n for (let j = 0; j < filled; j++) {\n set(x0 + i, y0 + h - 1 - j, '█');\n }\n if (filled > 0 && filled < h) {\n const frac = level * h - Math.floor(level * h);\n const glyph =\n SPARK_GLYPHS[Math.floor(frac * (SPARK_GLYPHS.length - 1))];\n set(x0 + i, y0 + h - filled, glyph);\n }\n }\n } else if (kind === 'line') {\n // Ascending trend with a single deterministic spike.\n const spikeAt = (((tick / 12) | 0) + seed) % Math.max(1, w);\n for (let i = 0; i < w; i++) {\n const norm = i / Math.max(1, w - 1);\n const base = h - 1 - norm * (h - 1);\n let yf = base + 0.6 * Math.sin(i * 0.7 + seed + tick * 0.05);\n if (i === spikeAt) yf = Math.max(0, base - 1.5);\n const y = Math.max(0, Math.min(h - 1, Math.round(yf)));\n const dist = Math.abs(i - (w - 1));\n const ch = dist === 0 ? '●' : dist < 3 ? '∙' : '·';\n set(x0 + i, y0 + y, ch);\n }\n } else if (kind === 'gauge') {\n // Progress bar that fills, drains, refills. Suggests a goal/target.\n const cycle = (tick + seed) % 40;\n const pct = cycle < 30 ? cycle / 30 : 1 - (cycle - 30) / 10;\n const midY = y0 + Math.floor(h / 2);\n const filled = Math.max(0, Math.min(w, Math.round(pct * w)));\n for (let i = 0; i < w; i++) {\n set(x0 + i, midY, i < filled ? '█' : '·');\n }\n } else if (kind === 'pulse') {\n // Mostly quiet bars with occasional spikes — like an error rate that\n // mostly hovers low.\n for (let i = 0; i < w; i++) {\n const t = (i + seed + Math.floor(tick / 3)) % 17;\n let level: number;\n if (t === 0) level = 0.9;\n else if (t === 1 || t === 16) level = 0.5;\n else level = 0.12 + 0.06 * Math.sin((i + tick) * 0.5);\n const filled = Math.max(1, Math.min(h, Math.round(level * h)));\n for (let j = 0; j < filled; j++) {\n set(x0 + i, y0 + h - 1 - j, '█');\n }\n }\n }\n}\n\nfunction tileValue(kind: TileKind, tick: number, seed: number): string {\n const wave = 0.5 + 0.5 * Math.sin(tick * 0.05 + seed);\n if (kind === 'bars') {\n const n = Math.round(8000 + wave * 6000);\n return `${(n / 1000).toFixed(1)}k ▲`;\n }\n if (kind === 'line') {\n const n = 2 + wave * 4;\n return `${n.toFixed(1)}% ▲`;\n }\n if (kind === 'gauge') {\n const n = Math.round(20 + wave * 60);\n return `$${n}k`;\n }\n // pulse\n const n = Math.round(1 + wave * 5);\n return `${n} ▼`;\n}\n","/**\n * Phase visuals — ambient ASCII visualizations of what the agent is currently\n * doing. The active phase is derived from the in-progress task labels (best-\n * effort heuristic). Each phase has its own component (under ./visualizer);\n * the orchestrator `PhaseVisual` picks which one to render.\n *\n * Width and height are passed in from the parent so visuals adapt to the\n * column they're placed in.\n */\n\nimport { Box, Text, measureElement, type DOMElement } from 'ink';\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react';\nimport type { WizardStore } from '@ui/tui/store';\nimport { useTick } from '@ui/tui/hooks/useTick';\nimport { AgentPhase } from '@lib/agent/agent-phase';\nimport { MATRIX_FADE } from './visualizer/panel';\nimport { VISUALIZER_PALETTE } from './visualizer/palette';\nimport { MatrixRain } from './visualizer/MatrixRain';\nimport { LibraryShelf } from './visualizer/LibraryShelf';\nimport { CrateStack } from './visualizer/CrateStack';\nimport { DiffCascade } from './visualizer/DiffCascade';\nimport { Tumblers } from './visualizer/Tumblers';\nimport { DashboardGrid } from './visualizer/DashboardGrid';\n\nexport { AgentPhase };\n\n// Track titles (PostHog being the \"artist\" — see VisualizerTab render).\nconst PHASE_LABELS: Record<AgentPhase, string> = {\n [AgentPhase.CodebaseScan]: 'Reading the Code',\n [AgentPhase.SkillInstall]: 'Picking the Right Skill',\n [AgentPhase.DepInstall]: 'Installing Packages',\n [AgentPhase.CodeEdits]: 'Editing Source',\n [AgentPhase.EnvSetup]: 'Wiring Up Secrets',\n [AgentPhase.Dashboards]: 'Building Dashboards',\n};\n\n/** Reads the active phase from the store. The agent loop pushes it in via\n * `getUI().setStage(...)` whenever a new tool fires. */\nexport function useAgentPhase(store: WizardStore): AgentPhase {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n return (store.currentStage?.stage as AgentPhase) ?? AgentPhase.CodebaseScan;\n}\n\ninterface PhaseVisualProps {\n store: WizardStore;\n width: number;\n height: number;\n}\n\nexport const PhaseVisual = ({ store, width, height }: PhaseVisualProps) => {\n const phase = useAgentPhase(store);\n return <PhaseBody phase={phase} width={width} height={height} />;\n};\n\n/**\n * VisualizerTab — Winamp-style fullscreen take on the phase visual.\n * \"NOW PLAYING\" header, centered visual, transport bar with elapsed time.\n *\n * Sizes itself off the *measured* container rather than the raw terminal so\n * the tab bar / hints / status panel above don't get pushed off-screen on\n * short terminals. When height runs out, chrome rows drop in order:\n * transport bar first, then track title, then the NOW PLAYING header.\n */\nexport const VisualizerTab = ({ store }: { store: WizardStore }) => {\n const phase = useAgentPhase(store);\n const containerRef = useRef<DOMElement>(null);\n const [size, setSize] = useState<{ width: number; height: number }>({\n width: 0,\n height: 0,\n });\n const tick = useTick(EQ_TICK_MS);\n\n useEffect(() => {\n if (!containerRef.current) return;\n const m = measureElement(containerRef.current);\n if (m.width !== size.width || m.height !== size.height) {\n setSize({ width: m.width, height: m.height });\n }\n }, [tick, size.width, size.height]);\n\n // Each chrome line below counts the row + its 1-row margin.\n const HEADER_ROWS = 2;\n const TITLE_ROWS = 2;\n const TRANSPORT_ROWS = 2;\n const BORDER_ROWS = 2;\n const MIN_VISUAL_H = 5;\n\n const availH = size.height;\n const availW = size.width;\n // Drop chrome rows greedily from the bottom up if there isn't room for the\n // minimum visual plus border.\n let chromeBudget = BORDER_ROWS + HEADER_ROWS + TITLE_ROWS + TRANSPORT_ROWS;\n let showHeader = true;\n let showTitle = true;\n let showTransport = true;\n if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {\n showTransport = false;\n chromeBudget -= TRANSPORT_ROWS;\n }\n if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {\n showTitle = false;\n chromeBudget -= TITLE_ROWS;\n }\n if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {\n showHeader = false;\n chromeBudget -= HEADER_ROWS;\n }\n\n const visualH =\n availH > 0\n ? Math.max(MIN_VISUAL_H, Math.min(18, availH - chromeBudget))\n : MIN_VISUAL_H;\n const visualW = availW > 0 ? Math.max(20, Math.min(64, availW - 12)) : 40;\n\n // Anchor both the elapsed clock and the EQ beat grid to the stage's\n // startedAt — a fresh stage drops the needle on beat 1.\n const now = Date.now();\n const beatTimeMs = now - (store.currentStage?.startedAt ?? now);\n const elapsedSec = Math.max(0, Math.floor(beatTimeMs / 1000));\n const timeStr = formatElapsed(elapsedSec);\n const eqLevelsRef = useRef<number[]>(new Array(EQ_BARS).fill(0));\n const equalizer = renderMiniEqualizer(beatTimeMs, eqLevelsRef.current);\n\n return (\n <Box\n ref={containerRef}\n flexDirection=\"column\"\n flexGrow={1}\n alignItems=\"center\"\n justifyContent=\"center\"\n overflow=\"hidden\"\n >\n {showHeader && (\n <Box flexDirection=\"row\" marginBottom={1}>\n <Text color={MATRIX_FADE}>┌─</Text>\n <Text bold color={VISUALIZER_PALETTE.bright}>\n {' ► NOW PLAYING '}\n </Text>\n <Text color={MATRIX_FADE}>─┐</Text>\n </Box>\n )}\n {showTitle && (\n <Box marginBottom={1}>\n <Text bold color={VISUALIZER_PALETTE.head}>\n {PHASE_LABELS[phase]} - PostHog\n </Text>\n </Box>\n )}\n <PhaseBody phase={phase} width={visualW} height={visualH} />\n {showTransport && (\n <Box flexDirection=\"row\" marginTop={1} gap={2}>\n <Text color={VISUALIZER_PALETTE.mid}>[{timeStr}]</Text>\n <Text color={MATRIX_FADE}>{equalizer}</Text>\n <Text color={VISUALIZER_PALETTE.mid}>WizardAmp</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nfunction formatElapsed(totalSec: number): string {\n const m = Math.floor(totalSec / 60);\n const s = totalSec % 60;\n return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;\n}\n\n// 120 BPM techno in 4/4: a beat is 500 ms, a bar (measure) is 4 beats = 2 s.\nconst BPM = 120;\nconst BEAT_MS = (60 / BPM) * 1000;\nconst EQ_BARS = 12;\nconst EQ_TICK_MS = 67; // ~15 fps\n// 0.08 / frame at ~15 fps ≈ 0.8 s peak-to-silence. Scale with EQ_TICK_MS if\n// you change the frame rate so the decay *time* stays the same.\nconst EQ_FALL_PER_FRAME = 0.08;\n\n// One \"drum hit\": a value that snaps to 1.0 on the beat and fades out before\n// the next one. Higher `decay` = snappier (quicker fade). `phaseMs` shifts\n// when the hit fires (e.g. snare lands on beat 2, not beat 1).\nfunction pulse(\n t: number,\n periodMs: number,\n decay: number,\n phaseMs = 0,\n): number {\n // `+ periodMs * 100` keeps the modulo positive when phaseMs > t (start of stage).\n const since = (t - phaseMs + periodMs * 100) % periodMs;\n return Math.exp((-decay * since) / periodMs);\n}\n\nconst EQ_GLYPHS = '▁▂▃▄▅▆▇█';\n\nfunction renderMiniEqualizer(beatTimeMs: number, levels: number[]): string {\n // Voices — what you'd hear in a techno track:\n // kick = the BOOM on every beat (the four-on-the-floor thing)\n // bass = a longer-ringing sub note that overlaps the kick (the rumble)\n // clap = the CLAP on beats 2 & 4 (the backbeat)\n // hat8 = the TSSSS on eighth notes (twice per beat)\n // hat16 = the faster ticka-ticka on sixteenth notes\n // pad = a slow background hum so the track never feels totally silent\n const kick = pulse(beatTimeMs, BEAT_MS, 4);\n const bass = pulse(beatTimeMs, BEAT_MS, 1.5);\n const clap = pulse(beatTimeMs, BEAT_MS * 2, 5, BEAT_MS);\n const hat8 = pulse(beatTimeMs, BEAT_MS / 2, 8);\n const hat16 = pulse(beatTimeMs, BEAT_MS / 4, 12);\n // Slow ~4 s wobble between 0.05 and 0.35 — ambient floor.\n const pad = 0.2 + 0.15 * Math.sin((2 * Math.PI * beatTimeMs) / 4000);\n\n // Each of the 12 bars is a mix of voices, going low → high like a real\n // spectrum analyzer. Low bars feel the kick + bass, mid bars feel the clap,\n // high bars feel the hats. Pad layered in everywhere so nothing dies.\n const mix = [\n bass * 0.7 + kick * 0.5 + pad,\n bass * 0.6 + kick * 0.6 + pad * 0.9,\n bass * 0.4 + kick * 0.7 + pad * 0.8,\n kick * 0.6 + clap * 0.3 + pad * 0.7,\n kick * 0.4 + clap * 0.5 + pad * 0.7,\n clap * 0.7 + hat8 * 0.3 + pad * 0.6,\n clap * 0.6 + hat8 * 0.5 + pad * 0.5,\n hat8 * 0.7 + clap * 0.3 + pad * 0.5,\n hat8 * 0.5 + hat16 * 0.4 + pad * 0.4,\n hat8 * 0.4 + hat16 * 0.5 + pad * 0.4,\n hat16 * 0.6 + hat8 * 0.3 + pad * 0.3,\n hat16 * 0.7 + pad * 0.3,\n ];\n\n // Winamp-style smoothing: each bar jumps up instantly to the current audio\n // level (so kicks read as snap), then drifts down by EQ_FALL_PER_FRAME each\n // frame until the next hit catches it.\n let out = '';\n for (let i = 0; i < EQ_BARS; i++) {\n const target = Math.min(1, mix[i]);\n levels[i] = Math.max(target, levels[i] - EQ_FALL_PER_FRAME);\n out += EQ_GLYPHS[Math.floor(levels[i] * (EQ_GLYPHS.length - 1))];\n }\n return out;\n}\n\nconst PhaseBody = ({\n phase,\n width,\n height,\n}: {\n phase: AgentPhase;\n width: number;\n height: number;\n}) => {\n switch (phase) {\n case AgentPhase.CodebaseScan:\n return <MatrixRain width={width} height={height} />;\n case AgentPhase.SkillInstall:\n return <LibraryShelf width={width} height={height} />;\n case AgentPhase.DepInstall:\n return <CrateStack width={width} height={height} />;\n case AgentPhase.CodeEdits:\n return <DiffCascade width={width} height={height} />;\n case AgentPhase.EnvSetup:\n return <Tumblers width={width} height={height} />;\n case AgentPhase.Dashboards:\n return <DashboardGrid width={width} height={height} />;\n }\n};\n","/**\n * ServiceHealthList — Shared component for displaying service health status.\n *\n * Used by HealthCheckScreen (blocking services only) and HealthWarningsTab (all services).\n */\n\nimport { Box, Text } from 'ink';\nimport {\n ServiceHealthStatus,\n type AllServicesHealth,\n type ComponentHealthResult,\n type ComponentStatus,\n type HealthCheckKey,\n} from '@lib/health-checks/types';\nimport { SERVICE_LABELS } from '@lib/health-checks/readiness';\nimport { Icons } from '@ui/tui/styles';\n\n/** Keys that are component-level detail — shown inline under their parent. */\nconst COMPONENT_KEYS: HealthCheckKey[] = [\n 'posthogComponents',\n 'npmComponents',\n 'cloudflareComponents',\n];\n\n/** Map component key → its parent \"overall\" key */\nconst COMPONENT_PARENT: Partial<Record<HealthCheckKey, HealthCheckKey>> = {\n posthogComponents: 'posthogOverall',\n npmComponents: 'npmOverall',\n cloudflareComponents: 'cloudflareOverall',\n};\n\nfunction statusIcon(status: ServiceHealthStatus): {\n icon: string;\n color: string;\n} {\n switch (status) {\n case ServiceHealthStatus.Down:\n return { icon: Icons.squareFilled, color: 'red' };\n case ServiceHealthStatus.Degraded:\n return { icon: Icons.squareFilled, color: '#DC9300' };\n case ServiceHealthStatus.NoConnection:\n return { icon: Icons.squareFilled, color: 'gray' };\n case ServiceHealthStatus.Healthy:\n return { icon: Icons.check, color: 'green' };\n }\n}\n\ninterface ServiceHealthListProps {\n health: AllServicesHealth;\n /** If set, only show services with these keys */\n filterKeys?: HealthCheckKey[];\n /** Show healthy services (default true) */\n showHealthy?: boolean;\n}\n\nexport const ServiceHealthList = ({\n health,\n filterKeys,\n showHealthy = true,\n}: ServiceHealthListProps) => {\n const topLevelKeys = (Object.keys(health) as HealthCheckKey[]).filter(\n (k) => !COMPONENT_KEYS.includes(k),\n );\n\n const keysToShow = filterKeys\n ? topLevelKeys.filter((k) => filterKeys.includes(k))\n : topLevelKeys;\n\n return (\n <Box flexDirection=\"column\" paddingLeft={1}>\n {keysToShow.map((key) => {\n const result = health[key];\n if (!showHealthy && result.status === ServiceHealthStatus.Healthy) {\n return null;\n }\n\n const { icon, color } = statusIcon(result.status);\n const label = SERVICE_LABELS[key];\n\n // Find component-level details if this is a parent key\n const componentKey = (\n Object.entries(COMPONENT_PARENT) as [HealthCheckKey, HealthCheckKey][]\n ).find(([, parent]) => parent === key)?.[0];\n const componentResult = componentKey\n ? (health[componentKey] as ComponentHealthResult)\n : undefined;\n const affectedComponents: ComponentStatus[] =\n componentResult?.degradedOrDownComponents ?? [];\n\n return (\n <Box key={key} flexDirection=\"column\">\n <Text>\n <Text color={color}>{icon}</Text>{' '}\n <Text bold={result.status !== ServiceHealthStatus.Healthy}>\n {label}\n </Text>\n </Text>\n {affectedComponents.length > 0 && (\n <Box flexDirection=\"column\" paddingLeft={3}>\n {affectedComponents.slice(0, 5).map((c) => {\n const ci = statusIcon(c.status);\n return (\n <Text key={c.name} dimColor>\n <Text color={ci.color}>{ci.icon}</Text> {c.name}\n </Text>\n );\n })}\n {affectedComponents.length > 5 && (\n <Text dimColor>+{affectedComponents.length - 5} more</Text>\n )}\n </Box>\n )}\n </Box>\n );\n })}\n </Box>\n );\n};\n","import { Box, Text } from 'ink';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport {\n getKindMeta,\n type HealthIssue,\n type HealthIssueSeverity,\n} from '@lib/programs/posthog-doctor/index';\n\nexport const SEVERITY_ORDER: HealthIssueSeverity[] = [\n 'critical',\n 'warning',\n 'info',\n];\n\nconst SEVERITY_COLOR: Record<HealthIssueSeverity, string> = {\n critical: Colors.error,\n warning: Colors.accent,\n info: Colors.primary,\n};\n\nexport const SEVERITY_LABEL: Record<HealthIssueSeverity, string> = {\n critical: 'Critical',\n warning: 'Warning',\n info: 'Info',\n};\n\nconst ICON_COL = 2;\nconst ROW_GAP = 2;\nconst NARROW_TERM_THRESHOLD = 90;\nconst MAX_DOCS_WIDTH = 50;\nconst MIN_DOCS_WIDTH = 20;\n\nfunction computeDocsWidth(termCols: number): number {\n if (termCols < NARROW_TERM_THRESHOLD) return 0;\n const inner = termCols - 12;\n return Math.min(\n MAX_DOCS_WIDTH,\n Math.max(MIN_DOCS_WIDTH, Math.floor(inner * 0.45)),\n );\n}\n\ninterface IssueTableProps {\n issues: HealthIssue[];\n}\n\nexport const IssueTable = ({ issues }: IssueTableProps) => {\n const [termCols] = useStdoutDimensions();\n const docsWidth = computeDocsWidth(termCols);\n\n const grouped: Partial<Record<HealthIssueSeverity, HealthIssue[]>> = {};\n for (const issue of issues) {\n (grouped[issue.severity] ??= []).push(issue);\n }\n\n return (\n <Box flexDirection=\"column\">\n {SEVERITY_ORDER.map((sev) => {\n const list = grouped[sev];\n if (!list || list.length === 0) return null;\n return (\n <Box key={sev} flexDirection=\"column\" marginTop={1}>\n <Text bold color={SEVERITY_COLOR[sev]}>\n {SEVERITY_LABEL[sev]} ({list.length})\n </Text>\n {list.map((issue) => (\n <IssueRow key={issue.id} issue={issue} docsWidth={docsWidth} />\n ))}\n </Box>\n );\n })}\n </Box>\n );\n};\n\nconst IssueRow = ({\n issue,\n docsWidth,\n}: {\n issue: HealthIssue;\n docsWidth: number;\n}) => {\n const meta = getKindMeta(issue.kind);\n const sevColor = SEVERITY_COLOR[issue.severity];\n\n if (docsWidth === 0) {\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Box width={ICON_COL}>\n <Text color={sevColor}>{Icons.squareFilled}</Text>\n </Box>\n <Box flexGrow={1} flexShrink={1} overflow=\"hidden\">\n <Text wrap=\"truncate\">{meta.title}</Text>\n </Box>\n </Box>\n <Box paddingLeft={ICON_COL}>\n <Text color={Colors.primary} wrap=\"truncate\">\n {meta.docsUrl}\n </Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box>\n <Box width={ICON_COL}>\n <Text color={sevColor}>{Icons.squareFilled}</Text>\n </Box>\n <Box flexGrow={1} flexShrink={1} overflow=\"hidden\" marginRight={ROW_GAP}>\n <Text wrap=\"truncate\">{meta.title}</Text>\n </Box>\n <Box width={docsWidth} flexShrink={0}>\n <Text color={Colors.primary} wrap=\"truncate\">\n {meta.docsUrl}\n </Text>\n </Box>\n </Box>\n );\n};\n","/**\n * McpScreen — MCP server install/remove flow.\n *\n * Uses an McpInstaller service (passed via props) instead of\n * importing business logic directly. Testable, no dynamic imports.\n *\n * Supports two modes via the `mode` prop:\n * - 'install': detect clients → confirm → [pick clients] → pick features → install\n * - 'remove': detect installed clients → confirm → remove\n *\n * When done, calls store.setMcpComplete(). The router resolves to outro.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { useState, useEffect } from 'react';\nimport { useSyncExternalStore } from 'react';\nimport { type WizardStore, McpOutcome } from '@ui/tui/store';\nimport {\n ConfirmationInput,\n PickerMenu,\n GroupedPickerMenu,\n} from '@ui/tui/primitives/index';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport type {\n McpInstaller,\n McpClientInfo,\n} from '@ui/tui/services/mcp-installer';\nimport {\n AVAILABLE_FEATURES,\n ALL_FEATURE_VALUES,\n isAllFeaturesSelected,\n} from '@steps/add-mcp-server-to-clients/defaults';\n\nexport type McpMode = 'install' | 'remove';\n\ninterface McpScreenProps {\n store: WizardStore;\n installer: McpInstaller;\n mode?: McpMode;\n}\n\nenum Phase {\n Detecting = 'detecting',\n Ask = 'ask',\n Pick = 'pick',\n FeatureSelect = 'feature-select',\n Connector = 'connector',\n Working = 'working',\n Done = 'done',\n None = 'none',\n}\n\nconst markDone = (\n store: WizardStore,\n outcome: McpOutcome,\n clients: string[] = [],\n featuresSelected?: 'all' | string[],\n) => {\n store.setMcpComplete(outcome, clients, featuresSelected);\n};\n\nconst reportFeatures = (features: string[]): 'all' | string[] =>\n isAllFeaturesSelected(features) ? 'all' : features;\n\n/**\n * Connector step prompt — Enter continues (opens the connector page). There's\n * no skip: picking the connector commits to opening it.\n */\nconst ConnectorContinue = ({ onContinue }: { onContinue: () => void }) => {\n useInput((_input, key) => {\n if (key.return) {\n onContinue();\n }\n });\n return (\n <Text color={Colors.primary}>\n Press enter to continue {Icons.triangleRight}\n </Text>\n );\n};\n\nexport const McpScreen = ({\n store,\n installer,\n mode = 'install',\n}: McpScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n // Keep stdin active from mount so Windows cmd.exe doesn't drop\n // the first keypress when ConfirmationInput appears after detection.\n useInput(() => undefined);\n\n const isRemove = mode === 'remove';\n\n const [phase, setPhase] = useState<Phase>(Phase.Detecting);\n const [clients, setClients] = useState<McpClientInfo[]>([]);\n const [selectedClientNames, setSelectedClientNames] = useState<string[]>([]);\n const [resultClients, setResultClients] = useState<string[]>([]);\n const [pluginClients, setPluginClients] = useState<string[]>([]);\n const [installMode, setInstallMode] = useState<'all' | 'custom'>('custom');\n\n useEffect(() => {\n void (async () => {\n try {\n const detected = await installer.detectClients();\n if (detected.length === 0) {\n setPhase(Phase.None);\n setTimeout(() => markDone(store, McpOutcome.NoClients), 1500);\n } else {\n setClients(detected);\n setPhase(Phase.Ask);\n }\n } catch {\n setPhase(Phase.None);\n setTimeout(() => markDone(store, McpOutcome.Failed), 1500);\n }\n })();\n }, [installer]); // eslint-disable-line\n\n const proceedAfterClientPick = (\n clientNames: string[],\n chosenMode: 'all' | 'custom',\n ) => {\n setSelectedClientNames(clientNames);\n\n // Recommended flow: install everything straight away. Browser connectors\n // (e.g. Claude Desktop/Web) just open their connector page here, same as\n // before — no extra screen.\n if (chosenMode === 'all') {\n void doInstall(clientNames, [...ALL_FEATURE_VALUES]);\n return;\n }\n if (store.session.mcpFeatures) {\n void doInstall(clientNames, store.session.mcpFeatures);\n return;\n }\n\n // Customize flow: a browser connector configures its tools and features in\n // Claude's UI, not through the wizard's feature picker. The picker keeps it\n // mutually exclusive from local editors, so a connector selection is\n // connector-only — show its own screen instead of the feature picker.\n const isConnector = clientNames.some(\n (name) => clients.find((c) => c.name === name)?.finish,\n );\n if (isConnector) {\n setPhase(Phase.Connector);\n return;\n }\n setPhase(Phase.FeatureSelect);\n };\n\n const handleConfirm = () => {\n if (isRemove) {\n void doRemove();\n } else if (clients.length === 1) {\n proceedAfterClientPick([clients[0]!.name], 'custom');\n } else {\n setPhase(Phase.Pick);\n }\n };\n\n const handleTriStateChoice = (choice: 'all' | 'custom' | 'skip') => {\n if (choice === 'skip') {\n handleSkip();\n return;\n }\n setInstallMode(choice);\n if (clients.length === 1) {\n proceedAfterClientPick([clients[0]!.name], choice);\n } else {\n setPhase(Phase.Pick);\n }\n };\n\n const handleSkip = () => {\n markDone(store, McpOutcome.Skipped);\n };\n\n const doInstall = async (names: string[], features?: string[]) => {\n setPhase(Phase.Working);\n let mcpResult: string[] = [];\n let pluginResult: string[] = [];\n\n const pluginCapableSet = new Set(\n clients.filter((c) => c.supportsPlugin).map((c) => c.name),\n );\n const pluginCapableNames = names.filter((n) => pluginCapableSet.has(n));\n const directNames = names.filter((n) => !pluginCapableSet.has(n));\n\n if (installMode === 'all') {\n // Plugin-capable clients get the plugin (which bundles MCP).\n // Non-plugin-capable clients get a direct MCP config write.\n try {\n mcpResult = await installer.install(\n directNames,\n features,\n store.session.apiKey,\n );\n } catch {\n // mcpResult stays []\n }\n try {\n pluginResult = await installer.installPlugins(pluginCapableNames);\n } catch {\n // best-effort\n }\n } else {\n // 'custom' — MCP-only for every selected client. Plugin install is\n // skipped so the user's feature selection is actually respected.\n try {\n mcpResult = await installer.install(\n names,\n features,\n store.session.apiKey,\n );\n } catch {\n // mcpResult stays []\n }\n }\n\n setResultClients(mcpResult);\n setPluginClients(pluginResult);\n setPhase(Phase.Done);\n const succeeded = mcpResult.length + pluginResult.length > 0;\n const outcome = succeeded ? McpOutcome.Installed : McpOutcome.Failed;\n const featuresReport = reportFeatures(features ?? [...ALL_FEATURE_VALUES]);\n setTimeout(\n () =>\n markDone(\n store,\n outcome,\n [...mcpResult, ...pluginResult],\n featuresReport,\n ),\n 2000,\n );\n };\n\n const doRemove = async () => {\n setPhase(Phase.Working);\n let result: string[] = [];\n try {\n result = await installer.remove();\n setResultClients(result);\n } catch {\n setResultClients([]);\n }\n setPhase(Phase.Done);\n const outcome =\n result.length > 0 ? McpOutcome.Installed : McpOutcome.Failed;\n setTimeout(() => markDone(store, outcome, result), 2000);\n };\n\n // The \"what you get\" preview shown above the install confirmation —\n // installed users have no idea what \"MCP\" means; lead with the value.\n const installValueBullets = [\n 'Ask your agent: \"List my feature flags\" — and it does.',\n 'Run SQL, build dashboards, ship flags, all from your IDE.',\n 'No copy-pasting tokens or context. Your agent has the keys.',\n ];\n\n // Clients connected via a browser page (e.g. Claude Desktop/Web) aren't truly\n // \"installed\" — the user finishes in the browser. Split them out of the\n // \"installed for\" list and render the finish instructions separately.\n const finishNotes = clients.flatMap((c) =>\n c.finish && resultClients.includes(c.name)\n ? [{ name: c.name, url: c.finish.url, instruction: c.finish.instruction }]\n : [],\n );\n const installedNow = resultClients.filter(\n (name) => !finishNotes.some((n) => n.name === name),\n );\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text bold color={Colors.accent}>\n {isRemove\n ? 'Remove the PostHog MCP'\n : 'Install the MCP so you can chat to your data'}\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\">\n {phase === Phase.Detecting && (\n <Text dimColor>Detecting supported editors...</Text>\n )}\n\n {phase === Phase.None && (\n <Text dimColor>\n No {isRemove ? 'installed' : 'supported'} MCP clients detected.\n Skipping...\n </Text>\n )}\n\n {phase === Phase.Ask && (\n <>\n {!isRemove && (\n <Box flexDirection=\"column\" marginBottom={1}>\n {installValueBullets.map((bullet) => (\n <Text key={bullet} dimColor>\n {'•'} {bullet}\n </Text>\n ))}\n </Box>\n )}\n <Text dimColor>\n Detected: {clients.map((c) => c.name).join(', ')}\n </Text>\n <Box marginTop={1}>\n {!isRemove && !store.session.mcpFeatures ? (\n <PickerMenu\n message={`Install the PostHog MCP server${\n clients.some((c) => c.supportsPlugin) ? ' and plugin' : ''\n }?`}\n options={[\n {\n label: 'Install with all features',\n value: 'all',\n hint: 'recommended',\n },\n {\n label: 'Customize features',\n value: 'custom',\n },\n { label: 'No thanks', value: 'skip' },\n ]}\n mode=\"single\"\n onSelect={(choice) =>\n handleTriStateChoice(choice as 'all' | 'custom' | 'skip')\n }\n />\n ) : (\n <ConfirmationInput\n message={`${\n isRemove ? 'Remove' : 'Install'\n } the PostHog MCP server${\n clients.some((c) => c.supportsPlugin) ? ' and plugin' : ''\n }?`}\n confirmLabel={isRemove ? 'Remove' : 'Install'}\n cancelLabel=\"No thanks\"\n onConfirm={handleConfirm}\n onCancel={handleSkip}\n />\n )}\n </Box>\n </>\n )}\n\n {phase === Phase.Pick && (\n <PickerMenu\n message={\n installMode === 'all'\n ? 'Select editor to install'\n : 'Select editor to install MCP server'\n }\n options={clients.map((c) => ({\n label: c.name,\n value: c.name,\n // Browser connectors can't be installed alongside local editors\n // and are configured on their own screen, not the feature picker.\n exclusive: Boolean(c.finish),\n // Hints only show in the recommended flow; the customize flow\n // keeps the list clean.\n hint:\n installMode === 'all'\n ? c.finish\n ? 'connector'\n : c.supportsPlugin\n ? 'plugin'\n : 'MCP'\n : undefined,\n }))}\n mode=\"multi\"\n onSelect={(selected) => {\n const names = Array.isArray(selected) ? selected : [selected];\n proceedAfterClientPick(names, installMode);\n }}\n />\n )}\n\n {phase === Phase.FeatureSelect && (\n <GroupedPickerMenu\n message=\"Select features to enable\"\n groups={AVAILABLE_FEATURES}\n initialSelected={[]}\n onSelect={(features) => {\n void doInstall(selectedClientNames, features);\n }}\n />\n )}\n\n {phase === Phase.Connector && (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text dimColor>\n You'll choose which features and tools to enable in\n Claude's UI after connecting.\n </Text>\n </Box>\n <ConnectorContinue\n onContinue={() => void doInstall(selectedClientNames, [])}\n />\n </Box>\n )}\n\n {phase === Phase.Working && (\n <Text dimColor>\n {isRemove ? 'Removing' : 'Installing'} MCP server...\n </Text>\n )}\n\n {phase === Phase.Done && (\n <Box flexDirection=\"column\">\n {installedNow.length + pluginClients.length + finishNotes.length ===\n 0 ? (\n <Text dimColor>\n {isRemove ? 'Removal' : 'Installation'} skipped.\n </Text>\n ) : (\n <>\n {pluginClients.length > 0 && (\n <>\n <Text color=\"green\" bold>\n {'\\u2714'} Plugin installed for:\n </Text>\n {pluginClients.map((name, i) => (\n <Text key={`p-${i}`}>\n {' '}\n {'\\u2022'} {name}\n </Text>\n ))}\n </>\n )}\n {installedNow.length > 0 && (\n <>\n <Text color=\"green\" bold>\n {'\\u2714'} MCP server{' '}\n {isRemove ? 'removed from' : 'installed for'}:\n </Text>\n {installedNow.map((name, i) => (\n <Text key={`m-${i}`}>\n {' '}\n {'\\u2022'} {name}\n </Text>\n ))}\n </>\n )}\n {finishNotes.map((note) => (\n <Box key={note.name} flexDirection=\"column\" marginTop={1}>\n <Text color=\"green\" bold>\n {'\\u2714'} {note.name} {'\\u2014'} installs a PostHog\n connector:\n </Text>\n <Text>\n {' '}Opened <Text color=\"cyan\">{note.url}</Text>\n </Text>\n <Text dimColor>\n {' '}\n {note.instruction}\n </Text>\n <Text dimColor>\n {' '}(If it didn't open, paste the URL above.)\n </Text>\n </Box>\n ))}\n </>\n )}\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n","","/**\n * Role + framework-tailored MCP prompt suggestions.\n *\n * All copy lives in `mcp-role-prompts.copy.json` so prompts can be\n * edited without touching TypeScript. This file holds the types,\n * the lookup functions, and the framework-family mapping.\n *\n * Editing rule for the JSON (which can't carry comments itself): every\n * prompt is either (a) a read query on any PostHog product, or (b) a\n * write on dashboards, insights, notebooks, or annotations — the four\n * \"persistence\" surfaces. No prompt should ask the agent to ship a\n * flag, run an experiment, send a survey, or create an alert. See\n * prompt-tree.md §5 for the scope reality.\n *\n * The wizard surfaces these on the McpSuggestedPromptsScreen after\n * MCP install. Picking strategy for the kit:\n * 1. Known role + known framework → role kit with family overrides.\n * 2. Known role + unknown framework → role kit, no overrides.\n * 3. Unknown role → DEFAULT_KIT.\n */\n\nimport type { Integration } from './constants';\nimport copyData from './mcp-role-prompts.copy.json';\n\n/**\n * Roles that ship from `role_at_organization` on the PostHog user object.\n * `security` isn't in the enum upstream — the engineering kit covers\n * that audience.\n */\nexport const TAILORED_ROLES = [\n 'founder',\n 'product',\n 'leadership',\n 'marketing',\n 'engineering',\n 'data',\n] as const;\n\nexport type TailoredRole = (typeof TAILORED_ROLES)[number];\n\n/**\n * Unified shape for every clickable picker entry the screen renders —\n * initial-picker kit prompts, cross-sell prompts, and follow-up prompts.\n * The three flavors are distinguished by which optional fields they\n * populate, not by separate types:\n *\n * kit prompt → { prompt, description }\n * cross-sell prompt → { prompt, description, product }\n * follow-up prompt → { prompt, label }\n */\nexport interface PromptOption {\n /** Sent to the agent when picked. Also serves as the picker label when `label` is omitted. */\n prompt: string;\n /** Optional picker label override. Follow-ups use this to show a short verb-phrase (\"Save as dashboard\") instead of the full prompt. */\n label?: string;\n /** Optional one-line description shown by the Goodbye sample list. */\n description?: string;\n /** Optional product tag — when present, picker prepends \"Try {product} —\" to the label. */\n product?: string;\n /** Stable identifier used by `roleFamilyOverrides` to target a kit entry by name (reorder-safe). Populated on kit entries; left out on cross-sells and follow-ups. */\n key?: string;\n}\n\nexport type PromptKit = PromptOption[];\n\n/**\n * Buckets `Integration` values into broader framework families so we can\n * write one kit per family instead of per individual integration.\n */\nexport type FrameworkFamily =\n | 'frontend-web'\n | 'mobile'\n | 'backend'\n | 'fullstack'\n | 'unknown';\n\nexport interface RoleGreeting {\n /** 1-line hook — typewrites in. */\n headline: string;\n /** 2-3 lines of value framing — revealed line-by-line. */\n bullets: string[];\n /** Sets up the picker, e.g. \"Pick one to try.\" — fades in. */\n outro: string;\n}\n\n/**\n * The \"Take PostHog to Slack\" card surfaced at the end of the MCP flow\n * (Goodbye phase + dedicated Connect-Slack step). `useCases` is resolved\n * per role; the rest is static. Every string here is presentation copy\n * shown to the user — none of it is sent to the agent, so the picker's\n * read/persistence prompt-scope rule does not apply.\n */\nexport interface SlackAppCard {\n headline: string;\n /** One-line hook covering both analysis and shipping. */\n pitch: string;\n /** posthog.com/slack — \"learn more\". */\n learnMoreUrl: string;\n /** integrations/slack — where the user connects Slack. */\n setupUrl: string;\n /** The Slack agent's two capabilities (code/PR + data) — fixed, not role-tailored. */\n capabilities: string[];\n}\n\nexport const FOLLOW_UP_EXIT_SENTINEL = '__follow_up_exit__';\n/** How many follow-up suggestions to surface above the exit entry. */\nexport const FOLLOW_UP_COUNT = 3;\n\n// ── Data loaded from JSON ──────────────────────────────────────────────\n// One cast per top-level key. JSON imports lose the precise key\n// constraints (e.g. Record<TailoredRole, ...>), so we re-attach them\n// here. TypeScript can still catch shape mismatches at the call site.\n\n/**\n * Always shown as the picker's first option regardless of role —\n * a safe generic read that works on any project setup. The screen\n * prepends it and dedupes against the role kit so it never appears\n * twice when DEFAULT_KIT happens to include it.\n */\nexport const PINNED_FIRST_PROMPT = copyData.pinnedFirstPrompt as PromptOption;\n\nconst DEFAULT_KIT = copyData.defaultKit as PromptKit;\nconst ROLE_KITS = copyData.roleKits as Record<TailoredRole, PromptKit>;\n// Overrides are keyed by a base-kit entry's `key` (e.g. \"onboarding\",\n// \"top-errors\") so a kit reorder doesn't silently shift overrides to\n// the wrong slot. Each override is a partial PromptOption that gets\n// merged onto the base entry.\nconst ROLE_FAMILY_OVERRIDES = copyData.roleFamilyOverrides as Partial<\n Record<\n TailoredRole,\n Partial<Record<FrameworkFamily, Record<string, PromptOption>>>\n >\n>;\nconst ROLE_GREETINGS = copyData.roleGreetings as Record<\n TailoredRole,\n RoleGreeting\n>;\nconst NEUTRAL_GREETING = copyData.neutralGreeting as RoleGreeting;\nconst TOOL_FOLLOW_UPS = copyData.toolFollowUps as Record<\n string,\n PromptOption[]\n>;\nconst ROLE_FOLLOW_UPS = copyData.roleFollowUps as Record<\n TailoredRole,\n PromptOption[]\n>;\nconst GENERIC_FOLLOW_UPS = copyData.genericFollowUps as PromptOption[];\nconst DEEP_DIVE_FOLLOW_UPS = copyData.deepDiveFollowUps as PromptOption[];\nconst CROSS_SELL_BY_ROLE = copyData.crossSellByRole as Record<\n TailoredRole,\n PromptOption[]\n>;\nconst NEUTRAL_CROSS_SELL = copyData.neutralCrossSell as PromptOption[];\n// Presentation copy for the \"Take PostHog to Slack\" surfaces (Goodbye\n// card + dedicated step). Shown to the user, never sent to the agent —\n// so the read/persistence prompt-scope rule above does not apply. The\n// capabilities describe the Slack agent itself, not role-specific\n// examples. Connecting Slack is a manual OAuth step in the PostHog app,\n// so we link out to `setupUrl` rather than wiring it up.\nconst SLACK_APP = copyData.slackApp as {\n learnMoreUrl: string;\n setupUrl: string;\n headline: string;\n pitch: string;\n capabilities: string[];\n};\n\n// ── Framework family map ───────────────────────────────────────────────\n// Stays in code (not JSON) because it's structural data tied to the\n// `Integration` enum, not user-facing copy.\n\nconst INTEGRATION_FAMILY: Record<string, FrameworkFamily> = {\n nextjs: 'fullstack',\n nuxt: 'fullstack',\n 'tanstack-start': 'fullstack',\n astro: 'fullstack',\n sveltekit: 'fullstack',\n vue: 'frontend-web',\n angular: 'frontend-web',\n 'react-router': 'frontend-web',\n 'tanstack-router': 'frontend-web',\n javascript_web: 'frontend-web',\n 'react-native': 'mobile',\n swift: 'mobile',\n android: 'mobile',\n django: 'backend',\n flask: 'backend',\n fastapi: 'backend',\n python: 'backend',\n laravel: 'backend',\n rails: 'backend',\n ruby: 'backend',\n javascript_node: 'backend',\n};\n\nconst EXIT_FOLLOW_UP: PromptOption = {\n label: \"I'm done — exit\",\n prompt: FOLLOW_UP_EXIT_SENTINEL,\n};\n\n// ── Helpers ────────────────────────────────────────────────────────────\n\nfunction isTailoredRole(role: string | null | undefined): role is TailoredRole {\n return (\n typeof role === 'string' &&\n (TAILORED_ROLES as readonly string[]).includes(role)\n );\n}\n\n/**\n * Strip MCP tool-name prefixes so lookup keys can stay short. Real MCP\n * tool names arrive as `mcp__<server>__<tool>`; the agent SDK also\n * sometimes drops the prefix. We take the substring after the last\n * double-underscore (or the input untouched if there's none).\n */\nfunction normalizeToolName(toolName: string | null): string | null {\n if (!toolName) return null;\n const idx = toolName.lastIndexOf('__');\n return idx >= 0 ? toolName.slice(idx + 2) : toolName;\n}\n\n/** Pick `n` items from a pool starting at a rotation offset. */\nfunction pickRotated<T>(pool: T[], n: number, rotation: number): T[] {\n if (pool.length === 0) return [];\n if (pool.length <= n) return pool;\n const start =\n ((Math.floor(rotation) % pool.length) + pool.length) % pool.length;\n const result: T[] = [];\n for (let i = 0; i < n; i++) {\n result.push(pool[(start + i) % pool.length]);\n }\n return result;\n}\n\n/** Drop duplicates while preserving order (by prompt text). */\nfunction dedupeFollowUps(list: PromptOption[]): PromptOption[] {\n const seen = new Set<string>();\n const out: PromptOption[] = [];\n for (const f of list) {\n if (seen.has(f.prompt)) continue;\n seen.add(f.prompt);\n out.push(f);\n }\n return out;\n}\n\n// ── Public API ─────────────────────────────────────────────────────────\n\nexport function getFrameworkFamily(\n integration: Integration | null | undefined,\n): FrameworkFamily {\n if (!integration) return 'unknown';\n return INTEGRATION_FAMILY[integration] ?? 'unknown';\n}\n\n/**\n * Resolve the right kit given everything we know about the user + project.\n * Always returns at least DEFAULT_KIT; never throws.\n */\nexport function getRolePrompts(\n role: string | null | undefined,\n integration: Integration | null | undefined,\n): PromptKit {\n const family = getFrameworkFamily(integration);\n\n if (!isTailoredRole(role)) {\n // Unknown role — DEFAULT_KIT is already framework-agnostic and broad.\n return DEFAULT_KIT;\n }\n\n const baseKit = ROLE_KITS[role];\n const overridesForRole = ROLE_FAMILY_OVERRIDES[role];\n const overridesForFamily = overridesForRole?.[family];\n\n if (!overridesForFamily) {\n return baseKit;\n }\n\n // Look up overrides by each entry's stable `key` so a kit reorder\n // doesn't shift overrides to the wrong slot. An entry without a key,\n // or a key not present in the override map, passes through unchanged.\n return baseKit.map((entry) => {\n const override = entry.key ? overridesForFamily[entry.key] : undefined;\n return override ?? entry;\n });\n}\n\nexport function getRoleGreeting(role: string | null | undefined): RoleGreeting {\n if (!isTailoredRole(role)) return NEUTRAL_GREETING;\n return ROLE_GREETINGS[role];\n}\n\n/**\n * Resolve `FOLLOW_UP_COUNT` context-aware follow-ups + an always-present\n * exit entry. Pulls from up to four pools — tool-specific, role-specific,\n * deep-dive (only after the user has explored a few steps), and generic —\n * dedupes, filters out anything already in `branchHistory`, then picks\n * `FOLLOW_UP_COUNT` with a rotation offset driven by `branchHistory.length`\n * so successive visits surface different slices.\n */\nexport function getFollowUps(args: {\n lastToolName: string | null;\n lastPrompt: string;\n role: string | null | undefined;\n branchHistory: string[];\n}): PromptOption[] {\n const { lastToolName, role, branchHistory } = args;\n const normalized = normalizeToolName(lastToolName);\n const depth = branchHistory.length;\n\n // Build the candidate pool — order matters because dedup keeps the\n // first occurrence. Tool-specific first (most relevant), then role,\n // then deep-dive (only after the user's been exploring), then generic.\n const candidates: PromptOption[] = [];\n if (normalized && TOOL_FOLLOW_UPS[normalized]) {\n candidates.push(...TOOL_FOLLOW_UPS[normalized]);\n }\n if (isTailoredRole(role)) {\n candidates.push(...ROLE_FOLLOW_UPS[role]);\n }\n if (depth >= 3) {\n candidates.push(...DEEP_DIVE_FOLLOW_UPS);\n }\n candidates.push(...GENERIC_FOLLOW_UPS);\n\n const deduped = dedupeFollowUps(candidates);\n const seen = new Set(branchHistory);\n const fresh = deduped.filter((f) => !seen.has(f.prompt));\n\n // Rotate by depth so repeat visits to the same tool surface different\n // slices of the pool. A user who keeps picking `query-trends` won't\n // see the same three options every time.\n const selected = pickRotated(fresh, FOLLOW_UP_COUNT, depth);\n\n return [...selected, EXIT_FOLLOW_UP];\n}\n\n/**\n * Cross-sell prompts to surface above the role kit in PromptPicker.\n * Filtered by role so the recommendations stay coherent (founders see\n * the \"exec-friendly\" cross-sells, engineers see \"debug-friendly\", etc).\n */\nexport function getCrossSellPrompts(\n role: string | null | undefined,\n): PromptOption[] {\n if (!isTailoredRole(role)) return NEUTRAL_CROSS_SELL;\n return CROSS_SELL_BY_ROLE[role];\n}\n\n/**\n * Resolve the \"Take PostHog to Slack\" card. Role-independent — the Slack\n * agent's two capabilities (code/PR + data) describe the product itself,\n * not role-specific examples.\n */\nexport function getSlackAppCard(): SlackAppCard {\n return {\n headline: SLACK_APP.headline,\n pitch: SLACK_APP.pitch,\n learnMoreUrl: SLACK_APP.learnMoreUrl,\n setupUrl: SLACK_APP.setupUrl,\n capabilities: SLACK_APP.capabilities,\n };\n}\n","/**\n * McpSuggestedPromptsScreen — shown after MCP install succeeds in the\n * standalone `wizard mcp add` program, and as the entry point for\n * `wizard mcp tutorial`.\n *\n * Phases:\n * 1. Choose — opens with a Log in / Exit picker, framed by a\n * teaser of what MCP can do.\n * 2. Authenticating — runs `services.performLogin()` (OAuth in\n * production, canned values in the playground).\n * Renders a spinner + login URL inline while the\n * promise is pending. Errors return to Choose\n * with an inline error line.\n * 3. Greeting — role-tuned welcome via `getRoleGreeting`. A\n * ContentSequencer animates the headline,\n * bullets, and outro, then hands off to\n * PromptPicker. Only fires once per session\n * (returning via `[p]` skips it).\n * 4. PromptPicker — lists the role-tailored kit from\n * `getRolePrompts`; user picks one to run.\n * 5. Running — streams the agent's response inline via\n * `services.runPromptStreaming`. Text chunks\n * typewrite in; tool calls and results render\n * as styled badges. `[esc]` aborts; `[p]`\n * returns to the picker. On `done`/`error`,\n * auto-advances to FollowUp.\n * 6. FollowUp — surfaces 3 context-aware next prompts inferred\n * from the last tool the agent used (via\n * `getFollowUps`), plus an explicit exit.\n * Picking a follow-up re-enters Running; the\n * conversation tree grows as deep as\n * MAX_PROMPT_RUNS allows.\n *\n * Credentials are guaranteed non-null once Greeting / PromptPicker /\n * Running / FollowUp are reached (the Choose → Authenticating gate\n * forces a successful login first). A defensive throw protects the\n * Running useEffect against a state-machine bug.\n */\n\nimport { Box, Text } from 'ink';\nimport { Spinner } from '@inkjs/ui';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useSyncExternalStore } from 'react';\n\nimport type { WizardStore } from '@ui/tui/store';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport { useKeyBindings, KeyMatch } from '@ui/tui/hooks/useKeyBindings';\nimport {\n ContentSequencer,\n LoadingBox,\n PickerMenu,\n TextRevealMode,\n type ContentBlock,\n} from '@ui/tui/primitives/index';\nimport {\n getRolePrompts,\n getRoleGreeting,\n getFollowUps,\n getCrossSellPrompts,\n FOLLOW_UP_EXIT_SENTINEL,\n PINNED_FIRST_PROMPT,\n type PromptOption,\n type RoleGreeting,\n} from '@lib/mcp-role-prompts';\nimport type { Integration } from '@lib/constants';\nimport { analytics } from '@utils/analytics';\nimport { logToFile } from '@utils/debug';\nimport type {\n AgentChunk,\n McpSuggestedPromptsServices,\n} from '@ui/tui/services/mcp-suggested-prompts-services';\n\ninterface McpSuggestedPromptsScreenProps {\n store: WizardStore;\n services: McpSuggestedPromptsServices;\n}\n\nenum Phase {\n Choose = 'choose',\n Authenticating = 'authenticating',\n Greeting = 'greeting',\n PromptPicker = 'prompt-picker',\n Running = 'running',\n FollowUp = 'follow-up',\n /** Final beat on every dismissal — reminds the user how to keep\n * talking to PostHog after the tutorial ends. */\n Goodbye = 'goodbye',\n Done = 'done',\n}\n\nenum ChoiceValue {\n Login = 'login',\n Exit = 'exit',\n}\n\n// Cap how many prompts a single tutorial session can run, including\n// follow-ups. Once reached, FollowUp shows a cap-reached state and the\n// only escape is [esc]. Keeps the wizard from becoming a free-tier MCP\n// front-end and gives the tutorial a natural \"done\" point.\nconst MAX_PROMPT_RUNS = 5;\n\n// How long to hold the final streamed result on screen before swapping\n// into FollowUp. Gives the user a beat to read the result before the\n// picker mounts underneath. [esc] / [p] still work during the delay.\nconst FOLLOW_UP_DELAY_MS = 3000;\n\nexport const McpSuggestedPromptsScreen = ({\n store,\n services,\n}: McpSuggestedPromptsScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const session = store.session;\n // Role + framework family drive the kit, greeting, and cross-sell\n // prompts. All helpers fall back to neutral defaults when either\n // input is missing, so these are always populated.\n const kit = getRolePrompts(session.roleAtOrganization, session.integration);\n const crossSell = useMemo(\n () => getCrossSellPrompts(session.roleAtOrganization),\n [session.roleAtOrganization],\n );\n const greeting = useMemo(\n () => getRoleGreeting(session.roleAtOrganization),\n [session.roleAtOrganization],\n );\n\n // Phase.Choose is the no-commitment entry. Login fires only when the\n // user picks 'Start tutorial' — explicit consent for the OAuth dance.\n const [phase, setPhase] = useState<Phase>(Phase.Choose);\n const [loginError, setLoginError] = useState<string | null>(null);\n // Whether the user picked \"Start MCP tutorial\" — decides where a\n // successful login lands: Greeting for a started tutorial, Choose\n // for the up-front auth.\n const startedTutorialRef = useRef(false);\n const [runningPrompt, setRunningPrompt] = useState<string | null>(null);\n const [runChunks, setRunChunks] = useState<AgentChunk[]>([]);\n const [runStartedAt, setRunStartedAt] = useState<number | null>(null);\n // Frozen elapsed-seconds value, set the moment the stream emits\n // 'done' / 'error'. Without this, the \"Done in Xs.\" line ticks up\n // every render once the result is parked under the FollowUp picker.\n const [runDurationSecs, setRunDurationSecs] = useState<number | null>(null);\n // Count every prompt the user has selected this session (including ones\n // they aborted mid-stream). Counted at pick-time, not completion-time,\n // so a user can't tap-cancel-tap-cancel to bypass the cap.\n const [runCount, setRunCount] = useState(0);\n const canPickAnother = runCount < MAX_PROMPT_RUNS;\n\n // The last tool the agent invoked during the current run. Drives the\n // context-aware follow-up suggestions in FollowUp. Cleared at the\n // start of each new run.\n const [lastToolName, setLastToolName] = useState<string | null>(null);\n // Every prompt the user has picked this session — initial + follow-ups.\n // Used to filter out already-seen suggestions in getFollowUps().\n const [branchHistory, setBranchHistory] = useState<string[]>([]);\n\n // AbortController for the in-flight runPromptStreaming call. Lifted\n // to a ref so [esc] / unmount can call abort() without the closure\n // needing to re-bind on every state change.\n const runAbortRef = useRef<AbortController | null>(null);\n\n // The Claude Agent SDK session ID of the most recent completed run.\n // Carried forward into follow-up runs via `resumeSessionId` so the\n // agent sees prior turns as context. Held in a ref so updating it\n // doesn't re-trigger the Running useEffect. Cleared whenever the\n // user returns to PromptPicker — that's a fresh conversation.\n const currentSessionIdRef = useRef<string | null>(null);\n\n // Run OAuth when entering Authenticating phase.\n useEffect(() => {\n if (phase !== Phase.Authenticating) return;\n let cancelled = false;\n\n void (async () => {\n try {\n const { credentials, roleAtOrganization, user } =\n await services.performLogin();\n if (cancelled) return;\n store.setCredentials(credentials);\n store.setRoleAtOrganization(roleAtOrganization);\n store.setApiUser(user);\n store.setLoginUrl(null);\n setPhase(startedTutorialRef.current ? Phase.Greeting : Phase.Choose);\n } catch (err) {\n if (cancelled) return;\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[McpSuggestedPromptsScreen] login failed: ${message}`);\n store.setLoginUrl(null);\n setLoginError(message);\n setPhase(Phase.Choose);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [phase, services, store]);\n\n // Stream the chosen prompt against the agent. On terminal chunks\n // ('done' or 'error') we schedule a short delay before swapping into\n // FollowUp so the user gets a beat to read the final text.\n useEffect(() => {\n if (phase !== Phase.Running) return;\n if (!runningPrompt) return;\n if (!session.credentials) {\n throw new Error(\n '[McpSuggestedPromptsScreen] Running phase reached without credentials. The Choose gate should have prevented this.',\n );\n }\n\n const controller = new AbortController();\n runAbortRef.current = controller;\n const startedAt = Date.now();\n setRunStartedAt(startedAt);\n setRunChunks([]);\n setLastToolName(null);\n setRunDurationSecs(null);\n\n const finishStream = (\n kind: 'done' | 'error',\n durationMs: number,\n errorText?: string,\n ) => {\n if (controller.signal.aborted) return;\n setRunDurationSecs(Math.round(durationMs / 1000));\n if (kind === 'done') {\n analytics.wizardCapture('mcp suggested prompts run', {\n prompt: runningPrompt,\n durationMs,\n });\n } else {\n analytics.wizardCapture('mcp suggested prompts run failed', {\n prompt: runningPrompt,\n error: errorText,\n });\n }\n // Hold the final result on screen for a beat before swapping into\n // FollowUp, so the user has a moment to read without the picker\n // jumping in underneath. Guard via the abort controller so an\n // [esc] / [p] press inside the delay window cancels the swap.\n setTimeout(() => {\n if (controller.signal.aborted) return;\n setPhase(Phase.FollowUp);\n }, FOLLOW_UP_DELAY_MS);\n };\n\n void (async () => {\n const credentials = session.credentials;\n if (!credentials) return;\n try {\n for await (const chunk of services.runPromptStreaming({\n prompt: runningPrompt,\n credentials,\n signal: controller.signal,\n // Read at call-time so a session id captured by the previous\n // run carries into the follow-up. Null on a fresh start.\n resumeSessionId: currentSessionIdRef.current ?? undefined,\n })) {\n if (controller.signal.aborted) return;\n setRunChunks((prev) => [...prev, chunk]);\n if (chunk.kind === 'tool-call') {\n setLastToolName(chunk.toolName);\n }\n if (chunk.kind === 'done') {\n // Remember the SDK session id so the next follow-up can\n // resume it. The SDK may issue a new id on resume — always\n // overwrite with the latest.\n if (chunk.sessionId) {\n currentSessionIdRef.current = chunk.sessionId;\n }\n finishStream('done', Date.now() - startedAt);\n return;\n }\n if (chunk.kind === 'error') {\n finishStream('error', Date.now() - startedAt, chunk.text);\n return;\n }\n }\n } catch (err) {\n if (controller.signal.aborted) return;\n const text = err instanceof Error ? err.message : String(err);\n setRunChunks((prev) => [...prev, { kind: 'error', text }]);\n finishStream('error', Date.now() - startedAt, text);\n }\n })();\n\n return () => {\n controller.abort();\n if (runAbortRef.current === controller) runAbortRef.current = null;\n };\n }, [phase, runningPrompt, services, session.credentials]);\n\n // Two-stage exit so the user always sees the Goodbye reminder\n // (installed clients + sample prompts) before the screen actually\n // tears down. `enterGoodbye` routes any dismissal into the reminder;\n // `closeWizard` does the actual store mutation that lets the router\n // move on.\n const enterGoodbye = (): void => {\n runAbortRef.current?.abort();\n setPhase(Phase.Goodbye);\n };\n\n const closeWizard = (): void => {\n setPhase(Phase.Done);\n setTimeout(() => {\n store.setMcpSuggestedPromptsDismissed();\n }, 0);\n };\n\n const handleChoice = (value: ChoiceValue | ChoiceValue[]): void => {\n const choice = Array.isArray(value) ? value[0] : value;\n setLoginError(null);\n if (choice === ChoiceValue.Login) {\n analytics.wizardCapture('mcp suggested prompts choose', {\n choice: 'login',\n });\n startedTutorialRef.current = true;\n // Picking Start tutorial is the explicit OAuth consent moment.\n // If we somehow already have credentials, skip straight to Greeting.\n setPhase(session.credentials ? Phase.Greeting : Phase.Authenticating);\n } else {\n analytics.wizardCapture('mcp suggested prompts choose', {\n choice: 'exit',\n });\n enterGoodbye();\n }\n };\n\n // Single entry-point for kicking off a stream. Used by both the\n // initial picker and the follow-up picker.\n const startRun = (prompt: string): void => {\n setRunningPrompt(prompt);\n setRunCount((c) => c + 1);\n setBranchHistory((h) => [...h, prompt]);\n setPhase(Phase.Running);\n };\n\n const handlePromptPick = (value: string | string[]): void => {\n const picked = Array.isArray(value) ? value[0] : value;\n startRun(picked);\n };\n\n const handleFollowUpPick = (value: string | string[]): void => {\n const picked = Array.isArray(value) ? value[0] : value;\n if (picked === FOLLOW_UP_EXIT_SENTINEL) {\n analytics.wizardCapture('mcp suggested prompts follow-up', {\n choice: 'exit',\n depth: branchHistory.length,\n });\n enterGoodbye();\n return;\n }\n analytics.wizardCapture('mcp suggested prompts follow-up', {\n choice: 'continue',\n depth: branchHistory.length,\n lastToolName,\n });\n startRun(picked);\n };\n\n // `[enter]` skips the auto-paced Greeting to the picker. Only\n // registered while Greeting is on screen — PickerMenu owns enter\n // during the picker phases, and Running auto-transitions on done\n // (no auto-advance timer left to short-circuit).\n const canSkipForward = phase === Phase.Greeting;\n\n useKeyBindings('mcp-suggested-prompts', [\n {\n match: KeyMatch.Escape,\n label: 'esc',\n action:\n phase === Phase.Goodbye\n ? 'close'\n : phase === Phase.Authenticating\n ? 'cancel'\n : 'exit',\n handler: () => {\n if (phase === Phase.Goodbye) {\n closeWizard();\n } else if (phase === Phase.Authenticating) {\n // Cancel the OAuth dance — the login effect's cleanup discards\n // the in-flight result. Choose still works without credentials.\n setPhase(Phase.Choose);\n } else if (\n phase === Phase.Running ||\n phase === Phase.PromptPicker ||\n phase === Phase.FollowUp ||\n phase === Phase.Greeting\n ) {\n enterGoodbye();\n }\n },\n },\n {\n // `[p]` is the primary \"pick a different prompt\" hotkey during\n // Running and FollowUp — always returns to the PromptPicker\n // (aborting the stream if necessary). No-op once the per-session\n // cap is reached. Clearing the session id here is what makes\n // the next pick a fresh conversation rather than a follow-up.\n match: 'p',\n label: 'p',\n action: canPickAnother ? 'pick new prompt' : 'cap reached',\n handler: () => {\n if (phase !== Phase.Running && phase !== Phase.FollowUp) return;\n if (!canPickAnother) return;\n runAbortRef.current?.abort();\n currentSessionIdRef.current = null;\n setPhase(Phase.PromptPicker);\n },\n },\n // Conditional enter binding — only active during the Greeting\n // (where it short-circuits the typewriter pacing). PickerMenu\n // owns enter in the picker phases; Running flips straight to\n // FollowUp the moment the stream completes.\n ...(canSkipForward\n ? [\n {\n match: KeyMatch.Return,\n label: 'enter',\n action: 'continue',\n handler: () => {\n setPhase(Phase.PromptPicker);\n },\n },\n ]\n : []),\n ]);\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box marginTop={1} flexDirection=\"column\">\n {phase === Phase.Choose && (\n <ChoosePhase error={loginError} onSelect={handleChoice} />\n )}\n\n {phase === Phase.Authenticating && (\n <AuthenticatingPhase loginUrl={session.loginUrl} />\n )}\n\n {phase === Phase.Greeting && (\n <GreetingPhase\n greeting={greeting}\n userDisplayName={session.apiUser?.first_name || null}\n onComplete={() => setPhase(Phase.PromptPicker)}\n />\n )}\n\n {phase === Phase.PromptPicker && (\n <PromptPickerPhase\n promptKit={kit}\n crossSell={crossSell}\n onSelect={handlePromptPick}\n />\n )}\n\n {phase === Phase.Running && runningPrompt && (\n <RunningPhase\n prompt={runningPrompt}\n chunks={runChunks}\n startedAt={runStartedAt}\n frozenDurationSecs={runDurationSecs}\n runCount={runCount}\n maxRuns={MAX_PROMPT_RUNS}\n />\n )}\n\n {phase === Phase.FollowUp && (\n <Box flexDirection=\"column\" flexGrow={1}>\n {/* Result area absorbs flex and shrinks first when the\n terminal is short. `capTextChunks` does the actual\n row-aware truncation; flexShrink here is belt-and-\n suspenders so Ink's layout never squeezes the picker. */}\n {runningPrompt && (\n <Box flexDirection=\"column\" flexShrink={1}>\n <RunningPhase\n prompt={runningPrompt}\n chunks={runChunks}\n startedAt={runStartedAt}\n frozenDurationSecs={runDurationSecs}\n runCount={runCount}\n maxRuns={MAX_PROMPT_RUNS}\n />\n </Box>\n )}\n {/* Picker is pinned: flexShrink={0} means it never gives\n up rows to siblings. flexBasis=\"auto\" keeps its\n natural height. */}\n <Box marginTop={1} flexShrink={0} flexDirection=\"column\">\n <FollowUpPhase\n lastToolName={lastToolName}\n lastPrompt={runningPrompt}\n chunks={runChunks}\n role={session.roleAtOrganization}\n branchHistory={branchHistory}\n canPickAnother={canPickAnother}\n maxRuns={MAX_PROMPT_RUNS}\n onSelect={handleFollowUpPick}\n />\n </Box>\n </Box>\n )}\n\n {phase === Phase.Goodbye && (\n <GoodbyePhase\n installedClients={session.mcpInstalledClients}\n role={session.roleAtOrganization}\n integration={session.integration}\n engaged={branchHistory.length > 0}\n onClose={closeWizard}\n />\n )}\n </Box>\n </Box>\n );\n};\n\n// ── Choose phase ───────────────────────────────────────────────────────\n\ninterface ChoosePhaseProps {\n error: string | null;\n onSelect: (value: ChoiceValue | ChoiceValue[]) => void;\n}\n\nconst ChoosePhase = ({ error, onSelect }: ChoosePhaseProps) => {\n return (\n <Box flexDirection=\"column\">\n <Text bold color={Colors.accent}>\n PostHog MCP\n </Text>\n\n <Box marginTop={1}>\n <Text>\n With MCP your agent works directly with the PostHog platform. You can\n prompt it to:\n </Text>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text>\n <Text color=\"cyan\">{Icons.diamond}</Text> Build dashboards\n </Text>\n <Text>\n <Text color=\"cyan\">{Icons.diamond}</Text> Run SQL queries\n </Text>\n <Text>\n <Text color=\"cyan\">{Icons.diamond}</Text> Deploy feature flags\n </Text>\n <Text>\n <Text color=\"cyan\">{Icons.diamond}</Text> Debug exceptions and errors\n </Text>\n <Text>\n <Text color=\"cyan\">{Icons.diamond}</Text> And lots more...\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text>Want a live demo using real data from your project?</Text>\n </Box>\n\n <Box>\n <PickerMenu\n options={[\n { label: 'Start MCP tutorial', value: ChoiceValue.Login },\n { label: 'Exit', value: ChoiceValue.Exit },\n ]}\n onSelect={onSelect}\n />\n </Box>\n {error && (\n <Box marginTop={1}>\n <Text color=\"red\">Login failed: {error}. Try again or exit.</Text>\n </Box>\n )}\n </Box>\n );\n};\n\n// ── Authenticating phase ───────────────────────────────────────────────\n\ninterface AuthenticatingPhaseProps {\n loginUrl: string | null;\n}\n\nconst AuthenticatingPhase = ({ loginUrl }: AuthenticatingPhaseProps) => (\n <Box flexDirection=\"column\">\n <LoadingBox message=\"Waiting for authentication...\" />\n {loginUrl && (\n <Box marginTop={1} marginBottom={1} flexDirection=\"column\">\n <Text>\n <Text dimColor>If the browser didn't open, copy and paste:</Text>\n {'\\n\\n'}\n <Text color=\"cyan\">{loginUrl}</Text>\n </Text>\n </Box>\n )}\n </Box>\n);\n\n// ── Greeting phase ─────────────────────────────────────────────────────\n\ninterface GreetingPhaseProps {\n greeting: RoleGreeting;\n userDisplayName: string | null;\n onComplete: () => void;\n}\n\nconst GreetingPhase = ({\n greeting,\n userDisplayName,\n onComplete,\n}: GreetingPhaseProps) => {\n // Sequence: optional first-name greeting → role-tuned headline →\n // bullets reveal line-by-line → outro fades in → handoff to picker.\n //\n // Pacing notes: `pause` is the time the sequencer waits AFTER a\n // block finishes before advancing — that's the user's reading\n // window. Each typed block is \"ready to read\" only after the\n // typewriter finishes, so the pauses are sized for the absorbed\n // length, not the typing time.\n const blocks: ContentBlock[] = [];\n\n if (userDisplayName) {\n blocks.push({\n content: `Hi ${userDisplayName}!`,\n mode: TextRevealMode.Typewriter,\n animationInterval: 70,\n pause: 1200,\n });\n }\n\n blocks.push({\n content: greeting.headline,\n mode: TextRevealMode.Typewriter,\n animationInterval: 45,\n pause: 2000,\n });\n\n blocks.push({\n type: 'lines',\n lines: greeting.bullets.map((bullet, i) => (\n <Text key={i}>\n <Text color={Colors.primary}>{Icons.diamond}</Text>{' '}\n <Text dimColor>{bullet}</Text>\n </Text>\n )),\n interval: 700,\n pause: 2200,\n });\n\n blocks.push({\n content: greeting.outro,\n mode: TextRevealMode.Typewriter,\n animationInterval: 38,\n pause: 1800,\n });\n\n return (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold color={Colors.accent}>\n MCP tutorial\n </Text>\n </Box>\n <ContentSequencer\n blocks={blocks}\n mode={TextRevealMode.Typewriter}\n blockInterval={500}\n onSequenceComplete={onComplete}\n />\n </Box>\n );\n};\n\n// ── Prompt picker phase ────────────────────────────────────────────────\n\ninterface PromptPickerPhaseProps {\n promptKit: PromptOption[];\n crossSell: PromptOption[];\n onSelect: (value: string | string[]) => void;\n}\n\nconst PromptPickerPhase = ({\n promptKit,\n crossSell,\n onSelect,\n}: PromptPickerPhaseProps) => {\n // PINNED_FIRST_PROMPT is the always-first option — a safe generic\n // read (\"Show me my top 5 events from the last 7 days\") that works\n // on any project regardless of role or setup. Cross-sells follow,\n // then the role kit. Dedupe by prompt text so the pinned entry\n // doesn't appear twice when the role kit also contains it. Cap at\n // 4 options total so the picker fits without scrolling.\n const seenPrompts = new Set<string>();\n const options = [PINNED_FIRST_PROMPT, ...crossSell, ...promptKit]\n .filter((o) => {\n if (seenPrompts.has(o.prompt)) return false;\n seenPrompts.add(o.prompt);\n return true;\n })\n .slice(0, 4)\n .map((o) => ({\n label: o.product\n ? `Try ${o.product} — ${o.label ?? o.prompt}`\n : o.label ?? o.prompt,\n value: o.prompt,\n }));\n\n return (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold color={Colors.accent}>\n MCP tutorial\n </Text>\n </Box>\n <Box marginBottom={1}>\n <Text>Pick a prompt to see the PostHog MCP in action.</Text>\n </Box>\n <PickerMenu\n options={options}\n optionMarginBottom={1}\n onSelect={onSelect}\n />\n <Box marginTop={2}>\n <Text>\n <Text bold>[esc]</Text>\n <Text> to exit</Text>\n </Text>\n </Box>\n </Box>\n );\n};\n\n// ── Running phase ──────────────────────────────────────────────────────\n\ninterface RunningPhaseProps {\n prompt: string;\n chunks: AgentChunk[];\n startedAt: number | null;\n /** Set the instant the stream finishes; freezes the displayed elapsed\n * time so re-renders under FollowUp don't keep ticking it forward. */\n frozenDurationSecs: number | null;\n runCount: number;\n maxRuns: number;\n}\n\nconst RunningPhase = ({\n prompt,\n chunks,\n startedAt,\n frozenDurationSecs,\n runCount,\n maxRuns,\n}: RunningPhaseProps) => {\n const isDone = chunks.some((c) => c.kind === 'done');\n const errorChunk = chunks.find((c) => c.kind === 'error');\n const finished = isDone || !!errorChunk;\n const elapsed =\n frozenDurationSecs ??\n (startedAt ? Math.round((Date.now() - startedAt) / 1000) : 0);\n\n // When finished, collapse to just the agent's final answer + any\n // error. The tool-call / tool-result chatter has already served its\n // purpose as a \"work in progress\" indicator. We also drop every text\n // block EXCEPT the last one — Sonnet often emits a \"I'll query X…\"\n // preamble alongside its first tool_use, and showing both the\n // preamble and the final answer doubles the noise above the picker.\n const visibleChunks = finished\n ? capTextChunks(collapseToFinalAnswer(chunks))\n : chunks;\n\n return (\n <Box flexDirection=\"column\">\n <Text>\n <Text bold>Prompt:</Text> <Text color={Colors.accent}>{prompt}</Text>\n </Text>\n\n <Box marginTop={1} gap={1}>\n {/* Spinner spins for the full duration of the stream — visual\n confirmation that work is still in flight even during pauses\n between chunks. */}\n {!finished && <Spinner />}\n <Text bold={finished}>\n {finished\n ? errorChunk\n ? `Failed after ${elapsed}s.`\n : `Done in ${elapsed}s.`\n : 'Streaming from PostHog MCP'}\n </Text>\n <Text dimColor>\n ({runCount}/{maxRuns} prompts)\n </Text>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n {visibleChunks.map((chunk, idx) => (\n <ChunkLine key={idx} chunk={chunk} />\n ))}\n </Box>\n </Box>\n );\n};\n\n/**\n * Strip everything except the agent's final answer + any error chunks.\n * Drops tool-call / tool-result chatter (their work is done once the\n * stream completes) and any text blocks emitted BEFORE the last text\n * block — those are typically Sonnet's \"I'll query X…\" preamble that\n * arrives alongside the first tool_use and adds noise above the picker.\n *\n * If the run produced no text at all (pure tool calls, or only errors),\n * fall through to whatever chunks survived so the user isn't left with\n * a blank result.\n */\nfunction collapseToFinalAnswer(chunks: AgentChunk[]): AgentChunk[] {\n const textChunks = chunks.filter((c) => c.kind === 'text');\n const errors = chunks.filter((c) => c.kind === 'error');\n if (textChunks.length === 0) return errors;\n // Keep only the last text block — that's the model's final answer.\n // Anything earlier was preamble emitted alongside tool_use.\n return [textChunks[textChunks.length - 1], ...errors];\n}\n\n/**\n * Belt-and-suspenders fallback for runs where Claude ignored the\n * terminal-fit system prompt and produced an overlong response. Joins\n * all text chunks, then walks them from the bottom keeping only as many\n * lines as fit in the visual row budget — wide lines that wrap to\n * multiple rows on a narrow terminal cost their wrapped row count, not\n * 1. Prepends an indicator showing how many source lines got cut. Tool\n * calls, results, and errors are preserved separately so they don't\n * disappear into the truncation.\n *\n * Visual-row-aware truncation is what makes the FollowUp picker feel\n * pinned: a 5-row table that wraps to 12 visual rows on a 60-col\n * terminal correctly counts as 12, so the cap leaves exactly the room\n * the picker needs.\n */\nfunction capTextChunks(chunks: AgentChunk[]): AgentChunk[] {\n const rows = process.stdout.rows ?? 24;\n const cols = process.stdout.columns ?? 120;\n // Reserve rows for the FollowUp picker that sits below the result:\n // recap line, 4 picker options, marginTop, plus the prompt + status\n // chrome above the result and the global keyboard hints bar. Be\n // pessimistic — `process.stdout.rows` doesn't always match the actual\n // visible area (terminal padding, host UI chrome, etc.), and an\n // off-by-a-few rows shows up as the result overlapping the picker.\n // Better to leave the picker breathing room than risk overprint.\n const maxVisualRows = Math.max(3, rows - 19);\n\n const textChunks = chunks.filter((c) => c.kind === 'text');\n const errors = chunks.filter((c) => c.kind === 'error');\n if (textChunks.length === 0) return chunks;\n\n const joined = textChunks.map((c) => c.text).join('');\n const lines = joined.split('\\n');\n\n // How many visual rows does this source line consume after wrap?\n // Empty lines still take 1; everything else is ceil(width / cols).\n const visualRows = (line: string): number =>\n Math.max(1, Math.ceil(line.length / cols));\n\n // Walk from the bottom, accumulating visual rows until budget runs\n // out, so we keep the tail of the message (which has the punchline).\n let used = 0;\n let keepFrom = lines.length;\n for (let i = lines.length - 1; i >= 0; i--) {\n const cost = visualRows(lines[i]);\n if (used + cost > maxVisualRows) break;\n used += cost;\n keepFrom = i;\n }\n\n if (keepFrom === 0) return chunks;\n\n const hidden = keepFrom;\n const tail = lines.slice(keepFrom).join('\\n');\n\n return [\n {\n kind: 'text',\n text: `[${hidden} line${\n hidden === 1 ? '' : 's'\n } above — expand terminal to see more]\\n\\n${tail}`,\n },\n ...errors,\n ];\n}\n\ninterface ChunkLineProps {\n chunk: AgentChunk;\n}\n\nconst ChunkLine = ({ chunk }: ChunkLineProps) => {\n if (chunk.kind === 'text') {\n return <Text>{chunk.text}</Text>;\n }\n if (chunk.kind === 'tool-call') {\n return (\n <Text>\n {' '}\n <Text color=\"cyan\">↳ {chunk.toolName}</Text>\n {chunk.detail ? ` ${chunk.detail}` : ''}\n </Text>\n );\n }\n if (chunk.kind === 'tool-result') {\n return (\n <Text>\n {' '}\n <Text color=\"green\">✓</Text> {chunk.detail}\n </Text>\n );\n }\n if (chunk.kind === 'error') {\n return <Text color=\"red\">Error: {chunk.text}</Text>;\n }\n // 'done' — no visual chunk; the dim status line above handles it.\n return null;\n};\n\n// ── Follow-up phase ────────────────────────────────────────────────────\n\ninterface FollowUpPhaseProps {\n lastToolName: string | null;\n lastPrompt: string | null;\n chunks: AgentChunk[];\n role: string | null;\n branchHistory: string[];\n canPickAnother: boolean;\n maxRuns: number;\n onSelect: (value: string | string[]) => void;\n}\n\nconst FollowUpPhase = ({\n lastToolName,\n lastPrompt,\n chunks,\n role,\n branchHistory,\n canPickAnother,\n maxRuns,\n onSelect,\n}: FollowUpPhaseProps) => {\n const followUps = useMemo(\n () =>\n getFollowUps({\n lastToolName,\n lastPrompt: lastPrompt || '',\n role,\n branchHistory,\n }),\n [lastToolName, lastPrompt, role, branchHistory],\n );\n\n // When the cap is reached, only the exit entry is available. Follow-up\n // entries always set `label`; fall back to `prompt` defensively in case\n // a future contributor omits it.\n const options = canPickAnother\n ? followUps.map((f) => ({ label: f.label ?? f.prompt, value: f.prompt }))\n : [{ label: 'Exit', value: FOLLOW_UP_EXIT_SENTINEL }];\n\n const errorChunk = chunks.find((c) => c.kind === 'error');\n const recap = errorChunk\n ? 'That one errored out — try a different angle?'\n : !canPickAnother\n ? `You've hit the ${maxRuns}-prompt tutorial cap.`\n : `Want to keep exploring? Select a follow-up prompt.`;\n\n return (\n <Box flexDirection=\"column\">\n <Text>{recap}</Text>\n <PickerMenu options={options} onSelect={onSelect} />\n </Box>\n );\n};\n\n// ── Goodbye phase ──────────────────────────────────────────────────────\n// Always shown before final dismissal. Reminds the user where MCP is\n// available and what to ask once they're back in their IDE.\n\ninterface GoodbyePhaseProps {\n installedClients: string[];\n role: string | null;\n integration: Integration | null;\n /** True if the user actually ran at least one prompt this session. */\n engaged: boolean;\n onClose: () => void;\n}\n\nconst GoodbyePhase = ({\n installedClients,\n role,\n integration,\n engaged,\n onClose,\n}: GoodbyePhaseProps) => {\n // Take 3 starter prompts from the role-tailored kit. These act as\n // \"next time you open your IDE, try this\" reminders.\n const kit = getRolePrompts(role, integration);\n const samples = kit.slice(0, 3);\n\n const headline = engaged\n ? 'Nice work. You can keep talking to PostHog anytime.'\n : \"You're all set — PostHog MCP is here when you're ready.\";\n\n const introLine =\n installedClients.length > 0 ? (\n <Text>\n MCP is set up in{' '}\n <Text bold color={Colors.primary}>\n {installedClients.join(', ')}\n </Text>\n . Open one and try a prompt like:\n </Text>\n ) : (\n <Text>\n Wherever you have MCP set up (Claude Code, Cursor, VS Code, Windsurf,\n Zed, etc.), open the agent and try a prompt like:\n </Text>\n );\n\n return (\n <Box flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold color={Colors.accent}>\n {headline}\n </Text>\n </Box>\n\n <Box marginBottom={1}>{introLine}</Box>\n\n <Box marginBottom={1} flexDirection=\"column\">\n {samples.map((p, i) => (\n <Box key={i}>\n <Text color={Colors.primary}>{Icons.triangleSmallRight}</Text>\n <Text> </Text>\n <Text dimColor>{p.prompt}</Text>\n </Box>\n ))}\n </Box>\n\n <Box marginBottom={1}>\n <Text dimColor>\n Re-run this tutorial anytime with{' '}\n <Text bold>npx @posthog/wizard mcp tutorial</Text>.\n </Text>\n </Box>\n\n <PickerMenu\n options={[{ label: 'Close', value: 'close' }]}\n onSelect={() => onClose()}\n />\n </Box>\n );\n};\n","import { Box, Text } from 'ink';\n\ninterface AreaHeaderRowProps {\n area: string;\n resolved: number;\n total: number;\n}\n\n/** Sub-header row inside the scrollable body — one per area group. */\nexport const AreaHeaderRow = ({\n area,\n resolved,\n total,\n}: AreaHeaderRowProps) => (\n <Box flexShrink={0} marginTop={1}>\n <Text bold color=\"cyan\">\n {area}{' '}\n </Text>\n <Text dimColor>\n ({resolved}/{total})\n </Text>\n </Box>\n);\n","import { MAX_WIDTH } from '@ui/tui/primitives/ScreenContainer';\n\n/** Terminal rows used by chrome outside the viewer\n * (TitleBar, spacer, screen padding, status bar, tab bar). */\nexport const CHROME_ROWS = 10;\n\n/** Rows used by the viewer's own header / footer\n * (title, subtitle, top summary, spacer, column headers, divider,\n * scroll-up marker, scroll-down marker, legend, footer summary). */\nexport const VIEWER_CHROME_BASE = 10;\n\nexport const COL_AREA_WIDTH = 18;\nexport const COL_LABEL_MIN = 28;\nexport const COL_GAP = 2;\n\nexport interface ViewerLayout {\n cols: number;\n visibleHeight: number;\n viewerChrome: number;\n padding: number;\n statusWidth: number;\n areaWidth: number;\n labelWidth: number;\n colGap: number;\n dividerWidth: number;\n detailIndent: number;\n detailWidth: number;\n}\n\n/** ScreenContainer wraps content in paddingX={1} inside a width capped at\n * MAX_WIDTH, so the actual width available to the viewer is\n * min(cols, MAX_WIDTH) - 2. */\nfunction getViewerWidth(rawCols: number): number {\n return Math.min(MAX_WIDTH, rawCols) - 2;\n}\n\nexport function computeLayout(rawCols: number, termRows: number): ViewerLayout {\n const cols = getViewerWidth(rawCols);\n const padding = 2;\n const statusWidth = 2;\n\n // CHECK flexes to consume the rest of the row so long labels stay readable\n // instead of getting truncated.\n const fixedExceptLabel =\n padding + statusWidth + COL_GAP + COL_AREA_WIDTH + COL_GAP + COL_GAP;\n const labelWidth = Math.max(COL_LABEL_MIN, cols - fixedExceptLabel);\n\n const detailIndent = statusWidth + COL_GAP + COL_AREA_WIDTH + COL_GAP;\n\n const viewerChrome = VIEWER_CHROME_BASE;\n const visibleHeight = Math.max(5, termRows - CHROME_ROWS - viewerChrome);\n\n return {\n cols,\n visibleHeight,\n viewerChrome,\n padding,\n statusWidth,\n areaWidth: COL_AREA_WIDTH,\n labelWidth,\n colGap: COL_GAP,\n dividerWidth: Math.max(20, cols - padding),\n detailIndent,\n detailWidth: Math.max(20, cols - detailIndent - padding),\n };\n}\n\nexport function truncate(text: string, max: number): string {\n if (max <= 0) return '';\n if (text.length <= max) return text;\n return text.slice(0, Math.max(1, max - 1)) + '…';\n}\n","import { Box, Text } from 'ink';\nimport {\n AUDIT_SEVERITY_STYLE,\n type AuditCheck,\n} from '@lib/programs/audit/types';\nimport { truncate, type ViewerLayout } from './layout.js';\n\ninterface CheckRowProps {\n item: AuditCheck;\n layout: ViewerLayout;\n}\n\nexport const CheckRow = ({ item, layout }: CheckRowProps) => {\n const style = AUDIT_SEVERITY_STYLE[item.status];\n return (\n <Box flexShrink={0}>\n <Box width={layout.statusWidth + layout.colGap}>\n <Text color={style.color}>{style.glyph}</Text>\n </Box>\n <Box width={layout.areaWidth + layout.colGap}>\n <Text dimColor>{truncate(item.area, layout.areaWidth)}</Text>\n </Box>\n <Box width={layout.labelWidth + layout.colGap}>\n <Text\n bold={item.status !== 'pending'}\n dimColor={item.status === 'pending'}\n >\n {truncate(item.label, layout.labelWidth)}\n </Text>\n </Box>\n </Box>\n );\n};\n","import { Box, Text } from 'ink';\nimport type { AuditCheck } from '@lib/programs/audit/types';\nimport type { ViewerLayout } from './layout.js';\n\ninterface DetailRowProps {\n item: AuditCheck;\n layout: ViewerLayout;\n}\n\n/** Format a `details` string. If it parses as a JSON object, render it as\n * indented key: value lines (skipping huge nested arrays/objects which we\n * truncate). Otherwise return the original text. v3000 emits structured\n * JSON for several event-quality checks — a raw dump is unreadable. */\nfunction formatDetails(raw: string): string[] {\n const trimmed = raw.trim();\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return [raw];\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return [raw];\n }\n if (parsed === null || typeof parsed !== 'object') return [raw];\n const lines: string[] = [];\n const renderValue = (v: unknown): string => {\n if (v === null) return 'null';\n if (typeof v === 'string') return v;\n if (typeof v === 'number' || typeof v === 'boolean') return String(v);\n if (Array.isArray(v)) {\n if (v.length === 0) return '[]';\n const allPrimitive = v.every((e) => e === null || typeof e !== 'object');\n if (allPrimitive) return v.map(renderValue).join(', ');\n return `[${v.length} item${v.length === 1 ? '' : 's'}]`;\n }\n if (typeof v === 'object') {\n const keys = Object.keys(v);\n return `{${keys.length} field${keys.length === 1 ? '' : 's'}}`;\n }\n return String(v);\n };\n for (const [key, value] of Object.entries(parsed)) {\n lines.push(`${key}: ${renderValue(value)}`);\n }\n return lines.length > 0 ? lines : [raw];\n}\n\n/** Indented under the CHECK column; wrap continuation aligns with the prefix. */\nexport const DetailRow = ({ item, layout }: DetailRowProps) => {\n const detailLines = item.details ? formatDetails(item.details) : [];\n return (\n <Box flexShrink={0}>\n <Box width={layout.detailIndent} />\n <Box flexDirection=\"column\" width={layout.detailWidth}>\n {item.file && (\n <Text dimColor wrap=\"wrap\">\n {`↳ File: ${item.file}`}\n </Text>\n )}\n {detailLines.map((line, i) => (\n <Text key={i} dimColor italic wrap=\"wrap\">\n {i === 0 ? `${item.file ? ' ' : '↳ '}${line}` : ` ${line}`}\n </Text>\n ))}\n </Box>\n </Box>\n );\n};\n","import { Text } from 'ink';\n\nexport const Legend = () => (\n <Text>\n <Text color=\"green\">✔ pass</Text>\n <Text dimColor>{' · '}</Text>\n <Text color=\"red\">✘ error</Text>\n <Text dimColor>{' · '}</Text>\n <Text color=\"yellow\">⚠ warning</Text>\n <Text dimColor>{' · '}</Text>\n <Text color=\"cyan\">• suggestion</Text>\n </Text>\n);\n","import { Box, Text } from 'ink';\nimport type { AuditCheck, AuditStatus } from '@lib/programs/audit/types';\nimport type { ViewerLayout } from './layout.js';\n\ninterface HeaderProps {\n layout: ViewerLayout;\n}\n\ninterface SummaryProps {\n total: number;\n counts: Record<AuditStatus, number>;\n}\n\nfunction statusCounts(checks: AuditCheck[]): Record<AuditStatus, number> {\n const out: Record<AuditStatus, number> = {\n pending: 0,\n pass: 0,\n error: 0,\n warning: 0,\n suggestion: 0,\n };\n for (const c of checks) out[c.status] += 1;\n return out;\n}\n\nexport { statusCounts };\n\nexport const Header = ({ layout }: HeaderProps) => (\n <Box>\n <Box width={layout.statusWidth + layout.colGap}>\n <Text dimColor bold>\n {' '}\n </Text>\n </Box>\n <Box width={layout.areaWidth + layout.colGap}>\n <Text dimColor bold>\n AREA\n </Text>\n </Box>\n <Box width={layout.labelWidth + layout.colGap}>\n <Text dimColor bold>\n CHECK\n </Text>\n </Box>\n </Box>\n);\n\nexport const Summary = ({ total, counts }: SummaryProps) => (\n <Text dimColor>\n {total} total · {counts.pending} pending · {counts.error} errors ·{' '}\n {counts.warning} warnings · {counts.suggestion} suggestions · {counts.pass}{' '}\n passes\n </Text>\n);\n","import { Legend } from './Legend.js';\nimport { Summary } from './Header.js';\nimport type { AuditStatus } from '@lib/programs/audit/types';\n\ninterface FooterProps {\n total: number;\n counts: Record<AuditStatus, number>;\n}\n\nexport const Footer = ({ total, counts }: FooterProps) => (\n <>\n <Legend />\n <Summary total={total} counts={counts} />\n </>\n);\n","import type { AuditCheck, AuditStatus } from '@lib/programs/audit/types';\n\nconst STATUS_ORDER: Record<AuditStatus, number> = {\n error: 0,\n warning: 1,\n suggestion: 2,\n pass: 3,\n pending: 4,\n};\n\n/** Audit areas in the order they should be displayed. Areas not listed\n * here fall through to alphabetical order at the end. Mirrors the\n * Full audit section grouping in the generated report. */\nconst AREA_ORDER: string[] = [\n 'Installation',\n 'Identification',\n 'Event Capture',\n 'Event Quality',\n 'Feature Flags',\n 'Session Replay',\n 'Session Replay — Optimize',\n 'Use Case: Expansion',\n 'Additional Sections',\n];\n\nfunction areaRank(area: string): number {\n const idx = AREA_ORDER.indexOf(area);\n return idx === -1 ? AREA_ORDER.length : idx;\n}\n\n/** Issues at the top (error → warning → suggestion), then passes, then pending todos. */\nexport function sortChecks(checks: ReadonlyArray<AuditCheck>): AuditCheck[] {\n return [...checks].sort((a, b) => {\n const da = STATUS_ORDER[a.status] - STATUS_ORDER[b.status];\n if (da !== 0) return da;\n return a.area.localeCompare(b.area);\n });\n}\n\nexport interface AreaGroup {\n area: string;\n checks: AuditCheck[];\n counts: { total: number; resolved: number };\n}\n\n/** Group checks by area, in AREA_ORDER. Within each area, sort by status. */\nexport function groupChecksByArea(\n checks: ReadonlyArray<AuditCheck>,\n): AreaGroup[] {\n const byArea = new Map<string, AuditCheck[]>();\n for (const c of checks) {\n const list = byArea.get(c.area);\n if (list) list.push(c);\n else byArea.set(c.area, [c]);\n }\n const groups: AreaGroup[] = [];\n for (const [area, areaChecks] of byArea) {\n const sorted = [...areaChecks].sort(\n (a, b) => STATUS_ORDER[a.status] - STATUS_ORDER[b.status],\n );\n const resolved = sorted.filter((c) => c.status !== 'pending').length;\n groups.push({\n area,\n checks: sorted,\n counts: { total: sorted.length, resolved },\n });\n }\n groups.sort((a, b) => {\n const dr = areaRank(a.area) - areaRank(b.area);\n if (dr !== 0) return dr;\n return a.area.localeCompare(b.area);\n });\n return groups;\n}\n","/**\n * AuditChecksViewer — \"Audit plan\" tab.\n *\n * Renders the full audit ledger as a scrollable, area-grouped list that\n * mirrors the structure of the final report. Each area gets a sub-header\n * with a resolved/total count; checks within an area are sorted by\n * severity (error → warning → suggestion → pass → pending).\n *\n * Two interactions, both registered via `useKeyBindings`:\n * - `e` — toggle detail rows (file:line + agent's `details` text)\n * - `↑` / `↓` — scroll one row at a time, clamped to content bounds\n *\n * Auto-expands on first mount when the ledger contains any issue, since\n * the AuditAreaPane's `[→] View issues` hint sends users here precisely\n * to read those details.\n */\n\nimport { Box, Text } from 'ink';\nimport { Fragment, useMemo, useState, type ReactNode } from 'react';\nimport { useStdoutDimensions } from '@ui/tui/hooks/useStdoutDimensions';\nimport {\n KeyMatch,\n useKeyBindings,\n type KeyBinding,\n} from '@ui/tui/hooks/useKeyBindings';\nimport type { AuditCheck } from '@lib/programs/audit/types';\nimport { AreaHeaderRow } from './AreaHeaderRow.js';\nimport { CheckRow } from './CheckRow.js';\nimport { DetailRow } from './DetailRow.js';\nimport { Footer } from './Footer.js';\nimport { Header, Summary, statusCounts } from './Header.js';\nimport { computeLayout } from './layout.js';\nimport { groupChecksByArea } from './sort.js';\n\ninterface AuditChecksViewerProps {\n checks: AuditCheck[];\n}\n\nexport const AuditChecksViewer = ({ checks }: AuditChecksViewerProps) => {\n // ── Layout ─────────────────────────────────────────────────────────\n const [rawCols, termRows] = useStdoutDimensions();\n const layout = computeLayout(rawCols, termRows);\n const totalHeight = layout.visibleHeight + layout.viewerChrome;\n\n // ── Group by area ──────────────────────────────────────────────────\n const groups = useMemo(() => groupChecksByArea(checks), [checks]);\n const counts = useMemo(() => statusCounts(checks), [checks]);\n\n // ── Expand state ───────────────────────────────────────────────────\n const hasExpandable = checks.some((c) => Boolean(c.details || c.file));\n const hasIssues = checks.some(\n (c) =>\n c.status === 'error' ||\n c.status === 'warning' ||\n c.status === 'suggestion',\n );\n const [expanded, setExpanded] = useState(hasIssues && hasExpandable);\n\n // ── Flat row list ──────────────────────────────────────────────────\n // One ReactNode per visible terminal row so scroll math stays simple.\n // Sub-header + check rows + (optional) detail rows interleave here.\n const allRows = useMemo<ReactNode[]>(() => {\n const rows: ReactNode[] = [];\n for (const group of groups) {\n rows.push(\n <AreaHeaderRow\n key={`header-${group.area}`}\n area={group.area}\n resolved={group.counts.resolved}\n total={group.counts.total}\n />,\n );\n for (const item of group.checks) {\n rows.push(<CheckRow key={item.id} item={item} layout={layout} />);\n if (expanded && (item.details || item.file)) {\n rows.push(\n <DetailRow key={`${item.id}-detail`} item={item} layout={layout} />,\n );\n }\n }\n }\n return rows;\n }, [groups, expanded, layout]);\n\n // ── Scroll viewport ────────────────────────────────────────────────\n const [offset, setOffset] = useState(0);\n const maxOffset = Math.max(0, allRows.length - layout.visibleHeight);\n const clampedOffset = Math.min(offset, maxOffset);\n const hiddenAbove = clampedOffset;\n const hiddenBelow = Math.max(\n 0,\n allRows.length - clampedOffset - layout.visibleHeight,\n );\n\n // ── Key bindings ───────────────────────────────────────────────────\n const bindings: KeyBinding[] = [];\n if (hasExpandable) {\n bindings.push({\n match: 'e',\n label: 'e',\n action: expanded ? 'collapse details' : 'expand details',\n handler: () => setExpanded((prev) => !prev),\n });\n }\n bindings.push({\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '↑↓',\n action: 'scroll',\n handler: (_input, key) => {\n if (key.upArrow) setOffset((o) => Math.max(0, o - 1));\n else if (key.downArrow) setOffset((o) => Math.min(maxOffset, o + 1));\n },\n });\n useKeyBindings('audit-checks-viewer', bindings);\n\n // ── Render ─────────────────────────────────────────────────────────\n const visibleRows = allRows.slice(\n clampedOffset,\n clampedOffset + layout.visibleHeight,\n );\n\n // Dynamic subtitle — lists the actual areas in the ledger.\n const subtitle =\n groups.length === 0\n ? 'No checks yet.'\n : `Review across ${groups.length} ${\n groups.length === 1 ? 'area' : 'areas'\n } — mirrors the final report.`;\n\n return (\n <Box flexDirection=\"column\" paddingX={1} height={totalHeight}>\n {/* Title + dynamic subtitle */}\n <Text bold>Audit plan</Text>\n <Text dimColor>{subtitle}</Text>\n\n {/* Top summary — same as Footer summary, promoted here for at-a-glance */}\n <Summary total={checks.length} counts={counts} />\n <Box height={1} />\n\n {/* Column headers + divider */}\n <Header layout={layout} />\n <Text dimColor>{'─'.repeat(layout.dividerWidth)}</Text>\n\n {/* Scroll-up marker */}\n <Text dimColor>{hiddenAbove > 0 ? `↑ ${hiddenAbove} more` : ' '}</Text>\n\n {/* Scrollable body */}\n <Box\n flexDirection=\"column\"\n height={layout.visibleHeight}\n overflow=\"hidden\"\n >\n {visibleRows.map((node, i) => (\n <Fragment key={`row-${clampedOffset + i}`}>{node}</Fragment>\n ))}\n </Box>\n\n {/* Scroll-down marker */}\n <Text dimColor>{hiddenBelow > 0 ? `↓ ${hiddenBelow} more` : ' '}</Text>\n\n {/* Legend (counts already shown at the top) */}\n <Footer total={checks.length} counts={counts} />\n </Box>\n );\n};\n","import { Box } from 'ink';\nimport type { ReactNode } from 'react';\nimport { Colors } from '@ui/tui/styles';\n\n/** Slide shape consumed by `AuditAreaPane`. One per `AuditCheck.area` value. */\nexport interface AreaSlide {\n area: string;\n /** One element per paragraph — rendered as separate `<Text>` blocks. */\n intro: string[];\n visual?: ReactNode;\n docsUrl: string;\n}\n\n/** Narrow bordered box for the small ASCII illustrations in baseline slides. */\nexport const VisualBox = ({ children }: { children: ReactNode }) => (\n <Box\n borderStyle=\"single\"\n borderColor={Colors.muted}\n paddingX={1}\n flexDirection=\"column\"\n marginBottom={1}\n >\n {children}\n </Box>\n);\n","import { Text } from 'ink';\nimport { VisualBox, type AreaSlide } from './shared.js';\n\nconst InstallationVisual = () => (\n <VisualBox>\n <Text dimColor>app boot</Text>\n <Text>\n <Text dimColor>{' ▼ '}</Text>\n <Text color=\"green\">posthog.init(...)</Text>\n <Text dimColor>{' once'}</Text>\n </Text>\n <Text dimColor>{' │'}</Text>\n <Text>\n <Text dimColor>{' ▼ '}</Text>\n <Text color=\"cyan\">posthog.capture('pageview')</Text>\n </Text>\n <Text>\n <Text dimColor>{' '}</Text>\n <Text color=\"cyan\">posthog.capture('signup')</Text>\n </Text>\n <Text>\n <Text dimColor>{' '}</Text>\n <Text color=\"cyan\">posthog.capture('purchase')</Text>\n </Text>\n </VisualBox>\n);\n\nexport const InstallationSlide: AreaSlide = {\n area: 'Installation',\n intro: [\n \"PostHog releases frequent SDK updates to fix bugs and add new features. We're checking your project's SDK version and making sure it's up to date.\",\n \"We're also checking that your SDK is initialized correctly and in the right part of your app's lifecycle.\",\n \"This ensures you won't miss any autocaptured events.\",\n ],\n visual: <InstallationVisual />,\n docsUrl: 'https://posthog.com/docs/getting-started/install',\n};\n","import { Text } from 'ink';\nimport { VisualBox, type AreaSlide } from './shared.js';\n\nconst IdentificationVisual = () => (\n <VisualBox>\n <Text>\n <Text bold>{'browser '}</Text>\n <Text dimColor>capture</Text>\n <Text>{' ('}</Text>\n <Text color=\"cyan\">u_42</Text>\n <Text>{', \"click\")'}</Text>\n </Text>\n <Text dimColor>{' │'}</Text>\n <Text>\n <Text dimColor>{' ▼ '}</Text>\n <Text color=\"green\">same distinct_id</Text>\n </Text>\n <Text dimColor>{' │'}</Text>\n <Text>\n <Text bold>{'server '}</Text>\n <Text dimColor>capture</Text>\n <Text>{' ('}</Text>\n <Text color=\"cyan\">u_42</Text>\n <Text>{', \"charged\")'}</Text>\n </Text>\n </VisualBox>\n);\n\nexport const IdentificationSlide: AreaSlide = {\n area: 'Identification',\n intro: [\n 'For events to be useful, they need to be reliably attributed to a user.',\n \"We're checking your project's `identify()` calls to make sure they're correctly and consistently implemented.\",\n \"We're also checking that your `distinct_id`s are correctly passed between your client and server runtimes if applicable.\",\n ],\n visual: <IdentificationVisual />,\n docsUrl: 'https://posthog.com/docs/product-analytics/identify',\n};\n","import { Text } from 'ink';\nimport { VisualBox, type AreaSlide } from './shared.js';\n\nconst CaptureVisual = () => (\n <VisualBox>\n <Text>\n <Text color=\"cyan\">{'pageview '}</Text>\n <Text color=\"green\">{'████████████'}</Text>\n <Text dimColor>{' 1000'}</Text>\n </Text>\n <Text>\n <Text color=\"cyan\">{'signup '}</Text>\n <Text color=\"green\">{'████████'}</Text>\n <Text dimColor>{' 640'}</Text>\n </Text>\n <Text>\n <Text color=\"cyan\">{'activated '}</Text>\n <Text color=\"green\">{'█████'}</Text>\n <Text dimColor>{' 410'}</Text>\n </Text>\n <Text>\n <Text color=\"cyan\">{'purchased '}</Text>\n <Text color=\"green\">{'██'}</Text>\n <Text dimColor>{' 120'}</Text>\n </Text>\n </VisualBox>\n);\n\nexport const EventCaptureSlide: AreaSlide = {\n area: 'Event Capture',\n intro: [\n 'Everything you do in PostHog starts with event captures. Every dashboard, insight, funnel, cohort, and replay is built on top of events.',\n \"We're checking that your project's event capture calls cover key user actions and use sensible event names, so you can build high-quality insights and reports.\",\n \"We're also checking that you use a reverse proxy so your events are not blocked by ad blockers or tracking blockers.\",\n ],\n visual: <CaptureVisual />,\n docsUrl: 'https://posthog.com/docs/product-analytics/capture-events',\n};\n","import { Text } from 'ink';\nimport { VisualBox, type AreaSlide } from './shared.js';\n\nconst ReportVisual = () => (\n <VisualBox>\n <Text dimColor>posthog-audit-report.md</Text>\n <Text>\n <Text dimColor>{' # '}</Text>\n <Text>Summary</Text>\n </Text>\n <Text>\n <Text dimColor>{' # '}</Text>\n <Text>Recommended actions</Text>\n </Text>\n <Text>\n <Text dimColor>{' # '}</Text>\n <Text>Full audit</Text>\n </Text>\n </VisualBox>\n);\n\nexport const WriteReportSlide: AreaSlide = {\n area: 'Write report',\n intro: [\n 'Now we write an audit report at ./posthog-audit-report.md. that summarizes our findings.',\n 'The report leads with a summary, then a prioritized list of fixes with file:line citations, then every check we ran grouped by area so nothing is hidden.',\n 'We will upload the report into a PostHog notebook in the next step.',\n ],\n visual: <ReportVisual />,\n docsUrl: 'https://posthog.com/docs/product-analytics/best-practices',\n};\n","import { Text } from 'ink';\nimport { VisualBox, type AreaSlide } from './shared.js';\n\nconst NotebookVisual = () => (\n <VisualBox>\n <Text dimColor>posthog-audit-report.md</Text>\n <Text dimColor>{' │'}</Text>\n <Text>\n <Text dimColor>{' ▼ '}</Text>\n <Text color=\"cyan\">PostHog notebook</Text>\n </Text>\n <Text dimColor>{' # Summary'}</Text>\n <Text dimColor>{' # Recommended actions'}</Text>\n <Text dimColor>{' # Full audit'}</Text>\n </VisualBox>\n);\n\nexport const UploadNotebookSlide: AreaSlide = {\n area: 'Upload notebook',\n intro: [\n 'Next we upload the report into a PostHog notebook so you can share it with your team as a URL.',\n 'Hang tight.',\n 'The markdown file on disk is still there for you to read locally.',\n ],\n visual: <NotebookVisual />,\n docsUrl: 'https://posthog.com/docs/notebooks',\n};\n","/**\n * Slide registry for `AuditAreaPane`. Each entry is a stand-alone module\n * keyed by `AuditCheck.area`. To add a new area, drop a `<area>.tsx` file\n * exporting an `AreaSlide` and append it here.\n */\n\nimport type { AreaSlide } from './shared.js';\nimport { InstallationSlide } from './installation.js';\nimport { IdentificationSlide } from './identification.js';\nimport { EventCaptureSlide } from './eventCapture.js';\nimport { WriteReportSlide } from './writeReport.js';\nimport { UploadNotebookSlide } from './uploadNotebook.js';\n\nexport type { AreaSlide };\n\nexport const AUDIT_AREA_SLIDES: AreaSlide[] = [\n InstallationSlide,\n IdentificationSlide,\n EventCaptureSlide,\n WriteReportSlide,\n UploadNotebookSlide,\n];\n","/**\n * SlackConnectScreen — the dedicated \"Connect Slack\" step shown after the\n * MCP tutorial (`wizard mcp tutorial`), after a successful install\n * (`wizard mcp add`), at the end of the integration flow, and as the whole\n * program in the standalone `wizard slack` flow.\n *\n * Presents the PostHog Slack app plus role-tailored use-cases. The copy\n * adapts to whether Slack is already connected (polled while the screen\n * is up, held as local state):\n * • not connected (or unknown) — nudge + \"Open Slack setup\", which\n * launches the browser at the integration settings page and keeps\n * the screen alive; the poll flips it to connected once the user\n * finishes the manual OAuth step in the browser.\n * • already connected — confirm it and skip the connect CTA, so users\n * who already have it aren't nagged.\n * \"Skip\" / \"Done\" / esc dismiss the step (`slackStepDismissed`) and let\n * the router advance to exit.\n *\n * The mcp and integration flows arrive here already authenticated. The\n * standalone `wizard slack` flow lands without credentials and only\n * triggers OAuth when the user explicitly picks \"Open Slack setup\" —\n * once authed, the connected-state poll lets the screen flip to the\n * \"Slack connected\" copy without nagging users who already have it.\n */\n\nimport { Box, Text } from 'ink';\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react';\n\nimport type { WizardStore } from '@ui/tui/store';\nimport { Colors, Icons } from '@ui/tui/styles';\nimport { PickerMenu, LoadingBox } from '@ui/tui/primitives/index';\nimport { useKeyBindings, KeyMatch } from '@ui/tui/hooks/useKeyBindings';\nimport { getSlackAppCard } from '@lib/mcp-role-prompts';\nimport { fetchSlackConnected } from '@lib/api';\nimport { Program } from '@lib/programs/program-registry';\nimport { getOrAskForProjectData } from '@utils/setup-utils';\nimport { analytics } from '@utils/analytics';\nimport { logToFile } from '@utils/debug';\nimport { openTrackedLink, withUtm } from '@utils/links';\n\ninterface SlackConnectScreenProps {\n store: WizardStore;\n}\n\nenum ChoiceValue {\n Open = 'open',\n Skip = 'skip',\n}\n\nenum Phase {\n /** Default — the marketing card with the picker. */\n Nudge = 'nudge',\n /** User picked \"Open Slack setup\" without credentials; OAuth is in flight. */\n Authenticating = 'authenticating',\n}\n\nconst POLL_INTERVAL_MS = 3000;\n\nexport const SlackConnectScreen = ({ store }: SlackConnectScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const role = store.session.roleAtOrganization;\n const slack = getSlackAppCard();\n const setupUrl = withUtm(slack.setupUrl, 'slack-connect-setup');\n const learnMoreUrl = withUtm(slack.learnMoreUrl, 'slack-connect-learn-more');\n\n const credentials = store.session.credentials;\n\n // `slackConnected` is three-state: null until something has actually\n // checked (the tutorial's prefetch, or this screen's first poll tick).\n const connectedState = store.session.slackConnected;\n const connected = connectedState === true;\n\n // Phase.Nudge is the default; Phase.Authenticating fires only when the\n // no-creds user picks \"Open Slack setup\" — explicit consent for the OAuth\n // dance. Without credentials the connected-state poll can't run, so\n // logging in is what unlocks the screen flipping to \"Slack connected\" on\n // its own once the browser-side Slack OAuth completes.\n const [phase, setPhase] = useState<Phase>(Phase.Nudge);\n const [loginError, setLoginError] = useState<string | null>(null);\n\n // Track whether we've already opened the Slack setup link this session.\n // Once we have, the picker drops the \"Open Slack setup\" CTA (it would\n // just re-fire the same browser action) and swaps in copy telling the\n // user to finish the steps in their browser. The poll will flip the\n // screen to \"Slack connected\" on its own when it succeeds.\n const [setupOpened, setSetupOpened] = useState(false);\n const openSlackSetup = (): void => {\n openTrackedLink(setupUrl, 'slack-connect-setup');\n setSetupOpened(true);\n };\n\n // Impression — once, and only when the connected state is known, so\n // `already_connected` is real: users who arrive connected segment apart\n // from users who connect during the screen ('slack connect completed').\n // The no-creds path can't know the state, so it fires\n // `slack connect nudge shown` instead — see below.\n const known = connectedState !== null;\n const impressionFired = useRef(false);\n useEffect(() => {\n if (!known || impressionFired.current) return;\n impressionFired.current = true;\n analytics.wizardCapture('slack connect shown', {\n role,\n already_connected: connected,\n });\n }, [known, connected, role]);\n\n // Separate impression for the no-creds path: we render the nudge but\n // don't know whether the user is already connected. Lets funnel\n // readers see those impressions distinctly from authenticated views.\n const nudgeImpressionFired = useRef(false);\n useEffect(() => {\n if (credentials || nudgeImpressionFired.current) return;\n nudgeImpressionFired.current = true;\n analytics.wizardCapture('slack connect nudge shown', { role });\n }, [credentials, role]);\n\n // While not connected, poll: connecting Slack is a manual OAuth step in\n // the browser, so the poll is what flips the screen to the connected\n // state when the user comes back. The first tick also resolves the\n // null/unknown state. Without credentials (user skipped login) it\n // renders the connect nudge.\n useEffect(() => {\n if (!credentials || connected) return;\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const controller = new AbortController();\n const check = (): void => {\n fetchSlackConnected(\n credentials.accessToken,\n credentials.projectId,\n credentials.host,\n controller.signal,\n )\n .then((isConnected) => {\n if (cancelled) return;\n if (isConnected) {\n // Only a false→true flip means the user completed the Slack\n // OAuth during this screen; true on the first-ever check just\n // means they arrived connected.\n if (store.session.slackConnected === false) {\n analytics.wizardCapture('slack connect completed', { role });\n }\n store.setSlackConnected(true);\n } else {\n if (store.session.slackConnected === null) {\n store.setSlackConnected(false);\n }\n timer = setTimeout(check, POLL_INTERVAL_MS);\n }\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n // Capture once and stop polling — repeating a failing call\n // every tick would spam error tracking. The nudge copy is\n // the fallback either way; a failed check counts as not\n // connected so the screen doesn't sit on the loading state.\n if (store.session.slackConnected === null) {\n store.setSlackConnected(false);\n }\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n { step: 'slack_connected_check' },\n );\n });\n };\n check();\n return () => {\n // Tear down fully on exit: no new ticks (cancelled), no pending\n // tick (clearTimeout), no in-flight request (abort).\n cancelled = true;\n if (timer) clearTimeout(timer);\n controller.abort();\n };\n }, [credentials, connected, store]);\n\n // Leaving while connected is \"done\"; leaving while not connected is a\n // skip. Two events so the funnel reads without prop gymnastics. The\n // `connection_state` property on `skipped` distinguishes \"we knew the\n // user wasn't connected\" (had creds, polled, false) from \"we never\n // knew\" (no creds, never polled).\n const dismiss = (): void => {\n if (connected) {\n analytics.wizardCapture('slack connect done', { role });\n } else {\n analytics.wizardCapture('slack connect skipped', {\n role,\n connection_state: credentials ? 'not_connected' : 'unknown',\n });\n }\n store.setSlackStepDismissed();\n };\n\n const handleSelect = (value: ChoiceValue | ChoiceValue[]): void => {\n const choice = Array.isArray(value) ? value[0] : value;\n if (choice === ChoiceValue.Open) {\n analytics.wizardCapture('slack connect opened', { role });\n setLoginError(null);\n // With credentials, the screen stays up and the existing poll flips\n // it to connected once the user finishes the browser Slack OAuth.\n // Without credentials, we kick off the wizard OAuth first so the\n // poll can run after the user returns — opening Slack setup before\n // login would mean we never get to confirm the connection.\n if (credentials) {\n openSlackSetup();\n return;\n }\n setPhase(Phase.Authenticating);\n return;\n }\n dismiss();\n };\n\n // OAuth runs when entering Authenticating. On success we land creds in\n // the store, open the Slack setup link, and return to Nudge — the\n // connected-state poll (keyed on credentials) then kicks in\n // automatically. On failure we surface the error inline and stay put.\n useEffect(() => {\n if (phase !== Phase.Authenticating) return;\n let cancelled = false;\n\n void (async () => {\n try {\n const data = await getOrAskForProjectData({\n signup: false,\n ci: false,\n apiKey: undefined,\n projectId: undefined,\n programId: Program.SlackConnect,\n });\n if (cancelled) return;\n store.setCredentials({\n accessToken: data.accessToken,\n projectApiKey: data.projectApiKey,\n host: data.host,\n projectId: data.projectId,\n });\n store.setRoleAtOrganization(data.roleAtOrganization);\n store.setApiUser(data.user);\n store.setLoginUrl(null);\n openSlackSetup();\n setPhase(Phase.Nudge);\n } catch (err) {\n if (cancelled) return;\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[SlackConnectScreen] login failed: ${message}`);\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n { step: 'slack_connect_login' },\n );\n store.setLoginUrl(null);\n setLoginError(message);\n setPhase(Phase.Nudge);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [phase, role, setupUrl, store]);\n\n useKeyBindings('slack-connect', [\n {\n match: KeyMatch.Escape,\n label: 'esc',\n action:\n phase === Phase.Authenticating ? 'cancel' : connected ? 'done' : 'skip',\n handler: () => {\n // Cancelling OAuth from the Authenticating phase returns to the\n // nudge without dismissing — the user can retry, skip, or pick\n // another action. The effect's cleanup discards the in-flight\n // login result via the cancelled flag.\n if (phase === Phase.Authenticating) {\n store.setLoginUrl(null);\n setPhase(Phase.Nudge);\n return;\n }\n dismiss();\n },\n },\n ]);\n\n if (phase === Phase.Authenticating) {\n return (\n <Box flexDirection=\"column\" flexGrow={1} marginTop={1}>\n <LoadingBox message=\"Waiting for authentication...\" />\n {store.session.loginUrl && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text>\n <Text dimColor>\n If the browser didn't open, copy and paste:\n </Text>\n {'\\n\\n'}\n <Text color=\"cyan\">{store.session.loginUrl}</Text>\n </Text>\n </Box>\n )}\n </Box>\n );\n }\n\n // Credentials in hand but the first integration check hasn't resolved —\n // hold the nudge so an already-connected user is never asked to connect.\n // Flows that prefetch (mcp tutorial) arrive with the state seeded and\n // never see this.\n if (credentials && connectedState === null) {\n return (\n <Box flexDirection=\"column\" flexGrow={1} marginTop={1}>\n <LoadingBox message=\"Checking for an existing Slack connection...\" />\n </Box>\n );\n }\n\n // Waiting-for-browser state: after the user has picked \"Open Slack\n // setup\" we've already triggered the browser action. Re-offering it as\n // the headline CTA is confusing; surface \"go finish it in your browser\"\n // copy and demote re-open to a recovery action.\n const awaitingBrowser = setupOpened && !connected;\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box marginTop={1} flexDirection=\"column\">\n {connected ? (\n <Text bold color={Colors.success}>\n {Icons.check} Slack connected\n </Text>\n ) : awaitingBrowser ? (\n <Text bold color={Colors.accent}>\n Finish connecting Slack\n </Text>\n ) : (\n <Text bold color={Colors.accent}>\n {slack.headline}\n </Text>\n )}\n\n <Box marginTop={1}>\n <Text>\n {connected\n ? \"Slack is connected — here's what you can do:\"\n : awaitingBrowser\n ? \"We've opened PostHog's Slack setup page in your browser. Authorize the Slack app there — we'll detect the connection automatically and continue.\"\n : slack.pitch}\n </Text>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n {slack.capabilities.map((capability, i) => (\n // Marker + copy in one <Text> so the (long) line wraps as a\n // single flow — separate row-Box siblings drop the marker on\n // wrapped bullets.\n <Box key={i} marginTop={i === 0 ? 0 : 1}>\n <Text>\n <Text color=\"cyan\">{Icons.diamond} </Text>\n {capability}\n </Text>\n </Box>\n ))}\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n {!connected && (\n <Text dimColor>\n {awaitingBrowser ? 'Setup page: ' : 'Connect it: '}\n <Text color=\"cyan\">{setupUrl}</Text>\n </Text>\n )}\n <Text dimColor>\n Learn more: <Text color=\"cyan\">{learnMoreUrl}</Text>\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <PickerMenu\n options={\n connected\n ? [{ label: 'Done', value: ChoiceValue.Skip }]\n : awaitingBrowser\n ? [\n {\n label: 'Re-open Slack setup',\n value: ChoiceValue.Open,\n },\n { label: 'Skip / Continue', value: ChoiceValue.Skip },\n ]\n : [\n { label: 'Open Slack setup', value: ChoiceValue.Open },\n { label: 'Skip / Continue', value: ChoiceValue.Skip },\n ]\n }\n onSelect={handleSelect}\n />\n </Box>\n\n {loginError && (\n <Box marginTop={1}>\n <Text color=\"red\">\n Login failed: {loginError}. Try again or skip.\n </Text>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n","/**\n * OutroScreen — Default post-run summary.\n *\n * Renders the success / error / cancel views from `outroData`. Programs\n * that need a different success view (e.g. with extra summary content)\n * ship their own screen component (see audit/AuditOutroScreen.tsx).\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { useSyncExternalStore } from 'react';\nimport type { WizardStore } from '@ui/tui/store';\nimport { OutroKind } from '@lib/wizard-session';\nimport { Colors } from '@ui/tui/styles';\nimport { withUtm } from '@utils/links';\n\ninterface OutroScreenProps {\n store: WizardStore;\n}\n\nexport const OutroScreen = ({ store }: OutroScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n useInput(() => {\n store.setOutroDismissed();\n });\n\n const outroData = store.session.outroData;\n\n if (!outroData) {\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text dimColor>Finishing up...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {outroData.kind === OutroKind.Success && (\n <Box flexDirection=\"column\">\n <Text color=\"green\" bold>\n ✔ {outroData.message || 'Done!'}\n </Text>\n\n {outroData.primaryLink && (\n <Box marginTop={1}>\n <Text>\n {outroData.primaryLink.label}:{' '}\n <Text color=\"cyan\">{outroData.primaryLink.url}</Text>\n </Text>\n </Box>\n )}\n\n {outroData.nextSteps && outroData.nextSteps.items.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"cyan\" bold>\n {outroData.nextSteps.heading}\n </Text>\n {outroData.nextSteps.items.map((item, i) => (\n <Text key={i}>• {item}</Text>\n ))}\n </Box>\n )}\n\n {outroData.dashboardUrl && (\n <Box marginTop={1}>\n <Text>\n Dashboard:{' '}\n <Text color=\"cyan\">\n {withUtm(outroData.dashboardUrl, 'outro-dashboard')}\n </Text>\n </Text>\n </Box>\n )}\n\n {outroData.notebookUrl && (\n <Box marginTop={1}>\n <Text>\n Notebook:{' '}\n <Text color=\"cyan\">\n {withUtm(outroData.notebookUrl, 'outro-notebook')}\n </Text>\n </Text>\n </Box>\n )}\n\n {outroData.body && (\n <Box marginTop={1}>\n <Text dimColor>{outroData.body}</Text>\n </Box>\n )}\n\n {outroData.reportFile && (\n <Box marginTop={1}>\n <Text>\n Check <Text bold>./{outroData.reportFile}</Text> for details\n </Text>\n </Box>\n )}\n\n {outroData.changes && outroData.changes.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"cyan\" bold>\n What the agent did:\n </Text>\n {outroData.changes.map((change, i) => (\n <Text key={i}>• {change}</Text>\n ))}\n </Box>\n )}\n\n {store.eventPlan.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"cyan\" bold>\n Events added:\n </Text>\n {store.eventPlan.map((event) => (\n <Text key={event.name}>\n • <Text bold>{event.name}</Text>\n <Text dimColor> {event.description}</Text>\n </Text>\n ))}\n </Box>\n )}\n\n {outroData.docsUrl && (\n <Box marginTop={1}>\n <Text>\n Learn more:{' '}\n <Text color=\"cyan\">\n {withUtm(outroData.docsUrl, 'outro-docs')}\n </Text>\n </Text>\n </Box>\n )}\n\n {outroData.continueUrl && (\n <Box>\n <Text>\n Continue onboarding:{' '}\n <Text color=\"cyan\">\n {withUtm(outroData.continueUrl, 'outro-continue')}\n </Text>\n </Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n Note: This wizard uses an LLM agent to analyze and modify your\n project. Please review the changes made.\n </Text>\n </Box>\n <Text dimColor>\n How did this work for you? Drop us a line: wizard@posthog.com\n </Text>\n </Box>\n )}\n\n {outroData.kind === OutroKind.Error && (\n <Box flexDirection=\"column\">\n <Text color=\"red\" bold>\n ✘ {outroData.message || 'An error occurred'}\n </Text>\n\n {outroData.body && (\n <Box marginTop={1}>\n <Text dimColor>{outroData.body}</Text>\n </Box>\n )}\n\n {outroData.docsUrl && (\n <Box marginTop={1}>\n <Text>\n Docs: <Text color=\"cyan\">{outroData.docsUrl}</Text>\n </Text>\n </Box>\n )}\n </Box>\n )}\n\n {outroData.kind === OutroKind.Cancel && (\n <Box flexDirection=\"column\">\n <Text color=\"yellow\">■ {outroData.message || 'Cancelled'}</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text color={Colors.muted}>Press any key to continue</Text>\n </Box>\n </Box>\n );\n};\n","/**\n * Shared \"Skill: <id> / URL: <downloadUrl>\" block for intro screens.\n *\n * `useSkillEntry` fetches the entry from the skill menu and re-runs when\n * `skillId` or `local` change. The previous fetch is cancelled (its result\n * is ignored) so a session that flips `local=false → true` mid-mount picks\n * up the right base URL.\n *\n * `<SkillSourceInfo>` renders the block, taking the entry as a prop so the\n * caller can reuse the same hook result for additional UI (e.g. showing\n * `skillEntry.name`) without invoking the hook twice.\n */\n\nimport { Box, Text } from 'ink';\nimport { useEffect, useState } from 'react';\nimport { fetchSkillMenu, type SkillEntry } from '@lib/wizard-tools';\nimport { CONTEXT_MILL_RELEASES_URL, getSkillsBaseUrl } from '@lib/constants';\n\n/**\n * Resolve a session skillId against the skill-menu entries.\n *\n * `session.skillId` is seeded with the raw integration id during\n * detection (e.g. 'python'), but the menu publishes integration skills\n * under prefixed ids ('integration-python'); frameworks with variants\n * publish several ('integration-nextjs-app-router', '-pages-router').\n * Match chain: exact id → `integration-<id>` → unique\n * `integration-<id>-*` prefix. Ambiguous variants (≥2 prefix matches)\n * return null — the caller should point at the skills repo instead of\n * guessing the wrong variant.\n */\nexport function resolveSkillEntry(\n entries: SkillEntry[],\n skillId: string,\n): SkillEntry | null {\n const exact = entries.find((s) => s.id === skillId);\n if (exact) return exact;\n\n const prefixed = entries.find((s) => s.id === `integration-${skillId}`);\n if (prefixed) return prefixed;\n\n const variants = entries.filter((s) =>\n s.id.startsWith(`integration-${skillId}-`),\n );\n return variants.length === 1 ? variants[0] : null;\n}\n\nexport function useSkillEntry(\n skillId: string | null,\n local: boolean,\n): { skillEntry: SkillEntry | null; fetchFailed: boolean } {\n const [skillEntry, setSkillEntry] = useState<SkillEntry | null>(null);\n const [fetchFailed, setFetchFailed] = useState(false);\n\n useEffect(() => {\n if (!skillId) {\n setFetchFailed(true);\n return;\n }\n let cancelled = false;\n setSkillEntry(null);\n setFetchFailed(false);\n void fetchSkillMenu(getSkillsBaseUrl(local)).then((menu) => {\n if (cancelled) return;\n if (!menu) {\n setFetchFailed(true);\n return;\n }\n const match = resolveSkillEntry(\n Object.values(menu.categories).flat(),\n skillId,\n );\n if (match) setSkillEntry(match);\n else setFetchFailed(true);\n });\n return () => {\n cancelled = true;\n };\n }, [skillId, local]);\n\n return { skillEntry, fetchFailed };\n}\n\ninterface SkillSourceInfoProps {\n skillId: string | null;\n skillEntry: SkillEntry | null;\n fetchFailed: boolean;\n}\n\nexport const SkillSourceInfo = ({\n skillId,\n skillEntry,\n fetchFailed,\n}: SkillSourceInfoProps) => (\n <Box flexDirection=\"column\">\n <Text>\n Skill:{' '}\n <Text italic color=\"cyan\">\n {skillId ?? 'unknown'}\n </Text>\n </Text>\n <Text>\n URL:{' '}\n <Text color=\"cyan\">\n {skillEntry?.downloadUrl ??\n (fetchFailed ? CONTEXT_MILL_RELEASES_URL : 'Loading...')}\n </Text>\n </Text>\n </Box>\n);\n","/**\n * AiOptInRequiredScreen — Renders when the wizard authenticates against an\n * org whose `is_ai_data_processing_approved` is not `true`. Mirrors Max's\n * strict reading: `null`, `undefined`, and `false` all block.\n *\n * Two variants selected from `apiUser.organization.membership_level`:\n * - Admin (>= 8): can fix it themselves — [O] opens settings in browser.\n * - Non-admin: needs to escalate — settings URL is displayed prominently\n * to copy and share with the admin.\n *\n * Both variants offer [S] (show skill source for BYOAI), [R] (retry —\n * re-fetches user data and re-evaluates the gate without restarting), and\n * [E] (exit).\n */\n\nimport opn from 'opn';\nimport { Box, Text } from 'ink';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\nimport type { WizardStore } from '@ui/tui/store';\nimport { useKeyBindings } from '@ui/tui/hooks/useKeyBindings';\nimport { Colors } from '@ui/tui/styles';\nimport { useSkillEntry } from '@ui/tui/screens/SkillSourceInfo';\nimport { fetchUserData } from '@lib/api';\nimport { getCloudUrlFromRegion } from '@utils/urls';\nimport { CONTEXT_MILL_RELEASES_URL, POSTHOG_APP_URL } from '@lib/constants';\nimport { analytics } from '@utils/analytics';\nimport { LoadingBox } from '@ui/tui/primitives/index';\n\nconst ORG_ADMIN_LEVEL = 8;\nconst SETTINGS_PATH = 'settings/organization-details';\nconst SETTINGS_ANCHOR = '#organization-ai-consent';\n\ninterface AiOptInRequiredScreenProps {\n store: WizardStore;\n}\n\nexport const AiOptInRequiredScreen = ({\n store,\n}: AiOptInRequiredScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const { session } = store;\n const org = session.apiUser?.organization;\n const isAdmin = (org?.membership_level ?? 0) >= ORG_ADMIN_LEVEL;\n const variant: 'admin' | 'non-admin' = isAdmin ? 'admin' : 'non-admin';\n\n const region = session.region ?? 'us';\n const projectId = session.credentials?.projectId;\n // Use the region-agnostic app.posthog.com URL so the redirect routes\n // the user to their actual region (us / eu) based on their profile.\n // This avoids relying on a possibly-stale local session.region.\n // `projectId != null` (not just `projectId`) so that 0 — possible in\n // synthetic playground sessions — still picks the project-scoped URL.\n const settingsUrl =\n projectId != null\n ? `${POSTHOG_APP_URL}/project/${projectId}/${SETTINGS_PATH}${SETTINGS_ANCHOR}`\n : `${POSTHOG_APP_URL}/${SETTINGS_PATH}${SETTINGS_ANCHOR}`;\n\n const [showSkill, setShowSkill] = useState(false);\n const [retrying, setRetrying] = useState(false);\n const [retryError, setRetryError] = useState<string | null>(null);\n\n const { skillEntry } = useSkillEntry(session.skillId, session.localMcp);\n\n // Fire the \"shown\" event once per variant transition.\n useEffect(() => {\n analytics.wizardCapture('ai opt-in shown', { variant });\n }, [variant]);\n\n const handleOpenSettings = () => {\n analytics.wizardCapture('ai opt-in action', {\n variant,\n action: 'open_settings',\n });\n opn(settingsUrl, { wait: false }).catch(() => {\n // Best-effort — if the browser doesn't open, the URL is still\n // visible in the screen for manual navigation.\n });\n };\n\n const handleShowSkill = () => {\n analytics.wizardCapture('ai opt-in action', {\n variant,\n action: 'show_skill',\n });\n setShowSkill(true);\n };\n\n const handleRetry = () => {\n analytics.wizardCapture('ai opt-in action', { variant, action: 'retry' });\n const accessToken = session.credentials?.accessToken;\n if (!accessToken) {\n setRetryError('Missing credentials — cannot retry.');\n return;\n }\n setRetrying(true);\n setRetryError(null);\n void fetchUserData(accessToken, getCloudUrlFromRegion(region))\n .then((user) => {\n store.setApiUser(user);\n })\n .catch((err: unknown) => {\n setRetryError(err instanceof Error ? err.message : 'Retry failed.');\n })\n .finally(() => {\n setRetrying(false);\n });\n };\n\n const handleExit = () => {\n analytics.wizardCapture('ai opt-in action', { variant, action: 'exit' });\n process.exit(0);\n };\n\n useKeyBindings('ai-opt-in', [\n ...(isAdmin\n ? [\n {\n match: ['o', 'O'],\n label: 'O',\n action: 'open settings',\n handler: handleOpenSettings,\n },\n ]\n : []),\n {\n match: ['s', 'S'],\n label: 'S',\n action: 'show skill',\n handler: handleShowSkill,\n },\n {\n match: ['r', 'R'],\n label: 'R',\n action: 'retry',\n handler: handleRetry,\n },\n {\n match: ['e', 'E'],\n label: 'E',\n action: 'exit',\n handler: handleExit,\n },\n ]);\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={Colors.accent}>\n PostHog Setup Wizard\n </Text>\n {session.apiUser?.email && (\n <Text>\n <Text color=\"green\">{'✔'} </Text>\n <Text>Authenticated as {session.apiUser.email}</Text>\n </Text>\n )}\n </Box>\n\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color=\"yellow\" bold>\n ⚠ PostHog AI services are disabled for your organization\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" marginBottom={1} width={68}>\n {isAdmin ? (\n <Text>\n The wizard uses Anthropic Claude. To proceed, enable{' '}\n <Text italic>\n \"Enable PostHog features that use third-party AI services\"\n </Text>{' '}\n in your organization settings.\n </Text>\n ) : (\n <>\n <Text>\n The wizard uses Anthropic Claude. Your organization admin needs to\n enable{' '}\n <Text italic>\n \"Enable PostHog features that use third-party AI services\"\n </Text>{' '}\n in organization settings.\n </Text>\n <Box marginTop={1}>\n <Text dimColor>Share this link with your admin:</Text>\n </Box>\n </>\n )}\n </Box>\n\n <Box marginBottom={1}>\n <Text color=\"cyan\">{settingsUrl}</Text>\n </Box>\n\n {/* Release PAGE, not the direct asset URL — asset URLs hard-wrap in\n the terminal and corrupt copy/paste (same rationale as\n PrivacyPanel). The resolved entry names the asset to grab. */}\n {showSkill && (\n <Box marginBottom={1} flexDirection=\"column\">\n <Text>\n Prefer your own AI? Download{' '}\n {skillEntry ? (\n <>\n the <Text bold>{skillEntry.id}</Text> skill\n </>\n ) : (\n 'the skill for your framework'\n )}{' '}\n and run it in your own agent:\n </Text>\n <Text color=\"cyan\">{CONTEXT_MILL_RELEASES_URL}</Text>\n </Box>\n )}\n\n {retrying && (\n <Box marginBottom={1}>\n <LoadingBox message=\"Re-checking organization settings...\" />\n </Box>\n )}\n\n {retryError && (\n <Box marginBottom={1}>\n <Text color=\"red\">{retryError}</Text>\n </Box>\n )}\n\n <Box flexDirection=\"column\" marginTop={1}>\n {isAdmin && (\n <Text>\n <Text color={Colors.accent}>[O]</Text> Open settings in browser\n </Text>\n )}\n <Text>\n <Text color={Colors.accent}>[S]</Text> Show how to use your own AI\n </Text>\n <Text>\n <Text color={Colors.accent}>[R]</Text> Retry (after the toggle is\n enabled)\n </Text>\n <Text>\n <Text color={Colors.accent}>[E]</Text> Exit\n </Text>\n </Box>\n </Box>\n );\n};\n","/**\n * Terminal setup shared by the wizard TUI and the primitives playground.\n *\n * Both enter the alternate screen buffer and paint a black background so\n * Ink renders on a consistent dark canvas regardless of the user's terminal\n * theme (light mode profiles included).\n */\n\n// ANSI escape sequences\nconst RESET_ATTRS = '\\x1b[0m';\nconst CLEAR_SCREEN = '\\x1b[2J';\nconst CURSOR_HOME = '\\x1b[H';\nconst BG_BLACK = '\\x1b[48;2;0;0;0m';\nconst ENTER_ALT_SCREEN = '\\x1b[?1049h';\nconst LEAVE_ALT_SCREEN = '\\x1b[?1049l';\n\n/** Enter alt screen and paint a black background. */\nexport function enterDarkTerminal(): void {\n process.stdout.write(\n ENTER_ALT_SCREEN + BG_BLACK + CLEAR_SCREEN + CURSOR_HOME,\n );\n}\n\n/** Leave alt screen and reset attributes. */\nexport function releaseTerminal(): void {\n process.stdout.write(RESET_ATTRS + LEAVE_ALT_SCREEN);\n}\n"],"mappings":"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"}
|