openxgen 2.3.0 → 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";
@@ -1113,28 +1222,44 @@ var raw_tui_exports = {};
1113
1222
  __export(raw_tui_exports, {
1114
1223
  startRawTui: () => startRawTui
1115
1224
  });
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
+ });
1236
+ }
1116
1237
  async function startRawTui() {
1117
1238
  const provider = getDefaultProvider();
1118
1239
  const server = getServer();
1119
1240
  const auth = getAuth();
1120
- const serverDisplay = auth && server ? `${auth.username}@${server.replace("https://", "").replace("http://", "")}` : "\uBBF8\uC5F0\uACB0";
1241
+ const serverDisplay = auth && server ? `${auth.username}@${server.replace(/https?:\/\//, "")}` : "\uBBF8\uC5F0\uACB0";
1121
1242
  let tab = "workflows";
1122
1243
  let selected = 0;
1123
1244
  let inputMode = false;
1124
1245
  let inputBuffer = "";
1125
- let runTarget = null;
1246
+ let formCtx = null;
1126
1247
  let workflows = [];
1127
1248
  let collections = [];
1128
1249
  let nodes = [];
1129
1250
  let prompts = [];
1130
1251
  let tools2 = [];
1252
+ let mcpSessions = [];
1131
1253
  let detail = ["\u2190 \uD56D\uBAA9\uC744 \uC120\uD0DD\uD558\uC138\uC694"];
1132
1254
  let statusMsg = "\uB85C\uB529...";
1255
+ let errors = [];
1133
1256
  async function loadData() {
1134
- statusMsg = "\uB85C\uB529...";
1257
+ statusMsg = "\uB370\uC774\uD130 \uB85C\uB529 \uC911...";
1258
+ errors = [];
1135
1259
  render();
1136
1260
  if (!server || !auth) {
1137
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"];
1138
1263
  render();
1139
1264
  return;
1140
1265
  }
@@ -1144,134 +1269,737 @@ async function startRawTui() {
1144
1269
  Promise.resolve().then(() => (init_document(), document_exports)),
1145
1270
  Promise.resolve().then(() => (init_xgen_extra(), xgen_extra_exports))
1146
1271
  ]);
1147
- const [wfR, colR, nodeR, promptR, toolR] = await Promise.allSettled([
1148
- wfMod.getWorkflowListDetail(),
1149
- docMod.listCollections(),
1150
- extraMod.listNodes(),
1151
- extraMod.listPrompts(),
1152
- extraMod.listToolStore()
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(() => [])
1153
1279
  ]);
1154
- if (wfR.status === "fulfilled") workflows = wfR.value.map((w) => ({ name: w.workflow_name, id: w.workflow_id ?? w.id ?? "", deployed: !!w.is_deployed }));
1155
- if (colR.status === "fulfilled") collections = colR.value.map((c) => ({ name: c.collection_make_name, docs: c.total_documents, chunks: c.total_chunks }));
1156
- if (nodeR.status === "fulfilled") nodes = nodeR.value.map((n) => ({ name: n.nodeName ?? n.name ?? "?", desc: (n.description ?? "").slice(0, 40) }));
1157
- if (promptR.status === "fulfilled") prompts = promptR.value.map((p) => ({ name: p.name ?? p.title ?? "?", type: p.prompt_type ?? "" }));
1158
- if (toolR.status === "fulfilled") tools2 = toolR.value.map((t) => ({ name: t.name ?? t.tool_name ?? "?", desc: (t.description ?? "").slice(0, 40) }));
1159
- } catch {
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
+ }
1324
+ }
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
+ }));
1356
+ }
1357
+ } catch (err) {
1358
+ errors.push(`\uC804\uCCB4: ${err.message}`);
1160
1359
  }
1161
- statusMsg = "\u2191\u2193:\uC774\uB3D9 Enter:\uC120\uD0DD/\uC2E4\uD589 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}`))];
1162
1364
  render();
