@nex-ai/nex 0.1.22 → 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 +9 -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/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,218 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Slash command autocomplete overlay and hook.
|
|
4
|
+
*
|
|
5
|
+
* Shows a small overlay Box above the input line listing matching slash
|
|
6
|
+
* commands when the input starts with "/". Tab cycles through matches,
|
|
7
|
+
* Enter accepts the current match, Escape dismisses.
|
|
8
|
+
*
|
|
9
|
+
* This is a standalone component — wire it into the home/conversation
|
|
10
|
+
* view by:
|
|
11
|
+
* 1. Calling useSlashAutocomplete(inputValue, slashCommands)
|
|
12
|
+
* 2. Rendering <SlashAutocomplete {...autocomplete} /> above the input
|
|
13
|
+
* 3. Intercepting Tab/Enter/Escape in useInput and calling the
|
|
14
|
+
* returned handlers (onTab, onAccept, onDismiss)
|
|
15
|
+
*/
|
|
16
|
+
import React from "react";
|
|
17
|
+
import { Box, Text } from "ink";
|
|
18
|
+
// ── Pure functions ──────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Filter and rank commands that match a prefix query.
|
|
21
|
+
*/
|
|
22
|
+
export function filterCommands(query, commands) {
|
|
23
|
+
const q = query.toLowerCase();
|
|
24
|
+
if (!q)
|
|
25
|
+
return commands;
|
|
26
|
+
return commands.filter((cmd) => cmd.name.toLowerCase().startsWith(q));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create initial autocomplete state.
|
|
30
|
+
*/
|
|
31
|
+
export function createAutocompleteState() {
|
|
32
|
+
return {
|
|
33
|
+
visible: false,
|
|
34
|
+
matches: [],
|
|
35
|
+
selectedIndex: 0,
|
|
36
|
+
query: "",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Compute new autocomplete state from current input value.
|
|
41
|
+
*/
|
|
42
|
+
export function computeAutocompleteState(input, commands) {
|
|
43
|
+
const trimmed = input.trimStart();
|
|
44
|
+
// Only activate when input starts with "/" and has no space yet
|
|
45
|
+
// (space means the user has moved on to arguments)
|
|
46
|
+
if (!trimmed.startsWith("/") || trimmed.includes(" ")) {
|
|
47
|
+
return createAutocompleteState();
|
|
48
|
+
}
|
|
49
|
+
const query = trimmed.slice(1); // everything after "/"
|
|
50
|
+
const matches = filterCommands(query, commands);
|
|
51
|
+
// Don't show if there's exactly one match that equals the query
|
|
52
|
+
if (matches.length === 1 && matches[0].name === query) {
|
|
53
|
+
return createAutocompleteState();
|
|
54
|
+
}
|
|
55
|
+
// Don't show if no matches
|
|
56
|
+
if (matches.length === 0) {
|
|
57
|
+
return { visible: false, matches: [], selectedIndex: 0, query };
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
visible: true,
|
|
61
|
+
matches,
|
|
62
|
+
selectedIndex: 0,
|
|
63
|
+
query,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create actions that manage autocomplete state.
|
|
68
|
+
* This is a factory for use in React state management.
|
|
69
|
+
*/
|
|
70
|
+
export function createAutocompleteActions(state, setState, commands) {
|
|
71
|
+
const accept = (index) => {
|
|
72
|
+
if (!state.visible || state.matches.length === 0)
|
|
73
|
+
return null;
|
|
74
|
+
const match = state.matches[index];
|
|
75
|
+
if (!match)
|
|
76
|
+
return null;
|
|
77
|
+
setState(createAutocompleteState());
|
|
78
|
+
return { text: `/${match.name} `, command: match.name };
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
onTab: () => {
|
|
82
|
+
if (!state.visible || state.matches.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
// If only one match, accept it immediately
|
|
85
|
+
if (state.matches.length === 1) {
|
|
86
|
+
return accept(0);
|
|
87
|
+
}
|
|
88
|
+
// Cycle to next
|
|
89
|
+
const nextIndex = (state.selectedIndex + 1) % state.matches.length;
|
|
90
|
+
setState({ ...state, selectedIndex: nextIndex });
|
|
91
|
+
return null;
|
|
92
|
+
},
|
|
93
|
+
onShiftTab: () => {
|
|
94
|
+
if (!state.visible || state.matches.length === 0)
|
|
95
|
+
return null;
|
|
96
|
+
if (state.matches.length === 1) {
|
|
97
|
+
return accept(0);
|
|
98
|
+
}
|
|
99
|
+
const nextIndex = (state.selectedIndex - 1 + state.matches.length) % state.matches.length;
|
|
100
|
+
setState({ ...state, selectedIndex: nextIndex });
|
|
101
|
+
return null;
|
|
102
|
+
},
|
|
103
|
+
onAccept: () => {
|
|
104
|
+
return accept(state.selectedIndex);
|
|
105
|
+
},
|
|
106
|
+
onDismiss: () => {
|
|
107
|
+
setState(createAutocompleteState());
|
|
108
|
+
},
|
|
109
|
+
update: (input) => {
|
|
110
|
+
const newState = computeAutocompleteState(input, commands);
|
|
111
|
+
setState(newState);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// ── React hook ──────────────────────────────────────────────────────
|
|
116
|
+
/**
|
|
117
|
+
* Hook that manages slash command autocomplete state.
|
|
118
|
+
*
|
|
119
|
+
* Usage:
|
|
120
|
+
* ```tsx
|
|
121
|
+
* const { state, actions } = useSlashAutocomplete(commands);
|
|
122
|
+
*
|
|
123
|
+
* // In your onChange handler:
|
|
124
|
+
* actions.update(newValue);
|
|
125
|
+
*
|
|
126
|
+
* // In your useInput handler:
|
|
127
|
+
* if (key.name === "tab" && acState.visible) {
|
|
128
|
+
* const result = actions.onTab();
|
|
129
|
+
* if (result) setInputValue(result.text);
|
|
130
|
+
* return;
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
import { useState, useRef } from "react";
|
|
135
|
+
export function useSlashAutocomplete(commands) {
|
|
136
|
+
const [acState, setAcState] = useState(createAutocompleteState());
|
|
137
|
+
const commandsRef = useRef(commands);
|
|
138
|
+
commandsRef.current = commands;
|
|
139
|
+
const stateRef = useRef(acState);
|
|
140
|
+
stateRef.current = acState;
|
|
141
|
+
// Stable reference — reads state/commands through refs so the object never changes
|
|
142
|
+
const actions = React.useMemo(() => {
|
|
143
|
+
const accept = (index) => {
|
|
144
|
+
const s = stateRef.current;
|
|
145
|
+
if (!s.visible || s.matches.length === 0)
|
|
146
|
+
return null;
|
|
147
|
+
const match = s.matches[index];
|
|
148
|
+
if (!match)
|
|
149
|
+
return null;
|
|
150
|
+
setAcState(createAutocompleteState());
|
|
151
|
+
return { text: `/${match.name} `, command: match.name };
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
onTab: () => {
|
|
155
|
+
const s = stateRef.current;
|
|
156
|
+
if (!s.visible || s.matches.length === 0)
|
|
157
|
+
return null;
|
|
158
|
+
if (s.matches.length === 1)
|
|
159
|
+
return accept(0);
|
|
160
|
+
const next = (s.selectedIndex + 1) % s.matches.length;
|
|
161
|
+
setAcState({ ...s, selectedIndex: next });
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
onShiftTab: () => {
|
|
165
|
+
const s = stateRef.current;
|
|
166
|
+
if (!s.visible || s.matches.length === 0)
|
|
167
|
+
return null;
|
|
168
|
+
if (s.matches.length === 1)
|
|
169
|
+
return accept(0);
|
|
170
|
+
const next = (s.selectedIndex - 1 + s.matches.length) % s.matches.length;
|
|
171
|
+
setAcState({ ...s, selectedIndex: next });
|
|
172
|
+
return null;
|
|
173
|
+
},
|
|
174
|
+
onAccept: () => accept(stateRef.current.selectedIndex),
|
|
175
|
+
onDismiss: () => setAcState(createAutocompleteState()),
|
|
176
|
+
update: (input) => {
|
|
177
|
+
const newState = computeAutocompleteState(input, commandsRef.current);
|
|
178
|
+
const cur = stateRef.current;
|
|
179
|
+
// Skip setState when nothing meaningful changed to avoid extra renders
|
|
180
|
+
if (cur.visible === newState.visible &&
|
|
181
|
+
cur.query === newState.query &&
|
|
182
|
+
cur.selectedIndex === newState.selectedIndex &&
|
|
183
|
+
cur.matches.length === newState.matches.length)
|
|
184
|
+
return;
|
|
185
|
+
setAcState(newState);
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}, []); // stable — reads through refs
|
|
189
|
+
return { state: acState, actions };
|
|
190
|
+
}
|
|
191
|
+
// ── Component ───────────────────────────────────────────────────────
|
|
192
|
+
/**
|
|
193
|
+
* Overlay rendering the list of matching slash commands.
|
|
194
|
+
* Position this above the input line.
|
|
195
|
+
*/
|
|
196
|
+
export function SlashAutocomplete({ state, maxVisible = 8, }) {
|
|
197
|
+
if (!state.visible || state.matches.length === 0) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
// Determine visible window
|
|
201
|
+
const total = state.matches.length;
|
|
202
|
+
const visible = Math.min(total, maxVisible);
|
|
203
|
+
let startIdx = 0;
|
|
204
|
+
if (state.selectedIndex >= startIdx + visible) {
|
|
205
|
+
startIdx = state.selectedIndex - visible + 1;
|
|
206
|
+
}
|
|
207
|
+
if (state.selectedIndex < startIdx) {
|
|
208
|
+
startIdx = state.selectedIndex;
|
|
209
|
+
}
|
|
210
|
+
const visibleItems = state.matches.slice(startIdx, startIdx + visible);
|
|
211
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderColor: "cyan", children: [visibleItems.map((cmd, i) => {
|
|
212
|
+
const actualIndex = startIdx + i;
|
|
213
|
+
const isSelected = actualIndex === state.selectedIndex;
|
|
214
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: isSelected ? "cyan" : undefined, bold: isSelected, dimColor: !isSelected, children: isSelected ? ">" : " " }), _jsx(Text, { color: isSelected ? "cyan" : "white", bold: isSelected, children: `/${cmd.name}` }), _jsx(Text, { dimColor: true, children: cmd.description })] }, cmd.name));
|
|
215
|
+
}), total > visible && (_jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { dimColor: true, children: `${state.selectedIndex + 1}/${total}` }) }))] }));
|
|
216
|
+
}
|
|
217
|
+
export default SlashAutocomplete;
|
|
218
|
+
//# sourceMappingURL=slash-autocomplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-autocomplete.js","sourceRoot":"","sources":["../../../src/tui/components/slash-autocomplete.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface SpinnerProps {
|
|
3
|
+
/** Label displayed after the spinner character */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** Animation interval in ms (default: 80) */
|
|
6
|
+
interval?: number;
|
|
7
|
+
/** Ink Text color for the spinner character */
|
|
8
|
+
color?: string;
|
|
9
|
+
/** When true, the spinner stops animating */
|
|
10
|
+
stopped?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Returns the current braille spinner frame, advancing every `interval` ms.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useSpinner(interval?: number): string;
|
|
16
|
+
export declare function Spinner({ label, interval, color, stopped, }: SpinnerProps): React.JSX.Element;
|
|
17
|
+
export default Spinner;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Text } from "ink";
|
|
4
|
+
// ── Braille spinner frames ──────────────────────────────────────────
|
|
5
|
+
const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
6
|
+
const DEFAULT_INTERVAL = 80;
|
|
7
|
+
// ── Hook ────────────────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Returns the current braille spinner frame, advancing every `interval` ms.
|
|
10
|
+
*/
|
|
11
|
+
export function useSpinner(interval = DEFAULT_INTERVAL) {
|
|
12
|
+
const [index, setIndex] = useState(0);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const id = setInterval(() => {
|
|
15
|
+
setIndex((prev) => (prev + 1) % FRAMES.length);
|
|
16
|
+
}, interval);
|
|
17
|
+
return () => clearInterval(id);
|
|
18
|
+
}, [interval]);
|
|
19
|
+
return FRAMES[index];
|
|
20
|
+
}
|
|
21
|
+
// ── Component ───────────────────────────────────────────────────────
|
|
22
|
+
export function Spinner({ label, interval = DEFAULT_INTERVAL, color = "cyan", stopped = false, }) {
|
|
23
|
+
const frame = useSpinner(interval);
|
|
24
|
+
if (stopped) {
|
|
25
|
+
return label ? _jsx(Text, { dimColor: true, children: label }) : _jsx(Text, { children: "" });
|
|
26
|
+
}
|
|
27
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: frame }), label ? _jsx(Text, { children: ` ${label}` }) : null] }));
|
|
28
|
+
}
|
|
29
|
+
export default Spinner;
|
|
30
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/tui/components/spinner.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAG3B,uEAAuE;AAEvE,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAC3E,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAe5B,uEAAuE;AAEvE;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,QAAQ,GAAG,gBAAgB;IACpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;YAC1B,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC,EAAE,QAAQ,CAAC,CAAC;QACb,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,uEAAuE;AAEvE,MAAM,UAAU,OAAO,CAAC,EACtB,KAAK,EACL,QAAQ,GAAG,gBAAgB,EAC3B,KAAK,GAAG,MAAM,EACd,OAAO,GAAG,KAAK,GACF;IACb,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,GAAQ,CAAC,CAAC,CAAC,KAAC,IAAI,cAAE,EAAE,GAAQ,CAAC;IACnE,CAAC;IAED,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,KAAK,GAAQ,EACjC,KAAK,CAAC,CAAC,CAAC,KAAC,IAAI,cAAE,IAAI,KAAK,EAAE,GAAQ,CAAC,CAAC,CAAC,IAAI,IACrC,CACR,CAAC;AACJ,CAAC;AAED,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type Mode = "normal" | "insert";
|
|
3
|
+
export interface SessionStats {
|
|
4
|
+
tokensUsed?: number;
|
|
5
|
+
costUsd?: number;
|
|
6
|
+
model?: string;
|
|
7
|
+
startTime?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface StatusBarProps {
|
|
10
|
+
mode: Mode;
|
|
11
|
+
breadcrumbs: string[];
|
|
12
|
+
scrollPercent?: number;
|
|
13
|
+
hint?: string;
|
|
14
|
+
/** When true, hides the mode badge (conversation view handles its own input) */
|
|
15
|
+
conversationMode?: boolean;
|
|
16
|
+
/** Session stats for token/cost/elapsed display */
|
|
17
|
+
session?: SessionStats;
|
|
18
|
+
}
|
|
19
|
+
export declare function formatTokens(n: number): string;
|
|
20
|
+
export declare function formatCost(usd: number): string;
|
|
21
|
+
export declare function formatElapsed(startTime: number, now?: number): string;
|
|
22
|
+
export declare function StatusBar({ mode, breadcrumbs, scrollPercent, hint, conversationMode, session, }: StatusBarProps): React.JSX.Element;
|
|
23
|
+
export default StatusBar;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
// --- Colors (Bubbletea scheme) ---
|
|
4
|
+
const NEX_BLUE = "#2980fb";
|
|
5
|
+
const NEX_PURPLE = "#cf72d9";
|
|
6
|
+
const MODE_NORMAL_BG = NEX_BLUE;
|
|
7
|
+
const MODE_INSERT_BG = "#03a04c";
|
|
8
|
+
// --- Formatting helpers ---
|
|
9
|
+
export function formatTokens(n) {
|
|
10
|
+
if (n < 1000)
|
|
11
|
+
return String(n);
|
|
12
|
+
if (n < 10_000)
|
|
13
|
+
return `${(n / 1000).toFixed(1)}k`;
|
|
14
|
+
if (n < 1_000_000)
|
|
15
|
+
return `${Math.round(n / 1000)}k`;
|
|
16
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
17
|
+
}
|
|
18
|
+
export function formatCost(usd) {
|
|
19
|
+
if (usd < 0.001)
|
|
20
|
+
return "$0.00";
|
|
21
|
+
if (usd < 1)
|
|
22
|
+
return `$${usd.toFixed(3)}`;
|
|
23
|
+
return `$${usd.toFixed(2)}`;
|
|
24
|
+
}
|
|
25
|
+
export function formatElapsed(startTime, now) {
|
|
26
|
+
const ms = (now ?? Date.now()) - startTime;
|
|
27
|
+
const totalSecs = Math.max(0, Math.floor(ms / 1000));
|
|
28
|
+
const mins = Math.floor(totalSecs / 60);
|
|
29
|
+
const secs = totalSecs % 60;
|
|
30
|
+
if (mins === 0)
|
|
31
|
+
return `${secs}s`;
|
|
32
|
+
return `${mins}m${String(secs).padStart(2, "0")}s`;
|
|
33
|
+
}
|
|
34
|
+
// --- Separator ---
|
|
35
|
+
const SEP = " \u2503 "; // ┃
|
|
36
|
+
// --- Session stats fragment ---
|
|
37
|
+
function SessionStatsFragment({ session }) {
|
|
38
|
+
if (!session)
|
|
39
|
+
return null;
|
|
40
|
+
return (_jsxs(_Fragment, { children: [session.tokensUsed !== undefined && session.tokensUsed > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { dimColor: true, children: "tokens " }), _jsx(Text, { children: formatTokens(session.tokensUsed) })] })), session.costUsd !== undefined && session.costUsd > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { children: formatCost(session.costUsd) })] })), session.startTime !== undefined && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { dimColor: true, children: formatElapsed(session.startTime) })] }))] }));
|
|
41
|
+
}
|
|
42
|
+
// --- Component ---
|
|
43
|
+
export function StatusBar({ mode, breadcrumbs, scrollPercent, hint, conversationMode = false, session, }) {
|
|
44
|
+
const breadcrumbText = breadcrumbs.join(" > ");
|
|
45
|
+
if (conversationMode) {
|
|
46
|
+
// Simplified bar for conversation mode — brand + tokens + cost on left, hint on right
|
|
47
|
+
return (_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: " " }), _jsx(Text, { color: NEX_PURPLE, bold: true, children: "\u258C" }), _jsx(Text, { bold: true, children: "nex" }), _jsx(SessionStatsFragment, { session: session }), scrollPercent !== undefined && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { children: `${scrollPercent}%` })] }))] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: hint || "/help for commands | Esc=back" }), _jsx(Text, { dimColor: true, children: " " })] })] }));
|
|
48
|
+
}
|
|
49
|
+
// Sub-view mode — show mode badge with Bubbletea colors
|
|
50
|
+
const modeBg = mode === "normal" ? MODE_NORMAL_BG : MODE_INSERT_BG;
|
|
51
|
+
const modeLabel = mode.toUpperCase();
|
|
52
|
+
return (_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { backgroundColor: modeBg, color: "black", bold: true, children: ` ${modeLabel} ` }), _jsx(Text, { children: " " }), _jsx(Text, { children: breadcrumbText }), scrollPercent !== undefined && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { children: `${scrollPercent}%` })] })), _jsx(SessionStatsFragment, { session: session }), hint && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: SEP }), _jsx(Text, { dimColor: true, children: hint })] }))] }), _jsxs(Box, { children: [_jsx(Text, { color: NEX_PURPLE, bold: true, children: "\u258C" }), _jsx(Text, { bold: true, children: "nex" }), _jsx(Text, { children: " " })] })] }));
|
|
53
|
+
}
|
|
54
|
+
export default StatusBar;
|
|
55
|
+
//# sourceMappingURL=status-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-bar.js","sourceRoot":"","sources":["../../../src/tui/components/status-bar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
// --- Colors ---
|
|
4
|
+
const SYS_SUCCESS = "#03a04c";
|
|
5
|
+
// --- Component ---
|
|
6
|
+
export function SuccessBox({ message, detail }) {
|
|
7
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: SYS_SUCCESS, paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: SYS_SUCCESS, bold: true, children: "✔ " }), _jsx(Text, { color: SYS_SUCCESS, children: message })] }), detail && (_jsx(Box, { marginTop: 0, children: _jsxs(Text, { dimColor: true, children: [" ", detail] }) }))] }));
|
|
8
|
+
}
|
|
9
|
+
export default SuccessBox;
|
|
10
|
+
//# sourceMappingURL=success-box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"success-box.js","sourceRoot":"","sources":["../../../src/tui/components/success-box.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,iBAAiB;AAEjB,MAAM,WAAW,GAAG,SAAS,CAAC;AAS9B,oBAAoB;AAEpB,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAmB;IAC7D,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,CAAC,aAGX,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAE,WAAW,EAAE,IAAI,kBAAE,IAAI,GAAQ,EAC5C,KAAC,IAAI,IAAC,KAAK,EAAE,WAAW,YAAG,OAAO,GAAQ,IACtC,EAGL,MAAM,IAAI,CACT,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,MAAC,IAAI,IAAC,QAAQ,mBAAE,IAAI,EAAE,MAAM,IAAQ,GAChC,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ToolStatus = "running" | "done" | "error";
|
|
3
|
+
export interface ToolIndicatorProps {
|
|
4
|
+
/** Name of the tool being executed */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Current status */
|
|
7
|
+
status: ToolStatus;
|
|
8
|
+
/** Elapsed time in seconds (shown when done) */
|
|
9
|
+
elapsed?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function ToolIndicator({ name, status, elapsed, }: ToolIndicatorProps): React.JSX.Element;
|
|
12
|
+
export default ToolIndicator;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from "ink";
|
|
3
|
+
import { useSpinner } from "./spinner.js";
|
|
4
|
+
// ── Component ───────────────────────────────────────────────────────
|
|
5
|
+
export function ToolIndicator({ name, status, elapsed, }) {
|
|
6
|
+
const frame = useSpinner();
|
|
7
|
+
if (status === "done") {
|
|
8
|
+
const time = elapsed !== undefined ? ` (${elapsed.toFixed(1)}s)` : "";
|
|
9
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "✓" }), _jsx(Text, { children: ` ${name}` }), _jsx(Text, { dimColor: true, children: time })] }));
|
|
10
|
+
}
|
|
11
|
+
if (status === "error") {
|
|
12
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: "red", children: "✗" }), _jsx(Text, { children: ` ${name}` })] }));
|
|
13
|
+
}
|
|
14
|
+
// running
|
|
15
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: frame }), _jsx(Text, { children: ` ${name}` })] }));
|
|
16
|
+
}
|
|
17
|
+
export default ToolIndicator;
|
|
18
|
+
//# sourceMappingURL=tool-indicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-indicator.js","sourceRoot":"","sources":["../../../src/tui/components/tool-indicator.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAe1C,uEAAuE;AAEvE,MAAM,UAAU,aAAa,CAAC,EAC5B,IAAI,EACJ,MAAM,EACN,OAAO,GACY;IACnB,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAE3B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,GAAG,GAAQ,EAChC,KAAC,IAAI,cAAE,IAAI,IAAI,EAAE,GAAQ,EACzB,KAAC,IAAI,IAAC,QAAQ,kBAAE,IAAI,GAAQ,IACvB,CACR,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,GAAG,GAAQ,EAC9B,KAAC,IAAI,cAAE,IAAI,IAAI,EAAE,GAAQ,IACpB,CACR,CAAC;IACJ,CAAC;IAED,UAAU;IACV,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,KAAK,GAAQ,EACjC,KAAC,IAAI,cAAE,IAAI,IAAI,EAAE,GAAQ,IACpB,CACR,CAAC;AACJ,CAAC;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface ViewportProps {
|
|
3
|
+
content: string;
|
|
4
|
+
scrollOffset: number;
|
|
5
|
+
onScroll: (offset: number) => void;
|
|
6
|
+
height?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function Viewport({ content, scrollOffset, onScroll: _onScroll, height, }: ViewportProps): React.JSX.Element;
|
|
9
|
+
export default Viewport;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
// --- Component ---
|
|
5
|
+
export function Viewport({ content, scrollOffset, onScroll: _onScroll, height, }) {
|
|
6
|
+
const effectiveHeight = height ?? 20;
|
|
7
|
+
const { visibleLines, scrollPercent, totalLines } = useMemo(() => {
|
|
8
|
+
const allLines = content.split("\n");
|
|
9
|
+
const total = allLines.length;
|
|
10
|
+
const clampedOffset = Math.max(0, Math.min(scrollOffset, Math.max(0, total - effectiveHeight)));
|
|
11
|
+
const slice = allLines.slice(clampedOffset, clampedOffset + effectiveHeight);
|
|
12
|
+
const pct = total <= effectiveHeight
|
|
13
|
+
? 100
|
|
14
|
+
: Math.round((clampedOffset / (total - effectiveHeight)) * 100);
|
|
15
|
+
return {
|
|
16
|
+
visibleLines: slice,
|
|
17
|
+
scrollPercent: pct,
|
|
18
|
+
totalLines: total,
|
|
19
|
+
};
|
|
20
|
+
}, [content, scrollOffset, effectiveHeight]);
|
|
21
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", height: effectiveHeight, children: visibleLines.map((line, i) => (_jsx(Text, { wrap: "truncate", children: line }, i))) }), totalLines > effectiveHeight && (_jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { dimColor: true, children: `${scrollPercent}%` }) }))] }));
|
|
22
|
+
}
|
|
23
|
+
export default Viewport;
|
|
24
|
+
//# sourceMappingURL=viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.js","sourceRoot":"","sources":["../../../src/tui/components/viewport.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAWhC,oBAAoB;AAEpB,MAAM,UAAU,QAAQ,CAAC,EACvB,OAAO,EACP,YAAY,EACZ,QAAQ,EAAE,SAAS,EACnB,MAAM,GACQ;IACd,MAAM,eAAe,GAAG,MAAM,IAAI,EAAE,CAAC;IAErC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAC5B,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC,CAC7D,CAAC;QACF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,EAAE,aAAa,GAAG,eAAe,CAAC,CAAC;QAE7E,MAAM,GAAG,GACP,KAAK,IAAI,eAAe;YACtB,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,CAAC,KAAK,GAAG,eAAe,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAEpE,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,GAAG;YAClB,UAAU,EAAE,KAAK;SAClB,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;IAE7C,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,MAAM,EAAE,eAAe,YAChD,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAC7B,KAAC,IAAI,IAAS,IAAI,EAAC,UAAU,YAC1B,IAAI,IADI,CAAC,CAEL,CACR,CAAC,GACE,EACL,UAAU,GAAG,eAAe,IAAI,CAC/B,KAAC,GAAG,IAAC,cAAc,EAAC,UAAU,YAC5B,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,aAAa,GAAG,GAAQ,GACvC,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 6901 JSON Pointer implementation for A2UI data binding.
|
|
3
|
+
* Provides resolve/set/apply operations over a flat data model.
|
|
4
|
+
*/
|
|
5
|
+
import type { A2UIDataModel, A2UIUpdate } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a JSON Pointer against a data object.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* resolvePointer({ user: { name: "Alice" } }, "/user/name") // "Alice"
|
|
11
|
+
* resolvePointer({ items: [{ status: "done" }] }, "/items/0/status") // "done"
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolvePointer(data: unknown, pointer: string): unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Set a value at a JSON Pointer path, creating intermediate objects as needed.
|
|
16
|
+
* Mutates the data object in place.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setPointer(data: Record<string, unknown>, pointer: string, value: unknown): void;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a string looks like a JSON Pointer (starts with "/").
|
|
21
|
+
*/
|
|
22
|
+
export declare function isPointer(value: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Apply a batch of updates to a data model.
|
|
25
|
+
* Returns a shallow copy of the model with updates applied.
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyUpdates(model: A2UIDataModel, updates: A2UIUpdate[]): A2UIDataModel;
|