@within-7/minto 0.3.9 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/commands/agents/AgentsCommand.js +459 -655
  2. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  3. package/dist/commands/agents/types.js +1 -0
  4. package/dist/commands/agents/types.js.map +2 -2
  5. package/dist/commands/agents/utils/fileOperations.js +96 -36
  6. package/dist/commands/agents/utils/fileOperations.js.map +3 -3
  7. package/dist/commands/agents/utils/index.js +3 -1
  8. package/dist/commands/agents/utils/index.js.map +2 -2
  9. package/dist/commands/context.js +54 -23
  10. package/dist/commands/context.js.map +2 -2
  11. package/dist/commands/export.js +673 -93
  12. package/dist/commands/export.js.map +2 -2
  13. package/dist/commands/language.js +19 -46
  14. package/dist/commands/language.js.map +2 -2
  15. package/dist/commands/mcp-interactive.js +419 -217
  16. package/dist/commands/mcp-interactive.js.map +2 -2
  17. package/dist/commands/model.js +415 -66
  18. package/dist/commands/model.js.map +2 -2
  19. package/dist/commands/permissions.js +75 -49
  20. package/dist/commands/permissions.js.map +2 -2
  21. package/dist/commands/plugin.js +882 -185
  22. package/dist/commands/plugin.js.map +3 -3
  23. package/dist/commands/resume.js +1 -1
  24. package/dist/commands/resume.js.map +1 -1
  25. package/dist/commands/sandbox.js +168 -70
  26. package/dist/commands/sandbox.js.map +2 -2
  27. package/dist/commands/setup.js +593 -107
  28. package/dist/commands/setup.js.map +2 -2
  29. package/dist/commands/stats.js +188 -131
  30. package/dist/commands/stats.js.map +2 -2
  31. package/dist/commands/status.js +75 -13
  32. package/dist/commands/status.js.map +2 -2
  33. package/dist/commands/undo.js +138 -174
  34. package/dist/commands/undo.js.map +2 -2
  35. package/dist/commands.js.map +1 -1
  36. package/dist/components/Help.js +165 -32
  37. package/dist/components/Help.js.map +2 -2
  38. package/dist/components/InfoPanel/InfoPanel.js +123 -0
  39. package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
  40. package/dist/components/InfoPanel/index.js +5 -0
  41. package/dist/components/InfoPanel/index.js.map +7 -0
  42. package/dist/components/InfoPanel/types.js +1 -0
  43. package/dist/components/InfoPanel/types.js.map +7 -0
  44. package/dist/components/ModelSelector/BrandTextInput.js +43 -0
  45. package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
  46. package/dist/components/ModelSelector/ModelSelector.js +419 -501
  47. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  48. package/dist/components/ModelSelector/WizardContainer.js +45 -0
  49. package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
  50. package/dist/components/ModelSelector/index.js +1 -3
  51. package/dist/components/ModelSelector/index.js.map +2 -2
  52. package/dist/components/PromptInput.js +5 -5
  53. package/dist/components/PromptInput.js.map +2 -2
  54. package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
  55. package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
  56. package/dist/components/SimpleSelector/index.js +5 -0
  57. package/dist/components/SimpleSelector/index.js.map +7 -0
  58. package/dist/components/SimpleSelector/types.js +1 -0
  59. package/dist/components/SimpleSelector/types.js.map +7 -0
  60. package/dist/components/StatusOverlayContent.js +21 -0
  61. package/dist/components/StatusOverlayContent.js.map +7 -0
  62. package/dist/components/TabbedListView/ScrollableList.js +31 -5
  63. package/dist/components/TabbedListView/ScrollableList.js.map +2 -2
  64. package/dist/components/TabbedListView/TabbedListView.js +122 -47
  65. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  66. package/dist/core/backupHook.js +29 -0
  67. package/dist/core/backupHook.js.map +7 -0
  68. package/dist/core/config/defaults.js +8 -2
  69. package/dist/core/config/defaults.js.map +2 -2
  70. package/dist/core/config/schema.js +14 -2
  71. package/dist/core/config/schema.js.map +2 -2
  72. package/dist/core/costTracker.js +0 -16
  73. package/dist/core/costTracker.js.map +2 -2
  74. package/dist/cost-tracker.js +0 -16
  75. package/dist/cost-tracker.js.map +2 -2
  76. package/dist/entrypoints/bootstrap.js +3 -1
  77. package/dist/entrypoints/bootstrap.js.map +2 -2
  78. package/dist/entrypoints/cli.js +32 -0
  79. package/dist/entrypoints/cli.js.map +2 -2
  80. package/dist/i18n/locales/en.js +300 -1
  81. package/dist/i18n/locales/en.js.map +2 -2
  82. package/dist/i18n/locales/zh-CN.js +301 -2
  83. package/dist/i18n/locales/zh-CN.js.map +2 -2
  84. package/dist/i18n/types.js.map +1 -1
  85. package/dist/services/customCommands.js +30 -8
  86. package/dist/services/customCommands.js.map +2 -2
  87. package/dist/services/plugins/lspServers.js +1 -1
  88. package/dist/services/plugins/lspServers.js.map +2 -2
  89. package/dist/services/plugins/pluginRuntime.js +2 -1
  90. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  91. package/dist/services/plugins/pluginValidation.js +10 -3
  92. package/dist/services/plugins/pluginValidation.js.map +2 -2
  93. package/dist/services/plugins/skillMarketplace.js +16 -8
  94. package/dist/services/plugins/skillMarketplace.js.map +2 -2
  95. package/dist/services/systemReminder.js +17 -6
  96. package/dist/services/systemReminder.js.map +2 -2
  97. package/dist/tools/FileEditTool/FileEditTool.js +7 -0
  98. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  99. package/dist/tools/FileWriteTool/FileWriteTool.js +7 -0
  100. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  101. package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
  102. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  103. package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
  104. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  105. package/dist/tools/TaskTool/TaskTool.js +9 -6
  106. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  107. package/dist/types/PermissionMode.js.map +1 -1
  108. package/dist/types/plugin.js +2 -4
  109. package/dist/types/plugin.js.map +2 -2
  110. package/dist/utils/agentHookExecutor.js +1 -4
  111. package/dist/utils/agentHookExecutor.js.map +2 -2
  112. package/dist/utils/agentLoader.js +67 -13
  113. package/dist/utils/agentLoader.js.map +2 -2
  114. package/dist/utils/agentMemory.js.map +2 -2
  115. package/dist/utils/claudeCodeSync.js +439 -0
  116. package/dist/utils/claudeCodeSync.js.map +7 -0
  117. package/dist/utils/config.js +1 -23
  118. package/dist/utils/config.js.map +2 -2
  119. package/dist/utils/execFileNoThrow.js +2 -1
  120. package/dist/utils/execFileNoThrow.js.map +2 -2
  121. package/dist/utils/marketplaceManager.js +80 -43
  122. package/dist/utils/marketplaceManager.js.map +2 -2
  123. package/dist/utils/messages.js +2 -2
  124. package/dist/utils/messages.js.map +2 -2
  125. package/dist/utils/pluginInstaller.js +34 -24
  126. package/dist/utils/pluginInstaller.js.map +2 -2
  127. package/dist/utils/pluginLoader.js +48 -25
  128. package/dist/utils/pluginLoader.js.map +2 -2
  129. package/dist/utils/repoFetcher.js +110 -0
  130. package/dist/utils/repoFetcher.js.map +7 -0
  131. package/dist/utils/skillLoader.js +18 -6
  132. package/dist/utils/skillLoader.js.map +2 -2
  133. package/dist/utils/stringSubstitution.js +4 -5
  134. package/dist/utils/stringSubstitution.js.map +2 -2
  135. package/dist/utils/teamConfig.js +153 -13
  136. package/dist/utils/teamConfig.js.map +2 -2
  137. package/dist/utils/terminal.js +1 -1
  138. package/dist/utils/terminal.js.map +2 -2
  139. package/dist/version.js +2 -2
  140. package/dist/version.js.map +1 -1
  141. package/package.json +6 -6
