xgen-dex-cli 1.2.2 → 1.3.0

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.
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  DexError,
3
3
  publicError
4
- } from "./chunk-GS2Q7ZZA.js";
4
+ } from "./chunk-ULMEXJOR.js";
5
5
 
6
6
  // src/tui/index.tsx
7
7
  import { render } from "ink";
8
8
 
9
9
  // src/tui/app.tsx
10
- import { useCallback, useEffect as useEffect6, useState as useState9 } from "react";
11
- import { Box as Box8, Text as Text9, useApp as useApp2, useInput as useInput7 } from "ink";
10
+ import { useCallback, useEffect as useEffect7, useState as useState10 } from "react";
11
+ import { Box as Box9, Text as Text10, useApp as useApp2, useInput as useInput9 } from "ink";
12
12
 
13
13
  // src/tui/dashboard.tsx
14
- import { useEffect as useEffect4, useReducer, useRef as useRef2, useState as useState5 } from "react";
15
- import { Box as Box4, Text as Text5, useApp, useInput as useInput4 } from "ink";
14
+ import { useEffect as useEffect5, useReducer, useRef as useRef2, useState as useState6 } from "react";
15
+ import { Box as Box5, Text as Text6, useApp, useInput as useInput5 } from "ink";
16
16
 
17
17
  // src/tui/chat-state.ts
18
18
  var initialChatState = { messages: [], running: false };
@@ -383,8 +383,94 @@ function HistoryScreen(props) {
383
383
  ] });
384
384
  }
385
385
 
386
- // src/tui/use-terminal-size.ts
386
+ // src/tui/start-panel.tsx
387
387
  import { useEffect as useEffect3, useState as useState4 } from "react";