1163
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];
1376
+ }
1164
1377
  function getItems() {
1165
1378
  switch (tab) {
1166
1379
  case "workflows":
1167
- return workflows.map((w) => ({ label: `${w.deployed ? "\u25CF" : "\u25CB"} ${w.name}`, sub: w.id.slice(0, 20) }));
1380
+ return workflows.map((w) => ({ label: `${w.deployed ? green("\u25CF") : dim("\u25CB")} ${w.name}`, sub: w.id.slice(0, 16) }));
1168
1381
  case "collections":
1169
1382
  return collections.map((c) => ({ label: c.name, sub: `${c.docs}\uBB38\uC11C ${c.chunks}\uCCAD\uD06C` }));
1170
1383
  case "nodes":
1171
- return nodes.map((n) => ({ label: n.name, sub: n.desc }));
1384
+ return nodes.map((n) => ({ label: n.name, sub: n.category ? `[${n.category}] ${n.desc}` : n.desc }));
1172
1385
  case "prompts":
1173
1386
  return prompts.map((p) => ({ label: p.name, sub: `[${p.type}]` }));
1174
1387
  case "tools":
1175
- return tools2.map((t) => ({ label: t.name, sub: t.desc }));
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
+ });
1176
1397
  }
1177
1398
  }
1178
1399
  function updateDetail() {
1179
1400
  const items = getItems();
1180
- if (selected < 0 || selected >= items.length) return;
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;
1181
1408
  if (tab === "workflows" && workflows[selected]) {
1182
1409
  const w = workflows[selected];
1183
- detail = [bold(w.name), "", `ID ${w.id}`, `\uBC30\uD3EC ${w.deployed ? "Yes" : "No"}`, "", "Enter \u2192 \uC2E4\uD589"];
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
+ ];
1184
1419
  } else if (tab === "collections" && collections[selected]) {
1185
1420
  const c = collections[selected];
1186
- detail = [bold(c.name), "", `\uBB38\uC11C ${c.docs}\uAC1C`, `\uCCAD\uD06C ${c.chunks}\uAC1C`];
1421
+ detail = [bold(c.name), "", `\uBB38\uC11C ${c.docs}\uAC1C`, `\uCCAD\uD06C ${c.chunks}\uAC1C`, "", cyan("Enter") + " \uBB38\uC11C \uBAA9\uB85D"];
1187
1422
  } else if (tab === "nodes" && nodes[selected]) {
1188
1423
  const n = nodes[selected];
1189
- detail = [bold(n.name), "", n.desc];
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
+ ];
1190
1432
  } else if (tab === "prompts" && prompts[selected]) {
1191
1433
  const p = prompts[selected];
1192
- detail = [bold(p.name), `[${p.type}]`];
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
+ ];
1193
1444
  } else if (tab === "tools" && tools2[selected]) {
1194
1445
  const t = tools2[selected];
1195
- detail = [bold(t.name), "", t.desc];
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
+ ];
1196
1469
  }
