openxgen 1.1.0 → 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,2241 +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
- }
1029
- }
1030
- var definition5;
1031
- var init_grep = __esm({
1032
- "src/agent/tools/grep.ts"() {
1033
- "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
- }
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;
1048
1137
  }
1049
- };
1050
- }
1051
- });
1052
-
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}"`;
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}`);
1069
1147
  }
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
- }
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();
1079
1185
  }
1080
- var definition6;
1081
- var init_list_files = __esm({
1082
- "src/agent/tools/list-files.ts"() {
1186
+ var init_tui = __esm({
1187
+ "src/dashboard/tui.ts"() {
1083
1188
  "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)" }
1094
- }
1095
- }
1096
- }
1097
- };
1189
+ init_store();
1098
1190
  }
1099
1191
  });
1100
1192
 
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;
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
+ });
1116
1243
  }
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"]
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");
1277
+ }
1278
+ } else {
1279
+ password += c;
1280
+ process.stdout.write("*");
1281
+ }
1282
+ };
1283
+ stdin.on("data", onData);
1284
+ } else {
1285
+ rl.question(question, (answer) => {
1286
+ rl.close();
1287
+ resolve(answer.trim());
1288
+ });
1289
+ }
1290
+ });
1291
+ }
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
- listDocuments: () => listDocuments,
1247
- uploadDocument: () => uploadDocument
1248
- });
1249
- import { createReadStream, statSync } from "fs";
1250
- import { basename } from "path";
1251
- async function listDocuments(collectionId) {
1252
- const client2 = getClient();
1253
- const params = {};
1254
- if (collectionId) params.collection_id = collectionId;
1255
- const res = await client2.get("/api/documents/list", { params });
1256
- return res.data.documents ?? res.data ?? [];
1257
- }
1258
- async function uploadDocument(filePath, collectionId, name) {
1259
- const client2 = getClient();
1260
- const stat = statSync(filePath);
1261
- const fileName = name || basename(filePath);
1262
- const FormData = (await import("buffer")).Blob ? globalThis.FormData : null;
1263
- if (!FormData) throw new Error("FormData not available");
1264
- const form = new FormData();
1265
- const fileBlob = new Blob([createReadStream(filePath)]);
1266
- form.append("file", fileBlob, fileName);
1267
- if (collectionId) form.append("collection_id", collectionId);
1268
- const res = await client2.post("/api/documents/upload", form, {
1269
- headers: { "Content-Type": "multipart/form-data" },
1270
- maxBodyLength: stat.size + 1024 * 1024
1271
- });
1272
- return res.data;
1273
- }
1274
- async function getDocumentInfo(docId) {
1275
- const client2 = getClient();
1276
- const res = await client2.get(`/api/documents/${docId}`);
1277
- return res.data;
1278
- }
1279
- var init_document = __esm({
1280
- "src/api/document.ts"() {
1281
- "use strict";
1282
- init_client();
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();
1378
+ try {
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);
1283
1419
  }
1284
- });
1285
-
1286
- // src/api/ontology.ts
1287
- var ontology_exports = {};
1288
- __export(ontology_exports, {
1289
- getGraphStats: () => getGraphStats,
1290
- listGraphs: () => listGraphs,
1291
- queryGraphRAG: () => queryGraphRAG,
1292
- queryGraphRAGMultiTurn: () => queryGraphRAGMultiTurn
1293
- });
1294
- async function queryGraphRAG(query, graphId, opts) {
1295
- const client2 = getClient();
1296
- const res = await client2.post("/api/graph-rag", {
1297
- query,
1298
- graph_id: graphId,
1299
- use_scs: opts?.scs ?? true
1300
- });
1301
- return res.data;
1302
- }
1303
- async function queryGraphRAGMultiTurn(query, sessionId, graphId, opts) {
1304
- const client2 = getClient();
1305
- const res = await client2.post("/api/graph-rag/multi-turn", {
1306
- query,
1307
- session_id: sessionId,
1308
- graph_id: graphId,
1309
- max_turns: opts?.maxTurns ?? 5
1310
- });
1311
- return res.data;
1312
- }
1313
- async function getGraphStats(graphId) {
1314
- const client2 = getClient();
1315
- const res = await client2.get(`/api/graph/${graphId}/stats`);
1316
- return res.data;
1317
1420
  }
1318
- async function listGraphs() {
1319
- const client2 = getClient();
1320
- const res = await client2.get("/api/graph/list");
1321
- return res.data.graphs ?? res.data ?? [];
1322
- }
1323
- var init_ontology = __esm({
1324
- "src/api/ontology.ts"() {
1325
- "use strict";
1326
- init_client();
1327
- }
1328
- });
1329
1421
 
1330
- // src/agent/tools/xgen-api.ts
1331
- async function execute8(name, args) {
1332
- const server = getServer();
1333
- const auth = getAuth();
1334
- if (!server || !auth) {
1335
- 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.";
1336
- }
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();
1337
1429
  try {
1338
- switch (name) {
1339
- case "xgen_workflow_list":
1340
- return await workflowList2();
1341
- case "xgen_workflow_run":
1342
- return await workflowRun2(args);
1343
- case "xgen_workflow_info":
1344
- return await workflowInfo2(args);
1345
- case "xgen_doc_list":
1346
- return await docList(args);
1347
- case "xgen_ontology_query":
1348
- return await ontologyQuery(args);
1349
- case "xgen_server_status":
1350
- return await serverStatus();
1351
- case "xgen_execution_history":
1352
- return await executionHistory(args);
1353
- default:
1354
- 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
+ }
1355
1451
  }
1452
+ console.log();
1356
1453
  } catch (err) {
1357
- 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);
1358
1457
  }
1359
1458
  }
1360
- function isXgenTool(name) {
1361
- return name.startsWith("xgen_");
1362
- }
1363
- async function workflowList2() {
1364
- const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1365
- const wfs = await getWorkflowListDetail2();
1366
- if (!wfs.length) return "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC5C6\uC74C.";
1367
- return wfs.map((w, i) => {
1368
- const deployed = w.is_deployed;
1369
- const dk = w.deploy_key;
1370
- const tag = deployed ? " [\uBC30\uD3EC\uB428]" : "";
1371
- return `${i + 1}. ${w.workflow_name}${tag}
1372
- ID: ${w.workflow_id ?? w.id}
1373
- deploy_key: ${dk || "\uC5C6\uC74C"}`;
1374
- }).join("\n");
1375
- }
1376
- async function workflowRun2(args) {
1377
- const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1378
- const { randomUUID: randomUUID4 } = await import("crypto");
1379
- const result = await executeWorkflow2({
1380
- workflow_id: args.workflow_id,
1381
- workflow_name: args.workflow_name,
1382
- input_data: args.input_data,
1383
- interaction_id: `cli_${randomUUID4().slice(0, 8)}`,
1384
- 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
+ });
1385
1514
  });
1386
- if (result.content) return String(result.content);
1387
- if (result.success === false) return `\uC624\uB958: ${result.error ?? result.message}`;
1388
- return JSON.stringify(result, null, 2).slice(0, 2e3);
1389
1515
  }
1390
- async function workflowInfo2(args) {
1391
- const { getWorkflowDetail: getWorkflowDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1392
- const detail = await getWorkflowDetail2(args.workflow_id);
1393
- const nodes = detail.nodes?.length ?? 0;
1394
- const edges = detail.edges?.length ?? 0;
1395
- return `\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name}
1396
- ID: ${detail.id}
1397
- \uB178\uB4DC: ${nodes}\uAC1C
1398
- \uC5E3\uC9C0: ${edges}\uAC1C`;
1399
- }
1400
- async function docList(args) {
1401
- const { listDocuments: listDocuments2 } = await Promise.resolve().then(() => (init_document(), document_exports));
1402
- const docs = await listDocuments2(args.collection_id);
1403
- if (!docs.length) return "\uBB38\uC11C \uC5C6\uC74C.";
1404
- return docs.map(
1405
- (d, i) => `${i + 1}. ${d.file_name ?? d.name ?? "-"} (${d.file_type ?? "-"}) \u2014 ${d.status ?? "-"}`
1406
- ).join("\n");
1407
- }
1408
- async function ontologyQuery(args) {
1409
- const { queryGraphRAG: queryGraphRAG2 } = await Promise.resolve().then(() => (init_ontology(), ontology_exports));
1410
- const result = await queryGraphRAG2(args.query, args.graph_id);
1411
- let output = "";
1412
- if (result.answer) output += `\uB2F5\uBCC0: ${result.answer}
1413
- `;
1414
- if (result.sources?.length) output += `\uCD9C\uCC98: ${result.sources.join(", ")}
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")}
1415
1538
  `;
1416
- if (result.triples_used?.length) output += `\uD2B8\uB9AC\uD50C: ${result.triples_used.join("; ")}`;
1417
- return output || "\uACB0\uACFC \uC5C6\uC74C.";
1418
- }
1419
- async function serverStatus() {
1420
- const server = getServer();
1421
- const auth = getAuth();
1422
- return `\uC11C\uBC84: ${server}
1423
- \uC0AC\uC6A9\uC790: ${auth?.username}
1424
- User ID: ${auth?.userId}`;
1425
- }
1426
- async function executionHistory(args) {
1427
- const { getIOLogs: getIOLogs2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
1428
- const limit = args.limit || 10;
1429
- const logs = await getIOLogs2(void 0, limit);
1430
- if (!logs.length) return "\uC2E4\uD589 \uC774\uB825 \uC5C6\uC74C.";
1431
- return logs.map(
1432
- (l, i) => `${i + 1}. [${l.created_at ?? ""}]
1433
- \uC785\uB825: ${(l.input_data ?? "").slice(0, 80)}
1434
- \uCD9C\uB825: ${(l.output_data ?? "").slice(0, 80)}`
1435
- ).join("\n");
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;
1436
1550
  }
1437
- var definitions;
1438
- var init_xgen_api = __esm({
1439
- "src/agent/tools/xgen-api.ts"() {
1440
- "use strict";
1441
- init_store();
1442
- definitions = [
1443
- {
1444
- type: "function",
1445
- function: {
1446
- name: "xgen_workflow_list",
1447
- description: "XGEN \uC11C\uBC84\uC5D0\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
1448
- parameters: { type: "object", properties: {} }
1449
- }
1450
- },
1451
- {
1452
- type: "function",
1453
- function: {
1454
- name: "xgen_workflow_run",
1455
- 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.",
1456
- parameters: {
1457
- type: "object",
1458
- properties: {
1459
- workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" },
1460
- workflow_name: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984" },
1461
- input_data: { type: "string", description: "\uC785\uB825 \uBA54\uC2DC\uC9C0" },
1462
- deploy_key: { type: "string", description: "\uBC30\uD3EC \uD0A4 (\uBC30\uD3EC\uB41C \uC6CC\uD06C\uD50C\uB85C\uC6B0)" }
1463
- },
1464
- required: ["workflow_id", "workflow_name", "input_data"]
1465
- }
1466
- }
1467
- },
1468
- {
1469
- type: "function",
1470
- function: {
1471
- name: "xgen_workflow_info",
1472
- description: "\uD2B9\uC815 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uC0C1\uC138 \uC815\uBCF4(\uB178\uB4DC, \uC5E3\uC9C0 \uB4F1)\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4.",
1473
- parameters: {
1474
- type: "object",
1475
- properties: {
1476
- workflow_id: { type: "string", description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 ID" }
1477
- },
1478
- required: ["workflow_id"]
1479
- }
1480
- }
1481
- },
1482
- {
1483
- type: "function",
1484
- function: {
1485
- name: "xgen_doc_list",
1486
- description: "XGEN \uC11C\uBC84\uC5D0\uC11C \uBB38\uC11C \uBAA9\uB85D\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
1487
- parameters: {
1488
- type: "object",
1489
- properties: {
1490
- collection_id: { type: "string", description: "\uCEEC\uB809\uC158 ID (\uC120\uD0DD)" }
1491
- }
1492
- }
1493
- }
1494
- },
1495
- {
1496
- type: "function",
1497
- function: {
1498
- name: "xgen_ontology_query",
1499
- description: "\uC628\uD1A8\uB85C\uC9C0(GraphRAG)\uC5D0 \uC9C8\uBB38\uD569\uB2C8\uB2E4. \uC9C0\uC2DD \uADF8\uB798\uD504 \uAE30\uBC18 \uAC80\uC0C9.",
1500
- parameters: {
1501
- type: "object",
1502
- properties: {
1503
- query: { type: "string", description: "\uC9C8\uC758 \uB0B4\uC6A9" },
1504
- graph_id: { type: "string", description: "\uADF8\uB798\uD504 ID (\uC120\uD0DD)" }
1505
- },
1506
- required: ["query"]
1507
- }
1508
- }
1509
- },
1510
- {
1511
- type: "function",
1512
- function: {
1513
- name: "xgen_server_status",
1514
- description: "XGEN \uC11C\uBC84 \uC0C1\uD0DC\uB97C \uD655\uC778\uD569\uB2C8\uB2E4.",
1515
- parameters: { type: "object", properties: {} }
1516
- }
1517
- },
1518
- {
1519
- type: "function",
1520
- function: {
1521
- name: "xgen_execution_history",
1522
- description: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589 \uC774\uB825\uC744 \uAC00\uC838\uC635\uB2C8\uB2E4.",
1523
- parameters: {
1524
- type: "object",
1525
- properties: {
1526
- limit: { type: "number", description: "\uAC00\uC838\uC62C \uC774\uB825 \uC218 (\uAE30\uBCF8 10)" }
1527
- }
1528
- }
1529
- }
1530
- }
1531
- ];
1532
- }
1533
- });
1534
1551
 
1535
- // src/mcp/client.ts
1536
- import { spawn } from "child_process";
1537
- import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
1538
- import { join as join3 } from "path";
1539
- import { createInterface as createInterface4 } from "readline";
1540
- function loadMcpConfig(dir) {
1541
- const searchPaths = [
1542
- dir ? join3(dir, ".mcp.json") : null,
1543
- join3(process.cwd(), ".mcp.json"),
1544
- join3(process.env.HOME ?? "", ".mcp.json")
1545
- ].filter(Boolean);
1546
- for (const p of searchPaths) {
1547
- if (existsSync3(p)) {
1548
- try {
1549
- return JSON.parse(readFileSync4(p, "utf-8"));
1550
- } catch {
1551
- continue;
1552
- }
1553
- }
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 {
1554
1560
  }
1555
- return null;
1556
- }
1557
- var McpClient, McpManager;
1558
- var init_client2 = __esm({
1559
- "src/mcp/client.ts"() {
1560
- "use strict";
1561
- McpClient = class {
1562
- process = null;
1563
- requestId = 0;
1564
- pending = /* @__PURE__ */ new Map();
1565
- serverName;
1566
- config;
1567
- tools = [];
1568
- constructor(serverName, config) {
1569
- this.serverName = serverName;
1570
- this.config = config;
1571
- }
1572
- async start() {
1573
- this.process = spawn(this.config.command, this.config.args ?? [], {
1574
- stdio: ["pipe", "pipe", "pipe"],
1575
- env: { ...process.env, ...this.config.env }
1576
- });
1577
- const rl = createInterface4({ input: this.process.stdout });
1578
- rl.on("line", (line) => {
1579
- try {
1580
- const msg = JSON.parse(line);
1581
- if (msg.id !== void 0 && this.pending.has(msg.id)) {
1582
- const p = this.pending.get(msg.id);
1583
- this.pending.delete(msg.id);
1584
- if (msg.error) {
1585
- p.reject(new Error(msg.error.message));
1586
- } else {
1587
- p.resolve(msg.result);
1588
- }
1589
- }
1590
- } catch {
1591
- }
1592
- });
1593
- this.process.on("error", (err) => {
1594
- console.error(`MCP [${this.serverName}] \uD504\uB85C\uC138\uC2A4 \uC624\uB958:`, err.message);
1595
- });
1596
- await this.send("initialize", {
1597
- protocolVersion: "2024-11-05",
1598
- capabilities: {},
1599
- clientInfo: { name: "open-xgen", version: "0.3.0" }
1600
- });
1601
- await this.send("notifications/initialized", {});
1602
- }
1603
- send(method, params) {
1604
- return new Promise((resolve, reject) => {
1605
- const id = ++this.requestId;
1606
- const request = { jsonrpc: "2.0", id, method, params };
1607
- this.pending.set(id, { resolve, reject });
1608
- const timeout = setTimeout(() => {
1609
- this.pending.delete(id);
1610
- reject(new Error(`MCP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3: ${method}`));
1611
- }, 15e3);
1612
- this.pending.set(id, {
1613
- resolve: (v) => {
1614
- clearTimeout(timeout);
1615
- resolve(v);
1616
- },
1617
- reject: (e) => {
1618
- clearTimeout(timeout);
1619
- reject(e);
1620
- }
1621
- });
1622
- this.process?.stdin?.write(JSON.stringify(request) + "\n");
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());
1623
1569
  });
1624
- }
1625
- async listTools() {
1626
- const result = await this.send("tools/list", {});
1627
- this.tools = result.tools ?? [];
1628
- return this.tools;
1629
- }
1630
- async callTool(name, args) {
1631
- const result = await this.send("tools/call", { name, arguments: args });
1632
- return result.content?.map((c) => c.text ?? "").join("\n") ?? "";
1633
- }
1634
- getOpenAITools() {
1635
- return this.tools.map((t) => ({
1636
- type: "function",
1637
- function: {
1638
- name: `mcp_${this.serverName}_${t.name}`,
1639
- description: `[MCP:${this.serverName}] ${t.description ?? t.name}`,
1640
- parameters: t.inputSchema ?? { type: "object", properties: {} }
1641
- }
1642
- }));
1643
- }
1644
- stop() {
1645
- this.process?.kill();
1646
- this.process = null;
1647
- }
1648
- };
1649
- McpManager = class {
1650
- clients = /* @__PURE__ */ new Map();
1651
- async startAll(config) {
1652
- for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
1653
- if (serverConfig.type !== "stdio") continue;
1654
- try {
1655
- const client2 = new McpClient(name, serverConfig);
1656
- await client2.start();
1657
- await client2.listTools();
1658
- this.clients.set(name, client2);
1659
- } catch (err) {
1660
- console.error(`MCP [${name}] \uC2DC\uC791 \uC2E4\uD328:`, err.message);
1661
- }
1662
- }
1663
- }
1664
- getAllTools() {
1665
- const tools2 = [];
1666
- for (const client2 of this.clients.values()) {
1667
- tools2.push(...client2.getOpenAITools());
1668
- }
1669
- return tools2;
1670
- }
1671
- async callTool(fullName, args) {
1672
- const parts = fullName.split("_");
1673
- if (parts.length < 3 || parts[0] !== "mcp") return `Unknown MCP tool: ${fullName}`;
1674
- const serverName = parts[1];
1675
- const toolName = parts.slice(2).join("_");
1676
- const client2 = this.clients.get(serverName);
1677
- if (!client2) return `MCP \uC11C\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${serverName}`;
1678
- return client2.callTool(toolName, args);
1679
- }
1680
- isMcpTool(name) {
1681
- return name.startsWith("mcp_");
1682
- }
1683
- stopAll() {
1684
- for (const client2 of this.clients.values()) {
1685
- client2.stop();
1686
- }
1687
- this.clients.clear();
1688
- }
1689
- get serverCount() {
1690
- return this.clients.size;
1691
- }
1692
- getServerNames() {
1693
- return [...this.clients.keys()];
1694
- }
1695
- };
1696
- }
1697
- });
1698
-
1699
- // src/commands/agent.ts
1700
- import chalk12 from "chalk";
1701
- import { createInterface as createInterface5 } from "readline";
1702
- function buildSystemPrompt() {
1703
- const server = getServer();
1704
- const auth = getAuth();
1705
- const env = getActiveEnvironment();
1706
- let prompt2 = `You are OPEN XGEN, an AI assistant in the user's terminal.
1707
- You combine AI coding capabilities with the XGEN workflow platform.
1708
-
1709
- ## Capabilities
1710
- 1. **Coding**: Read/write files, execute commands, search code, run sandboxed code (JS/TS/Python)
1711
- 2. **XGEN Platform**: List/run workflows, manage documents, query ontology (GraphRAG)
1712
-
1713
- ## Rules
1714
- - Respond in the same language as the user
1715
- - Be concise. Show what you did, not how.
1716
- - When using tools, briefly describe what you're doing
1717
- - For XGEN operations, use the xgen_* tools`;
1718
- if (server && auth) {
1719
- prompt2 += `
1720
-
1721
- ## XGEN Server Connected
1722
- - Server: ${server}
1723
- - User: ${auth.username} (ID: ${auth.userId})
1724
- - Environment: ${env?.name ?? "default"}
1725
- You can use xgen_workflow_list, xgen_workflow_run, xgen_doc_list, xgen_ontology_query, etc.`;
1726
- } else {
1727
- prompt2 += `
1728
-
1729
- ## XGEN Server: Not connected
1730
- Tell the user to run /connect to connect to an XGEN server.`;
1731
- }
1732
- return prompt2;
1733
- }
1734
- async function agentRepl() {
1735
- let provider = getDefaultProvider();
1736
- if (!provider) {
1737
- provider = await guidedProviderSetup();
1738
- if (!provider) process.exit(1);
1739
- }
1740
- const client2 = createLLMClient(provider);
1741
- const allTools = [...getAllToolDefs(), ...definitions];
1742
- const builtinNames = getToolNames();
1743
- const mcpConfig = loadMcpConfig();
1744
- if (mcpConfig && Object.keys(mcpConfig.mcpServers).length > 0) {
1745
- mcpManager = new McpManager();
1746
- try {
1747
- await mcpManager.startAll(mcpConfig);
1748
- if (mcpManager.serverCount > 0) allTools.push(...mcpManager.getAllTools());
1749
- } catch {
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);
1750
1576
  }
1751
1577
  }
1752
- const messages = [{ role: "system", content: buildSystemPrompt() }];
1753
- console.log(welcome());
1754
- console.log();
1755
- const server = getServer();
1756
- const auth = getAuth();
1757
- const env = getActiveEnvironment();
1758
- console.log(chalk12.gray(` ${provider.name} \xB7 ${provider.model}`));
1759
- if (server && auth) {
1760
- console.log(chalk12.gray(` ${env?.name ?? "XGEN"} \xB7 ${auth.username}@${server.replace("https://", "")}`));
1578
+ if (!input) {
1579
+ printError("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4");
1580
+ process.exit(1);
1761
1581
  }
1762
- console.log(chalk12.gray(` ${builtinNames.length} \uB3C4\uAD6C + ${definitions.length} XGEN${mcpManager?.serverCount ? ` + ${mcpManager.getAllTools().length} MCP` : ""}`));
1763
- console.log(chalk12.gray(` /help \xB7 /connect \xB7 /env \xB7 /provider \xB7 /exit
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}
1764
1612
  `));
1765
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
1766
- const askUser = () => new Promise((resolve) => rl.question(chalk12.cyan(" \u276F "), (a) => resolve(a.trim())));
1767
- process.on("SIGINT", () => {
1768
- console.log(chalk12.gray("\n \u{1F44B}\n"));
1769
- mcpManager?.stopAll();
1770
- rl.close();
1771
- process.exit(0);
1772
- });
1773
- while (true) {
1774
- const input = await askUser();
1775
- if (!input) continue;
1776
- if (input === "/exit" || input === "exit") {
1777
- console.log(chalk12.gray("\n \u{1F44B}\n"));
1778
- mcpManager?.stopAll();
1779
- rl.close();
1780
- break;
1781
- }
1782
- if (input === "/help") {
1783
- console.log(`
1784
- ${chalk12.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
1785
- ${chalk12.cyan("/connect")} XGEN \uC11C\uBC84 \uC5F0\uACB0 + \uB85C\uADF8\uC778
1786
- ${chalk12.cyan("/env")} \uD658\uACBD \uC804\uD658 (\uBCF8\uC0AC/\uC81C\uC8FC/\uB86F\uB370\uBAB0)
1787
- ${chalk12.cyan("/provider")} \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD
1788
- ${chalk12.cyan("/tools")} \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB3C4\uAD6C \uBAA9\uB85D
1789
- ${chalk12.cyan("/status")} \uD604\uC7AC \uC5F0\uACB0 \uC0C1\uD0DC
1790
- ${chalk12.cyan("/clear")} \uB300\uD654 \uCD08\uAE30\uD654
1791
- ${chalk12.cyan("/exit")} \uC885\uB8CC
1792
- `);
1793
- continue;
1794
- }
1795
- if (input === "/clear") {
1796
- messages.length = 0;
1797
- messages.push({ role: "system", content: buildSystemPrompt() });
1798
- console.log(chalk12.gray(" \uB300\uD654 \uCD08\uAE30\uD654\uB428.\n"));
1799
- continue;
1800
- }
1801
- if (input === "/status") {
1802
- const p = getDefaultProvider();
1803
- const s = getServer();
1804
- const a = getAuth();
1805
- const e = getActiveEnvironment();
1806
- console.log();
1807
- console.log(` ${chalk12.bold("\uD504\uB85C\uBC14\uC774\uB354")} ${p ? `${p.name} \xB7 ${p.model}` : chalk12.red("\uBBF8\uC124\uC815")}`);
1808
- console.log(` ${chalk12.bold("\uC11C\uBC84")} ${s && a ? `${a.username}@${s.replace("https://", "")}` : chalk12.red("\uBBF8\uC5F0\uACB0")}`);
1809
- console.log(` ${chalk12.bold("\uD658\uACBD")} ${e?.name ?? "\uC5C6\uC74C"} (${getEnvironments().length}\uAC1C \uB4F1\uB85D)`);
1810
- if (mcpManager?.serverCount) {
1811
- console.log(` ${chalk12.bold("MCP")} ${mcpManager.getServerNames().join(", ")}`);
1812
- }
1813
- console.log();
1814
- continue;
1815
- }
1816
- if (input === "/tools") {
1817
- console.log(`
1818
- ${chalk12.bold("\uCF54\uB529")} ${builtinNames.join(", ")}`);
1819
- console.log(` ${chalk12.bold("XGEN")} ${definitions.map((t) => t.function.name).join(", ")}`);
1820
- if (mcpManager?.serverCount) {
1821
- console.log(` ${chalk12.bold("MCP")} ${mcpManager.getAllTools().map((t) => t.function.name).join(", ")}`);
1822
- }
1823
- console.log();
1824
- continue;
1825
- }
1826
- if (input === "/connect") {
1827
- await connectServer();
1828
- messages[0] = { role: "system", content: buildSystemPrompt() };
1829
- continue;
1830
- }
1831
- if (input === "/env") {
1832
- await switchEnv();
1833
- messages[0] = { role: "system", content: buildSystemPrompt() };
1834
- continue;
1835
- }
1836
- if (input === "/provider") {
1837
- const { guidedProviderSetup: setup } = await Promise.resolve().then(() => (init_provider(), provider_exports));
1838
- await setup();
1839
- console.log(chalk12.gray(" \uD504\uB85C\uBC14\uC774\uB354 \uBCC0\uACBD\uB428. /exit \uD6C4 \uC7AC\uC2DC\uC791\uD558\uC138\uC694.\n"));
1840
- continue;
1841
- }
1842
- messages.push({ role: "user", content: input });
1843
- try {
1844
- await runLoop(client2, provider.model, messages, allTools);
1845
- } catch (err) {
1846
- console.log(chalk12.red(`
1847
- \uC624\uB958: ${err.message}
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)}
1848
1628
  `));
1849
- }
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
+ }
1645
+ }
1646
+ },
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));
1653
+ }
1654
+ }
1655
+ console.log();
1656
+ console.log(chalk7.gray(`\uC138\uC158: ${interactionId}`));
1657
+ },
1658
+ (err) => {
1659
+ console.log();
1660
+ printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
1661
+ }
1662
+ );
1663
+ } catch (err) {
1664
+ const msg = err?.response?.data?.detail ?? err.message;
1665
+ printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
1666
+ process.exit(1);
1850
1667
  }
1851
1668
  }
1852
- async function runLoop(client2, model, messages, tools2) {
1853
- for (let i = 0; i < 20; i++) {
1854
- let first = true;
1855
- const result = await streamChat(client2, model, messages, tools2, (delta) => {
1856
- if (first) {
1857
- process.stdout.write(chalk12.green("\n ") + "");
1858
- first = false;
1859
- }
1860
- process.stdout.write(delta);
1861
- });
1862
- if (result.content) process.stdout.write("\n\n");
1863
- if (result.toolCalls.length === 0) {
1864
- if (result.content) messages.push({ role: "assistant", content: result.content });
1669
+
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"));
1865
1682
  return;
1866
1683
  }
1867
- messages.push({
1868
- role: "assistant",
1869
- content: result.content || null,
1870
- tool_calls: result.toolCalls.map((tc) => ({
1871
- id: tc.id,
1872
- type: "function",
1873
- function: { name: tc.name, arguments: tc.arguments }
1874
- }))
1875
- });
1876
- for (const tc of result.toolCalls) {
1877
- let args;
1878
- try {
1879
- args = JSON.parse(tc.arguments);
1880
- } catch {
1881
- args = {};
1882
- }
1883
- const shortArgs = Object.entries(args).map(([k, v]) => {
1884
- const s = String(v);
1885
- return `${k}=${s.length > 30 ? s.slice(0, 30) + "\u2026" : s}`;
1886
- }).join(" ");
1887
- console.log(chalk12.gray(` \u2699 ${chalk12.white(tc.name)} ${shortArgs}`));
1888
- let toolResult;
1889
- if (isXgenTool(tc.name)) {
1890
- toolResult = await execute8(tc.name, args);
1891
- } else if (mcpManager?.isMcpTool(tc.name)) {
1892
- toolResult = await mcpManager.callTool(tc.name, args);
1893
- } else {
1894
- toolResult = await executeTool(tc.name, args);
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
+ );
1895
1698
  }
1896
- const truncated = toolResult.length > 4e3 ? toolResult.slice(0, 4e3) + "\n\u2026(truncated)" : toolResult;
1897
- messages.push({ role: "tool", tool_call_id: tc.id, content: truncated });
1699
+ console.log();
1898
1700
  }
1701
+ } catch (err) {
1702
+ const msg = err.message;
1703
+ printError(`\uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
1704
+ process.exit(1);
1899
1705
  }