@@ -0,0 +1,154 @@
1
+ import React, { useState, useMemo, useCallback } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
4
+ import { ScrollableList } from "../TabbedListView/index.js";
5
+ import { StatusOverlayContent } from "../StatusOverlayContent.js";
6
+ import { useTerminalSize } from "../../hooks/useTerminalSize.js";
7
+ import { t } from "../../i18n/index.js";
8
+ const PROMPT_HEIGHT = 5;
9
+ const CHROME_HEIGHT = 4;
10
+ function toListItems(items) {
11
+ return items.map((item) => ({
12
+ id: item.id,
13
+ label: item.label,
14
+ description: item.description,
15
+ category: item.category,
16
+ metadata: item.isCurrent ? `(${t("common.selected")})` : void 0,
17
+ status: item.isCurrent ? "enabled" : void 0,
18
+ data: item
19
+ }));
20
+ }
21
+ function SelectorItemRenderer({
22
+ item,
23
+ isFocused,
24
+ selectorItem
25
+ }) {
26
+ const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim;
27
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: isFocused ? BRAND_GRADIENT.START : void 0 }, isFocused ? "\u25C6 " : " "), selectorItem?.statusIcon && /* @__PURE__ */ React.createElement(Text, { color: selectorItem.statusColor || SEMANTIC_COLORS.dim }, selectorItem.statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { color: textColor }, item.label, selectorItem?.isCurrent && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, " (", t("common.selected"), ")"), item.description && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " ", item.description)));
28
+ }
29
+ function SimpleSelector({
30
+ title,
31
+ subtitle,
32
+ items,
33
+ onSelect,
34
+ onClose,
35
+ groupByCategory = false,
36
+ statusOverlay,
37
+ isActive = true,
38
+ maxVisible
39
+ }) {
40
+ const { rows } = useTerminalSize();
41
+ const dynamicVisible = Math.min(
42
+ 8,
43
+ Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT)
44
+ );
45
+ const effectiveMaxVisible = maxVisible ?? dynamicVisible;
46
+ const [focusedIndex, setFocusedIndex] = useState(0);
47
+ const listItems = useMemo(() => toListItems(items), [items]);
48
+ const selectorItemMap = useMemo(() => {
49
+ const map = /* @__PURE__ */ new Map();
50
+ items.forEach((item) => map.set(item.id, item));
51
+ return map;
52
+ }, [items]);
53
+ const handleSelect = useCallback(
54
+ (listItem) => {
55
+ const selectorItem = selectorItemMap.get(listItem.id);
56
+ if (selectorItem) {
57
+ onSelect(selectorItem);
58
+ }
59
+ },
60
+ [selectorItemMap, onSelect]
61
+ );
62
+ const renderItem = useCallback(
63
+ (item, isFocused) => /* @__PURE__ */ React.createElement(
64
+ SelectorItemRenderer,
65
+ {
66
+ item,
67
+ isFocused,
68
+ selectorItem: selectorItemMap.get(item.id)
69
+ }
70
+ ),
71
+ [selectorItemMap]
72
+ );
73
+ useInput(
74
+ (input, key) => {
75
+ if (statusOverlay && statusOverlay.type !== "loading") {
76
+ if (key.escape || key.return) {
77
+ onClose();
78
+ }
79
+ return;
80
+ }
81
+ if (statusOverlay) return;
82
+ if (key.escape) {
83
+ onClose();
84
+ return;
85
+ }
86
+ if (key.downArrow && listItems.length > 0) {
87
+ setFocusedIndex((prev) => prev < listItems.length - 1 ? prev + 1 : prev);
88
+ return;
89
+ }
90
+ if (key.upArrow && listItems.length > 0) {
91
+ setFocusedIndex((prev) => prev > 0 ? prev - 1 : prev);
92
+ return;
93
+ }
94
+ if (key.return && listItems.length > 0) {
95
+ handleSelect(listItems[focusedIndex]);
96
+ return;
97
+ }
98
+ },
99
+ { isActive }
100
+ );
101
+ const footerHint = statusOverlay ? statusOverlay.type === "loading" ? "" : t("ui.simpleSelector.dismissHint") : t("ui.simpleSelector.navigationHint");
102
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React.createElement(
103
+ Box,
104
+ {
105
+ borderTop: true,
106
+ borderBottom: false,
107
+ borderLeft: false,
108
+ borderRight: false,
109
+ borderColor: BRAND_GRADIENT.START,
110
+ borderStyle: "single",
111
+ width: "100%",
112
+ paddingX: 1,
113
+ flexDirection: "column"
114
+ },
115
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), subtitle && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", subtitle))
116
+ ), /* @__PURE__ */ React.createElement(
117
+ Box,
118
+ {
119
+ flexDirection: "column",
120
+ borderTop: false,
121
+ borderBottom: true,
122
+ borderLeft: false,
123
+ borderRight: false,
124
+ borderColor: BRAND_GRADIENT.START,
125
+ borderStyle: "single",
126
+ width: "100%",
127
+ paddingX: 1,
128
+ paddingY: 1
129
+ },
130
+ statusOverlay ? /* @__PURE__ */ React.createElement(
131
+ StatusOverlayContent,
132
+ {
133
+ type: statusOverlay.type,
134
+ message: statusOverlay.message
135
+ }
136
+ ) : listItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("ui.tabbedList.noItems"))) : /* @__PURE__ */ React.createElement(
137
+ ScrollableList,
138
+ {
139
+ items: listItems,
140
+ focusedIndex,
141
+ onFocusChange: setFocusedIndex,
142
+ onSelect: handleSelect,
143
+ visibleCount: effectiveMaxVisible,
144
+ groupByCategory,
145
+ renderItem
146
+ }
147
+ ),
148
+ footerHint && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, footerHint))
149
+ ));
150
+ }
151
+ export {
152
+ SimpleSelector
153
+ };
154
+ //# sourceMappingURL=SimpleSelector.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/SimpleSelector/SimpleSelector.tsx"],
4
+ "sourcesContent": ["/**\n * SimpleSelector Component\n *\n * A lightweight single-choice selector visually matching TabbedListView\n * but without tabs or search. Reuses ScrollableList internally.\n *\n * Visual pattern:\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 (BRAND_GRADIENT.START border)\n * \u25C6 Title subtitle\n *\n * Category Name\n * \u25C6 Item A (current)\n * Item B description\n * Item C description\n *\n * \u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Esc Close\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 (BRAND_GRADIENT.START border)\n */\n\nimport React, { useState, useMemo, useCallback } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { ScrollableList } from '@components/TabbedListView'\nimport { StatusOverlayContent } from '@components/StatusOverlayContent'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { t } from '@i18n'\nimport type { ListItem } from '@components/TabbedListView'\nimport type { SimpleSelectorProps, SelectorItem } from './types'\n\n// Heights for dynamic visible count calculation\nconst PROMPT_HEIGHT = 5 // PromptInput borders + input + hints\nconst CHROME_HEIGHT = 4 // title + footer + borders (no tabs/search)\n\n/**\n * Convert SelectorItems to ListItems for ScrollableList\n */\nfunction toListItems(items: SelectorItem[]): ListItem[] {\n return items.map(item => ({\n id: item.id,\n label: item.label,\n description: item.description,\n category: item.category,\n metadata: item.isCurrent ? `(${t('common.selected')})` : undefined,\n status: item.isCurrent ? ('enabled' as const) : undefined,\n data: item,\n }))\n}\n\n/**\n * Custom item renderer that supports statusIcon and statusColor\n */\nfunction SelectorItemRenderer({\n item,\n isFocused,\n selectorItem,\n}: {\n item: ListItem\n isFocused: boolean\n selectorItem?: SelectorItem\n}) {\n const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n\n return (\n <Box flexDirection=\"row\">\n {/* Selection indicator */}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\\u25C6 ' : ' '}\n </Text>\n\n {/* Status icon if present */}\n {selectorItem?.statusIcon && (\n <Text color={selectorItem.statusColor || SEMANTIC_COLORS.dim}>\n {selectorItem.statusIcon}{' '}\n </Text>\n )}\n\n {/* Main content */}\n <Text color={textColor}>\n {item.label}\n {selectorItem?.isCurrent && (\n <Text color={SEMANTIC_COLORS.success}> ({t('common.selected')})</Text>\n )}\n {item.description && (\n <Text color={SEMANTIC_COLORS.muted}> {item.description}</Text>\n )}\n </Text>\n </Box>\n )\n}\n\nexport function SimpleSelector({\n title,\n subtitle,\n items,\n onSelect,\n onClose,\n groupByCategory = false,\n statusOverlay,\n isActive = true,\n maxVisible,\n}: SimpleSelectorProps) {\n // Dynamic visible count based on terminal height\n const { rows } = useTerminalSize()\n const dynamicVisible = Math.min(\n 8,\n Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT),\n )\n const effectiveMaxVisible = maxVisible ?? dynamicVisible\n\n const [focusedIndex, setFocusedIndex] = useState(0)\n\n const listItems = useMemo(() => toListItems(items), [items])\n\n // Map from ListItem back to SelectorItem for custom rendering\n const selectorItemMap = useMemo(() => {\n const map = new Map<string, SelectorItem>()\n items.forEach(item => map.set(item.id, item))\n return map\n }, [items])\n\n const handleSelect = useCallback(\n (listItem: ListItem) => {\n const selectorItem = selectorItemMap.get(listItem.id)\n if (selectorItem) {\n onSelect(selectorItem)\n }\n },\n [selectorItemMap, onSelect],\n )\n\n const renderItem = useCallback(\n (item: ListItem, isFocused: boolean) => (\n <SelectorItemRenderer\n item={item}\n isFocused={isFocused}\n selectorItem={selectorItemMap.get(item.id)}\n />\n ),\n [selectorItemMap],\n )\n\n // Keyboard input handling\n useInput(\n (input, key) => {\n // Status overlay: success/error -> ESC/Enter closes\n if (statusOverlay && statusOverlay.type !== 'loading') {\n if (key.escape || key.return) {\n onClose()\n }\n return\n }\n\n // Status overlay: loading -> ignore all input\n if (statusOverlay) return\n\n // Escape closes\n if (key.escape) {\n onClose()\n return\n }\n\n // Arrow navigation\n if (key.downArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev < listItems.length - 1 ? prev + 1 : prev))\n return\n }\n\n if (key.upArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev > 0 ? prev - 1 : prev))\n return\n }\n\n // Enter to select\n if (key.return && listItems.length > 0) {\n handleSelect(listItems[focusedIndex])\n return\n }\n },\n { isActive },\n )\n\n // Build footer hint\n const footerHint = statusOverlay\n ? statusOverlay.type === 'loading'\n ? ''\n : t('ui.simpleSelector.dismissHint')\n : t('ui.simpleSelector.navigationHint')\n\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n {/* Header bar with top border */}\n <Box\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n flexDirection=\"column\"\n >\n {/* Title with brand color */}\n <Box>\n <Text color={BRAND_GRADIENT.START}>{'\\u25C6'}</Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {' '}\n {title}\n </Text>\n {subtitle && (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {subtitle}\n </Text>\n )}\n </Box>\n </Box>\n\n {/* Content container with bottom border */}\n <Box\n flexDirection=\"column\"\n borderTop={false}\n borderBottom={true}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n paddingY={1}\n >\n {statusOverlay ? (\n <StatusOverlayContent\n type={statusOverlay.type}\n message={statusOverlay.message}\n />\n ) : listItems.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('ui.tabbedList.noItems')}\n </Text>\n </Box>\n ) : (\n <ScrollableList\n items={listItems}\n focusedIndex={focusedIndex}\n onFocusChange={setFocusedIndex}\n onSelect={handleSelect}\n visibleCount={effectiveMaxVisible}\n groupByCategory={groupByCategory}\n renderItem={renderItem}\n />\n )}\n\n {/* Footer Hint */}\n {footerHint && (\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>{footerHint}</Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ import { SimpleSelector } from "./SimpleSelector.js";
2
+ export {
3
+ SimpleSelector
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/SimpleSelector/index.ts"],
4
+ "sourcesContent": ["/**\n * SimpleSelector Component Exports\n *\n * A lightweight single-choice selector for quick selection commands.\n */\n\nexport { SimpleSelector } from './SimpleSelector'\nexport type { SimpleSelectorProps, SelectorItem, StatusOverlay } from './types'\n"],
5
+ "mappings": "AAMA,SAAS,sBAAsB;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
4
+ import { SimpleSpinner } from "./Spinner.js";
5
+ function StatusOverlayContent({
6
+ type,
7
+ message
8
+ }) {
9
+ switch (type) {
10
+ case "loading":
11
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.MIDDLE }, " ", message));
12
+ case "success":
13
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "\u2713", " ", message));
14
+ case "error":
15
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, "\u2717", " ", message));
16
+ }
17
+ }
18
+ export {
19
+ StatusOverlayContent
20
+ };
21
+ //# sourceMappingURL=StatusOverlayContent.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/components/StatusOverlayContent.tsx"],
4
+ "sourcesContent": ["/**\n * Shared StatusOverlayContent component\n *\n * Renders loading/success/error overlay content used by\n * TabbedListView, InfoPanel, and SimpleSelector.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { SimpleSpinner } from '@components/Spinner'\n\nexport type StatusOverlay = {\n type: 'loading' | 'success' | 'error'\n message: string\n}\n\nexport function StatusOverlayContent({\n type,\n message,\n}: {\n type: 'loading' | 'success' | 'error'\n message: string\n}) {\n switch (type) {\n case 'loading':\n return (\n <Box>\n <SimpleSpinner />\n <Text color={BRAND_GRADIENT.MIDDLE}> {message}</Text>\n </Box>\n )\n case 'success':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.success}>\n {'\\u2713'} {message}\n </Text>\n </Box>\n )\n case 'error':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.error}>\n {'\\u2717'} {message}\n </Text>\n </Box>\n )\n }\n}\n"],
5
+ "mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAChD,SAAS,qBAAqB;AAOvB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AACF,GAGG;AACD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,mBAAc,GACf,oCAAC,QAAK,OAAO,eAAe,UAAQ,KAAE,OAAQ,CAChD;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,WAC1B,UAAS,KAAE,OACd,CACF;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,SAC1B,UAAS,KAAE,OACd,CACF;AAAA,EAEN;AACF;",
6
+ "names": []
7
+ }
@@ -17,11 +17,26 @@ const getStatusIcon = (status) => {
17
17
  };
