@nex-ai/nex 0.1.21 → 0.1.23
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/README.md +11 -2
- package/dist/agent/adoption.d.ts +23 -0
- package/dist/agent/adoption.js +87 -0
- package/dist/agent/adoption.js.map +1 -0
- package/dist/agent/gossip.d.ts +17 -0
- package/dist/agent/gossip.js +48 -0
- package/dist/agent/gossip.js.map +1 -0
- package/dist/agent/loop.d.ts +59 -0
- package/dist/agent/loop.js +389 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/queues.d.ts +16 -0
- package/dist/agent/queues.js +44 -0
- package/dist/agent/queues.js.map +1 -0
- package/dist/agent/session-store.d.ts +21 -0
- package/dist/agent/session-store.js +96 -0
- package/dist/agent/session-store.js.map +1 -0
- package/dist/agent/templates.d.ts +5 -0
- package/dist/agent/templates.js +48 -0
- package/dist/agent/templates.js.map +1 -0
- package/dist/agent/tools.d.ts +25 -0
- package/dist/agent/tools.js +238 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/agent/types.d.ts +59 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/calendar/scheduler.d.ts +32 -0
- package/dist/calendar/scheduler.js +178 -0
- package/dist/calendar/scheduler.js.map +1 -0
- package/dist/calendar/store.d.ts +15 -0
- package/dist/calendar/store.js +50 -0
- package/dist/calendar/store.js.map +1 -0
- package/dist/calendar/types.d.ts +17 -0
- package/dist/calendar/types.js +5 -0
- package/dist/calendar/types.js.map +1 -0
- package/dist/chat/channel.d.ts +20 -0
- package/dist/chat/channel.js +84 -0
- package/dist/chat/channel.js.map +1 -0
- package/dist/chat/message-store.d.ts +18 -0
- package/dist/chat/message-store.js +82 -0
- package/dist/chat/message-store.js.map +1 -0
- package/dist/chat/router.d.ts +17 -0
- package/dist/chat/router.js +65 -0
- package/dist/chat/router.js.map +1 -0
- package/dist/chat/suggested-responses.d.ts +6 -0
- package/dist/chat/suggested-responses.js +99 -0
- package/dist/chat/suggested-responses.js.map +1 -0
- package/dist/chat/types.d.ts +28 -0
- package/dist/chat/types.js +5 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/dispatch.d.ts +39 -0
- package/dist/commands/dispatch.js +1293 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/init.d.ts +49 -0
- package/dist/commands/init.js +315 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/parse-input.d.ts +5 -0
- package/dist/commands/parse-input.js +37 -0
- package/dist/commands/parse-input.js.map +1 -0
- package/dist/index.d.ts +6 -23
- package/dist/index.js +118 -50
- package/dist/index.js.map +1 -1
- package/dist/lib/client.js +1 -1
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/errors.js +1 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/graph-html.d.ts +1 -0
- package/dist/lib/graph-html.js +16 -3
- package/dist/lib/graph-html.js.map +1 -1
- package/dist/lib/integrations.d.ts +23 -0
- package/dist/lib/integrations.js +25 -0
- package/dist/lib/integrations.js.map +1 -0
- package/dist/lib/nex-mcp-config.d.ts +14 -0
- package/dist/lib/nex-mcp-config.js +26 -0
- package/dist/lib/nex-mcp-config.js.map +1 -0
- package/dist/orchestration/budget.d.ts +32 -0
- package/dist/orchestration/budget.js +72 -0
- package/dist/orchestration/budget.js.map +1 -0
- package/dist/orchestration/executor.d.ts +59 -0
- package/dist/orchestration/executor.js +197 -0
- package/dist/orchestration/executor.js.map +1 -0
- package/dist/orchestration/router.d.ts +30 -0
- package/dist/orchestration/router.js +98 -0
- package/dist/orchestration/router.js.map +1 -0
- package/dist/orchestration/templates.d.ts +11 -0
- package/dist/orchestration/templates.js +99 -0
- package/dist/orchestration/templates.js.map +1 -0
- package/dist/orchestration/types.d.ts +58 -0
- package/dist/orchestration/types.js +7 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/plugin/shared.js +1 -1
- package/dist/plugin/shared.js.map +1 -1
- package/dist/tui/agent-colors.d.ts +19 -0
- package/dist/tui/agent-colors.js +34 -0
- package/dist/tui/agent-colors.js.map +1 -0
- package/dist/tui/app.d.ts +14 -0
- package/dist/tui/app.js +267 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/channel-colors.d.ts +16 -0
- package/dist/tui/channel-colors.js +43 -0
- package/dist/tui/channel-colors.js.map +1 -0
- package/dist/tui/components/agent-card.d.ts +11 -0
- package/dist/tui/components/agent-card.js +40 -0
- package/dist/tui/components/agent-card.js.map +1 -0
- package/dist/tui/components/banner.d.ts +44 -0
- package/dist/tui/components/banner.js +130 -0
- package/dist/tui/components/banner.js.map +1 -0
- package/dist/tui/components/channel-colors.d.ts +21 -0
- package/dist/tui/components/channel-colors.js +53 -0
- package/dist/tui/components/channel-colors.js.map +1 -0
- package/dist/tui/components/channel-message.d.ts +53 -0
- package/dist/tui/components/channel-message.js +66 -0
- package/dist/tui/components/channel-message.js.map +1 -0
- package/dist/tui/components/chat-input.d.ts +11 -0
- package/dist/tui/components/chat-input.js +19 -0
- package/dist/tui/components/chat-input.js.map +1 -0
- package/dist/tui/components/data-table.d.ts +11 -0
- package/dist/tui/components/data-table.js +47 -0
- package/dist/tui/components/data-table.js.map +1 -0
- package/dist/tui/components/error-box.d.ts +11 -0
- package/dist/tui/components/error-box.js +59 -0
- package/dist/tui/components/error-box.js.map +1 -0
- package/dist/tui/components/help-screen.d.ts +3 -0
- package/dist/tui/components/help-screen.js +63 -0
- package/dist/tui/components/help-screen.js.map +1 -0
- package/dist/tui/components/index.d.ts +17 -0
- package/dist/tui/components/index.js +10 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/components/inline-confirm.d.ts +14 -0
- package/dist/tui/components/inline-confirm.js +13 -0
- package/dist/tui/components/inline-confirm.js.map +1 -0
- package/dist/tui/components/inline-select.d.ts +21 -0
- package/dist/tui/components/inline-select.js +20 -0
- package/dist/tui/components/inline-select.js.map +1 -0
- package/dist/tui/components/markdown.d.ts +6 -0
- package/dist/tui/components/markdown.js +179 -0
- package/dist/tui/components/markdown.js.map +1 -0
- package/dist/tui/components/mention-autocomplete.d.ts +77 -0
- package/dist/tui/components/mention-autocomplete.js +235 -0
- package/dist/tui/components/mention-autocomplete.js.map +1 -0
- package/dist/tui/components/message-list.d.ts +18 -0
- package/dist/tui/components/message-list.js +29 -0
- package/dist/tui/components/message-list.js.map +1 -0
- package/dist/tui/components/picker.d.ts +16 -0
- package/dist/tui/components/picker.js +32 -0
- package/dist/tui/components/picker.js.map +1 -0
- package/dist/tui/components/progress-steps.d.ts +13 -0
- package/dist/tui/components/progress-steps.js +21 -0
- package/dist/tui/components/progress-steps.js.map +1 -0
- package/dist/tui/components/slack/compose.d.ts +27 -0
- package/dist/tui/components/slack/compose.js +123 -0
- package/dist/tui/components/slack/compose.js.map +1 -0
- package/dist/tui/components/slack/layout.d.ts +36 -0
- package/dist/tui/components/slack/layout.js +96 -0
- package/dist/tui/components/slack/layout.js.map +1 -0
- package/dist/tui/components/slack/messages.d.ts +72 -0
- package/dist/tui/components/slack/messages.js +177 -0
- package/dist/tui/components/slack/messages.js.map +1 -0
- package/dist/tui/components/slack/quick-switcher.d.ts +33 -0
- package/dist/tui/components/slack/quick-switcher.js +98 -0
- package/dist/tui/components/slack/quick-switcher.js.map +1 -0
- package/dist/tui/components/slack/sidebar-types.d.ts +65 -0
- package/dist/tui/components/slack/sidebar-types.js +7 -0
- package/dist/tui/components/slack/sidebar-types.js.map +1 -0
- package/dist/tui/components/slack/sidebar.d.ts +46 -0
- package/dist/tui/components/slack/sidebar.js +52 -0
- package/dist/tui/components/slack/sidebar.js.map +1 -0
- package/dist/tui/components/slack/thread-panel.d.ts +45 -0
- package/dist/tui/components/slack/thread-panel.js +47 -0
- package/dist/tui/components/slack/thread-panel.js.map +1 -0
- package/dist/tui/components/slash-autocomplete.d.ts +81 -0
- package/dist/tui/components/slash-autocomplete.js +218 -0
- package/dist/tui/components/slash-autocomplete.js.map +1 -0
- package/dist/tui/components/spinner.d.ts +17 -0
- package/dist/tui/components/spinner.js +30 -0
- package/dist/tui/components/spinner.js.map +1 -0
- package/dist/tui/components/status-bar.d.ts +23 -0
- package/dist/tui/components/status-bar.js +55 -0
- package/dist/tui/components/status-bar.js.map +1 -0
- package/dist/tui/components/success-box.d.ts +7 -0
- package/dist/tui/components/success-box.js +10 -0
- package/dist/tui/components/success-box.js.map +1 -0
- package/dist/tui/components/tool-indicator.d.ts +12 -0
- package/dist/tui/components/tool-indicator.js +18 -0
- package/dist/tui/components/tool-indicator.js.map +1 -0
- package/dist/tui/components/viewport.d.ts +9 -0
- package/dist/tui/components/viewport.js +24 -0
- package/dist/tui/components/viewport.js.map +1 -0
- package/dist/tui/generative/bindings.d.ts +27 -0
- package/dist/tui/generative/bindings.js +152 -0
- package/dist/tui/generative/bindings.js.map +1 -0
- package/dist/tui/generative/registry.d.ts +19 -0
- package/dist/tui/generative/registry.js +31 -0
- package/dist/tui/generative/registry.js.map +1 -0
- package/dist/tui/generative/renderer.d.ts +24 -0
- package/dist/tui/generative/renderer.js +160 -0
- package/dist/tui/generative/renderer.js.map +1 -0
- package/dist/tui/generative/types.d.ts +68 -0
- package/dist/tui/generative/types.js +7 -0
- package/dist/tui/generative/types.js.map +1 -0
- package/dist/tui/hooks/use-cancellable.d.ts +28 -0
- package/dist/tui/hooks/use-cancellable.js +51 -0
- package/dist/tui/hooks/use-cancellable.js.map +1 -0
- package/dist/tui/hooks/use-streaming.d.ts +44 -0
- package/dist/tui/hooks/use-streaming.js +105 -0
- package/dist/tui/hooks/use-streaming.js.map +1 -0
- package/dist/tui/index.d.ts +4 -0
- package/dist/tui/index.js +7 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/keybindings.d.ts +25 -0
- package/dist/tui/keybindings.js +277 -0
- package/dist/tui/keybindings.js.map +1 -0
- package/dist/tui/register-views.d.ts +8 -0
- package/dist/tui/register-views.js +116 -0
- package/dist/tui/register-views.js.map +1 -0
- package/dist/tui/router.d.ts +29 -0
- package/dist/tui/router.js +87 -0
- package/dist/tui/router.js.map +1 -0
- package/dist/tui/services/agent-service.d.ts +58 -0
- package/dist/tui/services/agent-service.js +197 -0
- package/dist/tui/services/agent-service.js.map +1 -0
- package/dist/tui/services/calendar-service.d.ts +31 -0
- package/dist/tui/services/calendar-service.js +133 -0
- package/dist/tui/services/calendar-service.js.map +1 -0
- package/dist/tui/services/chat-service.d.ts +28 -0
- package/dist/tui/services/chat-service.js +91 -0
- package/dist/tui/services/chat-service.js.map +1 -0
- package/dist/tui/services/orchestration-service.d.ts +42 -0
- package/dist/tui/services/orchestration-service.js +153 -0
- package/dist/tui/services/orchestration-service.js.map +1 -0
- package/dist/tui/slash-commands.d.ts +106 -0
- package/dist/tui/slash-commands.js +1421 -0
- package/dist/tui/slash-commands.js.map +1 -0
- package/dist/tui/store.d.ts +96 -0
- package/dist/tui/store.js +120 -0
- package/dist/tui/store.js.map +1 -0
- package/dist/tui/theme.d.ts +40 -0
- package/dist/tui/theme.js +39 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/tui-context.d.ts +22 -0
- package/dist/tui/tui-context.js +17 -0
- package/dist/tui/tui-context.js.map +1 -0
- package/dist/tui/views/agent-list.d.ts +8 -0
- package/dist/tui/views/agent-list.js +11 -0
- package/dist/tui/views/agent-list.js.map +1 -0
- package/dist/tui/views/ask-chat.d.ts +9 -0
- package/dist/tui/views/ask-chat.js +40 -0
- package/dist/tui/views/ask-chat.js.map +1 -0
- package/dist/tui/views/calendar.d.ts +15 -0
- package/dist/tui/views/calendar.js +29 -0
- package/dist/tui/views/calendar.js.map +1 -0
- package/dist/tui/views/chat.d.ts +18 -0
- package/dist/tui/views/chat.js +28 -0
- package/dist/tui/views/chat.js.map +1 -0
- package/dist/tui/views/generative.d.ts +14 -0
- package/dist/tui/views/generative.js +37 -0
- package/dist/tui/views/generative.js.map +1 -0
- package/dist/tui/views/help.d.ts +6 -0
- package/dist/tui/views/help.js +9 -0
- package/dist/tui/views/help.js.map +1 -0
- package/dist/tui/views/home-screen.d.ts +67 -0
- package/dist/tui/views/home-screen.js +192 -0
- package/dist/tui/views/home-screen.js.map +1 -0
- package/dist/tui/views/home.d.ts +33 -0
- package/dist/tui/views/home.js +60 -0
- package/dist/tui/views/home.js.map +1 -0
- package/dist/tui/views/index.d.ts +20 -0
- package/dist/tui/views/index.js +11 -0
- package/dist/tui/views/index.js.map +1 -0
- package/dist/tui/views/insights.d.ts +19 -0
- package/dist/tui/views/insights.js +46 -0
- package/dist/tui/views/insights.js.map +1 -0
- package/dist/tui/views/orchestration.d.ts +18 -0
- package/dist/tui/views/orchestration.js +73 -0
- package/dist/tui/views/orchestration.js.map +1 -0
- package/dist/tui/views/record-detail.d.ts +10 -0
- package/dist/tui/views/record-detail.js +22 -0
- package/dist/tui/views/record-detail.js.map +1 -0
- package/dist/tui/views/record-list.d.ts +15 -0
- package/dist/tui/views/record-list.js +22 -0
- package/dist/tui/views/record-list.js.map +1 -0
- package/dist/tui/views/slack-channel-header.d.ts +15 -0
- package/dist/tui/views/slack-channel-header.js +16 -0
- package/dist/tui/views/slack-channel-header.js.map +1 -0
- package/dist/tui/views/slack-home.d.ts +21 -0
- package/dist/tui/views/slack-home.js +572 -0
- package/dist/tui/views/slack-home.js.map +1 -0
- package/dist/tui/views/task-board.d.ts +21 -0
- package/dist/tui/views/task-board.js +33 -0
- package/dist/tui/views/task-board.js.map +1 -0
- package/dist/tui/views/timeline.d.ts +17 -0
- package/dist/tui/views/timeline.js +24 -0
- package/dist/tui/views/timeline.js.map +1 -0
- package/package.json +8 -3
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Quick Switcher (Ctrl+K) modal overlay.
|
|
4
|
+
*
|
|
5
|
+
* Provides fuzzy search across channels and DMs with frecency-based
|
|
6
|
+
* ranking. Renders as a centered overlay capturing all keyboard input.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useState, useMemo, useCallback, useEffect } from "react";
|
|
9
|
+
import { Box, Text } from "ink";
|
|
10
|
+
import { TextInput } from "@inkjs/ui";
|
|
11
|
+
// ── Fuzzy match ─────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* Case-insensitive substring match on name.
|
|
14
|
+
* Matches partial words and hyphen/underscore-separated tokens.
|
|
15
|
+
*/
|
|
16
|
+
export function fuzzyMatch(query, name) {
|
|
17
|
+
if (!query)
|
|
18
|
+
return true;
|
|
19
|
+
const q = query.toLowerCase();
|
|
20
|
+
const n = name.toLowerCase();
|
|
21
|
+
// Direct substring
|
|
22
|
+
if (n.includes(q))
|
|
23
|
+
return true;
|
|
24
|
+
// Token initials match (e.g. "fa" matches "Founding Agent")
|
|
25
|
+
const tokens = n.split(/[\s\-_]+/);
|
|
26
|
+
const initials = tokens.map((t) => t[0] || "").join("");
|
|
27
|
+
if (initials.includes(q))
|
|
28
|
+
return true;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Filter and sort items by fuzzy match + frecency score.
|
|
33
|
+
*/
|
|
34
|
+
export function filterItems(query, items) {
|
|
35
|
+
const matched = items.filter((item) => fuzzyMatch(query, item.name));
|
|
36
|
+
// Sort by score descending (frecency)
|
|
37
|
+
return matched.sort((a, b) => b.score - a.score);
|
|
38
|
+
}
|
|
39
|
+
// ── Item row ────────────────────────────────────────────────────────
|
|
40
|
+
function SwitcherItem({ item, isSelected, }) {
|
|
41
|
+
let prefix;
|
|
42
|
+
if (item.type === "channel") {
|
|
43
|
+
prefix = _jsx(Text, { color: "gray", children: "# " });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const dotColor = item.online ? "green" : "gray";
|
|
47
|
+
const dot = item.online ? "●" : "○";
|
|
48
|
+
prefix = _jsxs(Text, { color: dotColor, children: [dot, " "] });
|
|
49
|
+
}
|
|
50
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: isSelected ? "cyan" : undefined, bold: isSelected, children: isSelected ? "> " : " " }), prefix, _jsx(Text, { color: isSelected ? "cyan" : "white", bold: isSelected, children: item.name }), item.unread > 0 && _jsxs(Text, { color: "gray", children: [" (", item.unread, ")"] })] }));
|
|
51
|
+
}
|
|
52
|
+
// ── QuickSwitcher ───────────────────────────────────────────────────
|
|
53
|
+
export function QuickSwitcher({ open, items, onSelect, onClose, }) {
|
|
54
|
+
// All hooks must be called unconditionally before any early return
|
|
55
|
+
const [query, setQuery] = useState("");
|
|
56
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
57
|
+
const maxVisible = 10;
|
|
58
|
+
const filtered = useMemo(() => filterItems(query, items), [query, items]);
|
|
59
|
+
const visibleItems = filtered.slice(0, maxVisible);
|
|
60
|
+
// Reset state when switcher opens
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (open) {
|
|
63
|
+
setQuery("");
|
|
64
|
+
setSelectedIndex(0);
|
|
65
|
+
}
|
|
66
|
+
}, [open]);
|
|
67
|
+
const handleChange = useCallback((newQuery) => {
|
|
68
|
+
setQuery(newQuery);
|
|
69
|
+
setSelectedIndex(0);
|
|
70
|
+
}, []);
|
|
71
|
+
const handleSubmit = useCallback(() => {
|
|
72
|
+
if (filtered.length > 0 && selectedIndex < filtered.length) {
|
|
73
|
+
onSelect(filtered[selectedIndex].id);
|
|
74
|
+
}
|
|
75
|
+
}, [filtered, selectedIndex, onSelect]);
|
|
76
|
+
// Register globalThis bridge for arrow key navigation from app.tsx
|
|
77
|
+
const filteredLengthRef = React.useRef(filtered.length);
|
|
78
|
+
filteredLengthRef.current = filtered.length;
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!open)
|
|
81
|
+
return;
|
|
82
|
+
const g = globalThis;
|
|
83
|
+
g.__nexQuickSwitcherNav = (direction) => {
|
|
84
|
+
setSelectedIndex((prev) => {
|
|
85
|
+
const len = Math.min(filteredLengthRef.current, maxVisible);
|
|
86
|
+
if (len === 0)
|
|
87
|
+
return 0;
|
|
88
|
+
return ((prev + direction) % len + len) % len;
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
return () => { delete g.__nexQuickSwitcherNav; };
|
|
92
|
+
}, [open]);
|
|
93
|
+
if (!open)
|
|
94
|
+
return null;
|
|
95
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", paddingX: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "cyan", children: "Switch to..." }) }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "\uD83D\uDD0D " }), _jsx(TextInput, { placeholder: "Search channels and DMs", onChange: handleChange, onSubmit: handleSubmit })] }), _jsx(Box, { children: _jsx(Text, { color: "gray", children: "─".repeat(40) }) }), _jsxs(Box, { flexDirection: "column", children: [visibleItems.length === 0 && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "gray", children: "No matches found" }) })), visibleItems.map((item, idx) => (_jsx(SwitcherItem, { item: item, isSelected: idx === selectedIndex }, item.id)))] }), _jsx(Box, { children: _jsx(Text, { color: "gray", children: "\u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc close" }) })] }));
|
|
96
|
+
}
|
|
97
|
+
export default QuickSwitcher;
|
|
98
|
+
//# sourceMappingURL=quick-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quick-switcher.js","sourceRoot":"","sources":["../../../../src/tui/components/slack/quick-switcher.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Slack sidebar components.
|
|
3
|
+
*
|
|
4
|
+
* Matches the interfaces defined in docs/slack-tui-architecture.md §2.3.
|
|
5
|
+
*/
|
|
6
|
+
/** A sidebar item (channel or DM). */
|
|
7
|
+
export interface SidebarItemData {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
type: "channel" | "dm" | "group-dm";
|
|
11
|
+
/** For channels: public or private */
|
|
12
|
+
visibility?: "public" | "private";
|
|
13
|
+
/** For DMs: the agent/user slugs */
|
|
14
|
+
members?: string[];
|
|
15
|
+
/** Online status (DMs only) */
|
|
16
|
+
online?: boolean;
|
|
17
|
+
/** Unread message count */
|
|
18
|
+
unread: number;
|
|
19
|
+
/** Has @mention in unread */
|
|
20
|
+
hasMention: boolean;
|
|
21
|
+
/** Muted by user */
|
|
22
|
+
muted: boolean;
|
|
23
|
+
/** Last message timestamp for frecency sort */
|
|
24
|
+
lastActivity: number;
|
|
25
|
+
}
|
|
26
|
+
/** Section grouping for the sidebar. */
|
|
27
|
+
export interface SidebarSectionData {
|
|
28
|
+
title: string;
|
|
29
|
+
items: SidebarItemData[];
|
|
30
|
+
}
|
|
31
|
+
/** Props for the root SlackSidebar component. */
|
|
32
|
+
export interface SidebarProps {
|
|
33
|
+
width: number;
|
|
34
|
+
focused: boolean;
|
|
35
|
+
workspaceName: string;
|
|
36
|
+
sections: SidebarSectionData[];
|
|
37
|
+
collapsedSections: string[];
|
|
38
|
+
activeChannelId: string;
|
|
39
|
+
cursor: number;
|
|
40
|
+
onToggleSection: (title: string) => void;
|
|
41
|
+
onSelectItem: (id: string) => void;
|
|
42
|
+
}
|
|
43
|
+
/** Props for SidebarSection. */
|
|
44
|
+
export interface SidebarSectionProps {
|
|
45
|
+
title: string;
|
|
46
|
+
collapsed: boolean;
|
|
47
|
+
items: SidebarItemData[];
|
|
48
|
+
activeChannelId: string;
|
|
49
|
+
/** Index of cursor within the flattened sidebar list */
|
|
50
|
+
cursorIndex: number;
|
|
51
|
+
/** Starting index of this section in the flat list */
|
|
52
|
+
startIndex: number;
|
|
53
|
+
onToggle: () => void;
|
|
54
|
+
onSelect: (id: string) => void;
|
|
55
|
+
}
|
|
56
|
+
/** Props for SidebarItem. */
|
|
57
|
+
export interface SidebarItemProps {
|
|
58
|
+
item: SidebarItemData;
|
|
59
|
+
isActive: boolean;
|
|
60
|
+
isCursor: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** Props for WorkspaceHeader. */
|
|
63
|
+
export interface WorkspaceHeaderProps {
|
|
64
|
+
name: string;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar-types.js","sourceRoot":"","sources":["../../../../src/tui/components/slack/sidebar-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack-style sidebar component.
|
|
3
|
+
*
|
|
4
|
+
* Contains workspace header, collapsible DM/channel sections,
|
|
5
|
+
* and individual sidebar items with online status, unread badges,
|
|
6
|
+
* and active/cursor indicators.
|
|
7
|
+
*/
|
|
8
|
+
import React from "react";
|
|
9
|
+
import type { SidebarItemData } from "./sidebar-types.js";
|
|
10
|
+
export type { SidebarItemData, SidebarSectionData, SidebarProps, SidebarSectionProps, SidebarItemProps, WorkspaceHeaderProps, } from "./sidebar-types.js";
|
|
11
|
+
export interface WorkspaceHeaderComponentProps {
|
|
12
|
+
name: string;
|
|
13
|
+
width: number;
|
|
14
|
+
focused?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function WorkspaceHeader({ name, width, focused, }: WorkspaceHeaderComponentProps): React.JSX.Element;
|
|
17
|
+
export declare function SidebarItem({ item, isActive, isCursor, }: {
|
|
18
|
+
item: SidebarItemData;
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
isCursor: boolean;
|
|
21
|
+
}): React.JSX.Element;
|
|
22
|
+
export declare function SidebarSection({ title, collapsed, items, activeChannelId, cursorIndex, startIndex, onToggle, onSelect, }: {
|
|
23
|
+
title: string;
|
|
24
|
+
collapsed: boolean;
|
|
25
|
+
items: SidebarItemData[];
|
|
26
|
+
activeChannelId: string;
|
|
27
|
+
cursorIndex: number;
|
|
28
|
+
startIndex: number;
|
|
29
|
+
onToggle: () => void;
|
|
30
|
+
onSelect: (id: string) => void;
|
|
31
|
+
}): React.JSX.Element;
|
|
32
|
+
export declare function SlackSidebar({ width, focused, workspaceName, sections, collapsedSections, activeChannelId, cursor, onToggleSection, onSelectItem, }: {
|
|
33
|
+
width: number;
|
|
34
|
+
focused: boolean;
|
|
35
|
+
workspaceName: string;
|
|
36
|
+
sections: Array<{
|
|
37
|
+
title: string;
|
|
38
|
+
items: SidebarItemData[];
|
|
39
|
+
}>;
|
|
40
|
+
collapsedSections: string[];
|
|
41
|
+
activeChannelId: string;
|
|
42
|
+
cursor: number;
|
|
43
|
+
onToggleSection: (title: string) => void;
|
|
44
|
+
onSelectItem: (id: string) => void;
|
|
45
|
+
}): React.JSX.Element;
|
|
46
|
+
export default SlackSidebar;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export function WorkspaceHeader({ name, width, focused, }) {
|
|
4
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsxs(Box, { paddingLeft: 1, children: [focused && _jsx(Text, { color: "cyan", children: "◆ " }), _jsx(Text, { bold: true, color: focused ? "cyan" : "white", children: name })] }), _jsx(Box, { paddingLeft: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(Math.max(width - 2, 1)) }) })] }));
|
|
5
|
+
}
|
|
6
|
+
// ── SidebarItem ─────────────────────────────────────────────────────
|
|
7
|
+
export function SidebarItem({ item, isActive, isCursor, }) {
|
|
8
|
+
const isUnread = item.unread > 0;
|
|
9
|
+
const isBold = isActive || isUnread;
|
|
10
|
+
// Active indicator: ▎ left border for active item (spec §2.3)
|
|
11
|
+
const prefix = isActive ? "▎ " : " ";
|
|
12
|
+
// Build the status dot / hash prefix
|
|
13
|
+
let indicator;
|
|
14
|
+
if (item.type === "dm" || item.type === "group-dm") {
|
|
15
|
+
const dotColor = item.online ? "green" : "gray";
|
|
16
|
+
const dot = item.online ? "●" : "○";
|
|
17
|
+
indicator = _jsxs(Text, { color: dotColor, children: [dot, " "] });
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
indicator = _jsx(Text, { color: "gray", children: "# " });
|
|
21
|
+
}
|
|
22
|
+
// Name color: active=cyan, unread=white bold, normal=white, muted=gray
|
|
23
|
+
const nameColor = isActive ? "cyan" : item.muted ? "gray" : "white";
|
|
24
|
+
// Unread badge
|
|
25
|
+
const badge = item.unread > 0 ? (_jsxs(Text, { color: "white", dimColor: !isActive, children: [" ", "(", item.unread, ")"] })) : null;
|
|
26
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: isActive ? "cyan" : isCursor ? "white" : "gray", children: prefix }), indicator, _jsx(Text, { color: nameColor, bold: isBold, children: item.name }), badge] }));
|
|
27
|
+
}
|
|
28
|
+
// ── SidebarSection ──────────────────────────────────────────────────
|
|
29
|
+
export function SidebarSection({ title, collapsed, items, activeChannelId, cursorIndex, startIndex, onToggle, onSelect, }) {
|
|
30
|
+
const triangle = collapsed ? "▸" : "▾";
|
|
31
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "gray", children: [triangle, " ", title] }) }), !collapsed &&
|
|
32
|
+
items.map((item, idx) => {
|
|
33
|
+
const flatIdx = startIndex + idx;
|
|
34
|
+
return (_jsx(SidebarItem, { item: item, isActive: item.id === activeChannelId, isCursor: cursorIndex === flatIdx }, item.id));
|
|
35
|
+
})] }));
|
|
36
|
+
}
|
|
37
|
+
// ── SlackSidebar (root) ─────────────────────────────────────────────
|
|
38
|
+
export function SlackSidebar({ width, focused, workspaceName, sections, collapsedSections, activeChannelId, cursor, onToggleSection, onSelectItem, }) {
|
|
39
|
+
// Compute flat index offsets for each section
|
|
40
|
+
let runningIndex = 0;
|
|
41
|
+
const sectionOffsets = [];
|
|
42
|
+
for (const section of sections) {
|
|
43
|
+
sectionOffsets.push(runningIndex);
|
|
44
|
+
const isCollapsed = collapsedSections.includes(section.title);
|
|
45
|
+
if (!isCollapsed) {
|
|
46
|
+
runningIndex += section.items.length;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(WorkspaceHeader, { name: workspaceName, width: width, focused: focused }), _jsx(Box, { height: 1 }), sections.map((section, sIdx) => (_jsx(SidebarSection, { title: section.title, collapsed: collapsedSections.includes(section.title), items: section.items, activeChannelId: activeChannelId, cursorIndex: cursor, startIndex: sectionOffsets[sIdx], onToggle: () => onToggleSection(section.title), onSelect: onSelectItem }, section.title))), _jsx(Box, { height: 1 }), _jsxs(Box, { paddingLeft: 1, gap: 2, children: [_jsx(Text, { color: "gray", children: "[n] channel" }), _jsx(Text, { color: "gray", children: "[a] agent" })] })] }));
|
|
50
|
+
}
|
|
51
|
+
export default SlackSidebar;
|
|
52
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../../../../src/tui/components/slack/sidebar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack-style thread panel component.
|
|
3
|
+
*
|
|
4
|
+
* Right panel showing a parent message, reply count divider,
|
|
5
|
+
* thread replies, and a compose area for sending replies.
|
|
6
|
+
* Escape closes the panel.
|
|
7
|
+
*/
|
|
8
|
+
import React from "react";
|
|
9
|
+
import type { SlashCommandEntry } from "../slash-autocomplete.js";
|
|
10
|
+
import type { AgentEntry } from "../mention-autocomplete.js";
|
|
11
|
+
/** A message with grouping metadata (matches architecture spec). */
|
|
12
|
+
export interface ThreadMessage {
|
|
13
|
+
id: string;
|
|
14
|
+
sender: string;
|
|
15
|
+
senderType: "agent" | "human" | "system";
|
|
16
|
+
initials: string;
|
|
17
|
+
content: string;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
isFirstInGroup: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ThreadPanelProps {
|
|
22
|
+
width: number;
|
|
23
|
+
focused: boolean;
|
|
24
|
+
parentMessage: ThreadMessage;
|
|
25
|
+
replies: ThreadMessage[];
|
|
26
|
+
sourceChannelName: string;
|
|
27
|
+
sourceChannelType: "channel" | "dm" | "group-dm";
|
|
28
|
+
alsoSendToChannel: boolean;
|
|
29
|
+
onSendReply: (content: string) => void;
|
|
30
|
+
onToggleAlsoSend: () => void;
|
|
31
|
+
onClose: () => void;
|
|
32
|
+
slashCommands?: SlashCommandEntry[];
|
|
33
|
+
agents?: AgentEntry[];
|
|
34
|
+
}
|
|
35
|
+
export declare function ThreadHeader({ channelName, channelType, onClose, }: {
|
|
36
|
+
channelName: string;
|
|
37
|
+
channelType: "channel" | "dm" | "group-dm";
|
|
38
|
+
onClose: () => void;
|
|
39
|
+
}): React.JSX.Element;
|
|
40
|
+
export declare function ReplyDivider({ count, width, }: {
|
|
41
|
+
count: number;
|
|
42
|
+
width: number;
|
|
43
|
+
}): React.JSX.Element;
|
|
44
|
+
export declare function ThreadPanel({ width, focused, parentMessage, replies, sourceChannelName, sourceChannelType, alsoSendToChannel, onSendReply, onToggleAlsoSend, onClose, slashCommands, agents, }: ThreadPanelProps): React.JSX.Element;
|
|
45
|
+
export default ThreadPanel;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { ComposeArea } from "./compose.js";
|
|
4
|
+
import { getAgentColor } from "../../agent-colors.js";
|
|
5
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
6
|
+
function formatTime(ts) {
|
|
7
|
+
const d = new Date(ts);
|
|
8
|
+
const h = d.getHours();
|
|
9
|
+
const m = d.getMinutes().toString().padStart(2, "0");
|
|
10
|
+
const ampm = h >= 12 ? "PM" : "AM";
|
|
11
|
+
const hour = h % 12 || 12;
|
|
12
|
+
return `${hour}:${m} ${ampm}`;
|
|
13
|
+
}
|
|
14
|
+
// ── ThreadHeader ────────────────────────────────────────────────────
|
|
15
|
+
export function ThreadHeader({ channelName, channelType, onClose, }) {
|
|
16
|
+
const channelLabel = channelType === "channel" ? `#${channelName}` : channelName;
|
|
17
|
+
return (_jsxs(Box, { justifyContent: "space-between", paddingX: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, color: "white", children: "Thread" }), _jsx(Text, { color: "cyan", children: channelLabel })] }), _jsx(Text, { color: "gray", children: "\u2715 Esc" })] }));
|
|
18
|
+
}
|
|
19
|
+
// ── ReplyDivider ────────────────────────────────────────────────────
|
|
20
|
+
export function ReplyDivider({ count, width, }) {
|
|
21
|
+
const label = `${count} ${count === 1 ? "reply" : "replies"}`;
|
|
22
|
+
const pad = Math.max(Math.floor((width - label.length - 4) / 2), 1);
|
|
23
|
+
const line = "─".repeat(pad);
|
|
24
|
+
return (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: "gray", children: [line, " ", label, " ", line] }) }));
|
|
25
|
+
}
|
|
26
|
+
// ── ThreadMessageItem ───────────────────────────────────────────────
|
|
27
|
+
function ThreadMessageItem({ message, }) {
|
|
28
|
+
const color = getAgentColor(message.sender);
|
|
29
|
+
const time = formatTime(message.timestamp);
|
|
30
|
+
if (message.isFirstInGroup) {
|
|
31
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { gap: 1, children: [_jsxs(Text, { color: color, bold: true, children: ["[", message.initials, "]"] }), _jsx(Text, { bold: true, color: "white", children: message.sender }), _jsx(Text, { color: "gray", children: time })] }), _jsx(Box, { paddingLeft: 5, children: _jsx(Text, { children: message.content }) })] }));
|
|
32
|
+
}
|
|
33
|
+
return (_jsx(Box, { paddingX: 1, paddingLeft: 6, children: _jsx(Text, { children: message.content }) }));
|
|
34
|
+
}
|
|
35
|
+
// ── AlsoSendCheckbox ────────────────────────────────────────────────
|
|
36
|
+
function AlsoSendCheckbox({ checked, channelName, channelType, onToggle, }) {
|
|
37
|
+
const icon = checked ? "☑" : "☐";
|
|
38
|
+
const iconColor = checked ? "green" : "gray";
|
|
39
|
+
const channelLabel = channelType === "channel" ? `#${channelName}` : channelName;
|
|
40
|
+
return (_jsxs(Box, { paddingX: 1, gap: 1, children: [_jsx(Text, { color: iconColor, children: icon }), _jsxs(Text, { color: "gray", children: ["Also send to ", channelLabel] })] }));
|
|
41
|
+
}
|
|
42
|
+
// ── ThreadPanel ─────────────────────────────────────────────────────
|
|
43
|
+
export function ThreadPanel({ width, focused, parentMessage, replies, sourceChannelName, sourceChannelType, alsoSendToChannel, onSendReply, onToggleAlsoSend, onClose, slashCommands = [], agents = [], }) {
|
|
44
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, borderStyle: "single", borderColor: focused ? "cyan" : "gray", children: [_jsx(ThreadHeader, { channelName: sourceChannelName, channelType: sourceChannelType, onClose: onClose }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "gray", children: "─".repeat(Math.max(width - 4, 1)) }) }), _jsx(ThreadMessageItem, { message: parentMessage }), _jsx(Box, { height: 1 }), _jsx(ReplyDivider, { count: replies.length, width: width }), _jsx(Box, { height: 1 }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: replies.map((reply) => (_jsx(ThreadMessageItem, { message: reply }, reply.id))) }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "gray", children: "─".repeat(Math.max(width - 4, 1)) }) }), _jsx(ComposeArea, { channelName: sourceChannelName, channelType: sourceChannelType, focused: focused, isThread: true, onSubmit: onSendReply, slashCommands: slashCommands, agents: agents }), _jsx(AlsoSendCheckbox, { checked: alsoSendToChannel, channelName: sourceChannelName, channelType: sourceChannelType, onToggle: onToggleAlsoSend })] }));
|
|
45
|
+
}
|
|
46
|
+
export default ThreadPanel;
|
|
47
|
+
//# sourceMappingURL=thread-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-panel.js","sourceRoot":"","sources":["../../../../src/tui/components/slack/thread-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash command autocomplete overlay and hook.
|
|
3
|
+
*
|
|
4
|
+
* Shows a small overlay Box above the input line listing matching slash
|
|
5
|
+
* commands when the input starts with "/". Tab cycles through matches,
|
|
6
|
+
* Enter accepts the current match, Escape dismisses.
|
|
7
|
+
*
|
|
8
|
+
* This is a standalone component — wire it into the home/conversation
|
|
9
|
+
* view by:
|
|
10
|
+
* 1. Calling useSlashAutocomplete(inputValue, slashCommands)
|
|
11
|
+
* 2. Rendering <SlashAutocomplete {...autocomplete} /> above the input
|
|
12
|
+
* 3. Intercepting Tab/Enter/Escape in useInput and calling the
|
|
13
|
+
* returned handlers (onTab, onAccept, onDismiss)
|
|
14
|
+
*/
|
|
15
|
+
import React from "react";
|
|
16
|
+
export interface SlashCommandEntry {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
usage?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AutocompleteState {
|
|
22
|
+
/** Whether the autocomplete overlay is visible */
|
|
23
|
+
visible: boolean;
|
|
24
|
+
/** Filtered list of matching commands */
|
|
25
|
+
matches: SlashCommandEntry[];
|
|
26
|
+
/** Currently highlighted index */
|
|
27
|
+
selectedIndex: number;
|
|
28
|
+
/** The query text (everything after "/") */
|
|
29
|
+
query: string;
|
|
30
|
+
}
|
|
31
|
+
export interface AutocompleteActions {
|
|
32
|
+
/** Call when Tab is pressed — cycles to next match */
|
|
33
|
+
onTab: () => AutocompleteResult | null;
|
|
34
|
+
/** Call on Shift+Tab — cycles to previous match */
|
|
35
|
+
onShiftTab: () => AutocompleteResult | null;
|
|
36
|
+
/** Call when Enter is pressed while overlay is visible — accepts the match */
|
|
37
|
+
onAccept: () => AutocompleteResult | null;
|
|
38
|
+
/** Call when Escape is pressed — dismisses the overlay */
|
|
39
|
+
onDismiss: () => void;
|
|
40
|
+
/** Update the autocomplete state when input changes */
|
|
41
|
+
update: (input: string) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface AutocompleteResult {
|
|
44
|
+
/** The completed text to replace the input with (e.g. "/search ") */
|
|
45
|
+
text: string;
|
|
46
|
+
/** The command name that was selected */
|
|
47
|
+
command: string;
|
|
48
|
+
}
|
|
49
|
+
export interface SlashAutocompleteProps {
|
|
50
|
+
/** Current autocomplete state */
|
|
51
|
+
state: AutocompleteState;
|
|
52
|
+
/** Max number of items to show in the overlay */
|
|
53
|
+
maxVisible?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Filter and rank commands that match a prefix query.
|
|
57
|
+
*/
|
|
58
|
+
export declare function filterCommands(query: string, commands: SlashCommandEntry[]): SlashCommandEntry[];
|
|
59
|
+
/**
|
|
60
|
+
* Create initial autocomplete state.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createAutocompleteState(): AutocompleteState;
|
|
63
|
+
/**
|
|
64
|
+
* Compute new autocomplete state from current input value.
|
|
65
|
+
*/
|
|
66
|
+
export declare function computeAutocompleteState(input: string, commands: SlashCommandEntry[]): AutocompleteState;
|
|
67
|
+
/**
|
|
68
|
+
* Create actions that manage autocomplete state.
|
|
69
|
+
* This is a factory for use in React state management.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createAutocompleteActions(state: AutocompleteState, setState: (s: AutocompleteState) => void, commands: SlashCommandEntry[]): AutocompleteActions;
|
|
72
|
+
export declare function useSlashAutocomplete(commands: SlashCommandEntry[]): {
|
|
73
|
+
state: AutocompleteState;
|
|
74
|
+
actions: AutocompleteActions;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Overlay rendering the list of matching slash commands.
|
|
78
|
+
* Position this above the input line.
|
|
79
|
+
*/
|
|
80
|
+
export declare function SlashAutocomplete({ state, maxVisible, }: SlashAutocompleteProps): React.JSX.Element | null;
|
|
81
|
+
export default SlashAutocomplete;
|