1900
- console.log(chalk12.yellow("\n \uCD5C\uB300 \uBC18\uBCF5 \uD69F\uC218 \uB3C4\uB2EC.\n"));
1901
1706
  }
1902
- async function connectServer() {
1903
- const { setServer: setServer2, setAuth: setAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1904
- const { addEnvironment: addEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1905
- console.log(chalk12.bold("\n XGEN \uC11C\uBC84 \uC5F0\uACB0\n"));
1906
- const presets = [
1907
- { id: "hq", name: "\uBCF8\uC0AC", url: "https://xgen.x2bee.com", email: "admin@plateer.com" },
1908
- { id: "jeju", name: "\uC81C\uC8FC", url: "https://jeju-xgen.x2bee.com", email: "admin@plateer.com" },
1909
- { id: "lotte", name: "\uB86F\uB370\uBAB0", url: "https://lotteimall-xgen.x2bee.com" }
1910
- ];
1911
- presets.forEach((p, i) => console.log(` ${chalk12.cyan(`${i + 1}.`)} ${p.name} ${chalk12.gray(p.url)}`));
1912
- console.log(` ${chalk12.cyan("4.")} \uC9C1\uC811 \uC785\uB825`);
1913
- console.log();
1914
- const choice = await ask(chalk12.cyan(" \u276F "));
1915
- let url;
1916
- let email;
1917
- const ci = parseInt(choice) - 1;
1918
- if (ci >= 0 && ci < presets.length) {
1919
- url = presets[ci].url;
1920
- email = presets[ci].email;
1921
- addEnvironment2({ ...presets[ci], description: presets[ci].name });
1922
- } else {
1923
- url = await ask(chalk12.white(" URL: "));
1924
- if (!url) return;
1925
- }
1926
- setServer2(url);
1927
- console.log(chalk12.green(` \u2713 ${url}
1928
- `));
1929
- const inputEmail = email || await ask(chalk12.white(" \uC774\uBA54\uC77C: "));
1930
- const pw = await ask(chalk12.white(" \uBE44\uBC00\uBC88\uD638: "));
1931
- if (!inputEmail || !pw) return;
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 = [];
1932
1750
  try {
1933
- const { apiLogin: apiLogin2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
1934
- const result = await apiLogin2(inputEmail, pw);
1935
- if (result.success && result.access_token) {
1936
- setAuth2({ accessToken: result.access_token, refreshToken: result.refresh_token ?? "", userId: result.user_id ?? "", username: result.username ?? "", isAdmin: false, expiresAt: null });
1937
- console.log(chalk12.green(` \u2713 ${result.username} \uB85C\uADF8\uC778\uB428
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}
1938
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];
1939
1779
  } else {
1940
- console.log(chalk12.red(` \u2717 ${result.message}
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}`);
1825
+ });
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}
1941
1839
  `));
1840
+ }
1841
+ break;
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`));
1868
+ }
1869
+ rl.prompt();
1870
+ return;
1942
1871
  }
1943
- } catch (err) {
1944
- console.log(chalk12.red(` \u2717 ${err.message}
1945
- `));
1946
- }
1947
- }
1948
- async function switchEnv() {
1949
- const { getEnvironments: getEnvs, switchEnvironment: switchEnvironment2 } = await Promise.resolve().then(() => (init_store(), store_exports));
1950
- const envs = getEnvs();
1951
- if (!envs.length) {
1952
- console.log(chalk12.gray("\n \uD658\uACBD \uC5C6\uC74C. /connect\uB85C \uBA3C\uC800 \uC5F0\uACB0\uD558\uC138\uC694.\n"));
1953
- return;
1954
- }
1955
- const active = getActiveEnvironment();
1956
- console.log();
1957
- envs.forEach((e, i) => {
1958
- const mark = e.id === active?.id ? chalk12.green("\u25CF ") : " ";
1959
- console.log(` ${mark}${chalk12.cyan(`${i + 1}.`)} ${e.name} ${chalk12.gray(e.url)}`);
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}`);
1913
+ }
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
+ });
1960
1927
  });
