@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,87 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* View stack router for the TUI.
|
|
4
|
+
* Renders the top-of-stack view and provides push/pop via context.
|
|
5
|
+
*/
|
|
6
|
+
import React, { createContext, useContext, useCallback } from "react";
|
|
7
|
+
import { Box, Text } from "ink";
|
|
8
|
+
import { useTheme } from "./theme.js";
|
|
9
|
+
const RouterContext = createContext({
|
|
10
|
+
push: () => { },
|
|
11
|
+
pop: () => { },
|
|
12
|
+
currentView: undefined,
|
|
13
|
+
viewStack: [],
|
|
14
|
+
});
|
|
15
|
+
export function useRouter() {
|
|
16
|
+
return useContext(RouterContext);
|
|
17
|
+
}
|
|
18
|
+
const viewRegistry = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Register a view component for a given name.
|
|
21
|
+
* Call this from the component layer (Agent 2) to wire up real views.
|
|
22
|
+
*/
|
|
23
|
+
export function registerView(name, component) {
|
|
24
|
+
viewRegistry.set(name, component);
|
|
25
|
+
}
|
|
26
|
+
// ── Placeholder component ──────────────────────────────────────────
|
|
27
|
+
function PlaceholderView({ name }) {
|
|
28
|
+
const t = useTheme();
|
|
29
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { color: t.colors.primary, bold: true, children: name }), _jsx(Text, { color: t.colors.muted, children: "View not yet implemented. Press Escape to go back." })] }));
|
|
30
|
+
}
|
|
31
|
+
// ── Supported view names ───────────────────────────────────────────
|
|
32
|
+
const SUPPORTED_VIEWS = new Set([
|
|
33
|
+
"home",
|
|
34
|
+
"help",
|
|
35
|
+
"record-list",
|
|
36
|
+
"record-detail",
|
|
37
|
+
"ask-chat",
|
|
38
|
+
"agent-list",
|
|
39
|
+
"chat",
|
|
40
|
+
"calendar",
|
|
41
|
+
"orchestration",
|
|
42
|
+
"generative",
|
|
43
|
+
"task-board",
|
|
44
|
+
"timeline",
|
|
45
|
+
"insights",
|
|
46
|
+
]);
|
|
47
|
+
// ── Breadcrumb ─────────────────────────────────────────────────────
|
|
48
|
+
function Breadcrumb({ stack }) {
|
|
49
|
+
const t = useTheme();
|
|
50
|
+
if (stack.length <= 1)
|
|
51
|
+
return null;
|
|
52
|
+
return (_jsx(Box, { marginBottom: 1, children: stack.map((entry, i) => {
|
|
53
|
+
const isLast = i === stack.length - 1;
|
|
54
|
+
return (_jsxs(React.Fragment, { children: [_jsx(Text, { color: isLast ? t.breadcrumb.activeColor : t.breadcrumb.color, bold: isLast, children: entry.name }), !isLast && (_jsx(Text, { color: t.breadcrumb.color, children: t.breadcrumb.separator }))] }, `${entry.name}-${i}`));
|
|
55
|
+
}) }));
|
|
56
|
+
}
|
|
57
|
+
export function Router({ viewStack, dispatch, children }) {
|
|
58
|
+
const push = useCallback((view) => dispatch({ type: "PUSH_VIEW", view }), [dispatch]);
|
|
59
|
+
const pop = useCallback(() => dispatch({ type: "POP_VIEW" }), [dispatch]);
|
|
60
|
+
const currentView = viewStack[viewStack.length - 1];
|
|
61
|
+
const contextValue = {
|
|
62
|
+
push,
|
|
63
|
+
pop,
|
|
64
|
+
currentView,
|
|
65
|
+
viewStack,
|
|
66
|
+
};
|
|
67
|
+
// Resolve the component for the current view
|
|
68
|
+
let ViewContent;
|
|
69
|
+
if (currentView) {
|
|
70
|
+
const registered = viewRegistry.get(currentView.name);
|
|
71
|
+
if (registered) {
|
|
72
|
+
const Component = registered;
|
|
73
|
+
ViewContent = _jsx(Component, { props: currentView.props });
|
|
74
|
+
}
|
|
75
|
+
else if (SUPPORTED_VIEWS.has(currentView.name)) {
|
|
76
|
+
ViewContent = _jsx(PlaceholderView, { name: currentView.name });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
ViewContent = _jsx(PlaceholderView, { name: `unknown: ${currentView.name}` });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
ViewContent = _jsx(PlaceholderView, { name: "home" });
|
|
84
|
+
}
|
|
85
|
+
return (_jsx(RouterContext.Provider, { value: contextValue, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Breadcrumb, { stack: viewStack }), ViewContent, children] }) }));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/tui/router.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton service that manages agent instances and exposes state for the TUI.
|
|
3
|
+
* Bridges the agent runtime (loop, tools, queues, sessions) to the view layer.
|
|
4
|
+
*/
|
|
5
|
+
import { AgentLoop } from "../../agent/loop.js";
|
|
6
|
+
import { ToolRegistry } from "../../agent/tools.js";
|
|
7
|
+
import { AgentSessionStore } from "../../agent/session-store.js";
|
|
8
|
+
import { MessageQueues } from "../../agent/queues.js";
|
|
9
|
+
import type { AgentConfig, AgentState } from "../../agent/types.js";
|
|
10
|
+
export interface ManagedAgent {
|
|
11
|
+
config: AgentConfig;
|
|
12
|
+
state: AgentState;
|
|
13
|
+
loop: AgentLoop;
|
|
14
|
+
}
|
|
15
|
+
export declare class AgentService {
|
|
16
|
+
private agents;
|
|
17
|
+
private toolRegistry;
|
|
18
|
+
private sessionStore;
|
|
19
|
+
private queues;
|
|
20
|
+
private listeners;
|
|
21
|
+
constructor(toolRegistry?: ToolRegistry, sessionStore?: AgentSessionStore, queues?: MessageQueues);
|
|
22
|
+
/** Create an agent from a full config. */
|
|
23
|
+
create(config: AgentConfig): ManagedAgent;
|
|
24
|
+
/** Create an agent from a pre-built template. */
|
|
25
|
+
createFromTemplate(slug: string, templateName: string): ManagedAgent;
|
|
26
|
+
/** Start the agent loop (sets phase to idle if done/error). */
|
|
27
|
+
start(slug: string): Promise<void>;
|
|
28
|
+
/** Stop the agent loop. */
|
|
29
|
+
stop(slug: string): void;
|
|
30
|
+
/** Send a high-priority steer message to interrupt the agent. */
|
|
31
|
+
steer(slug: string, message: string): void;
|
|
32
|
+
/** Queue a follow-up message for the agent's next turn. */
|
|
33
|
+
followUp(slug: string, message: string): void;
|
|
34
|
+
/** Get a managed agent by slug. */
|
|
35
|
+
get(slug: string): ManagedAgent | undefined;
|
|
36
|
+
/** List all managed agents. */
|
|
37
|
+
list(): ManagedAgent[];
|
|
38
|
+
/** Get the current state snapshot for an agent. */
|
|
39
|
+
getState(slug: string): AgentState | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to state changes. Returns an unsubscribe function.
|
|
42
|
+
* The listener fires whenever any agent's state changes (create, start, stop, phase change).
|
|
43
|
+
*/
|
|
44
|
+
subscribe(listener: () => void): () => void;
|
|
45
|
+
/** Get available template names. */
|
|
46
|
+
getTemplateNames(): string[];
|
|
47
|
+
/** Get a template config (without slug). */
|
|
48
|
+
getTemplate(name: string): Omit<AgentConfig, "slug"> | undefined;
|
|
49
|
+
private notify;
|
|
50
|
+
/** Remove an agent. Stops its loop first. */
|
|
51
|
+
remove(slug: string): void;
|
|
52
|
+
/** Update mutable fields of an agent's config. */
|
|
53
|
+
updateConfig(slug: string, updates: Partial<Pick<AgentConfig, "name" | "expertise" | "heartbeatCron">>): void;
|
|
54
|
+
private requireAgent;
|
|
55
|
+
}
|
|
56
|
+
export declare function getAgentService(): AgentService;
|
|
57
|
+
/** Reset the singleton (for testing). */
|
|
58
|
+
export declare function resetAgentService(): void;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton service that manages agent instances and exposes state for the TUI.
|
|
3
|
+
* Bridges the agent runtime (loop, tools, queues, sessions) to the view layer.
|
|
4
|
+
*/
|
|
5
|
+
import { AgentLoop } from "../../agent/loop.js";
|
|
6
|
+
import { ToolRegistry, createBuiltinTools } from "../../agent/tools.js";
|
|
7
|
+
import { AgentSessionStore } from "../../agent/session-store.js";
|
|
8
|
+
import { MessageQueues } from "../../agent/queues.js";
|
|
9
|
+
import { NexClient } from "../../lib/client.js";
|
|
10
|
+
import { resolveApiKey } from "../../lib/config.js";
|
|
11
|
+
import { templates } from "../../agent/templates.js";
|
|
12
|
+
import { getChatService } from "./chat-service.js";
|
|
13
|
+
export class AgentService {
|
|
14
|
+
agents = new Map();
|
|
15
|
+
toolRegistry;
|
|
16
|
+
sessionStore;
|
|
17
|
+
queues;
|
|
18
|
+
listeners = [];
|
|
19
|
+
constructor(toolRegistry, sessionStore, queues) {
|
|
20
|
+
if (toolRegistry) {
|
|
21
|
+
this.toolRegistry = toolRegistry;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const client = new NexClient(resolveApiKey());
|
|
25
|
+
this.toolRegistry = new ToolRegistry();
|
|
26
|
+
for (const tool of createBuiltinTools(client)) {
|
|
27
|
+
this.toolRegistry.register(tool);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.sessionStore = sessionStore ?? new AgentSessionStore();
|
|
31
|
+
this.queues = queues ?? new MessageQueues();
|
|
32
|
+
}
|
|
33
|
+
/** Create an agent from a full config. */
|
|
34
|
+
create(config) {
|
|
35
|
+
if (this.agents.has(config.slug)) {
|
|
36
|
+
throw new Error(`Agent "${config.slug}" already exists.`);
|
|
37
|
+
}
|
|
38
|
+
const loop = new AgentLoop(config, this.toolRegistry, this.sessionStore, this.queues);
|
|
39
|
+
// Wire phase_change events to notify TUI listeners
|
|
40
|
+
loop.on("phase_change", () => {
|
|
41
|
+
const managed = this.agents.get(config.slug);
|
|
42
|
+
if (managed) {
|
|
43
|
+
managed.state = loop.getState();
|
|
44
|
+
this.notify();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// Wire agent message output back to the DM channel in chat service
|
|
48
|
+
loop.on("message", (content) => {
|
|
49
|
+
if (typeof content !== "string" || !content.trim())
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
const chatService = getChatService();
|
|
53
|
+
// Ensure DM channel exists (creates if needed) then send reply
|
|
54
|
+
const dmChannel = chatService.ensureChannel(`dm-${config.slug}`);
|
|
55
|
+
chatService.send(dmChannel.id, content, config.name);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Chat service not available — ignore
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// Ensure DM channel exists in chat service immediately so it shows in sidebar
|
|
62
|
+
try {
|
|
63
|
+
getChatService().ensureChannel(`dm-${config.slug}`);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Chat service may not be ready yet — the message event handler will create it on first reply
|
|
67
|
+
}
|
|
68
|
+
const managed = {
|
|
69
|
+
config,
|
|
70
|
+
state: loop.getState(),
|
|
71
|
+
loop,
|
|
72
|
+
};
|
|
73
|
+
this.agents.set(config.slug, managed);
|
|
74
|
+
this.notify();
|
|
75
|
+
return managed;
|
|
76
|
+
}
|
|
77
|
+
/** Create an agent from a pre-built template. */
|
|
78
|
+
createFromTemplate(slug, templateName) {
|
|
79
|
+
const tmpl = templates[templateName];
|
|
80
|
+
if (!tmpl) {
|
|
81
|
+
throw new Error(`Unknown template: "${templateName}". Available: ${Object.keys(templates).join(", ")}`);
|
|
82
|
+
}
|
|
83
|
+
const config = { slug, ...tmpl };
|
|
84
|
+
return this.create(config);
|
|
85
|
+
}
|
|
86
|
+
/** Start the agent loop (sets phase to idle if done/error). */
|
|
87
|
+
async start(slug) {
|
|
88
|
+
const managed = this.requireAgent(slug);
|
|
89
|
+
managed.loop.start();
|
|
90
|
+
managed.state = managed.loop.getState();
|
|
91
|
+
this.notify();
|
|
92
|
+
// Run one tick to kick off the cycle
|
|
93
|
+
await managed.loop.tick();
|
|
94
|
+
managed.state = managed.loop.getState();
|
|
95
|
+
this.notify();
|
|
96
|
+
}
|
|
97
|
+
/** Stop the agent loop. */
|
|
98
|
+
stop(slug) {
|
|
99
|
+
const managed = this.requireAgent(slug);
|
|
100
|
+
managed.loop.stop();
|
|
101
|
+
managed.state = managed.loop.getState();
|
|
102
|
+
this.notify();
|
|
103
|
+
}
|
|
104
|
+
/** Send a high-priority steer message to interrupt the agent. */
|
|
105
|
+
steer(slug, message) {
|
|
106
|
+
this.requireAgent(slug);
|
|
107
|
+
this.queues.steer(slug, message);
|
|
108
|
+
}
|
|
109
|
+
/** Queue a follow-up message for the agent's next turn. */
|
|
110
|
+
followUp(slug, message) {
|
|
111
|
+
this.requireAgent(slug);
|
|
112
|
+
this.queues.followUp(slug, message);
|
|
113
|
+
}
|
|
114
|
+
/** Get a managed agent by slug. */
|
|
115
|
+
get(slug) {
|
|
116
|
+
return this.agents.get(slug);
|
|
117
|
+
}
|
|
118
|
+
/** List all managed agents. */
|
|
119
|
+
list() {
|
|
120
|
+
return Array.from(this.agents.values());
|
|
121
|
+
}
|
|
122
|
+
/** Get the current state snapshot for an agent. */
|
|
123
|
+
getState(slug) {
|
|
124
|
+
return this.agents.get(slug)?.state;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Subscribe to state changes. Returns an unsubscribe function.
|
|
128
|
+
* The listener fires whenever any agent's state changes (create, start, stop, phase change).
|
|
129
|
+
*/
|
|
130
|
+
subscribe(listener) {
|
|
131
|
+
this.listeners.push(listener);
|
|
132
|
+
return () => {
|
|
133
|
+
const idx = this.listeners.indexOf(listener);
|
|
134
|
+
if (idx >= 0)
|
|
135
|
+
this.listeners.splice(idx, 1);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** Get available template names. */
|
|
139
|
+
getTemplateNames() {
|
|
140
|
+
return Object.keys(templates);
|
|
141
|
+
}
|
|
142
|
+
/** Get a template config (without slug). */
|
|
143
|
+
getTemplate(name) {
|
|
144
|
+
return templates[name];
|
|
145
|
+
}
|
|
146
|
+
notify() {
|
|
147
|
+
for (const listener of this.listeners) {
|
|
148
|
+
try {
|
|
149
|
+
listener();
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// swallow listener errors
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Remove an agent. Stops its loop first. */
|
|
157
|
+
remove(slug) {
|
|
158
|
+
const managed = this.requireAgent(slug);
|
|
159
|
+
try {
|
|
160
|
+
managed.loop.stop();
|
|
161
|
+
}
|
|
162
|
+
catch { /* already stopped */ }
|
|
163
|
+
this.agents.delete(slug);
|
|
164
|
+
this.notify();
|
|
165
|
+
}
|
|
166
|
+
/** Update mutable fields of an agent's config. */
|
|
167
|
+
updateConfig(slug, updates) {
|
|
168
|
+
const managed = this.requireAgent(slug);
|
|
169
|
+
if (updates.name !== undefined)
|
|
170
|
+
managed.config.name = updates.name;
|
|
171
|
+
if (updates.expertise !== undefined)
|
|
172
|
+
managed.config.expertise = updates.expertise;
|
|
173
|
+
if (updates.heartbeatCron !== undefined)
|
|
174
|
+
managed.config.heartbeatCron = updates.heartbeatCron;
|
|
175
|
+
this.notify();
|
|
176
|
+
}
|
|
177
|
+
requireAgent(slug) {
|
|
178
|
+
const managed = this.agents.get(slug);
|
|
179
|
+
if (!managed) {
|
|
180
|
+
throw new Error(`Agent "${slug}" not found.`);
|
|
181
|
+
}
|
|
182
|
+
return managed;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// ── Singleton ──
|
|
186
|
+
let instance;
|
|
187
|
+
export function getAgentService() {
|
|
188
|
+
if (!instance) {
|
|
189
|
+
instance = new AgentService();
|
|
190
|
+
}
|
|
191
|
+
return instance;
|
|
192
|
+
}
|
|
193
|
+
/** Reset the singleton (for testing). */
|
|
194
|
+
export function resetAgentService() {
|
|
195
|
+
instance = undefined;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=agent-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-service.js","sourceRoot":"","sources":["../../../src/tui/services/agent-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI service layer for the calendar/scheduling system.
|
|
3
|
+
* Wraps Scheduler and CalendarStore into a single facade
|
|
4
|
+
* that the calendar view can consume without touching backend internals.
|
|
5
|
+
*/
|
|
6
|
+
import type { ScheduledTask } from '../../calendar/types.js';
|
|
7
|
+
export declare class CalendarService {
|
|
8
|
+
private scheduler;
|
|
9
|
+
private store;
|
|
10
|
+
private listeners;
|
|
11
|
+
constructor(calendarFilePath?: string);
|
|
12
|
+
/**
|
|
13
|
+
* Returns events formatted for the calendar grid view.
|
|
14
|
+
* Maps scheduled tasks to day/hour slots for the given week.
|
|
15
|
+
*/
|
|
16
|
+
getWeekEvents(weekOffset?: number): Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
agentName: string;
|
|
19
|
+
day: number;
|
|
20
|
+
hour: number;
|
|
21
|
+
label: string;
|
|
22
|
+
}>;
|
|
23
|
+
scheduleHeartbeat(agentSlug: string, agentName: string, cronExpression: string): void;
|
|
24
|
+
removeSchedule(agentSlug: string): void;
|
|
25
|
+
getUpcoming(hours?: number): ScheduledTask[];
|
|
26
|
+
getMissed(): ScheduledTask[];
|
|
27
|
+
subscribe(listener: () => void): () => void;
|
|
28
|
+
private notify;
|
|
29
|
+
private getWeekRange;
|
|
30
|
+
}
|
|
31
|
+
export declare function getCalendarService(): CalendarService;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI service layer for the calendar/scheduling system.
|
|
3
|
+
* Wraps Scheduler and CalendarStore into a single facade
|
|
4
|
+
* that the calendar view can consume without touching backend internals.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { Scheduler } from '../../calendar/scheduler.js';
|
|
9
|
+
import { CalendarStore } from '../../calendar/store.js';
|
|
10
|
+
export class CalendarService {
|
|
11
|
+
scheduler;
|
|
12
|
+
store;
|
|
13
|
+
listeners = [];
|
|
14
|
+
constructor(calendarFilePath) {
|
|
15
|
+
const filePath = calendarFilePath ?? join(homedir(), '.nex-cli', 'calendar.json');
|
|
16
|
+
this.store = new CalendarStore(filePath);
|
|
17
|
+
this.scheduler = new Scheduler(this.store);
|
|
18
|
+
}
|
|
19
|
+
// ── View data ──
|
|
20
|
+
/**
|
|
21
|
+
* Returns events formatted for the calendar grid view.
|
|
22
|
+
* Maps scheduled tasks to day/hour slots for the given week.
|
|
23
|
+
*/
|
|
24
|
+
getWeekEvents(weekOffset = 0) {
|
|
25
|
+
const { start, end } = this.getWeekRange(weekOffset);
|
|
26
|
+
const tasks = this.scheduler.getUpcoming(start, end);
|
|
27
|
+
const allTasks = this.store.load().filter(t => t.enabled);
|
|
28
|
+
// For recurring tasks, generate occurrences within the week window
|
|
29
|
+
const events = [];
|
|
30
|
+
// Include tasks whose nextRun falls within the week
|
|
31
|
+
for (const task of tasks) {
|
|
32
|
+
const runDate = new Date(task.nextRun);
|
|
33
|
+
events.push({
|
|
34
|
+
id: task.id,
|
|
35
|
+
agentName: task.agentSlug,
|
|
36
|
+
day: runDate.getDay(),
|
|
37
|
+
hour: runDate.getHours(),
|
|
38
|
+
label: `${task.agentSlug} ${task.type}`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Also scan all enabled tasks and project their cron into the week
|
|
42
|
+
for (const task of allTasks) {
|
|
43
|
+
// Skip tasks already captured via getUpcoming
|
|
44
|
+
if (tasks.some(t => t.id === task.id))
|
|
45
|
+
continue;
|
|
46
|
+
try {
|
|
47
|
+
let cursor = new Date(start.getTime());
|
|
48
|
+
// Walk through the week generating occurrences
|
|
49
|
+
while (cursor.getTime() <= end.getTime()) {
|
|
50
|
+
const next = this.scheduler.nextRun(task.cronExpression, cursor);
|
|
51
|
+
if (next.getTime() > end.getTime())
|
|
52
|
+
break;
|
|
53
|
+
if (next.getTime() >= start.getTime()) {
|
|
54
|
+
events.push({
|
|
55
|
+
id: task.id,
|
|
56
|
+
agentName: task.agentSlug,
|
|
57
|
+
day: next.getDay(),
|
|
58
|
+
hour: next.getHours(),
|
|
59
|
+
label: `${task.agentSlug} ${task.type}`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Advance cursor past this occurrence
|
|
63
|
+
cursor = new Date(next.getTime());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Skip tasks with unparseable cron
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return events;
|
|
71
|
+
}
|
|
72
|
+
// ── Scheduling ──
|
|
73
|
+
scheduleHeartbeat(agentSlug, agentName, cronExpression) {
|
|
74
|
+
this.scheduler.schedule({
|
|
75
|
+
agentSlug,
|
|
76
|
+
type: 'heartbeat',
|
|
77
|
+
cronExpression,
|
|
78
|
+
enabled: true,
|
|
79
|
+
});
|
|
80
|
+
this.notify();
|
|
81
|
+
}
|
|
82
|
+
removeSchedule(agentSlug) {
|
|
83
|
+
const agentTasks = this.store.getByAgent(agentSlug);
|
|
84
|
+
for (const task of agentTasks) {
|
|
85
|
+
this.store.remove(task.id);
|
|
86
|
+
}
|
|
87
|
+
this.notify();
|
|
88
|
+
}
|
|
89
|
+
// ── Queries ──
|
|
90
|
+
getUpcoming(hours = 24) {
|
|
91
|
+
const now = new Date();
|
|
92
|
+
const to = new Date(now.getTime() + hours * 60 * 60 * 1000);
|
|
93
|
+
return this.scheduler.getUpcoming(now, to);
|
|
94
|
+
}
|
|
95
|
+
getMissed() {
|
|
96
|
+
return this.scheduler.getMissed();
|
|
97
|
+
}
|
|
98
|
+
// ── Subscription for TUI re-renders ──
|
|
99
|
+
subscribe(listener) {
|
|
100
|
+
this.listeners.push(listener);
|
|
101
|
+
return () => {
|
|
102
|
+
const idx = this.listeners.indexOf(listener);
|
|
103
|
+
if (idx >= 0)
|
|
104
|
+
this.listeners.splice(idx, 1);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
notify() {
|
|
108
|
+
for (const listener of this.listeners) {
|
|
109
|
+
listener();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// ── Internal helpers ──
|
|
113
|
+
getWeekRange(offset) {
|
|
114
|
+
const now = new Date();
|
|
115
|
+
const dayOfWeek = now.getDay();
|
|
116
|
+
const start = new Date(now);
|
|
117
|
+
start.setDate(now.getDate() - dayOfWeek + offset * 7);
|
|
118
|
+
start.setHours(0, 0, 0, 0);
|
|
119
|
+
const end = new Date(start);
|
|
120
|
+
end.setDate(start.getDate() + 6);
|
|
121
|
+
end.setHours(23, 59, 59, 999);
|
|
122
|
+
return { start, end };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ── Singleton accessor ──
|
|
126
|
+
let instance;
|
|
127
|
+
export function getCalendarService() {
|
|
128
|
+
if (!instance) {
|
|
129
|
+
instance = new CalendarService();
|
|
130
|
+
}
|
|
131
|
+
return instance;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=calendar-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-service.js","sourceRoot":"","sources":["../../../src/tui/services/calendar-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI service layer for the chat system.
|
|
3
|
+
* Wraps ChannelManager, MessageStore, and ChatRouter into a single facade
|
|
4
|
+
* that the chat view can consume without touching backend internals.
|
|
5
|
+
*/
|
|
6
|
+
import type { Channel, ChatMessage } from '../../chat/types.js';
|
|
7
|
+
export declare class ChatService {
|
|
8
|
+
private channelManager;
|
|
9
|
+
private messageStore;
|
|
10
|
+
private chatRouter;
|
|
11
|
+
private listeners;
|
|
12
|
+
constructor(baseDir?: string);
|
|
13
|
+
getChannels(): Array<{
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
unread: number;
|
|
17
|
+
}>;
|
|
18
|
+
createChannel(name: string, type?: 'public' | 'private'): Channel;
|
|
19
|
+
/** Get existing channel by name, or create it if it doesn't exist. */
|
|
20
|
+
ensureChannel(name: string, type?: 'public' | 'private'): Channel;
|
|
21
|
+
getMessages(channelId: string, limit?: number): ChatMessage[];
|
|
22
|
+
send(channelId: string, content: string, sender?: string): ChatMessage;
|
|
23
|
+
route(channelId: string, sender: string, content: string): ChatMessage;
|
|
24
|
+
getPendingMentions(): ChatMessage[];
|
|
25
|
+
subscribe(listener: () => void): () => void;
|
|
26
|
+
private notify;
|
|
27
|
+
}
|
|
28
|
+
export declare function getChatService(): ChatService;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI service layer for the chat system.
|
|
3
|
+
* Wraps ChannelManager, MessageStore, and ChatRouter into a single facade
|
|
4
|
+
* that the chat view can consume without touching backend internals.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { ChannelManager } from '../../chat/channel.js';
|
|
9
|
+
import { MessageStore } from '../../chat/message-store.js';
|
|
10
|
+
import { ChatRouter } from '../../chat/router.js';
|
|
11
|
+
export class ChatService {
|
|
12
|
+
channelManager;
|
|
13
|
+
messageStore;
|
|
14
|
+
chatRouter;
|
|
15
|
+
listeners = [];
|
|
16
|
+
constructor(baseDir) {
|
|
17
|
+
const dir = baseDir ?? join(process.env.NEX_CLI_DATA_DIR ?? join(homedir(), '.nex-cli'), 'chat');
|
|
18
|
+
this.channelManager = new ChannelManager(dir);
|
|
19
|
+
this.messageStore = new MessageStore(join(dir, 'messages'));
|
|
20
|
+
this.chatRouter = new ChatRouter(this.channelManager, this.messageStore);
|
|
21
|
+
// Ensure a #general channel always exists
|
|
22
|
+
this.channelManager.ensureDefaults();
|
|
23
|
+
}
|
|
24
|
+
// ── Channel operations ──
|
|
25
|
+
getChannels() {
|
|
26
|
+
const channels = this.channelManager.list();
|
|
27
|
+
return channels.map(ch => ({
|
|
28
|
+
id: ch.id,
|
|
29
|
+
name: ch.name,
|
|
30
|
+
unread: this.messageStore.getUnread('human', 0)
|
|
31
|
+
.filter(m => m.channelId === ch.id).length,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
createChannel(name, type = 'public') {
|
|
35
|
+
const channel = this.channelManager.create({
|
|
36
|
+
name,
|
|
37
|
+
type,
|
|
38
|
+
members: ['human'],
|
|
39
|
+
});
|
|
40
|
+
this.notify();
|
|
41
|
+
return channel;
|
|
42
|
+
}
|
|
43
|
+
/** Get existing channel by name, or create it if it doesn't exist. */
|
|
44
|
+
ensureChannel(name, type = 'public') {
|
|
45
|
+
const existing = this.channelManager.list().find((ch) => ch.name === name);
|
|
46
|
+
if (existing)
|
|
47
|
+
return existing;
|
|
48
|
+
return this.createChannel(name, type);
|
|
49
|
+
}
|
|
50
|
+
// ── Message operations ──
|
|
51
|
+
getMessages(channelId, limit) {
|
|
52
|
+
return this.messageStore.getMessages(channelId, { limit });
|
|
53
|
+
}
|
|
54
|
+
send(channelId, content, sender = 'human') {
|
|
55
|
+
const message = this.chatRouter.route(channelId, sender, content);
|
|
56
|
+
this.notify();
|
|
57
|
+
return message;
|
|
58
|
+
}
|
|
59
|
+
// ── Routing ──
|
|
60
|
+
route(channelId, sender, content) {
|
|
61
|
+
const message = this.chatRouter.route(channelId, sender, content);
|
|
62
|
+
this.notify();
|
|
63
|
+
return message;
|
|
64
|
+
}
|
|
65
|
+
getPendingMentions() {
|
|
66
|
+
return this.chatRouter.hasPendingMentions();
|
|
67
|
+
}
|
|
68
|
+
// ── Subscription for TUI re-renders ──
|
|
69
|
+
subscribe(listener) {
|
|
70
|
+
this.listeners.push(listener);
|
|
71
|
+
return () => {
|
|
72
|
+
const idx = this.listeners.indexOf(listener);
|
|
73
|
+
if (idx >= 0)
|
|
74
|
+
this.listeners.splice(idx, 1);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
notify() {
|
|
78
|
+
for (const listener of this.listeners) {
|
|
79
|
+
listener();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ── Singleton accessor ──
|
|
84
|
+
let instance;
|
|
85
|
+
export function getChatService() {
|
|
86
|
+
if (!instance) {
|
|
87
|
+
instance = new ChatService();
|
|
88
|
+
}
|
|
89
|
+
return instance;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=chat-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-service.js","sourceRoot":"","sources":["../../../src/tui/services/chat-service.ts"],"names":[],"mappings":"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"}
|