1197
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
+ }
1198
1477
  function render() {
1199
1478
  const cols = process.stdout.columns || 120;
1200
1479
  const rows = process.stdout.rows || 30;
1201
- const leftW = Math.floor(cols / 2);
1202
- const rightW = cols - leftW;
1480
+ const leftW = Math.floor(cols * 0.5);
1481
+ const rightW = cols - leftW - 1;
1203
1482
  const listH = rows - 5;
1204
1483
  clear();
1205
1484
  moveTo(1, 1);
1206
- const tabStr = TABS.map((t) => {
1207
- const active = tab === t.key;
1208
- return `[${t.num}]${active ? bold("\u25B8" + t.label) : dim(t.label)}`;
1209
- }).join(" ");
1210
- process.stdout.write(` ${bold("OPEN XGEN")} ${dim(provider?.model ?? "")} ${serverDisplay} \u2502 ${tabStr}`);
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}`);
1211
1487
  moveTo(2, 1);
1212
- process.stdout.write(dim("\u2500".repeat(cols)));
1488
+ process.stdout.write(dim("\u2500".repeat(leftW) + "\u252C" + "\u2500".repeat(rightW)));
1213
1489
  const items = getItems();
1214
- const visibleCount = listH;
1215
- const scrollStart = Math.max(0, Math.min(selected - Math.floor(visibleCount / 2), items.length - visibleCount));
1216
- for (let i = 0; i < visibleCount; i++) {
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++) {
1217
1493
  moveTo(3 + i, 1);
1218
- const idx = scrollStart + i;
1494
+ const idx = scr + i;
1495
+ let left;
1219
1496
  if (idx < items.length) {
1220
1497
  const item = items[idx];
1221
- const prefix = idx === selected ? "\u25B8 " : " ";
1222
- const line = `${prefix}${String(idx + 1).padStart(2)}. ${item.label}`;
1223
- const trimmed = line.slice(0, leftW - 2);
1224
- process.stdout.write(idx === selected ? inverse(trimmed.padEnd(leftW - 1)) : trimmed);
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);
1225
1501
  } else {
1226
- process.stdout.write(" ".repeat(leftW - 1));
1502
+ left = " ".repeat(leftW);
1227
1503
  }
1504
+ process.stdout.write(left);
1228
1505
  process.stdout.write(dim("\u2502"));
1229
- if (i < detail.length) {
1230
- const dline = detail[i].slice(0, rightW - 2);
1231
- process.stdout.write(` ${dline}`);
1232
- }
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)"));
1233
1511
  }
1234
1512
  moveTo(rows - 2, 1);
1235
- process.stdout.write(dim("\u2500".repeat(cols)));
1513
+ process.stdout.write(dim("\u2500".repeat(leftW) + "\u2534" + "\u2500".repeat(rightW)));
1236
1514
  moveTo(rows - 1, 1);
1237
- if (inputMode) {
1238
- const prompt2 = runTarget ? `${runTarget.name} \u276F ` : "\u276F ";
1239
- process.stdout.write(` ${prompt2}${inputBuffer}`);
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}`);
1240
1518
  showCursor();
1241
1519
  } else {
1242
- process.stdout.write(dim(" \u276F i\uB97C \uB20C\uB7EC \uC785\uB825 \xB7 Enter\uB85C \uC2E4\uD589"));
1520
+ process.stdout.write(dim(` ${getHint()}`));
1243
1521
  hideCursor();
1244
1522
  }
1245
1523
  moveTo(rows, 1);
1246
1524
  process.stdout.write(dim(` ${statusMsg}`.slice(0, cols)));
1247
1525
  }