1961
- console.log();
1962
- const ci = parseInt(await ask(chalk12.cyan(" \u276F "))) - 1;
1963
- if (ci >= 0 && ci < envs.length) {
1964
- switchEnvironment2(envs[ci].id);
1965
- console.log(chalk12.green(` \u2713 ${envs[ci].name}
1966
- `));
1967
- }
1968
- }
1969
- function registerAgentCommand(program2) {
1970
- program2.command("agent").description("OPEN XGEN AI \uC5D0\uC774\uC804\uD2B8").action(async () => {
1971
- await agentRepl();
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);
1972
1935
  });
1973
1936
  }
1974
- var mcpManager;
1975
- var init_agent = __esm({
1976
- "src/commands/agent.ts"() {
1977
- "use strict";
1978
- init_store();
1979
- init_llm();
1980
- init_tools();
1981
- init_xgen_api();
1982
- init_client2();
1983
- init_provider();
1984
- init_ui();
1985
- mcpManager = null;
1986
- }
1987
- });
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
+ }
1988
1940
 
1989
- // src/dashboard/renderer.ts
1990
- import chalk15 from "chalk";
1991
- function clearScreen() {
1992
- process.stdout.write("\x1B[2J\x1B[H");
1993
- }
1994
- function renderHeader(activeTab, tabs, env) {
1995
- const w = W2();
1996
- const title = chalk15.cyan.bold(" OPEN XGEN ");
1997
- const envTag = env ? chalk15.gray(` \xB7 ${env}`) : "";
1998
- const tabBar = tabs.map((t) => {
1999
- if (t === activeTab) return chalk15.bgCyan.black(` ${t} `);
2000
- return chalk15.gray(` ${t} `);
2001
- }).join(chalk15.gray("\u2502"));
2002
- console.log(chalk15.bgGray.black(" ".repeat(w)));
2003
- console.log(chalk15.bgGray.black(`${title}${envTag}${" ".repeat(Math.max(0, w - stripAnsi(title + envTag).length))}`));
2004
- console.log(chalk15.gray("\u2500".repeat(w)));
2005
- console.log(tabBar);
2006
- console.log(chalk15.gray("\u2500".repeat(w)));
2007
- }
2008
- function renderStatusBar(text) {
2009
- const w = W2();
2010
- const padded = ` ${text}${" ".repeat(Math.max(0, w - text.length - 1))}`;
2011
- console.log(chalk15.gray("\u2500".repeat(w)));
2012
- console.log(chalk15.bgGray.black(padded));
2013
- }
2014
- function renderList(items, selected, title, startRow) {
2015
- if (title) console.log(chalk15.bold(` ${title}`));
2016
- console.log();
2017
- const pageSize = H() - 12;
2018
- const start = Math.max(0, selected - pageSize + 3);
2019
- const visible = items.slice(start, start + pageSize);
2020
- visible.forEach((item, i) => {
2021
- const idx = start + i;
2022
- const cursor = idx === selected ? chalk15.cyan("\u25B8 ") : " ";
2023
- const num = chalk15.gray(`${String(idx + 1).padStart(3)}.`);
2024
- const tag = item.tag ? ` ${item.tag}` : "";
2025
- const line = `${cursor}${num} ${item.label}${tag}`;
2026
- if (idx === selected) {
2027
- console.log(chalk15.white.bold(line));
2028
- if (item.detail) console.log(chalk15.gray(` ${item.detail}`));
2029
- } else {
2030
- console.log(line);
1941
+ // src/index.ts
1942
+ init_provider();
1943
+
1944
+ // src/commands/agent.ts
1945
+ init_store();
1946
+ init_llm();
1947
+ import chalk12 from "chalk";
1948
+ import { createInterface as createInterface5 } from "readline";
1949
+
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"]
2031
1970
  }
2032
- });
2033
- if (items.length > pageSize) {
2034
- console.log(chalk15.gray(`
2035
- ${start + 1}-${Math.min(start + pageSize, items.length)} / ${items.length}`));
2036
1971
  }
2037
- }
2038
- function renderPanel(title, lines) {
2039
- const w = W2() - 4;
2040
- console.log(chalk15.cyan(` \u250C${"\u2500".repeat(w)}\u2510`));
2041
- console.log(chalk15.cyan(` \u2502 ${chalk15.bold(title)}${" ".repeat(Math.max(0, w - stripAnsi(title).length - 1))}\u2502`));
2042
- console.log(chalk15.cyan(` \u251C${"\u2500".repeat(w)}\u2524`));
2043
- for (const line of lines) {
2044
- const clean = stripAnsi(line);
2045
- const pad = Math.max(0, w - clean.length - 1);
2046
- console.log(chalk15.cyan(` \u2502 `) + line + " ".repeat(pad) + chalk15.cyan("\u2502"));
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}`;
2047
1984
  }
2048
- console.log(chalk15.cyan(` \u2514${"\u2500".repeat(w)}\u2518`));
2049
1985
  }
2050
- function stripAnsi(str) {
2051
- return str.replace(/\x1b\[[0-9;]*m/g, "");
2052
- }
2053
- var W2, H;
2054
- var init_renderer = __esm({
2055
- "src/dashboard/renderer.ts"() {
2056
- "use strict";
2057
- W2 = () => Math.min(process.stdout.columns || 80, 100);
2058
- H = () => Math.min(process.stdout.rows || 30, 40);
2059
- }
2060
- });
2061
1986
 
2062
- // src/dashboard/index.ts
2063
- var dashboard_exports = {};
2064
- __export(dashboard_exports, {
2065
- dashboard: () => dashboard
1987
+ // src/agent/tools/file-write.ts
1988
+ var file_write_exports = {};
1989
+ __export(file_write_exports, {
1990
+ definition: () => definition2,
1991
+ execute: () => execute2
2066
1992
  });
2067
- import chalk16 from "chalk";
2068
- import { createInterface as createInterface7 } from "readline";
2069
- async function dashboard() {
2070
- const state = {
2071
- activeTab: 0,
2072
- workflows: [],
2073
- documents: [],
2074
- selectedIdx: 0
2075
- };
2076
- await loadData(state);
2077
- render(state);
2078
- const rl = createInterface7({ input: process.stdin, output: process.stdout });
2079
- if (process.stdin.isTTY) {
2080
- process.stdin.setRawMode(true);
2081
- process.stdin.resume();
2082
- process.stdin.setEncoding("utf8");
2083
- process.stdin.on("data", async (key) => {
2084
- if (key === "") {
2085
- cleanup(rl);
2086
- process.exit(0);
2087
- }
2088
- if (key === " ") {
2089
- state.activeTab = (state.activeTab + 1) % TABS.length;
2090
- state.selectedIdx = 0;
2091
- render(state);
2092
- return;
2093
- }
2094
- if (key === "\x1B[Z") {
2095
- state.activeTab = (state.activeTab - 1 + TABS.length) % TABS.length;
2096
- state.selectedIdx = 0;
2097
- render(state);
2098
- return;
2099
- }
2100
- if (key === "\x1B[A") {
2101
- state.selectedIdx = Math.max(0, state.selectedIdx - 1);
2102
- render(state);
2103
- return;
2104
- }
2105
- if (key === "\x1B[B") {
2106
- const max = getCurrentListLength(state) - 1;
2107
- state.selectedIdx = Math.min(max, state.selectedIdx + 1);
2108
- render(state);
2109
- return;
2110
- }
2111
- if (key === "\r") {
2112
- await handleEnter(state, rl);
2113
- return;
2114
- }
2115
- const num = parseInt(key);
2116
- if (num >= 1 && num <= 5) {
2117
- state.activeTab = num - 1;
2118
- state.selectedIdx = 0;
2119
- render(state);
2120
- return;
2121
- }
2122
- if (key === "c") {
2123
- state.activeTab = 0;
2124
- render(state);
2125
- return;
2126
- }
2127
- if (key === "w") {
2128
- state.activeTab = 1;
2129
- render(state);
2130
- return;
2131
- }
2132
- if (key === "d") {
2133
- state.activeTab = 2;
2134
- render(state);
2135
- return;
2136
- }
2137
- if (key === "o") {
2138
- state.activeTab = 3;
2139
- render(state);
2140
- return;
2141
- }
2142
- if (key === "s") {
2143
- state.activeTab = 4;
2144
- render(state);
2145
- return;
2146
- }
2147
- if (key === "r") {
2148
- await loadData(state);
2149
- render(state);
2150
- return;
2151
- }
2152
- if (key === "q") {
2153
- cleanup(rl);
2154
- process.exit(0);
2155
- }
2156
- });
2157
- } else {
2158
- cleanup(rl);
2159
- await agentRepl();
2160
- }
2161
- }
2162
- function render(state) {
2163
- clearScreen();
2164
- const env = getActiveEnvironment();
2165
- const auth = getAuth();
2166
- const server = getServer();
2167
- const envLabel = env?.name ?? (server ? server.replace("https://", "") : "\uBBF8\uC5F0\uACB0");
2168
- const userLabel = auth ? `${auth.username}@${envLabel}` : envLabel;
2169
- renderHeader(TABS[state.activeTab], TABS, userLabel);
2170
- console.log();
2171
- switch (state.activeTab) {
2172
- case 0:
2173
- renderChatTab();
2174
- break;
2175
- case 1:
2176
- renderWorkflowTab(state);
2177
- break;
2178
- case 2:
2179
- renderDocTab(state);
2180
- break;
2181
- case 3:
2182
- renderOntologyTab();
2183
- break;
2184
- case 4:
2185
- renderSettingsTab();
2186
- break;
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"]
2007
+ }
2187
2008
  }
2188
- const provider = getDefaultProvider();
2189
- 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`;
2190
- renderStatusBar(statusText);
2191
- }
2192
- function renderChatTab() {
2193
- console.log(chalk16.bold(" AI \uC5D0\uC774\uC804\uD2B8"));
2194
- console.log();
2195
- console.log(chalk16.gray(" Enter\uB97C \uB20C\uB7EC AI \uCC44\uD305 \uBAA8\uB4DC\uB85C \uC9C4\uC785\uD569\uB2C8\uB2E4."));
2196
- 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."));
2197
- console.log();
2198
- console.log(chalk16.gray(" \uC608\uC2DC:"));
2199
- console.log(chalk16.white(' "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uC5EC\uC918"'));
2200
- console.log(chalk16.white(' "\uC7AC\uC9C1\uC99D\uBA85\uC11C \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589\uD574\uC918"'));
2201
- console.log(chalk16.white(' "\uC774 \uD3F4\uB354\uC5D0 \uC788\uB294 \uD30C\uC77C \uBB50 \uC788\uC5B4?"'));
2202
- console.log(chalk16.white(' "Python\uC73C\uB85C fibonacci \uD568\uC218 \uB9CC\uB4E4\uC5B4\uC918"'));
2203
- console.log();
2204
- }
2205
- function renderWorkflowTab(state) {
2206
- if (state.workflows.length === 0) {
2207
- console.log(chalk16.gray(" \uC11C\uBC84 \uBBF8\uC5F0\uACB0 \uB610\uB294 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC5C6\uC74C"));
2208
- console.log(chalk16.gray(" s\uD0A4 \u2192 \uC124\uC815\uC5D0\uC11C \uC11C\uBC84 \uC5F0\uACB0"));
2209
- return;
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}`;
2210
2019
  }
2211
- renderList(state.workflows, state.selectedIdx, `\uC6CC\uD06C\uD50C\uB85C\uC6B0 (${state.workflows.length}\uAC1C)`);
2212
2020
  }
2213
- function renderDocTab(state) {
2214
- if (state.documents.length === 0) {
2215
- console.log(chalk16.gray(" \uC11C\uBC84 \uBBF8\uC5F0\uACB0 \uB610\uB294 \uBB38\uC11C \uC5C6\uC74C"));
2216
- return;
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"]
2042
+ }
2217
2043
  }
2218
- renderList(state.documents, state.selectedIdx, `\uBB38\uC11C (${state.documents.length}\uAC1C)`);
2219
- }
2220
- function renderOntologyTab() {
2221
- console.log(chalk16.bold(" \uC628\uD1A8\uB85C\uC9C0 (GraphRAG)"));
2222
- console.log();
2223
- console.log(chalk16.gray(" Enter\uB97C \uB20C\uB7EC \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758 \uBAA8\uB4DC\uB85C \uC9C4\uC785\uD569\uB2C8\uB2E4."));
2224
- console.log(chalk16.gray(" \uC9C0\uC2DD \uADF8\uB798\uD504 \uAE30\uBC18 \uC9C8\uBB38-\uB2F5\uBCC0\uC744 \uC218\uD589\uD569\uB2C8\uB2E4."));
2225
- console.log();
2226
- }
2227
- function renderSettingsTab() {
2228
- const provider = getDefaultProvider();
2229
- const server = getServer();
2230
- const auth = getAuth();
2231
- const env = getActiveEnvironment();
2232
- const lines = [
2233
- `\uD504\uB85C\uBC14\uC774\uB354: ${provider ? `${provider.name} \xB7 ${provider.model}` : chalk16.red("\uBBF8\uC124\uC815")}`,
2234
- `\uC11C\uBC84: ${server ?? chalk16.red("\uBBF8\uC5F0\uACB0")}`,
2235
- `\uC0AC\uC6A9\uC790: ${auth?.username ?? "-"}`,
2236
- `\uD658\uACBD: ${env?.name ?? "-"}`
2237
- ];
2238
- renderPanel("\uD604\uC7AC \uC124\uC815", lines);
2239
- console.log();
2240
- console.log(chalk16.gray(" Enter \u2192 AI \uCC44\uD305\uC5D0\uC11C /connect, /provider, /env \uC0AC\uC6A9"));
2241
- }
2242
- function getCurrentListLength(state) {
2243
- switch (state.activeTab) {
2244
- case 1:
2245
- return state.workflows.length;
2246
- case 2:
2247
- return state.documents.length;
2248
- default:
2249
- return 0;
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`;
2053
+ }
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}`;
2250
2059
  }
2251
2060
  }
2252
- async function handleEnter(state, rl) {
2253
- if (state.activeTab === 0 || state.activeTab === 3 || state.activeTab === 4) {
2254
- cleanup(rl);
2255
- await agentRepl();
2256
- await dashboard();
2257
- return;
2258
- }
2259
- if (state.activeTab === 1 && state.workflows.length > 0) {
2260
- const selected = state.workflows[state.selectedIdx];
2261
- cleanup(rl);
2262
- console.log(chalk16.green(`
2263
- \u2713 ${selected.label} \uC120\uD0DD\uB428
2264
- `));
2265
- await agentRepl();
2266
- await dashboard();
2267
- return;
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"]
2080
+ }
2268
2081
  }
2269
- }
2270
- async function loadData(state) {
2271
- const server = getServer();
2272
- const auth = getAuth();
2273
- if (!server || !auth) return;
2082
+ };
2083
+ async function execute4(args) {
2084
+ const command = args.command;
2274
2085
  try {
2275
- const { getWorkflowListDetail: getWorkflowListDetail2 } = await Promise.resolve().then(() => (init_workflow(), workflow_exports));
2276
- const wfs = await getWorkflowListDetail2();
2277
- state.workflows = wfs.map((w) => {
2278
- const deployed = w.is_deployed;
2279
- return {
2280
- label: w.workflow_name,
2281
- detail: (w.workflow_id ?? w.id ?? "").toString(),
2282
- tag: deployed ? chalk16.green("[\uBC30\uD3EC]") : void 0
2283
- };
2086
+ const output = execSync(command, {
2087
+ encoding: "utf-8",
2088
+ timeout: 3e4,
2089
+ maxBuffer: 1024 * 1024,
2090
+ stdio: ["pipe", "pipe", "pipe"]
2284
2091
  });
2285
- } catch {
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"]
2119
+ }
2286
2120
  }
2121
+ };
2122
+ async function execute5(args) {
2123
+ const pattern = args.pattern;
2124
+ const path = args.path || ".";
2125
+ const glob = args.glob;
2287
2126
  try {
2288
- const { listDocuments: listDocuments2 } = await Promise.resolve().then(() => (init_document(), document_exports));
2289
- const docs = await listDocuments2();
2290
- state.documents = docs.map((d) => ({
2291
- label: d.file_name ?? d.name ?? "-",
2292
- detail: d.file_type ?? "-",
2293
- tag: d.status ? chalk16.gray(`[${d.status}]`) : void 0
2294
- }));
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";
2295
2137
  } catch {
2138
+ return "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
2296
2139
  }
2297
2140
  }
2298
- function cleanup(rl) {
2299
- if (process.stdin.isTTY) process.stdin.setRawMode(false);
2300
- rl.close();
2301
- clearScreen();
2302
- }
2303
- var TABS;
2304
- var init_dashboard = __esm({
2305
- "src/dashboard/index.ts"() {
2306
- "use strict";
2307
- init_renderer();
2308
- init_store();
2309
- init_agent();
2310
- TABS = ["\u{1F4AC} Chat", "\u{1F4CB} Workflows", "\u{1F4C4} Documents", "\u{1F50D} Ontology", "\u2699 Settings"];
2311
- }
2312
- });
2313
-
2314
- // src/index.ts
2315
- import { Command } from "commander";
2316
- import chalk17 from "chalk";
2317
2141
 
2318
- // src/commands/config.ts
2319
- init_store();
2320
- init_client();
2321
- init_format();
2322
- import chalk2 from "chalk";
2323
- function registerConfigCommand(program2) {
2324
- const config = program2.command("config").description("XGEN CLI \uC124\uC815 \uAD00\uB9AC");
2325
- config.command("set-server <url>").description("XGEN \uC11C\uBC84 URL \uC124\uC815").action((url) => {
2326
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
2327
- printError("URL\uC740 http:// \uB610\uB294 https://\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4");
2328
- process.exit(1);
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)" }
2159
+ }
2329
2160
  }
2330
- setServer(url);
2331
- resetClient();
2332
- printSuccess(`\uC11C\uBC84 \uC124\uC815 \uC644\uB8CC: ${chalk2.underline(url)}`);
2333
- });
2334
- config.command("get-server").description("\uD604\uC7AC \uC124\uC815\uB41C \uC11C\uBC84 URL \uD655\uC778").action(() => {
2335
- const server = getServer();
2336
- if (server) {
2337
- console.log(server);
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`;
2338
2170
  } else {
2339
- printError("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
2340
- console.log(" \uC124\uC815: xgen config set-server <url>");
2341
- }
2342
- });
2343
- config.command("list").description("\uC804\uCCB4 \uC124\uC815 \uD655\uC778").action(() => {
2344
- const cfg = getConfig();
2345
- console.log(chalk2.bold("\nXGEN CLI \uC124\uC815"));
2346
- console.log(chalk2.gray("\u2500".repeat(40)));
2347
- printKeyValue("\uC11C\uBC84", cfg.server);
2348
- printKeyValue("\uAE30\uBCF8 \uC6CC\uD06C\uD50C\uB85C\uC6B0", cfg.defaultWorkflow);
2349
- printKeyValue("\uD14C\uB9C8", cfg.theme);
2350
- printKeyValue("\uC2A4\uD2B8\uB9BC \uB85C\uADF8", String(cfg.streamLogs));
2351
- console.log();
2352
- });
2353
- config.command("set <key> <value>").description("\uC124\uC815 \uAC12 \uBCC0\uACBD").action((key, value) => {
2354
- const allowedKeys = ["defaultWorkflow", "theme", "streamLogs"];
2355
- if (!allowedKeys.includes(key)) {
2356
- printError(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}`);
2357
- console.log(` \uC0AC\uC6A9 \uAC00\uB2A5: ${allowedKeys.join(", ")}`);
2358
- process.exit(1);
2171
+ cmd = `ls -la "${path}"`;
2359
2172
  }
2360
- const parsed = key === "streamLogs" ? value === "true" : value;
2361
- setConfig({ [key]: parsed });
2362
- printSuccess(`${key} = ${value}`);
2363
- });
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}`;
2181
+ }
2364
2182
  }
2365
2183
 
2366
- // src/commands/login.ts
2367
- init_auth();
2368
- init_store();
2369
- init_format();
2370
- import chalk3 from "chalk";
2371
- import { createInterface } from "readline";
2372
- function prompt(question, hidden = false) {
2373
- return new Promise((resolve) => {
2374
- const rl = createInterface({
2375
- input: process.stdin,
2376
- output: process.stdout
2377
- });
2378
- if (hidden) {
2379
- process.stdout.write(question);
2380
- const stdin = process.stdin;
2381
- const wasRaw = stdin.isRaw;
2382
- if (stdin.isTTY) stdin.setRawMode(true);
2383
- let password = "";
2384
- const onData = (ch) => {
2385
- const c = ch.toString("utf8");
2386
- if (c === "\n" || c === "\r" || c === "") {
2387
- if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
2388
- stdin.removeListener("data", onData);
2389
- process.stdout.write("\n");
2390
- rl.close();
2391
- resolve(password);
2392
- } else if (c === "") {
2393
- process.exit(0);
2394
- } else if (c === "\x7F" || c === "\b") {
2395
- if (password.length > 0) {
2396
- password = password.slice(0, -1);
2397
- process.stdout.write("\b \b");
2398
- }
2399
- } else {
2400
- password += c;
2401
- process.stdout.write("*");
2402
- }
2403
- };
2404
- stdin.on("data", onData);
2405
- } else {
2406
- rl.question(question, (answer) => {
2407
- rl.close();
2408
- resolve(answer.trim());
2409
- });
2410
- }
2411
- });
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 });
2198
+ }
2199
+ return SANDBOX_DIR;
2412
2200
  }
