openxgen 1.1.1 → 1.3.0

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