@ouro.bot/cli 0.1.0-alpha.175 → 0.1.0-alpha.176

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.
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TuiStore = void 0;
4
+ exports.createTuiCallbacks = createTuiCallbacks;
5
+ /**
6
+ * TUI Store — mutable external state for the OuroTui component.
7
+ *
8
+ * Tracks two buckets:
9
+ * 1. completedMessages — fed to Ink's <Static>, rendered once
10
+ * 2. live — current turn state, re-renders on change
11
+ *
12
+ * ZERO business logic. Just state + notify.
13
+ */
14
+ const phrases_1 = require("../../mind/phrases");
15
+ const format_1 = require("../../mind/format");
16
+ const runtime_1 = require("../../nerves/runtime");
17
+ class TuiStore {
18
+ _completed = [];
19
+ _live = {
20
+ streamingText: "",
21
+ loading: false,
22
+ spinnerPhrase: "",
23
+ spinnerPhrasePool: [],
24
+ activeTool: null,
25
+ errorMessage: null,
26
+ kickMessage: null,
27
+ inputSuppressed: false,
28
+ };
29
+ _spinnerStart = 0;
30
+ _hadTool = false;
31
+ _turnId = 0;
32
+ _listeners = new Set();
33
+ _headerShown = false;
34
+ _inputHistory = [];
35
+ get completedMessages() { return this._completed; }
36
+ get live() { return this._live; }
37
+ get headerShown() { return this._headerShown; }
38
+ get inputHistory() { return this._inputHistory; }
39
+ /** Elapsed seconds since spinner started — computed on demand, not stored */
40
+ getElapsed() {
41
+ if (this._live.loading && this._spinnerStart > 0) {
42
+ return Math.floor((Date.now() - this._spinnerStart) / 1000);
43
+ }
44
+ return 0;
45
+ }
46
+ subscribe(fn) {
47
+ this._listeners.add(fn);
48
+ return () => { this._listeners.delete(fn); };
49
+ }
50
+ notify() {
51
+ for (const fn of this._listeners)
52
+ fn();
53
+ }
54
+ // ─── Called by business logic (via callbacks) ───
55
+ modelStart() {
56
+ const phrases = (0, phrases_1.getPhrases)();
57
+ const pool = this._hadTool ? phrases.followup : phrases.thinking;
58
+ this._live = {
59
+ ...this._live,
60
+ loading: true,
61
+ spinnerPhrase: (0, phrases_1.pickPhrase)(pool),
62
+ spinnerPhrasePool: pool,
63
+ streamingText: "",
64
+ activeTool: null,
65
+ errorMessage: null,
66
+ kickMessage: null,
67
+ };
68
+ this._spinnerStart = Date.now();
69
+ this._turnId++;
70
+ this.notify();
71
+ }
72
+ appendText(text) {
73
+ this._live = {
74
+ ...this._live,
75
+ loading: false,
76
+ streamingText: this._live.streamingText + text,
77
+ };
78
+ this.notify();
79
+ }
80
+ clearText() {
81
+ this._live = { ...this._live, streamingText: "" };
82
+ this.notify();
83
+ }
84
+ toolStart(name, args) {
85
+ this._hadTool = true;
86
+ // Before showing tool in-progress, commit any buffered streaming text
87
+ // so it doesn't disappear when the live area switches to tool display
88
+ if (this._live.streamingText.trim()) {
89
+ this._completed = [...this._completed, {
90
+ id: `asst-${this._turnId}-${Date.now()}`,
91
+ role: "assistant",
92
+ content: this._live.streamingText.trim(),
93
+ }];
94
+ }
95
+ this._live = {
96
+ ...this._live,
97
+ loading: true,
98
+ streamingText: "",
99
+ activeTool: { name, args },
100
+ spinnerPhrase: (0, phrases_1.pickPhrase)((0, phrases_1.getPhrases)().tool),
101
+ spinnerPhrasePool: (0, phrases_1.getPhrases)().tool,
102
+ };
103
+ this._spinnerStart = Date.now();
104
+ this.notify();
105
+ }
106
+ toolEnd(name, argSummary, success) {
107
+ // Move tool result to completed messages (so it renders via Static)
108
+ this._completed = [...this._completed, {
109
+ id: `tool-${this._turnId}-${Date.now()}`,
110
+ role: "tool",
111
+ content: "",
112
+ toolCalls: [{ name, argSummary, success }],
113
+ }];
114
+ this._live = {
115
+ ...this._live,
116
+ loading: false,
117
+ activeTool: null,
118
+ };
119
+ this.notify();
120
+ }
121
+ setError(msg) {
122
+ this._live = { ...this._live, loading: false, errorMessage: msg };
123
+ this.notify();
124
+ }
125
+ setKick() {
126
+ this._live = { ...this._live, loading: false, kickMessage: (0, format_1.formatKick)() };
127
+ this.notify();
128
+ }
129
+ suppressInput() {
130
+ this._live = { ...this._live, inputSuppressed: true };
131
+ this.notify();
132
+ }
133
+ restoreInput() {
134
+ this._live = { ...this._live, inputSuppressed: false };
135
+ this.notify();
136
+ }
137
+ /** Commit current streaming text as a completed assistant message */
138
+ commitAssistantMessage() {
139
+ if (this._live.streamingText.trim()) {
140
+ this._completed = [...this._completed, {
141
+ id: `asst-${this._turnId}-${Date.now()}`,
142
+ role: "assistant",
143
+ content: this._live.streamingText.trim(),
144
+ }];
145
+ }
146
+ // Clear streaming text immediately — prevents double display
147
+ this._live = {
148
+ ...this._live,
149
+ loading: false,
150
+ streamingText: "",
151
+ activeTool: null,
152
+ errorMessage: null,
153
+ kickMessage: null,
154
+ };
155
+ this.notify();
156
+ }
157
+ /** Add a user message to completed (for display) AND input history */
158
+ addUserMessage(text) {
159
+ if (this._completed.length === 0) {
160
+ this._headerShown = false;
161
+ }
162
+ this._completed = [...this._completed, {
163
+ id: `user-${Date.now()}`,
164
+ role: "user",
165
+ content: text,
166
+ }];
167
+ this._inputHistory.push(text);
168
+ this.notify();
169
+ }
170
+ /** Seed input history from previous session messages (display only, no rendering) */
171
+ seedHistory(texts) {
172
+ this._inputHistory.push(...texts);
173
+ }
174
+ }
175
+ exports.TuiStore = TuiStore;
176
+ // ─── Callbacks factory ──────────────────────────────────────────────
177
+ function createTuiCallbacks(store) {
178
+ (0, runtime_1.emitNervesEvent)({
179
+ component: "senses",
180
+ event: "senses.tui_callbacks_created",
181
+ message: "TUI callbacks created",
182
+ meta: {},
183
+ });
184
+ return {
185
+ onModelStart: () => { store.modelStart(); },
186
+ onModelStreamStart: () => { },
187
+ onClearText: () => { store.clearText(); },
188
+ onTextChunk: (text) => { store.appendText(text); },
189
+ onReasoningChunk: () => { },
190
+ onToolStart: (name, args) => { store.toolStart(name, args); },
191
+ onToolEnd: (name, argSummary, success) => { store.toolEnd(name, argSummary, success); },
192
+ onError: (error, severity) => {
193
+ store.setError(severity === "terminal" ? (0, format_1.formatError)(error) : error.message);
194
+ },
195
+ onKick: () => { store.setKick(); },
196
+ flushMarkdown: () => { store.commitAssistantMessage(); },
197
+ };
198
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.VirtualList = VirtualList;
37
+ const jsx_runtime_1 = require("react/jsx-runtime");
38
+ const react_1 = __importStar(require("react"));
39
+ const ink_1 = require("ink");
40
+ function VirtualList({ items, viewportHeight, scrollOffset, renderItem, }) {
41
+ const { startIndex, visibleItems } = (0, react_1.useMemo)(() => {
42
+ if (items.length === 0) {
43
+ return { startIndex: 0, visibleItems: [] };
44
+ }
45
+ // Determine the start index for the visible window
46
+ let start;
47
+ if (scrollOffset !== undefined) {
48
+ // Scroll-locked: show items starting at the given offset
49
+ start = Math.max(0, Math.min(scrollOffset, items.length - 1));
50
+ }
51
+ else {
52
+ // Auto-scroll: pin to bottom, show last viewportHeight items
53
+ start = Math.max(0, items.length - viewportHeight);
54
+ }
55
+ const end = Math.min(start + viewportHeight, items.length);
56
+ return {
57
+ startIndex: start,
58
+ visibleItems: items.slice(start, end),
59
+ };
60
+ }, [items, viewportHeight, scrollOffset]);
61
+ if (visibleItems.length === 0) {
62
+ return (0, jsx_runtime_1.jsx)(ink_1.Box, { children: (0, jsx_runtime_1.jsx)(ink_1.Text, { children: "" }) });
63
+ }
64
+ return ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: visibleItems.map((item, i) => {
65
+ const globalIndex = startIndex + i;
66
+ return ((0, jsx_runtime_1.jsx)(ink_1.Box, { children: (0, jsx_runtime_1.jsx)(ink_1.Text, { children: renderItem(item, globalIndex) }) }, globalIndex));
67
+ }) }));
68
+ }