2413
- function registerLoginCommand(program2) {
2414
- 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) => {
2415
- const server = requireServer();
2416
- printHeader("XGEN Login");
2417
- console.log(chalk3.gray(`\uC11C\uBC84: ${server}
2418
- `));
2419
- let email = opts.email;
2420
- let password = opts.password;
2421
- if (!email) {
2422
- email = await prompt(chalk3.white("\uC774\uBA54\uC77C: "));
2423
- }
2424
- if (!password) {
2425
- password = await prompt(chalk3.white("\uBE44\uBC00\uBC88\uD638: "), true);
2426
- }
2427
- if (!email || !password) {
2428
- printError("\uC774\uBA54\uC77C\uACFC \uBE44\uBC00\uBC88\uD638\uB97C \uBAA8\uB450 \uC785\uB825\uD558\uC138\uC694");
2429
- process.exit(1);
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"]
2430
2222
  }
2431
- try {
2432
- const result = await apiLogin(email, password);
2433
- if (result.success && result.access_token) {
2434
- setAuth({
2435
- accessToken: result.access_token,
2436
- refreshToken: result.refresh_token ?? "",
2437
- userId: result.user_id ?? "",
2438
- username: result.username ?? "",
2439
- isAdmin: false,
2440
- expiresAt: null
2223
+ }
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 });
2233
+ try {
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"]
2441
2242
  });
2442
- console.log();
2443
- printSuccess(`\uB85C\uADF8\uC778 \uC131\uACF5! ${chalk3.bold(result.username ?? email)}`);
2444
2243
  } else {
2445
- printError(result.message || "\uB85C\uADF8\uC778 \uC2E4\uD328");
2446
- process.exit(1);
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
+ });
2447
2252
  }