1248
- async function executeWorkflowAction(wf, input) {
1249
- detail = [`\uC2E4\uD589 \uC911: ${wf.name}`, `\uC785\uB825: ${input}`, "", "..."];
1526
+ async function runWorkflow(wf, input) {
1527
+ detail = [bold(wf.name), "", `\uC785\uB825: ${input}`, "", yellow("\uC2E4\uD589 \uC911...")];
1250
1528
  render();
1251
1529
  try {
1252
1530
  const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1253
1531
  const { randomUUID: randomUUID4 } = await import("crypto");
1254
- const r = await executeWorkflow2({
1532
+ const r = await withTimeout(executeWorkflow2({
1255
1533
  workflow_id: wf.id,
1256
1534
  workflow_name: wf.name,
1257
1535
  input_data: input,
1258
1536
  interaction_id: `tui_${randomUUID4().slice(0, 8)}`,
1259
1537
  user_id: auth?.userId ? parseInt(auth.userId) : 1
1260
- });
1261
- const content = r.content ?? r.message ?? JSON.stringify(r).slice(0, 500);
1262
- detail = [bold(wf.name), "", `\uC785\uB825: ${input}`, "", "\uACB0\uACFC:", ...String(content).split("\n").slice(0, 15)];
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();
1590
+ return;
1591
+ }
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();
1631
+ try {
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");
1636
+ } catch (err) {
1637
+ detail = [red(`\u2717 \uC2E4\uD328: ${err.message}`)];
1638
+ statusMsg = red("\uC2E4\uD328");
1639
+ }
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");
1263
1807
  } catch (err) {
1264
- detail = [`\uC2E4\uD589 \uC2E4\uD328: ${err.message}`];
1808
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1809
+ statusMsg = red("\uC2E4\uD328");
1265
1810
  }
1266
1811
  render();
1267
1812
  }
1268
- function handleKey(data) {
1269
- const s = data.toString();
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");
1915
+ }
1916
+ render();
1917
+ }
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
+ }
1270
1997
  if (inputMode) {
1271
1998
  if (s === "\x1B" || s === "\x1B\x1B") {
1272
1999
  inputMode = false;
1273
2000
  inputBuffer = "";
1274
- runTarget = null;
2001
+ updateDetail();
2002
+ statusMsg = getHint();
1275
2003
  render();
1276
2004
  return;
1277
2005
  }
@@ -1279,11 +2007,11 @@ async function startRawTui() {
1279
2007
  const val = inputBuffer.trim();
1280
2008
  inputMode = false;
1281
2009
  inputBuffer = "";
1282
- if (val && runTarget) {
1283
- executeWorkflowAction(runTarget, val);
1284
- runTarget = null;
2010
+ if (val && tab === "workflows" && workflows[selected]) {
2011
+ runWorkflow(workflows[selected], val);
2012
+ } else {
2013
+ render();
1285
2014
  }
1286
- render();
1287
2015
  return;
1288
2016
  }
1289
2017
  if (s === "\x7F" || s === "\b") {
@@ -1291,6 +2019,12 @@ async function startRawTui() {
1291
2019
  render();
1292
2020
  return;
1293
2021
  }
2022
+ if (s === "") {
2023
+ inputMode = false;
2024
+ inputBuffer = "";
2025
+ render();
2026
+ return;
2027
+ }
1294
2028
  if (s.length > 0 && s.charCodeAt(0) >= 32) {
1295
2029
  inputBuffer += s;
1296
2030
  render();
@@ -1302,20 +2036,79 @@ async function startRawTui() {
1302
2036
  cleanup();
1303
2037
  process.exit(0);
1304
2038
  }
1305
- if (s === "r") {
2039
+ if (s === "r" || s === "R") {
1306
2040
  loadData();
1307
2041
  return;
1308
2042
  }
1309
- if (s === "i") {
2043
+ if (s === "i" && tab === "workflows" && workflows[selected]) {
1310
2044
  inputMode = true;
2045
+ inputBuffer = "";
2046
+ statusMsg = `${workflows[selected].name} \u2014 \uC9C8\uBB38 \uC785\uB825 \uD6C4 Enter, Esc \uCDE8\uC18C`;
1311
2047
  render();
1312
2048
  return;
1313
2049
  }
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
+ }
1314
2106
  const tabNum = parseInt(s);
1315
- if (tabNum >= 1 && tabNum <= 5) {
2107
+ if (tabNum >= 1 && tabNum <= 6) {
1316
2108
  tab = TABS[tabNum - 1].key;
1317
2109
  selected = 0;
1318
2110
  updateDetail();
2111
+ statusMsg = getHint();
1319
2112
  render();
1320
2113
  return;
1321
2114
  }
@@ -1324,48 +2117,82 @@ async function startRawTui() {
1324
2117
  tab = TABS[(idx + 1) % TABS.length].key;
1325
2118
  selected = 0;
1326
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();
1327
2130
  render();
1328
2131
  return;
1329
2132
  }
1330
2133
  if (s === "\x1B[A") {
1331
2134
  const items = getItems();
1332
- selected = Math.max(0, selected - 1);
2135
+ if (items.length > 0) {
2136
+ selected = Math.max(0, selected - 1);
2137
+ updateDetail();
2138
+ render();
2139
+ }
2140
+ return;
2141
+ }
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();
2148
+ }
2149
+ return;
2150
+ }
2151
+ if (s === "\x1B[5~") {
2152
+ selected = Math.max(0, selected - 10);
1333
2153
  updateDetail();
1334
2154
  render();
1335
2155
  return;
1336
2156
  }
1337
- if (s === "\x1B[B") {
2157
+ if (s === "\x1B[6~") {
1338
2158
  const items = getItems();
1339
- selected = Math.min(items.length - 1, selected + 1);
2159
+ selected = Math.min(items.length - 1, selected + 10);
1340
2160
  updateDetail();
1341
2161
  render();
1342
2162
  return;
1343
2163
  }
1344
2164
  if (s === "\r" || s === "\n") {
2165
+ const items = getItems();
2166
+ if (items.length === 0) return;
1345
2167
  if (tab === "workflows" && workflows[selected]) {
1346
- runTarget = workflows[selected];
1347
- inputMode = true;
1348
- statusMsg = `${runTarget.name} \u2014 \uC785\uB825 \uD6C4 Enter \uC2E4\uD589, Esc \uCDE8\uC18C`;
1349
- render();
2168
+ loadWorkflowStructure(workflows[selected]);
1350
2169
  } else if (tab === "collections" && collections[selected]) {
1351
2170
  const c = collections[selected];
1352
- detail = [`${c.name} \uBB38\uC11C \uB85C\uB529...`];
2171
+ detail = [bold(c.name), "", yellow("\uBB38\uC11C \uB85C\uB529...")];
1353
2172
  render();
1354
2173
  Promise.resolve().then(() => (init_document(), document_exports)).then(async (m) => {
1355
2174
  try {
1356
- const docs = await m.listDocuments(String(collections[selected].id ?? ""));
1357
- if (!docs.length) {
1358
- detail = [bold(c.name), "", "\uBB38\uC11C \uC5C6\uC74C"];
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")];
1359
2178
  } else {
1360
- detail = [bold(c.name) + ` \u2014 ${docs.length}\uAC1C \uBB38\uC11C`, "", ...docs.map(
1361
- (d, i) => ` ${i + 1}. ${d.name || d.file_name || "\uC774\uB984\uC5C6\uC74C"}`
1362
- ).slice(0, 15)];
2179
+ detail = [bold(c.name) + ` \u2014 ${docs.length}\uAC1C`, "", ...docs.map((d, i) => ` ${i + 1}. ${d.name || d.file_name || "?"}`).slice(0, 20)];
1363
2180
  }
1364
2181
  } catch (err) {
1365
- detail = [`\uBB38\uC11C \uB85C\uB4DC \uC2E4\uD328: ${err.message}`];
2182
+ detail = [red(`\uC2E4\uD328: ${err.message}`)];
1366
2183
  }
1367
2184
  render();
1368
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();
1369
2196
  }
1370
2197
  return;
1371
2198
  }
@@ -1373,9 +2200,7 @@ async function startRawTui() {
1373
2200
  function cleanup() {
1374
2201
  showCursor();
1375
2202
  clear();
1376
- if (process.stdin.isTTY && process.stdin.isRaw) {
1377
- process.stdin.setRawMode(false);
1378
- }
2203
+ if (process.stdin.isTTY && process.stdin.isRaw) process.stdin.setRawMode(false);
1379
2204
  process.stdin.removeAllListeners("data");
1380
2205
  process.stdin.pause();
1381
2206
  }
@@ -1389,10 +2214,13 @@ async function startRawTui() {
1389
2214
  hideCursor();
1390
2215
  process.stdin.on("data", (data) => {
1391
2216
  try {
1392
- handleKey(data);
1393
- } catch {
2217
+ handleKey(String(data));
2218
+ } catch (err) {
2219
+ statusMsg = red(`\uC624\uB958: ${err.message}`);
2220
+ render();
1394
2221
  }
1395
2222
  });
2223
+ process.stdout.on("resize", () => render());
1396
2224
  process.on("SIGINT", () => {
1397
2225
  cleanup();
1398
2226
  process.exit(0);
@@ -1400,11 +2228,11 @@ async function startRawTui() {
1400
2228
  process.on("exit", () => {
1401
2229
  showCursor();
1402
2230
  });
1403
- await loadData();
2231
+ loadData();
1404
2232
  await new Promise(() => {
1405
2233
  });
1406
2234
  }
1407
- var TABS, CSI, clear, moveTo, dim, bold, inverse, hideCursor, showCursor;
2235
+ var TABS, CSI, clear, moveTo, dim, bold, inverse, red, green, yellow, cyan, hideCursor, showCursor;
1408
2236
  var init_raw_tui = __esm({
1409
2237
  "src/dashboard/raw-tui.ts"() {
1410
2238
  "use strict";
@@ -1414,7 +2242,8 @@ var init_raw_tui = __esm({
1414
2242
  { key: "collections", label: "\uCEEC\uB809\uC158", num: "2" },
1415
2243
  { key: "nodes", label: "\uB178\uB4DC", num: "3" },
1416
2244
  { key: "prompts", label: "\uD504\uB86C\uD504\uD2B8", num: "4" },
1417
- { key: "tools", label: "\uB3C4\uAD6C", num: "5" }
2245
+ { key: "tools", label: "\uB3C4\uAD6C", num: "5" },
2246
+ { key: "mcp", label: "MCP", num: "6" }
1418
2247
  ];
1419
2248
  CSI = "\x1B[";
1420
2249
  clear = () => process.stdout.write(`${CSI}2J${CSI}H`);
@@ -1422,6 +2251,10 @@ var init_raw_tui = __esm({
1422
2251
  dim = (s) => `${CSI}2m${s}${CSI}0m`;
1423
2252
  bold = (s) => `${CSI}1m${s}${CSI}0m`;
1424
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`;
1425
2258
  hideCursor = () => process.stdout.write(`${CSI}?25l`);
1426
2259
  showCursor = () => process.stdout.write(`${CSI}?25h`);
1427
2260
  }
@@ -3631,7 +4464,7 @@ ${result.answer}
3631
4464
  }
3632
4465
 
3633
4466
  // src/index.ts
3634
- var VERSION = "2.3.0";
4467
+ var VERSION = "2.4.0";
3635
4468
  var LOGO = chalk15.cyan(`
3636
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
3637
4470
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
@@ -3663,11 +4496,17 @@ ${chalk15.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
3663
4496
  ${chalk15.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
3664
4497
 
3665
4498
  ${chalk15.bold("XGEN \uD50C\uB7AB\uD3FC:")}
4499
+ ${chalk15.cyan("xgen dash")} TUI \uB300\uC2DC\uBCF4\uB4DC (\uC870\uD68C/\uD14C\uC2A4\uD2B8/\uC0DD\uC131)
3666
4500
  ${chalk15.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
3667
4501
  ${chalk15.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
3668
4502
  ${chalk15.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
3669
4503
  ${chalk15.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
3670
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
3671
4510
  `
3672
4511
  );
3673
4512
  registerConfigCommand(program);
@@ -3679,6 +4518,9 @@ registerAgentCommand(program);
3679
4518
  registerDocCommand(program);
3680
4519
  registerOntologyCommand(program);
3681
4520
  program.command("dash").alias("dashboard").description("XGEN TUI \uB300\uC2DC\uBCF4\uB4DC").action(async () => {
4521
+ process.stdin.removeAllListeners();
4522
+ process.stdin.pause();
4523
+ await new Promise((r) => setTimeout(r, 50));
3682
4524
  const { startRawTui: startRawTui2 } = await Promise.resolve().then(() => (init_raw_tui(), raw_tui_exports));
3683
4525
  await startRawTui2();
3684
4526
  });