openxgen 1.1.1 → 1.2.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
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
5
  var __esm = (fn, res) => function __init() {
@@ -775,6 +776,11 @@ var init_provider = __esm({
775
776
  });
776
777
 
777
778
  // src/agent/llm.ts
779
+ var llm_exports = {};
780
+ __export(llm_exports, {
781
+ createLLMClient: () => createLLMClient,
782
+ streamChat: () => streamChat
783
+ });
778
784
  import OpenAI2 from "openai";
779
785
  function createLLMClient(provider) {
780
786
  const opts = {
@@ -828,2172 +834,2076 @@ var init_llm = __esm({
828
834
  }
829
835
  });
830
836
 
831
- // src/agent/tools/file-read.ts
832
- var file_read_exports = {};
833
- __export(file_read_exports, {
834
- definition: () => definition,
835
- execute: () => execute
837
+ // src/api/document.ts
838
+ var document_exports = {};
839
+ __export(document_exports, {
840
+ getDocumentInfo: () => getDocumentInfo,
841
+ listCollections: () => listCollections,
842
+ listDocuments: () => listDocuments,
843
+ uploadDocument: () => uploadDocument
836
844
  });
837
- import { readFileSync as readFileSync2 } from "fs";
838
- async function execute(args) {
839
- const path = args.path;
840
- const startLine = args.start_line || 1;
841
- const endLine = args.end_line;
842
- try {
843
- const content = readFileSync2(path, "utf-8");
844
- const lines = content.split("\n");
845
- const sliced = lines.slice(startLine - 1, endLine ?? lines.length);
846
- return sliced.map((line, i) => `${startLine + i} ${line}`).join("\n");
847
- } catch (err) {
848
- return `Error: ${err.message}`;
849
- }
845
+ async function listCollections() {
846
+ const client2 = getClient();
847
+ const res = await client2.get("/api/retrieval/collections");
848
+ return Array.isArray(res.data) ? res.data : res.data.collections ?? [];
850
849
  }
851
- var definition;
852
- var init_file_read = __esm({
853
- "src/agent/tools/file-read.ts"() {
854
- "use strict";
855
- definition = {
856
- type: "function",
857
- function: {
858
- name: "file_read",
859
- description: "\uD30C\uC77C \uB0B4\uC6A9\uC744 \uC77D\uC2B5\uB2C8\uB2E4. \uC904 \uBC88\uD638\uAC00 \uD3EC\uD568\uB429\uB2C8\uB2E4.",
860
- parameters: {
861
- type: "object",
862
- properties: {
863
- path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
864
- start_line: { type: "number", description: "\uC2DC\uC791 \uC904 \uBC88\uD638 (\uC120\uD0DD)" },
865
- end_line: { type: "number", description: "\uB05D \uC904 \uBC88\uD638 (\uC120\uD0DD)" }
866
- },
867
- required: ["path"]
868
- }
869
- }
870
- };
871
- }
872
- });
873
-
874
- // src/agent/tools/file-write.ts
875
- var file_write_exports = {};
876
- __export(file_write_exports, {
877
- definition: () => definition2,
878
- execute: () => execute2
879
- });
880
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
881
- import { dirname } from "path";
882
- async function execute2(args) {
883
- const path = args.path;
884
- const content = args.content;
850
+ async function listDocuments(collectionId) {
851
+ const client2 = getClient();
885
852
  try {
886
- mkdirSync2(dirname(path), { recursive: true });
887
- writeFileSync2(path, content, "utf-8");
888
- return `\uD30C\uC77C \uC791\uC131 \uC644\uB8CC: ${path}`;
889
- } catch (err) {
890
- return `Error: ${err.message}`;
853
+ const params = {};
854
+ if (collectionId) params.collection_id = collectionId;
855
+ const res = await client2.get("/api/retrieval/documents/list", { params });
856
+ return res.data.documents ?? res.data ?? [];
857
+ } catch {
858
+ return [];
891
859
  }
892
860
  }
893
- var definition2;
894
- var init_file_write = __esm({
895
- "src/agent/tools/file-write.ts"() {
861
+ async function uploadDocument(filePath, collectionId, name) {
862
+ const client2 = getClient();
863
+ const { createReadStream, statSync } = await import("fs");
864
+ const { basename } = await import("path");
865
+ const stat = statSync(filePath);
866
+ const fileName = name || basename(filePath);
867
+ const form = new FormData();
868
+ const fileBlob = new Blob([createReadStream(filePath)]);
869
+ form.append("file", fileBlob, fileName);
870
+ if (collectionId) form.append("collection_id", collectionId);
871
+ const res = await client2.post("/api/retrieval/documents/upload", form, {
872
+ headers: { "Content-Type": "multipart/form-data" },
873
+ maxBodyLength: stat.size + 1024 * 1024
874
+ });
875
+ return res.data;
876
+ }
877
+ async function getDocumentInfo(docId) {
878
+ const client2 = getClient();
879
+ const res = await client2.get(`/api/retrieval/documents/${docId}`);
880
+ return res.data;
881
+ }
882
+ var init_document = __esm({
883
+ "src/api/document.ts"() {
896
884
  "use strict";
897
- definition2 = {
898
- type: "function",
899
- function: {
900
- name: "file_write",
901
- description: "\uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uAC70\uB098 \uB36E\uC5B4\uC501\uB2C8\uB2E4.",
902
- parameters: {
903
- type: "object",
904
- properties: {
905
- path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
906
- content: { type: "string", description: "\uD30C\uC77C \uB0B4\uC6A9" }
907
- },
908
- required: ["path", "content"]
909
- }
910
- }
911
- };
885
+ init_client();
912
886
  }
913
887
  });
914
888
 
915
- // src/agent/tools/file-edit.ts
916
- var file_edit_exports = {};
917
- __export(file_edit_exports, {
918
- definition: () => definition3,
919
- execute: () => execute3
889
+ // src/dashboard/tui.ts
890
+ var tui_exports = {};
891
+ __export(tui_exports, {
892
+ startTui: () => startTui
920
893
  });
921
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
922
- async function execute3(args) {
923
- const path = args.path;
924
- const oldText = args.old_text;
925
- const newText = args.new_text;
926
- try {
927
- const content = readFileSync3(path, "utf-8");
928
- if (!content.includes(oldText)) {
929
- return `Error: \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4`;
894
+ import blessed from "blessed";
895
+ async function startTui() {
896
+ const screen = blessed.screen({
897
+ smartCSR: true,
898
+ title: "OPEN XGEN",
899
+ fullUnicode: true
900
+ });
901
+ const provider = getDefaultProvider();
902
+ const server = getServer();
903
+ const auth = getAuth();
904
+ const env = getActiveEnvironment();
905
+ const header = blessed.box({
906
+ top: 0,
907
+ left: 0,
908
+ width: "100%",
909
+ height: 3,
910
+ content: `{center}{bold}OPEN XGEN{/bold} ${provider?.model ?? "AI \uBBF8\uC124\uC815"} \xB7 ${auth?.username ?? "\uBBF8\uC5F0\uACB0"}@${env?.name ?? server?.replace("https://", "") ?? ""}{/center}`,
911
+ tags: true,
912
+ style: { fg: "white", bg: "blue" }
913
+ });
914
+ const wfPanel = blessed.list({
915
+ top: 3,
916
+ left: 0,
917
+ width: "50%",
918
+ height: "50%-2",
919
+ label: " \uC6CC\uD06C\uD50C\uB85C\uC6B0 ",
920
+ border: { type: "line" },
921
+ style: {
922
+ border: { fg: "cyan" },
923
+ selected: { fg: "black", bg: "cyan" },
924
+ item: { fg: "white" },
925
+ label: { fg: "cyan", bold: true }
926
+ },
927
+ keys: true,
928
+ vi: true,
929
+ mouse: true,
930
+ scrollbar: { ch: "\u2502", style: { fg: "cyan" } },
931
+ tags: true
932
+ });
933
+ const detailPanel = blessed.box({
934
+ top: 3,
935
+ left: "50%",
936
+ width: "50%",
937
+ height: "50%-2",
938
+ label: " \uC0C1\uC138 ",
939
+ border: { type: "line" },
940
+ scrollable: true,
941
+ alwaysScroll: true,
942
+ mouse: true,
943
+ tags: true,
944
+ style: {
945
+ border: { fg: "green" },
946
+ label: { fg: "green", bold: true }
930
947
  }
931
- const updated = content.replace(oldText, newText);
932
- writeFileSync3(path, updated, "utf-8");
933
- return `\uD30C\uC77C \uC218\uC815 \uC644\uB8CC: ${path}`;
934
- } catch (err) {
935
- return `Error: ${err.message}`;
936
- }
937
- }
938
- var definition3;
939
- var init_file_edit = __esm({
940
- "src/agent/tools/file-edit.ts"() {
941
- "use strict";
942
- definition3 = {
943
- type: "function",
944
- function: {
945
- name: "file_edit",
946
- description: "\uD30C\uC77C\uC5D0\uC11C \uD2B9\uC815 \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC544 \uAD50\uCCB4\uD569\uB2C8\uB2E4.",
947
- parameters: {
948
- type: "object",
949
- properties: {
950
- path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
951
- old_text: { type: "string", description: "\uAD50\uCCB4\uD560 \uAE30\uC874 \uD14D\uC2A4\uD2B8" },
952
- new_text: { type: "string", description: "\uC0C8 \uD14D\uC2A4\uD2B8" }
953
- },
954
- required: ["path", "old_text", "new_text"]
955
- }
956
- }
957
- };
958
- }
959
- });
948
+ });
949
+ const colPanel = blessed.list({
950
+ top: "50%+1",
951
+ left: 0,
952
+ width: "50%",
953
+ height: "50%-4",
954
+ label: " \uCEEC\uB809\uC158 (\uBB38\uC11C) ",
955
+ border: { type: "line" },
956
+ style: {
957
+ border: { fg: "yellow" },
958
+ selected: { fg: "black", bg: "yellow" },
959
+ item: { fg: "white" },
960
+ label: { fg: "yellow", bold: true }
961
+ },
962
+ keys: true,
963
+ vi: true,
964
+ mouse: true,
965
+ tags: true
966
+ });
967
+ const chatLog = blessed.log({
968
+ top: "50%+1",
969
+ left: "50%",
970
+ width: "50%",
971
+ height: "50%-7",
972
+ label: " AI \uCC44\uD305 ",
973
+ border: { type: "line" },
974
+ scrollable: true,
975
+ alwaysScroll: true,
976
+ mouse: true,
977
+ tags: true,
978
+ style: {
979
+ border: { fg: "magenta" },
980
+ label: { fg: "magenta", bold: true }
981
+ }
982
+ });
983
+ const chatInput = blessed.textbox({
984
+ bottom: 3,
985
+ left: "50%",
986
+ width: "50%",
987
+ height: 3,
988
+ label: " \uC785\uB825 ",
989
+ border: { type: "line" },
990
+ inputOnFocus: true,
991
+ style: {
992
+ border: { fg: "magenta" },
993
+ label: { fg: "magenta" }
994
+ }
995
+ });
996
+ const statusBar = blessed.box({
997
+ bottom: 0,
998
+ left: 0,
999
+ width: "100%",
1000
+ height: 3,
1001
+ content: " {bold}Tab{/bold}:\uD328\uB110\uC804\uD658 {bold}Enter{/bold}:\uC120\uD0DD {bold}r{/bold}:\uC0C8\uB85C\uACE0\uCE68 {bold}c{/bold}:\uCC44\uD305 {bold}q{/bold}:\uC885\uB8CC {bold}\u2191\u2193{/bold}:\uC774\uB3D9",
1002
+ tags: true,
1003
+ style: { fg: "white", bg: "gray" }
1004
+ });
1005
+ screen.append(header);
1006
+ screen.append(wfPanel);
1007
+ screen.append(detailPanel);
1008
+ screen.append(colPanel);
1009
+ screen.append(chatLog);
1010
+ screen.append(chatInput);
1011
+ screen.append(statusBar);
1012
+ let workflows = [];
1013
+ let collections = [];
1014
+ async function loadData() {
1015
+ if (!server || !auth) {
1016
+ wfPanel.setItems(["\uC11C\uBC84 \uBBF8\uC5F0\uACB0 \u2014 q \uC885\uB8CC \uD6C4 xgen agent \u2192 /connect"]);
1017
+ colPanel.setItems(["\uC11C\uBC84 \uBBF8\uC5F0\uACB0"]);
1018
+ screen.render();
1019
+ return;
1020
+ }
1021
+ statusBar.setContent(" \uB85C\uB529 \uC911...");
1022
+ screen.render();
1023
+ try {
1024
+ const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1025
+ const wfs = await getWorkflowListDetail2();
1026
+ workflows = wfs.map((w) => ({
1027
+ name: w.workflow_name,
1028
+ id: (w.workflow_id ?? w.id ?? "").toString(),
1029
+ deployed: !!w.is_deployed,
1030
+ deployKey: w.deploy_key,
1031
+ nodeCount: w.node_count
1032
+ }));
1033
+ wfPanel.setItems(workflows.map((w) => {
1034
+ const tag = w.deployed ? "{green-fg}[\uBC30\uD3EC]{/green-fg}" : "";
1035
+ return ` ${w.name} ${tag}`;
1036
+ }));
1037
+ } catch (err) {
1038
+ wfPanel.setItems([`\uC624\uB958: ${err.message}`]);
1039
+ }
1040
+ try {
1041
+ const { listCollections: listCollections2 } = await Promise.resolve().then(() => (init_document(), document_exports));
1042
+ const cols = await listCollections2();
1043
+ collections = cols.map((c) => ({
1044
+ name: c.collection_make_name,
1045
+ docs: c.total_documents,
1046
+ chunks: c.total_chunks,
1047
+ shared: c.is_shared,
1048
+ group: c.share_group ?? void 0
1049
+ }));
1050
+ colPanel.setItems(collections.map((c) => {
1051
+ const shared = c.shared ? `{yellow-fg}[${c.group}]{/yellow-fg}` : "";
1052
+ return ` ${c.name} ${shared} \u2014 ${c.docs}\uBB38\uC11C ${c.chunks}\uCCAD\uD06C`;
1053
+ }));
1054
+ } catch {
1055
+ colPanel.setItems(["\uCEEC\uB809\uC158 \uB85C\uB4DC \uC2E4\uD328"]);
1056
+ }
1057
+ statusBar.setContent(" {bold}Tab{/bold}:\uD328\uB110\uC804\uD658 {bold}Enter{/bold}:\uC120\uD0DD {bold}r{/bold}:\uC0C8\uB85C\uACE0\uCE68 {bold}c{/bold}:\uCC44\uD305 {bold}q{/bold}:\uC885\uB8CC {bold}\u2191\u2193{/bold}:\uC774\uB3D9");
1058
+ screen.render();
1059
+ }
1060
+ wfPanel.on("select item", (_item, index) => {
1061
+ const w = workflows[index];
1062
+ if (!w) return;
1063
+ detailPanel.setContent([
1064
+ `{bold}${w.name}{/bold}`,
1065
+ "",
1066
+ `ID: ${w.id}`,
1067
+ `\uBC30\uD3EC: ${w.deployed ? "{green-fg}Yes{/green-fg}" : "No"}`,
1068
+ w.deployKey ? `Deploy Key: ${w.deployKey}` : "",
1069
+ w.nodeCount ? `\uB178\uB4DC: ${w.nodeCount}\uAC1C` : "",
1070
+ "",
1071
+ w.deployed ? "{green-fg}Enter\uB85C \uC2E4\uD589{/green-fg}" : "{gray-fg}\uBBF8\uBC30\uD3EC \u2014 \uC2E4\uD589 \uBD88\uAC00{/gray-fg}"
1072
+ ].filter(Boolean).join("\n"));
1073
+ screen.render();
1074
+ });
1075
+ wfPanel.on("select", async (_item, index) => {
1076
+ const w = workflows[index];
1077
+ if (!w || !w.deployed || !w.deployKey) {
1078
+ detailPanel.setContent("{red-fg}\uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB9CC \uC2E4\uD589 \uAC00\uB2A5\uD569\uB2C8\uB2E4.{/red-fg}");
1079
+ screen.render();
1080
+ return;
1081
+ }
1082
+ detailPanel.setContent(`{yellow-fg}${w.name} \uC2E4\uD589 \uC911...{/yellow-fg}`);
1083
+ screen.render();
1084
+ try {
1085
+ const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1086
+ const { randomUUID: randomUUID4 } = await import("crypto");
1087
+ const result = await executeWorkflow2({
1088
+ workflow_id: w.id,
1089
+ workflow_name: w.name,
1090
+ input_data: "\uD14C\uC2A4\uD2B8 \uC2E4\uD589",
1091
+ interaction_id: `cli_${randomUUID4().slice(0, 8)}`,
1092
+ deploy_key: w.deployKey
1093
+ });
1094
+ if (result.content) {
1095
+ detailPanel.setContent(`{green-fg}\uACB0\uACFC:{/green-fg}
960
1096
 
961
- // src/agent/tools/bash.ts
962
- var bash_exports = {};
963
- __export(bash_exports, {
964
- definition: () => definition4,
965
- execute: () => execute4
966
- });
967
- import { execSync } from "child_process";
968
- async function execute4(args) {
969
- const command = args.command;
970
- try {
971
- const output = execSync(command, {
972
- encoding: "utf-8",
973
- timeout: 3e4,
974
- maxBuffer: 1024 * 1024,
975
- stdio: ["pipe", "pipe", "pipe"]
976
- });
977
- return output || "(no output)";
978
- } catch (err) {
979
- const e = err;
980
- return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
981
- }
982
- }
983
- var definition4;
984
- var init_bash = __esm({
985
- "src/agent/tools/bash.ts"() {
986
- "use strict";
987
- definition4 = {
988
- type: "function",
989
- function: {
990
- name: "bash",
991
- description: "\uC178 \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. stdout + stderr\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.",
992
- parameters: {
993
- type: "object",
994
- properties: {
995
- command: { type: "string", description: "\uC2E4\uD589\uD560 \uBA85\uB839\uC5B4" }
996
- },
997
- required: ["command"]
998
- }
1097
+ ${String(result.content).slice(0, 500)}`);
1098
+ } else if (result.error) {
1099
+ detailPanel.setContent(`{red-fg}\uC624\uB958:{/red-fg} ${result.error}`);
1100
+ } else {
1101
+ detailPanel.setContent(JSON.stringify(result, null, 2).slice(0, 500));
999
1102
  }
1000
- };
1001
- }
1002
- });
1003
-
1004
- // src/agent/tools/grep.ts
1005
- var grep_exports = {};
1006
- __export(grep_exports, {
1007
- definition: () => definition5,
1008
- execute: () => execute5
1009
- });
1010
- import { execSync as execSync2 } from "child_process";
1011
- async function execute5(args) {
1012
- const pattern = args.pattern;
1013
- const path = args.path || ".";
1014
- const glob = args.glob;
1015
- try {
1016
- let cmd = `grep -rn --color=never "${pattern.replace(/"/g, '\\"')}" "${path}"`;
1017
- if (glob) cmd += ` --include="${glob}"`;
1018
- cmd += " | head -50";
1019
- const output = execSync2(cmd, {
1020
- encoding: "utf-8",
1021
- timeout: 1e4,
1022
- maxBuffer: 512 * 1024,
1023
- stdio: ["pipe", "pipe", "pipe"]
1024
- });
1025
- return output || "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
1026
- } catch {
1027
- return "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
1028
- }
1103
+ } catch (err) {
1104
+ detailPanel.setContent(`{red-fg}\uC2E4\uD589 \uC2E4\uD328:{/red-fg} ${err.message}`);
1105
+ }
1106
+ screen.render();
1107
+ });
1108
+ colPanel.on("select item", (_item, index) => {
1109
+ const c = collections[index];
1110
+ if (!c) return;
1111
+ detailPanel.setContent([
1112
+ `{bold}${c.name}{/bold}`,
1113
+ "",
1114
+ `\uBB38\uC11C: ${c.docs}\uAC1C`,
1115
+ `\uCCAD\uD06C: ${c.chunks}\uAC1C`,
1116
+ `\uACF5\uC720: ${c.shared ? `Yes (${c.group})` : "No"}`
1117
+ ].join("\n"));
1118
+ screen.render();
1119
+ });
1120
+ chatInput.on("submit", async (value) => {
1121
+ if (!value.trim()) {
1122
+ chatInput.clearValue();
1123
+ chatInput.focus();
1124
+ screen.render();
1125
+ return;
1126
+ }
1127
+ chatLog.log(`{blue-fg}You:{/blue-fg} ${value}`);
1128
+ chatInput.clearValue();
1129
+ screen.render();
1130
+ try {
1131
+ const provider2 = getDefaultProvider();
1132
+ if (!provider2) {
1133
+ chatLog.log("{red-fg}\uD504\uB85C\uBC14\uC774\uB354 \uBBF8\uC124\uC815{/red-fg}");
1134
+ chatInput.focus();
1135
+ screen.render();
1136
+ return;
1137
+ }
1138
+ const { createLLMClient: createLLMClient2, streamChat: streamChat2 } = await Promise.resolve().then(() => (init_llm(), llm_exports));
1139
+ const client2 = createLLMClient2(provider2);
1140
+ const result = await streamChat2(client2, provider2.model, [
1141
+ { role: "system", content: "You are OPEN XGEN. Be concise. Respond in Korean. Max 3 sentences." },
1142
+ { role: "user", content: value }
1143
+ ]);
1144
+ chatLog.log(`{green-fg}AI:{/green-fg} ${result.content || "(no response)"}`);
1145
+ } catch (err) {
1146
+ chatLog.log(`{red-fg}\uC624\uB958:{/red-fg} ${err.message}`);
1147
+ }
1148
+ chatInput.focus();
1149
+ screen.render();
1150
+ });
1151
+ const panels = [wfPanel, colPanel, chatInput];
1152
+ let activePanel = 0;
1153
+ function focusPanel(idx) {
1154
+ activePanel = idx;
1155
+ panels[idx].focus();
1156
+ screen.render();
1157
+ }
1158
+ screen.key(["tab"], () => {
1159
+ activePanel = (activePanel + 1) % panels.length;
1160
+ focusPanel(activePanel);
1161
+ });
1162
+ screen.key(["S-tab"], () => {
1163
+ activePanel = (activePanel - 1 + panels.length) % panels.length;
1164
+ focusPanel(activePanel);
1165
+ });
1166
+ screen.key(["r"], async () => {
1167
+ await loadData();
1168
+ });
1169
+ screen.key(["c"], () => {
1170
+ focusPanel(2);
1171
+ });
1172
+ screen.key(["q", "C-c"], () => {
1173
+ screen.destroy();
1174
+ process.exit(0);
1175
+ });
1176
+ setInterval(async () => {
1177
+ try {
1178
+ await loadData();
1179
+ } catch {
1180
+ }
1181
+ }, 3e4);
1182
+ await loadData();
1183
+ focusPanel(0);
1184
+ screen.render();
1029
1185
  }
1030
- var definition5;
1031
- var init_grep = __esm({
1032
- "src/agent/tools/grep.ts"() {
1186
+ var init_tui = __esm({
1187
+ "src/dashboard/tui.ts"() {
1033
1188
  "use strict";
1034
- definition5 = {
1035
- type: "function",
1036
- function: {
1037
- name: "grep",
1038
- description: "\uD30C\uC77C\uC5D0\uC11C \uD328\uD134\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4 (\uC7AC\uADC0, \uC904 \uBC88\uD638 \uD3EC\uD568).",
1039
- parameters: {
1040
- type: "object",
1041
- properties: {
1042
- pattern: { type: "string", description: "\uAC80\uC0C9 \uD328\uD134 (\uC815\uADDC\uC2DD)" },
1043
- path: { type: "string", description: "\uAC80\uC0C9 \uB514\uB809\uD1A0\uB9AC \uB610\uB294 \uD30C\uC77C (\uAE30\uBCF8: .)" },
1044
- glob: { type: "string", description: "\uD30C\uC77C \uD544\uD130 (\uC608: *.ts)" }
1045
- },
1046
- required: ["pattern"]
1047
- }
1048
- }
1049
- };
1189
+ init_store();
1050
1190
  }
1051
1191
  });
1052
1192
 
1053
- // src/agent/tools/list-files.ts
1054
- var list_files_exports = {};
1055
- __export(list_files_exports, {
1056
- definition: () => definition6,
1057
- execute: () => execute6
1058
- });
1059
- import { execSync as execSync3 } from "child_process";
1060
- async function execute6(args) {
1061
- const path = args.path || ".";
1062
- const pattern = args.pattern;
1063
- try {
1064
- let cmd;
1065
- if (pattern) {
1066
- cmd = `find "${path}" -name "${pattern}" -type f | head -100`;
1067
- } else {
1068
- cmd = `ls -la "${path}"`;
1069
- }
1070
- const output = execSync3(cmd, {
1071
- encoding: "utf-8",
1072
- timeout: 1e4,
1073
- stdio: ["pipe", "pipe", "pipe"]
1074
- });
1075
- return output || "(empty)";
1076
- } catch (err) {
1077
- return `Error: ${err.message}`;
1078
- }
1193
+ // src/index.ts
1194
+ import { Command } from "commander";
1195
+ import chalk15 from "chalk";
1196
+
1197
+ // src/commands/config.ts
1198
+ init_store();
1199
+ init_client();
1200
+ init_format();
1201
+ import chalk2 from "chalk";
1202
+ function registerConfigCommand(program2) {
1203
+ const config = program2.command("config").description("XGEN CLI \uC124\uC815 \uAD00\uB9AC");
1204
+ config.command("set-server <url>").description("XGEN \uC11C\uBC84 URL \uC124\uC815").action((url) => {
1205
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
1206
+ printError("URL\uC740 http:// \uB610\uB294 https://\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4");
1207
+ process.exit(1);
1208
+ }
1209
+ setServer(url);
1210
+ resetClient();
1211
+ printSuccess(`\uC11C\uBC84 \uC124\uC815 \uC644\uB8CC: ${chalk2.underline(url)}`);
1212
+ });
1213
+ config.command("get-server").description("\uD604\uC7AC \uC124\uC815\uB41C \uC11C\uBC84 URL \uD655\uC778").action(() => {
1214
+ const server = getServer();
1215
+ if (server) {
1216
+ console.log(server);
1217
+ } else {
1218
+ printError("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
1219
+ console.log(" \uC124\uC815: xgen config set-server <url>");
1220
+ }
1221
+ });
1222
+ config.command("list").description("\uC804\uCCB4 \uC124\uC815 \uD655\uC778").action(() => {
1223
+ const cfg = getConfig();
1224
+ console.log(chalk2.bold("\nXGEN CLI \uC124\uC815"));
1225
+ console.log(chalk2.gray("\u2500".repeat(40)));
1226
+ printKeyValue("\uC11C\uBC84", cfg.server);
1227
+ printKeyValue("\uAE30\uBCF8 \uC6CC\uD06C\uD50C\uB85C\uC6B0", cfg.defaultWorkflow);
1228
+ printKeyValue("\uD14C\uB9C8", cfg.theme);
1229
+ printKeyValue("\uC2A4\uD2B8\uB9BC \uB85C\uADF8", String(cfg.streamLogs));
1230
+ console.log();
1231
+ });
1232
+ config.command("set <key> <value>").description("\uC124\uC815 \uAC12 \uBCC0\uACBD").action((key, value) => {
1233
+ const allowedKeys = ["defaultWorkflow", "theme", "streamLogs"];
1234
+ if (!allowedKeys.includes(key)) {
1235
+ printError(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}`);
1236
+ console.log(` \uC0AC\uC6A9 \uAC00\uB2A5: ${allowedKeys.join(", ")}`);
1237
+ process.exit(1);
1238
+ }
1239
+ const parsed = key === "streamLogs" ? value === "true" : value;
1240
+ setConfig({ [key]: parsed });
1241
+ printSuccess(`${key} = ${value}`);
1242
+ });
1079
1243
  }
1080
- var definition6;
1081
- var init_list_files = __esm({
1082
- "src/agent/tools/list-files.ts"() {
1083
- "use strict";
1084
- definition6 = {
1085
- type: "function",
1086
- function: {
1087
- name: "list_files",
1088
- description: "\uB514\uB809\uD1A0\uB9AC\uC758 \uD30C\uC77C/\uD3F4\uB354 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. glob \uD328\uD134 \uC9C0\uC6D0.",
1089
- parameters: {
1090
- type: "object",
1091
- properties: {
1092
- path: { type: "string", description: "\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8: .)" },
1093
- pattern: { type: "string", description: "glob \uD328\uD134 (\uC608: **/*.ts)" }
1244
+
1245
+ // src/commands/login.ts
1246
+ init_auth();
1247
+ init_store();
1248
+ init_format();
1249
+ import chalk3 from "chalk";
1250
+ import { createInterface } from "readline";
1251
+ function prompt(question, hidden = false) {
1252
+ return new Promise((resolve) => {
1253
+ const rl = createInterface({
1254
+ input: process.stdin,
1255
+ output: process.stdout
1256
+ });
1257
+ if (hidden) {
1258
+ process.stdout.write(question);
1259
+ const stdin = process.stdin;
1260
+ const wasRaw = stdin.isRaw;
1261
+ if (stdin.isTTY) stdin.setRawMode(true);
1262
+ let password = "";
1263
+ const onData = (ch) => {
1264
+ const c = ch.toString("utf8");
1265
+ if (c === "\n" || c === "\r" || c === "") {
1266
+ if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
1267
+ stdin.removeListener("data", onData);
1268
+ process.stdout.write("\n");
1269
+ rl.close();
1270
+ resolve(password);
1271
+ } else if (c === "") {
1272
+ process.exit(0);
1273
+ } else if (c === "\x7F" || c === "\b") {
1274
+ if (password.length > 0) {
1275
+ password = password.slice(0, -1);
1276
+ process.stdout.write("\b \b");
1094
1277
  }
1278
+ } else {
1279
+ password += c;
1280
+ process.stdout.write("*");
1095
1281
  }
1096
- }
1097
- };
1098
- }
1099
- });
1100
-
1101
- // src/agent/tools/sandbox.ts
1102
- var sandbox_exports = {};
1103
- __export(sandbox_exports, {
1104
- definition: () => definition7,
1105
- execute: () => execute7
1106
- });
1107
- import { execSync as execSync4 } from "child_process";
1108
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync2, rmSync } from "fs";
1109
- import { join as join2 } from "path";
1110
- import { tmpdir } from "os";
1111
- function ensureSandbox() {
1112
- if (!existsSync2(SANDBOX_DIR)) {
1113
- mkdirSync3(SANDBOX_DIR, { recursive: true });
1114
- }
1115
- return SANDBOX_DIR;
1282
+ };
1283
+ stdin.on("data", onData);
1284
+ } else {
1285
+ rl.question(question, (answer) => {
1286
+ rl.close();
1287
+ resolve(answer.trim());
1288
+ });
1289
+ }
1290
+ });
1116
1291
  }
1117
- async function execute7(args) {
1118
- const language = args.language;
1119
- const code = args.code;
1120
- const packages = args.packages ?? [];
1121
- const dir = ensureSandbox();
1122
- const runId = `run_${Date.now()}`;
1123
- const runDir = join2(dir, runId);
1124
- mkdirSync3(runDir, { recursive: true });
1125
- try {
1126
- if (packages.length > 0) {
1127
- if (language === "python") {
1128
- const pkgList = packages.join(" ");
1129
- execSync4(`pip install ${pkgList}`, {
1130
- cwd: runDir,
1131
- encoding: "utf-8",
1132
- timeout: 6e4,
1133
- stdio: ["pipe", "pipe", "pipe"]
1292
+ function registerLoginCommand(program2) {
1293
+ program2.command("login").description("XGEN \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC778").option("-e, --email <email>", "\uC774\uBA54\uC77C").option("-p, --password <password>", "\uBE44\uBC00\uBC88\uD638").action(async (opts) => {
1294
+ const server = requireServer();
1295
+ printHeader("XGEN Login");
1296
+ console.log(chalk3.gray(`\uC11C\uBC84: ${server}
1297
+ `));
1298
+ let email = opts.email;
1299
+ let password = opts.password;
1300
+ if (!email) {
1301
+ email = await prompt(chalk3.white("\uC774\uBA54\uC77C: "));
1302
+ }
1303
+ if (!password) {
1304
+ password = await prompt(chalk3.white("\uBE44\uBC00\uBC88\uD638: "), true);
1305
+ }
1306
+ if (!email || !password) {
1307
+ printError("\uC774\uBA54\uC77C\uACFC \uBE44\uBC00\uBC88\uD638\uB97C \uBAA8\uB450 \uC785\uB825\uD558\uC138\uC694");
1308
+ process.exit(1);
1309
+ }
1310
+ try {
1311
+ const result = await apiLogin(email, password);
1312
+ if (result.success && result.access_token) {
1313
+ setAuth({
1314
+ accessToken: result.access_token,
1315
+ refreshToken: result.refresh_token ?? "",
1316
+ userId: result.user_id ?? "",
1317
+ username: result.username ?? "",
1318
+ isAdmin: false,
1319
+ expiresAt: null
1134
1320
  });
1321
+ console.log();
1322
+ printSuccess(`\uB85C\uADF8\uC778 \uC131\uACF5! ${chalk3.bold(result.username ?? email)}`);
1135
1323
  } else {
1136
- execSync4("npm init -y", { cwd: runDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
1137
- const pkgList = packages.join(" ");
1138
- execSync4(`npm install ${pkgList}`, {
1139
- cwd: runDir,
1140
- encoding: "utf-8",
1141
- timeout: 6e4,
1142
- stdio: ["pipe", "pipe", "pipe"]
1143
- });
1324
+ printError(result.message || "\uB85C\uADF8\uC778 \uC2E4\uD328");
1325
+ process.exit(1);
1144
1326
  }
1327
+ } catch (err) {
1328
+ const msg = err?.response?.data?.message ?? err?.response?.data?.detail ?? err.message;
1329
+ printError(`\uB85C\uADF8\uC778 \uC2E4\uD328: ${msg}`);
1330
+ process.exit(1);
1145
1331
  }
1146
- let cmd;
1147
- let filename;
1148
- if (language === "python") {
1149
- filename = "script.py";
1150
- writeFileSync4(join2(runDir, filename), code, "utf-8");
1151
- cmd = `python3 ${filename}`;
1152
- } else if (language === "typescript") {
1153
- filename = "script.ts";
1154
- writeFileSync4(join2(runDir, filename), code, "utf-8");
1155
- cmd = `npx tsx ${filename}`;
1156
- } else {
1157
- filename = "script.mjs";
1158
- writeFileSync4(join2(runDir, filename), code, "utf-8");
1159
- cmd = `node ${filename}`;
1332
+ });
1333
+ program2.command("logout").description("\uB85C\uADF8\uC544\uC6C3").action(async () => {
1334
+ const { clearAuth: clearAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1335
+ clearAuth2();
1336
+ printSuccess("\uB85C\uADF8\uC544\uC6C3 \uC644\uB8CC");
1337
+ });
1338
+ program2.command("whoami").description("\uD604\uC7AC \uB85C\uADF8\uC778\uB41C \uC0AC\uC6A9\uC790 \uC815\uBCF4").action(async () => {
1339
+ const auth = getAuth();
1340
+ if (!auth) {
1341
+ printError("\uB85C\uADF8\uC778\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. xgen login \uC2E4\uD589\uD558\uC138\uC694");
1342
+ process.exit(1);
1160
1343
  }
1161
- const output = execSync4(cmd, {
1162
- cwd: runDir,
1163
- encoding: "utf-8",
1164
- timeout: 3e4,
1165
- maxBuffer: 1024 * 1024,
1166
- stdio: ["pipe", "pipe", "pipe"]
1167
- });
1168
- return output || "(no output)";
1169
- } catch (err) {
1170
- const e = err;
1171
- return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
1172
- } finally {
1344
+ const server = requireServer();
1345
+ console.log(chalk3.bold("\n\uD604\uC7AC \uC0AC\uC6A9\uC790"));
1346
+ console.log(chalk3.gray("\u2500".repeat(30)));
1347
+ console.log(` ${chalk3.gray("\uC11C\uBC84:")} ${server}`);
1348
+ console.log(` ${chalk3.gray("\uC0AC\uC6A9\uC790:")} ${chalk3.bold(auth.username)}`);
1349
+ console.log(` ${chalk3.gray("User ID:")} ${auth.userId}`);
1173
1350
  try {
1174
- rmSync(runDir, { recursive: true, force: true });
1351
+ const { apiValidate: apiValidate2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
1352
+ const result = await apiValidate2(auth.accessToken);
1353
+ if (result.valid) {
1354
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.green("\uD65C\uC131")}`);
1355
+ if (result.is_admin) {
1356
+ console.log(` ${chalk3.gray("\uAD8C\uD55C:")} ${chalk3.yellow("\uAD00\uB9AC\uC790")}`);
1357
+ }
1358
+ if (result.user_type) {
1359
+ console.log(` ${chalk3.gray("\uC720\uD615:")} ${result.user_type}`);
1360
+ }
1361
+ } else {
1362
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.red("\uD1A0\uD070 \uB9CC\uB8CC")}`);
1363
+ }
1175
1364
  } catch {
1365
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.yellow("\uAC80\uC99D \uBD88\uAC00 (\uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328)")}`);
1176
1366
  }
1177
- }
1367
+ console.log();
1368
+ });
1178
1369
  }
1179
- var SANDBOX_DIR, definition7;
1180
- var init_sandbox = __esm({
1181
- "src/agent/tools/sandbox.ts"() {
1182
- "use strict";
1183
- SANDBOX_DIR = join2(tmpdir(), "xgen-sandbox");
1184
- definition7 = {
1185
- type: "function",
1186
- function: {
1187
- name: "sandbox_run",
1188
- description: "\uACA9\uB9AC\uB41C \uC0CC\uB4DC\uBC15\uC2A4\uC5D0\uC11C \uCF54\uB4DC\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. Node.js \uB610\uB294 Python \uCF54\uB4DC\uB97C \uC548\uC804\uD558\uAC8C \uC2E4\uD589\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. npm \uD328\uD0A4\uC9C0 \uC124\uCE58\uB3C4 \uAC00\uB2A5\uD569\uB2C8\uB2E4.",
1189
- parameters: {
1190
- type: "object",
1191
- properties: {
1192
- language: {
1193
- type: "string",
1194
- enum: ["javascript", "typescript", "python"],
1195
- description: "\uC2E4\uD589\uD560 \uC5B8\uC5B4"
1196
- },
1197
- code: { type: "string", description: "\uC2E4\uD589\uD560 \uCF54\uB4DC" },
1198
- packages: {
1199
- type: "array",
1200
- items: { type: "string" },
1201
- description: "\uC124\uCE58\uD560 \uD328\uD0A4\uC9C0 (npm \uB610\uB294 pip)"
1202
- }
1203
- },
1204
- required: ["language", "code"]
1205
- }
1206
- }
1207
- };
1208
- }
1209
- });
1210
1370
 
1211
- // src/agent/tools/index.ts
1212
- function getAllToolDefs() {
1213
- return tools.map((t) => t.definition);
1214
- }
1215
- async function executeTool(name, args) {
1216
- const tool = toolMap.get(name);
1217
- if (!tool) return `Unknown tool: ${name}`;
1218
- return tool.execute(args);
1219
- }
1220
- function getToolNames() {
1221
- return tools.map((t) => t.definition.function.name);
1222
- }
1223
- var tools, toolMap;
1224
- var init_tools = __esm({
1225
- "src/agent/tools/index.ts"() {
1226
- "use strict";
1227
- init_file_read();
1228
- init_file_write();
1229
- init_file_edit();
1230
- init_bash();
1231
- init_grep();
1232
- init_list_files();
1233
- init_sandbox();
1234
- tools = [file_read_exports, file_write_exports, file_edit_exports, bash_exports, grep_exports, list_files_exports, sandbox_exports];
1235
- toolMap = /* @__PURE__ */ new Map();
1236
- for (const t of tools) {
1237
- toolMap.set(t.definition.function.name, t);
1238
- }
1239
- }
1240
- });
1241
-
1242
- // src/api/document.ts
1243
- var document_exports = {};
1244
- __export(document_exports, {
1245
- getDocumentInfo: () => getDocumentInfo,
1246
- listCollections: () => listCollections,
1247
- listDocuments: () => listDocuments,
1248
- uploadDocument: () => uploadDocument
1249
- });
1250
- async function listCollections() {
1251
- const client2 = getClient();
1252
- const res = await client2.get("/api/retrieval/collections");
1253
- return Array.isArray(res.data) ? res.data : res.data.collections ?? [];
1254
- }
1255
- async function listDocuments(collectionId) {
1256
- const client2 = getClient();
1371
+ // src/commands/workflow/list.ts
1372
+ init_store();
1373
+ init_workflow();
1374
+ init_format();
1375
+ import chalk4 from "chalk";
1376
+ async function workflowList(opts) {
1377
+ requireAuth();
1257
1378
  try {
1258
- const params = {};
1259
- if (collectionId) params.collection_id = collectionId;
1260
- const res = await client2.get("/api/retrieval/documents/list", { params });
1261
- return res.data.documents ?? res.data ?? [];
1262
- } catch {
1263
- return [];
1379
+ if (opts.detail) {
1380
+ const workflows = await getWorkflowListDetail();
1381
+ if (!workflows || workflows.length === 0) {
1382
+ console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
1383
+ return;
1384
+ }
1385
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
1386
+ console.log();
1387
+ printTable(
1388
+ ["#", "ID", "\uC774\uB984", "\uBC30\uD3EC", "\uC5C5\uB370\uC774\uD2B8"],
1389
+ workflows.map((w, i) => [
1390
+ String(i + 1),
1391
+ (w.workflow_id ?? w.id ?? "-").slice(0, 12),
1392
+ truncate(w.workflow_name ?? "-", 30),
1393
+ w.is_deployed ? chalk4.green("\uBC30\uD3EC\uB428") : chalk4.gray("\uBBF8\uBC30\uD3EC"),
1394
+ formatDate(w.updated_at)
1395
+ ])
1396
+ );
1397
+ } else {
1398
+ const workflows = await listWorkflows();
1399
+ if (!workflows || workflows.length === 0) {
1400
+ console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
1401
+ return;
1402
+ }
1403
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
1404
+ console.log();
1405
+ printTable(
1406
+ ["#", "ID", "\uC774\uB984"],
1407
+ workflows.map((w, i) => [
1408
+ String(i + 1),
1409
+ (w.workflow_id ?? w.id ?? "-").slice(0, 12),
1410
+ w.workflow_name ?? "-"
1411
+ ])
1412
+ );
1413
+ }
1414
+ console.log();
1415
+ } catch (err) {
1416
+ const msg = err.message;
1417
+ printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${msg}`);
1418
+ process.exit(1);
1264
1419
  }
1265
1420
  }
1266
- async function uploadDocument(filePath, collectionId, name) {
1267
- const client2 = getClient();
1268
- const { createReadStream, statSync } = await import("fs");
1269
- const { basename } = await import("path");
1270
- const stat = statSync(filePath);
1271
- const fileName = name || basename(filePath);
1272
- const form = new FormData();
1273
- const fileBlob = new Blob([createReadStream(filePath)]);
1274
- form.append("file", fileBlob, fileName);
1275
- if (collectionId) form.append("collection_id", collectionId);
1276
- const res = await client2.post("/api/retrieval/documents/upload", form, {
1277
- headers: { "Content-Type": "multipart/form-data" },
1278
- maxBodyLength: stat.size + 1024 * 1024
1279
- });
1280
- return res.data;
1281
- }
1282
- async function getDocumentInfo(docId) {
1283
- const client2 = getClient();
1284
- const res = await client2.get(`/api/retrieval/documents/${docId}`);
1285
- return res.data;
1286
- }
1287
- var init_document = __esm({
1288
- "src/api/document.ts"() {
1289
- "use strict";
1290
- init_client();
1291
- }
1292
- });
1293
1421
 
1294
- // src/agent/tools/xgen-api.ts
1295
- async function execute8(name, args) {
1296
- const server = getServer();
1297
- const auth = getAuth();
1298
- if (!server || !auth) {
1299
- return "XGEN \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. /connect \uBA85\uB839\uC73C\uB85C \uC5F0\uACB0\uD558\uC138\uC694.";
1300
- }
1422
+ // src/commands/workflow/info.ts
1423
+ init_store();
1424
+ init_workflow();
1425
+ init_format();
1426
+ import chalk5 from "chalk";
1427
+ async function workflowInfo(workflowId) {
1428
+ requireAuth();
1301
1429
  try {
1302
- switch (name) {
1303
- case "xgen_workflow_list":
1304
- return await workflowList2();
1305
- case "xgen_workflow_run":
1306
- return await workflowRun2(args);
1307
- case "xgen_workflow_info":
1308
- return await workflowInfo2(args);
1309
- case "xgen_collection_list":
1310
- return await collectionList();
1311
- case "xgen_server_status":
1312
- return await serverStatus();
1313
- case "xgen_execution_history":
1314
- return await executionHistory(args);
1315
- default:
1316
- return `Unknown XGEN tool: ${name}`;
1430
+ const detail = await getWorkflowDetail(workflowId);
1431
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name ?? workflowId}`);
1432
+ console.log();
1433
+ printKeyValue("ID", detail.id);
1434
+ printKeyValue("\uC774\uB984", detail.workflow_name);
1435
+ printKeyValue("\uC124\uBA85", detail.description ?? "(\uC5C6\uC74C)");
1436
+ if (detail.nodes && Array.isArray(detail.nodes)) {
1437
+ console.log();
1438
+ console.log(chalk5.bold(" \uB178\uB4DC \uAD6C\uC131:"));
1439
+ for (const node of detail.nodes) {
1440
+ const label = node.data?.label ?? node.id;
1441
+ const type = node.data?.type ?? "unknown";
1442
+ console.log(` ${chalk5.cyan("\u2022")} ${label} ${chalk5.gray(`(${type})`)}`);
1443
+ }
1444
+ }
1445
+ if (detail.parameters && Object.keys(detail.parameters).length > 0) {
1446
+ console.log();
1447
+ console.log(chalk5.bold(" \uD30C\uB77C\uBBF8\uD130:"));
1448
+ for (const [key, val] of Object.entries(detail.parameters)) {
1449
+ console.log(` ${chalk5.gray(key)}: ${JSON.stringify(val)}`);
1450
+ }
1317
1451
  }
1452
+ console.log();
1318
1453
  } catch (err) {
1319
- return `XGEN API \uC624\uB958: ${err.message}`;
1454
+ const msg = err.message;
1455
+ printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC870\uD68C \uC2E4\uD328: ${msg}`);
1456
+ process.exit(1);
1320
1457
  }
1321
1458
  }
1322
- function isXgenTool(name) {
1323
- return name.startsWith("xgen_");
1324
- }
1325
- async function workflowList2() {
1326
- const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1327
- const wfs = await getWorkflowListDetail2();
1328
- if (!wfs.length) return "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC5C6\uC74C.";
1329
- return wfs.map((w, i) => {
1330
- const deployed = w.is_deployed;
1331
- const dk = w.deploy_key;
1332
- const tag = deployed ? " [\uBC30\uD3EC\uB428]" : "";
1333
- return `${i + 1}. ${w.workflow_name}${tag}
1334
- ID: ${w.workflow_id ?? w.id}
1335
- deploy_key: ${dk || "\uC5C6\uC74C"}`;
1336
- }).join("\n");
1337
- }
1338
- async function workflowRun2(args) {
1339
- const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1340
- const { randomUUID: randomUUID4 } = await import("crypto");
1341
- const result = await executeWorkflow2({
1342
- workflow_id: args.workflow_id,
1343
- workflow_name: args.workflow_name,
1344
- input_data: args.input_data,
1345
- interaction_id: `cli_${randomUUID4().slice(0, 8)}`,
1346
- deploy_key: args.deploy_key
1459
+
1460
+ // src/commands/workflow/run.ts
1461
+ init_store();
1462
+ init_workflow();
1463
+ import chalk7 from "chalk";
1464
+ import { randomUUID } from "crypto";
1465
+
1466
+ // src/utils/sse.ts
1467
+ async function parseSSEStream(stream, onEvent, onDone, onError) {
1468
+ let buffer = "";
1469
+ return new Promise((resolve, reject) => {
1470
+ stream.on("data", (chunk) => {
1471
+ buffer += chunk.toString();
1472
+ const parts = buffer.split("\n\n");
1473
+ buffer = parts.pop() ?? "";
1474
+ for (const part of parts) {
1475
+ const lines = part.split("\n");
1476
+ let data = "";
1477
+ for (const line of lines) {
1478
+ if (line.startsWith("data: ")) {
1479
+ data += line.slice(6);
1480
+ } else if (line.startsWith("data:")) {
1481
+ data += line.slice(5);
1482
+ }
1483
+ }
1484
+ if (!data) continue;
1485
+ try {
1486
+ const event = JSON.parse(data);
1487
+ onEvent(event);
1488
+ } catch {
1489
+ onEvent({ type: "token", content: data });
1490
+ }
1491
+ }
1492
+ });
1493
+ stream.on("end", () => {
1494
+ if (buffer.trim()) {
1495
+ const lines = buffer.split("\n");
1496
+ for (const line of lines) {
1497
+ if (line.startsWith("data: ")) {
1498
+ try {
1499
+ const event = JSON.parse(line.slice(6));
1500
+ onEvent(event);
1501
+ } catch {
1502
+ onEvent({ type: "token", content: line.slice(6) });
1503
+ }
1504
+ }
1505
+ }
1506
+ }
1507
+ onDone?.();
1508
+ resolve();
1509
+ });
1510
+ stream.on("error", (err) => {
1511
+ onError?.(err);
1512
+ reject(err);
1513
+ });
1347
1514
  });
1348
- if (result.content) return String(result.content);
1349
- if (result.success === false) return `\uC624\uB958: ${result.error ?? result.message}`;
1350
- return JSON.stringify(result, null, 2).slice(0, 2e3);
1351
- }
1352
- async function workflowInfo2(args) {
1353
- const { getWorkflowDetail: getWorkflowDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1354
- const detail = await getWorkflowDetail2(args.workflow_id);
1355
- const nodes = detail.nodes?.length ?? 0;
1356
- const edges = detail.edges?.length ?? 0;
1357
- return `\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name}
1358
- ID: ${detail.id}
1359
- \uB178\uB4DC: ${nodes}\uAC1C
1360
- \uC5E3\uC9C0: ${edges}\uAC1C`;
1361
1515
  }
1362
- async function collectionList() {
1363
- const { listCollections: listCollections2 } = await Promise.resolve().then(() => (init_document(), document_exports));
1364
- const cols = await listCollections2();
1365
- if (!cols.length) return "\uCEEC\uB809\uC158 \uC5C6\uC74C.";
1366
- return cols.map((c, i) => {
1367
- const shared = c.is_shared ? ` [\uACF5\uC720:${c.share_group}]` : "";
1368
- return `${i + 1}. ${c.collection_make_name}${shared}
1369
- \uBB38\uC11C: ${c.total_documents}\uAC1C \xB7 \uCCAD\uD06C: ${c.total_chunks}\uAC1C \xB7 \uBAA8\uB378: ${c.init_embedding_model ?? "-"}`;
1370
- }).join("\n");
1371
- }
1372
- async function serverStatus() {
1373
- const server = getServer();
1374
- const auth = getAuth();
1375
- return `\uC11C\uBC84: ${server}
1376
- \uC0AC\uC6A9\uC790: ${auth?.username}
1377
- User ID: ${auth?.userId}`;
1378
- }
1379
- async function executionHistory(args) {
1380
- const { getIOLogs: getIOLogs2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1381
- const limit = args.limit || 10;
1382
- const logs = await getIOLogs2(void 0, limit);
1383
- if (!logs.length) return "\uC2E4\uD589 \uC774\uB825 \uC5C6\uC74C.";
1384
- return logs.map(
1385
- (l, i) => `${i + 1}. [${l.created_at ?? ""}]
1386
- \uC785\uB825: ${(l.input_data ?? "").slice(0, 80)}
1387
- \uCD9C\uB825: ${(l.output_data ?? "").slice(0, 80)}`
1388
- ).join("\n");
1516
+
1517
+ // src/commands/workflow/run.ts
1518
+ init_format();
1519
+
1520
+ // src/utils/markdown.ts
1521
+ import chalk6 from "chalk";
1522
+ var CODE_BLOCK_RE = /```(\w*)\n([\s\S]*?)```/g;
1523
+ var INLINE_CODE_RE = /`([^`]+)`/g;
1524
+ var BOLD_RE = /\*\*(.+?)\*\*/g;
1525
+ var HEADING_RE = /^(#{1,3})\s+(.+)$/gm;
1526
+ var LIST_RE = /^(\s*)[-*]\s+(.+)$/gm;
1527
+ var LINK_RE = /\[([^\]]+)\]\(([^)]+)\)/g;
1528
+ function renderMarkdown(text) {
1529
+ let result = text;
1530
+ result = result.replace(CODE_BLOCK_RE, (_match, lang, code) => {
1531
+ const trimmed = code.trimEnd();
1532
+ const header = lang ? chalk6.gray(` \u2500\u2500 ${lang} \u2500\u2500`) : chalk6.gray(" \u2500\u2500 code \u2500\u2500");
1533
+ const lines = trimmed.split("\n").map((l) => chalk6.white(` ${l}`)).join("\n");
1534
+ return `
1535
+ ${header}
1536
+ ${lines}
1537
+ ${chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
1538
+ `;
1539
+ });
1540
+ result = result.replace(INLINE_CODE_RE, (_m, code) => chalk6.cyan(`\`${code}\``));
1541
+ result = result.replace(BOLD_RE, (_m, text2) => chalk6.bold(text2));
1542
+ result = result.replace(HEADING_RE, (_m, hashes, text2) => {
1543
+ if (hashes.length === 1) return chalk6.bold.underline(text2);
1544
+ if (hashes.length === 2) return chalk6.bold(text2);
1545
+ return chalk6.bold.dim(text2);
1546
+ });
1547
+ result = result.replace(LIST_RE, (_m, indent, text2) => `${indent}${chalk6.cyan("\u2022")} ${text2}`);
1548
+ result = result.replace(LINK_RE, (_m, label, url) => `${chalk6.blue.underline(label)} ${chalk6.gray(`(${url})`)}`);
1549
+ return result;
1389
1550
  }
1390
- var definitions;
1391
- var init_xgen_api = __esm({
1392
- "src/agent/tools/xgen-api.ts"() {
1393
- "use strict";
1394
- init_store();
1395
- definitions = [
1396
- {
1397
- type: "function",
1398
- function: {
1399
- name: "xgen_workflow_list",
1400
- description: "XGEN \uC11C\uBC84\uC5D0\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
1401
- parameters: { type: "object", properties: {} }
1402
- }
1403
- },
1404
- {
1405
- type: "function",
1406
- function: {
1407
- name: "xgen_workflow_run",
1408
- description: "XGEN \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. \uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB9CC \uC2E4\uD589 \uAC00\uB2A5.",
1409
- parameters: {
1410
- type: "object",
1411
- properties: {
1412
- workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" },
1413
- workflow_name: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984" },
1414
- input_data: { type: "string", description: "\uC785\uB825 \uBA54\uC2DC\uC9C0" },
1415
- deploy_key: { type: "string", description: "\uBC30\uD3EC \uD0A4 (\uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0)" }
1416
- },
1417
- required: ["workflow_id", "workflow_name", "input_data"]
1418
- }
1551
+
1552
+ // src/commands/workflow/run.ts
1553
+ async function workflowRun(workflowId, input, opts) {
1554
+ const auth = requireAuth();
1555
+ let workflowName = workflowId;
1556
+ try {
1557
+ const detail = await getWorkflowDetail(workflowId);
1558
+ workflowName = detail.workflow_name ?? workflowId;
1559
+ } catch {
1560
+ }
1561
+ if (!input) {
1562
+ if (opts.interactive || !process.stdin.isTTY) {
1563
+ const { createInterface: createInterface7 } = await import("readline");
1564
+ const rl = createInterface7({ input: process.stdin, output: process.stdout });
1565
+ input = await new Promise((resolve) => {
1566
+ rl.question(chalk7.cyan("\uC785\uB825> "), (answer) => {
1567
+ rl.close();
1568
+ resolve(answer.trim());
1569
+ });
1570
+ });
1571
+ } else {
1572
+ printError("\uC785\uB825\uAC12\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uBC95:");
1573
+ console.log(' xgen workflow run <id> "\uC785\uB825 \uD14D\uC2A4\uFFFD\uFFFD\uFFFD"');
1574
+ console.log(" xgen workflow run -i <id>");
1575
+ process.exit(1);
1576
+ }
1577
+ }
1578
+ if (!input) {
1579
+ printError("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4");
1580
+ process.exit(1);
1581
+ }
1582
+ const interactionId = `cli_${randomUUID().slice(0, 8)}`;
1583
+ printHeader(`\uC2E4\uD589: ${workflowName}`);
1584
+ printInfo(`\uC785\uB825: ${input}`);
1585
+ console.log();
1586
+ try {
1587
+ const stream = await executeWorkflowStream({
1588
+ workflow_id: workflowId,
1589
+ workflow_name: workflowName,
1590
+ input_data: input,
1591
+ interaction_id: interactionId
1592
+ });
1593
+ let hasOutput = false;
1594
+ let fullResponse = "";
1595
+ await parseSSEStream(
1596
+ stream,
1597
+ (event) => {
1598
+ switch (event.type) {
1599
+ case "token":
1600
+ if (event.content) {
1601
+ if (!hasOutput) {
1602
+ hasOutput = true;
1603
+ console.log();
1604
+ }
1605
+ process.stdout.write(event.content);
1606
+ fullResponse += event.content;
1607
+ }
1608
+ break;
1609
+ case "log":
1610
+ if (opts.logs && event.content) {
1611
+ process.stderr.write(chalk7.gray(`[LOG] ${event.content}
1612
+ `));
1613
+ }
1614
+ break;
1615
+ case "node_status":
1616
+ if (opts.logs) {
1617
+ const nodeName = event.node_name ?? event.node_id ?? "?";
1618
+ const status = event.status ?? "?";
1619
+ process.stderr.write(
1620
+ chalk7.gray(`[\uB178\uB4DC] ${nodeName}: ${status}
1621
+ `)
1622
+ );
1623
+ }
1624
+ break;
1625
+ case "tool":
1626
+ if (opts.logs) {
1627
+ process.stderr.write(chalk7.gray(`[\uB3C4\uAD6C] ${JSON.stringify(event.data)}
1628
+ `));
1629
+ }
1630
+ break;
1631
+ case "complete":
1632
+ break;
1633
+ case "error":
1634
+ console.log();
1635
+ printError(event.error ?? event.content ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958");
1636
+ break;
1637
+ default:
1638
+ if (event.content) {
1639
+ if (!hasOutput) {
1640
+ process.stdout.write(chalk7.green("\uC751\uB2F5: "));
1641
+ hasOutput = true;
1642
+ }
1643
+ process.stdout.write(event.content);
1644
+ }
1419
1645
  }
1420
1646
  },
1421
- {
1422
- type: "function",
1423
- function: {
1424
- name: "xgen_workflow_info",
1425
- description: "\uD2B9\uC815 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uC0C1\uC138 \uC815\uBCF4(\uB178\uB4DC, \uC5E3\uC9C0 \uB4F1)\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4.",
1426
- parameters: {
1427
- type: "object",
1428
- properties: {
1429
- workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" }
1430
- },
1431
- required: ["workflow_id"]
1647
+ () => {
1648
+ if (hasOutput) {
1649
+ console.log();
1650
+ if (fullResponse.includes("```") || fullResponse.includes("**")) {
1651
+ console.log(chalk7.gray("\u2500".repeat(40)));
1652
+ console.log(renderMarkdown(fullResponse));
1432
1653
  }
1433
1654
  }
1655
+ console.log();
1656
+ console.log(chalk7.gray(`\uC138\uC158: ${interactionId}`));
1434
1657
  },
1435
- {
1436
- type: "function",
1437
- function: {
1438
- name: "xgen_collection_list",
1439
- description: "XGEN \uC11C\uBC84\uC758 \uBB38\uC11C \uCEEC\uB809\uC158(\uC9C0\uC2DD\uBCA0\uC774\uC2A4) \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4. \uBB38\uC11C \uC218, \uCCAD\uD06C \uC218, \uACF5\uC720 \uC0C1\uD0DC \uB4F1 \uD3EC\uD568.",
1440
- parameters: { type: "object", properties: {} }
1441
- }
1442
- },
1443
- {
1444
- type: "function",
1445
- function: {
1446
- name: "xgen_server_status",
1447
- description: "XGEN \uC11C\uBC84 \uC0C1\uD0DC\uB97C \uD655\uC778\uD569\uB2C8\uB2E4.",
1448
- parameters: { type: "object", properties: {} }
1449
- }
1450
- },
1451
- {
1452
- type: "function",
1453
- function: {
1454
- name: "xgen_execution_history",
1455
- description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589 \uC774\uB825\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
1456
- parameters: {
1457
- type: "object",
1458
- properties: {
1459
- limit: { type: "number", description: "\uAC00\uC838\uC62C \uC774\uB825 \uC218 (\uAE30\uBCF8 10)" }
1460
- }
1461
- }
1462
- }
1658
+ (err) => {
1659
+ console.log();
1660
+ printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
1463
1661
  }
1464
- ];
1662
+ );
1663
+ } catch (err) {
1664
+ const msg = err?.response?.data?.detail ?? err.message;
1665
+ printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
1666
+ process.exit(1);
1465
1667
  }
1466
- });
1668
+ }
1467
1669
 
1468
- // src/mcp/client.ts
1469
- import { spawn } from "child_process";
1470
- import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
1471
- import { join as join3 } from "path";
1472
- import { createInterface as createInterface4 } from "readline";
1473
- function loadMcpConfig(dir) {
1474
- const searchPaths = [
1475
- dir ? join3(dir, ".mcp.json") : null,
1476
- join3(process.cwd(), ".mcp.json"),
1477
- join3(process.env.HOME ?? "", ".mcp.json")
1478
- ].filter(Boolean);
1479
- for (const p of searchPaths) {
1480
- if (existsSync3(p)) {
1481
- try {
1482
- return JSON.parse(readFileSync4(p, "utf-8"));
1483
- } catch {
1484
- continue;
1670
+ // src/commands/workflow/history.ts
1671
+ init_store();
1672
+ init_workflow();
1673
+ init_format();
1674
+ import chalk8 from "chalk";
1675
+ async function workflowHistory(workflowId, opts = {}) {
1676
+ requireAuth();
1677
+ const limit = opts.limit ?? 20;
1678
+ try {
1679
+ const logs = await getIOLogs(workflowId, limit);
1680
+ if (!logs || logs.length === 0) {
1681
+ console.log(chalk8.yellow("\n\uC2E4\uD589 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
1682
+ return;
1683
+ }
1684
+ printHeader(`\uC2E4\uD589 \uC774\uB825 (\uCD5C\uADFC ${logs.length}\uAC74)`);
1685
+ console.log();
1686
+ for (const log of logs) {
1687
+ console.log(
1688
+ ` ${chalk8.gray(formatDate(log.created_at))} ${chalk8.cyan(log.interaction_id)}`
1689
+ );
1690
+ console.log(` ${chalk8.white("\uC785\uB825:")} ${truncate(log.input_data, 60)}`);
1691
+ console.log(
1692
+ ` ${chalk8.green("\uCD9C\uB825:")} ${truncate(log.output_data, 60)}`
1693
+ );
1694
+ if (log.execution_time) {
1695
+ console.log(
1696
+ ` ${chalk8.gray("\uC2DC\uAC04:")} ${(log.execution_time / 1e3).toFixed(1)}s`
1697
+ );
1485
1698
  }
1699
+ console.log();
1486
1700
  }
1701
+ } catch (err) {
1702
+ const msg = err.message;
1703
+ printError(`\uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
1704
+ process.exit(1);
1487
1705
  }
1488
- return null;
1489
1706
  }
1490
- var McpClient, McpManager;
1491
- var init_client2 = __esm({
1492
- "src/mcp/client.ts"() {
1493
- "use strict";
1494
- McpClient = class {
1495
- process = null;
1496
- requestId = 0;
1497
- pending = /* @__PURE__ */ new Map();
1498
- serverName;
1499
- config;
1500
- tools = [];
1501
- constructor(serverName, config) {
1502
- this.serverName = serverName;
1503
- this.config = config;
1504
- }
1505
- async start() {
1506
- this.process = spawn(this.config.command, this.config.args ?? [], {
1507
- stdio: ["pipe", "pipe", "pipe"],
1508
- env: { ...process.env, ...this.config.env }
1509
- });
1510
- const rl = createInterface4({ input: this.process.stdout });
1511
- rl.on("line", (line) => {
1512
- try {
1513
- const msg = JSON.parse(line);
1514
- if (msg.id !== void 0 && this.pending.has(msg.id)) {
1515
- const p = this.pending.get(msg.id);
1516
- this.pending.delete(msg.id);
1517
- if (msg.error) {
1518
- p.reject(new Error(msg.error.message));
1519
- } else {
1520
- p.resolve(msg.result);
1521
- }
1522
- }
1523
- } catch {
1524
- }
1525
- });
1526
- this.process.on("error", (err) => {
1527
- console.error(`MCP [${this.serverName}] \uD504\uB85C\uC138\uC2A4 \uC624\uB958:`, err.message);
1528
- });
1529
- await this.send("initialize", {
1530
- protocolVersion: "2024-11-05",
1531
- capabilities: {},
1532
- clientInfo: { name: "open-xgen", version: "0.3.0" }
1533
- });
1534
- await this.send("notifications/initialized", {});
1535
- }
1536
- send(method, params) {
1537
- return new Promise((resolve, reject) => {
1538
- const id = ++this.requestId;
1539
- const request = { jsonrpc: "2.0", id, method, params };
1540
- this.pending.set(id, { resolve, reject });
1541
- const timeout = setTimeout(() => {
1542
- this.pending.delete(id);
1543
- reject(new Error(`MCP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3: ${method}`));
1544
- }, 15e3);
1545
- this.pending.set(id, {
1546
- resolve: (v) => {
1547
- clearTimeout(timeout);
1548
- resolve(v);
1549
- },
1550
- reject: (e) => {
1551
- clearTimeout(timeout);
1552
- reject(e);
1553
- }
1707
+
1708
+ // src/commands/workflow/index.ts
1709
+ function registerWorkflowCommand(program2) {
1710
+ const wf = program2.command("workflow").alias("wf").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAD00\uB9AC \uBC0F \uC2E4\uD589");
1711
+ wf.command("list").alias("ls").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C").option("-d, --detail", "\uC0C1\uC138 \uC815\uBCF4 \uD3EC\uD568").action((opts) => workflowList(opts));
1712
+ wf.command("info <workflow-id>").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uC138 \uC815\uBCF4").action((id) => workflowInfo(id));
1713
+ wf.command("run <workflow-id> [input]").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589").option("-i, --interactive", "\uC778\uD130\uB799\uD2F0\uBE0C \uBAA8\uB4DC (\uC785\uB825 \uD504\uB86C\uD504\uD2B8)").option("-l, --logs", "\uB514\uBC84\uADF8 \uB85C\uADF8 \uD45C\uC2DC").action((id, input, opts) => workflowRun(id, input, opts));
1714
+ wf.command("history [workflow-id]").description("\uC2E4\uD589 \uC774\uB825 \uC870\uD68C").option("-n, --limit <number>", "\uC870\uD68C \uAC74\uC218", "20").action((id, opts) => workflowHistory(id, { limit: parseInt(opts.limit) }));
1715
+ }
1716
+
1717
+ // src/commands/chat.ts
1718
+ init_store();
1719
+ init_workflow();
1720
+ import chalk9 from "chalk";
1721
+ import { createInterface as createInterface2 } from "readline";
1722
+ import { randomUUID as randomUUID2 } from "crypto";
1723
+ init_format();
1724
+ var CHAT_BANNER = `
1725
+ ${chalk9.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")}
1726
+ ${chalk9.cyan("\u2502")} ${chalk9.white.bold("XGEN")} ${chalk9.gray("\u2014 \uC6CC\uD06C\uD50C\uB85C\uC6B0 AI \uD130\uBBF8\uB110")} ${chalk9.cyan("\u2502")}
1727
+ ${chalk9.cyan("\u2502")} ${chalk9.gray("/help \uB3C4\uC6C0\uB9D0 /workflows \uC804\uD658 /exit")} ${chalk9.cyan("\u2502")}
1728
+ ${chalk9.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")}`;
1729
+ function printHelp() {
1730
+ console.log(`
1731
+ ${chalk9.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
1732
+ ${chalk9.cyan("/workflows")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uAE30 & \uC804\uD658
1733
+ ${chalk9.cyan("/switch")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBC88\uD638\uB85C \uC804\uD658 (\uC608: /switch 3)
1734
+ ${chalk9.cyan("/history")} \uD604\uC7AC \uC138\uC158 \uB300\uD654 \uC774\uB825
1735
+ ${chalk9.cyan("/clear")} \uD654\uBA74 \uC9C0\uC6B0\uAE30
1736
+ ${chalk9.cyan("/info")} \uD604\uC7AC \uC5F0\uACB0 \uC815\uBCF4
1737
+ ${chalk9.cyan("/help")} \uC774 \uB3C4\uC6C0\uB9D0
1738
+ ${chalk9.cyan("/exit")} \uC885\uB8CC (Ctrl+C\uB3C4 \uAC00\uB2A5)
1739
+ `);
1740
+ }
1741
+ async function promptLine(rl, promptStr) {
1742
+ return new Promise((resolve) => {
1743
+ rl.question(promptStr, (answer) => resolve(answer));
1744
+ });
1745
+ }
1746
+ async function chat(workflowId) {
1747
+ const auth = requireAuth();
1748
+ const server = getServer();
1749
+ let workflows = [];
1750
+ try {
1751
+ workflows = await listWorkflows();
1752
+ } catch {
1753
+ printError("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
1754
+ process.exit(1);
1755
+ }
1756
+ if (workflows.length === 0) {
1757
+ printError("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4");
1758
+ process.exit(1);
1759
+ }
1760
+ let current;
1761
+ if (workflowId) {
1762
+ const found = workflows.find((w) => w.id === workflowId || w.workflow_name === workflowId);
1763
+ current = found ?? { id: workflowId, workflow_name: workflowId };
1764
+ } else {
1765
+ console.log(CHAT_BANNER);
1766
+ console.log(chalk9.gray(` \uC11C\uBC84: ${server} | \uC0AC\uC6A9\uC790: ${auth.username}
1767
+ `));
1768
+ console.log(chalk9.bold(" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC120\uD0DD:\n"));
1769
+ workflows.forEach((w, i) => {
1770
+ console.log(` ${chalk9.cyan(String(i + 1).padStart(3))} ${w.workflow_name}`);
1771
+ });
1772
+ console.log();
1773
+ const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
1774
+ const answer = await promptLine(rl2, chalk9.cyan(" \uBC88\uD638> "));
1775
+ rl2.close();
1776
+ const idx = parseInt(answer.trim()) - 1;
1777
+ if (isNaN(idx) || idx < 0 || idx >= workflows.length) {
1778
+ current = workflows[0];
1779
+ } else {
1780
+ current = workflows[idx];
1781
+ }
1782
+ }
1783
+ const sessionId = randomUUID2().slice(0, 8);
1784
+ let turnCount = 0;
1785
+ const history = [];
1786
+ console.log();
1787
+ console.log(chalk9.cyan("\u2500".repeat(42)));
1788
+ console.log(chalk9.white.bold(` ${current.workflow_name}`));
1789
+ console.log(chalk9.cyan("\u2500".repeat(42)));
1790
+ console.log(chalk9.gray(" \uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694. /help \uB85C \uB3C4\uC6C0\uB9D0.\n"));
1791
+ const rl = createInterface2({
1792
+ input: process.stdin,
1793
+ output: process.stdout
1794
+ });
1795
+ const getPrompt = () => chalk9.cyan("\u276F ");
1796
+ const processInput = async (line) => {
1797
+ const input = line.trim();
1798
+ if (!input) return;
1799
+ if (input.startsWith("/")) {
1800
+ const [cmd, ...args] = input.slice(1).split(" ");
1801
+ switch (cmd.toLowerCase()) {
1802
+ case "exit":
1803
+ case "quit":
1804
+ case "q":
1805
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
1806
+ rl.close();
1807
+ process.exit(0);
1808
+ break;
1809
+ case "help":
1810
+ case "h":
1811
+ printHelp();
1812
+ break;
1813
+ case "clear":
1814
+ case "cls":
1815
+ console.clear();
1816
+ console.log(chalk9.white.bold(` ${current.workflow_name}`));
1817
+ console.log(chalk9.cyan("\u2500".repeat(42)));
1818
+ break;
1819
+ case "workflows":
1820
+ case "wf":
1821
+ console.log();
1822
+ workflows.forEach((w, i) => {
1823
+ const marker = w.id === current.id ? chalk9.green("\u25B8") : " ";
1824
+ console.log(` ${marker} ${chalk9.cyan(String(i + 1).padStart(2))} ${w.workflow_name}`);
1554
1825
  });
1555
- this.process?.stdin?.write(JSON.stringify(request) + "\n");
1556
- });
1557
- }
1558
- async listTools() {
1559
- const result = await this.send("tools/list", {});
1560
- this.tools = result.tools ?? [];
1561
- return this.tools;
1562
- }
1563
- async callTool(name, args) {
1564
- const result = await this.send("tools/call", { name, arguments: args });
1565
- return result.content?.map((c) => c.text ?? "").join("\n") ?? "";
1566
- }
1567
- getOpenAITools() {
1568
- return this.tools.map((t) => ({
1569
- type: "function",
1570
- function: {
1571
- name: `mcp_${this.serverName}_${t.name}`,
1572
- description: `[MCP:${this.serverName}] ${t.description ?? t.name}`,
1573
- parameters: t.inputSchema ?? { type: "object", properties: {} }
1574
- }
1575
- }));
1576
- }
1577
- stop() {
1578
- this.process?.kill();
1579
- this.process = null;
1580
- }
1581
- };
1582
- McpManager = class {
1583
- clients = /* @__PURE__ */ new Map();
1584
- async startAll(config) {
1585
- for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
1586
- if (serverConfig.type !== "stdio") continue;
1587
- try {
1588
- const client2 = new McpClient(name, serverConfig);
1589
- await client2.start();
1590
- await client2.listTools();
1591
- this.clients.set(name, client2);
1592
- } catch (err) {
1593
- console.error(`MCP [${name}] \uC2DC\uC791 \uC2E4\uD328:`, err.message);
1826
+ console.log(chalk9.gray("\n /switch <\uBC88\uD638> \uB85C \uC804\uD658\n"));
1827
+ break;
1828
+ case "switch":
1829
+ case "sw": {
1830
+ const num = parseInt(args[0]);
1831
+ if (isNaN(num) || num < 1 || num > workflows.length) {
1832
+ console.log(chalk9.yellow(` 1~${workflows.length} \uC0AC\uC774 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694`));
1833
+ } else {
1834
+ current = workflows[num - 1];
1835
+ turnCount = 0;
1836
+ history.length = 0;
1837
+ console.log(chalk9.green(`
1838
+ \uC804\uD658: ${current.workflow_name}
1839
+ `));
1594
1840
  }
1841
+ break;
1595
1842
  }
1843
+ case "history":
1844
+ case "hist":
1845
+ if (history.length === 0) {
1846
+ console.log(chalk9.gray(" \uB300\uD654 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
1847
+ } else {
1848
+ console.log();
1849
+ for (const h of history) {
1850
+ const label = h.role === "user" ? chalk9.cyan("\uB098") : chalk9.green("AI");
1851
+ const text = h.content.length > 80 ? h.content.slice(0, 80) + "..." : h.content;
1852
+ console.log(` ${label}: ${text}`);
1853
+ }
1854
+ console.log();
1855
+ }
1856
+ break;
1857
+ case "info":
1858
+ console.log(`
1859
+ ${chalk9.gray("\uC11C\uBC84:")} ${server}
1860
+ ${chalk9.gray("\uC0AC\uC6A9\uC790:")} ${auth.username}
1861
+ ${chalk9.gray("\uC6CC\uD06C\uD50C\uB85C\uC6B0:")} ${current.workflow_name}
1862
+ ${chalk9.gray("\uC138\uC158:")} ${sessionId}
1863
+ ${chalk9.gray("\uD134:")} ${turnCount}
1864
+ `);
1865
+ break;
1866
+ default:
1867
+ console.log(chalk9.yellow(` \uC54C \uC218 \uC5C6\uB294 \uCEE4\uB9E8\uB4DC: /${cmd}. /help \uCC38\uACE0`));
1596
1868
  }
1597
- getAllTools() {
1598
- const tools2 = [];
1599
- for (const client2 of this.clients.values()) {
1600
- tools2.push(...client2.getOpenAITools());
1601
- }
1602
- return tools2;
1603
- }
1604
- async callTool(fullName, args) {
1605
- const parts = fullName.split("_");
1606
- if (parts.length < 3 || parts[0] !== "mcp") return `Unknown MCP tool: ${fullName}`;
1607
- const serverName = parts[1];
1608
- const toolName = parts.slice(2).join("_");
1609
- const client2 = this.clients.get(serverName);
1610
- if (!client2) return `MCP \uC11C\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${serverName}`;
1611
- return client2.callTool(toolName, args);
1612
- }
1613
- isMcpTool(name) {
1614
- return name.startsWith("mcp_");
1615
- }
1616
- stopAll() {
1617
- for (const client2 of this.clients.values()) {
1618
- client2.stop();
1869
+ rl.prompt();
1870
+ return;
1871
+ }
1872
+ turnCount++;
1873
+ const interactionId = `${sessionId}_t${turnCount}`;
1874
+ history.push({ role: "user", content: input });
1875
+ process.stdout.write(chalk9.gray(" thinking..."));
1876
+ try {
1877
+ const stream = await executeWorkflowStream({
1878
+ workflow_id: current.id,
1879
+ workflow_name: current.workflow_name,
1880
+ input_data: input,
1881
+ interaction_id: interactionId
1882
+ });
1883
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1884
+ let fullResponse = "";
1885
+ let hasOutput = false;
1886
+ await parseSSEStream(
1887
+ stream,
1888
+ (event) => {
1889
+ if ((event.type === "token" || !event.type) && event.content) {
1890
+ if (!hasOutput) {
1891
+ hasOutput = true;
1892
+ console.log();
1893
+ }
1894
+ process.stdout.write(event.content);
1895
+ fullResponse += event.content;
1896
+ } else if (event.type === "error") {
1897
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1898
+ printError(event.error ?? event.content ?? "\uC624\uB958");
1899
+ }
1900
+ },
1901
+ () => {
1902
+ if (hasOutput) {
1903
+ console.log();
1904
+ console.log();
1905
+ }
1906
+ if (fullResponse) {
1907
+ history.push({ role: "assistant", content: fullResponse });
1908
+ }
1909
+ },
1910
+ (err) => {
1911
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1912
+ printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
1619
1913
  }
1620
- this.clients.clear();
1621
- }
1622
- get serverCount() {
1623
- return this.clients.size;
1624
- }
1625
- getServerNames() {
1626
- return [...this.clients.keys()];
1627
- }
1628
- };
1629
- }
1630
- });
1914
+ );
1915
+ } catch (err) {
1916
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1917
+ const msg = err?.response?.data?.detail ?? err.message;
1918
+ printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
1919
+ }
1920
+ rl.prompt();
1921
+ };
1922
+ rl.setPrompt(getPrompt());
1923
+ rl.prompt();
1924
+ rl.on("line", (line) => {
1925
+ processInput(line).then(() => {
1926
+ });
1927
+ });
1928
+ rl.on("close", () => {
1929
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
1930
+ process.exit(0);
1931
+ });
1932
+ process.on("SIGINT", () => {
1933
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
1934
+ process.exit(0);
1935
+ });
1936
+ }
1937
+ function registerChatCommand(program2) {
1938
+ program2.command("chat [workflow-id]").description("\uC778\uD130\uB799\uD2F0\uBE0C \uB300\uD654 \uBAA8\uB4DC").action((workflowId) => chat(workflowId));
1939
+ }
1940
+
1941
+ // src/index.ts
1942
+ init_provider();
1631
1943
 
1632
1944
  // src/commands/agent.ts
1945
+ init_store();
1946
+ init_llm();
1633
1947
  import chalk12 from "chalk";
1634
1948
  import { createInterface as createInterface5 } from "readline";
1635
- function buildSystemPrompt() {
1636
- const server = getServer();
1637
- const auth = getAuth();
1638
- const env = getActiveEnvironment();
1639
- let prompt2 = `You are OPEN XGEN. Terminal AI agent.
1640
1949
 
1641
- CRITICAL RULES:
1642
- - Be extremely concise. No menus, no numbered lists of options, no "what would you like to do" questions.
1643
- - Just DO things. If the user says "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D" \u2192 call xgen_workflow_list immediately, show results.
1644
- - If the user says a number after seeing a list, treat it as selection and act on it.
1645
- - If the user says "\uC2E4\uD589" or "run" \u2192 call the tool immediately with the context you have.
1646
- - Never ask "which option do you prefer" or show menus. Infer intent and act.
1647
- - Respond in the user's language. Korean if they speak Korean.
1648
- - Max 2-3 sentences per response unless showing data.
1649
-
1650
- TOOLS:
1651
- - Coding: file_read, file_write, file_edit, bash, grep, list_files, sandbox_run
1652
- - XGEN: xgen_workflow_list, xgen_workflow_run, xgen_workflow_info, xgen_doc_list, xgen_ontology_query, xgen_server_status, xgen_execution_history`;
1653
- if (server && auth) {
1654
- prompt2 += `
1655
-
1656
- XGEN CONNECTED: ${server} as ${auth.username} (${env?.name ?? "default"})
1657
- - Workflow execute uses deploy_key for deployed workflows.
1658
- - If workflow execution returns 404, it means the Istio routing blocks direct stream access. Use deploy endpoint.`;
1659
- } else {
1660
- prompt2 += `
1661
- XGEN: Not connected. Tell user to run /connect.`;
1950
+ // src/agent/tools/file-read.ts
1951
+ var file_read_exports = {};
1952
+ __export(file_read_exports, {
1953
+ definition: () => definition,
1954
+ execute: () => execute
1955
+ });
1956
+ import { readFileSync as readFileSync2 } from "fs";
1957
+ var definition = {
1958
+ type: "function",
1959
+ function: {
1960
+ name: "file_read",
1961
+ description: "\uD30C\uC77C \uB0B4\uC6A9\uC744 \uC77D\uC2B5\uB2C8\uB2E4. \uC904 \uBC88\uD638\uAC00 \uD3EC\uD568\uB429\uB2C8\uB2E4.",
1962
+ parameters: {
1963
+ type: "object",
1964
+ properties: {
1965
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
1966
+ start_line: { type: "number", description: "\uC2DC\uC791 \uC904 \uBC88\uD638 (\uC120\uD0DD)" },
1967
+ end_line: { type: "number", description: "\uB05D \uC904 \uBC88\uD638 (\uC120\uD0DD)" }
1968
+ },
1969
+ required: ["path"]
1970
+ }
1662
1971
  }
1663
- return prompt2;
1664
- }
1665
- async function agentRepl() {
1666
- let provider = getDefaultProvider();
1667
- if (!provider) {
1668
- provider = await guidedProviderSetup();
1669
- if (!provider) process.exit(1);
1972
+ };
1973
+ async function execute(args) {
1974
+ const path = args.path;
1975
+ const startLine = args.start_line || 1;
1976
+ const endLine = args.end_line;
1977
+ try {
1978
+ const content = readFileSync2(path, "utf-8");
1979
+ const lines = content.split("\n");
1980
+ const sliced = lines.slice(startLine - 1, endLine ?? lines.length);
1981
+ return sliced.map((line, i) => `${startLine + i} ${line}`).join("\n");
1982
+ } catch (err) {
1983
+ return `Error: ${err.message}`;
1670
1984
  }
1671
- const client2 = createLLMClient(provider);
1672
- const allTools = [...getAllToolDefs(), ...definitions];
1673
- const builtinNames = getToolNames();
1674
- const mcpConfig = loadMcpConfig();
1675
- if (mcpConfig && Object.keys(mcpConfig.mcpServers).length > 0) {
1676
- mcpManager = new McpManager();
1677
- try {
1678
- await mcpManager.startAll(mcpConfig);
1679
- if (mcpManager.serverCount > 0) allTools.push(...mcpManager.getAllTools());
1680
- } catch {
1985
+ }
1986
+
1987
+ // src/agent/tools/file-write.ts
1988
+ var file_write_exports = {};
1989
+ __export(file_write_exports, {
1990
+ definition: () => definition2,
1991
+ execute: () => execute2
1992
+ });
1993
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1994
+ import { dirname } from "path";
1995
+ var definition2 = {
1996
+ type: "function",
1997
+ function: {
1998
+ name: "file_write",
1999
+ description: "\uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uAC70\uB098 \uB36E\uC5B4\uC501\uB2C8\uB2E4.",
2000
+ parameters: {
2001
+ type: "object",
2002
+ properties: {
2003
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
2004
+ content: { type: "string", description: "\uD30C\uC77C \uB0B4\uC6A9" }
2005
+ },
2006
+ required: ["path", "content"]
1681
2007
  }
1682
2008
  }
1683
- const messages = [{ role: "system", content: buildSystemPrompt() }];
1684
- console.log(welcome());
1685
- console.log();
1686
- const server = getServer();
1687
- const auth = getAuth();
1688
- const env = getActiveEnvironment();
1689
- console.log(chalk12.gray(` ${provider.name} \xB7 ${provider.model}`));
1690
- if (server && auth) {
1691
- console.log(chalk12.gray(` ${env?.name ?? "XGEN"} \xB7 ${auth.username}@${server.replace("https://", "")}`));
2009
+ };
2010
+ async function execute2(args) {
2011
+ const path = args.path;
2012
+ const content = args.content;
2013
+ try {
2014
+ mkdirSync2(dirname(path), { recursive: true });
2015
+ writeFileSync2(path, content, "utf-8");
2016
+ return `\uD30C\uC77C \uC791\uC131 \uC644\uB8CC: ${path}`;
2017
+ } catch (err) {
2018
+ return `Error: ${err.message}`;
1692
2019
  }
1693
- console.log(chalk12.gray(` ${builtinNames.length} \uB3C4\uAD6C + ${definitions.length} XGEN${mcpManager?.serverCount ? ` + ${mcpManager.getAllTools().length} MCP` : ""}`));
1694
- console.log(chalk12.gray(` /help \xB7 /connect \xB7 /env \xB7 /provider \xB7 /exit
1695
- `));
1696
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
1697
- const askUser = () => new Promise((resolve) => rl.question(chalk12.cyan(" \u276F "), (a) => resolve(a.trim())));
1698
- process.on("SIGINT", () => {
1699
- console.log(chalk12.gray("\n \u{1F44B}\n"));
1700
- mcpManager?.stopAll();
1701
- rl.close();
1702
- process.exit(0);
1703
- });
1704
- while (true) {
1705
- const input = await askUser();
1706
- if (!input) continue;
1707
- if (input === "/exit" || input === "exit") {
1708
- console.log(chalk12.gray("\n \u{1F44B}\n"));
1709
- mcpManager?.stopAll();
1710
- rl.close();
1711
- break;
2020
+ }
2021
+
2022
+ // src/agent/tools/file-edit.ts
2023
+ var file_edit_exports = {};
2024
+ __export(file_edit_exports, {
2025
+ definition: () => definition3,
2026
+ execute: () => execute3
2027
+ });
2028
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
2029
+ var definition3 = {
2030
+ type: "function",
2031
+ function: {
2032
+ name: "file_edit",
2033
+ description: "\uD30C\uC77C\uC5D0\uC11C \uD2B9\uC815 \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC544 \uAD50\uCCB4\uD569\uB2C8\uB2E4.",
2034
+ parameters: {
2035
+ type: "object",
2036
+ properties: {
2037
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
2038
+ old_text: { type: "string", description: "\uAD50\uCCB4\uD560 \uAE30\uC874 \uD14D\uC2A4\uD2B8" },
2039
+ new_text: { type: "string", description: "\uC0C8 \uD14D\uC2A4\uD2B8" }
2040
+ },
2041
+ required: ["path", "old_text", "new_text"]
1712
2042
  }
1713
- if (input === "/help") {
1714
- console.log(`
1715
- ${chalk12.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
1716
- ${chalk12.cyan("/connect")} XGEN \uC11C\uBC84 \uC5F0\uACB0 + \uB85C\uADF8\uC778
1717
- ${chalk12.cyan("/env")} \uD658\uACBD \uC804\uD658 (\uBCF8\uC0AC/\uC81C\uC8FC/\uB86F\uB370\uBAB0)
1718
- ${chalk12.cyan("/provider")} \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD
1719
- ${chalk12.cyan("/tools")} \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB3C4\uAD6C \uBAA9\uB85D
1720
- ${chalk12.cyan("/status")} \uD604\uC7AC \uC5F0\uACB0 \uC0C1\uD0DC
1721
- ${chalk12.cyan("/clear")} \uB300\uD654 \uCD08\uAE30\uD654
1722
- ${chalk12.cyan("/exit")} \uC885\uB8CC
1723
- `);
1724
- continue;
2043
+ }
2044
+ };
2045
+ async function execute3(args) {
2046
+ const path = args.path;
2047
+ const oldText = args.old_text;
2048
+ const newText = args.new_text;
2049
+ try {
2050
+ const content = readFileSync3(path, "utf-8");
2051
+ if (!content.includes(oldText)) {
2052
+ return `Error: \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4`;
1725
2053
  }
1726
- if (input === "/clear") {
1727
- messages.length = 0;
1728
- messages.push({ role: "system", content: buildSystemPrompt() });
1729
- console.log(chalk12.gray(" \uB300\uD654 \uCD08\uAE30\uD654\uB428.\n"));
1730
- continue;
2054
+ const updated = content.replace(oldText, newText);
2055
+ writeFileSync3(path, updated, "utf-8");
2056
+ return `\uD30C\uC77C \uC218\uC815 \uC644\uB8CC: ${path}`;
2057
+ } catch (err) {
2058
+ return `Error: ${err.message}`;
2059
+ }
2060
+ }
2061
+
2062
+ // src/agent/tools/bash.ts
2063
+ var bash_exports = {};
2064
+ __export(bash_exports, {
2065
+ definition: () => definition4,
2066
+ execute: () => execute4
2067
+ });
2068
+ import { execSync } from "child_process";
2069
+ var definition4 = {
2070
+ type: "function",
2071
+ function: {
2072
+ name: "bash",
2073
+ description: "\uC178 \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. stdout + stderr\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.",
2074
+ parameters: {
2075
+ type: "object",
2076
+ properties: {
2077
+ command: { type: "string", description: "\uC2E4\uD589\uD560 \uBA85\uB839\uC5B4" }
2078
+ },
2079
+ required: ["command"]
1731
2080
  }
1732
- if (input === "/status") {
1733
- const p = getDefaultProvider();
1734
- const s = getServer();
1735
- const a = getAuth();
1736
- const e = getActiveEnvironment();
1737
- console.log();
1738
- console.log(` ${chalk12.bold("\uD504\uB85C\uBC14\uC774\uB354")} ${p ? `${p.name} \xB7 ${p.model}` : chalk12.red("\uBBF8\uC124\uC815")}`);
1739
- console.log(` ${chalk12.bold("\uC11C\uBC84")} ${s && a ? `${a.username}@${s.replace("https://", "")}` : chalk12.red("\uBBF8\uC5F0\uACB0")}`);
1740
- console.log(` ${chalk12.bold("\uD658\uACBD")} ${e?.name ?? "\uC5C6\uC74C"} (${getEnvironments().length}\uAC1C \uB4F1\uB85D)`);
1741
- if (mcpManager?.serverCount) {
1742
- console.log(` ${chalk12.bold("MCP")} ${mcpManager.getServerNames().join(", ")}`);
1743
- }
1744
- console.log();
1745
- continue;
2081
+ }
2082
+ };
2083
+ async function execute4(args) {
2084
+ const command = args.command;
2085
+ try {
2086
+ const output = execSync(command, {
2087
+ encoding: "utf-8",
2088
+ timeout: 3e4,
2089
+ maxBuffer: 1024 * 1024,
2090
+ stdio: ["pipe", "pipe", "pipe"]
2091
+ });
2092
+ return output || "(no output)";
2093
+ } catch (err) {
2094
+ const e = err;
2095
+ return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
2096
+ }
2097
+ }
2098
+
2099
+ // src/agent/tools/grep.ts
2100
+ var grep_exports = {};
2101
+ __export(grep_exports, {
2102
+ definition: () => definition5,
2103
+ execute: () => execute5
2104
+ });
2105
+ import { execSync as execSync2 } from "child_process";
2106
+ var definition5 = {
2107
+ type: "function",
2108
+ function: {
2109
+ name: "grep",
2110
+ description: "\uD30C\uC77C\uC5D0\uC11C \uD328\uD134\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4 (\uC7AC\uADC0, \uC904 \uBC88\uD638 \uD3EC\uD568).",
2111
+ parameters: {
2112
+ type: "object",
2113
+ properties: {
2114
+ pattern: { type: "string", description: "\uAC80\uC0C9 \uD328\uD134 (\uC815\uADDC\uC2DD)" },
2115
+ path: { type: "string", description: "\uAC80\uC0C9 \uB514\uB809\uD1A0\uB9AC \uB610\uB294 \uD30C\uC77C (\uAE30\uBCF8: .)" },
2116
+ glob: { type: "string", description: "\uD30C\uC77C \uD544\uD130 (\uC608: *.ts)" }
2117
+ },
2118
+ required: ["pattern"]
1746
2119
  }
1747
- if (input === "/tools") {
1748
- console.log(`
1749
- ${chalk12.bold("\uCF54\uB529")} ${builtinNames.join(", ")}`);
1750
- console.log(` ${chalk12.bold("XGEN")} ${definitions.map((t) => t.function.name).join(", ")}`);
1751
- if (mcpManager?.serverCount) {
1752
- console.log(` ${chalk12.bold("MCP")} ${mcpManager.getAllTools().map((t) => t.function.name).join(", ")}`);
2120
+ }
2121
+ };
2122
+ async function execute5(args) {
2123
+ const pattern = args.pattern;
2124
+ const path = args.path || ".";
2125
+ const glob = args.glob;
2126
+ try {
2127
+ let cmd = `grep -rn --color=never "${pattern.replace(/"/g, '\\"')}" "${path}"`;
2128
+ if (glob) cmd += ` --include="${glob}"`;
2129
+ cmd += " | head -50";
2130
+ const output = execSync2(cmd, {
2131
+ encoding: "utf-8",
2132
+ timeout: 1e4,
2133
+ maxBuffer: 512 * 1024,
2134
+ stdio: ["pipe", "pipe", "pipe"]
2135
+ });
2136
+ return output || "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
2137
+ } catch {
2138
+ return "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
2139
+ }
2140
+ }
2141
+
2142
+ // src/agent/tools/list-files.ts
2143
+ var list_files_exports = {};
2144
+ __export(list_files_exports, {
2145
+ definition: () => definition6,
2146
+ execute: () => execute6
2147
+ });
2148
+ import { execSync as execSync3 } from "child_process";
2149
+ var definition6 = {
2150
+ type: "function",
2151
+ function: {
2152
+ name: "list_files",
2153
+ description: "\uB514\uB809\uD1A0\uB9AC\uC758 \uD30C\uC77C/\uD3F4\uB354 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. glob \uD328\uD134 \uC9C0\uC6D0.",
2154
+ parameters: {
2155
+ type: "object",
2156
+ properties: {
2157
+ path: { type: "string", description: "\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8: .)" },
2158
+ pattern: { type: "string", description: "glob \uD328\uD134 (\uC608: **/*.ts)" }
1753
2159
  }
1754
- console.log();
1755
- continue;
1756
2160
  }
1757
- if (input === "/connect") {
1758
- await connectServer();
1759
- messages[0] = { role: "system", content: buildSystemPrompt() };
1760
- continue;
1761
- }
1762
- if (input === "/env") {
1763
- await switchEnv();
1764
- messages[0] = { role: "system", content: buildSystemPrompt() };
1765
- continue;
1766
- }
1767
- if (input === "/provider") {
1768
- const { guidedProviderSetup: setup } = await Promise.resolve().then(() => (init_provider(), provider_exports));
1769
- await setup();
1770
- console.log(chalk12.gray(" \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD\uB428. /exit \uD6C4 \uC7AC\uC2DC\uC791\uD558\uC138\uC694.\n"));
1771
- continue;
1772
- }
1773
- messages.push({ role: "user", content: input });
1774
- try {
1775
- await runLoop(client2, provider.model, messages, allTools);
1776
- } catch (err) {
1777
- console.log(chalk12.red(`
1778
- \uC624\uB958: ${err.message}
1779
- `));
2161
+ }
2162
+ };
2163
+ async function execute6(args) {
2164
+ const path = args.path || ".";
2165
+ const pattern = args.pattern;
2166
+ try {
2167
+ let cmd;
2168
+ if (pattern) {
2169
+ cmd = `find "${path}" -name "${pattern}" -type f | head -100`;
2170
+ } else {
2171
+ cmd = `ls -la "${path}"`;
1780
2172
  }
2173
+ const output = execSync3(cmd, {
2174
+ encoding: "utf-8",
2175
+ timeout: 1e4,
2176
+ stdio: ["pipe", "pipe", "pipe"]
2177
+ });
2178
+ return output || "(empty)";
2179
+ } catch (err) {
2180
+ return `Error: ${err.message}`;
1781
2181
  }
1782
2182
  }
1783
- async function runLoop(client2, model, messages, tools2) {
1784
- for (let i = 0; i < 20; i++) {
1785
- let first = true;
1786
- const result = await streamChat(client2, model, messages, tools2, (delta) => {
1787
- if (first) {
1788
- process.stdout.write(chalk12.green("\n ") + "");
1789
- first = false;
1790
- }
1791
- process.stdout.write(delta);
1792
- });
1793
- if (result.content) process.stdout.write("\n\n");
1794
- if (result.toolCalls.length === 0) {
1795
- if (result.content) messages.push({ role: "assistant", content: result.content });
1796
- return;
1797
- }
1798
- messages.push({
1799
- role: "assistant",
1800
- content: result.content || null,
1801
- tool_calls: result.toolCalls.map((tc) => ({
1802
- id: tc.id,
1803
- type: "function",
1804
- function: { name: tc.name, arguments: tc.arguments }
1805
- }))
1806
- });
1807
- for (const tc of result.toolCalls) {
1808
- let args;
1809
- try {
1810
- args = JSON.parse(tc.arguments);
1811
- } catch {
1812
- args = {};
1813
- }
1814
- const shortArgs = Object.entries(args).map(([k, v]) => {
1815
- const s = String(v);
1816
- return `${k}=${s.length > 30 ? s.slice(0, 30) + "\u2026" : s}`;
1817
- }).join(" ");
1818
- console.log(chalk12.gray(` \u2699 ${chalk12.white(tc.name)} ${shortArgs}`));
1819
- let toolResult;
1820
- if (isXgenTool(tc.name)) {
1821
- toolResult = await execute8(tc.name, args);
1822
- } else if (mcpManager?.isMcpTool(tc.name)) {
1823
- toolResult = await mcpManager.callTool(tc.name, args);
1824
- } else {
1825
- toolResult = await executeTool(tc.name, args);
1826
- }
1827
- const truncated = toolResult.length > 4e3 ? toolResult.slice(0, 4e3) + "\n\u2026(truncated)" : toolResult;
1828
- messages.push({ role: "tool", tool_call_id: tc.id, content: truncated });
1829
- }
2183
+
2184
+ // src/agent/tools/sandbox.ts
2185
+ var sandbox_exports = {};
2186
+ __export(sandbox_exports, {
2187
+ definition: () => definition7,
2188
+ execute: () => execute7
2189
+ });
2190
+ import { execSync as execSync4 } from "child_process";
2191
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync2, rmSync } from "fs";
2192
+ import { join as join2 } from "path";
2193
+ import { tmpdir } from "os";
2194
+ var SANDBOX_DIR = join2(tmpdir(), "xgen-sandbox");
2195
+ function ensureSandbox() {
2196
+ if (!existsSync2(SANDBOX_DIR)) {
2197
+ mkdirSync3(SANDBOX_DIR, { recursive: true });
1830
2198
  }
1831
- console.log(chalk12.yellow("\n \uCD5C\uB300 \uBC18\uBCF5 \uD69F\uC218 \uB3C4\uB2EC.\n"));
2199
+ return SANDBOX_DIR;
1832
2200
  }
1833
- async function connectServer() {
1834
- const { setServer: setServer2, setAuth: setAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1835
- const { addEnvironment: addEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1836
- console.log(chalk12.bold("\n XGEN \uC11C\uBC84 \uC5F0\uACB0\n"));
1837
- const presets = [
1838
- { id: "hq", name: "\uBCF8\uC0AC", url: "https://xgen.x2bee.com", email: "admin@plateer.com" },
1839
- { id: "jeju", name: "\uC81C\uC8FC", url: "https://jeju-xgen.x2bee.com", email: "admin@plateer.com" },
1840
- { id: "lotte", name: "\uB86F\uB370\uBAB0", url: "https://lotteimall-xgen.x2bee.com" }
1841
- ];
1842
- presets.forEach((p, i) => console.log(` ${chalk12.cyan(`${i + 1}.`)} ${p.name} ${chalk12.gray(p.url)}`));
1843
- console.log(` ${chalk12.cyan("4.")} \uC9C1\uC811 \uC785\uB825`);
1844
- console.log();
1845
- const choice = await ask(chalk12.cyan(" \u276F "));
1846
- let url;
1847
- let email;
1848
- const ci = parseInt(choice) - 1;
1849
- if (ci >= 0 && ci < presets.length) {
1850
- url = presets[ci].url;
1851
- email = presets[ci].email;
1852
- addEnvironment2({ ...presets[ci], description: presets[ci].name });
1853
- } else {
1854
- url = await ask(chalk12.white(" URL: "));
1855
- if (!url) return;
2201
+ var definition7 = {
2202
+ type: "function",
2203
+ function: {
2204
+ name: "sandbox_run",
2205
+ description: "\uACA9\uB9AC\uB41C \uC0CC\uB4DC\uBC15\uC2A4\uC5D0\uC11C \uCF54\uB4DC\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. Node.js \uB610\uB294 Python \uCF54\uB4DC\uB97C \uC548\uC804\uD558\uAC8C \uC2E4\uD589\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. npm \uD328\uD0A4\uC9C0 \uC124\uCE58\uB3C4 \uAC00\uB2A5\uD569\uB2C8\uB2E4.",
2206
+ parameters: {
2207
+ type: "object",
2208
+ properties: {
2209
+ language: {
2210
+ type: "string",
2211
+ enum: ["javascript", "typescript", "python"],
2212
+ description: "\uC2E4\uD589\uD560 \uC5B8\uC5B4"
2213
+ },
2214
+ code: { type: "string", description: "\uC2E4\uD589\uD560 \uCF54\uB4DC" },
2215
+ packages: {
2216
+ type: "array",
2217
+ items: { type: "string" },
2218
+ description: "\uC124\uCE58\uD560 \uD328\uD0A4\uC9C0 (npm \uB610\uB294 pip)"
2219
+ }
2220
+ },
2221
+ required: ["language", "code"]
2222
+ }
1856
2223
  }
1857
- setServer2(url);
1858
- console.log(chalk12.green(` \u2713 ${url}
1859
- `));
1860
- const inputEmail = email || await ask(chalk12.white(" \uC774\uBA54\uC77C: "));
1861
- const pw = await ask(chalk12.white(" \uBE44\uBC00\uBC88\uD638: "));
1862
- if (!inputEmail || !pw) return;
2224
+ };
2225
+ async function execute7(args) {
2226
+ const language = args.language;
2227
+ const code = args.code;
2228
+ const packages = args.packages ?? [];
2229
+ const dir = ensureSandbox();
2230
+ const runId = `run_${Date.now()}`;
2231
+ const runDir = join2(dir, runId);
2232
+ mkdirSync3(runDir, { recursive: true });
1863
2233
  try {
1864
- const { apiLogin: apiLogin2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
1865
- const result = await apiLogin2(inputEmail, pw);
1866
- if (result.success && result.access_token) {
1867
- setAuth2({ accessToken: result.access_token, refreshToken: result.refresh_token ?? "", userId: result.user_id ?? "", username: result.username ?? "", isAdmin: false, expiresAt: null });
1868
- console.log(chalk12.green(` \u2713 ${result.username} \uB85C\uADF8\uC778\uB428
1869
- `));
2234
+ if (packages.length > 0) {
2235
+ if (language === "python") {
2236
+ const pkgList = packages.join(" ");
2237
+ execSync4(`pip install ${pkgList}`, {
2238
+ cwd: runDir,
2239
+ encoding: "utf-8",
2240
+ timeout: 6e4,
2241
+ stdio: ["pipe", "pipe", "pipe"]
2242
+ });
2243
+ } else {
2244
+ execSync4("npm init -y", { cwd: runDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
2245
+ const pkgList = packages.join(" ");
2246
+ execSync4(`npm install ${pkgList}`, {
2247
+ cwd: runDir,
2248
+ encoding: "utf-8",
2249
+ timeout: 6e4,
2250
+ stdio: ["pipe", "pipe", "pipe"]
2251
+ });
2252
+ }
2253
+ }
2254
+ let cmd;
2255
+ let filename;
2256
+ if (language === "python") {
2257
+ filename = "script.py";
2258
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
2259
+ cmd = `python3 ${filename}`;
2260
+ } else if (language === "typescript") {
2261
+ filename = "script.ts";
2262
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
2263
+ cmd = `npx tsx ${filename}`;
1870
2264
  } else {
1871
- console.log(chalk12.red(` \u2717 ${result.message}
1872
- `));
2265
+ filename = "script.mjs";
2266
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
2267
+ cmd = `node ${filename}`;
1873
2268
  }
2269
+ const output = execSync4(cmd, {
2270
+ cwd: runDir,
2271
+ encoding: "utf-8",
2272
+ timeout: 3e4,
2273
+ maxBuffer: 1024 * 1024,
2274
+ stdio: ["pipe", "pipe", "pipe"]
2275
+ });
2276
+ return output || "(no output)";
1874
2277
  } catch (err) {
1875
- console.log(chalk12.red(` \u2717 ${err.message}
1876
- `));
1877
- }
1878
- }
1879
- async function switchEnv() {
1880
- const { getEnvironments: getEnvs, switchEnvironment: switchEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1881
- const envs = getEnvs();
1882
- if (!envs.length) {
1883
- console.log(chalk12.gray("\n \uD658\uACBD \uC5C6\uC74C. /connect\uB85C \uBA3C\uC800 \uC5F0\uACB0\uD558\uC138\uC694.\n"));
1884
- return;
1885
- }
1886
- const active = getActiveEnvironment();
1887
- console.log();
1888
- envs.forEach((e, i) => {
1889
- const mark = e.id === active?.id ? chalk12.green("\u25CF ") : " ";
1890
- console.log(` ${mark}${chalk12.cyan(`${i + 1}.`)} ${e.name} ${chalk12.gray(e.url)}`);
1891
- });
1892
- console.log();
1893
- const ci = parseInt(await ask(chalk12.cyan(" \u276F "))) - 1;
1894
- if (ci >= 0 && ci < envs.length) {
1895
- switchEnvironment2(envs[ci].id);
1896
- console.log(chalk12.green(` \u2713 ${envs[ci].name}
1897
- `));
2278
+ const e = err;
2279
+ return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
2280
+ } finally {
2281
+ try {
2282
+ rmSync(runDir, { recursive: true, force: true });
2283
+ } catch {
2284
+ }
1898
2285
  }
1899
2286
  }
1900
- function registerAgentCommand(program2) {
1901
- program2.command("agent").description("OPEN XGEN AI \uC5D0\uC774\uC804\uD2B8").action(async () => {
1902
- await agentRepl();
1903
- });
1904
- }
1905
- var mcpManager;
1906
- var init_agent = __esm({
1907
- "src/commands/agent.ts"() {
1908
- "use strict";
1909
- init_store();
1910
- init_llm();
1911
- init_tools();
1912
- init_xgen_api();
1913
- init_client2();
1914
- init_provider();
1915
- init_ui();
1916
- mcpManager = null;
1917
- }
1918
- });
1919
2287
 
1920
- // src/dashboard/renderer.ts
1921
- import chalk15 from "chalk";
1922
- function clearScreen() {
1923
- process.stdout.write("\x1B[2J\x1B[H");
1924
- }
1925
- function renderHeader(activeTab, tabs, env) {
1926
- const w = W2();
1927
- const title = chalk15.cyan.bold(" OPEN XGEN ");
1928
- const envTag = env ? chalk15.gray(` \xB7 ${env}`) : "";
1929
- const tabBar = tabs.map((t) => {
1930
- if (t === activeTab) return chalk15.bgCyan.black(` ${t} `);
1931
- return chalk15.gray(` ${t} `);
1932
- }).join(chalk15.gray("\u2502"));
1933
- console.log(chalk15.bgGray.black(" ".repeat(w)));
1934
- console.log(chalk15.bgGray.black(`${title}${envTag}${" ".repeat(Math.max(0, w - stripAnsi(title + envTag).length))}`));
1935
- console.log(chalk15.gray("\u2500".repeat(w)));
1936
- console.log(tabBar);
1937
- console.log(chalk15.gray("\u2500".repeat(w)));
1938
- }
1939
- function renderStatusBar(text) {
1940
- const w = W2();
1941
- const padded = ` ${text}${" ".repeat(Math.max(0, w - text.length - 1))}`;
1942
- console.log(chalk15.gray("\u2500".repeat(w)));
1943
- console.log(chalk15.bgGray.black(padded));
1944
- }
1945
- function renderList(items, selected, title, startRow) {
1946
- if (title) console.log(chalk15.bold(` ${title}`));
1947
- console.log();
1948
- const pageSize = H() - 12;
1949
- const start = Math.max(0, selected - pageSize + 3);
1950
- const visible = items.slice(start, start + pageSize);
1951
- visible.forEach((item, i) => {
1952
- const idx = start + i;
1953
- const cursor = idx === selected ? chalk15.cyan("\u25B8 ") : " ";
1954
- const num = chalk15.gray(`${String(idx + 1).padStart(3)}.`);
1955
- const tag = item.tag ? ` ${item.tag}` : "";
1956
- const line = `${cursor}${num} ${item.label}${tag}`;
1957
- if (idx === selected) {
1958
- console.log(chalk15.white.bold(line));
1959
- if (item.detail) console.log(chalk15.gray(` ${item.detail}`));
1960
- } else {
1961
- console.log(line);
1962
- }
1963
- });
1964
- if (items.length > pageSize) {
1965
- console.log(chalk15.gray(`
1966
- ${start + 1}-${Math.min(start + pageSize, items.length)} / ${items.length}`));
1967
- }
2288
+ // src/agent/tools/index.ts
2289
+ var tools = [file_read_exports, file_write_exports, file_edit_exports, bash_exports, grep_exports, list_files_exports, sandbox_exports];
2290
+ var toolMap = /* @__PURE__ */ new Map();
2291
+ for (const t of tools) {
2292
+ toolMap.set(t.definition.function.name, t);
1968
2293
  }
1969
- function renderPanel(title, lines) {
1970
- const w = W2() - 4;
1971
- console.log(chalk15.cyan(` \u250C${"\u2500".repeat(w)}\u2510`));
1972
- console.log(chalk15.cyan(` \u2502 ${chalk15.bold(title)}${" ".repeat(Math.max(0, w - stripAnsi(title).length - 1))}\u2502`));
1973
- console.log(chalk15.cyan(` \u251C${"\u2500".repeat(w)}\u2524`));
1974
- for (const line of lines) {
1975
- const clean = stripAnsi(line);
1976
- const pad = Math.max(0, w - clean.length - 1);
1977
- console.log(chalk15.cyan(` \u2502 `) + line + " ".repeat(pad) + chalk15.cyan("\u2502"));
1978
- }
1979
- console.log(chalk15.cyan(` \u2514${"\u2500".repeat(w)}\u2518`));
2294
+ function getAllToolDefs() {
2295
+ return tools.map((t) => t.definition);
2296
+ }
2297
+ async function executeTool(name, args) {
2298
+ const tool = toolMap.get(name);
2299
+ if (!tool) return `Unknown tool: ${name}`;
2300
+ return tool.execute(args);
1980
2301
  }
1981
- function stripAnsi(str) {
1982
- return str.replace(/\x1b\[[0-9;]*m/g, "");
2302
+ function getToolNames() {
2303
+ return tools.map((t) => t.definition.function.name);
1983
2304
  }
1984
- var W2, H;
1985
- var init_renderer = __esm({
1986
- "src/dashboard/renderer.ts"() {
1987
- "use strict";
1988
- W2 = () => Math.min(process.stdout.columns || 80, 100);
1989
- H = () => Math.min(process.stdout.rows || 30, 40);
1990
- }
1991
- });
1992
2305
 
1993
- // src/dashboard/index.ts
1994
- var dashboard_exports = {};
1995
- __export(dashboard_exports, {
1996
- dashboard: () => dashboard
1997
- });
1998
- import chalk16 from "chalk";
1999
- import { createInterface as createInterface7 } from "readline";
2000
- async function dashboard() {
2001
- const state = {
2002
- activeTab: 0,
2003
- workflows: [],
2004
- documents: [],
2005
- selectedIdx: 0
2006
- };
2007
- await loadData(state);
2008
- render(state);
2009
- const rl = createInterface7({ input: process.stdin, output: process.stdout });
2010
- if (process.stdin.isTTY) {
2011
- process.stdin.setRawMode(true);
2012
- process.stdin.resume();
2013
- process.stdin.setEncoding("utf8");
2014
- process.stdin.on("data", async (key) => {
2015
- if (key === "") {
2016
- cleanup(rl);
2017
- process.exit(0);
2018
- }
2019
- if (key === " ") {
2020
- state.activeTab = (state.activeTab + 1) % TABS.length;
2021
- state.selectedIdx = 0;
2022
- render(state);
2023
- return;
2306
+ // src/agent/tools/xgen-api.ts
2307
+ init_store();
2308
+ var definitions = [
2309
+ {
2310
+ type: "function",
2311
+ function: {
2312
+ name: "xgen_workflow_list",
2313
+ description: "XGEN \uC11C\uBC84\uC5D0\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
2314
+ parameters: { type: "object", properties: {} }
2315
+ }
2316
+ },
2317
+ {
2318
+ type: "function",
2319
+ function: {
2320
+ name: "xgen_workflow_run",
2321
+ description: "XGEN \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. \uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB9CC \uC2E4\uD589 \uAC00\uB2A5.",
2322
+ parameters: {
2323
+ type: "object",
2324
+ properties: {
2325
+ workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" },
2326
+ workflow_name: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984" },
2327
+ input_data: { type: "string", description: "\uC785\uB825 \uBA54\uC2DC\uC9C0" },
2328
+ deploy_key: { type: "string", description: "\uBC30\uD3EC \uD0A4 (\uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0)" }
2329
+ },
2330
+ required: ["workflow_id", "workflow_name", "input_data"]
2024
2331
  }
2025
- if (key === "\x1B[Z") {
2026
- state.activeTab = (state.activeTab - 1 + TABS.length) % TABS.length;
2027
- state.selectedIdx = 0;
2028
- render(state);
2029
- return;
2332
+ }
2333
+ },
2334
+ {
2335
+ type: "function",
2336
+ function: {
2337
+ name: "xgen_workflow_info",
2338
+ description: "\uD2B9\uC815 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uC0C1\uC138 \uC815\uBCF4(\uB178\uB4DC, \uC5E3\uC9C0 \uB4F1)\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4.",
2339
+ parameters: {
2340
+ type: "object",
2341
+ properties: {
2342
+ workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" }
2343
+ },
2344
+ required: ["workflow_id"]
2030
2345
  }
2031
- if (key === "\x1B[A") {
2032
- state.selectedIdx = Math.max(0, state.selectedIdx - 1);
2033
- render(state);
2034
- return;
2346
+ }
2347
+ },
2348
+ {
2349
+ type: "function",
2350
+ function: {
2351
+ name: "xgen_collection_list",
2352
+ description: "XGEN \uC11C\uBC84\uC758 \uBB38\uC11C \uCEEC\uB809\uC158(\uC9C0\uC2DD\uBCA0\uC774\uC2A4) \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4. \uBB38\uC11C \uC218, \uCCAD\uD06C \uC218, \uACF5\uC720 \uC0C1\uD0DC \uB4F1 \uD3EC\uD568.",
2353
+ parameters: { type: "object", properties: {} }
2354
+ }
2355
+ },
2356
+ {
2357
+ type: "function",
2358
+ function: {
2359
+ name: "xgen_server_status",
2360
+ description: "XGEN \uC11C\uBC84 \uC0C1\uD0DC\uB97C \uD655\uC778\uD569\uB2C8\uB2E4.",
2361
+ parameters: { type: "object", properties: {} }
2362
+ }
2363
+ },
2364
+ {
2365
+ type: "function",
2366
+ function: {
2367
+ name: "xgen_execution_history",
2368
+ description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589 \uC774\uB825\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
2369
+ parameters: {
2370
+ type: "object",
2371
+ properties: {
2372
+ limit: { type: "number", description: "\uAC00\uC838\uC62C \uC774\uB825 \uC218 (\uAE30\uBCF8 10)" }
2373
+ }
2035
2374
  }
2036
- if (key === "\x1B[B") {
2037
- const max = getCurrentListLength(state) - 1;
2038
- state.selectedIdx = Math.min(max, state.selectedIdx + 1);
2039
- render(state);
2040
- return;
2041
- }
2042
- if (key === "\r") {
2043
- await handleEnter(state, rl);
2044
- return;
2045
- }
2046
- const num = parseInt(key);
2047
- if (num >= 1 && num <= 5) {
2048
- state.activeTab = num - 1;
2049
- state.selectedIdx = 0;
2050
- render(state);
2051
- return;
2052
- }
2053
- if (key === "c") {
2054
- state.activeTab = 0;
2055
- render(state);
2056
- return;
2057
- }
2058
- if (key === "w") {
2059
- state.activeTab = 1;
2060
- render(state);
2061
- return;
2062
- }
2063
- if (key === "d") {
2064
- state.activeTab = 2;
2065
- render(state);
2066
- return;
2067
- }
2068
- if (key === "o") {
2069
- state.activeTab = 3;
2070
- render(state);
2071
- return;
2072
- }
2073
- if (key === "s") {
2074
- state.activeTab = 4;
2075
- render(state);
2076
- return;
2077
- }
2078
- if (key === "r") {
2079
- await loadData(state);
2080
- render(state);
2081
- return;
2082
- }
2083
- if (key === "q") {
2084
- cleanup(rl);
2085
- process.exit(0);
2086
- }
2087
- });
2088
- } else {
2089
- cleanup(rl);
2090
- await agentRepl();
2375
+ }
2091
2376
  }
2092
- }
2093
- function render(state) {
2094
- clearScreen();
2095
- const env = getActiveEnvironment();
2096
- const auth = getAuth();
2377
+ ];
2378
+ async function execute8(name, args) {
2097
2379
  const server = getServer();
2098
- const envLabel = env?.name ?? (server ? server.replace("https://", "") : "\uBBF8\uC5F0\uACB0");
2099
- const userLabel = auth ? `${auth.username}@${envLabel}` : envLabel;
2100
- renderHeader(TABS[state.activeTab], TABS, userLabel);
2101
- console.log();
2102
- switch (state.activeTab) {
2103
- case 0:
2104
- renderChatTab();
2105
- break;
2106
- case 1:
2107
- renderWorkflowTab(state);
2108
- break;
2109
- case 2:
2110
- renderDocTab(state);
2111
- break;
2112
- case 3:
2113
- renderOntologyTab();
2114
- break;
2115
- case 4:
2116
- renderSettingsTab();
2117
- break;
2380
+ const auth = getAuth();
2381
+ if (!server || !auth) {
2382
+ return "XGEN \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. /connect \uBA85\uB839\uC73C\uB85C \uC5F0\uACB0\uD558\uC138\uC694.";
2383
+ }
2384
+ try {
2385
+ switch (name) {
2386
+ case "xgen_workflow_list":
2387
+ return await workflowList2();
2388
+ case "xgen_workflow_run":
2389
+ return await workflowRun2(args);
2390
+ case "xgen_workflow_info":
2391
+ return await workflowInfo2(args);
2392
+ case "xgen_collection_list":
2393
+ return await collectionList();
2394
+ case "xgen_server_status":
2395
+ return await serverStatus();
2396
+ case "xgen_execution_history":
2397
+ return await executionHistory(args);
2398
+ default:
2399
+ return `Unknown XGEN tool: ${name}`;
2400
+ }
2401
+ } catch (err) {
2402
+ return `XGEN API \uC624\uB958: ${err.message}`;
2118
2403
  }
2119
- const provider = getDefaultProvider();
2120
- const statusText = `${provider?.name ?? "AI \uBBF8\uC124\uC815"} \xB7 ${provider?.model ?? ""} \u2502 Tab:\uC804\uD658 \u2191\u2193:\uC120\uD0DD Enter:\uC2E4\uD589 r:\uC0C8\uB85C\uACE0\uCE68 q:\uC885\uB8CC`;
2121
- renderStatusBar(statusText);
2122
2404
  }
2123
- function renderChatTab() {
2124
- console.log(chalk16.bold(" AI \uC5D0\uC774\uC804\uD2B8"));
2125
- console.log();
2126
- console.log(chalk16.gray(" Enter\uB97C \uB20C\uB7EC AI \uCC44\uD305 \uBAA8\uB4DC\uB85C \uC9C4\uC785\uD569\uB2C8\uB2E4."));
2127
- console.log(chalk16.gray(" \uCC44\uD305\uC5D0\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589, \uD30C\uC77C \uD3B8\uC9D1, \uCF54\uB4DC \uC2E4\uD589 \uBAA8\uB450 \uAC00\uB2A5\uD569\uB2C8\uB2E4."));
2128
- console.log();
2129
- console.log(chalk16.gray(" \uC608\uC2DC:"));
2130
- console.log(chalk16.white(' "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uC5EC\uC918"'));
2131
- console.log(chalk16.white(' "\uC7AC\uC9C1\uC99D\uBA85\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589\uD574\uC918"'));
2132
- console.log(chalk16.white(' "\uC774 \uD3F4\uB354\uC5D0 \uC788\uB294 \uD30C\uC77C \uBB50 \uC788\uC5B4?"'));
2133
- console.log(chalk16.white(' "Python\uC73C\uB85C fibonacci \uD568\uC218 \uB9CC\uB4E4\uC5B4\uC918"'));
2134
- console.log();
2405
+ function isXgenTool(name) {
2406
+ return name.startsWith("xgen_");
2135
2407
  }
2136
- function renderWorkflowTab(state) {
2137
- if (state.workflows.length === 0) {
2138
- console.log(chalk16.gray(" \uC11C\uBC84 \uBBF8\uC5F0\uACB0 \uB610\uB294 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC5C6\uC74C"));
2139
- console.log(chalk16.gray(" s\uD0A4 \u2192 \uC124\uC815\uC5D0\uC11C \uC11C\uBC84 \uC5F0\uACB0"));
2140
- return;
2141
- }
2142
- renderList(state.workflows, state.selectedIdx, `\uC6CC\uD06C\uD50C\uB85C\uC6B0 (${state.workflows.length}\uAC1C)`);
2408
+ async function workflowList2() {
2409
+ const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2410
+ const wfs = await getWorkflowListDetail2();
2411
+ if (!wfs.length) return "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC5C6\uC74C.";
2412
+ return wfs.map((w, i) => {
2413
+ const deployed = w.is_deployed;
2414
+ const dk = w.deploy_key;
2415
+ const tag = deployed ? " [\uBC30\uD3EC\uB428]" : "";
2416
+ return `${i + 1}. ${w.workflow_name}${tag}
2417
+ ID: ${w.workflow_id ?? w.id}
2418
+ deploy_key: ${dk || "\uC5C6\uC74C"}`;
2419
+ }).join("\n");
2143
2420
  }
2144
- function renderDocTab(state) {
2145
- if (state.documents.length === 0) {
2146
- console.log(chalk16.gray(" \uC11C\uBC84 \uBBF8\uC5F0\uACB0 \uB610\uB294 \uBB38\uC11C \uC5C6\uC74C"));
2147
- return;
2148
- }
2149
- renderList(state.documents, state.selectedIdx, `\uBB38\uC11C (${state.documents.length}\uAC1C)`);
2421
+ async function workflowRun2(args) {
2422
+ const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2423
+ const { randomUUID: randomUUID4 } = await import("crypto");
2424
+ const result = await executeWorkflow2({
2425
+ workflow_id: args.workflow_id,
2426
+ workflow_name: args.workflow_name,
2427
+ input_data: args.input_data,
2428
+ interaction_id: `cli_${randomUUID4().slice(0, 8)}`,
2429
+ deploy_key: args.deploy_key
2430
+ });
2431
+ if (result.content) return String(result.content);
2432
+ if (result.success === false) return `\uC624\uB958: ${result.error ?? result.message}`;
2433
+ return JSON.stringify(result, null, 2).slice(0, 2e3);
2150
2434
  }
2151
- function renderOntologyTab() {
2152
- console.log(chalk16.bold(" \uC628\uD1A8\uB85C\uC9C0 (GraphRAG)"));
2153
- console.log();
2154
- console.log(chalk16.gray(" Enter\uB97C \uB20C\uB7EC \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758 \uBAA8\uB4DC\uB85C \uC9C4\uC785\uD569\uB2C8\uB2E4."));
2155
- console.log(chalk16.gray(" \uC9C0\uC2DD \uADF8\uB798\uD504 \uAE30\uBC18 \uC9C8\uBB38-\uB2F5\uBCC0\uC744 \uC218\uD589\uD569\uB2C8\uB2E4."));
2156
- console.log();
2435
+ async function workflowInfo2(args) {
2436
+ const { getWorkflowDetail: getWorkflowDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2437
+ const detail = await getWorkflowDetail2(args.workflow_id);
2438
+ const nodes = detail.nodes?.length ?? 0;
2439
+ const edges = detail.edges?.length ?? 0;
2440
+ return `\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name}
2441
+ ID: ${detail.id}
2442
+ \uB178\uB4DC: ${nodes}\uAC1C
2443
+ \uC5E3\uC9C0: ${edges}\uAC1C`;
2157
2444
  }
2158
- function renderSettingsTab() {
2159
- const provider = getDefaultProvider();
2445
+ async function collectionList() {
2446
+ const { listCollections: listCollections2 } = await Promise.resolve().then(() => (init_document(), document_exports));
2447
+ const cols = await listCollections2();
2448
+ if (!cols.length) return "\uCEEC\uB809\uC158 \uC5C6\uC74C.";
2449
+ return cols.map((c, i) => {
2450
+ const shared = c.is_shared ? ` [\uACF5\uC720:${c.share_group}]` : "";
2451
+ return `${i + 1}. ${c.collection_make_name}${shared}
2452
+ \uBB38\uC11C: ${c.total_documents}\uAC1C \xB7 \uCCAD\uD06C: ${c.total_chunks}\uAC1C \xB7 \uBAA8\uB378: ${c.init_embedding_model ?? "-"}`;
2453
+ }).join("\n");
2454
+ }
2455
+ async function serverStatus() {
2160
2456
  const server = getServer();
2161
2457
  const auth = getAuth();
2162
- const env = getActiveEnvironment();
2163
- const lines = [
2164
- `\uD504\uB85C\uBC14\uC774\uB354: ${provider ? `${provider.name} \xB7 ${provider.model}` : chalk16.red("\uBBF8\uC124\uC815")}`,
2165
- `\uC11C\uBC84: ${server ?? chalk16.red("\uBBF8\uC5F0\uACB0")}`,
2166
- `\uC0AC\uC6A9\uC790: ${auth?.username ?? "-"}`,
2167
- `\uD658\uACBD: ${env?.name ?? "-"}`
2168
- ];
2169
- renderPanel("\uD604\uC7AC \uC124\uC815", lines);
2170
- console.log();
2171
- console.log(chalk16.gray(" Enter \u2192 AI \uCC44\uD305\uC5D0\uC11C /connect, /provider, /env \uC0AC\uC6A9"));
2458
+ return `\uC11C\uBC84: ${server}
2459
+ \uC0AC\uC6A9\uC790: ${auth?.username}
2460
+ User ID: ${auth?.userId}`;
2172
2461
  }
2173
- function getCurrentListLength(state) {
2174
- switch (state.activeTab) {
2175
- case 1:
2176
- return state.workflows.length;
2177
- case 2:
2178
- return state.documents.length;
2179
- default:
2180
- return 0;
2181
- }
2462
+ async function executionHistory(args) {
2463
+ const { getIOLogs: getIOLogs2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2464
+ const limit = args.limit || 10;
2465
+ const logs = await getIOLogs2(void 0, limit);
2466
+ if (!logs.length) return "\uC2E4\uD589 \uC774\uB825 \uC5C6\uC74C.";
2467
+ return logs.map(
2468
+ (l, i) => `${i + 1}. [${l.created_at ?? ""}]
2469
+ \uC785\uB825: ${(l.input_data ?? "").slice(0, 80)}
2470
+ \uCD9C\uB825: ${(l.output_data ?? "").slice(0, 80)}`
2471
+ ).join("\n");
2182
2472
  }
2183
- async function handleEnter(state, rl) {
2184
- if (state.activeTab === 0 || state.activeTab === 3 || state.activeTab === 4) {
2185
- cleanup(rl);
2186
- await agentRepl();
2187
- await dashboard();
2188
- return;
2473
+
2474
+ // src/mcp/client.ts
2475
+ import { spawn } from "child_process";
2476
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
2477
+ import { join as join3 } from "path";
2478
+ import { createInterface as createInterface4 } from "readline";
2479
+ var McpClient = class {
2480
+ process = null;
2481
+ requestId = 0;
2482
+ pending = /* @__PURE__ */ new Map();
2483
+ serverName;
2484
+ config;
2485
+ tools = [];
2486
+ constructor(serverName, config) {
2487
+ this.serverName = serverName;
2488
+ this.config = config;
2489
+ }
2490
+ async start() {
2491
+ this.process = spawn(this.config.command, this.config.args ?? [], {
2492
+ stdio: ["pipe", "pipe", "pipe"],
2493
+ env: { ...process.env, ...this.config.env }
2494
+ });
2495
+ const rl = createInterface4({ input: this.process.stdout });
2496
+ rl.on("line", (line) => {
2497
+ try {
2498
+ const msg = JSON.parse(line);
2499
+ if (msg.id !== void 0 && this.pending.has(msg.id)) {
2500
+ const p = this.pending.get(msg.id);
2501
+ this.pending.delete(msg.id);
2502
+ if (msg.error) {
2503
+ p.reject(new Error(msg.error.message));
2504
+ } else {
2505
+ p.resolve(msg.result);
2506
+ }
2507
+ }
2508
+ } catch {
2509
+ }
2510
+ });
2511
+ this.process.on("error", (err) => {
2512
+ console.error(`MCP [${this.serverName}] \uD504\uB85C\uC138\uC2A4 \uC624\uB958:`, err.message);
2513
+ });
2514
+ await this.send("initialize", {
2515
+ protocolVersion: "2024-11-05",
2516
+ capabilities: {},
2517
+ clientInfo: { name: "open-xgen", version: "0.3.0" }
2518
+ });
2519
+ await this.send("notifications/initialized", {});
2520
+ }
2521
+ send(method, params) {
2522
+ return new Promise((resolve, reject) => {
2523
+ const id = ++this.requestId;
2524
+ const request = { jsonrpc: "2.0", id, method, params };
2525
+ this.pending.set(id, { resolve, reject });
2526
+ const timeout = setTimeout(() => {
2527
+ this.pending.delete(id);
2528
+ reject(new Error(`MCP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3: ${method}`));
2529
+ }, 15e3);
2530
+ this.pending.set(id, {
2531
+ resolve: (v) => {
2532
+ clearTimeout(timeout);
2533
+ resolve(v);
2534
+ },
2535
+ reject: (e) => {
2536
+ clearTimeout(timeout);
2537
+ reject(e);
2538
+ }
2539
+ });
2540
+ this.process?.stdin?.write(JSON.stringify(request) + "\n");
2541
+ });
2189
2542
  }
2190
- if (state.activeTab === 1 && state.workflows.length > 0) {
2191
- const selected = state.workflows[state.selectedIdx];
2192
- cleanup(rl);
2193
- console.log(chalk16.green(`
2194
- \u2713 ${selected.label} \uC120\uD0DD\uB428
2195
- `));
2196
- await agentRepl();
2197
- await dashboard();
2198
- return;
2543
+ async listTools() {
2544
+ const result = await this.send("tools/list", {});
2545
+ this.tools = result.tools ?? [];
2546
+ return this.tools;
2199
2547
  }
2200
- }
2201
- async function loadData(state) {
2202
- const server = getServer();
2203
- const auth = getAuth();
2204
- if (!server || !auth) return;
2205
- try {
2206
- const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2207
- const wfs = await getWorkflowListDetail2();
2208
- state.workflows = wfs.map((w) => {
2209
- const deployed = w.is_deployed;
2210
- return {
2211
- label: w.workflow_name,
2212
- detail: (w.workflow_id ?? w.id ?? "").toString(),
2213
- tag: deployed ? chalk16.green("[\uBC30\uD3EC]") : void 0
2214
- };
2215
- });
2216
- } catch {
2548
+ async callTool(name, args) {
2549
+ const result = await this.send("tools/call", { name, arguments: args });
2550
+ return result.content?.map((c) => c.text ?? "").join("\n") ?? "";
2217
2551
  }
2218
- try {
2219
- const { listDocuments: listDocuments2 } = await Promise.resolve().then(() => (init_document(), document_exports));
2220
- const docs = await listDocuments2();
2221
- state.documents = docs.map((d) => ({
2222
- label: d.file_name ?? d.name ?? "-",
2223
- detail: d.file_type ?? "-",
2224
- tag: d.status ? chalk16.gray(`[${d.status}]`) : void 0
2552
+ getOpenAITools() {
2553
+ return this.tools.map((t) => ({
2554
+ type: "function",
2555
+ function: {
2556
+ name: `mcp_${this.serverName}_${t.name}`,
2557
+ description: `[MCP:${this.serverName}] ${t.description ?? t.name}`,
2558
+ parameters: t.inputSchema ?? { type: "object", properties: {} }
2559
+ }
2225
2560
  }));
2226
- } catch {
2227
2561
  }
2228
- }
2229
- function cleanup(rl) {
2230
- if (process.stdin.isTTY) process.stdin.setRawMode(false);
2231
- rl.close();
2232
- clearScreen();
2233
- }
2234
- var TABS;
2235
- var init_dashboard = __esm({
2236
- "src/dashboard/index.ts"() {
2237
- "use strict";
2238
- init_renderer();
2239
- init_store();
2240
- init_agent();
2241
- TABS = ["\u{1F4AC} Chat", "\u{1F4CB} Workflows", "\u{1F4C4} Documents", "\u{1F50D} Ontology", "\u2699 Settings"];
2562
+ stop() {
2563
+ this.process?.kill();
2564
+ this.process = null;
2242
2565
  }
2243
- });
2244
-
2245
- // src/index.ts
2246
- import { Command } from "commander";
2247
- import chalk17 from "chalk";
2248
-
2249
- // src/commands/config.ts
2250
- init_store();
2251
- init_client();
2252
- init_format();
2253
- import chalk2 from "chalk";
2254
- function registerConfigCommand(program2) {
2255
- const config = program2.command("config").description("XGEN CLI \uC124\uC815 \uAD00\uB9AC");
2256
- config.command("set-server <url>").description("XGEN \uC11C\uBC84 URL \uC124\uC815").action((url) => {
2257
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
2258
- printError("URL\uC740 http:// \uB610\uB294 https://\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4");
2259
- process.exit(1);
2566
+ };
2567
+ function loadMcpConfig(dir) {
2568
+ const searchPaths = [
2569
+ dir ? join3(dir, ".mcp.json") : null,
2570
+ join3(process.cwd(), ".mcp.json"),
2571
+ join3(process.env.HOME ?? "", ".mcp.json")
2572
+ ].filter(Boolean);
2573
+ for (const p of searchPaths) {
2574
+ if (existsSync3(p)) {
2575
+ try {
2576
+ return JSON.parse(readFileSync4(p, "utf-8"));
2577
+ } catch {
2578
+ continue;
2579
+ }
2260
2580
  }
2261
- setServer(url);
2262
- resetClient();
2263
- printSuccess(`\uC11C\uBC84 \uC124\uC815 \uC644\uB8CC: ${chalk2.underline(url)}`);
2264
- });
2265
- config.command("get-server").description("\uD604\uC7AC \uC124\uC815\uB41C \uC11C\uBC84 URL \uD655\uC778").action(() => {
2266
- const server = getServer();
2267
- if (server) {
2268
- console.log(server);
2269
- } else {
2270
- printError("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
2271
- console.log(" \uC124\uC815: xgen config set-server <url>");
2581
+ }
2582
+ return null;
2583
+ }
2584
+ var McpManager = class {
2585
+ clients = /* @__PURE__ */ new Map();
2586
+ async startAll(config) {
2587
+ for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
2588
+ if (serverConfig.type !== "stdio") continue;
2589
+ try {
2590
+ const client2 = new McpClient(name, serverConfig);
2591
+ await client2.start();
2592
+ await client2.listTools();
2593
+ this.clients.set(name, client2);
2594
+ } catch (err) {
2595
+ console.error(`MCP [${name}] \uC2DC\uC791 \uC2E4\uD328:`, err.message);
2596
+ }
2272
2597
  }
2273
- });
2274
- config.command("list").description("\uC804\uCCB4 \uC124\uC815 \uD655\uC778").action(() => {
2275
- const cfg = getConfig();
2276
- console.log(chalk2.bold("\nXGEN CLI \uC124\uC815"));
2277
- console.log(chalk2.gray("\u2500".repeat(40)));
2278
- printKeyValue("\uC11C\uBC84", cfg.server);
2279
- printKeyValue("\uAE30\uBCF8 \uC6CC\uD06C\uD50C\uB85C\uC6B0", cfg.defaultWorkflow);
2280
- printKeyValue("\uD14C\uB9C8", cfg.theme);
2281
- printKeyValue("\uC2A4\uD2B8\uB9BC \uB85C\uADF8", String(cfg.streamLogs));
2282
- console.log();
2283
- });
2284
- config.command("set <key> <value>").description("\uC124\uC815 \uAC12 \uBCC0\uACBD").action((key, value) => {
2285
- const allowedKeys = ["defaultWorkflow", "theme", "streamLogs"];
2286
- if (!allowedKeys.includes(key)) {
2287
- printError(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}`);
2288
- console.log(` \uC0AC\uC6A9 \uAC00\uB2A5: ${allowedKeys.join(", ")}`);
2289
- process.exit(1);
2598
+ }
2599
+ getAllTools() {
2600
+ const tools2 = [];
2601
+ for (const client2 of this.clients.values()) {
2602
+ tools2.push(...client2.getOpenAITools());
2290
2603
  }
2291
- const parsed = key === "streamLogs" ? value === "true" : value;
2292
- setConfig({ [key]: parsed });
2293
- printSuccess(`${key} = ${value}`);
2294
- });
2295
- }
2604
+ return tools2;
2605
+ }
2606
+ async callTool(fullName, args) {
2607
+ const parts = fullName.split("_");
2608
+ if (parts.length < 3 || parts[0] !== "mcp") return `Unknown MCP tool: ${fullName}`;
2609
+ const serverName = parts[1];
2610
+ const toolName = parts.slice(2).join("_");
2611
+ const client2 = this.clients.get(serverName);
2612
+ if (!client2) return `MCP \uC11C\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${serverName}`;
2613
+ return client2.callTool(toolName, args);
2614
+ }
2615
+ isMcpTool(name) {
2616
+ return name.startsWith("mcp_");
2617
+ }
2618
+ stopAll() {
2619
+ for (const client2 of this.clients.values()) {
2620
+ client2.stop();
2621
+ }
2622
+ this.clients.clear();
2623
+ }
2624
+ get serverCount() {
2625
+ return this.clients.size;
2626
+ }
2627
+ getServerNames() {
2628
+ return [...this.clients.keys()];
2629
+ }
2630
+ };
2296
2631
 
2297
- // src/commands/login.ts
2298
- init_auth();
2299
- init_store();
2300
- init_format();
2301
- import chalk3 from "chalk";
2302
- import { createInterface } from "readline";
2303
- function prompt(question, hidden = false) {
2304
- return new Promise((resolve) => {
2305
- const rl = createInterface({
2306
- input: process.stdin,
2307
- output: process.stdout
2308
- });
2309
- if (hidden) {
2310
- process.stdout.write(question);
2311
- const stdin = process.stdin;
2312
- const wasRaw = stdin.isRaw;
2313
- if (stdin.isTTY) stdin.setRawMode(true);
2314
- let password = "";
2315
- const onData = (ch) => {
2316
- const c = ch.toString("utf8");
2317
- if (c === "\n" || c === "\r" || c === "") {
2318
- if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
2319
- stdin.removeListener("data", onData);
2320
- process.stdout.write("\n");
2321
- rl.close();
2322
- resolve(password);
2323
- } else if (c === "") {
2324
- process.exit(0);
2325
- } else if (c === "\x7F" || c === "\b") {
2326
- if (password.length > 0) {
2327
- password = password.slice(0, -1);
2328
- process.stdout.write("\b \b");
2329
- }
2330
- } else {
2331
- password += c;
2332
- process.stdout.write("*");
2333
- }
2334
- };
2335
- stdin.on("data", onData);
2336
- } else {
2337
- rl.question(question, (answer) => {
2338
- rl.close();
2339
- resolve(answer.trim());
2340
- });
2341
- }
2342
- });
2632
+ // src/commands/agent.ts
2633
+ init_provider();
2634
+ init_ui();
2635
+ function buildSystemPrompt() {
2636
+ const server = getServer();
2637
+ const auth = getAuth();
2638
+ const env = getActiveEnvironment();
2639
+ let prompt2 = `You are OPEN XGEN. Terminal AI agent.
2640
+
2641
+ CRITICAL RULES:
2642
+ - Be extremely concise. No menus, no numbered lists of options, no "what would you like to do" questions.
2643
+ - Just DO things. If the user says "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D" \u2192 call xgen_workflow_list immediately, show results.
2644
+ - If the user says a number after seeing a list, treat it as selection and act on it.
2645
+ - If the user says "\uC2E4\uD589" or "run" \u2192 call the tool immediately with the context you have.
2646
+ - Never ask "which option do you prefer" or show menus. Infer intent and act.
2647
+ - Respond in the user's language. Korean if they speak Korean.
2648
+ - Max 2-3 sentences per response unless showing data.
2649
+
2650
+ TOOLS:
2651
+ - Coding: file_read, file_write, file_edit, bash, grep, list_files, sandbox_run
2652
+ - XGEN: xgen_workflow_list, xgen_workflow_run, xgen_workflow_info, xgen_doc_list, xgen_ontology_query, xgen_server_status, xgen_execution_history`;
2653
+ if (server && auth) {
2654
+ prompt2 += `
2655
+
2656
+ XGEN CONNECTED: ${server} as ${auth.username} (${env?.name ?? "default"})
2657
+ - Workflow execute uses deploy_key for deployed workflows.
2658
+ - If workflow execution returns 404, it means the Istio routing blocks direct stream access. Use deploy endpoint.`;
2659
+ } else {
2660
+ prompt2 += `
2661
+ XGEN: Not connected. Tell user to run /connect.`;
2662
+ }
2663
+ return prompt2;
2343
2664
  }
2344
- function registerLoginCommand(program2) {
2345
- program2.command("login").description("XGEN \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC778").option("-e, --email <email>", "\uC774\uBA54\uC77C").option("-p, --password <password>", "\uBE44\uBC00\uBC88\uD638").action(async (opts) => {
2346
- const server = requireServer();
2347
- printHeader("XGEN Login");
2348
- console.log(chalk3.gray(`\uC11C\uBC84: ${server}
2665
+ var mcpManager = null;
2666
+ async function agentRepl() {
2667
+ let provider = getDefaultProvider();
2668
+ if (!provider) {
2669
+ provider = await guidedProviderSetup();
2670
+ if (!provider) process.exit(1);
2671
+ }
2672
+ const client2 = createLLMClient(provider);
2673
+ const allTools = [...getAllToolDefs(), ...definitions];
2674
+ const builtinNames = getToolNames();
2675
+ const mcpConfig = loadMcpConfig();
2676
+ if (mcpConfig && Object.keys(mcpConfig.mcpServers).length > 0) {
2677
+ mcpManager = new McpManager();
2678
+ try {
2679
+ await mcpManager.startAll(mcpConfig);
2680
+ if (mcpManager.serverCount > 0) allTools.push(...mcpManager.getAllTools());
2681
+ } catch {
2682
+ }
2683
+ }
2684
+ const messages = [{ role: "system", content: buildSystemPrompt() }];
2685
+ console.log(welcome());
2686
+ console.log();
2687
+ const server = getServer();
2688
+ const auth = getAuth();
2689
+ const env = getActiveEnvironment();
2690
+ console.log(chalk12.gray(` ${provider.name} \xB7 ${provider.model}`));
2691
+ if (server && auth) {
2692
+ console.log(chalk12.gray(` ${env?.name ?? "XGEN"} \xB7 ${auth.username}@${server.replace("https://", "")}`));
2693
+ }
2694
+ console.log(chalk12.gray(` ${builtinNames.length} \uB3C4\uAD6C + ${definitions.length} XGEN${mcpManager?.serverCount ? ` + ${mcpManager.getAllTools().length} MCP` : ""}`));
2695
+ console.log(chalk12.gray(` /help \xB7 /connect \xB7 /env \xB7 /provider \xB7 /exit
2349
2696
  `));
2350
- let email = opts.email;
2351
- let password = opts.password;
2352
- if (!email) {
2353
- email = await prompt(chalk3.white("\uC774\uBA54\uC77C: "));
2697
+ const rl = createInterface5({ input: process.stdin, output: process.stdout });
2698
+ const askUser = () => new Promise((resolve) => rl.question(chalk12.cyan(" \u276F "), (a) => resolve(a.trim())));
2699
+ process.on("SIGINT", () => {
2700
+ console.log(chalk12.gray("\n \u{1F44B}\n"));
2701
+ mcpManager?.stopAll();
2702
+ rl.close();
2703
+ process.exit(0);
2704
+ });
2705
+ while (true) {
2706
+ const input = await askUser();
2707
+ if (!input) continue;
2708
+ if (input === "/exit" || input === "exit") {
2709
+ console.log(chalk12.gray("\n \u{1F44B}\n"));
2710
+ mcpManager?.stopAll();
2711
+ rl.close();
2712
+ break;
2354
2713
  }
2355
- if (!password) {
2356
- password = await prompt(chalk3.white("\uBE44\uBC00\uBC88\uD638: "), true);
2714
+ if (input === "/help") {
2715
+ console.log(`
2716
+ ${chalk12.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
2717
+ ${chalk12.cyan("/connect")} XGEN \uC11C\uBC84 \uC5F0\uACB0 + \uB85C\uADF8\uC778
2718
+ ${chalk12.cyan("/env")} \uD658\uACBD \uC804\uD658 (\uBCF8\uC0AC/\uC81C\uC8FC/\uB86F\uB370\uBAB0)
2719
+ ${chalk12.cyan("/provider")} \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD
2720
+ ${chalk12.cyan("/tools")} \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB3C4\uAD6C \uBAA9\uB85D
2721
+ ${chalk12.cyan("/status")} \uD604\uC7AC \uC5F0\uACB0 \uC0C1\uD0DC
2722
+ ${chalk12.cyan("/clear")} \uB300\uD654 \uCD08\uAE30\uD654
2723
+ ${chalk12.cyan("/exit")} \uC885\uB8CC
2724
+ `);
2725
+ continue;
2357
2726
  }
2358
- if (!email || !password) {
2359
- printError("\uC774\uBA54\uC77C\uACFC \uBE44\uBC00\uBC88\uD638\uB97C \uBAA8\uB450 \uC785\uB825\uD558\uC138\uC694");
2360
- process.exit(1);
2727
+ if (input === "/clear") {
2728
+ messages.length = 0;
2729
+ messages.push({ role: "system", content: buildSystemPrompt() });
2730
+ console.log(chalk12.gray(" \uB300\uD654 \uCD08\uAE30\uD654\uB428.\n"));
2731
+ continue;
2361
2732
  }
2362
- try {
2363
- const result = await apiLogin(email, password);
2364
- if (result.success && result.access_token) {
2365
- setAuth({
2366
- accessToken: result.access_token,
2367
- refreshToken: result.refresh_token ?? "",
2368
- userId: result.user_id ?? "",
2369
- username: result.username ?? "",
2370
- isAdmin: false,
2371
- expiresAt: null
2372
- });
2373
- console.log();
2374
- printSuccess(`\uB85C\uADF8\uC778 \uC131\uACF5! ${chalk3.bold(result.username ?? email)}`);
2375
- } else {
2376
- printError(result.message || "\uB85C\uADF8\uC778 \uC2E4\uD328");
2377
- process.exit(1);
2733
+ if (input === "/status") {
2734
+ const p = getDefaultProvider();
2735
+ const s = getServer();
2736
+ const a = getAuth();
2737
+ const e = getActiveEnvironment();
2738
+ console.log();
2739
+ console.log(` ${chalk12.bold("\uD504\uB85C\uBC14\uC774\uB354")} ${p ? `${p.name} \xB7 ${p.model}` : chalk12.red("\uBBF8\uC124\uC815")}`);
2740
+ console.log(` ${chalk12.bold("\uC11C\uBC84")} ${s && a ? `${a.username}@${s.replace("https://", "")}` : chalk12.red("\uBBF8\uC5F0\uACB0")}`);
2741
+ console.log(` ${chalk12.bold("\uD658\uACBD")} ${e?.name ?? "\uC5C6\uC74C"} (${getEnvironments().length}\uAC1C \uB4F1\uB85D)`);
2742
+ if (mcpManager?.serverCount) {
2743
+ console.log(` ${chalk12.bold("MCP")} ${mcpManager.getServerNames().join(", ")}`);
2378
2744
  }
2379
- } catch (err) {
2380
- const msg = err?.response?.data?.message ?? err?.response?.data?.detail ?? err.message;
2381
- printError(`\uB85C\uADF8\uC778 \uC2E4\uD328: ${msg}`);
2382
- process.exit(1);
2745
+ console.log();
2746
+ continue;
2383
2747
  }
2384
- });
2385
- program2.command("logout").description("\uB85C\uADF8\uC544\uC6C3").action(async () => {
2386
- const { clearAuth: clearAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
2387
- clearAuth2();
2388
- printSuccess("\uB85C\uADF8\uC544\uC6C3 \uC644\uB8CC");
2389
- });
2390
- program2.command("whoami").description("\uD604\uC7AC \uB85C\uADF8\uC778\uB41C \uC0AC\uC6A9\uC790 \uC815\uBCF4").action(async () => {
2391
- const auth = getAuth();
2392
- if (!auth) {
2393
- printError("\uB85C\uADF8\uC778\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. xgen login \uC2E4\uD589\uD558\uC138\uC694");
2394
- process.exit(1);
2748
+ if (input === "/tools") {
2749
+ console.log(`
2750
+ ${chalk12.bold("\uCF54\uB529")} ${builtinNames.join(", ")}`);
2751
+ console.log(` ${chalk12.bold("XGEN")} ${definitions.map((t) => t.function.name).join(", ")}`);
2752
+ if (mcpManager?.serverCount) {
2753
+ console.log(` ${chalk12.bold("MCP")} ${mcpManager.getAllTools().map((t) => t.function.name).join(", ")}`);
2754
+ }
2755
+ console.log();
2756
+ continue;
2395
2757
  }
2396
- const server = requireServer();
2397
- console.log(chalk3.bold("\n\uD604\uC7AC \uC0AC\uC6A9\uC790"));
2398
- console.log(chalk3.gray("\u2500".repeat(30)));
2399
- console.log(` ${chalk3.gray("\uC11C\uBC84:")} ${server}`);
2400
- console.log(` ${chalk3.gray("\uC0AC\uC6A9\uC790:")} ${chalk3.bold(auth.username)}`);
2401
- console.log(` ${chalk3.gray("User ID:")} ${auth.userId}`);
2758
+ if (input === "/connect") {
2759
+ await connectServer();
2760
+ messages[0] = { role: "system", content: buildSystemPrompt() };
2761
+ continue;
2762
+ }
2763
+ if (input === "/env") {
2764
+ await switchEnv();
2765
+ messages[0] = { role: "system", content: buildSystemPrompt() };
2766
+ continue;
2767
+ }
2768
+ if (input === "/provider") {
2769
+ const { guidedProviderSetup: setup } = await Promise.resolve().then(() => (init_provider(), provider_exports));
2770
+ await setup();
2771
+ console.log(chalk12.gray(" \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD\uB428. /exit \uD6C4 \uC7AC\uC2DC\uC791\uD558\uC138\uC694.\n"));
2772
+ continue;
2773
+ }
2774
+ messages.push({ role: "user", content: input });
2402
2775
  try {
2403
- const { apiValidate: apiValidate2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
2404
- const result = await apiValidate2(auth.accessToken);
2405
- if (result.valid) {
2406
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.green("\uD65C\uC131")}`);
2407
- if (result.is_admin) {
2408
- console.log(` ${chalk3.gray("\uAD8C\uD55C:")} ${chalk3.yellow("\uAD00\uB9AC\uC790")}`);
2409
- }
2410
- if (result.user_type) {
2411
- console.log(` ${chalk3.gray("\uC720\uD615:")} ${result.user_type}`);
2412
- }
2413
- } else {
2414
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.red("\uD1A0\uD070 \uB9CC\uB8CC")}`);
2415
- }
2416
- } catch {
2417
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.yellow("\uAC80\uC99D \uBD88\uAC00 (\uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328)")}`);
2776
+ await runLoop(client2, provider.model, messages, allTools);
2777
+ } catch (err) {
2778
+ console.log(chalk12.red(`
2779
+ \uC624\uB958: ${err.message}
2780
+ `));
2418
2781
  }
2419
- console.log();
2420
- });
2782
+ }
2421
2783
  }
2422
-
2423
- // src/commands/workflow/list.ts
2424
- init_store();
2425
- init_workflow();
2426
- init_format();
2427
- import chalk4 from "chalk";
2428
- async function workflowList(opts) {
2429
- requireAuth();
2430
- try {
2431
- if (opts.detail) {
2432
- const workflows = await getWorkflowListDetail();
2433
- if (!workflows || workflows.length === 0) {
2434
- console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2435
- return;
2436
- }
2437
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
2438
- console.log();
2439
- printTable(
2440
- ["#", "ID", "\uC774\uB984", "\uBC30\uD3EC", "\uC5C5\uB370\uC774\uD2B8"],
2441
- workflows.map((w, i) => [
2442
- String(i + 1),
2443
- (w.workflow_id ?? w.id ?? "-").slice(0, 12),
2444
- truncate(w.workflow_name ?? "-", 30),
2445
- w.is_deployed ? chalk4.green("\uBC30\uD3EC\uB428") : chalk4.gray("\uBBF8\uBC30\uD3EC"),
2446
- formatDate(w.updated_at)
2447
- ])
2448
- );
2449
- } else {
2450
- const workflows = await listWorkflows();
2451
- if (!workflows || workflows.length === 0) {
2452
- console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2453
- return;
2454
- }
2455
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
2456
- console.log();
2457
- printTable(
2458
- ["#", "ID", "\uC774\uB984"],
2459
- workflows.map((w, i) => [
2460
- String(i + 1),
2461
- (w.workflow_id ?? w.id ?? "-").slice(0, 12),
2462
- w.workflow_name ?? "-"
2463
- ])
2464
- );
2465
- }
2466
- console.log();
2467
- } catch (err) {
2468
- const msg = err.message;
2469
- printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${msg}`);
2470
- process.exit(1);
2471
- }
2472
- }
2473
-
2474
- // src/commands/workflow/info.ts
2475
- init_store();
2476
- init_workflow();
2477
- init_format();
2478
- import chalk5 from "chalk";
2479
- async function workflowInfo(workflowId) {
2480
- requireAuth();
2481
- try {
2482
- const detail = await getWorkflowDetail(workflowId);
2483
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name ?? workflowId}`);
2484
- console.log();
2485
- printKeyValue("ID", detail.id);
2486
- printKeyValue("\uC774\uB984", detail.workflow_name);
2487
- printKeyValue("\uC124\uBA85", detail.description ?? "(\uC5C6\uC74C)");
2488
- if (detail.nodes && Array.isArray(detail.nodes)) {
2489
- console.log();
2490
- console.log(chalk5.bold(" \uB178\uB4DC \uAD6C\uC131:"));
2491
- for (const node of detail.nodes) {
2492
- const label = node.data?.label ?? node.id;
2493
- const type = node.data?.type ?? "unknown";
2494
- console.log(` ${chalk5.cyan("\u2022")} ${label} ${chalk5.gray(`(${type})`)}`);
2495
- }
2496
- }
2497
- if (detail.parameters && Object.keys(detail.parameters).length > 0) {
2498
- console.log();
2499
- console.log(chalk5.bold(" \uD30C\uB77C\uBBF8\uD130:"));
2500
- for (const [key, val] of Object.entries(detail.parameters)) {
2501
- console.log(` ${chalk5.gray(key)}: ${JSON.stringify(val)}`);
2502
- }
2503
- }
2504
- console.log();
2505
- } catch (err) {
2506
- const msg = err.message;
2507
- printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC870\uD68C \uC2E4\uD328: ${msg}`);
2508
- process.exit(1);
2509
- }
2510
- }
2511
-
2512
- // src/commands/workflow/run.ts
2513
- init_store();
2514
- init_workflow();
2515
- import chalk7 from "chalk";
2516
- import { randomUUID } from "crypto";
2517
-
2518
- // src/utils/sse.ts
2519
- async function parseSSEStream(stream, onEvent, onDone, onError) {
2520
- let buffer = "";
2521
- return new Promise((resolve, reject) => {
2522
- stream.on("data", (chunk) => {
2523
- buffer += chunk.toString();
2524
- const parts = buffer.split("\n\n");
2525
- buffer = parts.pop() ?? "";
2526
- for (const part of parts) {
2527
- const lines = part.split("\n");
2528
- let data = "";
2529
- for (const line of lines) {
2530
- if (line.startsWith("data: ")) {
2531
- data += line.slice(6);
2532
- } else if (line.startsWith("data:")) {
2533
- data += line.slice(5);
2534
- }
2535
- }
2536
- if (!data) continue;
2537
- try {
2538
- const event = JSON.parse(data);
2539
- onEvent(event);
2540
- } catch {
2541
- onEvent({ type: "token", content: data });
2542
- }
2543
- }
2544
- });
2545
- stream.on("end", () => {
2546
- if (buffer.trim()) {
2547
- const lines = buffer.split("\n");
2548
- for (const line of lines) {
2549
- if (line.startsWith("data: ")) {
2550
- try {
2551
- const event = JSON.parse(line.slice(6));
2552
- onEvent(event);
2553
- } catch {
2554
- onEvent({ type: "token", content: line.slice(6) });
2555
- }
2556
- }
2557
- }
2784
+ async function runLoop(client2, model, messages, tools2) {
2785
+ for (let i = 0; i < 20; i++) {
2786
+ let first = true;
2787
+ const result = await streamChat(client2, model, messages, tools2, (delta) => {
2788
+ if (first) {
2789
+ process.stdout.write(chalk12.green("\n ") + "");
2790
+ first = false;
2558
2791
  }
2559
- onDone?.();
2560
- resolve();
2561
- });
2562
- stream.on("error", (err) => {
2563
- onError?.(err);
2564
- reject(err);
2565
- });
2566
- });
2567
- }
2568
-
2569
- // src/commands/workflow/run.ts
2570
- init_format();
2571
-
2572
- // src/utils/markdown.ts
2573
- import chalk6 from "chalk";
2574
- var CODE_BLOCK_RE = /```(\w*)\n([\s\S]*?)```/g;
2575
- var INLINE_CODE_RE = /`([^`]+)`/g;
2576
- var BOLD_RE = /\*\*(.+?)\*\*/g;
2577
- var HEADING_RE = /^(#{1,3})\s+(.+)$/gm;
2578
- var LIST_RE = /^(\s*)[-*]\s+(.+)$/gm;
2579
- var LINK_RE = /\[([^\]]+)\]\(([^)]+)\)/g;
2580
- function renderMarkdown(text) {
2581
- let result = text;
2582
- result = result.replace(CODE_BLOCK_RE, (_match, lang, code) => {
2583
- const trimmed = code.trimEnd();
2584
- const header = lang ? chalk6.gray(` \u2500\u2500 ${lang} \u2500\u2500`) : chalk6.gray(" \u2500\u2500 code \u2500\u2500");
2585
- const lines = trimmed.split("\n").map((l) => chalk6.white(` ${l}`)).join("\n");
2586
- return `
2587
- ${header}
2588
- ${lines}
2589
- ${chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
2590
- `;
2591
- });
2592
- result = result.replace(INLINE_CODE_RE, (_m, code) => chalk6.cyan(`\`${code}\``));
2593
- result = result.replace(BOLD_RE, (_m, text2) => chalk6.bold(text2));
2594
- result = result.replace(HEADING_RE, (_m, hashes, text2) => {
2595
- if (hashes.length === 1) return chalk6.bold.underline(text2);
2596
- if (hashes.length === 2) return chalk6.bold(text2);
2597
- return chalk6.bold.dim(text2);
2598
- });
2599
- result = result.replace(LIST_RE, (_m, indent, text2) => `${indent}${chalk6.cyan("\u2022")} ${text2}`);
2600
- result = result.replace(LINK_RE, (_m, label, url) => `${chalk6.blue.underline(label)} ${chalk6.gray(`(${url})`)}`);
2601
- return result;
2602
- }
2603
-
2604
- // src/commands/workflow/run.ts
2605
- async function workflowRun(workflowId, input, opts) {
2606
- const auth = requireAuth();
2607
- let workflowName = workflowId;
2608
- try {
2609
- const detail = await getWorkflowDetail(workflowId);
2610
- workflowName = detail.workflow_name ?? workflowId;
2611
- } catch {
2612
- }
2613
- if (!input) {
2614
- if (opts.interactive || !process.stdin.isTTY) {
2615
- const { createInterface: createInterface8 } = await import("readline");
2616
- const rl = createInterface8({ input: process.stdin, output: process.stdout });
2617
- input = await new Promise((resolve) => {
2618
- rl.question(chalk7.cyan("\uC785\uB825> "), (answer) => {
2619
- rl.close();
2620
- resolve(answer.trim());
2621
- });
2622
- });
2623
- } else {
2624
- printError("\uC785\uB825\uAC12\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uBC95:");
2625
- console.log(' xgen workflow run <id> "\uC785\uB825 \uD14D\uC2A4\uFFFD\uFFFD\uFFFD"');
2626
- console.log(" xgen workflow run -i <id>");
2627
- process.exit(1);
2628
- }
2629
- }
2630
- if (!input) {
2631
- printError("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4");
2632
- process.exit(1);
2633
- }
2634
- const interactionId = `cli_${randomUUID().slice(0, 8)}`;
2635
- printHeader(`\uC2E4\uD589: ${workflowName}`);
2636
- printInfo(`\uC785\uB825: ${input}`);
2637
- console.log();
2638
- try {
2639
- const stream = await executeWorkflowStream({
2640
- workflow_id: workflowId,
2641
- workflow_name: workflowName,
2642
- input_data: input,
2643
- interaction_id: interactionId
2792
+ process.stdout.write(delta);
2644
2793
  });
2645
- let hasOutput = false;
2646
- let fullResponse = "";
2647
- await parseSSEStream(
2648
- stream,
2649
- (event) => {
2650
- switch (event.type) {
2651
- case "token":
2652
- if (event.content) {
2653
- if (!hasOutput) {
2654
- hasOutput = true;
2655
- console.log();
2656
- }
2657
- process.stdout.write(event.content);
2658
- fullResponse += event.content;
2659
- }
2660
- break;
2661
- case "log":
2662
- if (opts.logs && event.content) {
2663
- process.stderr.write(chalk7.gray(`[LOG] ${event.content}
2664
- `));
2665
- }
2666
- break;
2667
- case "node_status":
2668
- if (opts.logs) {
2669
- const nodeName = event.node_name ?? event.node_id ?? "?";
2670
- const status = event.status ?? "?";
2671
- process.stderr.write(
2672
- chalk7.gray(`[\uB178\uB4DC] ${nodeName}: ${status}
2673
- `)
2674
- );
2675
- }
2676
- break;
2677
- case "tool":
2678
- if (opts.logs) {
2679
- process.stderr.write(chalk7.gray(`[\uB3C4\uAD6C] ${JSON.stringify(event.data)}
2680
- `));
2681
- }
2682
- break;
2683
- case "complete":
2684
- break;
2685
- case "error":
2686
- console.log();
2687
- printError(event.error ?? event.content ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958");
2688
- break;
2689
- default:
2690
- if (event.content) {
2691
- if (!hasOutput) {
2692
- process.stdout.write(chalk7.green("\uC751\uB2F5: "));
2693
- hasOutput = true;
2694
- }
2695
- process.stdout.write(event.content);
2696
- }
2697
- }
2698
- },
2699
- () => {
2700
- if (hasOutput) {
2701
- console.log();
2702
- if (fullResponse.includes("```") || fullResponse.includes("**")) {
2703
- console.log(chalk7.gray("\u2500".repeat(40)));
2704
- console.log(renderMarkdown(fullResponse));
2705
- }
2706
- }
2707
- console.log();
2708
- console.log(chalk7.gray(`\uC138\uC158: ${interactionId}`));
2709
- },
2710
- (err) => {
2711
- console.log();
2712
- printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
2713
- }
2714
- );
2715
- } catch (err) {
2716
- const msg = err?.response?.data?.detail ?? err.message;
2717
- printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
2718
- process.exit(1);
2719
- }
2720
- }
2721
-
2722
- // src/commands/workflow/history.ts
2723
- init_store();
2724
- init_workflow();
2725
- init_format();
2726
- import chalk8 from "chalk";
2727
- async function workflowHistory(workflowId, opts = {}) {
2728
- requireAuth();
2729
- const limit = opts.limit ?? 20;
2730
- try {
2731
- const logs = await getIOLogs(workflowId, limit);
2732
- if (!logs || logs.length === 0) {
2733
- console.log(chalk8.yellow("\n\uC2E4\uD589 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2794
+ if (result.content) process.stdout.write("\n\n");
2795
+ if (result.toolCalls.length === 0) {
2796
+ if (result.content) messages.push({ role: "assistant", content: result.content });
2734
2797
  return;
2735
2798
  }
2736
- printHeader(`\uC2E4\uD589 \uC774\uB825 (\uCD5C\uADFC ${logs.length}\uAC74)`);
2737
- console.log();
2738
- for (const log of logs) {
2739
- console.log(
2740
- ` ${chalk8.gray(formatDate(log.created_at))} ${chalk8.cyan(log.interaction_id)}`
2741
- );
2742
- console.log(` ${chalk8.white("\uC785\uB825:")} ${truncate(log.input_data, 60)}`);
2743
- console.log(
2744
- ` ${chalk8.green("\uCD9C\uB825:")} ${truncate(log.output_data, 60)}`
2745
- );
2746
- if (log.execution_time) {
2747
- console.log(
2748
- ` ${chalk8.gray("\uC2DC\uAC04:")} ${(log.execution_time / 1e3).toFixed(1)}s`
2749
- );
2750
- }
2751
- console.log();
2752
- }
2753
- } catch (err) {
2754
- const msg = err.message;
2755
- printError(`\uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
2756
- process.exit(1);
2757
- }
2758
- }
2759
-
2760
- // src/commands/workflow/index.ts
2761
- function registerWorkflowCommand(program2) {
2762
- const wf = program2.command("workflow").alias("wf").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAD00\uB9AC \uBC0F \uC2E4\uD589");
2763
- wf.command("list").alias("ls").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C").option("-d, --detail", "\uC0C1\uC138 \uC815\uBCF4 \uD3EC\uD568").action((opts) => workflowList(opts));
2764
- wf.command("info <workflow-id>").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uC138 \uC815\uBCF4").action((id) => workflowInfo(id));
2765
- wf.command("run <workflow-id> [input]").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589").option("-i, --interactive", "\uC778\uD130\uB799\uD2F0\uBE0C \uBAA8\uB4DC (\uC785\uB825 \uD504\uB86C\uD504\uD2B8)").option("-l, --logs", "\uB514\uBC84\uADF8 \uB85C\uADF8 \uD45C\uC2DC").action((id, input, opts) => workflowRun(id, input, opts));
2766
- wf.command("history [workflow-id]").description("\uC2E4\uD589 \uC774\uB825 \uC870\uD68C").option("-n, --limit <number>", "\uC870\uD68C \uAC74\uC218", "20").action((id, opts) => workflowHistory(id, { limit: parseInt(opts.limit) }));
2767
- }
2768
-
2769
- // src/commands/chat.ts
2770
- init_store();
2771
- init_workflow();
2772
- import chalk9 from "chalk";
2773
- import { createInterface as createInterface2 } from "readline";
2774
- import { randomUUID as randomUUID2 } from "crypto";
2775
- init_format();
2776
- var CHAT_BANNER = `
2777
- ${chalk9.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")}
2778
- ${chalk9.cyan("\u2502")} ${chalk9.white.bold("XGEN")} ${chalk9.gray("\u2014 \uC6CC\uD06C\uD50C\uB85C\uC6B0 AI \uD130\uBBF8\uB110")} ${chalk9.cyan("\u2502")}
2779
- ${chalk9.cyan("\u2502")} ${chalk9.gray("/help \uB3C4\uC6C0\uB9D0 /workflows \uC804\uD658 /exit")} ${chalk9.cyan("\u2502")}
2780
- ${chalk9.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")}`;
2781
- function printHelp() {
2782
- console.log(`
2783
- ${chalk9.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
2784
- ${chalk9.cyan("/workflows")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uAE30 & \uC804\uD658
2785
- ${chalk9.cyan("/switch")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBC88\uD638\uB85C \uC804\uD658 (\uC608: /switch 3)
2786
- ${chalk9.cyan("/history")} \uD604\uC7AC \uC138\uC158 \uB300\uD654 \uC774\uB825
2787
- ${chalk9.cyan("/clear")} \uD654\uBA74 \uC9C0\uC6B0\uAE30
2788
- ${chalk9.cyan("/info")} \uD604\uC7AC \uC5F0\uACB0 \uC815\uBCF4
2789
- ${chalk9.cyan("/help")} \uC774 \uB3C4\uC6C0\uB9D0
2790
- ${chalk9.cyan("/exit")} \uC885\uB8CC (Ctrl+C\uB3C4 \uAC00\uB2A5)
2791
- `);
2792
- }
2793
- async function promptLine(rl, promptStr) {
2794
- return new Promise((resolve) => {
2795
- rl.question(promptStr, (answer) => resolve(answer));
2796
- });
2797
- }
2798
- async function chat(workflowId) {
2799
- const auth = requireAuth();
2800
- const server = getServer();
2801
- let workflows = [];
2802
- try {
2803
- workflows = await listWorkflows();
2804
- } catch {
2805
- printError("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
2806
- process.exit(1);
2807
- }
2808
- if (workflows.length === 0) {
2809
- printError("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4");
2810
- process.exit(1);
2799
+ messages.push({
2800
+ role: "assistant",
2801
+ content: result.content || null,
2802
+ tool_calls: result.toolCalls.map((tc) => ({
2803
+ id: tc.id,
2804
+ type: "function",
2805
+ function: { name: tc.name, arguments: tc.arguments }
2806
+ }))
2807
+ });
2808
+ for (const tc of result.toolCalls) {
2809
+ let args;
2810
+ try {
2811
+ args = JSON.parse(tc.arguments);
2812
+ } catch {
2813
+ args = {};
2814
+ }
2815
+ const shortArgs = Object.entries(args).map(([k, v]) => {
2816
+ const s = String(v);
2817
+ return `${k}=${s.length > 30 ? s.slice(0, 30) + "\u2026" : s}`;
2818
+ }).join(" ");
2819
+ console.log(chalk12.gray(` \u2699 ${chalk12.white(tc.name)} ${shortArgs}`));
2820
+ let toolResult;
2821
+ if (isXgenTool(tc.name)) {
2822
+ toolResult = await execute8(tc.name, args);
2823
+ } else if (mcpManager?.isMcpTool(tc.name)) {
2824
+ toolResult = await mcpManager.callTool(tc.name, args);
2825
+ } else {
2826
+ toolResult = await executeTool(tc.name, args);
2827
+ }
2828
+ const truncated = toolResult.length > 4e3 ? toolResult.slice(0, 4e3) + "\n\u2026(truncated)" : toolResult;
2829
+ messages.push({ role: "tool", tool_call_id: tc.id, content: truncated });
2830
+ }
2811
2831
  }
2812
- let current;
2813
- if (workflowId) {
2814
- const found = workflows.find((w) => w.id === workflowId || w.workflow_name === workflowId);
2815
- current = found ?? { id: workflowId, workflow_name: workflowId };
2832
+ console.log(chalk12.yellow("\n \uCD5C\uB300 \uBC18\uBCF5 \uD69F\uC218 \uB3C4\uB2EC.\n"));
2833
+ }
2834
+ async function connectServer() {
2835
+ const { setServer: setServer2, setAuth: setAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
2836
+ const { addEnvironment: addEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
2837
+ console.log(chalk12.bold("\n XGEN \uC11C\uBC84 \uC5F0\uACB0\n"));
2838
+ const presets = [
2839
+ { id: "hq", name: "\uBCF8\uC0AC", url: "https://xgen.x2bee.com", email: "admin@plateer.com" },
2840
+ { id: "jeju", name: "\uC81C\uC8FC", url: "https://jeju-xgen.x2bee.com", email: "admin@plateer.com" },
2841
+ { id: "lotte", name: "\uB86F\uB370\uBAB0", url: "https://lotteimall-xgen.x2bee.com" }
2842
+ ];
2843
+ presets.forEach((p, i) => console.log(` ${chalk12.cyan(`${i + 1}.`)} ${p.name} ${chalk12.gray(p.url)}`));
2844
+ console.log(` ${chalk12.cyan("4.")} \uC9C1\uC811 \uC785\uB825`);
2845
+ console.log();
2846
+ const choice = await ask(chalk12.cyan(" \u276F "));
2847
+ let url;
2848
+ let email;
2849
+ const ci = parseInt(choice) - 1;
2850
+ if (ci >= 0 && ci < presets.length) {
2851
+ url = presets[ci].url;
2852
+ email = presets[ci].email;
2853
+ addEnvironment2({ ...presets[ci], description: presets[ci].name });
2816
2854
  } else {
2817
- console.log(CHAT_BANNER);
2818
- console.log(chalk9.gray(` \uC11C\uBC84: ${server} | \uC0AC\uC6A9\uC790: ${auth.username}
2855
+ url = await ask(chalk12.white(" URL: "));
2856
+ if (!url) return;
2857
+ }
2858
+ setServer2(url);
2859
+ console.log(chalk12.green(` \u2713 ${url}
2860
+ `));
2861
+ const inputEmail = email || await ask(chalk12.white(" \uC774\uBA54\uC77C: "));
2862
+ const pw = await ask(chalk12.white(" \uBE44\uBC00\uBC88\uD638: "));
2863
+ if (!inputEmail || !pw) return;
2864
+ try {
2865
+ const { apiLogin: apiLogin2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
2866
+ const result = await apiLogin2(inputEmail, pw);
2867
+ if (result.success && result.access_token) {
2868
+ setAuth2({ accessToken: result.access_token, refreshToken: result.refresh_token ?? "", userId: result.user_id ?? "", username: result.username ?? "", isAdmin: false, expiresAt: null });
2869
+ console.log(chalk12.green(` \u2713 ${result.username} \uB85C\uADF8\uC778\uB428
2819
2870
  `));
2820
- console.log(chalk9.bold(" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC120\uD0DD:\n"));
2821
- workflows.forEach((w, i) => {
2822
- console.log(` ${chalk9.cyan(String(i + 1).padStart(3))} ${w.workflow_name}`);
2823
- });
2824
- console.log();
2825
- const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
2826
- const answer = await promptLine(rl2, chalk9.cyan(" \uBC88\uD638> "));
2827
- rl2.close();
2828
- const idx = parseInt(answer.trim()) - 1;
2829
- if (isNaN(idx) || idx < 0 || idx >= workflows.length) {
2830
- current = workflows[0];
2831
2871
  } else {
2832
- current = workflows[idx];
2872
+ console.log(chalk12.red(` \u2717 ${result.message}
2873
+ `));
2833
2874
  }
2875
+ } catch (err) {
2876
+ console.log(chalk12.red(` \u2717 ${err.message}
2877
+ `));
2834
2878
  }
2835
- const sessionId = randomUUID2().slice(0, 8);
2836
- let turnCount = 0;
2837
- const history = [];
2879
+ }
2880
+ async function switchEnv() {
2881
+ const { getEnvironments: getEnvs, switchEnvironment: switchEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
2882
+ const envs = getEnvs();
2883
+ if (!envs.length) {
2884
+ console.log(chalk12.gray("\n \uD658\uACBD \uC5C6\uC74C. /connect\uB85C \uBA3C\uC800 \uC5F0\uACB0\uD558\uC138\uC694.\n"));
2885
+ return;
2886
+ }
2887
+ const active = getActiveEnvironment();
2838
2888
  console.log();
2839
- console.log(chalk9.cyan("\u2500".repeat(42)));
2840
- console.log(chalk9.white.bold(` ${current.workflow_name}`));
2841
- console.log(chalk9.cyan("\u2500".repeat(42)));
2842
- console.log(chalk9.gray(" \uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694. /help \uB85C \uB3C4\uC6C0\uB9D0.\n"));
2843
- const rl = createInterface2({
2844
- input: process.stdin,
2845
- output: process.stdout
2889
+ envs.forEach((e, i) => {
2890
+ const mark = e.id === active?.id ? chalk12.green("\u25CF ") : " ";
2891
+ console.log(` ${mark}${chalk12.cyan(`${i + 1}.`)} ${e.name} ${chalk12.gray(e.url)}`);
2846
2892
  });
2847
- const getPrompt = () => chalk9.cyan("\u276F ");
2848
- const processInput = async (line) => {
2849
- const input = line.trim();
2850
- if (!input) return;
2851
- if (input.startsWith("/")) {
2852
- const [cmd, ...args] = input.slice(1).split(" ");
2853
- switch (cmd.toLowerCase()) {
2854
- case "exit":
2855
- case "quit":
2856
- case "q":
2857
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
2858
- rl.close();
2859
- process.exit(0);
2860
- break;
2861
- case "help":
2862
- case "h":
2863
- printHelp();
2864
- break;
2865
- case "clear":
2866
- case "cls":
2867
- console.clear();
2868
- console.log(chalk9.white.bold(` ${current.workflow_name}`));
2869
- console.log(chalk9.cyan("\u2500".repeat(42)));
2870
- break;
2871
- case "workflows":
2872
- case "wf":
2873
- console.log();
2874
- workflows.forEach((w, i) => {
2875
- const marker = w.id === current.id ? chalk9.green("\u25B8") : " ";
2876
- console.log(` ${marker} ${chalk9.cyan(String(i + 1).padStart(2))} ${w.workflow_name}`);
2877
- });
2878
- console.log(chalk9.gray("\n /switch <\uBC88\uD638> \uB85C \uC804\uD658\n"));
2879
- break;
2880
- case "switch":
2881
- case "sw": {
2882
- const num = parseInt(args[0]);
2883
- if (isNaN(num) || num < 1 || num > workflows.length) {
2884
- console.log(chalk9.yellow(` 1~${workflows.length} \uC0AC\uC774 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694`));
2885
- } else {
2886
- current = workflows[num - 1];
2887
- turnCount = 0;
2888
- history.length = 0;
2889
- console.log(chalk9.green(`
2890
- \uC804\uD658: ${current.workflow_name}
2893
+ console.log();
2894
+ const ci = parseInt(await ask(chalk12.cyan(" \u276F "))) - 1;
2895
+ if (ci >= 0 && ci < envs.length) {
2896
+ switchEnvironment2(envs[ci].id);
2897
+ console.log(chalk12.green(` \u2713 ${envs[ci].name}
2891
2898
  `));
2892
- }
2893
- break;
2894
- }
2895
- case "history":
2896
- case "hist":
2897
- if (history.length === 0) {
2898
- console.log(chalk9.gray(" \uB300\uD654 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2899
- } else {
2900
- console.log();
2901
- for (const h of history) {
2902
- const label = h.role === "user" ? chalk9.cyan("\uB098") : chalk9.green("AI");
2903
- const text = h.content.length > 80 ? h.content.slice(0, 80) + "..." : h.content;
2904
- console.log(` ${label}: ${text}`);
2905
- }
2906
- console.log();
2907
- }
2908
- break;
2909
- case "info":
2910
- console.log(`
2911
- ${chalk9.gray("\uC11C\uBC84:")} ${server}
2912
- ${chalk9.gray("\uC0AC\uC6A9\uC790:")} ${auth.username}
2913
- ${chalk9.gray("\uC6CC\uD06C\uD50C\uB85C\uC6B0:")} ${current.workflow_name}
2914
- ${chalk9.gray("\uC138\uC158:")} ${sessionId}
2915
- ${chalk9.gray("\uD134:")} ${turnCount}
2916
- `);
2917
- break;
2918
- default:
2919
- console.log(chalk9.yellow(` \uC54C \uC218 \uC5C6\uB294 \uCEE4\uB9E8\uB4DC: /${cmd}. /help \uCC38\uACE0`));
2920
- }
2921
- rl.prompt();
2922
- return;
2923
- }
2924
- turnCount++;
2925
- const interactionId = `${sessionId}_t${turnCount}`;
2926
- history.push({ role: "user", content: input });
2927
- process.stdout.write(chalk9.gray(" thinking..."));
2928
- try {
2929
- const stream = await executeWorkflowStream({
2930
- workflow_id: current.id,
2931
- workflow_name: current.workflow_name,
2932
- input_data: input,
2933
- interaction_id: interactionId
2934
- });
2935
- process.stdout.write("\r" + " ".repeat(20) + "\r");
2936
- let fullResponse = "";
2937
- let hasOutput = false;
2938
- await parseSSEStream(
2939
- stream,
2940
- (event) => {
2941
- if ((event.type === "token" || !event.type) && event.content) {
2942
- if (!hasOutput) {
2943
- hasOutput = true;
2944
- console.log();
2945
- }
2946
- process.stdout.write(event.content);
2947
- fullResponse += event.content;
2948
- } else if (event.type === "error") {
2949
- process.stdout.write("\r" + " ".repeat(20) + "\r");
2950
- printError(event.error ?? event.content ?? "\uC624\uB958");
2951
- }
2952
- },
2953
- () => {
2954
- if (hasOutput) {
2955
- console.log();
2956
- console.log();
2957
- }
2958
- if (fullResponse) {
2959
- history.push({ role: "assistant", content: fullResponse });
2960
- }
2961
- },
2962
- (err) => {
2963
- process.stdout.write("\r" + " ".repeat(20) + "\r");
2964
- printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
2965
- }
2966
- );
2967
- } catch (err) {
2968
- process.stdout.write("\r" + " ".repeat(20) + "\r");
2969
- const msg = err?.response?.data?.detail ?? err.message;
2970
- printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
2971
- }
2972
- rl.prompt();
2973
- };
2974
- rl.setPrompt(getPrompt());
2975
- rl.prompt();
2976
- rl.on("line", (line) => {
2977
- processInput(line).then(() => {
2978
- });
2979
- });
2980
- rl.on("close", () => {
2981
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
2982
- process.exit(0);
2983
- });
2984
- process.on("SIGINT", () => {
2985
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
2986
- process.exit(0);
2987
- });
2899
+ }
2988
2900
  }
2989
- function registerChatCommand(program2) {
2990
- program2.command("chat [workflow-id]").description("\uC778\uD130\uB799\uD2F0\uBE0C \uB300\uD654 \uBAA8\uB4DC").action((workflowId) => chat(workflowId));
2901
+ function registerAgentCommand(program2) {
2902
+ program2.command("agent").description("OPEN XGEN AI \uC5D0\uC774\uC804\uD2B8").action(async () => {
2903
+ await agentRepl();
2904
+ });
2991
2905
  }
2992
2906
 
2993
- // src/index.ts
2994
- init_provider();
2995
- init_agent();
2996
-
2997
2907
  // src/commands/doc.ts
2998
2908
  init_store();
2999
2909
  init_document();
@@ -3149,42 +3059,42 @@ ${result.answer}
3149
3059
 
3150
3060
  // src/index.ts
3151
3061
  var VERSION = "0.3.0";
3152
- var LOGO = chalk17.cyan(`
3062
+ var LOGO = chalk15.cyan(`
3153
3063
  \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
3154
3064
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
3155
3065
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3156
3066
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3157
3067
  \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
3158
- `) + chalk17.white.bold(`
3068
+ `) + chalk15.white.bold(`
3159
3069
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
3160
3070
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
3161
3071
  \u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3162
3072
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3163
3073
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
3164
- `) + chalk17.gray(` v${VERSION}
3074
+ `) + chalk15.gray(` v${VERSION}
3165
3075
  `);
3166
3076
  var BANNER = LOGO;
3167
3077
  var program = new Command();
3168
3078
  program.name("xgen").description("OPEN XGEN \u2014 AI Coding Agent + XGEN Platform CLI").version(VERSION).addHelpText("before", BANNER).addHelpText(
3169
3079
  "after",
3170
3080
  `
3171
- ${chalk17.bold("\uC2DC\uC791\uD558\uAE30:")}
3172
- ${chalk17.cyan("xgen provider add")} AI \uD504\uB85C\uBC14\uC774\uB354 \uC124\uC815
3173
- ${chalk17.cyan("xgen agent")} AI \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8
3174
- ${chalk17.cyan("xgen config set-server")} <url> XGEN \uC11C\uBC84 \uC5F0\uACB0
3175
- ${chalk17.cyan("xgen login")} \uC11C\uBC84 \uB85C\uADF8\uC778
3081
+ ${chalk15.bold("\uC2DC\uC791\uD558\uAE30:")}
3082
+ ${chalk15.cyan("xgen provider add")} AI \uD504\uB85C\uBC14\uC774\uB354 \uC124\uC815
3083
+ ${chalk15.cyan("xgen agent")} AI \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8
3084
+ ${chalk15.cyan("xgen config set-server")} <url> XGEN \uC11C\uBC84 \uC5F0\uACB0
3085
+ ${chalk15.cyan("xgen login")} \uC11C\uBC84 \uB85C\uADF8\uC778
3176
3086
 
3177
- ${chalk17.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
3178
- ${chalk17.cyan("xgen agent")} \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8 (\uD30C\uC77C, \uD130\uBBF8\uB110, \uAC80\uC0C9)
3179
- ${chalk17.cyan("xgen provider ls")} \uD504\uB85C\uBC14\uC774\uB354 \uBAA9\uB85D
3180
- ${chalk17.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
3087
+ ${chalk15.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
3088
+ ${chalk15.cyan("xgen agent")} \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8 (\uD30C\uC77C, \uD130\uBBF8\uB110, \uAC80\uC0C9)
3089
+ ${chalk15.cyan("xgen provider ls")} \uD504\uB85C\uBC14\uC774\uB354 \uBAA9\uB85D
3090
+ ${chalk15.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
3181
3091
 
3182
- ${chalk17.bold("XGEN \uD50C\uB7AB\uD3FC:")}
3183
- ${chalk17.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
3184
- ${chalk17.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
3185
- ${chalk17.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
3186
- ${chalk17.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
3187
- ${chalk17.cyan("xgen ont query")} "\uC9C8\uBB38" \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758
3092
+ ${chalk15.bold("XGEN \uD50C\uB7AB\uD3FC:")}
3093
+ ${chalk15.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
3094
+ ${chalk15.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
3095
+ ${chalk15.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
3096
+ ${chalk15.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
3097
+ ${chalk15.cyan("xgen ont query")} "\uC9C8\uBB38" \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758
3188
3098
  `
3189
3099
  );
3190
3100
  registerConfigCommand(program);
@@ -3197,15 +3107,15 @@ registerDocCommand(program);
3197
3107
  registerOntologyCommand(program);
3198
3108
  if (process.argv.length <= 2) {
3199
3109
  if (process.stdin.isTTY) {
3200
- Promise.resolve().then(() => (init_dashboard(), dashboard_exports)).then(
3201
- ({ dashboard: dashboard2 }) => dashboard2().catch((err) => {
3202
- console.error(chalk17.red(`\uC624\uB958: ${err.message}`));
3110
+ Promise.resolve().then(() => (init_tui(), tui_exports)).then(
3111
+ ({ startTui: startTui2 }) => startTui2().catch((err) => {
3112
+ console.error(chalk15.red(`\uC624\uB958: ${err.message}`));
3203
3113
  process.exit(1);
3204
3114
  })
3205
3115
  );
3206
3116
  } else {
3207
3117
  agentRepl().catch((err) => {
3208
- console.error(chalk17.red(`\uC624\uB958: ${err.message}`));
3118
+ console.error(chalk15.red(`\uC624\uB958: ${err.message}`));
3209
3119
  process.exit(1);
3210
3120
  });
3211
3121
  }