388
+ import { Box as Box4, Text as Text5, useInput as useInput4 } from "ink";
389
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
390
+ function StartPanel(props) {
391
+ const rows = [
392
+ { kind: "new" },
393
+ ...props.conversations.map((conversation) => ({ kind: "conversation", conversation }))
394
+ ];
395
+ const [cursor, setCursor] = useState4(0);
396
+ const [opening, setOpening] = useState4(false);
397
+ const [error, setError] = useState4();
398
+ useEffect3(() => {
399
+ setCursor((current) => Math.min(current, Math.max(0, rows.length - 1)));
400
+ }, [rows.length]);
401
+ useInput4(
402
+ (_input, key) => {
403
+ if (key.escape) {
404
+ props.onCancel();
405
+ return;
406
+ }
407
+ if (key.upArrow) setCursor((current) => Math.max(0, current - 1));
408
+ if (key.downArrow) setCursor((current) => Math.min(rows.length - 1, current + 1));
409
+ if (!key.return) return;
410
+ const row = rows[cursor];
411
+ if (!row) return;
412
+ if (row.kind === "new" || !row.conversation) {
413
+ props.onNew();
414
+ return;
415
+ }
416
+ const conversation = row.conversation;
417
+ setOpening(true);
418
+ setError(void 0);
419
+ props.engine.historyTurns(
420
+ conversation.workflowId,
421
+ conversation.interactionId,
422
+ conversation.workflowName,
423
+ props.profile
424
+ ).then((turns) => props.onOpen(conversation, turns)).catch((reason) => {
425
+ setError(publicError(reason).message);
426
+ setOpening(false);
427
+ });
428
+ },
429
+ { isActive: !opening }
430
+ );
431
+ return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "cyan", padding: 1, children: [
432
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: props.agentName }),
433
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\uC5B4\uB5BB\uAC8C \uC2DC\uC791\uD560\uAE4C\uC694?" }),
434
+ /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", marginTop: 1, children: rows.map((row, index) => {
435
+ const active = index === cursor;
436
+ const mark = active ? "\u203A" : " ";
437
+ if (row.kind === "new") {
438
+ return /* @__PURE__ */ jsxs5(Text5, { color: active ? "cyan" : void 0, children: [
439
+ mark,
440
+ " \uC0C8 \uB300\uD654"
441
+ ] }, "new");
442
+ }
443
+ const conversation = row.conversation;
444
+ if (!conversation) return null;
445
+ return /* @__PURE__ */ jsxs5(Text5, { color: active ? "cyan" : void 0, children: [
446
+ mark,
447
+ " ",
448
+ when(conversation),
449
+ " ",
450
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
451
+ "\xB7 ",
452
+ conversation.interactionCount,
453
+ "\uD134"
454
+ ] })
455
+ ] }, conversation.interactionId);
456
+ }) }),
457
+ opening ? /* @__PURE__ */ jsx5(Loading, { label: "\uB300\uD654\uB97C \uBD88\uB7EC\uC624\uB294 \uC911..." }) : null,
458
+ error ? /* @__PURE__ */ jsx5(Notice, { error: true, children: error }) : null,
459
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\u2191\u2193 \uC774\uB3D9 \xB7 Enter \uC120\uD0DD \xB7 Esc \uBAA9\uB85D\uC73C\uB85C" }) })
460
+ ] });
461
+ }
462
+ function when(conversation) {
463
+ const raw = conversation.updatedAt || conversation.createdAt;
464
+ const date = new Date(raw);
465
+ if (Number.isNaN(date.getTime())) return raw || "(\uC2DC\uAC01 \uC5C6\uC74C)";
466
+ const now = /* @__PURE__ */ new Date();
467
+ const sameDay = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
468
+ const pad = (n) => String(n).padStart(2, "0");
469
+ return sameDay ? `\uC624\uB298 ${pad(date.getHours())}:${pad(date.getMinutes())}` : `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
470
+ }
471
+
472
+ // src/tui/use-terminal-size.ts
473
+ import { useEffect as useEffect4, useState as useState5 } from "react";
388
474
  import { useStdout as useStdout2 } from "ink";
389
475
  function useTerminalSize() {
390
476
  const { stdout } = useStdout2();
@@ -393,8 +479,8 @@ function useTerminalSize() {
393
479
  const rows = stdout.rows || 30;
394
480
  return { columns, rows, wide: columns >= 88 };
395
481
  };
396
- const [size, setSize] = useState4(read);
397
- useEffect3(() => {
482
+ const [size, setSize] = useState5(read);
483
+ useEffect4(() => {
398
484
  const resize = () => setSize(read());
399
485
  stdout.on("resize", resize);
400
486
  return () => {
@@ -405,18 +491,18 @@ function useTerminalSize() {
405
491
  }
406
492
 
407
493
  // src/tui/dashboard.tsx
408
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
494
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
409
495
  function AgentSidebar(props) {
410
496
  const radius = Math.max(3, Math.floor((props.height - 4) / 2));
411
497
  const start = Math.max(0, props.cursor - radius);
412
498
  const visible = props.agents.slice(start, start + radius * 2 + 1);
413
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", width: 30, borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
414
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Agents" }),
499
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", width: 30, borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
500
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Agents" }),
415
501
  visible.map((agent) => {
416
502
  const index = props.agents.indexOf(agent);
417
503
  const cursor = index === props.cursor;
418
504
  const selected = agent.workflowId === props.selected;
419
- return /* @__PURE__ */ jsxs5(Text5, { color: cursor && props.focused ? "cyan" : void 0, wrap: "truncate-end", children: [
505
+ return /* @__PURE__ */ jsxs6(Text6, { color: cursor && props.focused ? "cyan" : void 0, wrap: "truncate-end", children: [
420
506
  cursor ? "\u203A" : " ",
421
507
  " ",
422
508
  selected ? "\u25CF" : "\u25CB",
@@ -424,7 +510,7 @@ function AgentSidebar(props) {
424
510
  agent.workflowName
425
511
  ] }, agent.workflowId);
426
512
  }),
427
- props.agents.length === 0 ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C Agent\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) : null
513
+ props.agents.length === 0 ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C Agent\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) : null
428
514
  ] });
429
515
  }
430
516
  function messageColor(role) {
@@ -443,25 +529,25 @@ function labelOf(role, agentName) {
443
529
  function ChatPane(props) {
444
530
  const visibleCount = Math.max(4, Math.floor((props.height - 5) / 2));
445
531
  const visible = props.messages.slice(-visibleCount);
446
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
447
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: props.agent?.workflowName ?? "Agent\uB97C \uC120\uD0DD\uD558\uC138\uC694" }),
448
- /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", flexGrow: 1, children: [
449
- visible.length === 0 ? /* @__PURE__ */ jsx5(Text5, { 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,
450
- visible.map((message) => /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", marginTop: message.role === "activity" ? 0 : 1, children: [
451
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: messageColor(message.role), children: labelOf(message.role, props.agent?.workflowName ?? "Agent") }),
452
- /* @__PURE__ */ jsx5(Text5, { dimColor: message.role === "activity", children: message.text || (message.role === "assistant" ? "\u2026" : "") })
532
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
533
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: props.agent?.workflowName ?? "Agent\uB97C \uC120\uD0DD\uD558\uC138\uC694" }),
534
+ /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", flexGrow: 1, children: [
535
+ 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(Box5, { flexDirection: "column", marginTop: message.role === "activity" ? 0 : 1, children: [
537
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: messageColor(message.role), children: labelOf(message.role, props.agent?.workflowName ?? "Agent") }),
538
+ /* @__PURE__ */ jsx6(Text6, { dimColor: message.role === "activity", children: message.text || (message.role === "assistant" ? "\u2026" : "") })
453
539
  ] }, message.id))
454
540
  ] }),
455
- props.status ? /* @__PURE__ */ jsxs5(Text5, { color: "yellow", children: [
541
+ props.status ? /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
456
542
  "\u25C6 ",
457
543
  props.status
458
544
  ] }) : null
459
545
  ] });
460
546
  }
461
547
  function Composer(props) {
462
- return /* @__PURE__ */ jsxs5(Box4, { borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
463
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u203A " }),
464
- props.disabled ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\uC751\uB2F5\uC744 \uAE30\uB2E4\uB9AC\uB294 \uC911..." }) : /* @__PURE__ */ jsx5(
548
+ return /* @__PURE__ */ jsxs6(Box5, { borderStyle: "round", borderColor: props.focused ? "cyan" : "gray", paddingX: 1, children: [
549
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u203A " }),
550
+ props.disabled ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\uC751\uB2F5\uC744 \uAE30\uB2E4\uB9AC\uB294 \uC911..." }) : /* @__PURE__ */ jsx6(
465
551
  ImeTextInput,
466
552
  {
467
553
  value: props.value,
@@ -478,23 +564,46 @@ function Dashboard(props) {
478
564
  const { exit } = useApp();
479
565
  const size = useTerminalSize();
480
566
  const bodyHeight = Math.max(12, size.rows - 5);
481
- const [focus, setFocus] = useState5("agents");
482
- const [cursor, setCursor] = useState5(0);
483
- const [selected, setSelected] = useState5(() => {
567
+ const [focus, setFocus] = useState6("agents");
568
+ const [cursor, setCursor] = useState6(0);
569
+ const [selected, setSelected] = useState6(() => {
484
570
  const first = props.session.agents[0];
485
571
  return first ? { workflowId: first.workflowId, workflowName: first.workflowName } : void 0;
486
572
  });
487
- const [input, setInput] = useState5("");
573
+ const [input, setInput] = useState6("");
488
574
  const [chat, dispatch] = useReducer(chatReducer, initialChatState);
489
- const [palette, setPalette] = useState5(false);
490
- const [history, setHistory] = useState5(false);
575
+ const [palette, setPalette] = useState6(false);
576
+ const [history, setHistory] = useState6(false);
577
+ const [start, setStart] = useState6();
578
+ const [starting, setStarting] = useState6(false);
491
579
  const controller = useRef2(null);
492
- useEffect4(() => () => controller.current?.abort(), []);
493
- const selectAgent = () => {
580
+ useEffect5(() => () => controller.current?.abort(), []);
581
+ const selectAgent = async () => {
494
582
  const agent = props.session.agents[cursor];
495
- if (!agent || chat.running) return;
496
- setSelected({ workflowId: agent.workflowId, workflowName: agent.workflowName });
583
+ if (!agent || chat.running || starting) return;
584
+ const ref = { workflowId: agent.workflowId, workflowName: agent.workflowName };
585
+ setStarting(true);
586
+ let conversations = [];
587
+ try {
588
+ const all = await props.engine.listConversations(props.session.profile);
589
+ conversations = all.filter((item) => item.workflowId === ref.workflowId);
590
+ } catch {
591
+ conversations = [];
592
+ } finally {
593
+ setStarting(false);
594
+ }
595
+ if (conversations.length === 0) {
596
+ openNewChat(ref);
597
+ return;
598
+ }
599
+ setSelected(ref);
600
+ setStart({ agent: ref, conversations });
601
+ };
602
+ const openNewChat = (ref) => {
603
+ setSelected(ref);
497
604
  dispatch({ type: "reset" });
605
+ setInput("");
606
+ setStart(void 0);
498
607
  setFocus("composer");
499
608
  };
500
609
  const openHistory = (conversation, turns) => {
@@ -503,6 +612,7 @@ function Dashboard(props) {
503
612
  const index = props.session.agents.findIndex((agent) => agent.workflowId === conversation.workflowId);
504
613
  if (index >= 0) setCursor(index);
505
614
  setHistory(false);
615
+ setStart(void 0);
506
616
  setFocus("composer");
507
617
  };
508
618
  const cancelTurn = () => {
@@ -543,7 +653,7 @@ function Dashboard(props) {
543
653
  controller.current = null;
544
654
  }
545
655
  };
546
- useInput4(
656
+ useInput5(
547
657
  (keyInput, key) => {
548
658
  if (key.ctrl && keyInput === "k") setPalette(true);
549
659
  else if (key.ctrl && keyInput === "p") {
@@ -559,9 +669,11 @@ function Dashboard(props) {
559
669
  else if (focus === "agents" && key.upArrow) setCursor((current) => Math.max(0, current - 1));
560
670
  else if (focus === "agents" && key.downArrow && props.session.agents.length > 0) {
561
671
  setCursor((current) => Math.min(props.session.agents.length - 1, current + 1));
562
- } else if (focus === "agents" && key.return) selectAgent();
672
+ } else if (focus === "agents" && key.return) void selectAgent();
563
673
  },
564
- { isActive: !palette && !history }
674
+ // 갈림길·팔레트·이력 화면이 있으면 그 화면이 키를 갖는다 — 여기서도 받으면
675
+ // 방향키 하나가 두 곳에서 움직인다.
676
+ { isActive: !palette && !history && !start }
565
677
  );
566
678
  const paletteActions = [
567
679
  { id: "new", label: "\uC0C8 \uB300\uD654", run: newConversation },
@@ -595,9 +707,9 @@ function Dashboard(props) {
595
707
  ];
596
708
  let body;
597
709
  if (palette) {
598
- body = /* @__PURE__ */ jsx5(CommandPalette, { actions: paletteActions, onCancel: () => setPalette(false) });
710
+ body = /* @__PURE__ */ jsx6(CommandPalette, { actions: paletteActions, onCancel: () => setPalette(false) });
599
711
  } else if (history) {
600
- body = /* @__PURE__ */ jsx5(
712
+ body = /* @__PURE__ */ jsx6(
601
713
  HistoryScreen,
602
714
  {
603
715
  engine: props.engine,
@@ -607,7 +719,7 @@ function Dashboard(props) {
607
719
  }
608
720
  );
609
721
  } else {
610
- const sidebar = /* @__PURE__ */ jsx5(
722
+ const sidebar = /* @__PURE__ */ jsx6(
611
723
  AgentSidebar,
612
724
  {
613
725
  agents: props.session.agents,
@@ -617,9 +729,23 @@ function Dashboard(props) {
617
729
  height: bodyHeight
618
730
  }
619
731
  );
620
- const conversation = /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", flexGrow: 1, children: [
621
- /* @__PURE__ */ jsx5(ChatPane, { agent: selected, messages: chat.messages, status: chat.status, height: bodyHeight - 3 }),
622
- /* @__PURE__ */ jsx5(
732
+ const conversation = start ? /* @__PURE__ */ jsx6(
733
+ StartPanel,
734
+ {
735
+ engine: props.engine,
736
+ profile: props.session.profile,
737
+ agentName: start.agent.workflowName,
738
+ conversations: start.conversations,
739
+ onNew: () => openNewChat(start.agent),
740
+ onOpen: openHistory,
741
+ onCancel: () => {
742
+ setStart(void 0);
743
+ setFocus("agents");
744
+ }
745
+ }
746
+ ) : /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", flexGrow: 1, children: [
747
+ /* @__PURE__ */ jsx6(ChatPane, { agent: selected, messages: chat.messages, status: chat.status, height: bodyHeight - 3 }),
748
+ /* @__PURE__ */ jsx6(
623
749
  Composer,
624
750
  {
625
751
  value: input,
@@ -631,13 +757,13 @@ function Dashboard(props) {
631
757
  }
632
758
  )
633
759
  ] });
634
- body = size.wide ? /* @__PURE__ */ jsxs5(Box4, { height: bodyHeight, children: [
760
+ body = size.wide ? /* @__PURE__ */ jsxs6(Box5, { height: bodyHeight, children: [
635
761
  sidebar,
636
762
  conversation
637
- ] }) : focus === "agents" ? /* @__PURE__ */ jsx5(Box4, { height: bodyHeight, children: sidebar }) : /* @__PURE__ */ jsx5(Box4, { height: bodyHeight, children: conversation });
763
+ ] }) : focus === "agents" ? /* @__PURE__ */ jsx6(Box5, { height: bodyHeight, children: sidebar }) : /* @__PURE__ */ jsx6(Box5, { height: bodyHeight, children: conversation });
638
764
  }
639
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
640
- /* @__PURE__ */ jsx5(
765
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
766
+ /* @__PURE__ */ jsx6(
641
767
  Header,
642
768
  {
643
769
  profile: props.session.profile,
@@ -646,22 +772,23 @@ function Dashboard(props) {
646
772
  }
647
773
  ),
648
774
  body,
649
- /* @__PURE__ */ jsx5(Footer, { text: "Tab \uD328\uB110 \xB7 Ctrl+K \uBA85\uB839 \xB7 Ctrl+H \uAE30\uB85D \xB7 Ctrl+P \uD504\uB85C\uD544 \xB7 Esc \uCDE8\uC18C \xB7 Ctrl+Q \uC885\uB8CC" })
775
+ /* @__PURE__ */ jsx6(Footer, { text: "Tab \uD328\uB110 \xB7 Ctrl+K \uBA85\uB839 \xB7 Ctrl+H \uAE30\uB85D \xB7 Ctrl+P \uD504\uB85C\uD544 \xB7 Esc \uCDE8\uC18C \xB7 Ctrl+Q \uC885\uB8CC" })
650
776
  ] });
651
777
  }
652
778
 
653
779
  // src/tui/login-screen.tsx
654
- import { useState as useState6 } from "react";
655
- import { Box as Box5, Text as Text6, useInput as useInput5 } from "ink";
656
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
780
+ import { useState as useState7 } from "react";
781
+ import { Box as Box6, Text as Text7, useInput as useInput6 } from "ink";
782
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
657
783
  function LoginScreen(props) {
658
- const [email, setEmail] = useState6("");
659
- const [password, setPassword] = useState6("");
660
- const [focus, setFocus] = useState6("email");
661
- useInput5(
784
+ const [email, setEmail] = useState7("");
785
+ const [password, setPassword] = useState7("");
786
+ const [focus, setFocus] = useState7("email");
787
+ useInput6(
662
788
  (input, key) => {
663
789
  if (key.tab) setFocus((current) => current === "email" ? "password" : "email");
664
790
  if (key.ctrl && input === "p") props.onProfiles();
791
+ if (key.ctrl && input === "e") props.onEditServer();
665
792
  },
666
793
  { isActive: !props.busy }
667
794
  );
@@ -676,13 +803,17 @@ function LoginScreen(props) {
676
803
  props.onSubmit(email.trim(), secret);
677
804
  }
678
805
  };
679
- return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
680
- /* @__PURE__ */ jsx6(Header, { profile: props.profile, connected: false }),
681
- /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
682
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "\uB85C\uADF8\uC778" }),
683
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: props.serverUrl }),
684
- /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", marginTop: 1, children: [
685
- /* @__PURE__ */ jsx6(
806
+ return /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", children: [
807
+ /* @__PURE__ */ jsx7(Header, { profile: props.profile, connected: false }),
808
+ /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
809
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: "\uB85C\uADF8\uC778" }),
810
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
811
+ props.serverUrl,
812
+ " ",
813
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "(Ctrl+E \uBC14\uAFB8\uAE30)" })
814
+ ] }),
815
+ /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", marginTop: 1, children: [
816
+ /* @__PURE__ */ jsx7(
686
817
  FormField,
687
818
  {
688
819
  label: "Email",
@@ -694,7 +825,7 @@ function LoginScreen(props) {
694
825
  placeholder: "me@corp.com"
695
826
  }
696
827
  ),
697
- /* @__PURE__ */ jsx6(
828
+ /* @__PURE__ */ jsx7(
698
829
  FormField,
699
830
  {
700
831
  label: "Password",
@@ -707,25 +838,25 @@ function LoginScreen(props) {
707
838
  }
708
839
  )
709
840
  ] }),
710
- props.busy ? /* @__PURE__ */ jsx6(Loading, { label: "\uB85C\uADF8\uC778\uD558\uB294 \uC911..." }) : null,
711
- props.error ? /* @__PURE__ */ jsx6(Notice, { error: true, children: props.error }) : null
841
+ props.busy ? /* @__PURE__ */ jsx7(Loading, { label: "\uB85C\uADF8\uC778\uD558\uB294 \uC911..." }) : null,
842
+ props.error ? /* @__PURE__ */ jsx7(Notice, { error: true, children: props.error }) : null
712
843
  ] }),
713
- /* @__PURE__ */ jsx6(Footer, { text: "Tab \uC774\uB3D9 \xB7 Enter \uB85C\uADF8\uC778 \xB7 Ctrl+P \uD504\uB85C\uD544 \xB7 Ctrl+Q \uC885\uB8CC" })
844
+ /* @__PURE__ */ jsx7(Footer, { text: "Tab \uC774\uB3D9 \xB7 Enter \uB85C\uADF8\uC778 \xB7 Ctrl+E \uC11C\uBC84 \xB7 Ctrl+P \uD504\uB85C\uD544 \xB7 Ctrl+Q \uC885\uB8CC" })
714
845
  ] });
715
846
  }
716
847
 
717
848
  // src/tui/profile-screen.tsx
718
- import { useEffect as useEffect5, useState as useState7 } from "react";
719
- import { Box as Box6, Text as Text7, useInput as useInput6 } from "ink";
720
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
849
+ import { useEffect as useEffect6, useState as useState8 } from "react";
850
+ import { Box as Box7, Text as Text8, useInput as useInput7 } from "ink";
851
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
721
852
  function ProfileScreen(props) {
722
- const [cursor, setCursor] = useState7(Math.max(0, props.profiles.findIndex((profile) => profile.current)));
723
- const [creating, setCreating] = useState7(false);
724
- const [focus, setFocus] = useState7("name");
725
- const [name, setName] = useState7("");
726
- const [serverUrl, setServerUrl] = useState7("");
727
- useEffect5(() => setCursor((current) => Math.min(current, Math.max(0, props.profiles.length - 1))), [props.profiles]);
728
- useInput6(
853
+ const [cursor, setCursor] = useState8(Math.max(0, props.profiles.findIndex((profile) => profile.current)));
854
+ const [creating, setCreating] = useState8(false);
855
+ const [focus, setFocus] = useState8("name");
856
+ const [name, setName] = useState8("");
857
+ const [serverUrl, setServerUrl] = useState8("");
858
+ useEffect6(() => setCursor((current) => Math.min(current, Math.max(0, props.profiles.length - 1))), [props.profiles]);
859
+ useInput7(
729
860
  (input, key) => {
730
861
  if (key.escape) {
731
862
  if (creating) setCreating(false);
@@ -755,12 +886,12 @@ function ProfileScreen(props) {
755
886
  }
756
887
  if (name.trim() && serverUrl.trim()) props.onCreate(name.trim(), serverUrl.trim());
757
888
  };
758
- return /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", children: [
759
- /* @__PURE__ */ jsx7(Header, {}),
760
- /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
761
- /* @__PURE__ */ jsx7(Text7, { bold: true, children: creating ? "\uC0C8 \uD504\uB85C\uD544" : "\uD504\uB85C\uD544 \uC804\uD658" }),
762
- creating ? /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", marginTop: 1, children: [
763
- /* @__PURE__ */ jsx7(
889
+ return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
890
+ /* @__PURE__ */ jsx8(Header, {}),
891
+ /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
892
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: creating ? "\uC0C8 \uD504\uB85C\uD544" : "\uD504\uB85C\uD544 \uC804\uD658" }),
893
+ creating ? /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", marginTop: 1, children: [
894
+ /* @__PURE__ */ jsx8(
764
895
  FormField,
765
896
  {
766
897
  label: "Name",
@@ -772,7 +903,7 @@ function ProfileScreen(props) {
772
903
  placeholder: "corp"
773
904
  }
774
905
  ),
775
- /* @__PURE__ */ jsx7(
906
+ /* @__PURE__ */ jsx8(
776
907
  FormField,
777
908
  {
778
909
  label: "Server URL",
@@ -784,8 +915,8 @@ function ProfileScreen(props) {
784
915
  placeholder: "https://xgen.example.com"
785
916
  }
786
917
  )
787
- ] }) : /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", marginTop: 1, children: [
788
- props.profiles.map((profile, index) => /* @__PURE__ */ jsxs7(Text7, { color: index === cursor ? "cyan" : void 0, children: [
918
+ ] }) : /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", marginTop: 1, children: [
919
+ props.profiles.map((profile, index) => /* @__PURE__ */ jsxs8(Text8, { color: index === cursor ? "cyan" : void 0, children: [
789
920
  index === cursor ? "\u203A" : " ",
790
921
  " ",
791
922
  profile.current ? "\u25CF" : "\u25CB",
@@ -793,14 +924,14 @@ function ProfileScreen(props) {
793
924
  profile.name,
794
925
  " \xB7",
795
926
  " ",
796
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: profile.serverUrl })
927
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: profile.serverUrl })
797
928
  ] }, profile.name)),
798
- props.profiles.length === 0 ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\uC800\uC7A5\uB41C \uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : null
929
+ props.profiles.length === 0 ? /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\uC800\uC7A5\uB41C \uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : null
799
930
  ] }),
800
- props.busy ? /* @__PURE__ */ jsx7(Loading, { label: "\uD504\uB85C\uD544\uC744 \uC804\uD658\uD558\uB294 \uC911..." }) : null,
801
- props.error ? /* @__PURE__ */ jsx7(Notice, { error: true, children: props.error }) : null
931
+ props.busy ? /* @__PURE__ */ jsx8(Loading, { label: "\uD504\uB85C\uD544\uC744 \uC804\uD658\uD558\uB294 \uC911..." }) : null,
932
+ props.error ? /* @__PURE__ */ jsx8(Notice, { error: true, children: props.error }) : null
802
933
  ] }),
803
- /* @__PURE__ */ jsx7(
934
+ /* @__PURE__ */ jsx8(
804
935
  Footer,
805
936
  {
806
937
  text: creating ? "Tab \uC774\uB3D9 \xB7 Enter \uC800\uC7A5 \xB7 Esc \uB4A4\uB85C" : "\u2191\u2193 \uC774\uB3D9 \xB7 Enter \uC120\uD0DD \xB7 N \uC0C8 \uD504\uB85C\uD544 \xB7 Esc \uB2EB\uAE30"
@@ -809,18 +940,25 @@ function ProfileScreen(props) {
809
940
  ] });
810
941
  }
811
942
 
812
- // src/tui/setup-screen.tsx
813
- import { useState as useState8 } from "react";
814
- import { Box as Box7, Text as Text8 } from "ink";
815
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
816
- function SetupScreen(props) {
817
- const [serverUrl, setServerUrl] = useState8("");
818
- return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
819
- /* @__PURE__ */ jsx8(Header, {}),
820
- /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
821
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "\uCC98\uC74C \uC624\uC168\uAD70\uC694" }),
822
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\uC5F0\uACB0\uD560 XGEN Gateway \uC8FC\uC18C\uB97C \uC785\uB825\uD558\uC138\uC694." }),
823
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
943
+ // src/tui/server-screen.tsx
944
+ import { useState as useState9 } from "react";
945
+ import { Box as Box8, Text as Text9, useInput as useInput8 } from "ink";
946
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
947
+ function ServerScreen(props) {
948
+ const [serverUrl, setServerUrl] = useState9(props.initialValue ?? "");
949
+ const editing = props.initialValue !== void 0;
950
+ useInput8(
951
+ (_input, key) => {
952
+ if (key.escape) props.onCancel?.();
953
+ },
954
+ { isActive: !props.busy && !!props.onCancel }
955
+ );
956
+ return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", children: [
957
+ /* @__PURE__ */ jsx9(Header, { profile: props.profile, connected: false }),
958
+ /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "blue", padding: 1, children: [
959
+ /* @__PURE__ */ jsx9(Text9, { bold: true, children: editing ? "\uC11C\uBC84 \uC8FC\uC18C \uBC14\uAFB8\uAE30" : "\uCC98\uC74C \uC624\uC168\uAD70\uC694" }),
960
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\uC5F0\uACB0\uD560 XGEN Gateway \uC8FC\uC18C\uB97C \uC785\uB825\uD558\uC138\uC694." }),
961
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
824
962
  FormField,
825
963
  {
826
964
  label: "Server URL",
@@ -829,27 +967,34 @@ function SetupScreen(props) {
829
967
  onSubmit: (value) => value.trim() && props.onSubmit(value.trim()),
830
968
  focus: !props.busy,
831
969
  cursorOrigin: { x: 16, y: 6 },
832
- placeholder: "https://xgen.example.com"
970
+ placeholder: "xgen.example.com"
833
971
  }
834
972
  ) }),
835
- props.busy ? /* @__PURE__ */ jsx8(Loading, { label: "\uC11C\uBC84 \uD504\uB85C\uD544\uC744 \uC800\uC7A5\uD558\uB294 \uC911..." }) : null,
836
- props.error ? /* @__PURE__ */ jsx8(Notice, { error: true, children: props.error }) : null
973
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "https:// \uB294 \uC0DD\uB7B5\uD574\uB3C4 \uB429\uB2C8\uB2E4." }),
974
+ props.busy ? /* @__PURE__ */ jsx9(Loading, { label: "\uC11C\uBC84 \uD504\uB85C\uD544\uC744 \uC800\uC7A5\uD558\uB294 \uC911..." }) : null,
975
+ props.error ? /* @__PURE__ */ jsx9(Notice, { error: true, children: props.error }) : null
837
976
  ] }),
838
- /* @__PURE__ */ jsx8(Footer, { text: "Enter \uACC4\uC18D \xB7 Ctrl+Q \uC885\uB8CC" })
977
+ /* @__PURE__ */ jsx9(
978
+ Footer,
979
+ {
980
+ text: props.onCancel ? "Enter \uC800\uC7A5 \xB7 Esc \uCDE8\uC18C \xB7 Ctrl+Q \uC885\uB8CC" : "Enter \uACC4\uC18D \xB7 Ctrl+Q \uC885\uB8CC"
981
+ }
982
+ )
839
983
  ] });
840
984
  }
841
985
 
842
986
  // src/tui/app.tsx
843
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
987
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
844
988
  function App({ engine }) {
845
989
  const { exit } = useApp2();
846
- const [route, setRoute] = useState9("boot");
847
- const [session, setSession] = useState9();
848
- const [profiles, setProfiles] = useState9([]);
849
- const [loginTarget, setLoginTarget] = useState9();
850
- const [busy, setBusy] = useState9(false);
851
- const [error, setError] = useState9();
852
- useInput7((input, key) => {
990
+ const [route, setRoute] = useState10("boot");
991
+ const [session, setSession] = useState10();
992
+ const [profiles, setProfiles] = useState10([]);
993
+ const [loginTarget, setLoginTarget] = useState10();
994
+ const [editingServer, setEditingServer] = useState10();
995
+ const [busy, setBusy] = useState10(false);
996
+ const [error, setError] = useState10();
997
+ useInput9((input, key) => {
853
998
  if (key.ctrl && input === "q") exit();
854
999
  });
855
1000
  const bootstrap = useCallback(
@@ -862,7 +1007,7 @@ function App({ engine }) {
862
1007
  setProfiles(available);
863
1008
  if (available.length === 0) {
864
1009
  setSession(void 0);
865
- setRoute("setup");
1010
+ setRoute("server");
866
1011
  return;
867
1012
  }
868
1013
  if (preferredProfile) {
@@ -899,17 +1044,19 @@ function App({ engine }) {
899
1044
  },
900
1045
  [engine]
901
1046
  );
902
- useEffect6(() => {
1047
+ useEffect7(() => {
903
1048
  void bootstrap();
904
1049
  }, [bootstrap]);
905
1050
  const configure = async (serverUrl) => {
906
1051
  setBusy(true);
907
1052
  setError(void 0);
1053
+ const target = editingServer?.profile ?? loginTarget?.profile ?? "default";
908
1054
  try {
909
- const profile = await engine.setProfile("default", serverUrl);
1055
+ const profile = await engine.setProfile(target, serverUrl);
910
1056
  await engine.useProfile(profile.name);
911
1057
  setLoginTarget({ profile: profile.name, serverUrl: profile.serverUrl });
912
1058
  setProfiles(await engine.listProfiles());
1059
+ setEditingServer(void 0);
913
1060
  setRoute("login");
914
1061
  } catch (reason) {
915
1062
  setError(publicError(reason).message);
@@ -972,17 +1119,31 @@ function App({ engine }) {
972
1119
  }
973
1120
  };
974
1121
  if (route === "boot") {
975
- return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", children: [
976
- /* @__PURE__ */ jsx9(Header, {}),
977
- /* @__PURE__ */ jsx9(Loading, { label: "Dex\uB97C \uC900\uBE44\uD558\uB294 \uC911..." }),
978
- /* @__PURE__ */ jsx9(Footer, { text: "Ctrl+Q \uC885\uB8CC" })
1122
+ return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", children: [
1123
+ /* @__PURE__ */ jsx10(Header, {}),
1124
+ /* @__PURE__ */ jsx10(Loading, { label: "Dex\uB97C \uC900\uBE44\uD558\uB294 \uC911..." }),
1125
+ /* @__PURE__ */ jsx10(Footer, { text: "Ctrl+Q \uC885\uB8CC" })
979
1126
  ] });
980
1127
  }
981
- if (route === "setup") {
982
- return /* @__PURE__ */ jsx9(SetupScreen, { busy, error, onSubmit: (url) => void configure(url) });
1128
+ if (route === "server") {
1129
+ return /* @__PURE__ */ jsx10(
1130
+ ServerScreen,
1131
+ {
1132
+ initialValue: editingServer?.serverUrl,
1133
+ profile: editingServer?.profile,
1134
+ busy,
1135
+ error,
1136
+ onSubmit: (url) => void configure(url),
1137
+ onCancel: editingServer ? () => {
1138
+ setEditingServer(void 0);
1139
+ setError(void 0);
1140
+ setRoute("login");
1141
+ } : void 0
1142
+ }
1143
+ );
983
1144
  }
984
1145
  if (route === "login" && loginTarget) {
985
- return /* @__PURE__ */ jsx9(
1146
+ return /* @__PURE__ */ jsx10(
986
1147
  LoginScreen,
987
1148
  {
988
1149
  profile: loginTarget.profile,
@@ -990,12 +1151,17 @@ function App({ engine }) {
990
1151
  busy,
991
1152
  error,
992
1153
  onSubmit: (email, password) => void login(email, password),
993
- onProfiles: () => void openProfiles()
1154
+ onProfiles: () => void openProfiles(),
1155
+ onEditServer: () => {
1156
+ setEditingServer(loginTarget);
1157
+ setError(void 0);
1158
+ setRoute("server");
1159
+ }
994
1160
  }
995
1161
  );
996
1162
  }
997
1163
  if (route === "profiles") {
998
- return /* @__PURE__ */ jsx9(
1164
+ return /* @__PURE__ */ jsx10(
999
1165
  ProfileScreen,
1000
1166
  {
1001
1167
  profiles,
@@ -1003,12 +1169,12 @@ function App({ engine }) {
1003
1169
  error,
1004
1170
  onSelect: (name) => void bootstrap(name),
1005
1171
  onCreate: (name, url) => void createProfile(name, url),
1006
- onCancel: () => setRoute(session ? "dashboard" : loginTarget ? "login" : "setup")
1172
+ onCancel: () => setRoute(session ? "dashboard" : loginTarget ? "login" : "server")
1007
1173
  }
1008
1174
  );
1009
1175
  }
1010
1176
  if (route === "dashboard" && session) {
1011
- return /* @__PURE__ */ jsx9(
1177
+ return /* @__PURE__ */ jsx10(
1012
1178
  Dashboard,
1013
1179
  {
1014
1180
  engine,
@@ -1018,25 +1184,25 @@ function App({ engine }) {
1018
1184
  }
1019
1185
  );
1020
1186
  }
1021
- return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", children: [
1022
- /* @__PURE__ */ jsx9(Header, {}),
1023
- /* @__PURE__ */ jsx9(Notice, { error: true, children: error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4." }),
1024
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\uC11C\uBC84\uC640 \uD0A4\uCCB4\uC778 \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694." }),
1025
- /* @__PURE__ */ jsx9(Footer, { text: "R \uB2E4\uC2DC \uC2DC\uB3C4 \xB7 Ctrl+Q \uC885\uB8CC" }),
1026
- /* @__PURE__ */ jsx9(RetryInput, { onRetry: () => void bootstrap() })
1187
+ return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", children: [
1188
+ /* @__PURE__ */ jsx10(Header, {}),
1189
+ /* @__PURE__ */ jsx10(Notice, { error: true, children: error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4." }),
1190
+ /* @__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." }),
1191
+ /* @__PURE__ */ jsx10(Footer, { text: "R \uB2E4\uC2DC \uC2DC\uB3C4 \xB7 Ctrl+Q \uC885\uB8CC" }),
1192
+ /* @__PURE__ */ jsx10(RetryInput, { onRetry: () => void bootstrap() })
1027
1193
  ] });
1028
1194
  }
1029
1195
  function RetryInput({ onRetry }) {
1030
- useInput7((input) => {
1196
+ useInput9((input) => {
1031
1197
  if (input.toLowerCase() === "r") onRetry();
1032
1198
  });
1033
1199
  return null;
1034
1200
  }
1035
1201
 
1036
1202
  // src/tui/index.tsx
1037
- import { jsx as jsx10 } from "react/jsx-runtime";
1203
+ import { jsx as jsx11 } from "react/jsx-runtime";
1038
1204
  async function runTui(engine) {
1039
- const instance = render(/* @__PURE__ */ jsx10(App, { engine }), {
1205
+ const instance = render(/* @__PURE__ */ jsx11(App, { engine }), {
1040
1206
  exitOnCtrlC: true,
1041
1207
  patchConsole: true
1042
1208
  });
@@ -1045,4 +1211,4 @@ async function runTui(engine) {
1045
1211
  export {
1046
1212
  runTui
1047
1213
  };
1048
- //# sourceMappingURL=tui-PNFWGJTJ.js.map
1214
+ //# sourceMappingURL=tui-GDC2NODL.js.map