xgen-dex-cli 1.3.0 → 1.4.1
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/chunks/{tui-GDC2NODL.js → tui-HKY3YBAY.js} +198 -90
- package/dist/chunks/tui-HKY3YBAY.js.map +7 -0
- package/dist/chunks/update-NA7YA6YF.js +100 -0
- package/dist/chunks/update-NA7YA6YF.js.map +7 -0
- package/dist/cli.js +65 -2
- package/dist/cli.js.map +3 -3
- package/package.json +2 -2
- package/dist/chunks/tui-GDC2NODL.js.map +0 -7
|
@@ -5,14 +5,15 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/tui/index.tsx
|
|
7
7
|
import { render } from "ink";
|
|
8
|
+
import { stdout } from "node:process";
|
|
8
9
|
|
|
9
10
|
// src/tui/app.tsx
|
|
10
11
|
import { useCallback, useEffect as useEffect7, useState as useState10 } from "react";
|
|
11
|
-
import { Box as
|
|
12
|
+
import { Box as Box10, Text as Text10, useApp as useApp2, useInput as useInput9 } from "ink";
|
|
12
13
|
|
|
13
14
|
// src/tui/dashboard.tsx
|
|
14
15
|
import { useEffect as useEffect5, useReducer, useRef as useRef2, useState as useState6 } from "react";
|
|
15
|
-
import { Box as
|
|
16
|
+
import { Box as Box6, Text as Text6, useApp, useInput as useInput5 } from "ink";
|
|
16
17
|
|
|
17
18
|
// src/tui/chat-state.ts
|
|
18
19
|
var initialChatState = { messages: [], running: false };
|
|
@@ -135,16 +136,32 @@ function chatReducer(state, action) {
|
|
|
135
136
|
|
|
136
137
|
// src/tui/command-palette.tsx
|
|
137
138
|
import { useState as useState2 } from "react";
|
|
138
|
-
import { Box as
|
|
139
|
+
import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
|
|
139
140
|
|
|
140
141
|
// src/tui/components.tsx
|
|
141
|
-
import { Box, Text as Text2 } from "ink";
|
|
142
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
142
143
|
|
|
143
144
|
// src/tui/ime-text-input.tsx
|
|
144
145
|
import { useEffect, useRef, useState } from "react";
|
|
145
|
-
import { Text, useCursor, useInput
|
|
146
|
+
import { Box, Text, useCursor, useInput } from "ink";
|
|
146
147
|
import stringWidth from "string-width";
|
|
147
|
-
|
|
148
|
+
|
|
149
|
+
// src/tui/terminal-input.ts
|
|
150
|
+
var PASTE_START = "[200~";
|
|
151
|
+
var PASTE_END = "[201~";
|
|
152
|
+
var CONTROL_TAIL = /^(?:\[[\d;:<>?!"'$ ]*[@-~]|O[@-~])$/;
|
|
153
|
+
var CONTROL_CHARS = /[\u0000-\u001F\u007F]/g;
|
|
154
|
+
function classifyInput(input, pasting = false) {
|
|
155
|
+
if (input === PASTE_START) return { kind: "paste-start" };
|
|
156
|
+
if (input === PASTE_END) return { kind: "paste-end" };
|
|
157
|
+
if (!pasting && input.length > 1 && CONTROL_TAIL.test(input)) return { kind: "ignore" };
|
|
158
|
+
const flattened = input.replace(/\r\n|[\r\n]/g, " ");
|
|
159
|
+
const text = flattened.replace(CONTROL_CHARS, "");
|
|
160
|
+
return text ? { kind: "text", text } : { kind: "ignore" };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/tui/ime-text-input.tsx
|
|
164
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
148
165
|
var segmenter = new Intl.Segmenter("ko", { granularity: "grapheme" });
|
|
149
166
|
function graphemes(value) {
|
|
150
167
|
return [...segmenter.segment(value)].map(({ segment }) => segment);
|
|
@@ -152,6 +169,19 @@ function graphemes(value) {
|
|
|
152
169
|
function clamp(value, minimum, maximum) {
|
|
153
170
|
return Math.min(Math.max(value, minimum), maximum);
|
|
154
171
|
}
|
|
172
|
+
function placementOf(node) {
|
|
173
|
+
const width = node?.yogaNode?.getComputedWidth();
|
|
174
|
+
if (!node || width === void 0) return void 0;
|
|
175
|
+
let x = 0;
|
|
176
|
+
let y = 0;
|
|
177
|
+
for (let current = node; current; current = current.parentNode) {
|
|
178
|
+
const yoga = current.yogaNode;
|
|
179
|
+
if (!yoga) continue;
|
|
180
|
+
x += yoga.getComputedLeft();
|
|
181
|
+
y += yoga.getComputedTop();
|
|
182
|
+
}
|
|
183
|
+
return { x, y, width };
|
|
184
|
+
}
|
|
155
185
|
function visibleInput(segments, cursor, maximumWidth) {
|
|
156
186
|
let start = cursor;
|
|
157
187
|
let widthBeforeCursor = 0;
|
|
@@ -176,17 +206,26 @@ function visibleInput(segments, cursor, maximumWidth) {
|
|
|
176
206
|
cursorWidth: widthBeforeCursor
|
|
177
207
|
};
|
|
178
208
|
}
|
|
179
|
-
function TerminalCursor({
|
|
209
|
+
function TerminalCursor({ x, y }) {
|
|
180
210
|
const { setCursorPosition } = useCursor();
|
|
181
|
-
setCursorPosition({ x
|
|
211
|
+
setCursorPosition({ x, y });
|
|
182
212
|
return null;
|
|
183
213
|
}
|
|
184
214
|
function ImeTextInput(props) {
|
|
185
|
-
const
|
|
215
|
+
const ref = useRef(null);
|
|
216
|
+
const [placement, setPlacement] = useState(void 0);
|
|
186
217
|
const initialSegments = graphemes(props.value);
|
|
187
218
|
const [cursor, setCursor] = useState(initialSegments.length);
|
|
188
219
|
const valueRef = useRef(props.value);
|
|
189
220
|
const cursorRef = useRef(initialSegments.length);
|
|
221
|
+
const pastingRef = useRef(false);
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
const measured = placementOf(ref.current);
|
|
224
|
+
if (!measured) return;
|
|
225
|
+
if (placement?.x !== measured.x || placement?.y !== measured.y || placement?.width !== measured.width) {
|
|
226
|
+
setPlacement(measured);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
190
229
|
const moveCursor = (next, length) => {
|
|
191
230
|
const resolved = clamp(next, 0, length);
|
|
192
231
|
cursorRef.current = resolved;
|
|
@@ -210,6 +249,23 @@ function ImeTextInput(props) {
|
|
|
210
249
|
(input, key) => {
|
|
211
250
|
const current = graphemes(valueRef.current);
|
|
212
251
|
const currentCursor = clamp(cursorRef.current, 0, current.length);
|
|
252
|
+
const event = classifyInput(input, pastingRef.current);
|
|
253
|
+
if (event.kind === "paste-start") {
|
|
254
|
+
pastingRef.current = true;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (event.kind === "paste-end") {
|
|
258
|
+
pastingRef.current = false;
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (pastingRef.current) {
|
|
262
|
+
if (event.kind === "text") {
|
|
263
|
+
const inserted2 = graphemes(event.text);
|
|
264
|
+
current.splice(currentCursor, 0, ...inserted2);
|
|
265
|
+
updateValue(current, currentCursor + inserted2.length);
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
213
269
|
if (key.return) {
|
|
214
270
|
props.onSubmit?.(valueRef.current);
|
|
215
271
|
return;
|
|
@@ -236,10 +292,11 @@ function ImeTextInput(props) {
|
|
|
236
292
|
updateValue(current, currentCursor - 1);
|
|
237
293
|
return;
|
|
238
294
|
}
|
|
239
|
-
if (
|
|
295
|
+
if (key.ctrl || key.meta || key.tab || key.escape || key.upArrow || key.downArrow || key.pageUp || key.pageDown) {
|
|
240
296
|
return;
|
|
241
297
|
}
|
|
242
|
-
|
|
298
|
+
if (event.kind !== "text") return;
|
|
299
|
+
const inserted = graphemes(event.text);
|
|
243
300
|
current.splice(currentCursor, 0, ...inserted);
|
|
244
301
|
updateValue(current, currentCursor + inserted.length);
|
|
245
302
|
},
|
|
@@ -248,18 +305,18 @@ function ImeTextInput(props) {
|
|
|
248
305
|
const rawSegments = graphemes(props.value);
|
|
249
306
|
const safeCursor = clamp(cursor, 0, rawSegments.length);
|
|
250
307
|
const displayedSegments = props.mask ? rawSegments.map(() => props.mask ?? "") : rawSegments;
|
|
251
|
-
const maximumWidth = Math.max(1, (
|
|
308
|
+
const maximumWidth = Math.max(1, (placement?.width ?? 40) - 1);
|
|
252
309
|
const visible = visibleInput(displayedSegments, safeCursor, maximumWidth);
|
|
253
|
-
return /* @__PURE__ */ jsxs(
|
|
310
|
+
return /* @__PURE__ */ jsxs(Box, { ref, flexGrow: 1, children: [
|
|
254
311
|
rawSegments.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: props.placeholder ?? "" }) : /* @__PURE__ */ jsx(Text, { children: visible.text }),
|
|
255
|
-
props.focus ? /* @__PURE__ */ jsx(TerminalCursor, {
|
|
312
|
+
props.focus && placement ? /* @__PURE__ */ jsx(TerminalCursor, { x: placement.x + visible.cursorWidth, y: placement.y }) : null
|
|
256
313
|
] });
|
|
257
314
|
}
|
|
258
315
|
|
|
259
316
|
// src/tui/components.tsx
|
|
260
317
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
261
318
|
function Header(props) {
|
|
262
|
-
return /* @__PURE__ */ jsxs2(
|
|
319
|
+
return /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, justifyContent: "space-between", children: [
|
|
263
320
|
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "blueBright", children: "XGEN Dex" }),
|
|
264
321
|
props.profile ? /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
265
322
|
props.profile,
|
|
@@ -272,37 +329,40 @@ function Header(props) {
|
|
|
272
329
|
] });
|
|
273
330
|
}
|
|
274
331
|
function Footer({ text }) {
|
|
275
|
-
return /* @__PURE__ */ jsx2(
|
|
332
|
+
return /* @__PURE__ */ jsx2(Box2, { paddingX: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: text }) });
|
|
276
333
|
}
|
|
277
334
|
function Loading({ label = "\uBD88\uB7EC\uC624\uB294 \uC911..." }) {
|
|
278
|
-
return /* @__PURE__ */ jsx2(
|
|
335
|
+
return /* @__PURE__ */ jsx2(Box2, { padding: 1, children: /* @__PURE__ */ jsxs2(Text2, { color: "cyan", children: [
|
|
279
336
|
"\u25C6 ",
|
|
280
337
|
label
|
|
281
338
|
] }) });
|
|
282
339
|
}
|
|
283
340
|
function Notice({ children, error = false }) {
|
|
284
|
-
return /* @__PURE__ */ jsx2(
|
|
341
|
+
return /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: error ? "red" : "cyan", paddingX: 1, children: /* @__PURE__ */ jsx2(Text2, { color: error ? "red" : void 0, children }) });
|
|
285
342
|
}
|
|
286
343
|
function FormField(props) {
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
props.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
344
|
+
return (
|
|
345
|
+
// 가로로 늘려 둬야 입력 칸이 남는 폭을 알 수 있다. 내용만큼만 넓으면 칸의 폭이
|
|
346
|
+
// 곧 글자 폭이 되어, 긴 주소가 스스로를 잘라 내는 꼴이 된다.
|
|
347
|
+
/* @__PURE__ */ jsxs2(Box2, { flexGrow: 1, children: [
|
|
348
|
+
/* @__PURE__ */ jsx2(Box2, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsxs2(Text2, { color: props.focus ? "cyan" : void 0, children: [
|
|
349
|
+
props.focus ? "\u203A" : " ",
|
|
350
|
+
" ",
|
|
351
|
+
props.label
|
|
352
|
+
] }) }),
|
|
353
|
+
/* @__PURE__ */ jsx2(
|
|
354
|
+
ImeTextInput,
|
|
355
|
+
{
|
|
356
|
+
value: props.value,
|
|
357
|
+
onChange: props.onChange,
|
|
358
|
+
onSubmit: props.onSubmit,
|
|
359
|
+
focus: props.focus,
|
|
360
|
+
placeholder: props.placeholder,
|
|
361
|
+
mask: props.secret ? "\u2022" : void 0
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
] })
|
|
365
|
+
);
|
|
306
366
|
}
|
|
307
367
|
|
|
308
368
|
// src/tui/command-palette.tsx
|
|
@@ -315,9 +375,9 @@ function CommandPalette(props) {
|
|
|
315
375
|
if (key.downArrow) setCursor((current) => Math.min(props.actions.length - 1, current + 1));
|
|
316
376
|
if (key.return && props.actions[cursor]) props.actions[cursor].run();
|
|
317
377
|
});
|
|
318
|
-
return /* @__PURE__ */ jsxs3(
|
|
378
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", flexGrow: 1, borderStyle: "double", borderColor: "magenta", padding: 1, children: [
|
|
319
379
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "\uBA85\uB839" }),
|
|
320
|
-
/* @__PURE__ */ jsx3(
|
|
380
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginTop: 1, children: props.actions.map((action, index) => /* @__PURE__ */ jsxs3(Text3, { color: index === cursor ? "magentaBright" : void 0, children: [
|
|
321
381
|
index === cursor ? "\u203A" : " ",
|
|
322
382
|
" ",
|
|
323
383
|
action.label
|
|
@@ -328,7 +388,7 @@ function CommandPalette(props) {
|
|
|
328
388
|
|
|
329
389
|
// src/tui/history-screen.tsx
|
|
330
390
|
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
331
|
-
import { Box as
|
|
391
|
+
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
332
392
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
333
393
|
function HistoryScreen(props) {
|
|
334
394
|
const [items, setItems] = useState3([]);
|
|
@@ -363,7 +423,7 @@ function HistoryScreen(props) {
|
|
|
363
423
|
},
|
|
364
424
|
{ isActive: !loading }
|
|
365
425
|
);
|
|
366
|
-
return /* @__PURE__ */ jsxs4(
|
|
426
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
367
427
|
/* @__PURE__ */ jsx4(Text4, { bold: true, children: "\uB300\uD654 \uAE30\uB85D" }),
|
|
368
428
|
loading ? /* @__PURE__ */ jsx4(Loading, {}) : null,
|
|
369
429
|
!loading && items.length === 0 ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "\uB300\uD654 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : null,
|
|
@@ -385,7 +445,7 @@ function HistoryScreen(props) {
|
|
|
385
445
|
|
|
386
446
|
// src/tui/start-panel.tsx
|
|
387
447
|
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
388
|
-
import { Box as
|
|
448
|
+
import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
|
|
389
449
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
390
450
|
function StartPanel(props) {
|
|
391
451
|
const rows = [
|
|
@@ -428,10 +488,10 @@ function StartPanel(props) {
|
|
|
428
488
|
},
|
|
429
489
|
{ isActive: !opening }
|
|
430
490
|
);
|
|
431
|
-
return /* @__PURE__ */ jsxs5(
|
|
491
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
432
492
|
/* @__PURE__ */ jsx5(Text5, { bold: true, children: props.agentName }),
|
|
433
493
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\uC5B4\uB5BB\uAC8C \uC2DC\uC791\uD560\uAE4C\uC694?" }),
|
|
434
|
-
/* @__PURE__ */ jsx5(
|
|
494
|
+
/* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginTop: 1, children: rows.map((row, index) => {
|
|
435
495
|
const active = index === cursor;
|
|
436
496
|
const mark = active ? "\u203A" : " ";
|
|
437
497
|
if (row.kind === "new") {
|
|
@@ -456,7 +516,7 @@ function StartPanel(props) {
|
|
|
456
516
|
}) }),
|
|
457
517
|
opening ? /* @__PURE__ */ jsx5(Loading, { label: "\uB300\uD654\uB97C \uBD88\uB7EC\uC624\uB294 \uC911..." }) : null,
|
|
458
518
|
error ? /* @__PURE__ */ jsx5(Notice, { error: true, children: error }) : null,
|
|
459
|
-
/* @__PURE__ */ jsx5(
|
|
519
|
+
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\u2191\u2193 \uC774\uB3D9 \xB7 Enter \uC120\uD0DD \xB7 Esc \uBAA9\uB85D\uC73C\uB85C" }) })
|
|
460
520
|
] });
|
|
461
521
|
}
|
|
462
522
|
function when(conversation) {
|
|
@@ -471,22 +531,22 @@ function when(conversation) {
|
|
|
471
531
|
|
|
472
532
|
// src/tui/use-terminal-size.ts
|
|
473
533
|
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
474
|
-
import { useStdout
|
|
534
|
+
import { useStdout } from "ink";
|
|
475
535
|
function useTerminalSize() {
|
|
476
|
-
const { stdout } =
|
|
536
|
+
const { stdout: stdout2 } = useStdout();
|
|
477
537
|
const read = () => {
|
|
478
|
-
const columns =
|
|
479
|
-
const rows =
|
|
538
|
+
const columns = stdout2.columns || 100;
|
|
539
|
+
const rows = stdout2.rows || 30;
|
|
480
540
|
return { columns, rows, wide: columns >= 88 };
|
|
481
541
|
};
|
|
482
542
|
const [size, setSize] = useState5(read);
|
|
483
543
|
useEffect4(() => {
|
|
484
544
|
const resize = () => setSize(read());
|
|
485
|
-
|
|
545
|
+
stdout2.on("resize", resize);
|
|
486
546
|
return () => {
|
|
487
|
-
|
|
547
|
+
stdout2.off("resize", resize);
|
|
488
548
|
};
|
|
489
|
-
}, [
|
|
549
|
+
}, [stdout2]);
|
|
490
550
|
return size;
|
|
491
551
|
}
|
|
492
552
|
|
|
@@ -496,7 +556,7 @@ function AgentSidebar(props) {
|
|
|
496
556
|
const radius = Math.max(3, Math.floor((props.height - 4) / 2));
|
|
497
557
|
const start = Math.max(0, props.cursor - radius);
|
|
498
558
|
const visible = props.agents.slice(start, start + radius * 2 + 1);
|
|
499
|
-
return /* @__PURE__ */ jsxs6(
|
|
559
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", width: 30, borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
|
|
500
560
|
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Agents" }),
|
|
501
561
|
visible.map((agent) => {
|
|
502
562
|
const index = props.agents.indexOf(agent);
|
|
@@ -529,11 +589,11 @@ function labelOf(role, agentName) {
|
|
|
529
589
|
function ChatPane(props) {
|
|
530
590
|
const visibleCount = Math.max(4, Math.floor((props.height - 5) / 2));
|
|
531
591
|
const visible = props.messages.slice(-visibleCount);
|
|
532
|
-
return /* @__PURE__ */ jsxs6(
|
|
592
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
533
593
|
/* @__PURE__ */ jsx6(Text6, { bold: true, children: props.agent?.workflowName ?? "Agent\uB97C \uC120\uD0DD\uD558\uC138\uC694" }),
|
|
534
|
-
/* @__PURE__ */ jsxs6(
|
|
594
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", flexGrow: 1, children: [
|
|
535
595
|
visible.length === 0 ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: props.agent ? "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD574 \uB300\uD654\uB97C \uC2DC\uC791\uD558\uC138\uC694." : "\uC67C\uCABD\uC5D0\uC11C Agent\uB97C \uC120\uD0DD\uD558\uC138\uC694." }) : null,
|
|
536
|
-
visible.map((message) => /* @__PURE__ */ jsxs6(
|
|
596
|
+
visible.map((message) => /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: message.role === "activity" ? 0 : 1, children: [
|
|
537
597
|
/* @__PURE__ */ jsx6(Text6, { bold: true, color: messageColor(message.role), children: labelOf(message.role, props.agent?.workflowName ?? "Agent") }),
|
|
538
598
|
/* @__PURE__ */ jsx6(Text6, { dimColor: message.role === "activity", children: message.text || (message.role === "assistant" ? "\u2026" : "") })
|
|
539
599
|
] }, message.id))
|
|
@@ -545,7 +605,7 @@ function ChatPane(props) {
|
|
|
545
605
|
] });
|
|
546
606
|
}
|
|
547
607
|
function Composer(props) {
|
|
548
|
-
return /* @__PURE__ */ jsxs6(
|
|
608
|
+
return /* @__PURE__ */ jsxs6(Box6, { borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
|
|
549
609
|
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u203A " }),
|
|
550
610
|
props.disabled ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\uC751\uB2F5\uC744 \uAE30\uB2E4\uB9AC\uB294 \uC911..." }) : /* @__PURE__ */ jsx6(
|
|
551
611
|
ImeTextInput,
|
|
@@ -554,7 +614,6 @@ function Composer(props) {
|
|
|
554
614
|
onChange: props.onChange,
|
|
555
615
|
onSubmit: props.onSubmit,
|
|
556
616
|
focus: props.focused,
|
|
557
|
-
cursorOrigin: props.cursorOrigin,
|
|
558
617
|
placeholder: "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694"
|
|
559
618
|
}
|
|
560
619
|
)
|
|
@@ -743,7 +802,7 @@ function Dashboard(props) {
|
|
|
743
802
|
setFocus("agents");
|
|
744
803
|
}
|
|
745
804
|
}
|
|
746
|
-
) : /* @__PURE__ */ jsxs6(
|
|
805
|
+
) : /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", flexGrow: 1, children: [
|
|
747
806
|
/* @__PURE__ */ jsx6(ChatPane, { agent: selected, messages: chat.messages, status: chat.status, height: bodyHeight - 3 }),
|
|
748
807
|
/* @__PURE__ */ jsx6(
|
|
749
808
|
Composer,
|
|
@@ -752,17 +811,16 @@ function Dashboard(props) {
|
|
|
752
811
|
onChange: setInput,
|
|
753
812
|
onSubmit: (value) => void send(value),
|
|
754
813
|
focused: focus === "composer",
|
|
755
|
-
disabled: chat.running || !selected
|
|
756
|
-
cursorOrigin: { x: size.wide ? 34 : 4, y: bodyHeight - 1 }
|
|
814
|
+
disabled: chat.running || !selected
|
|
757
815
|
}
|
|
758
816
|
)
|
|
759
817
|
] });
|
|
760
|
-
body = size.wide ? /* @__PURE__ */ jsxs6(
|
|
818
|
+
body = size.wide ? /* @__PURE__ */ jsxs6(Box6, { height: bodyHeight, children: [
|
|
761
819
|
sidebar,
|
|
762
820
|
conversation
|
|
763
|
-
] }) : focus === "agents" ? /* @__PURE__ */ jsx6(
|
|
821
|
+
] }) : focus === "agents" ? /* @__PURE__ */ jsx6(Box6, { height: bodyHeight, children: sidebar }) : /* @__PURE__ */ jsx6(Box6, { height: bodyHeight, children: conversation });
|
|
764
822
|
}
|
|
765
|
-
return /* @__PURE__ */ jsxs6(
|
|
823
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
766
824
|
/* @__PURE__ */ jsx6(
|
|
767
825
|
Header,
|
|
768
826
|
{
|
|
@@ -778,7 +836,7 @@ function Dashboard(props) {
|
|
|
778
836
|
|
|
779
837
|
// src/tui/login-screen.tsx
|
|
780
838
|
import { useState as useState7 } from "react";
|
|
781
|
-
import { Box as
|
|
839
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
782
840
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
783
841
|
function LoginScreen(props) {
|
|
784
842
|
const [email, setEmail] = useState7("");
|
|
@@ -803,16 +861,16 @@ function LoginScreen(props) {
|
|
|
803
861
|
props.onSubmit(email.trim(), secret);
|
|
804
862
|
}
|
|
805
863
|
};
|
|
806
|
-
return /* @__PURE__ */ jsxs7(
|
|
864
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
807
865
|
/* @__PURE__ */ jsx7(Header, { profile: props.profile, connected: false }),
|
|
808
|
-
/* @__PURE__ */ jsxs7(
|
|
866
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
|
|
809
867
|
/* @__PURE__ */ jsx7(Text7, { bold: true, children: "\uB85C\uADF8\uC778" }),
|
|
810
868
|
/* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
|
|
811
869
|
props.serverUrl,
|
|
812
870
|
" ",
|
|
813
871
|
/* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "(Ctrl+E \uBC14\uAFB8\uAE30)" })
|
|
814
872
|
] }),
|
|
815
|
-
/* @__PURE__ */ jsxs7(
|
|
873
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
816
874
|
/* @__PURE__ */ jsx7(
|
|
817
875
|
FormField,
|
|
818
876
|
{
|
|
@@ -821,7 +879,6 @@ function LoginScreen(props) {
|
|
|
821
879
|
onChange: setEmail,
|
|
822
880
|
onSubmit: () => setFocus("password"),
|
|
823
881
|
focus: !props.busy && focus === "email",
|
|
824
|
-
cursorOrigin: { x: 16, y: 6 },
|
|
825
882
|
placeholder: "me@corp.com"
|
|
826
883
|
}
|
|
827
884
|
),
|
|
@@ -833,7 +890,6 @@ function LoginScreen(props) {
|
|
|
833
890
|
onChange: setPassword,
|
|
834
891
|
onSubmit: submit,
|
|
835
892
|
focus: !props.busy && focus === "password",
|
|
836
|
-
cursorOrigin: { x: 16, y: 7 },
|
|
837
893
|
secret: true
|
|
838
894
|
}
|
|
839
895
|
)
|
|
@@ -847,7 +903,7 @@ function LoginScreen(props) {
|
|
|
847
903
|
|
|
848
904
|
// src/tui/profile-screen.tsx
|
|
849
905
|
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
850
|
-
import { Box as
|
|
906
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
851
907
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
852
908
|
function ProfileScreen(props) {
|
|
853
909
|
const [cursor, setCursor] = useState8(Math.max(0, props.profiles.findIndex((profile) => profile.current)));
|
|
@@ -886,11 +942,11 @@ function ProfileScreen(props) {
|
|
|
886
942
|
}
|
|
887
943
|
if (name.trim() && serverUrl.trim()) props.onCreate(name.trim(), serverUrl.trim());
|
|
888
944
|
};
|
|
889
|
-
return /* @__PURE__ */ jsxs8(
|
|
945
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
890
946
|
/* @__PURE__ */ jsx8(Header, {}),
|
|
891
|
-
/* @__PURE__ */ jsxs8(
|
|
947
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
892
948
|
/* @__PURE__ */ jsx8(Text8, { bold: true, children: creating ? "\uC0C8 \uD504\uB85C\uD544" : "\uD504\uB85C\uD544 \uC804\uD658" }),
|
|
893
|
-
creating ? /* @__PURE__ */ jsxs8(
|
|
949
|
+
creating ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
894
950
|
/* @__PURE__ */ jsx8(
|
|
895
951
|
FormField,
|
|
896
952
|
{
|
|
@@ -899,7 +955,6 @@ function ProfileScreen(props) {
|
|
|
899
955
|
onChange: setName,
|
|
900
956
|
onSubmit: () => setFocus("url"),
|
|
901
957
|
focus: !props.busy && focus === "name",
|
|
902
|
-
cursorOrigin: { x: 16, y: 5 },
|
|
903
958
|
placeholder: "corp"
|
|
904
959
|
}
|
|
905
960
|
),
|
|
@@ -911,11 +966,10 @@ function ProfileScreen(props) {
|
|
|
911
966
|
onChange: setServerUrl,
|
|
912
967
|
onSubmit: create,
|
|
913
968
|
focus: !props.busy && focus === "url",
|
|
914
|
-
cursorOrigin: { x: 16, y: 6 },
|
|
915
969
|
placeholder: "https://xgen.example.com"
|
|
916
970
|
}
|
|
917
971
|
)
|
|
918
|
-
] }) : /* @__PURE__ */ jsxs8(
|
|
972
|
+
] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
919
973
|
props.profiles.map((profile, index) => /* @__PURE__ */ jsxs8(Text8, { color: index === cursor ? "cyan" : void 0, children: [
|
|
920
974
|
index === cursor ? "\u203A" : " ",
|
|
921
975
|
" ",
|
|
@@ -942,7 +996,7 @@ function ProfileScreen(props) {
|
|
|
942
996
|
|
|
943
997
|
// src/tui/server-screen.tsx
|
|
944
998
|
import { useState as useState9 } from "react";
|
|
945
|
-
import { Box as
|
|
999
|
+
import { Box as Box9, Text as Text9, useInput as useInput8 } from "ink";
|
|
946
1000
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
947
1001
|
function ServerScreen(props) {
|
|
948
1002
|
const [serverUrl, setServerUrl] = useState9(props.initialValue ?? "");
|
|
@@ -953,12 +1007,12 @@ function ServerScreen(props) {
|
|
|
953
1007
|
},
|
|
954
1008
|
{ isActive: !props.busy && !!props.onCancel }
|
|
955
1009
|
);
|
|
956
|
-
return /* @__PURE__ */ jsxs9(
|
|
1010
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
957
1011
|
/* @__PURE__ */ jsx9(Header, { profile: props.profile, connected: false }),
|
|
958
|
-
/* @__PURE__ */ jsxs9(
|
|
1012
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
|
|
959
1013
|
/* @__PURE__ */ jsx9(Text9, { bold: true, children: editing ? "\uC11C\uBC84 \uC8FC\uC18C \uBC14\uAFB8\uAE30" : "\uCC98\uC74C \uC624\uC168\uAD70\uC694" }),
|
|
960
1014
|
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\uC5F0\uACB0\uD560 XGEN Gateway \uC8FC\uC18C\uB97C \uC785\uB825\uD558\uC138\uC694." }),
|
|
961
|
-
/* @__PURE__ */ jsx9(
|
|
1015
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(
|
|
962
1016
|
FormField,
|
|
963
1017
|
{
|
|
964
1018
|
label: "Server URL",
|
|
@@ -966,7 +1020,6 @@ function ServerScreen(props) {
|
|
|
966
1020
|
onChange: setServerUrl,
|
|
967
1021
|
onSubmit: (value) => value.trim() && props.onSubmit(value.trim()),
|
|
968
1022
|
focus: !props.busy,
|
|
969
|
-
cursorOrigin: { x: 16, y: 6 },
|
|
970
1023
|
placeholder: "xgen.example.com"
|
|
971
1024
|
}
|
|
972
1025
|
) }),
|
|
@@ -1119,7 +1172,7 @@ function App({ engine }) {
|
|
|
1119
1172
|
}
|
|
1120
1173
|
};
|
|
1121
1174
|
if (route === "boot") {
|
|
1122
|
-
return /* @__PURE__ */ jsxs10(
|
|
1175
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
1123
1176
|
/* @__PURE__ */ jsx10(Header, {}),
|
|
1124
1177
|
/* @__PURE__ */ jsx10(Loading, { label: "Dex\uB97C \uC900\uBE44\uD558\uB294 \uC911..." }),
|
|
1125
1178
|
/* @__PURE__ */ jsx10(Footer, { text: "Ctrl+Q \uC885\uB8CC" })
|
|
@@ -1184,7 +1237,7 @@ function App({ engine }) {
|
|
|
1184
1237
|
}
|
|
1185
1238
|
);
|
|
1186
1239
|
}
|
|
1187
|
-
return /* @__PURE__ */ jsxs10(
|
|
1240
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
1188
1241
|
/* @__PURE__ */ jsx10(Header, {}),
|
|
1189
1242
|
/* @__PURE__ */ jsx10(Notice, { error: true, children: error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4." }),
|
|
1190
1243
|
/* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\uC11C\uBC84\uC640 \uD0A4\uCCB4\uC778 \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694." }),
|
|
@@ -1199,16 +1252,71 @@ function RetryInput({ onRetry }) {
|
|
|
1199
1252
|
return null;
|
|
1200
1253
|
}
|
|
1201
1254
|
|
|
1255
|
+
// src/tui/screen.ts
|
|
1256
|
+
var ESC = "\x1B";
|
|
1257
|
+
var ENTER_ALT_SCREEN = `${ESC}[?1049h`;
|
|
1258
|
+
var LEAVE_ALT_SCREEN = `${ESC}[?1049l`;
|
|
1259
|
+
var SHOW_CURSOR = `${ESC}[?25h`;
|
|
1260
|
+
var DISABLE_REPORTS = [
|
|
1261
|
+
`${ESC}[?1004l`,
|
|
1262
|
+
// 포커스 들어옴/나감
|
|
1263
|
+
`${ESC}[?1000l`,
|
|
1264
|
+
// 마우스 클릭
|
|
1265
|
+
`${ESC}[?1002l`,
|
|
1266
|
+
// 마우스 드래그
|
|
1267
|
+
`${ESC}[?1003l`,
|
|
1268
|
+
// 마우스 이동 전부
|
|
1269
|
+
`${ESC}[?1006l`
|
|
1270
|
+
// SGR 확장 좌표
|
|
1271
|
+
].join("");
|
|
1272
|
+
var ENABLE_BRACKETED_PASTE = `${ESC}[?2004h`;
|
|
1273
|
+
var DISABLE_BRACKETED_PASTE = `${ESC}[?2004l`;
|
|
1274
|
+
function createScreenGuard(stream) {
|
|
1275
|
+
const alt = Boolean(stream.isTTY);
|
|
1276
|
+
let entered = false;
|
|
1277
|
+
let restored = false;
|
|
1278
|
+
return {
|
|
1279
|
+
enter() {
|
|
1280
|
+
if (entered || !alt) return;
|
|
1281
|
+
entered = true;
|
|
1282
|
+
stream.write(ENTER_ALT_SCREEN + DISABLE_REPORTS + ENABLE_BRACKETED_PASTE);
|
|
1283
|
+
},
|
|
1284
|
+
restore() {
|
|
1285
|
+
if (restored) return;
|
|
1286
|
+
restored = true;
|
|
1287
|
+
if (entered) stream.write(DISABLE_BRACKETED_PASTE + LEAVE_ALT_SCREEN);
|
|
1288
|
+
stream.write(SHOW_CURSOR);
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1202
1293
|
// src/tui/index.tsx
|
|
1203
1294
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1204
1295
|
async function runTui(engine) {
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1296
|
+
const screen = createScreenGuard(stdout);
|
|
1297
|
+
const restore = () => screen.restore();
|
|
1298
|
+
const onSignal = () => {
|
|
1299
|
+
restore();
|
|
1300
|
+
process.exit(0);
|
|
1301
|
+
};
|
|
1302
|
+
process.once("exit", restore);
|
|
1303
|
+
process.once("SIGINT", onSignal);
|
|
1304
|
+
process.once("SIGTERM", onSignal);
|
|
1305
|
+
screen.enter();
|
|
1306
|
+
try {
|
|
1307
|
+
const instance = render(/* @__PURE__ */ jsx11(App, { engine }), {
|
|
1308
|
+
exitOnCtrlC: true,
|
|
1309
|
+
patchConsole: true
|
|
1310
|
+
});
|
|
1311
|
+
await instance.waitUntilExit();
|
|
1312
|
+
} finally {
|
|
1313
|
+
restore();
|
|
1314
|
+
process.off("exit", restore);
|
|
1315
|
+
process.off("SIGINT", onSignal);
|
|
1316
|
+
process.off("SIGTERM", onSignal);
|
|
1317
|
+
}
|
|
1210
1318
|
}
|
|
1211
1319
|
export {
|
|
1212
1320
|
runTui
|
|
1213
1321
|
};
|
|
1214
|
-
//# sourceMappingURL=tui-
|
|
1322
|
+
//# sourceMappingURL=tui-HKY3YBAY.js.map
|