klyro 0.1.27 → 0.1.29
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/dist/tui/app.d.ts +2 -3
- package/dist/tui/app.js +96 -100
- package/package.json +1 -1
package/dist/tui/app.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Klyro TUI — TUI_DESIGN.md §
|
|
3
|
-
*
|
|
4
|
-
* Regions: scrollback (header+turns) / live window (streaming tail+groups) / pinned (input+status)
|
|
2
|
+
* Klyro TUI — opencode-perfect — TUI_DESIGN.md §2-7 + user request: no clumsy words, smooth scroll like opencode
|
|
3
|
+
* Full-screen alt takeover when supported, inline degrade otherwise. Clean wrap at word boundaries, slider │●.
|
|
5
4
|
*/
|
|
6
5
|
import React from 'react';
|
|
7
6
|
import type { StatusSnapshot } from './status.js';
|
package/dist/tui/app.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* Klyro TUI — TUI_DESIGN.md §
|
|
4
|
-
*
|
|
5
|
-
* Regions: scrollback (header+turns) / live window (streaming tail+groups) / pinned (input+status)
|
|
3
|
+
* Klyro TUI — opencode-perfect — TUI_DESIGN.md §2-7 + user request: no clumsy words, smooth scroll like opencode
|
|
4
|
+
* Full-screen alt takeover when supported, inline degrade otherwise. Clean wrap at word boundaries, slider │●.
|
|
6
5
|
*/
|
|
7
6
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
8
7
|
import { Box, Text, useInput, useStdout } from 'ink';
|
|
@@ -11,7 +10,6 @@ import { parse as parseSlash } from '../cli/slash/parser.js';
|
|
|
11
10
|
import { tokens, g } from './tokens.js';
|
|
12
11
|
let _id = 0;
|
|
13
12
|
function nextId(p) { _id++; return `${p}-${_id}`; }
|
|
14
|
-
// ── Header §4 ───────────────────────────────────────────────────────────────
|
|
15
13
|
function Header({ cwd, model, version, width }) {
|
|
16
14
|
const branch = (() => { try {
|
|
17
15
|
const { execSync } = require('node:child_process');
|
|
@@ -21,29 +19,26 @@ function Header({ cwd, model, version, width }) {
|
|
|
21
19
|
return '';
|
|
22
20
|
} })();
|
|
23
21
|
const showLinks = width >= 120;
|
|
24
|
-
|
|
25
|
-
const ctxShort = '200k'; // TODO wire real context window
|
|
26
|
-
const row1Left = `KLYRO v${version}`;
|
|
27
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: tokens.ansi.accent, children: row1Left }), showLinks ? _jsx(Text, { color: tokens.ansi.dim, children: links }) : null] }), _jsxs(Text, { color: tokens.ansi.dim, children: [model, "[", ctxShort, "] \u00B7 API Usage Billing"] }), _jsxs(Text, { color: tokens.ansi.dim, children: [cwd, branch ? ` · ${branch}` : ''] })] }));
|
|
22
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { bold: true, color: tokens.ansi.accent, children: ["KLYRO v", version] }), showLinks ? _jsx(Text, { color: tokens.ansi.dim, children: "\u2502 /help /config /clear /exit" }) : null] }), _jsxs(Text, { color: tokens.ansi.dim, children: [model, "[200k] \u00B7 API Usage Billing"] }), _jsxs(Text, { color: tokens.ansi.dim, children: [cwd, branch ? ` · ${branch}` : ''] })] }));
|
|
28
23
|
}
|
|
29
24
|
function verbForTool(name) {
|
|
30
25
|
if (name === 'read_file')
|
|
31
|
-
return
|
|
26
|
+
return 'Read';
|
|
32
27
|
if (name === 'list_directory')
|
|
33
|
-
return
|
|
28
|
+
return 'Listed';
|
|
34
29
|
if (name === 'grep' || name === 'glob' || name === 'find_files' || name === 'search_files' || name === 'recent_files')
|
|
35
|
-
return
|
|
30
|
+
return 'Searched';
|
|
36
31
|
if (name === 'shell_exec')
|
|
37
|
-
return
|
|
32
|
+
return 'Ran';
|
|
38
33
|
if (name.startsWith('git_'))
|
|
39
|
-
return
|
|
34
|
+
return 'Checked git';
|
|
40
35
|
if (name === 'web_fetch')
|
|
41
|
-
return
|
|
36
|
+
return 'Fetched';
|
|
42
37
|
if (name === 'web_search')
|
|
43
|
-
return
|
|
38
|
+
return 'Searched web';
|
|
44
39
|
if (name === 'edit_file' || name === 'multi_edit' || name === 'apply_patch' || name === 'write_file')
|
|
45
|
-
return
|
|
46
|
-
return
|
|
40
|
+
return 'Edited';
|
|
41
|
+
return 'Called';
|
|
47
42
|
}
|
|
48
43
|
function groupTools(items) {
|
|
49
44
|
const out = [];
|
|
@@ -51,10 +46,9 @@ function groupTools(items) {
|
|
|
51
46
|
const flush = () => {
|
|
52
47
|
if (cur.length === 0)
|
|
53
48
|
return;
|
|
54
|
-
// bucket by verb
|
|
55
49
|
const byVerb = new Map();
|
|
56
50
|
for (const it of cur) {
|
|
57
|
-
const v = verbForTool(it.name)
|
|
51
|
+
const v = verbForTool(it.name);
|
|
58
52
|
if (!byVerb.has(v))
|
|
59
53
|
byVerb.set(v, []);
|
|
60
54
|
byVerb.get(v).push(it);
|
|
@@ -77,7 +71,6 @@ function groupTools(items) {
|
|
|
77
71
|
flush();
|
|
78
72
|
return out;
|
|
79
73
|
}
|
|
80
|
-
// ── Main App §3 ────────────────────────────────────────────────────────────
|
|
81
74
|
export function App(props) {
|
|
82
75
|
const { stdout } = useStdout();
|
|
83
76
|
const [transcript, setTranscript] = useState(props.initialTranscript ?? []);
|
|
@@ -87,17 +80,27 @@ export function App(props) {
|
|
|
87
80
|
const [plan, setPlan] = useState([]);
|
|
88
81
|
const [status, setStatus] = useState({ model: props.initialModel, step: 0, maxSteps: props.maxSteps, usageInput: 0, usageOutput: 0, repairs: 0, status: 'idle', ...props.initialStatus });
|
|
89
82
|
const [elapsed, setElapsed] = useState(0);
|
|
90
|
-
const [
|
|
83
|
+
const [queuedInputs, setQueuedInputs] = useState([]);
|
|
91
84
|
const [expandedGroups, setExpandedGroups] = useState(new Set());
|
|
92
85
|
const [scrollOffset, setScrollOffset] = useState(0);
|
|
93
86
|
const streamingIdRef = useRef(null);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
87
|
+
const placeholder = 'Message Klyro…';
|
|
88
|
+
const width = stdout?.columns ?? 100;
|
|
89
|
+
const height = stdout?.rows ?? 30;
|
|
90
|
+
const isFullscreen = props.isFullscreen ?? false;
|
|
91
|
+
const viewportH = Math.max(5, height - 10);
|
|
92
|
+
const grouped = groupTools(transcript);
|
|
93
|
+
const totalRows = grouped.length + (plan.length > 0 ? 1 : 0) + 2;
|
|
94
|
+
const maxOffset = Math.max(0, totalRows - viewportH);
|
|
95
|
+
const isAtBottom = scrollOffset >= maxOffset;
|
|
96
|
+
const trackH = viewportH;
|
|
97
|
+
const thumbPos = maxOffset === 0 ? 0 : Math.round((scrollOffset / maxOffset) * (trackH - 1));
|
|
98
|
+
const visibleGrouped = isFullscreen ? grouped.slice(scrollOffset, scrollOffset + viewportH) : grouped;
|
|
96
99
|
useEffect(() => bridge.subscribe((p) => setAwaitingApproval(p !== null)), [bridge]);
|
|
97
100
|
useEffect(() => {
|
|
98
|
-
if (
|
|
99
|
-
const toSend =
|
|
100
|
-
|
|
101
|
+
if (queuedInputs.length > 0 && status.status !== 'running' && !awaitingApproval) {
|
|
102
|
+
const toSend = queuedInputs[0];
|
|
103
|
+
setQueuedInputs((prev) => prev.slice(1));
|
|
101
104
|
setTranscript((prev) => [...prev, { id: nextId('user'), kind: 'text', text: toSend, role: 'user' }]);
|
|
102
105
|
streamingIdRef.current = null;
|
|
103
106
|
const cmd = parseSlash(toSend.trim());
|
|
@@ -106,35 +109,20 @@ export function App(props) {
|
|
|
106
109
|
else
|
|
107
110
|
void props.onSlash(cmd);
|
|
108
111
|
}
|
|
109
|
-
}, [
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}, [status.status, elapsed]);
|
|
117
|
-
const append = useCallback((item) => {
|
|
118
|
-
if (item.kind !== 'text' || item.role !== 'assistant')
|
|
119
|
-
streamingIdRef.current = null;
|
|
120
|
-
setTranscript((prev) => [...prev, item]);
|
|
121
|
-
}, []);
|
|
112
|
+
}, [queuedInputs, status.status, awaitingApproval]);
|
|
113
|
+
useEffect(() => { if (status.status !== 'running')
|
|
114
|
+
return; const start = Date.now() - elapsed; const t = setInterval(() => setElapsed(Date.now() - start), 1000); return () => clearInterval(t); }, [status.status, elapsed]);
|
|
115
|
+
useEffect(() => { if (isAtBottom)
|
|
116
|
+
setScrollOffset(maxOffset); }, [transcript.length, plan.length, maxOffset, isAtBottom]);
|
|
117
|
+
const append = useCallback((item) => { if (item.kind !== 'text' || item.role !== 'assistant')
|
|
118
|
+
streamingIdRef.current = null; setTranscript((prev) => [...prev, item]); }, []);
|
|
122
119
|
const appendDelta = useCallback((text) => {
|
|
123
120
|
if (!text)
|
|
124
121
|
return;
|
|
125
122
|
const sid = streamingIdRef.current;
|
|
126
|
-
if (sid)
|
|
127
|
-
setTranscript((prev) => {
|
|
128
|
-
const idx = prev
|
|
129
|
-
if (idx === -1)
|
|
130
|
-
return [...prev, { id: sid, kind: 'text', text, role: 'assistant' }];
|
|
131
|
-
const cur = prev[idx];
|
|
132
|
-
const next = { ...cur, text: cur.text + text };
|
|
133
|
-
const copy = [...prev];
|
|
134
|
-
copy[idx] = next;
|
|
135
|
-
return copy;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
123
|
+
if (sid)
|
|
124
|
+
setTranscript((prev) => { const idx = prev.findIndex((x) => x.id === sid); if (idx === -1)
|
|
125
|
+
return [...prev, { id: sid, kind: 'text', text, role: 'assistant' }]; const cur = prev[idx]; const copy = [...prev]; copy[idx] = { ...cur, text: cur.text + text }; return copy; });
|
|
138
126
|
else {
|
|
139
127
|
const id = nextId('stream');
|
|
140
128
|
streamingIdRef.current = id;
|
|
@@ -147,32 +135,18 @@ export function App(props) {
|
|
|
147
135
|
const updatePlan = useCallback((p) => setPlan(p), []);
|
|
148
136
|
const onMountedRef = useRef(props.onMounted);
|
|
149
137
|
useEffect(() => { onMountedRef.current = props.onMounted; }, [props.onMounted]);
|
|
150
|
-
useEffect(() => {
|
|
151
|
-
onMountedRef.current?.({ append, appendDelta, updateStatus, updatePlan });
|
|
152
|
-
globalThis.__klyroAppAppend = append;
|
|
153
|
-
globalThis.__klyroAppendDelta = appendDelta;
|
|
154
|
-
globalThis.__klyroAppStatus = updateStatus;
|
|
155
|
-
globalThis.__klyroAppPlan = updatePlan;
|
|
156
|
-
return () => { delete globalThis.__klyroAppAppend; delete globalThis.__klyroAppendDelta; delete globalThis.__klyroAppStatus; delete globalThis.__klyroAppPlan; };
|
|
157
|
-
}, [append, appendDelta, updateStatus, updatePlan]);
|
|
138
|
+
useEffect(() => { onMountedRef.current?.({ append, appendDelta, updateStatus, updatePlan }); globalThis.__klyroAppAppend = append; globalThis.__klyroAppendDelta = appendDelta; globalThis.__klyroAppStatus = updateStatus; globalThis.__klyroAppPlan = updatePlan; return () => { delete globalThis.__klyroAppAppend; delete globalThis.__klyroAppendDelta; delete globalThis.__klyroAppStatus; delete globalThis.__klyroAppPlan; }; }, [append, appendDelta, updateStatus, updatePlan]);
|
|
158
139
|
const toggleGroup = (id) => setExpandedGroups((prev) => { const n = new Set(prev); if (n.has(id))
|
|
159
140
|
n.delete(id);
|
|
160
141
|
else
|
|
161
142
|
n.add(id); return n; });
|
|
162
|
-
const width = stdout?.columns ?? 100;
|
|
163
|
-
const height = stdout?.rows ?? 30;
|
|
164
|
-
const isFullscreen = props.isFullscreen ?? false;
|
|
165
|
-
const grouped = groupTools(transcript);
|
|
166
|
-
const viewportH = Math.max(5, height - 10);
|
|
167
|
-
const totalRows = grouped.length + (plan.length > 0 ? 1 : 0) + 2;
|
|
168
|
-
const maxOffset = Math.max(0, totalRows - viewportH);
|
|
169
|
-
const isAtBottom = scrollOffset >= maxOffset;
|
|
170
|
-
useEffect(() => { if (isAtBottom)
|
|
171
|
-
setScrollOffset(maxOffset); }, [transcript.length, plan.length, maxOffset, isAtBottom]);
|
|
172
143
|
const scrollUp = (n = 3) => setScrollOffset((p) => Math.max(0, p - n));
|
|
173
144
|
const scrollDown = (n = 3) => setScrollOffset((p) => Math.min(maxOffset, p + n));
|
|
174
145
|
useInput((inputStr, key) => {
|
|
175
|
-
|
|
146
|
+
if (key.escape && queuedInputs.length > 0) {
|
|
147
|
+
setQueuedInputs((prev) => prev.slice(1));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
176
150
|
if (key.pageUp || (key.ctrl && inputStr === 'u')) {
|
|
177
151
|
scrollUp(5);
|
|
178
152
|
return;
|
|
@@ -192,7 +166,7 @@ export function App(props) {
|
|
|
192
166
|
if (awaitingApproval)
|
|
193
167
|
return;
|
|
194
168
|
if (key.ctrl && inputStr === 'o') {
|
|
195
|
-
const groups =
|
|
169
|
+
const groups = grouped.filter((x) => typeof x.verb === 'string');
|
|
196
170
|
const last = groups[groups.length - 1];
|
|
197
171
|
if (last)
|
|
198
172
|
toggleGroup(last.id);
|
|
@@ -207,9 +181,10 @@ export function App(props) {
|
|
|
207
181
|
const v = input.trim();
|
|
208
182
|
if (!v)
|
|
209
183
|
return;
|
|
210
|
-
|
|
184
|
+
if (queuedInputs.length >= 3)
|
|
185
|
+
return; // max 3 queued per §6.6
|
|
186
|
+
setQueuedInputs((prev) => [...prev, v]);
|
|
211
187
|
setInput('');
|
|
212
|
-
setTranscript((prev) => [...prev, { id: nextId('queued'), kind: 'text', text: `queued: ${v.slice(0, 80)}`, role: 'assistant' }]);
|
|
213
188
|
return;
|
|
214
189
|
}
|
|
215
190
|
if (key.backspace || key.delete) {
|
|
@@ -241,37 +216,37 @@ export function App(props) {
|
|
|
241
216
|
if (!key.ctrl && !key.meta)
|
|
242
217
|
setInput((v) => v + inputStr);
|
|
243
218
|
});
|
|
244
|
-
const
|
|
245
|
-
const ver = props.version ?? '0.1.24';
|
|
219
|
+
const ver = props.version ?? '0.1.27';
|
|
246
220
|
const rule = g('rule').repeat(Math.max(10, width - 2));
|
|
247
|
-
// Derived status right
|
|
248
221
|
const cost = (status.usageInput / 1000 * 0.003 + status.usageOutput / 1000 * 0.015);
|
|
249
222
|
const totalTokens = status.usageInput + status.usageOutput;
|
|
250
223
|
const ctxPct = totalTokens > 0 ? Math.round((totalTokens / 120_000) * 100) : 0;
|
|
251
|
-
const baseHints = status.status === 'running' ? 'ctrl+c to stop · enter to queue · ctrl+o expand' :
|
|
224
|
+
const baseHints = status.status === 'running' ? 'ctrl+c to stop · enter to queue · ctrl+o expand' : transcript.length === 0 ? 'shift+tab to cycle · ↑↓ for history · / for commands' : 'enter to send · shift+enter newline · @ to attach';
|
|
252
225
|
const hints = maxOffset > 0 && isFullscreen ? `${baseHints} · PgUp/Dn scroll` : baseHints;
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
const thumbPos = maxOffset === 0 ? 0 : Math.round((scrollOffset / maxOffset) * (trackH - 1));
|
|
226
|
+
// wrap width: leave 6 cells for guide+indent+scrollbar so words never clump
|
|
227
|
+
const wrapW = Math.max(20, width - 6);
|
|
256
228
|
return (_jsxs(Box, { flexDirection: "column", width: width, height: isFullscreen ? height - 1 : undefined, children: [_jsx(Header, { cwd: props.cwd, model: status.model, version: ver, width: width }), _jsxs(Box, { flexDirection: "row", flexGrow: isFullscreen ? 1 : 0, overflow: isFullscreen ? 'hidden' : undefined, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: isFullscreen ? 'hidden' : undefined, paddingX: 0, children: [grouped.length === 0 ? (_jsx(Text, { color: tokens.ansi.dim, children: placeholder })) : visibleGrouped.map((item) => {
|
|
257
229
|
if (item.verb) {
|
|
258
230
|
const gr = item;
|
|
259
231
|
const isExpanded = expandedGroups.has(gr.id);
|
|
260
|
-
const marker = isExpanded ? g('expanded') : g('collapsed');
|
|
261
232
|
const verbLine = (() => {
|
|
262
233
|
if (gr.items.length === 1) {
|
|
263
234
|
const it = gr.items[0];
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
235
|
+
let p = '';
|
|
236
|
+
try {
|
|
237
|
+
const a = JSON.parse(it.args);
|
|
238
|
+
p = a.path ?? a.pattern ?? a.command?.slice(0, 48) ?? '';
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
p = '';
|
|
242
|
+
}
|
|
243
|
+
if (gr.verb === 'Read' && p)
|
|
244
|
+
return `Read ${p.split('/').pop()}`;
|
|
245
|
+
if (gr.verb === 'Searched' && p)
|
|
246
|
+
return `Searched "${p}"`;
|
|
247
|
+
if (gr.verb === 'Ran' && p)
|
|
248
|
+
return `Ran ${p.split(' ')[0]}`;
|
|
249
|
+
return `${gr.verb} ${p}`;
|
|
275
250
|
}
|
|
276
251
|
if (gr.verb === 'Read')
|
|
277
252
|
return `Read ${gr.items.length} files`;
|
|
@@ -279,30 +254,51 @@ export function App(props) {
|
|
|
279
254
|
return `Searched ${gr.items.length} patterns`;
|
|
280
255
|
if (gr.verb === 'Ran')
|
|
281
256
|
return `Ran ${gr.items.length} commands`;
|
|
282
|
-
if (gr.verb === 'Edited'
|
|
283
|
-
return
|
|
257
|
+
if (gr.verb === 'Edited')
|
|
258
|
+
return `Edited ${gr.items.length} files`;
|
|
284
259
|
return `${gr.verb} ${gr.items.length} items`;
|
|
285
260
|
})();
|
|
286
261
|
const right = gr.status === 'running' ? `${(elapsed / 1000).toFixed(1)}s` : gr.status === 'error' ? '✗' : `${gr.totalMs}ms`;
|
|
287
|
-
|
|
262
|
+
const marker = isExpanded ? '▼' : '✓';
|
|
263
|
+
const markerColor = gr.status === 'error' ? tokens.ansi.err : gr.status === 'running' ? tokens.ansi.warn : tokens.ansi.ok;
|
|
264
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { color: markerColor, children: [marker, " ", verbLine] }), _jsxs(Text, { color: tokens.ansi.dim, children: [" ", right] })] }), isExpanded ? gr.items.map((it) => {
|
|
265
|
+
let friendly = '';
|
|
266
|
+
try {
|
|
267
|
+
const a = JSON.parse(it.args);
|
|
268
|
+
const p = a.path ?? a.pattern ?? a.command ?? '';
|
|
269
|
+
const short = p ? String(p).split('/').pop()?.slice(0, 40) ?? p : '';
|
|
270
|
+
if (it.name === 'read_file' && short)
|
|
271
|
+
friendly = `${short} ${it.result ? String(it.result).split('\n').length + ' lines' : ''}`.trim();
|
|
272
|
+
else if (it.name === 'shell_exec' && p)
|
|
273
|
+
friendly = `$ ${String(p).slice(0, 40)}`;
|
|
274
|
+
else if (short)
|
|
275
|
+
friendly = short;
|
|
276
|
+
else
|
|
277
|
+
friendly = it.args.slice(0, 40);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
friendly = it.args.slice(0, 40);
|
|
281
|
+
}
|
|
282
|
+
return (_jsxs(Box, { paddingLeft: 4, children: [_jsxs(Text, { color: tokens.ansi.guide, children: [g('end'), " "] }), _jsx(Text, { color: tokens.ansi.dim, children: friendly }), it.isError ? _jsx(Text, { color: tokens.ansi.err, children: " \u2717" }) : null] }, it.id));
|
|
283
|
+
}) : null] }, gr.id));
|
|
288
284
|
}
|
|
289
285
|
const it = item;
|
|
290
286
|
if (it.kind === 'text' && it.role === 'user') {
|
|
291
|
-
return _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: tokens.ansi.accent, bold: true, children: [g('prompt'), " "] }), _jsx(Text, { children: it.text })] }, it.id);
|
|
287
|
+
return _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: tokens.ansi.accent, bold: true, children: [g('prompt'), " "] }), _jsx(Text, { wrap: "wrap", children: it.text })] }, it.id);
|
|
292
288
|
}
|
|
293
289
|
if (it.kind === 'text') {
|
|
294
290
|
if (it.text.startsWith('queued:'))
|
|
295
291
|
return _jsx(Box, { paddingLeft: 2, marginBottom: 1, children: _jsxs(Text, { color: tokens.ansi.dim, children: [" ", g('guide'), " ", it.text, " esc to drop"] }) }, it.id);
|
|
296
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { color: tokens.ansi.accent, children: [g('agentBullet'), " Klyro"] })] }), _jsxs(Box, { paddingLeft: 2,
|
|
292
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { color: tokens.ansi.accent, children: [g('agentBullet'), " Klyro"] })] }), _jsxs(Box, { paddingLeft: 2, children: [_jsxs(Text, { color: tokens.ansi.dim, children: [" ", g('guide'), " "] }), _jsx(Text, { wrap: "wrap", children: it.text })] })] }, it.id));
|
|
297
293
|
}
|
|
298
294
|
if (it.kind === 'error')
|
|
299
295
|
return _jsx(Box, { paddingLeft: 2, marginBottom: 1, children: _jsxs(Text, { color: tokens.ansi.err, children: [" ", g('guide'), " \u2717 ", it.message] }) }, it.id);
|
|
300
296
|
if (it.kind === 'policy')
|
|
301
|
-
return
|
|
297
|
+
return null;
|
|
302
298
|
if (it.kind === 'file_changed')
|
|
303
299
|
return _jsx(Box, { paddingLeft: 2, marginBottom: 1, children: _jsxs(Text, { color: tokens.ansi.dim, children: [" ", g('guide'), " ", g('editsBadge'), " ", it.path, " ", it.op] }) }, it.id);
|
|
304
300
|
if (it.kind === 'diff')
|
|
305
301
|
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: tokens.ansi.soft, children: it.summary ?? 'Diff' }), it.hunks.map((h, i) => (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: tokens.ansi.soft, children: h.path }), h.lines.map((l, j) => (_jsxs(Text, { wrap: "wrap", color: l.kind === 'add' ? tokens.ansi.ok : l.kind === 'remove' ? tokens.ansi.err : tokens.ansi.dim, children: [l.kind === 'add' ? '+ ' : l.kind === 'remove' ? '- ' : ' ', l.text] }, j)))] }, i)))] }, it.id));
|
|
306
302
|
return null;
|
|
307
|
-
}), status.status === 'running' && !streamingIdRef.current ? (_jsxs(Box, { paddingLeft: 2, marginBottom: 1, children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsx(Text, { color: tokens.ansi.dim, children: "Thinking..." }), _jsxs(Text, { color: tokens.ansi.dim, children: [" ", (elapsed / 1000).toFixed(1), "s"] })] })) : null, plan.length > 0 ? (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginTop: 0, marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { bold: true, children: [g('todoPlan'), " Plan ", plan.filter((p) => p.status === 'done').length, "/", plan.length] })] }), plan.slice(0, 8).map((p) => (_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { color: p.status === 'done' ? tokens.ansi.ok : p.status === 'in_progress' ? tokens.ansi.accent : tokens.ansi.dim, children: [p.status === 'done' ? g('todoDone') : p.status === 'in_progress' ? g('todoActive') : g('todoPending'), " ", p.title] })] }, p.id)))
|
|
303
|
+
}), status.status === 'running' && !streamingIdRef.current ? (_jsxs(Box, { paddingLeft: 2, marginBottom: 1, children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsx(Text, { color: tokens.ansi.dim, children: "Thinking..." }), _jsxs(Text, { color: tokens.ansi.dim, children: [" ", (elapsed / 1000).toFixed(1), "s"] })] })) : null, plan.length > 0 ? (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, marginTop: 0, marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { bold: true, children: [g('todoPlan'), " Plan ", plan.filter((p) => p.status === 'done').length, "/", plan.length] })] }), plan.slice(0, 8).map((p) => (_jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.guide, children: [" ", g('guide'), " "] }), _jsxs(Text, { color: p.status === 'done' ? tokens.ansi.ok : p.status === 'in_progress' ? tokens.ansi.accent : tokens.ansi.dim, children: [p.status === 'done' ? g('todoDone') : p.status === 'in_progress' ? g('todoActive') : g('todoPending'), " ", p.title] })] }, p.id)))] })) : null, queuedInputs.length > 0 ? (_jsx(Box, { flexDirection: "column", paddingLeft: 2, marginBottom: 1, children: queuedInputs.map((q, i) => (_jsxs(Text, { color: tokens.ansi.dim, children: ["queued: ", q.slice(0, 60), i === 0 ? ' esc to drop' : ''] }, i))) })) : null] }), isFullscreen ? (_jsx(Box, { flexDirection: "column", width: 1, marginLeft: 1, children: Array.from({ length: trackH }).map((_, i) => (_jsx(Text, { color: i === thumbPos ? tokens.ansi.accent : tokens.ansi.guide, children: i === thumbPos ? '●' : '│' }, i))) })) : null] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: tokens.ansi.guide, children: rule }), _jsxs(Box, { children: [_jsxs(Text, { color: tokens.ansi.accent, bold: true, children: [g('prompt'), " "] }), _jsxs(Text, { wrap: "wrap", children: [input || _jsx(Text, { color: tokens.ansi.dim, children: placeholder }), "\u258F"] })] }), _jsx(Text, { color: tokens.ansi.guide, children: rule })] }), _jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: tokens.ansi.dim, children: hints }), _jsxs(Text, { color: tokens.ansi.dim, children: [cost > 0 ? `$${cost.toFixed(2)} · ` : '', ctxPct > 0 ? `${ctxPct}% ctx · ` : '', status.status === 'running' ? 'auto mode on ●' : ''] })] })] }));
|
|
308
304
|
}
|