@ouro.bot/cli 0.1.0-alpha.243 → 0.1.0-alpha.244

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.243",
3
+ "version": "0.1.0-alpha.244",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",
@@ -1,274 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CliStore = void 0;
4
- exports.createInkCallbacks = createInkCallbacks;
5
- exports.InkCliApp = InkCliApp;
6
- const jsx_runtime_1 = require("react/jsx-runtime");
7
- const react_1 = require("react");
8
- const ink_1 = require("ink");
9
- const streaming_markdown_1 = require("./streaming-markdown");
10
- const spinner_1 = require("./spinner");
11
- const tool_render_1 = require("./tool-render");
12
- const phrases_1 = require("../../mind/phrases");
13
- const format_1 = require("../../mind/format");
14
- const runtime_1 = require("../../nerves/runtime");
15
- /**
16
- * Ink CLI Adapter — bridges RunCliSessionOptions with Ink/React rendering.
17
- *
18
- * Architecture:
19
- * - CliStore: mutable external state, updated by callbacks
20
- * - InkCliApp: reads from store via subscription, renders Ink components
21
- * - createInkCallbacks: returns ChannelCallbacks that update the store
22
- *
23
- * The business logic (runAgent, pipeline, commands) stays unchanged.
24
- * Only the rendering layer is replaced: readline -> Ink.
25
- */
26
- // Ouroboros brand palette
27
- const OURO_GREEN = "#2ecc40";
28
- const OURO_TEAL = "#4ec9b0";
29
- /**
30
- * Mutable external store. Callbacks mutate state; React subscribes via
31
- * useSyncExternalStore pattern (simplified: we use a version counter +
32
- * forceUpdate in the component).
33
- */
34
- class CliStore {
35
- state = {
36
- streamingText: "",
37
- loading: false,
38
- spinnerPhrase: "",
39
- activeTool: null,
40
- toolResults: [],
41
- errorMessage: null,
42
- kickMessage: null,
43
- inputSuppressed: false,
44
- bannerLines: [],
45
- };
46
- listeners = new Set();
47
- spinnerStartTime = 0;
48
- hadToolRun = false;
49
- getState() {
50
- return this.state;
51
- }
52
- subscribe(listener) {
53
- this.listeners.add(listener);
54
- return () => { this.listeners.delete(listener); };
55
- }
56
- notify() {
57
- for (const fn of this.listeners)
58
- fn();
59
- }
60
- // ─── Mutation methods called by callbacks ───
61
- modelStart() {
62
- const phrases = (0, phrases_1.getPhrases)();
63
- const pool = this.hadToolRun ? phrases.followup : phrases.thinking;
64
- const first = (0, phrases_1.pickPhrase)(pool);
65
- this.state = {
66
- ...this.state,
67
- loading: true,
68
- spinnerPhrase: first,
69
- streamingText: "",
70
- activeTool: null,
71
- toolResults: [],
72
- errorMessage: null,
73
- kickMessage: null,
74
- };
75
- this.spinnerStartTime = Date.now();
76
- this.notify();
77
- }
78
- clearText() {
79
- this.state = { ...this.state, streamingText: "" };
80
- this.notify();
81
- }
82
- appendText(text) {
83
- this.state = {
84
- ...this.state,
85
- loading: false,
86
- streamingText: this.state.streamingText + text,
87
- };
88
- this.notify();
89
- }
90
- toolStart(name, args) {
91
- this.hadToolRun = true;
92
- this.state = {
93
- ...this.state,
94
- loading: true,
95
- activeTool: { name, args },
96
- spinnerPhrase: (0, phrases_1.pickPhrase)((0, phrases_1.getPhrases)().tool),
97
- };
98
- this.spinnerStartTime = Date.now();
99
- this.notify();
100
- }
101
- toolEnd(name, argSummary, success) {
102
- this.state = {
103
- ...this.state,
104
- loading: false,
105
- activeTool: null,
106
- toolResults: [...this.state.toolResults, { name, argSummary, success }],
107
- };
108
- this.notify();
109
- }
110
- setError(message) {
111
- this.state = { ...this.state, loading: false, errorMessage: message };
112
- this.notify();
113
- }
114
- setKick() {
115
- this.state = { ...this.state, loading: false, kickMessage: (0, format_1.formatKick)() };
116
- this.notify();
117
- }
118
- suppressInput() {
119
- this.state = { ...this.state, inputSuppressed: true };
120
- this.notify();
121
- }
122
- restoreInput() {
123
- this.state = { ...this.state, inputSuppressed: false };
124
- this.notify();
125
- }
126
- /** Flush streaming state at end of turn */
127
- endTurn() {
128
- this.state = {
129
- ...this.state,
130
- loading: false,
131
- activeTool: null,
132
- errorMessage: null,
133
- kickMessage: null,
134
- };
135
- this.notify();
136
- }
137
- setBanner(lines) {
138
- this.state = { ...this.state, bannerLines: lines };
139
- this.notify();
140
- }
141
- getElapsedSeconds() {
142
- if (!this.state.loading)
143
- return 0;
144
- return Math.floor((Date.now() - this.spinnerStartTime) / 1000);
145
- }
146
- }
147
- exports.CliStore = CliStore;
148
- // ─── Callbacks factory ─────────────────────────────────────────────
149
- function createInkCallbacks(store) {
150
- (0, runtime_1.emitNervesEvent)({
151
- component: "senses",
152
- event: "senses.cli_callbacks_created",
153
- message: "ink cli callbacks created",
154
- meta: {},
155
- });
156
- return {
157
- onModelStart: () => { store.modelStart(); },
158
- onModelStreamStart: () => { },
159
- onClearText: () => { store.clearText(); },
160
- onTextChunk: (text) => { store.appendText(text); },
161
- onReasoningChunk: (_text) => { },
162
- onToolStart: (name, args) => { store.toolStart(name, args); },
163
- onToolEnd: (name, argSummary, success) => { store.toolEnd(name, argSummary, success); },
164
- onError: (error, severity) => {
165
- if (severity === "transient") {
166
- store.setError(error.message);
167
- }
168
- else {
169
- store.setError((0, format_1.formatError)(error));
170
- }
171
- },
172
- onKick: () => { store.setKick(); },
173
- flushMarkdown: () => { store.endTurn(); },
174
- };
175
- }
176
- // ─── Input Area ────────────────────────────────────────────────────
177
- function InputArea({ onSubmit, suppressed, }) {
178
- const [input, setInput] = (0, react_1.useState)("");
179
- const inputRef = (0, react_1.useRef)("");
180
- const [history, setHistory] = (0, react_1.useState)([]);
181
- const historyIdx = (0, react_1.useRef)(-1);
182
- (0, ink_1.useInput)((inputChar, key) => {
183
- if (suppressed)
184
- return;
185
- if (key.return) {
186
- const text = inputRef.current;
187
- if (text.trim()) {
188
- onSubmit(text);
189
- setHistory(prev => {
190
- const next = [...prev, text];
191
- return next;
192
- });
193
- historyIdx.current = -1;
194
- }
195
- inputRef.current = "";
196
- setInput("");
197
- return;
198
- }
199
- if (key.backspace || key.delete) {
200
- inputRef.current = inputRef.current.slice(0, -1);
201
- setInput(inputRef.current);
202
- return;
203
- }
204
- // History navigation
205
- if (key.upArrow) {
206
- if (history.length > 0) {
207
- const idx = historyIdx.current < 0 ? history.length - 1 : Math.max(0, historyIdx.current - 1);
208
- historyIdx.current = idx;
209
- inputRef.current = history[idx];
210
- setInput(history[idx]);
211
- }
212
- return;
213
- }
214
- if (key.downArrow) {
215
- if (historyIdx.current >= 0) {
216
- const idx = historyIdx.current + 1;
217
- if (idx >= history.length) {
218
- historyIdx.current = -1;
219
- inputRef.current = "";
220
- setInput("");
221
- }
222
- else {
223
- historyIdx.current = idx;
224
- inputRef.current = history[idx];
225
- setInput(history[idx]);
226
- }
227
- }
228
- return;
229
- }
230
- if (!key.ctrl && !key.meta && inputChar) {
231
- inputRef.current += inputChar;
232
- setInput(inputRef.current);
233
- }
234
- });
235
- if (suppressed) {
236
- return (0, jsx_runtime_1.jsx)(ink_1.Text, { children: "" });
237
- }
238
- return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: input })] }));
239
- }
240
- function InkCliApp({ store, onSubmit, onExit }) {
241
- const { exit } = (0, ink_1.useApp)();
242
- const [, forceUpdate] = (0, react_1.useState)(0);
243
- const [elapsed, setElapsed] = (0, react_1.useState)(0);
244
- // Subscribe to store changes
245
- (0, react_1.useEffect)(() => {
246
- return store.subscribe(() => {
247
- forceUpdate(n => n + 1);
248
- });
249
- }, [store]);
250
- // Elapsed timer for spinner
251
- (0, react_1.useEffect)(() => {
252
- const iv = setInterval(() => {
253
- setElapsed(store.getElapsedSeconds());
254
- }, 1000);
255
- return () => clearInterval(iv);
256
- }, [store]);
257
- // Ctrl-C handling
258
- (0, ink_1.useInput)((_input, key) => {
259
- if (key.ctrl && _input === "c") {
260
- if (onExit) {
261
- onExit();
262
- }
263
- else {
264
- exit();
265
- }
266
- }
267
- });
268
- const state = store.getState();
269
- return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [state.bannerLines.length > 0 ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: state.bannerLines.map((line, i) => ((0, jsx_runtime_1.jsx)(ink_1.Text, { children: line }, i))) })) : null, state.streamingText ? ((0, jsx_runtime_1.jsx)(streaming_markdown_1.StreamingMarkdown, { text: state.streamingText })) : null, state.toolResults.map((tr, i) => {
270
- const color = tr.success ? OURO_GREEN : "#e74c3c";
271
- const icon = tr.success ? "\u2713" : "\u2717";
272
- return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { color: color, children: [icon, " "] }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: tr.name }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", tr.argSummary] })] }, i));
273
- }), state.activeTool ? ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(tool_render_1.ToolBadge, { name: state.activeTool.name }), (0, jsx_runtime_1.jsx)(tool_render_1.ToolParams, { name: state.activeTool.name, args: state.activeTool.args })] })) : null, state.loading ? ((0, jsx_runtime_1.jsx)(spinner_1.EnhancedSpinner, { elapsedSeconds: elapsed, phrase: state.spinnerPhrase })) : null, state.errorMessage ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "#e74c3c", children: state.errorMessage })) : null, state.kickMessage ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "#f39c12", children: state.kickMessage })) : null, (0, jsx_runtime_1.jsx)(InputArea, { onSubmit: onSubmit, suppressed: state.inputSuppressed })] }));
274
- }