2448
- } catch (err) {
2449
- const msg = err?.response?.data?.message ?? err?.response?.data?.detail ?? err.message;
2450
- printError(`\uB85C\uADF8\uC778 \uC2E4\uD328: ${msg}`);
2451
- process.exit(1);
2452
2253
  }
2453
- });
2454
- program2.command("logout").description("\uB85C\uADF8\uC544\uC6C3").action(async () => {
2455
- const { clearAuth: clearAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
2456
- clearAuth2();
2457
- printSuccess("\uB85C\uADF8\uC544\uC6C3 \uC644\uB8CC");
2458
- });
2459
- program2.command("whoami").description("\uD604\uC7AC \uB85C\uADF8\uC778\uB41C \uC0AC\uC6A9\uC790 \uC815\uBCF4").action(async () => {
2460
- const auth = getAuth();
2461
- if (!auth) {
2462
- printError("\uB85C\uADF8\uC778\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. xgen login \uC2E4\uD589\uD558\uC138\uC694");
2463
- process.exit(1);
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}`;
2264
+ } else {
2265
+ filename = "script.mjs";
2266
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
2267
+ cmd = `node ${filename}`;
2464
2268
  }
2465
- const server = requireServer();
2466
- console.log(chalk3.bold("\n\uD604\uC7AC \uC0AC\uC6A9\uC790"));
2467
- console.log(chalk3.gray("\u2500".repeat(30)));
2468
- console.log(` ${chalk3.gray("\uC11C\uBC84:")} ${server}`);
2469
- console.log(` ${chalk3.gray("\uC0AC\uC6A9\uC790:")} ${chalk3.bold(auth.username)}`);
2470
- console.log(` ${chalk3.gray("User ID:")} ${auth.userId}`);
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)";
2277
+ } catch (err) {
2278
+ const e = err;
2279
+ return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
2280
+ } finally {
2471
2281
  try {
2472
- const { apiValidate: apiValidate2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
2473
- const result = await apiValidate2(auth.accessToken);
2474
- if (result.valid) {
2475
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.green("\uD65C\uC131")}`);
2476
- if (result.is_admin) {
2477
- console.log(` ${chalk3.gray("\uAD8C\uD55C:")} ${chalk3.yellow("\uAD00\uB9AC\uC790")}`);
2478
- }
2479
- if (result.user_type) {
2480
- console.log(` ${chalk3.gray("\uC720\uD615:")} ${result.user_type}`);
2481
- }
2482
- } else {
2483
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.red("\uD1A0\uD070 \uB9CC\uB8CC")}`);
2484
- }
2282
+ rmSync(runDir, { recursive: true, force: true });
2485
2283
  } catch {
2486
- console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.yellow("\uAC80\uC99D \uBD88\uAC00 (\uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328)")}`);
2487
2284
  }
