openxgen 2.2.1 → 2.4.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.
package/dist/index.js CHANGED
@@ -894,23 +894,40 @@ var init_provider = __esm({
894
894
  // src/api/xgen-extra.ts
895
895
  var xgen_extra_exports = {};
896
896
  __export(xgen_extra_exports, {
897
+ apiTest: () => apiTest,
898
+ changePromptVersion: () => changePromptVersion,
899
+ createMcpSession: () => createMcpSession,
897
900
  createPrompt: () => createPrompt,
901
+ deleteMcpSession: () => deleteMcpSession,
902
+ deletePrompt: () => deletePrompt,
898
903
  generateWorkflow: () => generateWorkflow,
904
+ getMcpSession: () => getMcpSession,
905
+ getMcpSessionTools: () => getMcpSessionTools,
899
906
  getNodeCategories: () => getNodeCategories,
900
907
  getNodeDetail: () => getNodeDetail,
908
+ getNodeParameters: () => getNodeParameters,
909
+ getNodeTags: () => getNodeTags,
901
910
  getSchedulerStatus: () => getSchedulerStatus,
902
911
  getTraceDetail: () => getTraceDetail,
903
912
  getWorkflowPerformance: () => getWorkflowPerformance,
904
913
  listInteractions: () => listInteractions,
905
914
  listMcpSessions: () => listMcpSessions,
906
915
  listNodes: () => listNodes,
916
+ listPromptStore: () => listPromptStore,
917
+ listPromptVersions: () => listPromptVersions,
907
918
  listPrompts: () => listPrompts,
908
919
  listSchedules: () => listSchedules,
909
920
  listToolStore: () => listToolStore,
910
921
  listTraces: () => listTraces,
911
922
  listUserTools: () => listUserTools,
912
923
  listWorkflowStore: () => listWorkflowStore,
913
- searchNodes: () => searchNodes
924
+ saveTool: () => saveTool,
925
+ searchNodes: () => searchNodes,
926
+ sendMcpRequest: () => sendMcpRequest,
927
+ toolTest: () => toolTest,
928
+ updatePrompt: () => updatePrompt,
929
+ uploadPromptToStore: () => uploadPromptToStore,
930
+ uploadToolToStore: () => uploadToolToStore
914
931
  });
915
932
  async function listNodes() {
916
933
  const client2 = getClient();
@@ -939,11 +956,6 @@ async function listPrompts(opts) {
939
956
  const res = await client2.get("/api/prompt/list", { params });
940
957
  return res.data.prompts ?? res.data ?? [];
941
958
  }
942
- async function createPrompt(data) {
943
- const client2 = getClient();
944
- const res = await client2.post("/api/prompt/create", data);
945
- return res.data;
946
- }
947
959
  async function listToolStore() {
948
960
  const client2 = getClient();
949
961
  const res = await client2.get("/api/tools/store/list");
@@ -1000,11 +1012,108 @@ async function getWorkflowPerformance(workflowId, workflowName) {
1000
1012
  });
1001
1013
  return res.data;
1002
1014
  }
1015
+ async function saveTool(functionName, content) {
1016
+ const client2 = getClient();
1017
+ const res = await client2.post("/api/tools/storage/save", { function_name: functionName, content });
1018
+ return res.data;
1019
+ }
1020
+ async function apiTest(params) {
1021
+ const client2 = getClient();
1022
+ const res = await client2.post("/api/tools/storage/api-test", params);
1023
+ return res.data;
1024
+ }
1025
+ async function toolTest(toolId, functionId) {
1026
+ const client2 = getClient();
1027
+ const res = await client2.post(`/api/tools/storage/tool-test?tool_id=${toolId}&function_id=${functionId}`);
1028
+ return res.data;
1029
+ }
1030
+ async function uploadToolToStore(functionUploadId, description, tags) {
1031
+ const client2 = getClient();
1032
+ const res = await client2.post("/api/tools/store/upload", {
1033
+ function_upload_id: functionUploadId,
1034
+ description: description ?? "",
1035
+ tags: tags ?? []
1036
+ });
1037
+ return res.data;
1038
+ }
1039
+ async function createPrompt(data) {
1040
+ const client2 = getClient();
1041
+ const res = await client2.post("/api/prompt/create", data);
1042
+ return res.data;
1043
+ }
1044
+ async function updatePrompt(data) {
1045
+ const client2 = getClient();
1046
+ const res = await client2.post("/api/prompt/update", data);
1047
+ return res.data;
1048
+ }
1049
+ async function deletePrompt(promptUid) {
1050
+ const client2 = getClient();
1051
+ const res = await client2.post("/api/prompt/delete", { prompt_uid: promptUid });
1052
+ return res.data;
1053
+ }
1054
+ async function getNodeTags() {
1055
+ const client2 = getClient();
1056
+ const res = await client2.get("/api/node/tags");
1057
+ return res.data ?? [];
1058
+ }
1059
+ async function getNodeParameters(nodeId) {
1060
+ const client2 = getClient();
1061
+ const res = await client2.get(`/api/node/parameters/categorized/${nodeId}`);
1062
+ return res.data;
1063
+ }
1064
+ async function listPromptStore() {
1065
+ const client2 = getClient();
1066
+ const res = await client2.post("/api/prompt/store/list");
1067
+ return res.data.prompts ?? res.data ?? [];
1068
+ }
1069
+ async function uploadPromptToStore(promptId) {
1070
+ const client2 = getClient();
1071
+ const res = await client2.post(`/api/prompt/store/upload`, null, { params: { prompt_id: promptId } });
1072
+ return res.data;
1073
+ }
1074
+ async function listPromptVersions(promptUid) {
1075
+ const client2 = getClient();
1076
+ const res = await client2.get("/api/prompt/version/list", { params: { prompt_uid: promptUid } });
1077
+ return res.data.versions ?? res.data ?? [];
1078
+ }
1079
+ async function changePromptVersion(promptUid, version) {
1080
+ const client2 = getClient();
1081
+ const res = await client2.post("/api/prompt/version/change", { prompt_uid: promptUid, version });
1082
+ return res.data;
1083
+ }
1003
1084
  async function listMcpSessions() {
1004
1085
  const client2 = getClient();
1005
1086
  const res = await client2.get("/api/mcp/sessions");
1006
1087
  return res.data.sessions ?? res.data ?? [];
1007
1088
  }
1089
+ async function createMcpSession(data) {
1090
+ const client2 = getClient();
1091
+ const res = await client2.post("/api/mcp/sessions", data);
1092
+ return res.data;
1093
+ }
1094
+ async function getMcpSession(sessionId) {
1095
+ const client2 = getClient();
1096
+ const res = await client2.get(`/api/mcp/sessions/${sessionId}`);
1097
+ return res.data;
1098
+ }
1099
+ async function deleteMcpSession(sessionId) {
1100
+ const client2 = getClient();
1101
+ await client2.delete(`/api/mcp/sessions/${sessionId}`);
1102
+ }
1103
+ async function getMcpSessionTools(sessionId) {
1104
+ const client2 = getClient();
1105
+ const res = await client2.get(`/api/mcp/sessions/${sessionId}/tools`);
1106
+ return res.data.tools ?? res.data ?? [];
1107
+ }
1108
+ async function sendMcpRequest(sessionId, method, params) {
1109
+ const client2 = getClient();
1110
+ const res = await client2.post("/api/mcp/mcp-request", {
1111
+ session_id: sessionId,
1112
+ method,
1113
+ params
1114
+ });
1115
+ return res.data;
1116
+ }
1008
1117
  var init_xgen_extra = __esm({
1009
1118
  "src/api/xgen-extra.ts"() {
1010
1119
  "use strict";
@@ -1108,288 +1217,1046 @@ var init_ontology = __esm({
1108
1217
  }
1109
1218
  });
1110
1219
 
1111
- // src/dashboard/InkDashboard.tsx
1112
- var InkDashboard_exports = {};
1113
- __export(InkDashboard_exports, {
1114
- startInkDashboard: () => startInkDashboard
1220
+ // src/dashboard/raw-tui.ts
1221
+ var raw_tui_exports = {};
1222
+ __export(raw_tui_exports, {
1223
+ startRawTui: () => startRawTui
1115
1224
  });
1116
- import { useState, useEffect } from "react";
1117
- import { render, Box, Text, useInput, useApp, useStdout } from "ink";
1118
- import TextInput from "ink-text-input";
1119
- import { jsx, jsxs } from "react/jsx-runtime";
1120
- function Header({ tab, serverDisplay, model }) {
1121
- const tabStr = TABS.map((t) => {
1122
- const active = tab === t.key;
1123
- return `[${t.shortcut}]${active ? "\u25B8" : " "}${t.label}`;
1124
- }).join(" ");
1125
- return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
1126
- /* @__PURE__ */ jsx(Text, { bold: true, children: "OPEN XGEN" }),
1127
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1128
- " ",
1129
- model,
1130
- " ",
1131
- serverDisplay,
1132
- " \u2502 ",
1133
- tabStr
1134
- ] })
1135
- ] });
1136
- }
1137
- function ListPanel({ items, selected, onSelect }) {
1138
- const { stdout } = useStdout();
1139
- const height = (stdout?.rows ?? 24) - 8;
1140
- const visibleCount = Math.max(1, height);
1141
- const start = Math.max(0, Math.min(selected - Math.floor(visibleCount / 2), items.length - visibleCount));
1142
- const visible = items.slice(start, start + visibleCount);
1143
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "50%", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
1144
- visible.map((item, i) => {
1145
- const realIndex = start + i;
1146
- const isSelected = realIndex === selected;
1147
- return /* @__PURE__ */ jsxs(Text, { inverse: isSelected, children: [
1148
- isSelected ? "\u25B8 " : " ",
1149
- item.label,
1150
- item.dimLabel ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1151
- " ",
1152
- item.dimLabel
1153
- ] }) : null
1154
- ] }, `item-${realIndex}`);
1155
- }),
1156
- items.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (\uC5C6\uC74C)" })
1157
- ] });
1158
- }
1159
- function DetailPanel({ lines }) {
1160
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "50%", borderStyle: "single", borderColor: "gray", paddingX: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { children: line }, `line-${i}`)) });
1161
- }
1162
- function StatusBar({ message }) {
1163
- return /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: message }) });
1164
- }
1165
- function InputBar({ value, onChange, onSubmit, placeholder }) {
1166
- return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
1167
- /* @__PURE__ */ jsx(Text, { children: "\u276F " }),
1168
- /* @__PURE__ */ jsx(
1169
- TextInput,
1170
- {
1171
- value,
1172
- onChange,
1173
- onSubmit,
1174
- placeholder: placeholder ?? "\uC785\uB825..."
1175
- }
1176
- )
1177
- ] });
1225
+ function withTimeout(p, ms = 5e3, label = "API") {
1226
+ return new Promise((resolve, reject) => {
1227
+ const t = setTimeout(() => reject(new Error(`${label} \uD0C0\uC784\uC544\uC6C3 (${ms}ms)`)), ms);
1228
+ p.then((v) => {
1229
+ clearTimeout(t);
1230
+ resolve(v);
1231
+ }, (e) => {
1232
+ clearTimeout(t);
1233
+ reject(e);
1234
+ });
1235
+ });
1178
1236
  }
