@posthog/wizard 2.3.0 → 2.5.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/bin.js +10 -0
- package/dist/bin.js.map +1 -1
- package/dist/src/lib/__tests__/agent-interface.test.js +22 -0
- package/dist/src/lib/__tests__/agent-interface.test.js.map +1 -1
- package/dist/src/lib/agent-interface.d.ts +20 -2
- package/dist/src/lib/agent-interface.js +97 -14
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/agent-runner.js +17 -5
- package/dist/src/lib/agent-runner.js.map +1 -1
- package/dist/src/lib/api.d.ts +4 -4
- package/dist/src/lib/constants.d.ts +1 -1
- package/dist/src/lib/version.d.ts +1 -1
- package/dist/src/lib/version.js +1 -1
- package/dist/src/lib/version.js.map +1 -1
- package/dist/src/lib/wizard-session.d.ts +4 -0
- package/dist/src/lib/wizard-session.js +2 -0
- package/dist/src/lib/wizard-session.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js +6 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.d.ts +6 -6
- package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +15 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js +119 -4
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +2 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.js +2 -2
- package/dist/src/steps/add-mcp-server-to-clients/index.js.map +1 -1
- package/dist/src/ui/logging-ui.d.ts +3 -1
- package/dist/src/ui/logging-ui.js +6 -6
- package/dist/src/ui/logging-ui.js.map +1 -1
- package/dist/src/ui/tui/ink-ui.d.ts +3 -1
- package/dist/src/ui/tui/ink-ui.js +5 -2
- package/dist/src/ui/tui/ink-ui.js.map +1 -1
- package/dist/src/ui/tui/primitives/GroupedPickerMenu.d.ts +20 -0
- package/dist/src/ui/tui/primitives/GroupedPickerMenu.js +77 -0
- package/dist/src/ui/tui/primitives/GroupedPickerMenu.js.map +1 -0
- package/dist/src/ui/tui/primitives/PickerMenu.js +12 -3
- package/dist/src/ui/tui/primitives/PickerMenu.js.map +1 -1
- package/dist/src/ui/tui/primitives/index.d.ts +1 -0
- package/dist/src/ui/tui/primitives/index.js +1 -0
- package/dist/src/ui/tui/primitives/index.js.map +1 -1
- package/dist/src/ui/tui/router.d.ts +3 -1
- package/dist/src/ui/tui/router.js +2 -0
- package/dist/src/ui/tui/router.js.map +1 -1
- package/dist/src/ui/tui/screen-registry.js +4 -0
- package/dist/src/ui/tui/screen-registry.js.map +1 -1
- package/dist/src/ui/tui/screens/AuthErrorScreen.d.ts +7 -0
- package/dist/src/ui/tui/screens/AuthErrorScreen.js +16 -0
- package/dist/src/ui/tui/screens/AuthErrorScreen.js.map +1 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.d.ts +13 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.js +32 -0
- package/dist/src/ui/tui/screens/ManagedSettingsScreen.js.map +1 -0
- package/dist/src/ui/tui/screens/McpScreen.d.ts +1 -1
- package/dist/src/ui/tui/screens/McpScreen.js +21 -6
- package/dist/src/ui/tui/screens/McpScreen.js.map +1 -1
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +0 -4
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +13 -7
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js.map +1 -1
- package/dist/src/ui/tui/services/mcp-installer.d.ts +1 -1
- package/dist/src/ui/tui/services/mcp-installer.js +3 -3
- package/dist/src/ui/tui/services/mcp-installer.js.map +1 -1
- package/dist/src/ui/tui/store.d.ts +4 -1
- package/dist/src/ui/tui/store.js +16 -3
- package/dist/src/ui/tui/store.js.map +1 -1
- package/dist/src/ui/wizard-ui.d.ts +4 -2
- package/dist/src/ui/wizard-ui.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GroupedPickerMenu — Multi-select with category headers.
|
|
3
|
+
*
|
|
4
|
+
* Renders groups of options with bold category labels.
|
|
5
|
+
* Arrow keys navigate selectable items (headers are skipped),
|
|
6
|
+
* space toggles, "a" toggles all, enter submits.
|
|
7
|
+
*/
|
|
8
|
+
interface GroupOption {
|
|
9
|
+
value: string;
|
|
10
|
+
label: string;
|
|
11
|
+
hint?: string;
|
|
12
|
+
}
|
|
13
|
+
interface GroupedPickerMenuProps {
|
|
14
|
+
message?: string;
|
|
15
|
+
groups: Record<string, GroupOption[]>;
|
|
16
|
+
initialSelected?: string[];
|
|
17
|
+
onSelect: (values: string[]) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const GroupedPickerMenu: ({ message, groups, initialSelected, onSelect, }: GroupedPickerMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* GroupedPickerMenu — Multi-select with category headers.
|
|
4
|
+
*
|
|
5
|
+
* Renders groups of options with bold category labels.
|
|
6
|
+
* Arrow keys navigate selectable items (headers are skipped),
|
|
7
|
+
* space toggles, "a" toggles all, enter submits.
|
|
8
|
+
*/
|
|
9
|
+
import { Box, Text, useInput } from 'ink';
|
|
10
|
+
import { useState, useMemo } from 'react';
|
|
11
|
+
import { Icons, Colors } from '../styles.js';
|
|
12
|
+
import { PromptLabel } from './PromptLabel.js';
|
|
13
|
+
export const GroupedPickerMenu = ({ message, groups, initialSelected, onSelect, }) => {
|
|
14
|
+
// Build a flat row list with headers interleaved
|
|
15
|
+
const rows = useMemo(() => {
|
|
16
|
+
const result = [];
|
|
17
|
+
for (const [groupName, options] of Object.entries(groups)) {
|
|
18
|
+
result.push({ kind: 'header', label: groupName });
|
|
19
|
+
for (const opt of options) {
|
|
20
|
+
result.push({ kind: 'option', ...opt });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}, [groups]);
|
|
25
|
+
// Indices of selectable (non-header) rows
|
|
26
|
+
const selectableIndices = useMemo(() => rows.map((r, i) => (r.kind === 'option' ? i : -1)).filter((i) => i >= 0), [rows]);
|
|
27
|
+
// All option values for toggle-all
|
|
28
|
+
const allValues = useMemo(() => rows.filter((r) => r.kind === 'option').map((r) => r.value), [rows]);
|
|
29
|
+
const [focusedSelectable, setFocusedSelectable] = useState(0);
|
|
30
|
+
const [selected, setSelected] = useState(() => new Set(initialSelected ?? allValues));
|
|
31
|
+
const focusedRowIdx = selectableIndices[focusedSelectable] ?? 0;
|
|
32
|
+
useInput((input, key) => {
|
|
33
|
+
if (key.upArrow) {
|
|
34
|
+
setFocusedSelectable((prev) => (prev > 0 ? prev - 1 : selectableIndices.length - 1));
|
|
35
|
+
}
|
|
36
|
+
if (key.downArrow) {
|
|
37
|
+
setFocusedSelectable((prev) => (prev < selectableIndices.length - 1 ? prev + 1 : 0));
|
|
38
|
+
}
|
|
39
|
+
if (input === ' ') {
|
|
40
|
+
const row = rows[focusedRowIdx];
|
|
41
|
+
if (row?.kind === 'option') {
|
|
42
|
+
setSelected((prev) => {
|
|
43
|
+
const next = new Set(prev);
|
|
44
|
+
if (next.has(row.value)) {
|
|
45
|
+
next.delete(row.value);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
next.add(row.value);
|
|
49
|
+
}
|
|
50
|
+
return next;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (input === 'a') {
|
|
55
|
+
setSelected((prev) => {
|
|
56
|
+
if (prev.size === allValues.length) {
|
|
57
|
+
return new Set();
|
|
58
|
+
}
|
|
59
|
+
return new Set(allValues);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (key.return) {
|
|
63
|
+
onSelect([...selected]);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(PromptLabel, { message: message }), _jsx(Text, { dimColor: true, children: " (space to toggle, a to toggle all, enter to confirm)" }), _jsx(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: rows.map((row, idx) => {
|
|
67
|
+
if (row.kind === 'header') {
|
|
68
|
+
return (_jsx(Box, { marginTop: idx > 0 ? 1 : 0, children: _jsx(Text, { bold: true, dimColor: true, children: row.label }) }, `h-${idx}`));
|
|
69
|
+
}
|
|
70
|
+
const isFocused = focusedRowIdx === idx;
|
|
71
|
+
const isSelected = selected.has(row.value);
|
|
72
|
+
const checkbox = isSelected ? Icons.squareFilled : Icons.squareOpen;
|
|
73
|
+
const label = row.hint ? `${row.label} (${row.hint})` : row.label;
|
|
74
|
+
return (_jsxs(Box, { gap: 1, marginLeft: 1, children: [_jsx(Text, { color: isSelected ? 'white' : Colors.muted, dimColor: !isFocused && !isSelected, children: checkbox }), _jsx(Text, { color: isFocused ? Colors.accent : undefined, bold: isFocused, dimColor: !isFocused, children: label })] }, row.value));
|
|
75
|
+
}) })] }));
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=GroupedPickerMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupedPickerMenu.js","sourceRoot":"","sources":["../../../../../src/ui/tui/primitives/GroupedPickerMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\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),\n * space toggles, \"a\" toggles all, enter submits.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { useState, useMemo } from 'react';\nimport { Icons, Colors } from '../styles.js';\nimport { PromptLabel } from './PromptLabel.js';\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\nexport const GroupedPickerMenu = ({\n message,\n groups,\n initialSelected,\n onSelect,\n}: GroupedPickerMenuProps) => {\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 () => 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.filter((r): r is Row & { kind: 'option' } => r.kind === 'option').map((r) => r.value),\n [rows],\n );\n\n const [focusedSelectable, setFocusedSelectable] = useState(0);\n const [selected, setSelected] = useState<Set<string>>(\n () => new Set(initialSelected ?? allValues),\n );\n\n const focusedRowIdx = selectableIndices[focusedSelectable] ?? 0;\n\n useInput((input, key) => {\n if (key.upArrow) {\n setFocusedSelectable((prev) => (prev > 0 ? prev - 1 : selectableIndices.length - 1));\n }\n if (key.downArrow) {\n setFocusedSelectable((prev) => (prev < selectableIndices.length - 1 ? prev + 1 : 0));\n }\n if (input === ' ') {\n const row = rows[focusedRowIdx];\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 if (input === 'a') {\n setSelected((prev) => {\n if (prev.size === allValues.length) {\n return new Set();\n }\n return new Set(allValues);\n });\n }\n if (key.return) {\n onSelect([...selected]);\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <PromptLabel message={message} />\n <Text dimColor> (space to toggle, a to toggle all, enter to confirm)</Text>\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n {rows.map((row, idx) => {\n if (row.kind === 'header') {\n return (\n <Box key={`h-${idx}`} marginTop={idx > 0 ? 1 : 0}>\n <Text bold dimColor>\n {row.label}\n </Text>\n </Box>\n );\n }\n\n const isFocused = focusedRowIdx === idx;\n const isSelected = selected.has(row.value);\n const checkbox = isSelected ? Icons.squareFilled : Icons.squareOpen;\n const label = row.hint ? `${row.label} (${row.hint})` : row.label;\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 <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n </Box>\n );\n};\n"]}
|
|
@@ -112,15 +112,24 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, onSe
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
if (key.return) {
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
if (selected.size === 0) {
|
|
116
|
+
// Nothing toggled, select hovered
|
|
117
|
+
const hovered = options[focused];
|
|
118
|
+
if (hovered) {
|
|
119
|
+
onSelect(hovered.value);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const values = [...selected].sort().map((i) => options[i].value);
|
|
124
|
+
onSelect(values);
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
});
|
|
119
128
|
const columnArrays = [];
|
|
120
129
|
for (let c = 0; c < columns; c++) {
|
|
121
130
|
columnArrays.push(options.slice(c * rows, c * rows + rows));
|
|
122
131
|
}
|
|
123
|
-
return (_jsxs(Box, { flexDirection: "column", alignItems: centered ? 'center' : undefined, children: [_jsx(PromptLabel, { message: message }), _jsx(Text, { dimColor: true, children: " (space to
|
|
132
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: centered ? 'center' : undefined, children: [_jsx(PromptLabel, { message: message }), _jsx(Text, { dimColor: true, children: " (space to multi-select, enter to confirm)" }), _jsx(Box, { flexDirection: "row", gap: 4, marginLeft: centered ? 0 : 2, marginTop: 1, children: columnArrays.map((colOpts, colIdx) => (_jsx(Box, { flexDirection: "column", children: colOpts.map((opt, rowIdx) => {
|
|
124
133
|
const flatIdx = colIdx * rows + rowIdx;
|
|
125
134
|
const isFocused = flatIdx === focused;
|
|
126
135
|
const isSelected = selected.has(flatIdx);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PickerMenu.js","sourceRoot":"","sources":["../../../../../src/ui/tui/primitives/PickerMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * PickerMenu — Single and multi select.\n * Single mode: custom renderer with small triangle indicator.\n * Multi mode: checkbox glyphs with space to toggle.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { useState } from 'react';\nimport { Icons, Colors } from '../styles.js';\nimport { PromptLabel } from './PromptLabel.js';\n\ninterface PickerOption<T> {\n label: string;\n value: T;\n hint?: string;\n}\n\ninterface PickerMenuProps<T> {\n message?: string;\n options: PickerOption<T>[];\n mode?: 'single' | 'multi';\n centered?: boolean;\n columns?: 1 | 2 | 3 | 4;\n onSelect: (value: T | T[]) => void;\n}\n\nexport const PickerMenu = <T,>({\n message,\n options,\n mode = 'single',\n centered = false,\n columns = 1,\n onSelect,\n}: PickerMenuProps<T>) => {\n if (mode === 'multi') {\n return (\n <MultiPickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n onSelect={onSelect}\n />\n );\n }\n\n return (\n <SinglePickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n onSelect={onSelect}\n />\n );\n};\n\n/** Custom single-select with triangle indicator and accent highlight. */\nconst SinglePickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(0);\n const rows = Math.ceil(options.length / columns);\n\n useInput((_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n if (key.upArrow) {\n if (row > 0) {\n setFocused(col * rows + row - 1);\n } else {\n setFocused(Math.min(col * rows + rows - 1, options.length - 1));\n }\n }\n if (key.downArrow) {\n const next = col * rows + row + 1;\n if (next < options.length && row + 1 < rows) {\n setFocused(next);\n } else {\n setFocused(col * rows);\n }\n }\n if (key.leftArrow && columns > 1) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n setFocused(Math.min(prevCol * rows + row, options.length - 1));\n }\n if (key.rightArrow && columns > 1) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n setFocused(Math.min(nextCol * rows + row, options.length - 1));\n }\n if (key.return) {\n const selected = options[focused];\n if (selected) {\n onSelect(selected.value);\n }\n }\n });\n\n // Chunk options into columns (column-first ordering)\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n const align = centered ? 'center' : undefined;\n\n return (\n <Box flexDirection=\"column\" alignItems={align}>\n <PromptLabel message={message} />\n <Box flexDirection=\"row\" gap={4}>\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n return (\n <Box key={flatIdx} gap={1}>\n <Text\n color={isFocused ? Colors.accent : undefined}\n dimColor={!isFocused}\n >\n {isFocused ? Icons.triangleSmallRight : ' '}\n </Text>\n <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\n/** Custom multi-select with checkbox glyphs and accent highlight. */\nconst MultiPickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(0);\n const [selected, setSelected] = useState<Set<number>>(new Set());\n const rows = Math.ceil(options.length / columns);\n\n useInput((_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n if (key.upArrow) {\n if (row > 0) {\n setFocused(col * rows + row - 1);\n } else {\n setFocused(Math.min(col * rows + rows - 1, options.length - 1));\n }\n }\n if (key.downArrow) {\n const next = col * rows + row + 1;\n if (next < options.length && row + 1 < rows) {\n setFocused(next);\n } else {\n setFocused(col * rows);\n }\n }\n if (key.leftArrow && columns > 1) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n setFocused(Math.min(prevCol * rows + row, options.length - 1));\n }\n if (key.rightArrow && columns > 1) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n setFocused(Math.min(nextCol * rows + row, options.length - 1));\n }\n if (_input === ' ') {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(focused)) {\n next.delete(focused);\n } else {\n next.add(focused);\n }\n return next;\n });\n }\n if (key.return) {\n const values = [...selected].sort().map((i) => options[i].value);\n onSelect(values);\n }\n });\n\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n return (\n <Box flexDirection=\"column\" alignItems={centered ? 'center' : undefined}>\n <PromptLabel message={message} />\n <Text dimColor> (space to toggle, enter to submit)</Text>\n <Box\n flexDirection=\"row\"\n gap={4}\n marginLeft={centered ? 0 : 2}\n marginTop={1}\n >\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const isSelected = selected.has(flatIdx);\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n const checkbox = isSelected\n ? Icons.squareFilled\n : Icons.squareOpen;\n return (\n <Box key={flatIdx} gap={1}>\n <Text\n color={isSelected ? 'white' : Colors.muted}\n dimColor={!isFocused && !isSelected}\n >\n {checkbox}\n </Text>\n <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"PickerMenu.js","sourceRoot":"","sources":["../../../../../src/ui/tui/primitives/PickerMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * PickerMenu — Single and multi select.\n * Single mode: custom renderer with small triangle indicator.\n * Multi mode: checkbox glyphs with space to toggle.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { useState } from 'react';\nimport { Icons, Colors } from '../styles.js';\nimport { PromptLabel } from './PromptLabel.js';\n\ninterface PickerOption<T> {\n label: string;\n value: T;\n hint?: string;\n}\n\ninterface PickerMenuProps<T> {\n message?: string;\n options: PickerOption<T>[];\n mode?: 'single' | 'multi';\n centered?: boolean;\n columns?: 1 | 2 | 3 | 4;\n onSelect: (value: T | T[]) => void;\n}\n\nexport const PickerMenu = <T,>({\n message,\n options,\n mode = 'single',\n centered = false,\n columns = 1,\n onSelect,\n}: PickerMenuProps<T>) => {\n if (mode === 'multi') {\n return (\n <MultiPickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n onSelect={onSelect}\n />\n );\n }\n\n return (\n <SinglePickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n onSelect={onSelect}\n />\n );\n};\n\n/** Custom single-select with triangle indicator and accent highlight. */\nconst SinglePickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(0);\n const rows = Math.ceil(options.length / columns);\n\n useInput((_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n if (key.upArrow) {\n if (row > 0) {\n setFocused(col * rows + row - 1);\n } else {\n setFocused(Math.min(col * rows + rows - 1, options.length - 1));\n }\n }\n if (key.downArrow) {\n const next = col * rows + row + 1;\n if (next < options.length && row + 1 < rows) {\n setFocused(next);\n } else {\n setFocused(col * rows);\n }\n }\n if (key.leftArrow && columns > 1) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n setFocused(Math.min(prevCol * rows + row, options.length - 1));\n }\n if (key.rightArrow && columns > 1) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n setFocused(Math.min(nextCol * rows + row, options.length - 1));\n }\n if (key.return) {\n const selected = options[focused];\n if (selected) {\n onSelect(selected.value);\n }\n }\n });\n\n // Chunk options into columns (column-first ordering)\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n const align = centered ? 'center' : undefined;\n\n return (\n <Box flexDirection=\"column\" alignItems={align}>\n <PromptLabel message={message} />\n <Box flexDirection=\"row\" gap={4}>\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n return (\n <Box key={flatIdx} gap={1}>\n <Text\n color={isFocused ? Colors.accent : undefined}\n dimColor={!isFocused}\n >\n {isFocused ? Icons.triangleSmallRight : ' '}\n </Text>\n <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\n/** Custom multi-select with checkbox glyphs and accent highlight. */\nconst MultiPickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(0);\n const [selected, setSelected] = useState<Set<number>>(new Set());\n const rows = Math.ceil(options.length / columns);\n\n useInput((_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n if (key.upArrow) {\n if (row > 0) {\n setFocused(col * rows + row - 1);\n } else {\n setFocused(Math.min(col * rows + rows - 1, options.length - 1));\n }\n }\n if (key.downArrow) {\n const next = col * rows + row + 1;\n if (next < options.length && row + 1 < rows) {\n setFocused(next);\n } else {\n setFocused(col * rows);\n }\n }\n if (key.leftArrow && columns > 1) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n setFocused(Math.min(prevCol * rows + row, options.length - 1));\n }\n if (key.rightArrow && columns > 1) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n setFocused(Math.min(nextCol * rows + row, options.length - 1));\n }\n if (_input === ' ') {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(focused)) {\n next.delete(focused);\n } else {\n next.add(focused);\n }\n return next;\n });\n }\n if (key.return) {\n if (selected.size === 0) {\n // Nothing toggled, select hovered\n const hovered = options[focused];\n if (hovered) {\n onSelect(hovered.value);\n }\n } else {\n const values = [...selected].sort().map((i) => options[i].value);\n onSelect(values);\n }\n }\n });\n\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n return (\n <Box flexDirection=\"column\" alignItems={centered ? 'center' : undefined}>\n <PromptLabel message={message} />\n <Text dimColor> (space to multi-select, enter to confirm)</Text>\n <Box\n flexDirection=\"row\"\n gap={4}\n marginLeft={centered ? 0 : 2}\n marginTop={1}\n >\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const isSelected = selected.has(flatIdx);\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n const checkbox = isSelected\n ? Icons.squareFilled\n : Icons.squareOpen;\n return (\n <Box key={flatIdx} gap={1}>\n <Text\n color={isSelected ? 'white' : Colors.muted}\n dimColor={!isFocused && !isSelected}\n >\n {checkbox}\n </Text>\n <Text\n color={isFocused ? Colors.accent : undefined}\n bold={isFocused}\n dimColor={!isFocused}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n"]}
|
|
@@ -8,6 +8,7 @@ export { ProgressList } from './ProgressList.js';
|
|
|
8
8
|
export type { ProgressItem } from './ProgressList.js';
|
|
9
9
|
export { PromptLabel } from './PromptLabel.js';
|
|
10
10
|
export { PickerMenu } from './PickerMenu.js';
|
|
11
|
+
export { GroupedPickerMenu } from './GroupedPickerMenu.js';
|
|
11
12
|
export { ConfirmationInput } from './ConfirmationInput.js';
|
|
12
13
|
export { Divider } from './Divider.js';
|
|
13
14
|
export { ModalOverlay } from './ModalOverlay.js';
|
|
@@ -7,6 +7,7 @@ export { LoadingBox } from './LoadingBox.js';
|
|
|
7
7
|
export { ProgressList } from './ProgressList.js';
|
|
8
8
|
export { PromptLabel } from './PromptLabel.js';
|
|
9
9
|
export { PickerMenu } from './PickerMenu.js';
|
|
10
|
+
export { GroupedPickerMenu } from './GroupedPickerMenu.js';
|
|
10
11
|
export { ConfirmationInput } from './ConfirmationInput.js';
|
|
11
12
|
export { Divider } from './Divider.js';
|
|
12
13
|
export { ModalOverlay } from './ModalOverlay.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/ui/tui/primitives/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAOzD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,EACR,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC","sourcesContent":["/**\n * Barrel export for all TUI layout primitives.\n */\n\nexport { CardLayout } from './CardLayout.js';\nexport { SplitView } from './SplitView.js';\nexport { LoadingBox } from './LoadingBox.js';\nexport { ProgressList } from './ProgressList.js';\nexport type { ProgressItem } from './ProgressList.js';\nexport { PromptLabel } from './PromptLabel.js';\nexport { PickerMenu } from './PickerMenu.js';\nexport { ConfirmationInput } from './ConfirmationInput.js';\nexport { Divider } from './Divider.js';\nexport { ModalOverlay } from './ModalOverlay.js';\nexport { LogViewer } from './LogViewer.js';\nexport { EventPlanViewer } from './EventPlanViewer.js';\nexport { ScreenContainer } from './ScreenContainer.js';\nexport { ScreenErrorBoundary } from './ScreenErrorBoundary.js';\nexport { TabContainer } from './TabContainer.js';\nexport type { TabDefinition } from './TabContainer.js';\nexport { HNViewer } from './HNViewer.js';\nexport { DissolveTransition } from './DissolveTransition.js';\nexport type { WipeDirection } from './DissolveTransition.js';\nexport { ContentSequencer } from './ContentSequencer.js';\nexport type {\n ContentBlock,\n ContentObjectBlock,\n ContentLinesBlock,\n ContentClearBlock,\n} from './ContentSequencer.js';\nexport {\n estimateBlockHeight,\n computeVisibleRange,\n wordWrap,\n wrapAndTruncate,\n} from './layout-helpers.js';\nexport {\n TextRevealMode,\n TEXT_REVEAL_MODE_LABELS,\n TEXT_REVEAL_MODE_COUNT,\n TEXT_REVEAL_MODE_DEFAULTS,\n} from './TextBlock.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/ui/tui/primitives/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAOzD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,EACR,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC","sourcesContent":["/**\n * Barrel export for all TUI layout primitives.\n */\n\nexport { CardLayout } from './CardLayout.js';\nexport { SplitView } from './SplitView.js';\nexport { LoadingBox } from './LoadingBox.js';\nexport { ProgressList } from './ProgressList.js';\nexport type { ProgressItem } from './ProgressList.js';\nexport { PromptLabel } from './PromptLabel.js';\nexport { PickerMenu } from './PickerMenu.js';\nexport { GroupedPickerMenu } from './GroupedPickerMenu.js';\nexport { ConfirmationInput } from './ConfirmationInput.js';\nexport { Divider } from './Divider.js';\nexport { ModalOverlay } from './ModalOverlay.js';\nexport { LogViewer } from './LogViewer.js';\nexport { EventPlanViewer } from './EventPlanViewer.js';\nexport { ScreenContainer } from './ScreenContainer.js';\nexport { ScreenErrorBoundary } from './ScreenErrorBoundary.js';\nexport { TabContainer } from './TabContainer.js';\nexport type { TabDefinition } from './TabContainer.js';\nexport { HNViewer } from './HNViewer.js';\nexport { DissolveTransition } from './DissolveTransition.js';\nexport type { WipeDirection } from './DissolveTransition.js';\nexport { ContentSequencer } from './ContentSequencer.js';\nexport type {\n ContentBlock,\n ContentObjectBlock,\n ContentLinesBlock,\n ContentClearBlock,\n} from './ContentSequencer.js';\nexport {\n estimateBlockHeight,\n computeVisibleRange,\n wordWrap,\n wrapAndTruncate,\n} from './layout-helpers.js';\nexport {\n TextRevealMode,\n TEXT_REVEAL_MODE_LABELS,\n TEXT_REVEAL_MODE_COUNT,\n TEXT_REVEAL_MODE_DEFAULTS,\n} from './TextBlock.js';\n"]}
|
|
@@ -18,7 +18,9 @@ export type { FlowEntry };
|
|
|
18
18
|
/** Screens that interrupt flows as overlays */
|
|
19
19
|
export declare enum Overlay {
|
|
20
20
|
SettingsOverride = "settings-override",
|
|
21
|
-
|
|
21
|
+
ManagedSettings = "managed-settings",
|
|
22
|
+
PortConflict = "port-conflict",
|
|
23
|
+
AuthError = "auth-error"
|
|
22
24
|
}
|
|
23
25
|
/** Union of all screen names */
|
|
24
26
|
export type ScreenName = Screen | Overlay;
|
|
@@ -19,7 +19,9 @@ export { Screen, Flow };
|
|
|
19
19
|
export var Overlay;
|
|
20
20
|
(function (Overlay) {
|
|
21
21
|
Overlay["SettingsOverride"] = "settings-override";
|
|
22
|
+
Overlay["ManagedSettings"] = "managed-settings";
|
|
22
23
|
Overlay["PortConflict"] = "port-conflict";
|
|
24
|
+
Overlay["AuthError"] = "auth-error";
|
|
23
25
|
})(Overlay || (Overlay = {}));
|
|
24
26
|
// ── Router ────────────────────────────────────────────────────────────
|
|
25
27
|
export class WizardRouter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../../src/ui/tui/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAC;AAEjE,gEAAgE;AAChE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAGxB,yEAAyE;AAEzE,+CAA+C;AAC/C,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../../src/ui/tui/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAC;AAEjE,gEAAgE;AAChE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAGxB,yEAAyE;AAEzE,+CAA+C;AAC/C,MAAM,CAAN,IAAY,OAKX;AALD,WAAY,OAAO;IACjB,iDAAsC,CAAA;IACtC,+CAAoC,CAAA;IACpC,yCAA8B,CAAA;IAC9B,mCAAwB,CAAA;AAC1B,CAAC,EALW,OAAO,KAAP,OAAO,QAKlB;AAKD,yEAAyE;AAEzE,MAAM,OAAO,YAAY;IACf,IAAI,CAAc;IAClB,QAAQ,CAAO;IACf,QAAQ,GAAc,EAAE,CAAC;IAEjC,YAAY,WAAiB,IAAI,CAAC,MAAM;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,OAAsB;QAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,SAAS;YACjD,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YAC5D,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;QAED,sDAAsD;QACtD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAChD,CAAC;IAED,oDAAoD;IACpD,IAAI,YAAY;QACd,uDAAuD;QACvD,uEAAuE;QACvE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,mCAAmC;IACnC,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,8CAA8C;IAC9C,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,OAAgB;QAC1B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;IAED;;OAEG;IACK,cAAc,GAA0B,IAAI,CAAC;IAErD,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,6DAA6D;IAC7D,aAAa,CAAC,GAA0B;QACtC,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;IAC5B,CAAC;CACF","sourcesContent":["/**\n * WizardRouter — declarative flow pipelines + overlay stack.\n *\n * Two layers:\n * Flow cursor — linear pipeline of screens, advanced with next()\n * Overlay stack — interrupts (outage, auth-expired, etc.) that push/pop\n *\n * The visible screen is: top of overlay stack if non-empty, otherwise the flow cursor.\n *\n * Adding a flow screen = append to a pipeline array.\n * Adding an overlay = call pushOverlay() from anywhere.\n * No switch statements, no hardcoded transitions in business logic.\n */\n\nimport type { WizardSession } from '../../lib/wizard-session.js';\nimport { FLOWS, Screen, Flow, type FlowEntry } from './flows.js';\n\n// Re-export so existing imports from './router.js' keep working\nexport { Screen, Flow };\nexport type { FlowEntry };\n\n// ── Screen name taxonomy ──────────────────────────────────────────────\n\n/** Screens that interrupt flows as overlays */\nexport enum Overlay {\n SettingsOverride = 'settings-override',\n ManagedSettings = 'managed-settings',\n PortConflict = 'port-conflict',\n AuthError = 'auth-error',\n}\n\n/** Union of all screen names */\nexport type ScreenName = Screen | Overlay;\n\n// ── Router ────────────────────────────────────────────────────────────\n\nexport class WizardRouter {\n private flow: FlowEntry[];\n private flowName: Flow;\n private overlays: Overlay[] = [];\n\n constructor(flowName: Flow = Flow.Wizard) {\n this.flowName = flowName;\n this.flow = FLOWS[flowName];\n }\n\n /**\n * Resolve which screen should be active based on session state.\n * Walks the flow pipeline, skipping hidden entries and completed entries,\n * returns the first incomplete screen.\n */\n resolve(session: WizardSession): ScreenName {\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n\n for (const entry of this.flow) {\n if (entry.show && !entry.show(session)) continue;\n if (entry.isComplete && entry.isComplete(session)) continue;\n return entry.screen;\n }\n\n // All entries complete — show the last screen (outro)\n return this.flow[this.flow.length - 1].screen;\n }\n\n /** The screen that should be rendered right now. */\n get activeScreen(): ScreenName {\n // Overlays take priority — resolve() handles this too,\n // but activeScreen is called before session is available in some paths\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n return this.flow[0].screen;\n }\n\n /** The name of the active flow. */\n get activeFlow(): Flow {\n return this.flowName;\n }\n\n /** Whether an overlay is currently active. */\n get hasOverlay(): boolean {\n return this.overlays.length > 0;\n }\n\n /**\n * Push an overlay that interrupts the current flow.\n * The flow resumes when the overlay is dismissed via popOverlay().\n */\n pushOverlay(overlay: Overlay): void {\n this.overlays.push(overlay);\n }\n\n /**\n * Dismiss the topmost overlay. The flow screen underneath resumes.\n */\n popOverlay(): void {\n this.overlays.pop();\n }\n\n /**\n * Direction hint for screen transitions.\n */\n private _lastDirection: 'push' | 'pop' | null = null;\n\n get lastNavDirection(): 'push' | 'pop' | null {\n return this._lastDirection;\n }\n\n /** @internal — called by store wrapper to track direction */\n _setDirection(dir: 'push' | 'pop' | null): void {\n this._lastDirection = dir;\n }\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Screen, Overlay } from './router.js';
|
|
3
3
|
import { HealthCheckScreen } from './screens/health/HealthCheckScreen.js';
|
|
4
4
|
import { SettingsOverrideScreen } from './screens/SettingsOverrideScreen.js';
|
|
5
|
+
import { ManagedSettingsScreen } from './screens/ManagedSettingsScreen.js';
|
|
5
6
|
import { PortConflictScreen } from './screens/PortConflictScreen.js';
|
|
6
7
|
import { IntroScreen } from './screens/IntroScreen.js';
|
|
7
8
|
import { SetupScreen } from './screens/SetupScreen.js';
|
|
@@ -9,6 +10,7 @@ import { AuthScreen } from './screens/AuthScreen.js';
|
|
|
9
10
|
import { RunScreen } from './screens/RunScreen.js';
|
|
10
11
|
import { McpScreen } from './screens/McpScreen.js';
|
|
11
12
|
import { OutroScreen } from './screens/OutroScreen.js';
|
|
13
|
+
import { AuthErrorScreen } from './screens/AuthErrorScreen.js';
|
|
12
14
|
import { createMcpInstaller } from './services/mcp-installer.js';
|
|
13
15
|
export function createServices() {
|
|
14
16
|
return {
|
|
@@ -19,7 +21,9 @@ export function createScreens(store, services) {
|
|
|
19
21
|
return {
|
|
20
22
|
// Overlays
|
|
21
23
|
[Overlay.SettingsOverride]: _jsx(SettingsOverrideScreen, { store: store }),
|
|
24
|
+
[Overlay.ManagedSettings]: _jsx(ManagedSettingsScreen, { store: store }),
|
|
22
25
|
[Overlay.PortConflict]: _jsx(PortConflictScreen, { store: store }),
|
|
26
|
+
[Overlay.AuthError]: _jsx(AuthErrorScreen, {}),
|
|
23
27
|
// Wizard flow
|
|
24
28
|
[Screen.Intro]: _jsx(IntroScreen, { store: store }),
|
|
25
29
|
[Screen.HealthCheck]: _jsx(HealthCheckScreen, { store: store }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-registry.js","sourceRoot":"","sources":["../../../../src/ui/tui/screen-registry.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOjE,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,YAAY,EAAE,kBAAkB,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,KAAkB,EAClB,QAAwB;IAExB,OAAO;QACL,WAAW;QACX,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,KAAC,sBAAsB,IAAC,KAAK,EAAE,KAAK,GAAI;QACpE,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,GAAI;
|
|
1
|
+
{"version":3,"file":"screen-registry.js","sourceRoot":"","sources":["../../../../src/ui/tui/screen-registry.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOjE,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,YAAY,EAAE,kBAAkB,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,KAAkB,EAClB,QAAwB;IAExB,OAAO;QACL,WAAW;QACX,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,KAAC,sBAAsB,IAAC,KAAK,EAAE,KAAK,GAAI;QACpE,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,KAAC,qBAAqB,IAAC,KAAK,EAAE,KAAK,GAAI;QAClE,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,GAAI;QAC5D,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,KAAC,eAAe,KAAG;QAExC,cAAc;QACd,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,GAAI;QAC7C,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,KAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,GAAI;QACzD,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,GAAI;QAC7C,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI;QAC3C,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,GAAI;QACzC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,YAAY,GAAI;QAC3E,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,GAAI;QAE7C,uBAAuB;QACvB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CACf,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,YAAY,EAAE,UAAU,SAAG,CACzE;QACD,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAClB,KAAC,SAAS,IACR,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,QAAQ,CAAC,YAAY,EAChC,IAAI,EAAC,QAAQ,EACb,UAAU,SACV,CACH;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Screen registry — maps screen names to React components.\n *\n * Adding a new screen:\n * 1. Create the component in screens/\n * 2. Add an entry here\n * 3. Add the screen name to the router flow (router.ts)\n *\n * App.tsx never needs to change.\n */\n\nimport type { ReactNode } from 'react';\nimport type { WizardStore } from './store.js';\nimport { Screen, Overlay, type ScreenName } from './router.js';\n\nimport { HealthCheckScreen } from './screens/health/HealthCheckScreen.js';\nimport { SettingsOverrideScreen } from './screens/SettingsOverrideScreen.js';\nimport { ManagedSettingsScreen } from './screens/ManagedSettingsScreen.js';\nimport { PortConflictScreen } from './screens/PortConflictScreen.js';\nimport { IntroScreen } from './screens/IntroScreen.js';\nimport { SetupScreen } from './screens/SetupScreen.js';\nimport { AuthScreen } from './screens/AuthScreen.js';\nimport { RunScreen } from './screens/RunScreen.js';\nimport { McpScreen } from './screens/McpScreen.js';\nimport { OutroScreen } from './screens/OutroScreen.js';\nimport { AuthErrorScreen } from './screens/AuthErrorScreen.js';\nimport { createMcpInstaller } from './services/mcp-installer.js';\nimport type { McpInstaller } from './services/mcp-installer.js';\n\nexport interface ScreenServices {\n mcpInstaller: McpInstaller;\n}\n\nexport function createServices(): ScreenServices {\n return {\n mcpInstaller: createMcpInstaller(),\n };\n}\n\nexport function createScreens(\n store: WizardStore,\n services: ScreenServices,\n): Record<ScreenName, ReactNode> {\n return {\n // Overlays\n [Overlay.SettingsOverride]: <SettingsOverrideScreen store={store} />,\n [Overlay.ManagedSettings]: <ManagedSettingsScreen store={store} />,\n [Overlay.PortConflict]: <PortConflictScreen store={store} />,\n [Overlay.AuthError]: <AuthErrorScreen />,\n\n // Wizard flow\n [Screen.Intro]: <IntroScreen store={store} />,\n [Screen.HealthCheck]: <HealthCheckScreen store={store} />,\n [Screen.Setup]: <SetupScreen store={store} />,\n [Screen.Auth]: <AuthScreen store={store} />,\n [Screen.Run]: <RunScreen store={store} />,\n [Screen.Mcp]: <McpScreen store={store} installer={services.mcpInstaller} />,\n [Screen.Outro]: <OutroScreen store={store} />,\n\n // Standalone MCP flows\n [Screen.McpAdd]: (\n <McpScreen store={store} installer={services.mcpInstaller} standalone />\n ),\n [Screen.McpRemove]: (\n <McpScreen\n store={store}\n installer={services.mcpInstaller}\n mode=\"remove\"\n standalone\n />\n ),\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthErrorScreen — Shown when the Anthropic API returns a 401.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code's own auth can conflict with the wizard's OAuth token.
|
|
5
|
+
* This overlay tells the user to log out of Claude Code and retry.
|
|
6
|
+
*/
|
|
7
|
+
export declare const AuthErrorScreen: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AuthErrorScreen — Shown when the Anthropic API returns a 401.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code's own auth can conflict with the wizard's OAuth token.
|
|
6
|
+
* This overlay tells the user to log out of Claude Code and retry.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text, useInput } from 'ink';
|
|
9
|
+
import { Colors } from '../styles.js';
|
|
10
|
+
export const AuthErrorScreen = () => {
|
|
11
|
+
useInput(() => {
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
14
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Text, { color: "red", bold: true, children: ['\u2718', " Authentication error"] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { children: "The Wizard couldn't connect to the PostHog LLM Gateway. If you use Claude Code, its credentials might conflict with the Wizard." }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Try logging out of Claude Code temporarily and re-running the Wizard by running:" }) }), _jsx(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, children: _jsx(Text, { color: "cyan", children: "claude auth logout" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: Colors.muted, children: "Press any key to exit" }) })] }));
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=AuthErrorScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthErrorScreen.js","sourceRoot":"","sources":["../../../../../src/ui/tui/screens/AuthErrorScreen.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAClC,QAAQ,CAAC,GAAG,EAAE;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aACrC,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,EAAC,IAAI,mBACnB,QAAQ,6BACJ,EAEP,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,YACtC,KAAC,IAAI,kJAIE,GACH,EAEN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,QAAQ,uGAGP,GACH,EAEN,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,YACtD,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,mCAA0B,GACxC,EAEN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,sCAA8B,GACnD,IACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * AuthErrorScreen — Shown when the Anthropic API returns a 401.\n *\n * Claude Code's own auth can conflict with the wizard's OAuth token.\n * This overlay tells the user to log out of Claude Code and retry.\n */\n\nimport { Box, Text, useInput } from 'ink';\nimport { Colors } from '../styles.js';\n\nexport const AuthErrorScreen = () => {\n useInput(() => {\n process.exit(1);\n });\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Text color=\"red\" bold>\n {'\\u2718'} Authentication error\n </Text>\n\n <Box flexDirection=\"column\" marginTop={1}>\n <Text>\n The Wizard couldn't connect to the PostHog LLM Gateway. If\n you use Claude Code, its credentials might conflict with the\n Wizard.\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n Try logging out of Claude Code temporarily and re-running the Wizard\n by running:\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" marginTop={1} paddingLeft={2}>\n <Text color=\"cyan\">claude auth logout</Text>\n </Box>\n\n <Box marginTop={1}>\n <Text color={Colors.muted}>Press any key to exit</Text>\n </Box>\n </Box>\n );\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ManagedSettingsScreen — Modal when IT/org-managed settings contain overrides
|
|
3
|
+
* that block the Wizard from reaching the PostHog LLM Gateway.
|
|
4
|
+
*
|
|
5
|
+
* Unlike SettingsOverrideScreen, the wizard cannot back up or modify these files.
|
|
6
|
+
* The user must contact their IT administrator to resolve the conflict.
|
|
7
|
+
*/
|
|
8
|
+
import type { WizardStore } from '../store.js';
|
|
9
|
+
interface ManagedSettingsScreenProps {
|
|
10
|
+
store: WizardStore;
|
|
11
|
+
}
|
|
12
|
+
export declare const ManagedSettingsScreen: ({ store, }: ManagedSettingsScreenProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ManagedSettingsScreen — Modal when IT/org-managed settings contain overrides
|
|
4
|
+
* that block the Wizard from reaching the PostHog LLM Gateway.
|
|
5
|
+
*
|
|
6
|
+
* Unlike SettingsOverrideScreen, the wizard cannot back up or modify these files.
|
|
7
|
+
* The user must contact their IT administrator to resolve the conflict.
|
|
8
|
+
*/
|
|
9
|
+
import { Box, Text } from 'ink';
|
|
10
|
+
import { useSyncExternalStore } from 'react';
|
|
11
|
+
import { ConfirmationInput, ModalOverlay } from '../primitives/index.js';
|
|
12
|
+
import { Icons } from '../styles.js';
|
|
13
|
+
function sourceLabel(source) {
|
|
14
|
+
switch (source) {
|
|
15
|
+
case 'managed':
|
|
16
|
+
return 'Managed settings (IT/org-managed)';
|
|
17
|
+
case 'project':
|
|
18
|
+
return '.claude/settings.json';
|
|
19
|
+
default:
|
|
20
|
+
return source;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export const ManagedSettingsScreen = ({ store, }) => {
|
|
24
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
25
|
+
const conflicts = store.session.settingsConflicts;
|
|
26
|
+
const readOnlyConflicts = conflicts?.filter((c) => !c.writable);
|
|
27
|
+
if (!readOnlyConflicts || readOnlyConflicts.length === 0) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return (_jsxs(ModalOverlay, { borderColor: "red", title: `${Icons.warning} Organization settings conflict`, width: 68, footer: _jsx(ConfirmationInput, { message: "Contact your IT administrator to resolve this.", confirmLabel: "", cancelLabel: "Exit [Esc]", onConfirm: () => process.exit(1), onCancel: () => process.exit(1) }), children: [_jsx(Text, { dimColor: true, children: "Your organization's managed settings contain overrides that prevent the Wizard from reaching the PostHog LLM Gateway." }), readOnlyConflicts.map((conflict) => (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: sourceLabel(conflict.source) }), _jsx(Box, { flexDirection: "column", paddingLeft: 2, children: conflict.keys.map((key) => (_jsxs(Text, { children: [Icons.bullet, ' ', _jsx(Text, { color: "yellow", bold: true, children: key })] }, key))) })] }, conflict.source))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Try running \"claude auth logout\" or contact your IT administrator to resolve this." }) })] }));
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=ManagedSettingsScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManagedSettingsScreen.js","sourceRoot":"","sources":["../../../../../src/ui/tui/screens/ManagedSettingsScreen.tsx"],"names":[],"mappings":";AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAGrC,SAAS,WAAW,CAAC,MAAkC;IACrD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,SAAS;YACZ,OAAO,mCAAmC,CAAC;QAC7C,KAAK,SAAS;YACZ,OAAO,uBAAuB,CAAC;QACjC;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EACpC,KAAK,GACsB,EAAE,EAAE;IAC/B,oBAAoB,CAClB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,EAC3B,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAC1B,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC;IAClD,MAAM,iBAAiB,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEhE,IAAI,CAAC,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,MAAC,YAAY,IACX,WAAW,EAAC,KAAK,EACjB,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,iCAAiC,EACxD,KAAK,EAAE,EAAE,EACT,MAAM,EACJ,KAAC,iBAAiB,IAChB,OAAO,EAAC,gDAAgD,EACxD,YAAY,EAAC,EAAE,EACf,WAAW,EAAC,YAAY,EACxB,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAChC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAC/B,aAGJ,KAAC,IAAI,IAAC,QAAQ,4IAGP,EACN,iBAAiB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CACnC,MAAC,GAAG,IAAuB,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,aAC5D,KAAC,IAAI,IAAC,IAAI,kBAAE,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAQ,EAChD,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,YACvC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC1B,MAAC,IAAI,eACF,KAAK,CAAC,MAAM,EAAE,GAAG,EAClB,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,kBACtB,GAAG,GACC,KAJE,GAAG,CAKP,CACR,CAAC,GACE,KAXE,QAAQ,CAAC,MAAM,CAYnB,CACP,CAAC,EACF,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,QAAQ,2GAGP,GACH,IACO,CAChB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * ManagedSettingsScreen — Modal when IT/org-managed settings contain overrides\n * that block the Wizard from reaching the PostHog LLM Gateway.\n *\n * Unlike SettingsOverrideScreen, the wizard cannot back up or modify these files.\n * The user must contact their IT administrator to resolve the conflict.\n */\n\nimport { Box, Text } from 'ink';\nimport { useSyncExternalStore } from 'react';\nimport type { WizardStore } from '../store.js';\nimport { ConfirmationInput, ModalOverlay } from '../primitives/index.js';\nimport { Icons } from '../styles.js';\nimport type { SettingsConflict } from '../../../lib/agent-interface.js';\n\nfunction sourceLabel(source: SettingsConflict['source']): string {\n switch (source) {\n case 'managed':\n return 'Managed settings (IT/org-managed)';\n case 'project':\n return '.claude/settings.json';\n default:\n return source;\n }\n}\n\ninterface ManagedSettingsScreenProps {\n store: WizardStore;\n}\n\nexport const ManagedSettingsScreen = ({\n store,\n}: ManagedSettingsScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const conflicts = store.session.settingsConflicts;\n const readOnlyConflicts = conflicts?.filter((c) => !c.writable);\n\n if (!readOnlyConflicts || readOnlyConflicts.length === 0) {\n return null;\n }\n\n return (\n <ModalOverlay\n borderColor=\"red\"\n title={`${Icons.warning} Organization settings conflict`}\n width={68}\n footer={\n <ConfirmationInput\n message=\"Contact your IT administrator to resolve this.\"\n confirmLabel=\"\"\n cancelLabel=\"Exit [Esc]\"\n onConfirm={() => process.exit(1)}\n onCancel={() => process.exit(1)}\n />\n }\n >\n <Text dimColor>\n Your organization's managed settings contain overrides that prevent\n the Wizard from reaching the PostHog LLM Gateway.\n </Text>\n {readOnlyConflicts.map((conflict) => (\n <Box key={conflict.source} flexDirection=\"column\" marginTop={1}>\n <Text bold>{sourceLabel(conflict.source)}</Text>\n <Box flexDirection=\"column\" paddingLeft={2}>\n {conflict.keys.map((key) => (\n <Text key={key}>\n {Icons.bullet}{' '}\n <Text color=\"yellow\" bold>\n {key}\n </Text>\n </Text>\n ))}\n </Box>\n </Box>\n ))}\n <Box marginTop={1}>\n <Text dimColor>\n Try running \"claude auth logout\" or contact your IT administrator to\n resolve this.\n </Text>\n </Box>\n </ModalOverlay>\n );\n};\n"]}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* importing business logic directly. Testable, no dynamic imports.
|
|
6
6
|
*
|
|
7
7
|
* Supports two modes via the `mode` prop:
|
|
8
|
-
* - 'install': detect clients → confirm → install
|
|
8
|
+
* - 'install': detect clients → confirm → [pick clients] → pick features → install
|
|
9
9
|
* - 'remove': detect installed clients → confirm → remove
|
|
10
10
|
*
|
|
11
11
|
* When done, calls store.setMcpComplete(). The router resolves to outro.
|
|
@@ -6,7 +6,7 @@ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-run
|
|
|
6
6
|
* importing business logic directly. Testable, no dynamic imports.
|
|
7
7
|
*
|
|
8
8
|
* Supports two modes via the `mode` prop:
|
|
9
|
-
* - 'install': detect clients → confirm → install
|
|
9
|
+
* - 'install': detect clients → confirm → [pick clients] → pick features → install
|
|
10
10
|
* - 'remove': detect installed clients → confirm → remove
|
|
11
11
|
*
|
|
12
12
|
* When done, calls store.setMcpComplete(). The router resolves to outro.
|
|
@@ -15,13 +15,15 @@ import { Box, Text } from 'ink';
|
|
|
15
15
|
import { useState, useEffect } from 'react';
|
|
16
16
|
import { useSyncExternalStore } from 'react';
|
|
17
17
|
import { McpOutcome } from '../store.js';
|
|
18
|
-
import { ConfirmationInput, PickerMenu } from '../primitives/index.js';
|
|
18
|
+
import { ConfirmationInput, PickerMenu, GroupedPickerMenu, } from '../primitives/index.js';
|
|
19
19
|
import { Colors } from '../styles.js';
|
|
20
|
+
import { AVAILABLE_FEATURES, ALL_FEATURE_VALUES, } from '../../../steps/add-mcp-server-to-clients/defaults.js';
|
|
20
21
|
var Phase;
|
|
21
22
|
(function (Phase) {
|
|
22
23
|
Phase["Detecting"] = "detecting";
|
|
23
24
|
Phase["Ask"] = "ask";
|
|
24
25
|
Phase["Pick"] = "pick";
|
|
26
|
+
Phase["FeatureSelect"] = "feature-select";
|
|
25
27
|
Phase["Working"] = "working";
|
|
26
28
|
Phase["Done"] = "done";
|
|
27
29
|
Phase["None"] = "none";
|
|
@@ -37,6 +39,7 @@ export const McpScreen = ({ store, installer, mode = 'install', standalone = fal
|
|
|
37
39
|
const isRemove = mode === 'remove';
|
|
38
40
|
const [phase, setPhase] = useState(Phase.Detecting);
|
|
39
41
|
const [clients, setClients] = useState([]);
|
|
42
|
+
const [selectedClientNames, setSelectedClientNames] = useState([]);
|
|
40
43
|
const [resultClients, setResultClients] = useState([]);
|
|
41
44
|
useEffect(() => {
|
|
42
45
|
void (async () => {
|
|
@@ -57,12 +60,22 @@ export const McpScreen = ({ store, installer, mode = 'install', standalone = fal
|
|
|
57
60
|
}
|
|
58
61
|
})();
|
|
59
62
|
}, [installer]); // eslint-disable-line
|
|
63
|
+
const proceedToFeatureSelectOrInstall = (clientNames) => {
|
|
64
|
+
setSelectedClientNames(clientNames);
|
|
65
|
+
// Skip feature picker if CLI already specified features
|
|
66
|
+
if (store.session.mcpFeatures) {
|
|
67
|
+
void doInstall(clientNames, store.session.mcpFeatures);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
setPhase(Phase.FeatureSelect);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
60
73
|
const handleConfirm = () => {
|
|
61
74
|
if (isRemove) {
|
|
62
75
|
void doRemove();
|
|
63
76
|
}
|
|
64
77
|
else if (clients.length === 1) {
|
|
65
|
-
|
|
78
|
+
proceedToFeatureSelectOrInstall(clients.map((c) => c.name));
|
|
66
79
|
}
|
|
67
80
|
else {
|
|
68
81
|
setPhase(Phase.Pick);
|
|
@@ -71,11 +84,11 @@ export const McpScreen = ({ store, installer, mode = 'install', standalone = fal
|
|
|
71
84
|
const handleSkip = () => {
|
|
72
85
|
markDone(store, McpOutcome.Skipped, [], standalone);
|
|
73
86
|
};
|
|
74
|
-
const doInstall = async (names) => {
|
|
87
|
+
const doInstall = async (names, features) => {
|
|
75
88
|
setPhase(Phase.Working);
|
|
76
89
|
let result = [];
|
|
77
90
|
try {
|
|
78
|
-
result = await installer.install(names);
|
|
91
|
+
result = await installer.install(names, features);
|
|
79
92
|
setResultClients(result);
|
|
80
93
|
}
|
|
81
94
|
catch {
|
|
@@ -106,7 +119,9 @@ export const McpScreen = ({ store, installer, mode = 'install', standalone = fal
|
|
|
106
119
|
value: c.name,
|
|
107
120
|
})), mode: "multi", onSelect: (selected) => {
|
|
108
121
|
const names = Array.isArray(selected) ? selected : [selected];
|
|
109
|
-
|
|
122
|
+
proceedToFeatureSelectOrInstall(names);
|
|
123
|
+
} })), phase === Phase.FeatureSelect && (_jsx(GroupedPickerMenu, { message: "Select features to enable", groups: AVAILABLE_FEATURES, initialSelected: [...ALL_FEATURE_VALUES], onSelect: (features) => {
|
|
124
|
+
void doInstall(selectedClientNames, features);
|
|
110
125
|
} })), phase === Phase.Working && (_jsxs(Text, { dimColor: true, children: [isRemove ? 'Removing' : 'Installing', " MCP server..."] })), phase === Phase.Done && (_jsx(Box, { flexDirection: "column", children: resultClients.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", bold: true, children: ['\u2714', " MCP server", ' ', isRemove ? 'removed from' : 'installed for', ":"] }), resultClients.map((name, i) => (_jsxs(Text, { children: [' ', '\u2022', " ", name] }, i)))] })) : (_jsxs(Text, { dimColor: true, children: [isRemove ? 'Removal' : 'Installation', " skipped."] })) }))] })] }));
|
|
111
126
|
};
|
|
112
127
|
//# sourceMappingURL=McpScreen.js.map
|