openxgen 1.0.0 → 1.1.1

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