1179
- function Dashboard() {
1180
- const { exit } = useApp();
1237
+ async function startRawTui() {
1181
1238
  const provider = getDefaultProvider();
1182
1239
  const server = getServer();
1183
1240
  const auth = getAuth();
1184
- const serverDisplay = auth && server ? `${auth.username}@${server.replace("https://", "").replace("http://", "")}` : "\uBBF8\uC5F0\uACB0";
1185
- const [tab, setTab] = useState("workflows");
1186
- const [selected, setSelected] = useState(0);
1187
- const [workflows, setWorkflows] = useState([]);
1188
- const [collections, setCollections] = useState([]);
1189
- const [nodes, setNodes] = useState([]);
1190
- const [prompts, setPrompts] = useState([]);
1191
- const [tools2, setTools] = useState([]);
1192
- const [detail, setDetail] = useState(["\u2190 \uD56D\uBAA9\uC744 \uC120\uD0DD\uD558\uC138\uC694"]);
1193
- const [inputValue, setInputValue] = useState("");
1194
- const [inputMode, setInputMode] = useState(false);
1195
- const [runTarget, setRunTarget] = useState(null);
1196
- const [loading, setLoading] = useState(true);
1197
- const [statusMsg, setStatusMsg] = useState("\uB85C\uB529...");
1198
- useEffect(() => {
1199
- loadAll();
1200
- }, []);
1201
- async function loadAll() {
1202
- setLoading(true);
1203
- setStatusMsg("\uB85C\uB529...");
1241
+ const serverDisplay = auth && server ? `${auth.username}@${server.replace(/https?:\/\//, "")}` : "\uBBF8\uC5F0\uACB0";
1242
+ let tab = "workflows";
1243
+ let selected = 0;
1244
+ let inputMode = false;
1245
+ let inputBuffer = "";
1246
+ let formCtx = null;
1247
+ let workflows = [];
1248
+ let collections = [];
1249
+ let nodes = [];
1250
+ let prompts = [];
1251
+ let tools2 = [];
1252
+ let mcpSessions = [];
1253
+ let detail = ["\u2190 \uD56D\uBAA9\uC744 \uC120\uD0DD\uD558\uC138\uC694"];
1254
+ let statusMsg = "\uB85C\uB529...";
1255
+ let errors = [];
1256
+ async function loadData() {
1257
+ statusMsg = "\uB370\uC774\uD130 \uB85C\uB529 \uC911...";
1258
+ errors = [];
1259
+ render();
1260
+ if (!server || !auth) {
1261
+ statusMsg = "\uC11C\uBC84 \uBBF8\uC5F0\uACB0";
1262
+ detail = [red("\uC11C\uBC84 \uBBF8\uC5F0\uACB0"), "", cyan(" xgen config set-server <URL>"), cyan(" xgen login"), "", "\uD6C4 r \uC0C8\uB85C\uACE0\uCE68"];
1263
+ render();
1264
+ return;
1265
+ }
1204
1266
  try {
1205
- if (server && auth) {
1206
- const [wfMod, docMod, extraMod] = await Promise.all([
1207
- Promise.resolve().then(() => (init_workflow(), workflow_exports)),
1208
- Promise.resolve().then(() => (init_document(), document_exports)),
1209
- Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports))
1210
- ]);
1211
- const [wfs, cols, nodeList, promptList, toolList] = await Promise.allSettled([
1212
- wfMod.getWorkflowListDetail(),
1213
- docMod.listCollections(),
1214
- extraMod.listNodes(),
1215
- extraMod.listPrompts(),
1216
- extraMod.listToolStore()
1217
- ]);
1218
- if (wfs.status === "fulfilled") {
1219
- setWorkflows(wfs.value.map((w) => ({
1220
- name: w.workflow_name,
1221
- id: w.workflow_id ?? w.id ?? "",
1222
- deployed: !!w.is_deployed
1223
- })));
1224
- }
1225
- if (cols.status === "fulfilled") {
1226
- setCollections(cols.value.map((c) => ({
1227
- name: c.collection_make_name,
1228
- docs: c.total_documents,
1229
- chunks: c.total_chunks
1230
- })));
1267
+ const [wfMod, docMod, extraMod] = await Promise.all([
1268
+ Promise.resolve().then(() => (init_workflow(), workflow_exports)),
1269
+ Promise.resolve().then(() => (init_document(), document_exports)),
1270
+ Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports))
1271
+ ]);
1272
+ const results = await Promise.allSettled([
1273
+ withTimeout(wfMod.getWorkflowListDetail(), 3e3, "\uC6CC\uD06C\uD50C\uB85C\uC6B0"),
1274
+ withTimeout(docMod.listCollections(), 3e3, "\uCEEC\uB809\uC158"),
1275
+ withTimeout(extraMod.listNodes(), 3e3, "\uB178\uB4DC"),
1276
+ withTimeout(extraMod.listPrompts(), 3e3, "\uD504\uB86C\uD504\uD2B8"),
1277
+ withTimeout(extraMod.listToolStore(), 3e3, "\uB3C4\uAD6C"),
1278
+ withTimeout(extraMod.listMcpSessions(), 3e3, "MCP").catch(() => [])
1279
+ ]);
1280
+ const [wfR, colR, nodeR, promptR, toolR, mcpR] = results;
1281
+ if (wfR.status === "fulfilled") {
1282
+ workflows = wfR.value.map((w) => ({
1283
+ name: w.workflow_name ?? w.name ?? "?",
1284
+ id: w.workflow_id ?? w.id ?? "",
1285
+ deployed: w.deploy_status === "deployed" || w.deploy_status === "DEPLOYED" || !!w.is_deployed
1286
+ }));
1287
+ } else errors.push(`\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${wfR.reason?.message ?? "\uC2E4\uD328"}`);
1288
+ if (colR.status === "fulfilled") {
1289
+ collections = colR.value.map((c) => ({
1290
+ name: c.collection_make_name ?? c.collection_name ?? c.name ?? "?",
1291
+ id: c.id ?? c.collection_id ?? "",
1292
+ docs: c.total_documents ?? 0,
1293
+ chunks: c.total_chunks ?? 0
1294
+ }));
1295
+ } else errors.push(`\uCEEC\uB809\uC158: ${colR.reason?.message ?? "\uC2E4\uD328"}`);
1296
+ if (nodeR.status === "fulfilled") {
1297
+ nodes = [];
1298
+ const raw = nodeR.value;
1299
+ for (const cat of raw) {
1300
+ const catName = cat.categoryName ?? cat.categoryId ?? "";
1301
+ const fns = cat.functions ?? cat.nodes ?? [];
1302
+ if (Array.isArray(fns)) {
1303
+ for (const fn of fns) {
1304
+ const fnNodes = fn.nodes ?? [];
1305
+ if (Array.isArray(fnNodes)) {
1306
+ for (const n of fnNodes) {
1307
+ nodes.push({
1308
+ name: n.nodeName ?? n.name ?? "?",
1309
+ desc: (n.description ?? "").slice(0, 50),
1310
+ id: n.id ?? n.nodeId,
1311
+ category: `${catName}/${fn.functionName ?? fn.functionId ?? ""}`
1312
+ });
1313
+ }
1314
+ } else {
1315
+ nodes.push({
1316
+ name: fn.nodeName ?? fn.name ?? "?",
1317
+ desc: (fn.description ?? "").slice(0, 50),
1318
+ id: fn.id ?? fn.nodeId,
1319
+ category: catName
1320
+ });
1321
+ }
1322
+ }
1323
+ }
1231
1324
  }
1232
- if (nodeList.status === "fulfilled") setNodes(nodeList.value);
1233
- if (promptList.status === "fulfilled") setPrompts(promptList.value);
1234
- if (toolList.status === "fulfilled") setTools(toolList.value);
1325
+ } else errors.push(`\uB178\uB4DC: ${nodeR.reason?.message ?? "\uC2E4\uD328"}`);
1326
+ if (promptR.status === "fulfilled") {
1327
+ prompts = promptR.value.map((p) => ({
1328
+ name: p.prompt_title ?? p.name ?? p.title ?? "?",
1329
+ type: p.prompt_type ?? p.type ?? "",
1330
+ uid: p.prompt_uid ?? p.uid,
1331
+ content: p.prompt_content ?? p.content,
1332
+ dbId: p.id
1333
+ }));
1334
+ } else errors.push(`\uD504\uB86C\uD504\uD2B8: ${promptR.reason?.message ?? "\uC2E4\uD328"}`);
1335
+ if (toolR.status === "fulfilled") {
1336
+ tools2 = toolR.value.map((t) => {
1337
+ const fd = t.function_data ?? {};
1338
+ return {
1339
+ name: fd.function_name ?? t.function_name ?? t.name ?? t.tool_name ?? "?",
1340
+ desc: (fd.description ?? t.description ?? "").slice(0, 50),
1341
+ id: t.id,
1342
+ functionId: fd.function_id ?? t.function_id ?? t.function_upload_id,
1343
+ apiUrl: fd.api_url ?? t.api_url,
1344
+ status: fd.status ?? t.status
1345
+ };
1346
+ });
1347
+ } else errors.push(`\uB3C4\uAD6C: ${toolR.reason?.message ?? "\uC2E4\uD328"}`);
1348
+ if (mcpR.status === "fulfilled" && Array.isArray(mcpR.value)) {
1349
+ mcpSessions = mcpR.value.map((s) => ({
1350
+ id: s.session_id ?? s.id ?? "",
1351
+ name: s.session_name ?? s.name ?? "\uC774\uB984\uC5C6\uC74C",
1352
+ type: s.server_type ?? "?",
1353
+ status: s.status ?? "unknown",
1354
+ command: s.server_command
1355
+ }));
1235
1356
  }
1236
- } catch {
1357
+ } catch (err) {
1358
+ errors.push(`\uC804\uCCB4: ${err.message}`);
1237
1359
  }
1238
- setLoading(false);
1239
- setStatusMsg("\u2191\u2193:\uC774\uB3D9 Enter:\uC120\uD0DD 1-5:\uD0ED i:\uC785\uB825 r:\uC0C8\uB85C\uACE0\uCE68 q:\uC885\uB8CC");
1360
+ selected = 0;
1361
+ updateDetail();
1362
+ statusMsg = errors.length > 0 ? `\u26A0 ${errors.length}\uAC1C \uC624\uB958 \u2502 r \uC7AC\uC2DC\uB3C4` : getHint();
1363
+ if (errors.length > 0) detail = [red("\uB85C\uB4DC \uC624\uB958:"), "", ...errors.map((e) => yellow(` \u2022 ${e}`))];
1364
+ render();
1365
+ }
1366
+ function getHint() {
1367
+ const hints = {
1368
+ workflows: "\u2191\u2193 \u2502 Enter \uB178\uB4DC\uAD6C\uC870/\uC2E4\uD589 \u2502 1-6 \uD0ED \u2502 r \u2502 q",
1369
+ collections: "\u2191\u2193 \u2502 Enter \uBB38\uC11C\uBAA9\uB85D \u2502 1-6 \uD0ED \u2502 r \u2502 q",
1370
+ nodes: "\u2191\u2193 \u2502 Enter \uC0C1\uC138(\uD30C\uB77C\uBBF8\uD130) \u2502 1-6 \uD0ED \u2502 r \u2502 q",
1371
+ prompts: "\u2191\u2193 \u2502 Enter \uB0B4\uC6A9 \u2502 c\uC0DD\uC131 e\uC218\uC815 d\uC0AD\uC81C u\uC2A4\uD1A0\uC5B4 v\uBC84\uC804 \u2502 q",
1372
+ tools: "\u2191\u2193 \u2502 Enter/t \uD14C\uC2A4\uD2B8 \u2502 c\uC0DD\uC131 u\uC2A4\uD1A0\uC5B4\uB4F1\uB85D \u2502 q",
1373
+ mcp: "\u2191\u2193 \u2502 Enter \uB3C4\uAD6C\uBAA9\uB85D \u2502 c\uC138\uC158\uC0DD\uC131 t\uB3C4\uAD6C\uD638\uCD9C d\uC0AD\uC81C \u2502 q"
1374
+ };
1375
+ return hints[tab];
1240
1376
  }
1241
- function getListItems() {
1377
+ function getItems() {
1242
1378
  switch (tab) {
1243
1379
  case "workflows":
1244
- return workflows.map((w) => ({ label: `${w.deployed ? "\u25CF" : "\u25CB"} ${w.name}`, dimLabel: "" }));
1380
+ return workflows.map((w) => ({ label: `${w.deployed ? green("\u25CF") : dim("\u25CB")} ${w.name}`, sub: w.id.slice(0, 16) }));
1245
1381
  case "collections":
1246
- return collections.map((c) => ({ label: c.name, dimLabel: `${c.docs}\uBB38\uC11C ${c.chunks}\uCCAD\uD06C` }));
1382
+ return collections.map((c) => ({ label: c.name, sub: `${c.docs}\uBB38\uC11C ${c.chunks}\uCCAD\uD06C` }));
1247
1383
  case "nodes":
1248
- return nodes.map((n) => ({ label: n.nodeName ?? n.name ?? "?", dimLabel: (n.description ?? "").slice(0, 30) }));
1384
+ return nodes.map((n) => ({ label: n.name, sub: n.category ? `[${n.category}] ${n.desc}` : n.desc }));
1249
1385
  case "prompts":
1250
- return prompts.map((p) => ({ label: p.name ?? p.title ?? "?", dimLabel: `[${p.prompt_type ?? ""}]` }));
1386
+ return prompts.map((p) => ({ label: p.name, sub: `[${p.type}]` }));
1251
1387
  case "tools":
1252
- return tools2.map((t) => ({ label: t.name ?? t.tool_name ?? "?", dimLabel: (t.description ?? "").slice(0, 30) }));
1253
- default:
1254
- return [];
1388
+ return tools2.map((t) => {
1389
+ const st = t.status === "active" ? green("\u25CF") : t.status === "inactive" ? red("\u25CF") : dim("\u25CB");
1390
+ return { label: `${st} ${t.name}`, sub: t.desc };
1391
+ });
1392
+ case "mcp":
1393
+ return mcpSessions.map((s) => {
1394
+ const st = s.status === "running" ? green("\u25CF") : s.status === "error" ? red("\u25CF") : dim("\u25CB");
1395
+ return { label: `${st} ${s.name}`, sub: `[${s.type}] ${s.status}` };
1396
+ });
1255
1397
  }
1256
1398
  }
1257
- function showDetail() {
1258
- const items = getListItems();
1259
- if (selected < 0 || selected >= items.length) return;
1260
- if (tab === "workflows") {
1399
+ function updateDetail() {
1400
+ const items = getItems();
1401
+ if (items.length === 0) {
1402
+ const createHint = tab === "tools" ? "c \uB3C4\uAD6C \uC0DD\uC131" : tab === "prompts" ? "c \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131" : tab === "mcp" ? "c MCP \uC138\uC158 \uC0DD\uC131" : "";
1403
+ detail = [dim("\uB370\uC774\uD130 \uC5C6\uC74C"), "", dim(createHint)];
1404
+ return;
1405
+ }
1406
+ if (selected < 0) selected = 0;
1407
+ if (selected >= items.length) selected = items.length - 1;
1408
+ if (tab === "workflows" && workflows[selected]) {
1261
1409
  const w = workflows[selected];
1262
- if (w) setDetail([w.name, "", `ID ${w.id}`, `\uBC30\uD3EC ${w.deployed ? "Yes" : "No"}`, "", "Enter \u2192 \uC2E4\uD589"]);
1263
- } else if (tab === "collections") {
1410
+ detail = [
1411
+ bold(w.name),
1412
+ "",
1413
+ `ID ${w.id || dim("\uC5C6\uC74C")}`,
1414
+ `\uBC30\uD3EC ${w.deployed ? green("\u25CF Yes") : red("\u25CB No")}`,
1415
+ "",
1416
+ cyan("Enter") + " \uB178\uB4DC/\uC5E3\uC9C0 \uAD6C\uC870 \uBCF4\uAE30",
1417
+ cyan("i") + " \uC9C8\uBB38 \uC785\uB825 \uD6C4 \uC2E4\uD589"
1418
+ ];
1419
+ } else if (tab === "collections" && collections[selected]) {
1264
1420
  const c = collections[selected];
1265
- if (c) setDetail([c.name, "", `\uBB38\uC11C ${c.docs}\uAC1C`, `\uCCAD\uD06C ${c.chunks}\uAC1C`]);
1266
- } else if (tab === "nodes") {
1421
+ detail = [bold(c.name), "", `\uBB38\uC11C ${c.docs}\uAC1C`, `\uCCAD\uD06C ${c.chunks}\uAC1C`, "", cyan("Enter") + " \uBB38\uC11C \uBAA9\uB85D"];
1422
+ } else if (tab === "nodes" && nodes[selected]) {
1267
1423
  const n = nodes[selected];
1268
- if (n) setDetail([n.nodeName ?? n.name ?? "?", "", n.description ?? "", "", `ID: ${n.node_id ?? n.id ?? "?"}`]);
1269
- } else if (tab === "prompts") {
1424
+ detail = [
1425
+ bold(n.name),
1426
+ "",
1427
+ `\uCE74\uD14C\uACE0\uB9AC: ${n.category || dim("\uC5C6\uC74C")}`,
1428
+ n.desc || dim("\uC124\uBA85 \uC5C6\uC74C"),
1429
+ "",
1430
+ cyan("Enter") + " \uD30C\uB77C\uBBF8\uD130/\uD3EC\uD2B8 \uC0C1\uC138"
1431
+ ];
1432
+ } else if (tab === "prompts" && prompts[selected]) {
1270
1433
  const p = prompts[selected];
1271
- if (p) setDetail([p.name ?? "?", `[${p.prompt_type ?? ""}]`, "", (p.content ?? "").slice(0, 200)]);
1272
- } else if (tab === "tools") {
1434
+ const preview = p.content ? p.content.split("\n").slice(0, 8) : [dim("\uB0B4\uC6A9 \uC5C6\uC74C")];
1435
+ detail = [
1436
+ bold(p.name),
1437
+ `\uD0C0\uC785: ${p.type || "\uC5C6\uC74C"}`,
1438
+ `UID: ${p.uid || dim("\uC5C6\uC74C")}`,
1439
+ "",
1440
+ ...preview,
1441
+ "",
1442
+ `${cyan("c")}\uC0DD\uC131 ${cyan("e")}\uC218\uC815 ${cyan("d")}\uC0AD\uC81C ${cyan("u")}\uC2A4\uD1A0\uC5B4 ${cyan("v")}\uBC84\uC804`
1443
+ ];
1444
+ } else if (tab === "tools" && tools2[selected]) {
1273
1445
  const t = tools2[selected];
1274
- if (t) setDetail([t.name ?? t.tool_name ?? "?", "", t.description ?? ""]);
1275
- }
1276
- }
1277
- useEffect(() => {
1278
- showDetail();
1279
- }, [selected, tab]);
1280
- function switchTab(t) {
1281
- setTab(t);
1282
- setSelected(0);
1283
- setInputMode(false);
1284
- setRunTarget(null);
1285
- }
1286
- async function handleSubmit(value) {
1287
- if (!value.trim()) {
1288
- setInputMode(false);
1289
- setRunTarget(null);
1446
+ detail = [
1447
+ bold(t.name),
1448
+ "",
1449
+ `ID ${t.functionId || dim("\uC5C6\uC74C")}`,
1450
+ `URL ${t.apiUrl || dim("\uC5C6\uC74C")}`,
1451
+ `\uC0C1\uD0DC ${t.status === "active" ? green("active") : t.status === "inactive" ? red("inactive") : dim(t.status || "\uC5C6\uC74C")}`,
1452
+ "",
1453
+ t.desc || dim("\uC124\uBA85 \uC5C6\uC74C"),
1454
+ "",
1455
+ `${cyan("t")}\uD14C\uC2A4\uD2B8 ${cyan("u")}\uC2A4\uD1A0\uC5B4\uB4F1\uB85D ${cyan("c")}\uC0DD\uC131`
1456
+ ];
1457
+ } else if (tab === "mcp" && mcpSessions[selected]) {
1458
+ const s = mcpSessions[selected];
1459
+ detail = [
1460
+ bold(s.name),
1461
+ "",
1462
+ `\uC138\uC158ID ${s.id}`,
1463
+ `\uD0C0\uC785 ${s.type}`,
1464
+ `\uC0C1\uD0DC ${s.status === "running" ? green(s.status) : red(s.status)}`,
1465
+ `\uCEE4\uB9E8\uB4DC ${s.command || dim("\uC5C6\uC74C")}`,
1466
+ "",
1467
+ `${cyan("Enter")}\uB3C4\uAD6C\uBAA9\uB85D ${cyan("t")}\uB3C4\uAD6C\uD638\uCD9C ${cyan("d")}\uC0AD\uC81C`
1468
+ ];
1469
+ }
1470
+ }
1471
+ function visualLen(s) {
1472
+ return s.replace(/\x1b\[[0-9;]*m/g, "").length;
1473
+ }
1474
+ function padVisual(s, w) {
1475
+ return s + " ".repeat(Math.max(0, w - visualLen(s)));
1476
+ }
1477
+ function render() {
1478
+ const cols = process.stdout.columns || 120;
1479
+ const rows = process.stdout.rows || 30;
1480
+ const leftW = Math.floor(cols * 0.5);
1481
+ const rightW = cols - leftW - 1;
1482
+ const listH = rows - 5;
1483
+ clear();
1484
+ moveTo(1, 1);
1485
+ const tabStr = TABS.map((t) => tab === t.key ? inverse(` ${t.num}:${t.label} `) : dim(` ${t.num}:${t.label} `)).join("");
1486
+ process.stdout.write(` ${bold(cyan("OPEN XGEN"))} ${dim("v2.4")} ${dim(serverDisplay)} \u2502 ${tabStr}`);
1487
+ moveTo(2, 1);
1488
+ process.stdout.write(dim("\u2500".repeat(leftW) + "\u252C" + "\u2500".repeat(rightW)));
1489
+ const items = getItems();
1490
+ const vis = Math.max(1, listH);
1491
+ const scr = items.length <= vis ? 0 : Math.max(0, Math.min(selected - Math.floor(vis / 2), items.length - vis));
1492
+ for (let i = 0; i < vis; i++) {
1493
+ moveTo(3 + i, 1);
1494
+ const idx = scr + i;
1495
+ let left;
1496
+ if (idx < items.length) {
1497
+ const item = items[idx];
1498
+ const sub = item.sub ? dim(` ${item.sub}`) : "";
1499
+ left = padVisual(`${idx === selected ? "\u25B8" : " "} ${String(idx + 1).padStart(2)}. ${item.label}${sub}`, leftW);
1500
+ if (idx === selected) left = inverse(left);
1501
+ } else {
1502
+ left = " ".repeat(leftW);
1503
+ }
1504
+ process.stdout.write(left);
1505
+ process.stdout.write(dim("\u2502"));
1506
+ if (i < detail.length) process.stdout.write(` ${detail[i]}`);
1507
+ }
1508
+ if (items.length === 0) {
1509
+ moveTo(4, 3);
1510
+ process.stdout.write(dim("(\uD56D\uBAA9 \uC5C6\uC74C)"));
1511
+ }
1512
+ moveTo(rows - 2, 1);
1513
+ process.stdout.write(dim("\u2500".repeat(leftW) + "\u2534" + "\u2500".repeat(rightW)));
1514
+ moveTo(rows - 1, 1);
1515
+ if (inputMode || formCtx) {
1516
+ const pr = formCtx ? `${formCtx.fields[formCtx.step].label}${formCtx.fields[formCtx.step].required ? "*" : ""} \u276F ` : "\u276F ";
1517
+ process.stdout.write(` ${cyan(pr)}${inputBuffer}`);
1518
+ showCursor();
1519
+ } else {
1520
+ process.stdout.write(dim(` ${getHint()}`));
1521
+ hideCursor();
1522
+ }
1523
+ moveTo(rows, 1);
1524
+ process.stdout.write(dim(` ${statusMsg}`.slice(0, cols)));
1525
+ }
1526
+ async function runWorkflow(wf, input) {
1527
+ detail = [bold(wf.name), "", `\uC785\uB825: ${input}`, "", yellow("\uC2E4\uD589 \uC911...")];
1528
+ render();
1529
+ try {
1530
+ const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1531
+ const { randomUUID: randomUUID4 } = await import("crypto");
1532
+ const r = await withTimeout(executeWorkflow2({
1533
+ workflow_id: wf.id,
1534
+ workflow_name: wf.name,
1535
+ input_data: input,
1536
+ interaction_id: `tui_${randomUUID4().slice(0, 8)}`,
1537
+ user_id: auth?.userId ? parseInt(auth.userId) : 1
1538
+ }), 3e4, "\uC2E4\uD589");
1539
+ const content = r?.content ?? r?.message ?? r?.result ?? JSON.stringify(r).slice(0, 500);
1540
+ detail = [bold(wf.name), "", `\uC785\uB825: ${input}`, "", green("\uACB0\uACFC:"), ...String(content).split("\n").slice(0, 15)];
1541
+ } catch (err) {
1542
+ detail = [bold(wf.name), "", red(`\uC2E4\uD328: ${err.message}`)];
1543
+ }
1544
+ statusMsg = getHint();
1545
+ render();
1546
+ }
1547
+ async function loadWorkflowStructure(wf) {
1548
+ detail = [bold(wf.name), "", yellow("\uB178\uB4DC/\uC5E3\uC9C0 \uB85C\uB529...")];
1549
+ render();
1550
+ try {
1551
+ const { getWorkflowDetail: getWorkflowDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1552
+ const data = await withTimeout(getWorkflowDetail2(wf.id), 1e4, "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB85C\uB4DC");
1553
+ const wfData = data?.workflow_data ?? data;
1554
+ const ns = wfData?.nodes ?? data?.nodes ?? [];
1555
+ const es = wfData?.edges ?? data?.edges ?? [];
1556
+ detail = [
1557
+ bold(wf.name),
1558
+ "",
1559
+ `\uB178\uB4DC ${ns.length}\uAC1C \uC5E3\uC9C0 ${es.length}\uAC1C`,
1560
+ "",
1561
+ bold("\uB178\uB4DC:"),
1562
+ ...ns.slice(0, 15).map((n, i) => {
1563
+ const label = n.data?.label ?? n.data?.nodeName ?? n.type ?? "?";
1564
+ const nodeType = n.data?.nodeId ?? n.type ?? "";
1565
+ return ` ${i + 1}. ${label} ${dim(nodeType)}`;
1566
+ }),
1567
+ ...ns.length > 15 ? [dim(` ... +${ns.length - 15}\uAC1C`)] : [],
1568
+ "",
1569
+ bold("\uC5F0\uACB0:"),
1570
+ ...es.slice(0, 8).map((e) => {
1571
+ const src = ns.find((n) => n.id === e.source);
1572
+ const tgt = ns.find((n) => n.id === e.target);
1573
+ const srcName = src?.data?.label ?? src?.data?.nodeName ?? e.source;
1574
+ const tgtName = tgt?.data?.label ?? tgt?.data?.nodeName ?? e.target;
1575
+ return ` ${srcName} \u2192 ${tgtName}`;
1576
+ }),
1577
+ ...es.length > 8 ? [dim(` ... +${es.length - 8}\uAC1C`)] : [],
1578
+ "",
1579
+ cyan("i") + " \uC9C8\uBB38 \uC785\uB825 \uD6C4 \uC2E4\uD589"
1580
+ ];
1581
+ } catch (err) {
1582
+ detail = [bold(wf.name), "", red(`\uB85C\uB4DC \uC2E4\uD328: ${err.message}`)];
1583
+ }
1584
+ render();
1585
+ }
1586
+ async function loadNodeDetail(n) {
1587
+ if (!n.id) {
1588
+ detail = [bold(n.name), "", red("\uB178\uB4DC ID \uC5C6\uC74C")];
1589
+ render();
1290
1590
  return;
1291
1591
  }
1292
- if (runTarget) {
1293
- setDetail([`\uC2E4\uD589 \uC911: ${runTarget.name}`, `\uC785\uB825: ${value}`, "", "..."]);
1294
- setInputValue("");
1295
- setInputMode(false);
1592
+ detail = [bold(n.name), "", yellow("\uC0C1\uC138 \uB85C\uB529...")];
1593
+ render();
1594
+ try {
1595
+ const { getNodeDetail: getNodeDetail2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1596
+ const d = await withTimeout(getNodeDetail2(n.id), 8e3, "\uB178\uB4DC \uC0C1\uC138");
1597
+ const inputs = d?.inputs ?? d?.inputPorts ?? [];
1598
+ const outputs = d?.outputs ?? d?.outputPorts ?? [];
1599
+ const params = d?.parameters ?? d?.params ?? d?.defaultParams ?? {};
1600
+ const paramKeys = typeof params === "object" ? Object.keys(params) : [];
1601
+ detail = [
1602
+ bold(d?.nodeName ?? d?.name ?? n.name),
1603
+ "",
1604
+ `ID ${d?.nodeId ?? d?.id ?? n.id}`,
1605
+ `\uCE74\uD14C\uACE0\uB9AC ${d?.category ?? d?.nodeCategory ?? dim("\uC5C6\uC74C")}`,
1606
+ `\uC124\uBA85 ${d?.description ?? dim("\uC5C6\uC74C")}`,
1607
+ "",
1608
+ bold(`\uC785\uB825 \uD3EC\uD2B8 (${inputs.length}):`),
1609
+ ...inputs.slice(0, 5).map((p) => ` \u2022 ${p.name ?? p.id ?? "?"} ${dim(p.type ?? "")}`),
1610
+ "",
1611
+ bold(`\uCD9C\uB825 \uD3EC\uD2B8 (${outputs.length}):`),
1612
+ ...outputs.slice(0, 5).map((p) => ` \u2022 ${p.name ?? p.id ?? "?"} ${dim(p.type ?? "")}`),
1613
+ "",
1614
+ bold(`\uD30C\uB77C\uBBF8\uD130 (${paramKeys.length}):`),
1615
+ ...paramKeys.slice(0, 8).map((k) => ` \u2022 ${k}: ${dim(String(params[k]).slice(0, 30))}`)
1616
+ ];
1617
+ } catch (err) {
1618
+ detail = [bold(n.name), "", red(`\uC2E4\uD328: ${err.message}`)];
1619
+ }
1620
+ render();
1621
+ }
1622
+ function startCreatePrompt() {
1623
+ startForm("create-prompt", "\uC0C8 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131", [
1624
+ { key: "prompt_title", label: "\uC81C\uBAA9", required: true },
1625
+ { key: "prompt_content", label: "\uB0B4\uC6A9", required: true },
1626
+ { key: "prompt_type", label: "\uD0C0\uC785 (user/system)", default: "user" },
1627
+ { key: "language", label: "\uC5B8\uC5B4 (ko/en)", default: "ko" }
1628
+ ], async (v) => {
1629
+ detail = [bold("\uD504\uB86C\uD504\uD2B8 \uC0DD\uC131"), "", yellow("\uC800\uC7A5 \uC911...")];
1630
+ render();
1296
1631
  try {
1297
- const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1298
- const { randomUUID: randomUUID4 } = await import("crypto");
1299
- const result = await executeWorkflow2({
1300
- workflow_id: runTarget.id,
1301
- workflow_name: runTarget.name,
1302
- input_data: value,
1303
- interaction_id: `tui_${randomUUID4().slice(0, 8)}`,
1304
- user_id: auth?.userId ? parseInt(auth.userId) : 1
1305
- });
1306
- const content = result.content ?? result.message ?? JSON.stringify(result).slice(0, 500);
1307
- setDetail([`${runTarget.name}`, "", `\uC785\uB825: ${value}`, "", `\uACB0\uACFC:`, String(content)]);
1632
+ const { createPrompt: createPrompt2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1633
+ await withTimeout(createPrompt2({ prompt_title: v.prompt_title, prompt_content: v.prompt_content, prompt_type: v.prompt_type || "user", language: v.language || "ko" }), 1e4, "\uC800\uC7A5");
1634
+ detail = [bold("\uD504\uB86C\uD504\uD2B8 \uC0DD\uC131"), "", green("\u2713 \uC800\uC7A5 \uC644\uB8CC!"), "", "r \uC0C8\uB85C\uACE0\uCE68"];
1635
+ statusMsg = green("\uC800\uC7A5 \uC644\uB8CC");
1308
1636
  } catch (err) {
1309
- setDetail([`\uC2E4\uD589 \uC2E4\uD328: ${err.message}`]);
1637
+ detail = [red(`\u2717 \uC2E4\uD328: ${err.message}`)];
1638
+ statusMsg = red("\uC2E4\uD328");
1310
1639
  }
1311
- setRunTarget(null);
1312
- } else {
1313
- setInputValue("");
1314
- setInputMode(false);
1640
+ render();
1641
+ });
1642
+ }
1643
+ function startEditPrompt() {
1644
+ if (!prompts[selected]) return;
1645
+ const p = prompts[selected];
1646
+ if (!p.uid) {
1647
+ detail = [red("UID \uC5C6\uC74C \u2014 \uC218\uC815 \uBD88\uAC00")];
1648
+ render();
1649
+ return;
1650
+ }
1651
+ startForm("edit-prompt", `\uD504\uB86C\uD504\uD2B8 \uC218\uC815: ${p.name}`, [
1652
+ { key: "prompt_title", label: "\uC81C\uBAA9", default: p.name },
1653
+ { key: "prompt_content", label: "\uB0B4\uC6A9", default: p.content || "" },
1654
+ { key: "prompt_type", label: "\uD0C0\uC785", default: p.type || "user" }
1655
+ ], async (v) => {
1656
+ detail = [yellow("\uC218\uC815 \uC911...")];
1657
+ render();
1658
+ try {
1659
+ const { updatePrompt: updatePrompt2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1660
+ await withTimeout(updatePrompt2({ prompt_uid: p.uid, prompt_title: v.prompt_title, prompt_content: v.prompt_content, prompt_type: v.prompt_type }), 1e4, "\uC218\uC815");
1661
+ detail = [green("\u2713 \uC218\uC815 \uC644\uB8CC!"), "", "r \uC0C8\uB85C\uACE0\uCE68"];
1662
+ statusMsg = green("\uC218\uC815 \uC644\uB8CC");
1663
+ } catch (err) {
1664
+ detail = [red(`\u2717 \uC2E4\uD328: ${err.message}`)];
1665
+ statusMsg = red("\uC2E4\uD328");
1666
+ }
1667
+ render();
1668
+ });
1669
+ }
1670
+ async function deleteSelectedPrompt() {
1671
+ if (!prompts[selected]?.uid) {
1672
+ detail = [red("UID \uC5C6\uC74C")];
1673
+ render();
1674
+ return;
1675
+ }
1676
+ const p = prompts[selected];
1677
+ detail = [bold(p.name), "", yellow("\uC0AD\uC81C \uC911...")];
1678
+ render();
1679
+ try {
1680
+ const { deletePrompt: deletePrompt2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1681
+ await withTimeout(deletePrompt2(p.uid), 1e4, "\uC0AD\uC81C");
1682
+ detail = [green("\u2713 \uC0AD\uC81C \uC644\uB8CC!"), "", "r \uC0C8\uB85C\uACE0\uCE68"];
1683
+ statusMsg = green("\uC0AD\uC81C \uC644\uB8CC");
1684
+ } catch (err) {
1685
+ detail = [red(`\uC0AD\uC81C \uC2E4\uD328: ${err.message}`)];
1686
+ statusMsg = red("\uC2E4\uD328");
1687
+ }
1688
+ render();
1689
+ }
1690
+ async function uploadSelectedPromptToStore() {
1691
+ if (!prompts[selected]?.dbId) {
1692
+ detail = [red("DB ID \uC5C6\uC74C")];
1693
+ render();
1694
+ return;
1695
+ }
1696
+ const p = prompts[selected];
1697
+ detail = [bold(p.name), "", yellow("\uC2A4\uD1A0\uC5B4 \uB4F1\uB85D \uC911...")];
1698
+ render();
1699
+ try {
1700
+ const { uploadPromptToStore: uploadPromptToStore2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1701
+ await withTimeout(uploadPromptToStore2(p.dbId), 1e4, "\uC2A4\uD1A0\uC5B4");
1702
+ detail = [green("\u2713 \uC2A4\uD1A0\uC5B4 \uB4F1\uB85D \uC644\uB8CC!")];
1703
+ statusMsg = green("\uB4F1\uB85D \uC644\uB8CC");
1704
+ } catch (err) {
1705
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1706
+ statusMsg = red("\uC2E4\uD328");
1707
+ }
1708
+ render();
1709
+ }
1710
+ async function showPromptVersions() {
1711
+ if (!prompts[selected]?.uid) {
1712
+ detail = [red("UID \uC5C6\uC74C")];
1713
+ render();
1714
+ return;
1715
+ }
1716
+ const p = prompts[selected];
1717
+ detail = [bold(p.name), "", yellow("\uBC84\uC804 \uB85C\uB529...")];
1718
+ render();
1719
+ try {
1720
+ const { listPromptVersions: listPromptVersions2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1721
+ const vers = await withTimeout(listPromptVersions2(p.uid), 8e3, "\uBC84\uC804");
1722
+ if (!vers.length) {
1723
+ detail = [bold(p.name), "", dim("\uBC84\uC804 \uC5C6\uC74C")];
1724
+ } else {
1725
+ detail = [
1726
+ bold(p.name),
1727
+ "",
1728
+ bold(`\uBC84\uC804 ${vers.length}\uAC1C:`),
1729
+ "",
1730
+ ...vers.slice(0, 15).map((v, i) => ` ${i + 1}. v${v.version ?? v.id ?? "?"} ${dim(v.label_name ?? v.created_at ?? "")}`)
1731
+ ];
1732
+ }
1733
+ } catch (err) {
1734
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1735
+ }
1736
+ render();
1737
+ }
1738
+ function startCreateTool() {
1739
+ startForm("create-tool", "\uC0C8 \uB3C4\uAD6C \uC0DD\uC131", [
1740
+ { key: "function_name", label: "\uB3C4\uAD6C \uC774\uB984", required: true },
1741
+ { key: "function_id", label: "\uB3C4\uAD6C ID (\uC601\uBB38)", required: true },
1742
+ { key: "description", label: "\uC124\uBA85" },
1743
+ { key: "api_url", label: "API URL", required: true },
1744
+ { key: "api_method", label: "HTTP \uBA54\uC11C\uB4DC", default: "GET" },
1745
+ { key: "api_timeout", label: "\uD0C0\uC784\uC544\uC6C3(\uCD08)", default: "30" }
1746
+ ], async (v) => {
1747
+ detail = [bold("\uB3C4\uAD6C \uC0DD\uC131"), "", yellow("\uC800\uC7A5 \uC911...")];
1748
+ render();
1749
+ try {
1750
+ const { saveTool: saveTool2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1751
+ await withTimeout(saveTool2(v.function_name, {
1752
+ function_name: v.function_name,
1753
+ function_id: v.function_id,
1754
+ description: v.description || "",
1755
+ api_url: v.api_url,
1756
+ api_method: v.api_method || "GET",
1757
+ api_timeout: parseInt(v.api_timeout || "30")
1758
+ }), 1e4, "\uC800\uC7A5");
1759
+ detail = [green("\u2713 \uB3C4\uAD6C \uC800\uC7A5 \uC644\uB8CC!"), "", "r \uC0C8\uB85C\uACE0\uCE68"];
1760
+ statusMsg = green("\uC800\uC7A5 \uC644\uB8CC");
1761
+ } catch (err) {
1762
+ detail = [red(`\u2717 \uC2E4\uD328: ${err.message}`)];
1763
+ statusMsg = red("\uC2E4\uD328");
1764
+ }
1765
+ render();
1766
+ });
1767
+ }
1768
+ async function testSelectedTool() {
1769
+ if (!tools2[selected]) return;
1770
+ const t = tools2[selected];
1771
+ if (!t.apiUrl) {
1772
+ detail = [bold(t.name), "", red("API URL \uC5C6\uC74C")];
1773
+ render();
1774
+ return;
1775
+ }
1776
+ detail = [bold(t.name), "", yellow("API \uD14C\uC2A4\uD2B8 \uC911..."), `URL: ${t.apiUrl}`];
1777
+ render();
1778
+ try {
1779
+ const { apiTest: apiTest2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1780
+ const r = await withTimeout(apiTest2({ api_url: t.apiUrl, api_method: "GET", api_timeout: 15 }), 2e4, "\uD14C\uC2A4\uD2B8");
1781
+ const ok = r?.success ?? (r?.data?.status && r.data.status < 400);
1782
+ const st = r?.data?.status ?? "?";
1783
+ const resp = r?.data?.response;
1784
+ const lines = (typeof resp === "string" ? resp : JSON.stringify(resp ?? {}, null, 2)).split("\n").slice(0, 12);
1785
+ detail = [bold(t.name), "", ok ? green(`\u2713 ${st} OK`) : red(`\u2717 ${st} FAIL`), "", bold("\uC751\uB2F5:"), ...lines];
1786
+ statusMsg = ok ? green("\uD14C\uC2A4\uD2B8 \uC131\uACF5") : red("\uD14C\uC2A4\uD2B8 \uC2E4\uD328");
1787
+ } catch (err) {
1788
+ detail = [bold(t.name), "", red(`\uC2E4\uD328: ${err.message}`)];
1789
+ statusMsg = red("\uC2E4\uD328");
1790
+ }
1791
+ render();
1792
+ }
1793
+ async function uploadSelectedTool() {
1794
+ if (!tools2[selected]?.functionId) {
1795
+ detail = [red("function_id \uC5C6\uC74C")];
1796
+ render();
1797
+ return;
1798
+ }
1799
+ const t = tools2[selected];
1800
+ detail = [bold(t.name), "", yellow("\uC2A4\uD1A0\uC5B4 \uB4F1\uB85D \uC911...")];
1801
+ render();
1802
+ try {
1803
+ const { uploadToolToStore: uploadToolToStore2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1804
+ await withTimeout(uploadToolToStore2(t.functionId, t.desc), 1e4, "\uB4F1\uB85D");
1805
+ detail = [green("\u2713 \uC2A4\uD1A0\uC5B4 \uB4F1\uB85D \uC644\uB8CC!")];
1806
+ statusMsg = green("\uB4F1\uB85D \uC644\uB8CC");
1807
+ } catch (err) {
1808
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1809
+ statusMsg = red("\uC2E4\uD328");
1810
+ }
1811
+ render();
1812
+ }
1813
+ function startCreateMcpSession() {
1814
+ startForm("create-mcp", "MCP \uC138\uC158 \uC0DD\uC131", [
1815
+ { key: "session_name", label: "\uC138\uC158 \uC774\uB984", required: true },
1816
+ { key: "server_type", label: "\uD0C0\uC785 (python/node)", required: true, default: "python" },
1817
+ { key: "server_command", label: "\uC11C\uBC84 \uCEE4\uB9E8\uB4DC", required: true },
1818
+ { key: "server_args", label: "\uCD94\uAC00 \uC778\uC790 (\uC27C\uD45C \uAD6C\uBD84)" },
1819
+ { key: "working_dir", label: "\uC791\uC5C5 \uB514\uB809\uD1A0\uB9AC" }
1820
+ ], async (v) => {
1821
+ detail = [yellow("MCP \uC138\uC158 \uC0DD\uC131 \uC911...")];
1822
+ render();
1823
+ try {
1824
+ const { createMcpSession: createMcpSession2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1825
+ const args = v.server_args ? v.server_args.split(",").map((a) => a.trim()) : void 0;
1826
+ const r = await withTimeout(createMcpSession2({
1827
+ server_type: v.server_type,
1828
+ server_command: v.server_command,
1829
+ session_name: v.session_name,
1830
+ server_args: args,
1831
+ working_dir: v.working_dir || void 0
1832
+ }), 15e3, "MCP \uC138\uC158");
1833
+ detail = [green("\u2713 \uC138\uC158 \uC0DD\uC131 \uC644\uB8CC!"), "", `\uC138\uC158ID: ${r?.session_id ?? "?"}`, "", "r \uC0C8\uB85C\uACE0\uCE68"];
1834
+ statusMsg = green("MCP \uC138\uC158 \uC0DD\uC131 \uC644\uB8CC");
1835
+ } catch (err) {
1836
+ detail = [red(`\u2717 \uC2E4\uD328: ${err.message}`)];
1837
+ statusMsg = red("\uC2E4\uD328");
1838
+ }
1839
+ render();
1840
+ });
1841
+ }
1842
+ async function loadMcpTools() {
1843
+ if (!mcpSessions[selected]) return;
1844
+ const s = mcpSessions[selected];
1845
+ detail = [bold(s.name), "", yellow("\uB3C4\uAD6C \uBAA9\uB85D \uB85C\uB529...")];
1846
+ render();
1847
+ try {
1848
+ const { getMcpSessionTools: getMcpSessionTools2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1849
+ const tools3 = await withTimeout(getMcpSessionTools2(s.id), 1e4, "MCP \uB3C4\uAD6C");
1850
+ if (!tools3.length) {
1851
+ detail = [bold(s.name), "", dim("\uB3C4\uAD6C \uC5C6\uC74C")];
1852
+ } else {
1853
+ detail = [
1854
+ bold(s.name),
1855
+ "",
1856
+ bold(`\uB3C4\uAD6C ${tools3.length}\uAC1C:`),
1857
+ "",
1858
+ ...tools3.slice(0, 15).map((t, i) => {
1859
+ const name = t.name ?? t.function?.name ?? "?";
1860
+ const desc = (t.description ?? t.function?.description ?? "").slice(0, 40);
1861
+ return ` ${i + 1}. ${name} ${dim(desc)}`;
1862
+ }),
1863
+ ...tools3.length > 15 ? [dim(` ... +${tools3.length - 15}\uAC1C`)] : [],
1864
+ "",
1865
+ cyan("t") + " \uB3C4\uAD6C \uD638\uCD9C \uD14C\uC2A4\uD2B8"
1866
+ ];
1867
+ }
1868
+ } catch (err) {
1869
+ detail = [bold(s.name), "", red(`\uC2E4\uD328: ${err.message}`)];
1870
+ }
1871
+ render();
1872
+ }
1873
+ function startMcpToolCall() {
1874
+ if (!mcpSessions[selected]) return;
1875
+ const s = mcpSessions[selected];
1876
+ startForm("mcp-call", `MCP \uB3C4\uAD6C \uD638\uCD9C: ${s.name}`, [
1877
+ { key: "tool_name", label: "\uB3C4\uAD6C \uC774\uB984", required: true },
1878
+ { key: "params_json", label: "\uD30C\uB77C\uBBF8\uD130 (JSON)", default: "{}" }
1879
+ ], async (v) => {
1880
+ detail = [yellow("MCP \uB3C4\uAD6C \uD638\uCD9C \uC911...")];
1881
+ render();
1882
+ try {
1883
+ const { sendMcpRequest: sendMcpRequest2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1884
+ let params = {};
1885
+ try {
1886
+ params = JSON.parse(v.params_json || "{}");
1887
+ } catch {
1888
+ }
1889
+ const r = await withTimeout(sendMcpRequest2(s.id, "tools/call", { name: v.tool_name, arguments: params }), 2e4, "MCP \uD638\uCD9C");
1890
+ const ok = r?.success;
1891
+ const data = r?.data;
1892
+ const lines = (typeof data === "string" ? data : JSON.stringify(data ?? {}, null, 2)).split("\n").slice(0, 15);
1893
+ detail = [bold(`${s.name} \u2192 ${v.tool_name}`), "", ok ? green("\u2713 \uC131\uACF5") : red("\u2717 \uC2E4\uD328"), "", bold("\uC751\uB2F5:"), ...lines];
1894
+ statusMsg = ok ? green("\uD638\uCD9C \uC131\uACF5") : red("\uD638\uCD9C \uC2E4\uD328");
1895
+ } catch (err) {
1896
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1897
+ statusMsg = red("\uC2E4\uD328");
1898
+ }
1899
+ render();
1900
+ });
1901
+ }
1902
+ async function deleteSelectedMcpSession() {
1903
+ if (!mcpSessions[selected]) return;
1904
+ const s = mcpSessions[selected];
1905
+ detail = [bold(s.name), "", yellow("\uC0AD\uC81C \uC911...")];
1906
+ render();
1907
+ try {
1908
+ const { deleteMcpSession: deleteMcpSession2 } = await Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports));
1909
+ await withTimeout(deleteMcpSession2(s.id), 1e4, "\uC0AD\uC81C");
1910
+ detail = [green("\u2713 \uC138\uC158 \uC0AD\uC81C \uC644\uB8CC!"), "", "r \uC0C8\uB85C\uACE0\uCE68"];
1911
+ statusMsg = green("\uC0AD\uC81C \uC644\uB8CC");
1912
+ } catch (err) {
1913
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1914
+ statusMsg = red("\uC2E4\uD328");
1315
1915
  }
1916
+ render();
1316
1917
  }
1317
- useInput((input, key) => {
1918
+ function startForm(type, title, fields, onSubmit) {
1919
+ formCtx = { type, fields, step: 0, values: {}, onSubmit };
1920
+ inputBuffer = "";
1921
+ detail = [
1922
+ bold(title),
1923
+ "",
1924
+ ...fields.map((f, i) => ` ${i === 0 ? cyan("\u25B8") : " "} ${f.label}${f.required ? red("*") : ""} ${f.default ? dim(`(\uAE30\uBCF8: ${f.default})`) : ""}`),
1925
+ "",
1926
+ dim("Enter: \uB2E4\uC74C \u2502 Esc: \uCDE8\uC18C")
1927
+ ];
1928
+ statusMsg = `${fields[0].label} \uC785\uB825`;
1929
+ render();
1930
+ }
1931
+ function handleKey(s) {
1932
+ if (formCtx) {
1933
+ if (s === "\x1B" || s === "\x1B\x1B") {
1934
+ formCtx = null;
1935
+ inputBuffer = "";
1936
+ inputMode = false;
1937
+ updateDetail();
1938
+ statusMsg = getHint();
1939
+ render();
1940
+ return;
1941
+ }
1942
+ if (s === "\r" || s === "\n") {
1943
+ const field = formCtx.fields[formCtx.step];
1944
+ const value = inputBuffer.trim() || field.default || "";
1945
+ if (field.required && !value) {
1946
+ statusMsg = red(`${field.label} \uD544\uC218`);
1947
+ render();
1948
+ return;
1949
+ }
1950
+ formCtx.values[field.key] = value;
1951
+ inputBuffer = "";
1952
+ formCtx.step++;
1953
+ if (formCtx.step >= formCtx.fields.length) {
1954
+ const ctx = formCtx;
1955
+ formCtx = null;
1956
+ inputMode = false;
1957
+ ctx.onSubmit(ctx.values);
1958
+ } else {
1959
+ const nf = formCtx.fields[formCtx.step];
1960
+ detail = [
1961
+ bold(formCtx.type.includes("tool") ? "\uC0C8 \uB3C4\uAD6C" : formCtx.type.includes("prompt") ? "\uC0C8 \uD504\uB86C\uD504\uD2B8" : formCtx.type.includes("mcp") ? "MCP" : "\uC785\uB825"),
1962
+ "",
1963
+ ...formCtx.fields.map((f, i) => {
1964
+ const val = formCtx.values[f.key];
1965
+ if (val !== void 0) return ` ${green("\u2713")} ${f.label}: ${val}`;
1966
+ if (i === formCtx.step) return ` ${cyan("\u25B8")} ${f.label}${f.required ? red("*") : ""} ${f.default ? dim(`(\uAE30\uBCF8: ${f.default})`) : ""}`;
1967
+ return ` ${f.label}`;
1968
+ }),
1969
+ "",
1970
+ dim(`${formCtx.step + 1}/${formCtx.fields.length} \u2502 Enter \u2502 Esc`)
1971
+ ];
1972
+ statusMsg = `${nf.label} \uC785\uB825`;
1973
+ render();
1974
+ }
1975
+ return;
1976
+ }
1977
+ if (s === "\x7F" || s === "\b") {
1978
+ inputBuffer = inputBuffer.slice(0, -1);
1979
+ render();
1980
+ return;
1981
+ }
1982
+ if (s === "") {
1983
+ formCtx = null;
1984
+ inputBuffer = "";
1985
+ inputMode = false;
1986
+ updateDetail();
1987
+ render();
1988
+ return;
1989
+ }
1990
+ if (s.length > 0 && s.charCodeAt(0) >= 32) {
1991
+ inputBuffer += s;
1992
+ render();
1993
+ return;
1994
+ }
1995
+ return;
1996
+ }
1318
1997
  if (inputMode) {
1319
- if (key.escape) {
1320
- setInputMode(false);
1321
- setRunTarget(null);
1998
+ if (s === "\x1B" || s === "\x1B\x1B") {
1999
+ inputMode = false;
2000
+ inputBuffer = "";
2001
+ updateDetail();
2002
+ statusMsg = getHint();
2003
+ render();
2004
+ return;
2005
+ }
2006
+ if (s === "\r" || s === "\n") {
2007
+ const val = inputBuffer.trim();
2008
+ inputMode = false;
2009
+ inputBuffer = "";
2010
+ if (val && tab === "workflows" && workflows[selected]) {
2011
+ runWorkflow(workflows[selected], val);
2012
+ } else {
2013
+ render();
2014
+ }
2015
+ return;
2016
+ }
2017
+ if (s === "\x7F" || s === "\b") {
2018
+ inputBuffer = inputBuffer.slice(0, -1);
2019
+ render();
2020
+ return;
2021
+ }
2022
+ if (s === "") {
2023
+ inputMode = false;
2024
+ inputBuffer = "";
2025
+ render();
2026
+ return;
2027
+ }
2028
+ if (s.length > 0 && s.charCodeAt(0) >= 32) {
2029
+ inputBuffer += s;
2030
+ render();
2031
+ return;
1322
2032
  }
1323
2033
  return;
1324
2034
  }
1325
- if (input === "q" || key.ctrl && input === "c") {
1326
- exit();
2035
+ if (s === "q" || s === "") {
2036
+ cleanup();
2037
+ process.exit(0);
2038
+ }
2039
+ if (s === "r" || s === "R") {
2040
+ loadData();
1327
2041
  return;
1328
2042
  }
1329
- if (input === "r") {
1330
- loadAll();
2043
+ if (s === "i" && tab === "workflows" && workflows[selected]) {
2044
+ inputMode = true;
2045
+ inputBuffer = "";
2046
+ statusMsg = `${workflows[selected].name} \u2014 \uC9C8\uBB38 \uC785\uB825 \uD6C4 Enter, Esc \uCDE8\uC18C`;
2047
+ render();
1331
2048
  return;
1332
2049
  }
1333
- if (input === "i") {
1334
- setInputMode(true);
2050
+ if (s === "c" || s === "C") {
2051
+ if (tab === "tools") {
2052
+ startCreateTool();
2053
+ return;
2054
+ }
2055
+ if (tab === "prompts") {
2056
+ startCreatePrompt();
2057
+ return;
2058
+ }
2059
+ if (tab === "mcp") {
2060
+ startCreateMcpSession();
2061
+ return;
2062
+ }
2063
+ }
2064
+ if (s === "t" || s === "T") {
2065
+ if (tab === "tools") {
2066
+ testSelectedTool();
2067
+ return;
2068
+ }
2069
+ if (tab === "mcp") {
2070
+ startMcpToolCall();
2071
+ return;
2072
+ }
2073
+ }
2074
+ if (s === "u" || s === "U") {
2075
+ if (tab === "tools") {
2076
+ uploadSelectedTool();
2077
+ return;
2078
+ }
2079
+ if (tab === "prompts") {
2080
+ uploadSelectedPromptToStore();
2081
+ return;
2082
+ }
2083
+ }
2084
+ if (s === "e" || s === "E") {
2085
+ if (tab === "prompts") {
2086
+ startEditPrompt();
2087
+ return;
2088
+ }
2089
+ }
2090
+ if (s === "d" || s === "D") {
2091
+ if (tab === "prompts") {
2092
+ deleteSelectedPrompt();
2093
+ return;
2094
+ }
2095
+ if (tab === "mcp") {
2096
+ deleteSelectedMcpSession();
2097
+ return;
2098
+ }
2099
+ }
2100
+ if (s === "v" || s === "V") {
2101
+ if (tab === "prompts") {
2102
+ showPromptVersions();
2103
+ return;
2104
+ }
2105
+ }
2106
+ const tabNum = parseInt(s);
2107
+ if (tabNum >= 1 && tabNum <= 6) {
2108
+ tab = TABS[tabNum - 1].key;
2109
+ selected = 0;
2110
+ updateDetail();
2111
+ statusMsg = getHint();
2112
+ render();
1335
2113
  return;
1336
2114
  }
1337
- if (input === "1") switchTab("workflows");
1338
- else if (input === "2") switchTab("collections");
1339
- else if (input === "3") switchTab("nodes");
1340
- else if (input === "4") switchTab("prompts");
1341
- else if (input === "5") switchTab("tools");
1342
- const items = getListItems();
1343
- if (key.upArrow) setSelected(Math.max(0, selected - 1));
1344
- else if (key.downArrow) setSelected(Math.min(items.length - 1, selected + 1));
1345
- else if (key.tab) switchTab(TABS[(TABS.findIndex((t) => t.key === tab) + 1) % TABS.length].key);
1346
- if (key.return && items.length > 0) {
1347
- if (tab === "workflows" && workflows[selected]) {
1348
- setRunTarget(workflows[selected]);
1349
- setInputMode(true);
1350
- setStatusMsg(`${workflows[selected].name} \u2014 \uC785\uB825 \uD6C4 Enter\uB85C \uC2E4\uD589, Esc \uCDE8\uC18C`);
2115
+ if (s === " ") {
2116
+ const idx = TABS.findIndex((t) => t.key === tab);
2117
+ tab = TABS[(idx + 1) % TABS.length].key;
2118
+ selected = 0;
2119
+ updateDetail();
2120
+ statusMsg = getHint();
2121
+ render();
2122
+ return;
2123
+ }
2124
+ if (s === "\x1B[Z") {
2125
+ const idx = TABS.findIndex((t) => t.key === tab);
2126
+ tab = TABS[(idx - 1 + TABS.length) % TABS.length].key;
2127
+ selected = 0;
2128
+ updateDetail();
2129
+ statusMsg = getHint();
2130
+ render();
2131
+ return;
2132
+ }
2133
+ if (s === "\x1B[A") {
2134
+ const items = getItems();
2135
+ if (items.length > 0) {
2136
+ selected = Math.max(0, selected - 1);
2137
+ updateDetail();
2138
+ render();
1351
2139
  }
2140
+ return;
1352
2141
  }
1353
- });
1354
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1355
- /* @__PURE__ */ jsx(Header, { tab, serverDisplay, model: provider?.model ?? "" }),
1356
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [
1357
- /* @__PURE__ */ jsx(ListPanel, { items: getListItems(), selected }),
1358
- /* @__PURE__ */ jsx(DetailPanel, { lines: detail })
1359
- ] }),
1360
- inputMode ? /* @__PURE__ */ jsx(
1361
- InputBar,
1362
- {
1363
- value: inputValue,
1364
- onChange: setInputValue,
1365
- onSubmit: handleSubmit,
1366
- placeholder: runTarget ? `${runTarget.name}\uC5D0 \uC785\uB825...` : "\uC785\uB825..."
2142
+ if (s === "\x1B[B") {
2143
+ const items = getItems();
2144
+ if (items.length > 0) {
2145
+ selected = Math.min(items.length - 1, selected + 1);
2146
+ updateDetail();
2147
+ render();
1367
2148
  }
1368
- ) : /* @__PURE__ */ jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u276F i\uB97C \uB20C\uB7EC \uC785\uB825 \xB7 Enter\uB85C \uC2E4\uD589" }) }),
1369
- /* @__PURE__ */ jsx(StatusBar, { message: loading ? "\uB85C\uB529..." : statusMsg })
1370
- ] });
1371
- }
1372
- async function startInkDashboard() {
1373
- if (process.stdin.isPaused?.()) {
1374
- process.stdin.resume();
2149
+ return;
2150
+ }
2151
+ if (s === "\x1B[5~") {
2152
+ selected = Math.max(0, selected - 10);
2153
+ updateDetail();
2154
+ render();
2155
+ return;
2156
+ }
2157
+ if (s === "\x1B[6~") {
2158
+ const items = getItems();
2159
+ selected = Math.min(items.length - 1, selected + 10);
2160
+ updateDetail();
2161
+ render();
2162
+ return;
2163
+ }
2164
+ if (s === "\r" || s === "\n") {
2165
+ const items = getItems();
2166
+ if (items.length === 0) return;
2167
+ if (tab === "workflows" && workflows[selected]) {
2168
+ loadWorkflowStructure(workflows[selected]);
2169
+ } else if (tab === "collections" && collections[selected]) {
2170
+ const c = collections[selected];
2171
+ detail = [bold(c.name), "", yellow("\uBB38\uC11C \uB85C\uB529...")];
2172
+ render();
2173
+ Promise.resolve().then(() => (init_document(), document_exports)).then(async (m) => {
2174
+ try {
2175
+ const docs = await withTimeout(m.listDocuments(String(c.id)), 8e3, "\uBB38\uC11C");
2176
+ if (!docs?.length) {
2177
+ detail = [bold(c.name), "", dim("\uBB38\uC11C \uC5C6\uC74C")];
2178
+ } else {
2179
+ detail = [bold(c.name) + ` \u2014 ${docs.length}\uAC1C`, "", ...docs.map((d, i) => ` ${i + 1}. ${d.name || d.file_name || "?"}`).slice(0, 20)];
2180
+ }
2181
+ } catch (err) {
2182
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
2183
+ }
2184
+ render();
2185
+ });
2186
+ } else if (tab === "nodes" && nodes[selected]) {
2187
+ loadNodeDetail(nodes[selected]);
2188
+ } else if (tab === "prompts" && prompts[selected]) {
2189
+ const p = prompts[selected];
2190
+ detail = [bold(p.name), `\uD0C0\uC785: ${p.type}`, `UID: ${p.uid || "?"}`, "", bold("\uB0B4\uC6A9:"), "", ...p.content ? p.content.split("\n").slice(0, 18) : [dim("\uC5C6\uC74C")]];
2191
+ render();
2192
+ } else if (tab === "tools" && tools2[selected]) {
2193
+ testSelectedTool();
2194
+ } else if (tab === "mcp" && mcpSessions[selected]) {
2195
+ loadMcpTools();
2196
+ }
2197
+ return;
2198
+ }
1375
2199
  }
1376
- const { waitUntilExit } = render(/* @__PURE__ */ jsx(Dashboard, {}), {
1377
- exitOnCtrlC: true
2200
+ function cleanup() {
2201
+ showCursor();
2202
+ clear();
2203
+ if (process.stdin.isTTY && process.stdin.isRaw) process.stdin.setRawMode(false);
2204
+ process.stdin.removeAllListeners("data");
2205
+ process.stdin.pause();
2206
+ }
2207
+ if (!process.stdin.isTTY) {
2208
+ console.error("\uB300\uC2DC\uBCF4\uB4DC\uB294 \uD130\uBBF8\uB110(TTY)\uC5D0\uC11C\uB9CC \uC2E4\uD589 \uAC00\uB2A5\uD569\uB2C8\uB2E4.");
2209
+ return;
2210
+ }
2211
+ process.stdin.setRawMode(true);
2212
+ process.stdin.resume();
2213
+ process.stdin.setEncoding("utf8");
2214
+ hideCursor();
2215
+ process.stdin.on("data", (data) => {
2216
+ try {
2217
+ handleKey(String(data));
2218
+ } catch (err) {
2219
+ statusMsg = red(`\uC624\uB958: ${err.message}`);
2220
+ render();
2221
+ }
2222
+ });
2223
+ process.stdout.on("resize", () => render());
2224
+ process.on("SIGINT", () => {
2225
+ cleanup();
2226
+ process.exit(0);
2227
+ });
2228
+ process.on("exit", () => {
2229
+ showCursor();
2230
+ });
2231
+ loadData();
2232
+ await new Promise(() => {
1378
2233
  });
1379
- await waitUntilExit();
1380
2234
  }
1381
- var TABS;
1382
- var init_InkDashboard = __esm({
1383
- "src/dashboard/InkDashboard.tsx"() {
2235
+ var TABS, CSI, clear, moveTo, dim, bold, inverse, red, green, yellow, cyan, hideCursor, showCursor;
2236
+ var init_raw_tui = __esm({
2237
+ "src/dashboard/raw-tui.ts"() {
1384
2238
  "use strict";
1385
2239
  init_store();
1386
2240
  TABS = [
1387
- { key: "workflows", label: "\uC6CC\uD06C\uD50C\uB85C\uC6B0", shortcut: "1" },
1388
- { key: "collections", label: "\uCEEC\uB809\uC158", shortcut: "2" },
1389
- { key: "nodes", label: "\uB178\uB4DC", shortcut: "3" },
1390
- { key: "prompts", label: "\uD504\uB86C\uD504\uD2B8", shortcut: "4" },
1391
- { key: "tools", label: "\uB3C4\uAD6C", shortcut: "5" }
2241
+ { key: "workflows", label: "\uC6CC\uD06C\uD50C\uB85C\uC6B0", num: "1" },
2242
+ { key: "collections", label: "\uCEEC\uB809\uC158", num: "2" },
2243
+ { key: "nodes", label: "\uB178\uB4DC", num: "3" },
2244
+ { key: "prompts", label: "\uD504\uB86C\uD504\uD2B8", num: "4" },
2245
+ { key: "tools", label: "\uB3C4\uAD6C", num: "5" },
2246
+ { key: "mcp", label: "MCP", num: "6" }
1392
2247
  ];
2248
+ CSI = "\x1B[";
2249
+ clear = () => process.stdout.write(`${CSI}2J${CSI}H`);
2250
+ moveTo = (r, c) => process.stdout.write(`${CSI}${r};${c}H`);
2251
+ dim = (s) => `${CSI}2m${s}${CSI}0m`;
2252
+ bold = (s) => `${CSI}1m${s}${CSI}0m`;
2253
+ inverse = (s) => `${CSI}7m${s}${CSI}0m`;
2254
+ red = (s) => `${CSI}31m${s}${CSI}0m`;
2255
+ green = (s) => `${CSI}32m${s}${CSI}0m`;
2256
+ yellow = (s) => `${CSI}33m${s}${CSI}0m`;
2257
+ cyan = (s) => `${CSI}36m${s}${CSI}0m`;
2258
+ hideCursor = () => process.stdout.write(`${CSI}?25l`);
2259
+ showCursor = () => process.stdout.write(`${CSI}?25h`);
1393
2260
  }
1394
2261
  });
1395
2262
 
@@ -3597,7 +4464,7 @@ ${result.answer}
3597
4464
  }
3598
4465
 
3599
4466
  // src/index.ts
3600
- var VERSION = "2.2.0";
4467
+ var VERSION = "2.4.0";
3601
4468
  var LOGO = chalk15.cyan(`
3602
4469
  \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
3603
4470
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
@@ -3629,11 +4496,17 @@ ${chalk15.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
3629
4496
  ${chalk15.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
3630
4497
 
3631
4498
  ${chalk15.bold("XGEN \uD50C\uB7AB\uD3FC:")}
4499
+ ${chalk15.cyan("xgen dash")} TUI \uB300\uC2DC\uBCF4\uB4DC (\uC870\uD68C/\uD14C\uC2A4\uD2B8/\uC0DD\uC131)
3632
4500
  ${chalk15.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
3633
4501
  ${chalk15.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
3634
4502
  ${chalk15.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
3635
4503
  ${chalk15.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
3636
4504
  ${chalk15.cyan("xgen ont query")} "\uC9C8\uBB38" \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758
4505
+
4506
+ ${chalk15.bold("\uB300\uC2DC\uBCF4\uB4DC (xgen dash):")}
4507
+ ${chalk15.gray("\u2191\u2193")} \uC774\uB3D9 ${chalk15.gray("Enter")} \uC0C1\uC138/\uC2E4\uD589 ${chalk15.gray("1-6")} \uD0ED\uC804\uD658 ${chalk15.gray("r")} \uC0C8\uB85C\uACE0\uCE68 ${chalk15.gray("q")} \uC885\uB8CC
4508
+ ${chalk15.gray("c")} \uC0DD\uC131 ${chalk15.gray("e")} \uC218\uC815 ${chalk15.gray("d")} \uC0AD\uC81C ${chalk15.gray("t")} \uD14C\uC2A4\uD2B8 ${chalk15.gray("u")} \uC2A4\uD1A0\uC5B4\uB4F1\uB85D ${chalk15.gray("v")} \uBC84\uC804
4509
+ \uD0ED: \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uCEEC\uB809\uC158 \uB178\uB4DC \uD504\uB86C\uD504\uD2B8 \uB3C4\uAD6C MCP
3637
4510
  `
3638
4511
  );
3639
4512
  registerConfigCommand(program);
@@ -3645,8 +4518,11 @@ registerAgentCommand(program);
3645
4518
  registerDocCommand(program);
3646
4519
  registerOntologyCommand(program);
3647
4520
  program.command("dash").alias("dashboard").description("XGEN TUI \uB300\uC2DC\uBCF4\uB4DC").action(async () => {
3648
- const { startInkDashboard: startInkDashboard2 } = await Promise.resolve().then(() => (init_InkDashboard(), InkDashboard_exports));
3649
- await startInkDashboard2();
4521
+ process.stdin.removeAllListeners();
4522
+ process.stdin.pause();
4523
+ await new Promise((r) => setTimeout(r, 50));
4524
+ const { startRawTui: startRawTui2 } = await Promise.resolve().then(() => (init_raw_tui(), raw_tui_exports));
4525
+ await startRawTui2();
3650
4526
  });
3651
4527
  if (process.argv.length <= 2) {
3652
4528
  agentRepl().catch((err) => {