2488
- console.log();
2489
- });
2285
+ }
2490
2286
  }
2491
2287
 
2492
- // src/commands/workflow/list.ts
2493
- init_store();
2494
- init_workflow();
2495
- init_format();
2496
- import chalk4 from "chalk";
2497
- async function workflowList(opts) {
2498
- requireAuth();
2499
- try {
2500
- if (opts.detail) {
2501
- const workflows = await getWorkflowListDetail();
2502
- if (!workflows || workflows.length === 0) {
2503
- console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2504
- return;
2505
- }
2506
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
2507
- console.log();
2508
- printTable(
2509
- ["#", "ID", "\uC774\uB984", "\uBC30\uD3EC", "\uC5C5\uB370\uC774\uD2B8"],
2510
- workflows.map((w, i) => [
2511
- String(i + 1),
2512
- (w.workflow_id ?? w.id ?? "-").slice(0, 12),
2513
- truncate(w.workflow_name ?? "-", 30),
2514
- w.is_deployed ? chalk4.green("\uBC30\uD3EC\uB428") : chalk4.gray("\uBBF8\uBC30\uD3EC"),
2515
- formatDate(w.updated_at)
2516
- ])
2517
- );
2518
- } else {
2519
- const workflows = await listWorkflows();
2520
- if (!workflows || workflows.length === 0) {
2521
- console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2522
- return;
2523
- }
2524
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
2525
- console.log();
2526
- printTable(
2527
- ["#", "ID", "\uC774\uB984"],
2528
- workflows.map((w, i) => [
2529
- String(i + 1),
2530
- (w.workflow_id ?? w.id ?? "-").slice(0, 12),
2531
- w.workflow_name ?? "-"
2532
- ])
2533
- );
2534
- }
2535
- console.log();
2536
- } catch (err) {
2537
- const msg = err.message;
2538
- printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${msg}`);
2539
- process.exit(1);
2540
- }
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);
2293
+ }
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);
2301
+ }
2302
+ function getToolNames() {
2303
+ return tools.map((t) => t.definition.function.name);
2541
2304
  }
2542
2305
 
2543
- // src/commands/workflow/info.ts
2306
+ // src/agent/tools/xgen-api.ts
2544
2307
  init_store();
2545
- init_workflow();
2546
- init_format();
2547
- import chalk5 from "chalk";
2548
- async function workflowInfo(workflowId) {
2549
- requireAuth();
2550
- try {
2551
- const detail = await getWorkflowDetail(workflowId);
2552
- printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name ?? workflowId}`);
2553
- console.log();
2554
- printKeyValue("ID", detail.id);
2555
- printKeyValue("\uC774\uB984", detail.workflow_name);
2556
- printKeyValue("\uC124\uBA85", detail.description ?? "(\uC5C6\uC74C)");
2557
- if (detail.nodes && Array.isArray(detail.nodes)) {
2558
- console.log();
2559
- console.log(chalk5.bold(" \uB178\uB4DC \uAD6C\uC131:"));
2560
- for (const node of detail.nodes) {
2561
- const label = node.data?.label ?? node.id;
2562
- const type = node.data?.type ?? "unknown";
2563
- console.log(` ${chalk5.cyan("\u2022")} ${label} ${chalk5.gray(`(${type})`)}`);
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"]
2564
2331
  }
2565
2332
  }
2566
- if (detail.parameters && Object.keys(detail.parameters).length > 0) {
2567
- console.log();
2568
- console.log(chalk5.bold(" \uD30C\uB77C\uBBF8\uD130:"));
2569
- for (const [key, val] of Object.entries(detail.parameters)) {
2570
- console.log(` ${chalk5.gray(key)}: ${JSON.stringify(val)}`);
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"]
2571
2345
  }
2572
2346
  }
2573
- console.log();
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
+ }
2374
+ }
2375
+ }
2376
+ }
2377
+ ];
2378
+ async function execute8(name, args) {
2379
+ const server = getServer();
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
+ }
2574
2401
  } catch (err) {
2575
- const msg = err.message;
2576
- printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC870\uD68C \uC2E4\uD328: ${msg}`);
2577
- process.exit(1);
2402
+ return `XGEN API \uC624\uB958: ${err.message}`;
2578
2403
  }
2579
2404
  }
2405
+ function isXgenTool(name) {
2406
+ return name.startsWith("xgen_");
2407
+ }
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");
2420
+ }
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);
2434
+ }
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`;
2444
+ }
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() {
2456
+ const server = getServer();
2457
+ const auth = getAuth();
2458
+ return `\uC11C\uBC84: ${server}
2459
+ \uC0AC\uC6A9\uC790: ${auth?.username}
2460
+ User ID: ${auth?.userId}`;
2461
+ }
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");
2472
+ }
2580
2473
 
2581
- // src/commands/workflow/run.ts
2582
- init_store();
2583
- init_workflow();
2584
- import chalk7 from "chalk";
2585
- import { randomUUID } from "crypto";
2586
-
2587
- // src/utils/sse.ts
2588
- async function parseSSEStream(stream, onEvent, onDone, onError) {
2589
- let buffer = "";
2590
- return new Promise((resolve, reject) => {
2591
- stream.on("data", (chunk) => {
2592
- buffer += chunk.toString();
2593
- const parts = buffer.split("\n\n");
2594
- buffer = parts.pop() ?? "";
2595
- for (const part of parts) {
2596
- const lines = part.split("\n");
2597
- let data = "";
2598
- for (const line of lines) {
2599
- if (line.startsWith("data: ")) {
2600
- data += line.slice(6);
2601
- } else if (line.startsWith("data:")) {
2602
- data += line.slice(5);
2603
- }
2604
- }
2605
- if (!data) continue;
2606
- try {
2607
- const event = JSON.parse(data);
2608
- onEvent(event);
2609
- } catch {
2610
- onEvent({ type: "token", content: data });
2611
- }
2612
- }
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 }
2613
2494
  });
2614
- stream.on("end", () => {
2615
- if (buffer.trim()) {
2616
- const lines = buffer.split("\n");
2617
- for (const line of lines) {
2618
- if (line.startsWith("data: ")) {
2619
- try {
2620
- const event = JSON.parse(line.slice(6));
2621
- onEvent(event);
2622
- } catch {
2623
- onEvent({ type: "token", content: line.slice(6) });
2624
- }
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);
2625
2506
  }
2626
2507
  }
2508
+ } catch {
2627
2509
  }
2628
- onDone?.();
2629
- resolve();
2630
2510
  });
2631
- stream.on("error", (err) => {
2632
- onError?.(err);
2633
- reject(err);
2511
+ this.process.on("error", (err) => {
2512
+ console.error(`MCP [${this.serverName}] \uD504\uB85C\uC138\uC2A4 \uC624\uB958:`, err.message);
2634
2513
  });
2635
- });
2636
- }
2637
-
2638
- // src/commands/workflow/run.ts
2639
- init_format();
2640
-
2641
- // src/utils/markdown.ts
2642
- import chalk6 from "chalk";
2643
- var CODE_BLOCK_RE = /```(\w*)\n([\s\S]*?)```/g;
2644
- var INLINE_CODE_RE = /`([^`]+)`/g;
2645
- var BOLD_RE = /\*\*(.+?)\*\*/g;
2646
- var HEADING_RE = /^(#{1,3})\s+(.+)$/gm;
2647
- var LIST_RE = /^(\s*)[-*]\s+(.+)$/gm;
2648
- var LINK_RE = /\[([^\]]+)\]\(([^)]+)\)/g;
2649
- function renderMarkdown(text) {
2650
- let result = text;
2651
- result = result.replace(CODE_BLOCK_RE, (_match, lang, code) => {
2652
- const trimmed = code.trimEnd();
2653
- const header = lang ? chalk6.gray(` \u2500\u2500 ${lang} \u2500\u2500`) : chalk6.gray(" \u2500\u2500 code \u2500\u2500");
2654
- const lines = trimmed.split("\n").map((l) => chalk6.white(` ${l}`)).join("\n");
2655
- return `
2656
- ${header}
2657
- ${lines}
2658
- ${chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
2659
- `;
2660
- });
2661
- result = result.replace(INLINE_CODE_RE, (_m, code) => chalk6.cyan(`\`${code}\``));
2662
- result = result.replace(BOLD_RE, (_m, text2) => chalk6.bold(text2));
2663
- result = result.replace(HEADING_RE, (_m, hashes, text2) => {
2664
- if (hashes.length === 1) return chalk6.bold.underline(text2);
2665
- if (hashes.length === 2) return chalk6.bold(text2);
2666
- return chalk6.bold.dim(text2);
2667
- });
2668
- result = result.replace(LIST_RE, (_m, indent, text2) => `${indent}${chalk6.cyan("\u2022")} ${text2}`);
2669
- result = result.replace(LINK_RE, (_m, label, url) => `${chalk6.blue.underline(label)} ${chalk6.gray(`(${url})`)}`);
2670
- return result;
2671
- }
2672
-
2673
- // src/commands/workflow/run.ts
2674
- async function workflowRun(workflowId, input, opts) {
2675
- const auth = requireAuth();
2676
- let workflowName = workflowId;
2677
- try {
2678
- const detail = await getWorkflowDetail(workflowId);
2679
- workflowName = detail.workflow_name ?? workflowId;
2680
- } catch {
2681
- }
2682
- if (!input) {
2683
- if (opts.interactive || !process.stdin.isTTY) {
2684
- const { createInterface: createInterface8 } = await import("readline");
2685
- const rl = createInterface8({ input: process.stdin, output: process.stdout });
2686
- input = await new Promise((resolve) => {
2687
- rl.question(chalk7.cyan("\uC785\uB825> "), (answer) => {
2688
- rl.close();
2689
- resolve(answer.trim());
2690
- });
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
+ }
2691
2539
  });
2692
- } else {
2693
- printError("\uC785\uB825\uAC12\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uBC95:");
2694
- console.log(' xgen workflow run <id> "\uC785\uB825 \uD14D\uC2A4\uFFFD\uFFFD\uFFFD"');
2695
- console.log(" xgen workflow run -i <id>");
2696
- process.exit(1);
2697
- }
2540
+ this.process?.stdin?.write(JSON.stringify(request) + "\n");
2541
+ });
2698
2542
  }