18
18
  function DefaultItemRenderer({
19
19
  item,
20
- isFocused
20
+ isFocused,
21
+ multiSelect,
22
+ isSelected
21
23
  }) {
22
24
  const statusInfo = getStatusIcon(item.status);
23
- const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim;
24
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: isFocused ? BRAND_GRADIENT.START : void 0 }, isFocused ? "\u25C6 " : " "), statusInfo && /* @__PURE__ */ React.createElement(Text, { color: statusInfo.color }, statusInfo.icon, " "), /* @__PURE__ */ React.createElement(Text, { color: textColor }, item.label, item.description && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " ", item.description), item.metadata && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " \xB7 ", item.metadata)));
25
+ const checkboxWidth = multiSelect ? 2 : 0;
26
+ const focusWidth = 2;
27
+ const statusWidth = statusInfo ? 2 : 0;
28
+ const prefixPad = checkboxWidth + focusWidth + statusWidth;
29
+ const labelColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.secondary;
30
+ const descColor = SEMANTIC_COLORS.dim;
31
+ const metaColor = SEMANTIC_COLORS.muted;
32
+ const hasDescription = !!item.description;
33
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, multiSelect && /* @__PURE__ */ React.createElement(
34
+ Text,
35
+ {
36
+ color: isSelected ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.dim
37
+ },
38
+ isSelected ? "\u2611 " : "\u2610 "
39
+ ), /* @__PURE__ */ React.createElement(Text, { color: isFocused ? BRAND_GRADIENT.START : void 0 }, isFocused ? "\u25C6 " : " "), statusInfo && /* @__PURE__ */ React.createElement(Text, { color: statusInfo.color }, statusInfo.icon, " "), /* @__PURE__ */ React.createElement(Text, { bold: isFocused, color: labelColor }, item.label), item.metadata && /* @__PURE__ */ React.createElement(Text, { color: metaColor }, " \xB7 ", item.metadata)), hasDescription && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: descColor }, " ".repeat(prefixPad), item.description)));
25
40
  }