2699
- if (!input) {
2700
- printError("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4");
2701
- process.exit(1);
2543
+ async listTools() {
2544
+ const result = await this.send("tools/list", {});
2545
+ this.tools = result.tools ?? [];
2546
+ return this.tools;
2702
2547
  }
2703
- const interactionId = `cli_${randomUUID().slice(0, 8)}`;
2704
- printHeader(`\uC2E4\uD589: ${workflowName}`);
2705
- printInfo(`\uC785\uB825: ${input}`);
2706
- console.log();
2707
- try {
2708
- const stream = await executeWorkflowStream({
2709
- workflow_id: workflowId,
2710
- workflow_name: workflowName,
2711
- input_data: input,
2712
- interaction_id: interactionId
2713
- });
2714
- let hasOutput = false;
2715
- let fullResponse = "";
2716
- await parseSSEStream(
2717
- stream,
2718
- (event) => {
2719
- switch (event.type) {
2720
- case "token":
2721
- if (event.content) {
2722
- if (!hasOutput) {
2723
- hasOutput = true;
2724
- console.log();
2725
- }
2726
- process.stdout.write(event.content);
2727
- fullResponse += event.content;
2728
- }
2729
- break;
2730
- case "log":
2731
- if (opts.logs && event.content) {
2732
- process.stderr.write(chalk7.gray(`[LOG] ${event.content}
2733
- `));
2734
- }
2735
- break;
2736
- case "node_status":
2737
- if (opts.logs) {
2738
- const nodeName = event.node_name ?? event.node_id ?? "?";
2739
- const status = event.status ?? "?";
2740
- process.stderr.write(
2741
- chalk7.gray(`[\uB178\uB4DC] ${nodeName}: ${status}
2742
- `)
2743
- );
2744
- }
2745
- break;
2746
- case "tool":
2747
- if (opts.logs) {
2748
- process.stderr.write(chalk7.gray(`[\uB3C4\uAD6C] ${JSON.stringify(event.data)}
2749
- `));
2750
- }
2751
- break;
2752
- case "complete":
2753
- break;
2754
- case "error":
2755
- console.log();
2756
- printError(event.error ?? event.content ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958");
2757
- break;
2758
- default:
2759
- if (event.content) {
2760
- if (!hasOutput) {
2761
- process.stdout.write(chalk7.green("\uC751\uB2F5: "));
2762
- hasOutput = true;
2763
- }
2764
- process.stdout.write(event.content);
2765
- }
2766
- }
2767
- },
2768
- () => {
2769
- if (hasOutput) {
2770
- console.log();
2771
- if (fullResponse.includes("```") || fullResponse.includes("**")) {
2772
- console.log(chalk7.gray("\u2500".repeat(40)));
2773
- console.log(renderMarkdown(fullResponse));
2774
- }
2775
- }
2776
- console.log();
2777
- console.log(chalk7.gray(`\uC138\uC158: ${interactionId}`));
2778
- },
2779
- (err) => {
2780
- console.log();
2781
- printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
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") ?? "";
2551
+ }
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: {} }
2782
2559
  }
2783
- );
2784
- } catch (err) {
2785
- const msg = err?.response?.data?.detail ?? err.message;
2786
- printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
2787
- process.exit(1);
2560
+ }));
2788
2561
  }
2789
- }
2790
-
2791
- // src/commands/workflow/history.ts
2792
- init_store();
2793
- init_workflow();
2794
- init_format();
2795
- import chalk8 from "chalk";
2796
- async function workflowHistory(workflowId, opts = {}) {
2797
- requireAuth();
2798
- const limit = opts.limit ?? 20;
2799
- try {
2800
- const logs = await getIOLogs(workflowId, limit);
2801
- if (!logs || logs.length === 0) {
2802
- console.log(chalk8.yellow("\n\uC2E4\uD589 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2803
- return;
2804
- }
2805
- printHeader(`\uC2E4\uD589 \uC774\uB825 (\uCD5C\uADFC ${logs.length}\uAC74)`);
2806
- console.log();
2807
- for (const log of logs) {
2808
- console.log(
2809
- ` ${chalk8.gray(formatDate(log.created_at))} ${chalk8.cyan(log.interaction_id)}`
2810
- );
2811
- console.log(` ${chalk8.white("\uC785\uB825:")} ${truncate(log.input_data, 60)}`);
2812
- console.log(
2813
- ` ${chalk8.green("\uCD9C\uB825:")} ${truncate(log.output_data, 60)}`
2814
- );
2815
- if (log.execution_time) {
2816
- console.log(
2817
- ` ${chalk8.gray("\uC2DC\uAC04:")} ${(log.execution_time / 1e3).toFixed(1)}s`
2818
- );
2562
+ stop() {
2563
+ this.process?.kill();
2564
+ this.process = null;
2565
+ }
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;
2819
2579
  }
2820
- console.log();
2821
2580
  }
2822
- } catch (err) {
2823
- const msg = err.message;
2824
- printError(`\uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
2825
- process.exit(1);
2826
2581
  }
2582
+ return null;
2827
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
+ }
2597
+ }
2598
+ }
2599
+ getAllTools() {
2600
+ const tools2 = [];
2601
+ for (const client2 of this.clients.values()) {
2602
+ tools2.push(...client2.getOpenAITools());
2603
+ }
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
+ };
2828
2631
 
2829
- // src/commands/workflow/index.ts
2830
- function registerWorkflowCommand(program2) {
2831
- const wf = program2.command("workflow").alias("wf").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAD00\uB9AC \uBC0F \uC2E4\uD589");
2832
- 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));
2833
- wf.command("info <workflow-id>").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uC138 \uC815\uBCF4").action((id) => workflowInfo(id));
2834
- 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));
2835
- 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) }));
2836
- }
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.
2837
2640
 
2838
- // src/commands/chat.ts
2839
- init_store();
2840
- init_workflow();
2841
- import chalk9 from "chalk";
2842
- import { createInterface as createInterface2 } from "readline";
2843
- import { randomUUID as randomUUID2 } from "crypto";
2844
- init_format();
2845
- var CHAT_BANNER = `
2846
- ${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")}
2847
- ${chalk9.cyan("\u2502")} ${chalk9.white.bold("XGEN")} ${chalk9.gray("\u2014 \uC6CC\uD06C\uD50C\uB85C\uC6B0 AI \uD130\uBBF8\uB110")} ${chalk9.cyan("\u2502")}
2848
- ${chalk9.cyan("\u2502")} ${chalk9.gray("/help \uB3C4\uC6C0\uB9D0 /workflows \uC804\uD658 /exit")} ${chalk9.cyan("\u2502")}
2849
- ${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")}`;
2850
- function printHelp() {
2851
- console.log(`
2852
- ${chalk9.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
2853
- ${chalk9.cyan("/workflows")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uAE30 & \uC804\uD658
2854
- ${chalk9.cyan("/switch")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBC88\uD638\uB85C \uC804\uD658 (\uC608: /switch 3)
2855
- ${chalk9.cyan("/history")} \uD604\uC7AC \uC138\uC158 \uB300\uD654 \uC774\uB825
2856
- ${chalk9.cyan("/clear")} \uD654\uBA74 \uC9C0\uC6B0\uAE30
2857
- ${chalk9.cyan("/info")} \uD604\uC7AC \uC5F0\uACB0 \uC815\uBCF4
2858
- ${chalk9.cyan("/help")} \uC774 \uB3C4\uC6C0\uB9D0
2859
- ${chalk9.cyan("/exit")} \uC885\uB8CC (Ctrl+C\uB3C4 \uAC00\uB2A5)
2860
- `);
2861
- }
2862
- async function promptLine(rl, promptStr) {
2863
- return new Promise((resolve) => {
2864
- rl.question(promptStr, (answer) => resolve(answer));
2865
- });
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;
2866
2664
  }
2867
- async function chat(workflowId) {
2868
- const auth = requireAuth();
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();
2869
2687
  const server = getServer();
2870
- let workflows = [];
2871
- try {
2872
- workflows = await listWorkflows();
2873
- } catch {
2874
- printError("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
2875
- process.exit(1);
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://", "")}`));
2876
2693
  }
2877
- if (workflows.length === 0) {
2878
- printError("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4");
2879
- process.exit(1);
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
2696
+ `));
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;
2713
+ }
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;
2726
+ }
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;
2732
+ }
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(", ")}`);
2744
+ }
2745
+ console.log();
2746
+ continue;
2747
+ }
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;
2757
+ }
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 });
2775
+ try {
2776
+ await runLoop(client2, provider.model, messages, allTools);
2777
+ } catch (err) {
2778
+ console.log(chalk12.red(`
2779
+ \uC624\uB958: ${err.message}
2780
+ `));
2781
+ }
2880
2782
  }
2881
- let current;
2882
- if (workflowId) {
2883
- const found = workflows.find((w) => w.id === workflowId || w.workflow_name === workflowId);
2884
- current = found ?? { id: workflowId, workflow_name: workflowId };
2783
+ }
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;
2791
+ }
2792
+ process.stdout.write(delta);
2793
+ });
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 });
2797
+ return;
2798
+ }
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
+ }
2831
+ }
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 });
2885
2854
  } else {
2886
- console.log(CHAT_BANNER);
2887
- 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
2888
2870
  `));
2889
- console.log(chalk9.bold(" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC120\uD0DD:\n"));
2890
- workflows.forEach((w, i) => {
2891
- console.log(` ${chalk9.cyan(String(i + 1).padStart(3))} ${w.workflow_name}`);
2892
- });
2893
- console.log();
2894
- const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
2895
- const answer = await promptLine(rl2, chalk9.cyan(" \uBC88\uD638> "));
2896
- rl2.close();
2897
- const idx = parseInt(answer.trim()) - 1;
2898
- if (isNaN(idx) || idx < 0 || idx >= workflows.length) {
2899
- current = workflows[0];
2900
2871
  } else {
2901
- current = workflows[idx];
2872
+ console.log(chalk12.red(` \u2717 ${result.message}
2873
+ `));
2902
2874
  }
2875
+ } catch (err) {
2876
+ console.log(chalk12.red(` \u2717 ${err.message}
2877
+ `));
2903
2878
  }
2904
- const sessionId = randomUUID2().slice(0, 8);
2905
- let turnCount = 0;
2906
- 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();
2907
2888
  console.log();
2908
- console.log(chalk9.cyan("\u2500".repeat(42)));
2909
- console.log(chalk9.white.bold(` ${current.workflow_name}`));
2910
- console.log(chalk9.cyan("\u2500".repeat(42)));
2911
- console.log(chalk9.gray(" \uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694. /help \uB85C \uB3C4\uC6C0\uB9D0.\n"));
2912
- const rl = createInterface2({
2913
- input: process.stdin,
2914
- 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)}`);
2915
2892
  });
2916
- const getPrompt = () => chalk9.cyan("\u276F ");
2917
- const processInput = async (line) => {
2918
- const input = line.trim();
2919
- if (!input) return;
2920
- if (input.startsWith("/")) {
2921
- const [cmd, ...args] = input.slice(1).split(" ");
2922
- switch (cmd.toLowerCase()) {
2923
- case "exit":
2924
- case "quit":
2925
- case "q":
2926
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
2927
- rl.close();
2928
- process.exit(0);
2929
- break;
2930
- case "help":
2931
- case "h":
2932
- printHelp();
2933
- break;
2934
- case "clear":
2935
- case "cls":
2936
- console.clear();
2937
- console.log(chalk9.white.bold(` ${current.workflow_name}`));
2938
- console.log(chalk9.cyan("\u2500".repeat(42)));
2939
- break;
2940
- case "workflows":
2941
- case "wf":
2942
- console.log();
2943
- workflows.forEach((w, i) => {
2944
- const marker = w.id === current.id ? chalk9.green("\u25B8") : " ";
2945
- console.log(` ${marker} ${chalk9.cyan(String(i + 1).padStart(2))} ${w.workflow_name}`);
2946
- });
2947
- console.log(chalk9.gray("\n /switch <\uBC88\uD638> \uB85C \uC804\uD658\n"));
2948
- break;
2949
- case "switch":
2950
- case "sw": {
2951
- const num = parseInt(args[0]);
2952
- if (isNaN(num) || num < 1 || num > workflows.length) {
2953
- console.log(chalk9.yellow(` 1~${workflows.length} \uC0AC\uC774 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694`));
2954
- } else {
2955
- current = workflows[num - 1];
2956
- turnCount = 0;
2957
- history.length = 0;
2958
- console.log(chalk9.green(`
2959
- \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}
2960
2898
  `));
2961
- }
2962
- break;
2963
- }
2964
- case "history":
2965
- case "hist":
2966
- if (history.length === 0) {
2967
- console.log(chalk9.gray(" \uB300\uD654 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
2968
- } else {
2969
- console.log();
2970
- for (const h of history) {
2971
- const label = h.role === "user" ? chalk9.cyan("\uB098") : chalk9.green("AI");
2972
- const text = h.content.length > 80 ? h.content.slice(0, 80) + "..." : h.content;
2973
- console.log(` ${label}: ${text}`);
2974
- }
2975
- console.log();
2976
- }
2977
- break;
2978
- case "info":
2979
- console.log(`
2980
- ${chalk9.gray("\uC11C\uBC84:")} ${server}
2981
- ${chalk9.gray("\uC0AC\uC6A9\uC790:")} ${auth.username}
2982
- ${chalk9.gray("\uC6CC\uD06C\uD50C\uB85C\uC6B0:")} ${current.workflow_name}
2983
- ${chalk9.gray("\uC138\uC158:")} ${sessionId}
2984
- ${chalk9.gray("\uD134:")} ${turnCount}
2985
- `);
2986
- break;
2987
- default:
2988
- console.log(chalk9.yellow(` \uC54C \uC218 \uC5C6\uB294 \uCEE4\uB9E8\uB4DC: /${cmd}. /help \uCC38\uACE0`));
2989
- }
2990
- rl.prompt();
2991
- return;
2992
- }
2993
- turnCount++;
2994
- const interactionId = `${sessionId}_t${turnCount}`;
2995
- history.push({ role: "user", content: input });
2996
- process.stdout.write(chalk9.gray(" thinking..."));
2997
- try {
2998
- const stream = await executeWorkflowStream({
2999
- workflow_id: current.id,
3000
- workflow_name: current.workflow_name,
3001
- input_data: input,
3002
- interaction_id: interactionId
3003
- });
3004
- process.stdout.write("\r" + " ".repeat(20) + "\r");
3005
- let fullResponse = "";
3006
- let hasOutput = false;
3007
- await parseSSEStream(
3008
- stream,
3009
- (event) => {
3010
- if ((event.type === "token" || !event.type) && event.content) {
3011
- if (!hasOutput) {
3012
- hasOutput = true;
3013
- console.log();
3014
- }
3015
- process.stdout.write(event.content);
3016
- fullResponse += event.content;
3017
- } else if (event.type === "error") {
3018
- process.stdout.write("\r" + " ".repeat(20) + "\r");
3019
- printError(event.error ?? event.content ?? "\uC624\uB958");
3020
- }
3021
- },
3022
- () => {
3023
- if (hasOutput) {
3024
- console.log();
3025
- console.log();
3026
- }
3027
- if (fullResponse) {
3028
- history.push({ role: "assistant", content: fullResponse });
3029
- }
3030
- },
3031
- (err) => {
3032
- process.stdout.write("\r" + " ".repeat(20) + "\r");
3033
- printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
3034
- }
3035
- );
3036
- } catch (err) {
3037
- process.stdout.write("\r" + " ".repeat(20) + "\r");
3038
- const msg = err?.response?.data?.detail ?? err.message;
3039
- printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
3040
- }
3041
- rl.prompt();
3042
- };
3043
- rl.setPrompt(getPrompt());
3044
- rl.prompt();
3045
- rl.on("line", (line) => {
3046
- processInput(line).then(() => {
3047
- });
3048
- });
3049
- rl.on("close", () => {
3050
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
3051
- process.exit(0);
3052
- });
3053
- process.on("SIGINT", () => {
3054
- console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
3055
- process.exit(0);
3056
- });
2899
+ }
3057
2900
  }
3058
- function registerChatCommand(program2) {
3059
- 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
+ });
3060
2905
  }
3061
2906
 
3062
- // src/index.ts
3063
- init_provider();
3064
- init_agent();
3065
-
3066
2907
  // src/commands/doc.ts
3067
2908
  init_store();
3068
2909
  init_document();
@@ -3121,10 +2962,38 @@ function registerDocCommand(program2) {
3121
2962
 
3122
2963
  // src/commands/ontology.ts
3123
2964
  init_store();
3124
- init_ontology();
3125
- init_format();
3126
2965
  import chalk14 from "chalk";
3127
2966
  import { createInterface as createInterface6 } from "readline";
2967
+
2968
+ // src/api/ontology.ts
2969
+ init_client();
2970
+ async function queryGraphRAG(query, graphId, opts) {
2971
+ const client2 = getClient();
2972
+ const res = await client2.post("/api/graph-rag", {
2973
+ query,
2974
+ graph_id: graphId,
2975
+ use_scs: opts?.scs ?? true
2976
+ });
2977
+ return res.data;
2978
+ }
2979
+ async function queryGraphRAGMultiTurn(query, sessionId, graphId, opts) {
2980
+ const client2 = getClient();
2981
+ const res = await client2.post("/api/graph-rag/multi-turn", {
2982
+ query,
2983
+ session_id: sessionId,
2984
+ graph_id: graphId,
2985
+ max_turns: opts?.maxTurns ?? 5
2986
+ });
2987
+ return res.data;
2988
+ }
2989
+ async function getGraphStats(graphId) {
2990
+ const client2 = getClient();
2991
+ const res = await client2.get(`/api/graph/${graphId}/stats`);
2992
+ return res.data;
2993
+ }
2994
+
2995
+ // src/commands/ontology.ts
2996
+ init_format();
3128
2997
  import { randomUUID as randomUUID3 } from "crypto";
3129
2998
  function registerOntologyCommand(program2) {
3130
2999
  const ont = program2.command("ontology").alias("ont").description("\uC628\uD1A8\uB85C\uC9C0 GraphRAG \uC9C8\uC758");
@@ -3190,42 +3059,42 @@ ${result.answer}
3190
3059
 
3191
3060
  // src/index.ts
3192
3061
  var VERSION = "0.3.0";
3193
- var LOGO = chalk17.cyan(`
3062
+ var LOGO = chalk15.cyan(`
3194
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
3195
3064
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
3196
3065
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3197
3066
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3198
3067
  \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
3199
- `) + chalk17.white.bold(`
3068
+ `) + chalk15.white.bold(`
3200
3069
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
3201
3070
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
3202
3071
  \u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3203
3072
  \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
3204
3073
  \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
3205
- `) + chalk17.gray(` v${VERSION}
3074
+ `) + chalk15.gray(` v${VERSION}
3206
3075
  `);
3207
3076
  var BANNER = LOGO;
3208
3077
  var program = new Command();
3209
3078
  program.name("xgen").description("OPEN XGEN \u2014 AI Coding Agent + XGEN Platform CLI").version(VERSION).addHelpText("before", BANNER).addHelpText(
3210
3079
  "after",
3211
3080
  `
3212
- ${chalk17.bold("\uC2DC\uC791\uD558\uAE30:")}
3213
- ${chalk17.cyan("xgen provider add")} AI \uD504\uB85C\uBC14\uC774\uB354 \uC124\uC815
3214
- ${chalk17.cyan("xgen agent")} AI \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8
3215
- ${chalk17.cyan("xgen config set-server")} <url> XGEN \uC11C\uBC84 \uC5F0\uACB0
3216
- ${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
3217
3086
 
3218
- ${chalk17.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
3219
- ${chalk17.cyan("xgen agent")} \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8 (\uD30C\uC77C, \uD130\uBBF8\uB110, \uAC80\uC0C9)
3220
- ${chalk17.cyan("xgen provider ls")} \uD504\uB85C\uBC14\uC774\uB354 \uBAA9\uB85D
3221
- ${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
3222
3091
 
3223
- ${chalk17.bold("XGEN \uD50C\uB7AB\uD3FC:")}
3224
- ${chalk17.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
3225
- ${chalk17.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
3226
- ${chalk17.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
3227
- ${chalk17.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
3228
- ${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
3229
3098
  `
3230
3099
  );
3231
3100
  registerConfigCommand(program);
@@ -3238,15 +3107,15 @@ registerDocCommand(program);
3238
3107
  registerOntologyCommand(program);
3239
3108
  if (process.argv.length <= 2) {
3240
3109
  if (process.stdin.isTTY) {
3241
- Promise.resolve().then(() => (init_dashboard(), dashboard_exports)).then(
3242
- ({ dashboard: dashboard2 }) => dashboard2().catch((err) => {
3243
- 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}`));
3244
3113
  process.exit(1);
3245
3114
  })
3246
3115
  );
3247
3116
  } else {
3248
3117
  agentRepl().catch((err) => {
3249
- console.error(chalk17.red(`\uC624\uB958: ${err.message}`));
3118
+ console.error(chalk15.red(`\uC624\uB958: ${err.message}`));
3250
3119
  process.exit(1);
3251
3120
  });
3252
3121
  }