26
41
  function ScrollableList({
27
42
  items,
@@ -30,7 +45,9 @@ function ScrollableList({
30
45
  onSelect,
31
46
  visibleCount,
32
47
  groupByCategory = false,
33
- renderItem
48
+ renderItem,
49
+ multiSelect,
50
+ selectedIds
34
51
  }) {
35
52
  const { visibleItems, startIndex, endIndex } = useMemo(() => {
36
53
  if (items.length === 0) {
@@ -80,7 +97,16 @@ function ScrollableList({
80
97
  );
81
98
  }
82
99
  const isFocused = globalIndex === focusedIndex;
83
- const itemElement = renderItem ? renderItem(item, isFocused) : /* @__PURE__ */ React.createElement(DefaultItemRenderer, { item, isFocused });
100
+ const isSelected = selectedIds?.has(item.id) ?? false;
101
+ const itemElement = renderItem ? renderItem(item, isFocused, isSelected) : /* @__PURE__ */ React.createElement(
102
+ DefaultItemRenderer,
103
+ {
104
+ item,
105
+ isFocused,
106
+ multiSelect,
107
+ isSelected
108
+ }
109
+ );
84
110
  displayElements.push(/* @__PURE__ */ React.createElement(Box, { key: item.id }, itemElement));
85
111
  });
86
112
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, hasMoreAbove && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \u2191 ", countAbove, " more above...")), displayElements, hasMoreBelow && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \u2193 ", countBelow, " more below...")));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/TabbedListView/ScrollableList.tsx"],
4
- "sourcesContent": ["/**\n * ScrollableList Component\n *\n * A scrollable list matching the /command suggestion UI pattern.\n * Uses \u25C6 indicator for selection, brand colors, and scroll indicators.\n */\n\nimport React, { useMemo } from 'react'\nimport { Box, Text } from 'ink'\nimport { SEMANTIC_COLORS, BRAND_GRADIENT } from '@constants/colors'\nimport { t } from '@i18n'\nimport type { ListItem, ScrollableListProps, CategoryGroup } from './types'\n\n/** Status icon mapping */\nconst getStatusIcon = (status?: ListItem['status']) => {\n switch (status) {\n case 'enabled':\n return { icon: '\u2714', color: SEMANTIC_COLORS.success }\n case 'disabled':\n return { icon: '\u25CB', color: SEMANTIC_COLORS.dim }\n case 'running':\n return { icon: '\u25D0', color: SEMANTIC_COLORS.running }\n case 'error':\n return { icon: '\u2717', color: SEMANTIC_COLORS.error }\n default:\n return null\n }\n}\n\n/** Default item renderer - matches command suggestion style */\nfunction DefaultItemRenderer({\n item,\n isFocused,\n}: {\n item: ListItem\n isFocused: boolean\n}) {\n const statusInfo = getStatusIcon(item.status)\n\n // Use brand gradient color for selection, dim for others\n const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n\n return (\n <Box flexDirection=\"row\">\n {/* Selection indicator: \u25C6 for selected, 2 spaces for unselected */}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\u25C6 ' : ' '}\n </Text>\n\n {/* Status icon if present */}\n {statusInfo && <Text color={statusInfo.color}>{statusInfo.icon} </Text>}\n\n {/* Main content */}\n <Text color={textColor}>\n {item.label}\n {item.description && (\n <Text color={SEMANTIC_COLORS.muted}> {item.description}</Text>\n )}\n {item.metadata && (\n <Text color={SEMANTIC_COLORS.muted}> \u00B7 {item.metadata}</Text>\n )}\n </Text>\n </Box>\n )\n}\n\nexport function ScrollableList({\n items,\n focusedIndex,\n onFocusChange,\n onSelect,\n visibleCount,\n groupByCategory = false,\n renderItem,\n}: ScrollableListProps) {\n // Calculate scroll window to keep selected item visible (same logic as command suggestions)\n const { visibleItems, startIndex, endIndex } = useMemo(() => {\n if (items.length === 0) {\n return { visibleItems: [], startIndex: 0, endIndex: 0 }\n }\n\n // If all items fit in window, show them all\n if (items.length <= visibleCount) {\n return {\n visibleItems: items.map((item, i) => ({ item, globalIndex: i })),\n startIndex: 0,\n endIndex: items.length,\n }\n }\n\n // Calculate scroll window to keep focused item visible\n const halfWindow = Math.floor(visibleCount / 2)\n let start = Math.max(0, focusedIndex - halfWindow)\n let end = start + visibleCount\n\n // Adjust if we're near the end\n if (end > items.length) {\n end = items.length\n start = Math.max(0, end - visibleCount)\n }\n\n return {\n visibleItems: items.slice(start, end).map((item, i) => ({\n item,\n globalIndex: start + i,\n })),\n startIndex: start,\n endIndex: end,\n }\n }, [items, focusedIndex, visibleCount])\n\n // Scroll indicators\n const hasMoreAbove = startIndex > 0\n const hasMoreBelow = endIndex < items.length\n const countAbove = startIndex\n const countBelow = items.length - endIndex\n\n // Build display with optional category headers\n const displayElements: React.ReactNode[] = []\n let currentCategory = ''\n\n visibleItems.forEach(({ item, globalIndex }, visibleIndex) => {\n // Add category header if category changed and grouping is enabled\n if (groupByCategory && item.category !== currentCategory) {\n currentCategory = item.category || 'Other'\n displayElements.push(\n <Box\n key={`category-${currentCategory}-${globalIndex}`}\n marginTop={visibleIndex > 0 ? 1 : 0}\n >\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {currentCategory}\n </Text>\n </Box>,\n )\n }\n\n const isFocused = globalIndex === focusedIndex\n const itemElement = renderItem ? (\n renderItem(item, isFocused)\n ) : (\n <DefaultItemRenderer item={item} isFocused={isFocused} />\n )\n\n displayElements.push(<Box key={item.id}>{itemElement}</Box>)\n })\n\n return (\n <Box flexDirection=\"column\">\n {/* Scroll up indicator */}\n {hasMoreAbove && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2191 {countAbove} more above...</Text>\n </Box>\n )}\n\n {/* List items */}\n {displayElements}\n\n {/* Scroll down indicator */}\n {hasMoreBelow && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2193 {countBelow} more below...</Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * ScrollableList Component\n *\n * A scrollable list matching the /command suggestion UI pattern.\n * Uses \u25C6 indicator for selection, brand colors, and scroll indicators.\n */\n\nimport React, { useMemo } from 'react'\nimport { Box, Text } from 'ink'\nimport { SEMANTIC_COLORS, BRAND_GRADIENT } from '@constants/colors'\nimport { t } from '@i18n'\nimport type { ListItem, ScrollableListProps, CategoryGroup } from './types'\n\n/** Status icon mapping */\nconst getStatusIcon = (status?: ListItem['status']) => {\n switch (status) {\n case 'enabled':\n return { icon: '\u2714', color: SEMANTIC_COLORS.success }\n case 'disabled':\n return { icon: '\u25CB', color: SEMANTIC_COLORS.dim }\n case 'running':\n return { icon: '\u25D0', color: SEMANTIC_COLORS.running }\n case 'error':\n return { icon: '\u2717', color: SEMANTIC_COLORS.error }\n default:\n return null\n }\n}\n\n/** Default item renderer - two-line layout with clear visual hierarchy */\nfunction DefaultItemRenderer({\n item,\n isFocused,\n multiSelect,\n isSelected,\n}: {\n item: ListItem\n isFocused: boolean\n multiSelect?: boolean\n isSelected?: boolean\n}) {\n const statusInfo = getStatusIcon(item.status)\n\n // Prefix width: checkbox \"\u2611 \" (2) + \"\u25C6 \" (2) + optional status icon \"\u2714 \" (2)\n const checkboxWidth = multiSelect ? 2 : 0\n const focusWidth = 2\n const statusWidth = statusInfo ? 2 : 0\n const prefixPad = checkboxWidth + focusWidth + statusWidth\n\n // Colors: focused items use brand gradient, unfocused use secondary/dim\n const labelColor = isFocused\n ? BRAND_GRADIENT.START\n : SEMANTIC_COLORS.secondary\n const descColor = SEMANTIC_COLORS.dim\n const metaColor = SEMANTIC_COLORS.muted\n\n const hasDescription = !!item.description\n\n return (\n <Box flexDirection=\"column\">\n {/* Line 1: [checkbox] + indicator + status + label + metadata */}\n <Box flexDirection=\"row\">\n {multiSelect && (\n <Text\n color={isSelected ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.dim}\n >\n {isSelected ? '\u2611 ' : '\u2610 '}\n </Text>\n )}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\u25C6 ' : ' '}\n </Text>\n {statusInfo && <Text color={statusInfo.color}>{statusInfo.icon} </Text>}\n <Text bold={isFocused} color={labelColor}>\n {item.label}\n </Text>\n {item.metadata && <Text color={metaColor}> \u00B7 {item.metadata}</Text>}\n </Box>\n\n {/* Line 2: description (indented to align under label) */}\n {hasDescription && (\n <Box>\n <Text color={descColor}>\n {' '.repeat(prefixPad)}\n {item.description}\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\nexport function ScrollableList({\n items,\n focusedIndex,\n onFocusChange,\n onSelect,\n visibleCount,\n groupByCategory = false,\n renderItem,\n multiSelect,\n selectedIds,\n}: ScrollableListProps) {\n // Calculate scroll window to keep selected item visible (same logic as command suggestions)\n const { visibleItems, startIndex, endIndex } = useMemo(() => {\n if (items.length === 0) {\n return { visibleItems: [], startIndex: 0, endIndex: 0 }\n }\n\n // If all items fit in window, show them all\n if (items.length <= visibleCount) {\n return {\n visibleItems: items.map((item, i) => ({ item, globalIndex: i })),\n startIndex: 0,\n endIndex: items.length,\n }\n }\n\n // Calculate scroll window to keep focused item visible\n const halfWindow = Math.floor(visibleCount / 2)\n let start = Math.max(0, focusedIndex - halfWindow)\n let end = start + visibleCount\n\n // Adjust if we're near the end\n if (end > items.length) {\n end = items.length\n start = Math.max(0, end - visibleCount)\n }\n\n return {\n visibleItems: items.slice(start, end).map((item, i) => ({\n item,\n globalIndex: start + i,\n })),\n startIndex: start,\n endIndex: end,\n }\n }, [items, focusedIndex, visibleCount])\n\n // Scroll indicators\n const hasMoreAbove = startIndex > 0\n const hasMoreBelow = endIndex < items.length\n const countAbove = startIndex\n const countBelow = items.length - endIndex\n\n // Build display with optional category headers\n const displayElements: React.ReactNode[] = []\n let currentCategory = ''\n\n visibleItems.forEach(({ item, globalIndex }, visibleIndex) => {\n // Add category header if category changed and grouping is enabled\n if (groupByCategory && item.category !== currentCategory) {\n currentCategory = item.category || 'Other'\n displayElements.push(\n <Box\n key={`category-${currentCategory}-${globalIndex}`}\n marginTop={visibleIndex > 0 ? 1 : 0}\n >\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {currentCategory}\n </Text>\n </Box>,\n )\n }\n\n const isFocused = globalIndex === focusedIndex\n const isSelected = selectedIds?.has(item.id) ?? false\n const itemElement = renderItem ? (\n renderItem(item, isFocused, isSelected)\n ) : (\n <DefaultItemRenderer\n item={item}\n isFocused={isFocused}\n multiSelect={multiSelect}\n isSelected={isSelected}\n />\n )\n\n displayElements.push(<Box key={item.id}>{itemElement}</Box>)\n })\n\n return (\n <Box flexDirection=\"column\">\n {/* Scroll up indicator */}\n {hasMoreAbove && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2191 {countAbove} more above...</Text>\n </Box>\n )}\n\n {/* List items */}\n {displayElements}\n\n {/* Scroll down indicator */}\n {hasMoreBelow && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2193 {countBelow} more below...</Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,10 @@ import { TabBar } from "./TabBar.js";
5
5
  import { SearchInput } from "./SearchInput.js";
6
6
  import { ScrollableList } from "./ScrollableList.js";
7
7
  import { SimpleSpinner } from "../Spinner.js";
8
- const MAX_VISIBLE_ITEMS = 8;
8
+ import { StatusOverlayContent } from "../StatusOverlayContent.js";
9
+ import { useTerminalSize } from "../../hooks/useTerminalSize.js";
10
+ const PROMPT_HEIGHT = 5;
11
+ const CHROME_HEIGHT = 6;
9
12
  function TabbedListView({
10
13
  title,
11
14
  tabs,
@@ -16,15 +19,31 @@ function TabbedListView({
16
19
  searchPlaceholder = "Search...",
17
20
  searchQuery = "",
18
21
  onSearchChange,
22
+ onSearchSubmit,
19
23
  onSelect,
20
24
  onClose,
25
+ onBack,
21
26
  footerHint,
22
27
  isLoading = false,
23
28
  loadingText = "Loading...",
24
29
  emptyText = "No items found",
25
30
  groupByCategory = false,
26
- renderItem
31
+ renderItem,
32
+ statusOverlay,
33
+ isActive = true,
34
+ showItemCount = true,
35
+ statusDismissHint,
36
+ multiSelect,
37
+ selectedIds,
38
+ onSelectionChange,
39
+ onMultiSelect,
40
+ multiSelectActionLabel
27
41
  }) {
42
+ const { rows } = useTerminalSize();
43
+ const visibleCount = Math.min(
44
+ 8,
45
+ Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT)
46
+ );
28
47
  const [focusArea, setFocusArea] = useState(
29
48
  searchEnabled ? "search" : "list"
30
49
  );
@@ -60,57 +79,105 @@ function TabbedListView({
60
79
  },
61
80
  [onSelect]
62
81
  );
63
- useInput((input, key) => {
64
- if (key.escape) {
65
- onClose();
66
- return;
67
- }
68
- if (key.tab) {
69
- cycleTab(key.shift ? "left" : "right");
70
- return;
71
- }
72
- if (focusArea === "tabs" || focusArea === "search") {
73
- if (key.leftArrow) {
74
- cycleTab("left");
82
+ useInput(
83
+ (input, key) => {
84
+ if (statusOverlay && statusOverlay.type !== "loading") {
85
+ if (key.escape || key.return) {
86
+ onClose();
87
+ }
75
88
  return;
76
89
  }
77
- if (key.rightArrow) {
78
- cycleTab("right");
90
+ if (statusOverlay) return;
91
+ if (key.escape) {
92
+ if (onBack) {
93
+ onBack();
94
+ } else {
95
+ onClose();
96
+ }
79
97
  return;
80
98
  }
81
- }
82
- if (key.downArrow) {
83
- if (focusArea === "search") {
84
- setFocusArea("list");
99
+ if (key.tab) {
100
+ cycleTab(key.shift ? "left" : "right");
85
101
  return;
86
102
  }
87
- if (focusArea === "list" && filteredItems.length > 0) {
88
- setFocusedIndex(
89
- (prev) => prev < filteredItems.length - 1 ? prev + 1 : prev
90
- );
103
+ if (focusArea === "tabs" || focusArea === "search") {
104
+ if (key.leftArrow) {
105
+ cycleTab("left");
106
+ return;
107
+ }
108
+ if (key.rightArrow) {
109
+ cycleTab("right");
110
+ return;
111
+ }
112
+ }
113
+ if (key.downArrow) {
114
+ if (focusArea === "search") {
115
+ setFocusArea("list");
116
+ return;
117
+ }
118
+ if (focusArea === "list" && filteredItems.length > 0) {
119
+ setFocusedIndex(
120
+ (prev) => prev < filteredItems.length - 1 ? prev + 1 : prev
121
+ );
122
+ return;
123
+ }
124
+ }
125
+ if (key.upArrow) {
126
+ if (focusArea === "list") {
127
+ if (focusedIndex > 0) {
128
+ setFocusedIndex((prev) => prev - 1);
129
+ } else if (searchEnabled) {
130
+ setFocusArea("search");
131
+ }
132
+ return;
133
+ }
134
+ }
135
+ if (key.return && focusArea === "search" && onSearchSubmit) {
136
+ onSearchSubmit(searchQuery);
91
137
  return;
92
138
  }
93
- }
94
- if (key.upArrow) {
95
- if (focusArea === "list") {
96
- if (focusedIndex > 0) {
97
- setFocusedIndex((prev) => prev - 1);
98
- } else if (searchEnabled) {
99
- setFocusArea("search");
139
+ if (input === " " && multiSelect && focusArea === "list" && filteredItems.length > 0) {
140
+ const item = filteredItems[focusedIndex];
141
+ if (item && onSelectionChange) {
142
+ const isCurrentlySelected = selectedIds?.has(item.id) ?? false;
143
+ onSelectionChange(item.id, !isCurrentlySelected);
100
144
  }
101
145
  return;
102
146
  }
103
- }
104
- if (key.return && focusArea === "list" && filteredItems.length > 0) {
105
- handleSelect(filteredItems[focusedIndex]);
106
- return;
107
- }
108
- if (input === "/" && searchEnabled && focusArea !== "search") {
109
- setFocusArea("search");
110
- return;
111
- }
112
- });
147
+ if (input === "a" && multiSelect && focusArea === "list" && filteredItems.length > 0) {
148
+ if (onSelectionChange) {
149
+ const allSelected = filteredItems.every(
150
+ (item) => selectedIds?.has(item.id)
151
+ );
152
+ for (const item of filteredItems) {
153
+ onSelectionChange(item.id, !allSelected);
154
+ }
155
+ }
156
+ return;
157
+ }
158
+ if (key.return && focusArea === "list" && filteredItems.length > 0) {
159
+ if (multiSelect && selectedIds && selectedIds.size > 0 && onMultiSelect) {
160
+ const selectedItems = filteredItems.filter(
161
+ (item) => selectedIds.has(item.id)
162
+ );
163
+ if (selectedItems.length > 0) {
164
+ onMultiSelect(selectedItems);
165
+ return;
166
+ }
167
+ }
168
+ handleSelect(filteredItems[focusedIndex]);
169
+ return;
170
+ }
171
+ if (input === "/" && searchEnabled && focusArea !== "search") {
172
+ setFocusArea("search");
173
+ return;
174
+ }
175
+ },
176
+ { isActive }
177
+ );
113
178
  const defaultHint = "\u2191\u2193 Navigate \xB7 Enter Select \xB7 Tab/\u2190\u2192 Switch \xB7 Esc Close";
179
+ const multiSelectHint = "\u2191\u2193 Navigate \xB7 Space Select \xB7 a All \xB7 Enter Action \xB7 Tab Switch \xB7 Esc Close";
180
+ const displayHint = statusOverlay ? statusOverlay.type === "loading" ? "" : statusDismissHint || "Esc Close" : multiSelect ? selectedIds && selectedIds.size > 0 && multiSelectActionLabel ? `${multiSelectActionLabel} \xB7 ${footerHint || multiSelectHint}` : footerHint || multiSelectHint : footerHint || defaultHint;
114
181
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React.createElement(
115
182
  Box,
116
183
  {
@@ -124,7 +191,7 @@ function TabbedListView({
124
191
  paddingX: 1,
125
192
  flexDirection: "column"
126
193
  },
127
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), filteredItems.length > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", filteredItems.length, ")")),
194
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), showItemCount && !statusOverlay && filteredItems.length > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", filteredItems.length, ")")),
128
195
  /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(TabBar, { tabs, activeTab, onTabChange }))
129
196
  ), /* @__PURE__ */ React.createElement(
130
197
  Box,
@@ -140,7 +207,7 @@ function TabbedListView({
140
207
  paddingX: 1,
141
208
  paddingY: 1
142
209
  },
143
- searchEnabled && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(
210
+ searchEnabled && !statusOverlay && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(
144
211
  SearchInput,
145
212
  {
146
213
  value: searchQuery,
@@ -150,19 +217,27 @@ function TabbedListView({
150
217
  isActive: focusArea === "search"
151
218
  }
152
219
  )),
153
- /* @__PURE__ */ React.createElement(Box, { key: `content-${activeTab}`, flexDirection: "column" }, isLoading ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", loadingText)) : filteredItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, emptyText)) : /* @__PURE__ */ React.createElement(
220
+ /* @__PURE__ */ React.createElement(Box, { key: `content-${activeTab}`, flexDirection: "column" }, statusOverlay ? /* @__PURE__ */ React.createElement(
221
+ StatusOverlayContent,
222
+ {
223
+ type: statusOverlay.type,
224
+ message: statusOverlay.message
225
+ }
226
+ ) : isLoading ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", loadingText)) : filteredItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, emptyText)) : /* @__PURE__ */ React.createElement(
154
227
  ScrollableList,
155
228
  {
156
229
  items: filteredItems,
157
230
  focusedIndex,
158
231
  onFocusChange: setFocusedIndex,
159
232
  onSelect: handleSelect,
160
- visibleCount: MAX_VISIBLE_ITEMS,
233
+ visibleCount,
161
234
  groupByCategory,
162
- renderItem
235
+ renderItem,
236
+ multiSelect,
237
+ selectedIds
163
238
  }
164
239
  )),
165
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, footerHint || defaultHint))
240
+ displayHint && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, displayHint))
166
241
  ));
167
242
  }
168
243
  export {