openxgen 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2161 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/config/store.ts
13
+ var store_exports = {};
14
+ __export(store_exports, {
15
+ addProvider: () => addProvider,
16
+ clearAuth: () => clearAuth,
17
+ getAccessToken: () => getAccessToken,
18
+ getAuth: () => getAuth,
19
+ getConfig: () => getConfig,
20
+ getDefaultProvider: () => getDefaultProvider,
21
+ getProviders: () => getProviders,
22
+ getProvidersStore: () => getProvidersStore,
23
+ getRefreshToken: () => getRefreshToken,
24
+ getServer: () => getServer,
25
+ removeProvider: () => removeProvider,
26
+ requireAuth: () => requireAuth,
27
+ requireServer: () => requireServer,
28
+ setAuth: () => setAuth,
29
+ setConfig: () => setConfig,
30
+ setDefaultProvider: () => setDefaultProvider,
31
+ setServer: () => setServer
32
+ });
33
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
34
+ import { homedir } from "os";
35
+ import { join } from "path";
36
+ function ensureDir() {
37
+ if (!existsSync(XGEN_DIR)) {
38
+ mkdirSync(XGEN_DIR, { recursive: true, mode: 448 });
39
+ }
40
+ }
41
+ function readJson(filePath, fallback) {
42
+ try {
43
+ if (!existsSync(filePath)) return fallback;
44
+ const data = readFileSync(filePath, "utf-8");
45
+ return JSON.parse(data);
46
+ } catch {
47
+ return fallback;
48
+ }
49
+ }
50
+ function writeJson(filePath, data, secure = false) {
51
+ ensureDir();
52
+ writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
53
+ if (secure) {
54
+ chmodSync(filePath, 384);
55
+ }
56
+ }
57
+ function getConfig() {
58
+ return { ...DEFAULT_CONFIG, ...readJson(CONFIG_FILE, {}) };
59
+ }
60
+ function setConfig(partial) {
61
+ const current = getConfig();
62
+ writeJson(CONFIG_FILE, { ...current, ...partial });
63
+ }
64
+ function getServer() {
65
+ return getConfig().server;
66
+ }
67
+ function setServer(url) {
68
+ const normalized = url.replace(/\/+$/, "");
69
+ setConfig({ server: normalized });
70
+ }
71
+ function getAuth() {
72
+ const auth = readJson(AUTH_FILE, null);
73
+ if (!auth || !auth.accessToken) return null;
74
+ return auth;
75
+ }
76
+ function setAuth(auth) {
77
+ writeJson(AUTH_FILE, auth, true);
78
+ }
79
+ function clearAuth() {
80
+ writeJson(AUTH_FILE, {}, true);
81
+ }
82
+ function getAccessToken() {
83
+ return getAuth()?.accessToken ?? null;
84
+ }
85
+ function getRefreshToken() {
86
+ return getAuth()?.refreshToken ?? null;
87
+ }
88
+ function getProvidersStore() {
89
+ return { ...DEFAULT_PROVIDERS, ...readJson(PROVIDERS_FILE, DEFAULT_PROVIDERS) };
90
+ }
91
+ function getProviders() {
92
+ return getProvidersStore().providers;
93
+ }
94
+ function addProvider(provider) {
95
+ const store = getProvidersStore();
96
+ store.providers = store.providers.filter((p) => p.id !== provider.id);
97
+ store.providers.push(provider);
98
+ if (!store.defaultId) store.defaultId = provider.id;
99
+ writeJson(PROVIDERS_FILE, store, true);
100
+ }
101
+ function removeProvider(id) {
102
+ const store = getProvidersStore();
103
+ const before = store.providers.length;
104
+ store.providers = store.providers.filter((p) => p.id !== id);
105
+ if (store.defaultId === id) {
106
+ store.defaultId = store.providers[0]?.id ?? null;
107
+ }
108
+ writeJson(PROVIDERS_FILE, store, true);
109
+ return store.providers.length < before;
110
+ }
111
+ function getDefaultProvider() {
112
+ const store = getProvidersStore();
113
+ if (!store.defaultId) return store.providers[0] ?? null;
114
+ return store.providers.find((p) => p.id === store.defaultId) ?? null;
115
+ }
116
+ function setDefaultProvider(id) {
117
+ const store = getProvidersStore();
118
+ const exists = store.providers.some((p) => p.id === id);
119
+ if (!exists) return false;
120
+ store.defaultId = id;
121
+ writeJson(PROVIDERS_FILE, store, true);
122
+ return true;
123
+ }
124
+ function requireServer() {
125
+ const server = getServer();
126
+ if (!server) {
127
+ console.error("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694:");
128
+ console.error(" xgen config set-server <url>");
129
+ process.exit(1);
130
+ }
131
+ return server;
132
+ }
133
+ function requireAuth() {
134
+ const auth = getAuth();
135
+ if (!auth) {
136
+ console.error("\uB85C\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694:");
137
+ console.error(" xgen login");
138
+ process.exit(1);
139
+ }
140
+ return auth;
141
+ }
142
+ var XGEN_DIR, CONFIG_FILE, AUTH_FILE, PROVIDERS_FILE, DEFAULT_CONFIG, DEFAULT_PROVIDERS;
143
+ var init_store = __esm({
144
+ "src/config/store.ts"() {
145
+ "use strict";
146
+ XGEN_DIR = join(homedir(), ".xgen");
147
+ CONFIG_FILE = join(XGEN_DIR, "config.json");
148
+ AUTH_FILE = join(XGEN_DIR, "auth.json");
149
+ PROVIDERS_FILE = join(XGEN_DIR, "providers.json");
150
+ DEFAULT_CONFIG = {
151
+ server: null,
152
+ defaultWorkflow: null,
153
+ theme: "default",
154
+ streamLogs: false
155
+ };
156
+ DEFAULT_PROVIDERS = { providers: [], defaultId: null };
157
+ }
158
+ });
159
+
160
+ // src/api/auth.ts
161
+ var auth_exports = {};
162
+ __export(auth_exports, {
163
+ apiLogin: () => apiLogin,
164
+ apiRefresh: () => apiRefresh,
165
+ apiValidate: () => apiValidate
166
+ });
167
+ import axios2 from "axios";
168
+ import { createHash } from "crypto";
169
+ async function apiLogin(email, password) {
170
+ const server = getServer();
171
+ if (!server) throw new Error("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
172
+ const hashedPassword = createHash("sha256").update(password).digest("hex");
173
+ const res = await axios2.post(`${server}/api/auth/login`, {
174
+ email,
175
+ password: hashedPassword
176
+ });
177
+ return res.data;
178
+ }
179
+ async function apiValidate(accessToken) {
180
+ const server = getServer();
181
+ if (!server) throw new Error("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
182
+ const res = await axios2.get(`${server}/api/auth/validate`, {
183
+ headers: { Authorization: `Bearer ${accessToken}` }
184
+ });
185
+ return res.data;
186
+ }
187
+ async function apiRefresh(refreshToken) {
188
+ const server = getServer();
189
+ if (!server) throw new Error("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
190
+ const res = await axios2.post(`${server}/api/auth/refresh`, {
191
+ refresh_token: refreshToken
192
+ });
193
+ return res.data;
194
+ }
195
+ var init_auth = __esm({
196
+ "src/api/auth.ts"() {
197
+ "use strict";
198
+ init_store();
199
+ }
200
+ });
201
+
202
+ // src/index.ts
203
+ import { Command } from "commander";
204
+ import chalk14 from "chalk";
205
+
206
+ // src/commands/config.ts
207
+ init_store();
208
+ import chalk2 from "chalk";
209
+
210
+ // src/api/client.ts
211
+ init_store();
212
+ import axios from "axios";
213
+ var client = null;
214
+ function getClient() {
215
+ if (client) return client;
216
+ const server = getServer();
217
+ if (!server) {
218
+ throw new Error("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. xgen config set-server <url>");
219
+ }
220
+ client = axios.create({
221
+ baseURL: server,
222
+ timeout: 12e4,
223
+ headers: {
224
+ "Content-Type": "application/json"
225
+ }
226
+ });
227
+ client.interceptors.request.use((config) => {
228
+ const token = getAccessToken();
229
+ if (token && config.headers) {
230
+ config.headers.Authorization = `Bearer ${token}`;
231
+ }
232
+ return config;
233
+ });
234
+ client.interceptors.response.use(
235
+ (response) => response,
236
+ async (error) => {
237
+ const originalRequest = error.config;
238
+ if (error.response?.status === 401 && !originalRequest._retry && getRefreshToken()) {
239
+ originalRequest._retry = true;
240
+ try {
241
+ const refreshToken = getRefreshToken();
242
+ const server2 = getServer();
243
+ const res = await axios.post(`${server2}/api/auth/refresh`, {
244
+ refresh_token: refreshToken
245
+ });
246
+ if (res.data.success && res.data.access_token) {
247
+ const auth = getAuth();
248
+ setAuth({
249
+ ...auth,
250
+ accessToken: res.data.access_token
251
+ });
252
+ originalRequest.headers.Authorization = `Bearer ${res.data.access_token}`;
253
+ return client(originalRequest);
254
+ }
255
+ } catch {
256
+ clearAuth();
257
+ console.error("\n\uC138\uC158\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uB85C\uADF8\uC778\uD558\uC138\uC694: xgen login");
258
+ process.exit(1);
259
+ }
260
+ }
261
+ return Promise.reject(error);
262
+ }
263
+ );
264
+ return client;
265
+ }
266
+ function resetClient() {
267
+ client = null;
268
+ }
269
+
270
+ // src/utils/format.ts
271
+ import chalk from "chalk";
272
+ function printHeader(text) {
273
+ const line = "\u2500".repeat(Math.max(text.length + 4, 40));
274
+ console.log(chalk.cyan(line));
275
+ console.log(chalk.cyan.bold(` ${text}`));
276
+ console.log(chalk.cyan(line));
277
+ }
278
+ function printSuccess(text) {
279
+ console.log(chalk.green(`\u2713 ${text}`));
280
+ }
281
+ function printError(text) {
282
+ console.error(chalk.red(`\u2717 ${text}`));
283
+ }
284
+ function printInfo(text) {
285
+ console.log(chalk.blue(`\u2139 ${text}`));
286
+ }
287
+ function printKeyValue(key, value) {
288
+ console.log(` ${chalk.gray(key + ":")} ${value ?? chalk.dim("(\uC5C6\uC74C)")}`);
289
+ }
290
+ function printTable(headers, rows) {
291
+ const widths = headers.map((h, i) => {
292
+ const colMax = rows.reduce((max, row) => Math.max(max, (row[i] ?? "").length), 0);
293
+ return Math.max(h.length, colMax);
294
+ });
295
+ const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(" ");
296
+ console.log(chalk.bold(headerLine));
297
+ console.log(chalk.gray("\u2500".repeat(headerLine.length)));
298
+ for (const row of rows) {
299
+ const line = row.map((cell, i) => (cell ?? "").padEnd(widths[i])).join(" ");
300
+ console.log(line);
301
+ }
302
+ }
303
+ function truncate(text, maxLen = 50) {
304
+ if (text.length <= maxLen) return text;
305
+ return text.slice(0, maxLen - 3) + "...";
306
+ }
307
+ function formatDate(dateStr) {
308
+ if (!dateStr) return "-";
309
+ try {
310
+ const d = new Date(dateStr);
311
+ return d.toLocaleDateString("ko-KR") + " " + d.toLocaleTimeString("ko-KR", { hour: "2-digit", minute: "2-digit" });
312
+ } catch {
313
+ return dateStr;
314
+ }
315
+ }
316
+
317
+ // src/commands/config.ts
318
+ function registerConfigCommand(program2) {
319
+ const config = program2.command("config").description("XGEN CLI \uC124\uC815 \uAD00\uB9AC");
320
+ config.command("set-server <url>").description("XGEN \uC11C\uBC84 URL \uC124\uC815").action((url) => {
321
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
322
+ printError("URL\uC740 http:// \uB610\uB294 https://\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4");
323
+ process.exit(1);
324
+ }
325
+ setServer(url);
326
+ resetClient();
327
+ printSuccess(`\uC11C\uBC84 \uC124\uC815 \uC644\uB8CC: ${chalk2.underline(url)}`);
328
+ });
329
+ config.command("get-server").description("\uD604\uC7AC \uC124\uC815\uB41C \uC11C\uBC84 URL \uD655\uC778").action(() => {
330
+ const server = getServer();
331
+ if (server) {
332
+ console.log(server);
333
+ } else {
334
+ printError("\uC11C\uBC84\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
335
+ console.log(" \uC124\uC815: xgen config set-server <url>");
336
+ }
337
+ });
338
+ config.command("list").description("\uC804\uCCB4 \uC124\uC815 \uD655\uC778").action(() => {
339
+ const cfg = getConfig();
340
+ console.log(chalk2.bold("\nXGEN CLI \uC124\uC815"));
341
+ console.log(chalk2.gray("\u2500".repeat(40)));
342
+ printKeyValue("\uC11C\uBC84", cfg.server);
343
+ printKeyValue("\uAE30\uBCF8 \uC6CC\uD06C\uD50C\uB85C\uC6B0", cfg.defaultWorkflow);
344
+ printKeyValue("\uD14C\uB9C8", cfg.theme);
345
+ printKeyValue("\uC2A4\uD2B8\uB9BC \uB85C\uADF8", String(cfg.streamLogs));
346
+ console.log();
347
+ });
348
+ config.command("set <key> <value>").description("\uC124\uC815 \uAC12 \uBCC0\uACBD").action((key, value) => {
349
+ const allowedKeys = ["defaultWorkflow", "theme", "streamLogs"];
350
+ if (!allowedKeys.includes(key)) {
351
+ printError(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${key}`);
352
+ console.log(` \uC0AC\uC6A9 \uAC00\uB2A5: ${allowedKeys.join(", ")}`);
353
+ process.exit(1);
354
+ }
355
+ const parsed = key === "streamLogs" ? value === "true" : value;
356
+ setConfig({ [key]: parsed });
357
+ printSuccess(`${key} = ${value}`);
358
+ });
359
+ }
360
+
361
+ // src/commands/login.ts
362
+ init_auth();
363
+ init_store();
364
+ import chalk3 from "chalk";
365
+ import { createInterface } from "readline";
366
+ function prompt(question, hidden = false) {
367
+ return new Promise((resolve) => {
368
+ const rl = createInterface({
369
+ input: process.stdin,
370
+ output: process.stdout
371
+ });
372
+ if (hidden) {
373
+ process.stdout.write(question);
374
+ const stdin = process.stdin;
375
+ const wasRaw = stdin.isRaw;
376
+ if (stdin.isTTY) stdin.setRawMode(true);
377
+ let password = "";
378
+ const onData = (ch) => {
379
+ const c = ch.toString("utf8");
380
+ if (c === "\n" || c === "\r" || c === "") {
381
+ if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
382
+ stdin.removeListener("data", onData);
383
+ process.stdout.write("\n");
384
+ rl.close();
385
+ resolve(password);
386
+ } else if (c === "") {
387
+ process.exit(0);
388
+ } else if (c === "\x7F" || c === "\b") {
389
+ if (password.length > 0) {
390
+ password = password.slice(0, -1);
391
+ process.stdout.write("\b \b");
392
+ }
393
+ } else {
394
+ password += c;
395
+ process.stdout.write("*");
396
+ }
397
+ };
398
+ stdin.on("data", onData);
399
+ } else {
400
+ rl.question(question, (answer) => {
401
+ rl.close();
402
+ resolve(answer.trim());
403
+ });
404
+ }
405
+ });
406
+ }
407
+ function registerLoginCommand(program2) {
408
+ 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) => {
409
+ const server = requireServer();
410
+ printHeader("XGEN Login");
411
+ console.log(chalk3.gray(`\uC11C\uBC84: ${server}
412
+ `));
413
+ let email = opts.email;
414
+ let password = opts.password;
415
+ if (!email) {
416
+ email = await prompt(chalk3.white("\uC774\uBA54\uC77C: "));
417
+ }
418
+ if (!password) {
419
+ password = await prompt(chalk3.white("\uBE44\uBC00\uBC88\uD638: "), true);
420
+ }
421
+ if (!email || !password) {
422
+ printError("\uC774\uBA54\uC77C\uACFC \uBE44\uBC00\uBC88\uD638\uB97C \uBAA8\uB450 \uC785\uB825\uD558\uC138\uC694");
423
+ process.exit(1);
424
+ }
425
+ try {
426
+ const result = await apiLogin(email, password);
427
+ if (result.success && result.access_token) {
428
+ setAuth({
429
+ accessToken: result.access_token,
430
+ refreshToken: result.refresh_token ?? "",
431
+ userId: result.user_id ?? "",
432
+ username: result.username ?? "",
433
+ isAdmin: false,
434
+ expiresAt: null
435
+ });
436
+ console.log();
437
+ printSuccess(`\uB85C\uADF8\uC778 \uC131\uACF5! ${chalk3.bold(result.username ?? email)}`);
438
+ } else {
439
+ printError(result.message || "\uB85C\uADF8\uC778 \uC2E4\uD328");
440
+ process.exit(1);
441
+ }
442
+ } catch (err) {
443
+ const msg = err?.response?.data?.message ?? err?.response?.data?.detail ?? err.message;
444
+ printError(`\uB85C\uADF8\uC778 \uC2E4\uD328: ${msg}`);
445
+ process.exit(1);
446
+ }
447
+ });
448
+ program2.command("logout").description("\uB85C\uADF8\uC544\uC6C3").action(async () => {
449
+ const { clearAuth: clearAuth2 } = await Promise.resolve().then(() => (init_store(), store_exports));
450
+ clearAuth2();
451
+ printSuccess("\uB85C\uADF8\uC544\uC6C3 \uC644\uB8CC");
452
+ });
453
+ program2.command("whoami").description("\uD604\uC7AC \uB85C\uADF8\uC778\uB41C \uC0AC\uC6A9\uC790 \uC815\uBCF4").action(async () => {
454
+ const auth = getAuth();
455
+ if (!auth) {
456
+ printError("\uB85C\uADF8\uC778\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. xgen login \uC2E4\uD589\uD558\uC138\uC694");
457
+ process.exit(1);
458
+ }
459
+ const server = requireServer();
460
+ console.log(chalk3.bold("\n\uD604\uC7AC \uC0AC\uC6A9\uC790"));
461
+ console.log(chalk3.gray("\u2500".repeat(30)));
462
+ console.log(` ${chalk3.gray("\uC11C\uBC84:")} ${server}`);
463
+ console.log(` ${chalk3.gray("\uC0AC\uC6A9\uC790:")} ${chalk3.bold(auth.username)}`);
464
+ console.log(` ${chalk3.gray("User ID:")} ${auth.userId}`);
465
+ try {
466
+ const { apiValidate: apiValidate2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
467
+ const result = await apiValidate2(auth.accessToken);
468
+ if (result.valid) {
469
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.green("\uD65C\uC131")}`);
470
+ if (result.is_admin) {
471
+ console.log(` ${chalk3.gray("\uAD8C\uD55C:")} ${chalk3.yellow("\uAD00\uB9AC\uC790")}`);
472
+ }
473
+ if (result.user_type) {
474
+ console.log(` ${chalk3.gray("\uC720\uD615:")} ${result.user_type}`);
475
+ }
476
+ } else {
477
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.red("\uD1A0\uD070 \uB9CC\uB8CC")}`);
478
+ }
479
+ } catch {
480
+ console.log(` ${chalk3.gray("\uC0C1\uD0DC:")} ${chalk3.yellow("\uAC80\uC99D \uBD88\uAC00 (\uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328)")}`);
481
+ }
482
+ console.log();
483
+ });
484
+ }
485
+
486
+ // src/commands/workflow/list.ts
487
+ init_store();
488
+ import chalk4 from "chalk";
489
+
490
+ // src/api/workflow.ts
491
+ async function listWorkflows(userId) {
492
+ const client2 = getClient();
493
+ const params = {};
494
+ if (userId) params.user_id = userId;
495
+ const res = await client2.get("/api/workflow/list", { params });
496
+ return res.data.workflows ?? res.data;
497
+ }
498
+ async function getWorkflowDetail(workflowId) {
499
+ const client2 = getClient();
500
+ const res = await client2.get(`/api/workflow/load/${workflowId}`);
501
+ return res.data;
502
+ }
503
+ async function getWorkflowListDetail() {
504
+ const client2 = getClient();
505
+ const res = await client2.get("/api/workflow/list/detail");
506
+ return res.data;
507
+ }
508
+ async function executeWorkflowStream(request) {
509
+ const client2 = getClient();
510
+ const res = await client2.post("/api/workflow/execute/based_id/stream", request, {
511
+ responseType: "stream",
512
+ headers: {
513
+ Accept: "text/event-stream"
514
+ }
515
+ });
516
+ return res.data;
517
+ }
518
+ async function getIOLogs(workflowId, limit = 20) {
519
+ const client2 = getClient();
520
+ const params = { limit };
521
+ if (workflowId) params.workflow_id = workflowId;
522
+ const res = await client2.get("/api/workflow/io_logs", { params });
523
+ return res.data;
524
+ }
525
+
526
+ // src/commands/workflow/list.ts
527
+ async function workflowList(opts) {
528
+ requireAuth();
529
+ try {
530
+ if (opts.detail) {
531
+ const workflows = await getWorkflowListDetail();
532
+ if (!workflows || workflows.length === 0) {
533
+ console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
534
+ return;
535
+ }
536
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
537
+ console.log();
538
+ printTable(
539
+ ["#", "ID", "\uC774\uB984", "\uBC30\uD3EC", "\uC5C5\uB370\uC774\uD2B8"],
540
+ workflows.map((w, i) => [
541
+ String(i + 1),
542
+ (w.workflow_id ?? w.id ?? "-").slice(0, 12),
543
+ truncate(w.workflow_name ?? "-", 30),
544
+ w.deploy_status === "deployed" ? chalk4.green("\uBC30\uD3EC\uB428") : chalk4.gray("\uBBF8\uBC30\uD3EC"),
545
+ formatDate(w.updated_at)
546
+ ])
547
+ );
548
+ } else {
549
+ const workflows = await listWorkflows();
550
+ if (!workflows || workflows.length === 0) {
551
+ console.log(chalk4.yellow("\n\uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
552
+ return;
553
+ }
554
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D (${workflows.length}\uAC1C)`);
555
+ console.log();
556
+ printTable(
557
+ ["#", "ID", "\uC774\uB984"],
558
+ workflows.map((w, i) => [
559
+ String(i + 1),
560
+ (w.workflow_id ?? w.id ?? "-").slice(0, 12),
561
+ w.workflow_name ?? "-"
562
+ ])
563
+ );
564
+ }
565
+ console.log();
566
+ } catch (err) {
567
+ const msg = err.message;
568
+ printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${msg}`);
569
+ process.exit(1);
570
+ }
571
+ }
572
+
573
+ // src/commands/workflow/info.ts
574
+ init_store();
575
+ import chalk5 from "chalk";
576
+ async function workflowInfo(workflowId) {
577
+ requireAuth();
578
+ try {
579
+ const detail = await getWorkflowDetail(workflowId);
580
+ printHeader(`\uC6CC\uD06C\uD50C\uB85C\uC6B0: ${detail.workflow_name ?? workflowId}`);
581
+ console.log();
582
+ printKeyValue("ID", detail.id);
583
+ printKeyValue("\uC774\uB984", detail.workflow_name);
584
+ printKeyValue("\uC124\uBA85", detail.description ?? "(\uC5C6\uC74C)");
585
+ if (detail.nodes && Array.isArray(detail.nodes)) {
586
+ console.log();
587
+ console.log(chalk5.bold(" \uB178\uB4DC \uAD6C\uC131:"));
588
+ for (const node of detail.nodes) {
589
+ const label = node.data?.label ?? node.id;
590
+ const type = node.data?.type ?? "unknown";
591
+ console.log(` ${chalk5.cyan("\u2022")} ${label} ${chalk5.gray(`(${type})`)}`);
592
+ }
593
+ }
594
+ if (detail.parameters && Object.keys(detail.parameters).length > 0) {
595
+ console.log();
596
+ console.log(chalk5.bold(" \uD30C\uB77C\uBBF8\uD130:"));
597
+ for (const [key, val] of Object.entries(detail.parameters)) {
598
+ console.log(` ${chalk5.gray(key)}: ${JSON.stringify(val)}`);
599
+ }
600
+ }
601
+ console.log();
602
+ } catch (err) {
603
+ const msg = err.message;
604
+ printError(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC870\uD68C \uC2E4\uD328: ${msg}`);
605
+ process.exit(1);
606
+ }
607
+ }
608
+
609
+ // src/commands/workflow/run.ts
610
+ init_store();
611
+ import chalk7 from "chalk";
612
+ import { randomUUID } from "crypto";
613
+
614
+ // src/utils/sse.ts
615
+ async function parseSSEStream(stream, onEvent, onDone, onError) {
616
+ let buffer = "";
617
+ return new Promise((resolve, reject) => {
618
+ stream.on("data", (chunk) => {
619
+ buffer += chunk.toString();
620
+ const parts = buffer.split("\n\n");
621
+ buffer = parts.pop() ?? "";
622
+ for (const part of parts) {
623
+ const lines = part.split("\n");
624
+ let data = "";
625
+ for (const line of lines) {
626
+ if (line.startsWith("data: ")) {
627
+ data += line.slice(6);
628
+ } else if (line.startsWith("data:")) {
629
+ data += line.slice(5);
630
+ }
631
+ }
632
+ if (!data) continue;
633
+ try {
634
+ const event = JSON.parse(data);
635
+ onEvent(event);
636
+ } catch {
637
+ onEvent({ type: "token", content: data });
638
+ }
639
+ }
640
+ });
641
+ stream.on("end", () => {
642
+ if (buffer.trim()) {
643
+ const lines = buffer.split("\n");
644
+ for (const line of lines) {
645
+ if (line.startsWith("data: ")) {
646
+ try {
647
+ const event = JSON.parse(line.slice(6));
648
+ onEvent(event);
649
+ } catch {
650
+ onEvent({ type: "token", content: line.slice(6) });
651
+ }
652
+ }
653
+ }
654
+ }
655
+ onDone?.();
656
+ resolve();
657
+ });
658
+ stream.on("error", (err) => {
659
+ onError?.(err);
660
+ reject(err);
661
+ });
662
+ });
663
+ }
664
+
665
+ // src/utils/markdown.ts
666
+ import chalk6 from "chalk";
667
+ var CODE_BLOCK_RE = /```(\w*)\n([\s\S]*?)```/g;
668
+ var INLINE_CODE_RE = /`([^`]+)`/g;
669
+ var BOLD_RE = /\*\*(.+?)\*\*/g;
670
+ var HEADING_RE = /^(#{1,3})\s+(.+)$/gm;
671
+ var LIST_RE = /^(\s*)[-*]\s+(.+)$/gm;
672
+ var LINK_RE = /\[([^\]]+)\]\(([^)]+)\)/g;
673
+ function renderMarkdown(text) {
674
+ let result = text;
675
+ result = result.replace(CODE_BLOCK_RE, (_match, lang, code) => {
676
+ const trimmed = code.trimEnd();
677
+ const header = lang ? chalk6.gray(` \u2500\u2500 ${lang} \u2500\u2500`) : chalk6.gray(" \u2500\u2500 code \u2500\u2500");
678
+ const lines = trimmed.split("\n").map((l) => chalk6.white(` ${l}`)).join("\n");
679
+ return `
680
+ ${header}
681
+ ${lines}
682
+ ${chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
683
+ `;
684
+ });
685
+ result = result.replace(INLINE_CODE_RE, (_m, code) => chalk6.cyan(`\`${code}\``));
686
+ result = result.replace(BOLD_RE, (_m, text2) => chalk6.bold(text2));
687
+ result = result.replace(HEADING_RE, (_m, hashes, text2) => {
688
+ if (hashes.length === 1) return chalk6.bold.underline(text2);
689
+ if (hashes.length === 2) return chalk6.bold(text2);
690
+ return chalk6.bold.dim(text2);
691
+ });
692
+ result = result.replace(LIST_RE, (_m, indent, text2) => `${indent}${chalk6.cyan("\u2022")} ${text2}`);
693
+ result = result.replace(LINK_RE, (_m, label, url) => `${chalk6.blue.underline(label)} ${chalk6.gray(`(${url})`)}`);
694
+ return result;
695
+ }
696
+
697
+ // src/commands/workflow/run.ts
698
+ async function workflowRun(workflowId, input, opts) {
699
+ const auth = requireAuth();
700
+ let workflowName = workflowId;
701
+ try {
702
+ const detail = await getWorkflowDetail(workflowId);
703
+ workflowName = detail.workflow_name ?? workflowId;
704
+ } catch {
705
+ }
706
+ if (!input) {
707
+ if (opts.interactive || !process.stdin.isTTY) {
708
+ const { createInterface: createInterface7 } = await import("readline");
709
+ const rl = createInterface7({ input: process.stdin, output: process.stdout });
710
+ input = await new Promise((resolve) => {
711
+ rl.question(chalk7.cyan("\uC785\uB825> "), (answer) => {
712
+ rl.close();
713
+ resolve(answer.trim());
714
+ });
715
+ });
716
+ } else {
717
+ printError("\uC785\uB825\uAC12\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uBC95:");
718
+ console.log(' xgen workflow run <id> "\uC785\uB825 \uD14D\uC2A4\uFFFD\uFFFD\uFFFD"');
719
+ console.log(" xgen workflow run -i <id>");
720
+ process.exit(1);
721
+ }
722
+ }
723
+ if (!input) {
724
+ printError("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4");
725
+ process.exit(1);
726
+ }
727
+ const interactionId = `cli_${randomUUID().slice(0, 8)}`;
728
+ printHeader(`\uC2E4\uD589: ${workflowName}`);
729
+ printInfo(`\uC785\uB825: ${input}`);
730
+ console.log();
731
+ try {
732
+ const stream = await executeWorkflowStream({
733
+ workflow_id: workflowId,
734
+ workflow_name: workflowName,
735
+ input_data: input,
736
+ interaction_id: interactionId
737
+ });
738
+ let hasOutput = false;
739
+ let fullResponse = "";
740
+ await parseSSEStream(
741
+ stream,
742
+ (event) => {
743
+ switch (event.type) {
744
+ case "token":
745
+ if (event.content) {
746
+ if (!hasOutput) {
747
+ hasOutput = true;
748
+ console.log();
749
+ }
750
+ process.stdout.write(event.content);
751
+ fullResponse += event.content;
752
+ }
753
+ break;
754
+ case "log":
755
+ if (opts.logs && event.content) {
756
+ process.stderr.write(chalk7.gray(`[LOG] ${event.content}
757
+ `));
758
+ }
759
+ break;
760
+ case "node_status":
761
+ if (opts.logs) {
762
+ const nodeName = event.node_name ?? event.node_id ?? "?";
763
+ const status = event.status ?? "?";
764
+ process.stderr.write(
765
+ chalk7.gray(`[\uB178\uB4DC] ${nodeName}: ${status}
766
+ `)
767
+ );
768
+ }
769
+ break;
770
+ case "tool":
771
+ if (opts.logs) {
772
+ process.stderr.write(chalk7.gray(`[\uB3C4\uAD6C] ${JSON.stringify(event.data)}
773
+ `));
774
+ }
775
+ break;
776
+ case "complete":
777
+ break;
778
+ case "error":
779
+ console.log();
780
+ printError(event.error ?? event.content ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958");
781
+ break;
782
+ default:
783
+ if (event.content) {
784
+ if (!hasOutput) {
785
+ process.stdout.write(chalk7.green("\uC751\uB2F5: "));
786
+ hasOutput = true;
787
+ }
788
+ process.stdout.write(event.content);
789
+ }
790
+ }
791
+ },
792
+ () => {
793
+ if (hasOutput) {
794
+ console.log();
795
+ if (fullResponse.includes("```") || fullResponse.includes("**")) {
796
+ console.log(chalk7.gray("\u2500".repeat(40)));
797
+ console.log(renderMarkdown(fullResponse));
798
+ }
799
+ }
800
+ console.log();
801
+ console.log(chalk7.gray(`\uC138\uC158: ${interactionId}`));
802
+ },
803
+ (err) => {
804
+ console.log();
805
+ printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
806
+ }
807
+ );
808
+ } catch (err) {
809
+ const msg = err?.response?.data?.detail ?? err.message;
810
+ printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
811
+ process.exit(1);
812
+ }
813
+ }
814
+
815
+ // src/commands/workflow/history.ts
816
+ init_store();
817
+ import chalk8 from "chalk";
818
+ async function workflowHistory(workflowId, opts = {}) {
819
+ requireAuth();
820
+ const limit = opts.limit ?? 20;
821
+ try {
822
+ const logs = await getIOLogs(workflowId, limit);
823
+ if (!logs || logs.length === 0) {
824
+ console.log(chalk8.yellow("\n\uC2E4\uD589 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
825
+ return;
826
+ }
827
+ printHeader(`\uC2E4\uD589 \uC774\uB825 (\uCD5C\uADFC ${logs.length}\uAC74)`);
828
+ console.log();
829
+ for (const log of logs) {
830
+ console.log(
831
+ ` ${chalk8.gray(formatDate(log.created_at))} ${chalk8.cyan(log.interaction_id)}`
832
+ );
833
+ console.log(` ${chalk8.white("\uC785\uB825:")} ${truncate(log.input_data, 60)}`);
834
+ console.log(
835
+ ` ${chalk8.green("\uCD9C\uB825:")} ${truncate(log.output_data, 60)}`
836
+ );
837
+ if (log.execution_time) {
838
+ console.log(
839
+ ` ${chalk8.gray("\uC2DC\uAC04:")} ${(log.execution_time / 1e3).toFixed(1)}s`
840
+ );
841
+ }
842
+ console.log();
843
+ }
844
+ } catch (err) {
845
+ const msg = err.message;
846
+ printError(`\uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
847
+ process.exit(1);
848
+ }
849
+ }
850
+
851
+ // src/commands/workflow/index.ts
852
+ function registerWorkflowCommand(program2) {
853
+ const wf = program2.command("workflow").alias("wf").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAD00\uB9AC \uBC0F \uC2E4\uD589");
854
+ 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));
855
+ wf.command("info <workflow-id>").description("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uC138 \uC815\uBCF4").action((id) => workflowInfo(id));
856
+ 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));
857
+ 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) }));
858
+ }
859
+
860
+ // src/commands/chat.ts
861
+ init_store();
862
+ import chalk9 from "chalk";
863
+ import { createInterface as createInterface2 } from "readline";
864
+ import { randomUUID as randomUUID2 } from "crypto";
865
+ var CHAT_BANNER = `
866
+ ${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")}
867
+ ${chalk9.cyan("\u2502")} ${chalk9.white.bold("XGEN")} ${chalk9.gray("\u2014 \uC6CC\uD06C\uD50C\uB85C\uC6B0 AI \uD130\uBBF8\uB110")} ${chalk9.cyan("\u2502")}
868
+ ${chalk9.cyan("\u2502")} ${chalk9.gray("/help \uB3C4\uC6C0\uB9D0 /workflows \uC804\uD658 /exit")} ${chalk9.cyan("\u2502")}
869
+ ${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")}`;
870
+ function printHelp() {
871
+ console.log(`
872
+ ${chalk9.bold("\uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC")}
873
+ ${chalk9.cyan("/workflows")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D \uBCF4\uAE30 & \uC804\uD658
874
+ ${chalk9.cyan("/switch")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBC88\uD638\uB85C \uC804\uD658 (\uC608: /switch 3)
875
+ ${chalk9.cyan("/history")} \uD604\uC7AC \uC138\uC158 \uB300\uD654 \uC774\uB825
876
+ ${chalk9.cyan("/clear")} \uD654\uBA74 \uC9C0\uC6B0\uAE30
877
+ ${chalk9.cyan("/info")} \uD604\uC7AC \uC5F0\uACB0 \uC815\uBCF4
878
+ ${chalk9.cyan("/help")} \uC774 \uB3C4\uC6C0\uB9D0
879
+ ${chalk9.cyan("/exit")} \uC885\uB8CC (Ctrl+C\uB3C4 \uAC00\uB2A5)
880
+ `);
881
+ }
882
+ async function promptLine(rl, promptStr) {
883
+ return new Promise((resolve) => {
884
+ rl.question(promptStr, (answer) => resolve(answer));
885
+ });
886
+ }
887
+ async function chat(workflowId) {
888
+ const auth = requireAuth();
889
+ const server = getServer();
890
+ let workflows = [];
891
+ try {
892
+ workflows = await listWorkflows();
893
+ } catch {
894
+ printError("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
895
+ process.exit(1);
896
+ }
897
+ if (workflows.length === 0) {
898
+ printError("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4");
899
+ process.exit(1);
900
+ }
901
+ let current;
902
+ if (workflowId) {
903
+ const found = workflows.find((w) => w.id === workflowId || w.workflow_name === workflowId);
904
+ current = found ?? { id: workflowId, workflow_name: workflowId };
905
+ } else {
906
+ console.log(CHAT_BANNER);
907
+ console.log(chalk9.gray(` \uC11C\uBC84: ${server} | \uC0AC\uC6A9\uC790: ${auth.username}
908
+ `));
909
+ console.log(chalk9.bold(" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC120\uD0DD:\n"));
910
+ workflows.forEach((w, i) => {
911
+ console.log(` ${chalk9.cyan(String(i + 1).padStart(3))} ${w.workflow_name}`);
912
+ });
913
+ console.log();
914
+ const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
915
+ const answer = await promptLine(rl2, chalk9.cyan(" \uBC88\uD638> "));
916
+ rl2.close();
917
+ const idx = parseInt(answer.trim()) - 1;
918
+ if (isNaN(idx) || idx < 0 || idx >= workflows.length) {
919
+ current = workflows[0];
920
+ } else {
921
+ current = workflows[idx];
922
+ }
923
+ }
924
+ const sessionId = randomUUID2().slice(0, 8);
925
+ let turnCount = 0;
926
+ const history = [];
927
+ console.log();
928
+ console.log(chalk9.cyan("\u2500".repeat(42)));
929
+ console.log(chalk9.white.bold(` ${current.workflow_name}`));
930
+ console.log(chalk9.cyan("\u2500".repeat(42)));
931
+ console.log(chalk9.gray(" \uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694. /help \uB85C \uB3C4\uC6C0\uB9D0.\n"));
932
+ const rl = createInterface2({
933
+ input: process.stdin,
934
+ output: process.stdout
935
+ });
936
+ const getPrompt = () => chalk9.cyan("\u276F ");
937
+ const processInput = async (line) => {
938
+ const input = line.trim();
939
+ if (!input) return;
940
+ if (input.startsWith("/")) {
941
+ const [cmd, ...args] = input.slice(1).split(" ");
942
+ switch (cmd.toLowerCase()) {
943
+ case "exit":
944
+ case "quit":
945
+ case "q":
946
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
947
+ rl.close();
948
+ process.exit(0);
949
+ break;
950
+ case "help":
951
+ case "h":
952
+ printHelp();
953
+ break;
954
+ case "clear":
955
+ case "cls":
956
+ console.clear();
957
+ console.log(chalk9.white.bold(` ${current.workflow_name}`));
958
+ console.log(chalk9.cyan("\u2500".repeat(42)));
959
+ break;
960
+ case "workflows":
961
+ case "wf":
962
+ console.log();
963
+ workflows.forEach((w, i) => {
964
+ const marker = w.id === current.id ? chalk9.green("\u25B8") : " ";
965
+ console.log(` ${marker} ${chalk9.cyan(String(i + 1).padStart(2))} ${w.workflow_name}`);
966
+ });
967
+ console.log(chalk9.gray("\n /switch <\uBC88\uD638> \uB85C \uC804\uD658\n"));
968
+ break;
969
+ case "switch":
970
+ case "sw": {
971
+ const num = parseInt(args[0]);
972
+ if (isNaN(num) || num < 1 || num > workflows.length) {
973
+ console.log(chalk9.yellow(` 1~${workflows.length} \uC0AC\uC774 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694`));
974
+ } else {
975
+ current = workflows[num - 1];
976
+ turnCount = 0;
977
+ history.length = 0;
978
+ console.log(chalk9.green(`
979
+ \uC804\uD658: ${current.workflow_name}
980
+ `));
981
+ }
982
+ break;
983
+ }
984
+ case "history":
985
+ case "hist":
986
+ if (history.length === 0) {
987
+ console.log(chalk9.gray(" \uB300\uD654 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
988
+ } else {
989
+ console.log();
990
+ for (const h of history) {
991
+ const label = h.role === "user" ? chalk9.cyan("\uB098") : chalk9.green("AI");
992
+ const text = h.content.length > 80 ? h.content.slice(0, 80) + "..." : h.content;
993
+ console.log(` ${label}: ${text}`);
994
+ }
995
+ console.log();
996
+ }
997
+ break;
998
+ case "info":
999
+ console.log(`
1000
+ ${chalk9.gray("\uC11C\uBC84:")} ${server}
1001
+ ${chalk9.gray("\uC0AC\uC6A9\uC790:")} ${auth.username}
1002
+ ${chalk9.gray("\uC6CC\uD06C\uD50C\uB85C\uC6B0:")} ${current.workflow_name}
1003
+ ${chalk9.gray("\uC138\uC158:")} ${sessionId}
1004
+ ${chalk9.gray("\uD134:")} ${turnCount}
1005
+ `);
1006
+ break;
1007
+ default:
1008
+ console.log(chalk9.yellow(` \uC54C \uC218 \uC5C6\uB294 \uCEE4\uB9E8\uB4DC: /${cmd}. /help \uCC38\uACE0`));
1009
+ }
1010
+ rl.prompt();
1011
+ return;
1012
+ }
1013
+ turnCount++;
1014
+ const interactionId = `${sessionId}_t${turnCount}`;
1015
+ history.push({ role: "user", content: input });
1016
+ process.stdout.write(chalk9.gray(" thinking..."));
1017
+ try {
1018
+ const stream = await executeWorkflowStream({
1019
+ workflow_id: current.id,
1020
+ workflow_name: current.workflow_name,
1021
+ input_data: input,
1022
+ interaction_id: interactionId
1023
+ });
1024
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1025
+ let fullResponse = "";
1026
+ let hasOutput = false;
1027
+ await parseSSEStream(
1028
+ stream,
1029
+ (event) => {
1030
+ if ((event.type === "token" || !event.type) && event.content) {
1031
+ if (!hasOutput) {
1032
+ hasOutput = true;
1033
+ console.log();
1034
+ }
1035
+ process.stdout.write(event.content);
1036
+ fullResponse += event.content;
1037
+ } else if (event.type === "error") {
1038
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1039
+ printError(event.error ?? event.content ?? "\uC624\uB958");
1040
+ }
1041
+ },
1042
+ () => {
1043
+ if (hasOutput) {
1044
+ console.log();
1045
+ console.log();
1046
+ }
1047
+ if (fullResponse) {
1048
+ history.push({ role: "assistant", content: fullResponse });
1049
+ }
1050
+ },
1051
+ (err) => {
1052
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1053
+ printError(`\uC2A4\uD2B8\uB9AC\uBC0D \uC624\uB958: ${err.message}`);
1054
+ }
1055
+ );
1056
+ } catch (err) {
1057
+ process.stdout.write("\r" + " ".repeat(20) + "\r");
1058
+ const msg = err?.response?.data?.detail ?? err.message;
1059
+ printError(`\uC2E4\uD589 \uC2E4\uD328: ${msg}`);
1060
+ }
1061
+ rl.prompt();
1062
+ };
1063
+ rl.setPrompt(getPrompt());
1064
+ rl.prompt();
1065
+ rl.on("line", (line) => {
1066
+ processInput(line).then(() => {
1067
+ });
1068
+ });
1069
+ rl.on("close", () => {
1070
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
1071
+ process.exit(0);
1072
+ });
1073
+ process.on("SIGINT", () => {
1074
+ console.log(chalk9.gray("\n \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
1075
+ process.exit(0);
1076
+ });
1077
+ }
1078
+ function registerChatCommand(program2) {
1079
+ program2.command("chat [workflow-id]").description("\uC778\uD130\uB799\uD2F0\uBE0C \uB300\uD654 \uBAA8\uB4DC").action((workflowId) => chat(workflowId));
1080
+ }
1081
+
1082
+ // src/commands/provider.ts
1083
+ init_store();
1084
+ import chalk10 from "chalk";
1085
+ import { createInterface as createInterface3 } from "readline";
1086
+ function prompt2(question) {
1087
+ return new Promise((resolve) => {
1088
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
1089
+ rl.question(question, (answer) => {
1090
+ rl.close();
1091
+ resolve(answer.trim());
1092
+ });
1093
+ });
1094
+ }
1095
+ var PROVIDER_PRESETS = {
1096
+ openai: { defaultModel: "gpt-4o-mini" },
1097
+ gemini: { baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", defaultModel: "gemini-2.0-flash" },
1098
+ ollama: { baseUrl: "http://localhost:11434/v1", defaultModel: "llama3.1" },
1099
+ anthropic: { baseUrl: "https://api.anthropic.com/v1", defaultModel: "claude-sonnet-4-20250514" },
1100
+ custom: { defaultModel: "gpt-4o-mini" }
1101
+ };
1102
+ function registerProviderCommand(program2) {
1103
+ const prov = program2.command("provider").description("AI \uD504\uB85C\uBC14\uC774\uB354 \uAD00\uB9AC");
1104
+ prov.command("add").description("\uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00 (\uB300\uD654\uD615)").action(async () => {
1105
+ printHeader("\uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00");
1106
+ console.log();
1107
+ const types = Object.keys(PROVIDER_PRESETS);
1108
+ console.log(chalk10.gray("\uC9C0\uC6D0 \uD0C0\uC785:"), types.join(", "));
1109
+ const type = await prompt2(chalk10.white("\uD0C0\uC785: "));
1110
+ if (!types.includes(type)) {
1111
+ printError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD0C0\uC785: ${type}`);
1112
+ process.exit(1);
1113
+ }
1114
+ const preset = PROVIDER_PRESETS[type];
1115
+ const name = await prompt2(chalk10.white("\uC774\uB984 (\uD45C\uC2DC\uC6A9): ")) || type;
1116
+ const id = name.toLowerCase().replace(/[^a-z0-9]/g, "-");
1117
+ let baseUrl = preset.baseUrl;
1118
+ if (type === "custom" || type === "ollama") {
1119
+ const input = await prompt2(chalk10.white(`Base URL [${preset.baseUrl ?? ""}]: `));
1120
+ if (input) baseUrl = input;
1121
+ }
1122
+ let apiKey = "";
1123
+ if (type !== "ollama") {
1124
+ apiKey = await prompt2(chalk10.white("API Key: "));
1125
+ if (!apiKey) {
1126
+ printError("API Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4");
1127
+ process.exit(1);
1128
+ }
1129
+ }
1130
+ const model = await prompt2(chalk10.white(`\uBAA8\uB378 [${preset.defaultModel}]: `)) || preset.defaultModel;
1131
+ const provider = { id, name, type, baseUrl, apiKey, model };
1132
+ addProvider(provider);
1133
+ console.log();
1134
+ printSuccess(`\uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00 \uC644\uB8CC: ${chalk10.bold(name)} (${model})`);
1135
+ });
1136
+ prov.command("list").alias("ls").description("\uD504\uB85C\uBC14\uC774\uB354 \uBAA9\uB85D").action(() => {
1137
+ const providers = getProviders();
1138
+ const defaultP = getDefaultProvider();
1139
+ if (providers.length === 0) {
1140
+ console.log(chalk10.yellow("\n\uD504\uB85C\uBC14\uC774\uB354\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. xgen provider add \uB85C \uCD94\uAC00\uD558\uC138\uC694.\n"));
1141
+ return;
1142
+ }
1143
+ printHeader(`\uD504\uB85C\uBC14\uC774\uB354 (${providers.length}\uAC1C)`);
1144
+ console.log();
1145
+ printTable(
1146
+ ["", "ID", "\uC774\uB984", "\uD0C0\uC785", "\uBAA8\uB378"],
1147
+ providers.map((p) => [
1148
+ p.id === defaultP?.id ? chalk10.green("\u25CF") : " ",
1149
+ p.id,
1150
+ p.name,
1151
+ p.type,
1152
+ p.model
1153
+ ])
1154
+ );
1155
+ console.log();
1156
+ });
1157
+ prov.command("remove <id>").description("\uD504\uB85C\uBC14\uC774\uB354 \uC81C\uAC70").action((id) => {
1158
+ if (removeProvider(id)) {
1159
+ printSuccess(`\uD504\uB85C\uBC14\uC774\uB354 \uC81C\uAC70: ${id}`);
1160
+ } else {
1161
+ printError(`\uD504\uB85C\uBC14\uC774\uB354\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${id}`);
1162
+ }
1163
+ });
1164
+ prov.command("use <id>").description("\uAE30\uBCF8 \uD504\uB85C\uBC14\uC774\uB354 \uC124\uC815").action((id) => {
1165
+ if (setDefaultProvider(id)) {
1166
+ printSuccess(`\uAE30\uBCF8 \uD504\uB85C\uBC14\uC774\uB354: ${id}`);
1167
+ } else {
1168
+ printError(`\uD504\uB85C\uBC14\uC774\uB354\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${id}`);
1169
+ }
1170
+ });
1171
+ }
1172
+
1173
+ // src/commands/agent.ts
1174
+ init_store();
1175
+ import chalk11 from "chalk";
1176
+ import { createInterface as createInterface5 } from "readline";
1177
+
1178
+ // src/agent/llm.ts
1179
+ import OpenAI from "openai";
1180
+ function createLLMClient(provider) {
1181
+ const opts = {
1182
+ apiKey: provider.apiKey || "ollama"
1183
+ };
1184
+ if (provider.baseUrl) {
1185
+ opts.baseURL = provider.baseUrl;
1186
+ }
1187
+ return new OpenAI(opts);
1188
+ }
1189
+ async function streamChat(client2, model, messages, tools2, onDelta) {
1190
+ const params = {
1191
+ model,
1192
+ messages,
1193
+ stream: true
1194
+ };
1195
+ if (tools2 && tools2.length > 0) {
1196
+ params.tools = tools2;
1197
+ }
1198
+ const stream = await client2.chat.completions.create(params);
1199
+ let content = "";
1200
+ const toolCallMap = /* @__PURE__ */ new Map();
1201
+ for await (const chunk of stream) {
1202
+ const delta = chunk.choices[0]?.delta;
1203
+ if (!delta) continue;
1204
+ if (delta.content) {
1205
+ content += delta.content;
1206
+ onDelta?.(delta.content);
1207
+ }
1208
+ if (delta.tool_calls) {
1209
+ for (const tc of delta.tool_calls) {
1210
+ const idx = tc.index;
1211
+ if (!toolCallMap.has(idx)) {
1212
+ toolCallMap.set(idx, { id: tc.id ?? "", name: tc.function?.name ?? "", arguments: "" });
1213
+ }
1214
+ const entry = toolCallMap.get(idx);
1215
+ if (tc.id) entry.id = tc.id;
1216
+ if (tc.function?.name) entry.name = tc.function.name;
1217
+ if (tc.function?.arguments) entry.arguments += tc.function.arguments;
1218
+ }
1219
+ }
1220
+ }
1221
+ return {
1222
+ content,
1223
+ toolCalls: [...toolCallMap.values()]
1224
+ };
1225
+ }
1226
+
1227
+ // src/agent/tools/file-read.ts
1228
+ var file_read_exports = {};
1229
+ __export(file_read_exports, {
1230
+ definition: () => definition,
1231
+ execute: () => execute
1232
+ });
1233
+ import { readFileSync as readFileSync2 } from "fs";
1234
+ var definition = {
1235
+ type: "function",
1236
+ function: {
1237
+ name: "file_read",
1238
+ description: "\uD30C\uC77C \uB0B4\uC6A9\uC744 \uC77D\uC2B5\uB2C8\uB2E4. \uC904 \uBC88\uD638\uAC00 \uD3EC\uD568\uB429\uB2C8\uB2E4.",
1239
+ parameters: {
1240
+ type: "object",
1241
+ properties: {
1242
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
1243
+ start_line: { type: "number", description: "\uC2DC\uC791 \uC904 \uBC88\uD638 (\uC120\uD0DD)" },
1244
+ end_line: { type: "number", description: "\uB05D \uC904 \uBC88\uD638 (\uC120\uD0DD)" }
1245
+ },
1246
+ required: ["path"]
1247
+ }
1248
+ }
1249
+ };
1250
+ async function execute(args) {
1251
+ const path = args.path;
1252
+ const startLine = args.start_line || 1;
1253
+ const endLine = args.end_line;
1254
+ try {
1255
+ const content = readFileSync2(path, "utf-8");
1256
+ const lines = content.split("\n");
1257
+ const sliced = lines.slice(startLine - 1, endLine ?? lines.length);
1258
+ return sliced.map((line, i) => `${startLine + i} ${line}`).join("\n");
1259
+ } catch (err) {
1260
+ return `Error: ${err.message}`;
1261
+ }
1262
+ }
1263
+
1264
+ // src/agent/tools/file-write.ts
1265
+ var file_write_exports = {};
1266
+ __export(file_write_exports, {
1267
+ definition: () => definition2,
1268
+ execute: () => execute2
1269
+ });
1270
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1271
+ import { dirname } from "path";
1272
+ var definition2 = {
1273
+ type: "function",
1274
+ function: {
1275
+ name: "file_write",
1276
+ description: "\uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uAC70\uB098 \uB36E\uC5B4\uC501\uB2C8\uB2E4.",
1277
+ parameters: {
1278
+ type: "object",
1279
+ properties: {
1280
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
1281
+ content: { type: "string", description: "\uD30C\uC77C \uB0B4\uC6A9" }
1282
+ },
1283
+ required: ["path", "content"]
1284
+ }
1285
+ }
1286
+ };
1287
+ async function execute2(args) {
1288
+ const path = args.path;
1289
+ const content = args.content;
1290
+ try {
1291
+ mkdirSync2(dirname(path), { recursive: true });
1292
+ writeFileSync2(path, content, "utf-8");
1293
+ return `\uD30C\uC77C \uC791\uC131 \uC644\uB8CC: ${path}`;
1294
+ } catch (err) {
1295
+ return `Error: ${err.message}`;
1296
+ }
1297
+ }
1298
+
1299
+ // src/agent/tools/file-edit.ts
1300
+ var file_edit_exports = {};
1301
+ __export(file_edit_exports, {
1302
+ definition: () => definition3,
1303
+ execute: () => execute3
1304
+ });
1305
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1306
+ var definition3 = {
1307
+ type: "function",
1308
+ function: {
1309
+ name: "file_edit",
1310
+ description: "\uD30C\uC77C\uC5D0\uC11C \uD2B9\uC815 \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC544 \uAD50\uCCB4\uD569\uB2C8\uB2E4.",
1311
+ parameters: {
1312
+ type: "object",
1313
+ properties: {
1314
+ path: { type: "string", description: "\uD30C\uC77C \uACBD\uB85C" },
1315
+ old_text: { type: "string", description: "\uAD50\uCCB4\uD560 \uAE30\uC874 \uD14D\uC2A4\uD2B8" },
1316
+ new_text: { type: "string", description: "\uC0C8 \uD14D\uC2A4\uD2B8" }
1317
+ },
1318
+ required: ["path", "old_text", "new_text"]
1319
+ }
1320
+ }
1321
+ };
1322
+ async function execute3(args) {
1323
+ const path = args.path;
1324
+ const oldText = args.old_text;
1325
+ const newText = args.new_text;
1326
+ try {
1327
+ const content = readFileSync3(path, "utf-8");
1328
+ if (!content.includes(oldText)) {
1329
+ return `Error: \uD14D\uC2A4\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4`;
1330
+ }
1331
+ const updated = content.replace(oldText, newText);
1332
+ writeFileSync3(path, updated, "utf-8");
1333
+ return `\uD30C\uC77C \uC218\uC815 \uC644\uB8CC: ${path}`;
1334
+ } catch (err) {
1335
+ return `Error: ${err.message}`;
1336
+ }
1337
+ }
1338
+
1339
+ // src/agent/tools/bash.ts
1340
+ var bash_exports = {};
1341
+ __export(bash_exports, {
1342
+ definition: () => definition4,
1343
+ execute: () => execute4
1344
+ });
1345
+ import { execSync } from "child_process";
1346
+ var definition4 = {
1347
+ type: "function",
1348
+ function: {
1349
+ name: "bash",
1350
+ description: "\uC178 \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4. stdout + stderr\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.",
1351
+ parameters: {
1352
+ type: "object",
1353
+ properties: {
1354
+ command: { type: "string", description: "\uC2E4\uD589\uD560 \uBA85\uB839\uC5B4" }
1355
+ },
1356
+ required: ["command"]
1357
+ }
1358
+ }
1359
+ };
1360
+ async function execute4(args) {
1361
+ const command = args.command;
1362
+ try {
1363
+ const output = execSync(command, {
1364
+ encoding: "utf-8",
1365
+ timeout: 3e4,
1366
+ maxBuffer: 1024 * 1024,
1367
+ stdio: ["pipe", "pipe", "pipe"]
1368
+ });
1369
+ return output || "(no output)";
1370
+ } catch (err) {
1371
+ const e = err;
1372
+ return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
1373
+ }
1374
+ }
1375
+
1376
+ // src/agent/tools/grep.ts
1377
+ var grep_exports = {};
1378
+ __export(grep_exports, {
1379
+ definition: () => definition5,
1380
+ execute: () => execute5
1381
+ });
1382
+ import { execSync as execSync2 } from "child_process";
1383
+ var definition5 = {
1384
+ type: "function",
1385
+ function: {
1386
+ name: "grep",
1387
+ description: "\uD30C\uC77C\uC5D0\uC11C \uD328\uD134\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4 (\uC7AC\uADC0, \uC904 \uBC88\uD638 \uD3EC\uD568).",
1388
+ parameters: {
1389
+ type: "object",
1390
+ properties: {
1391
+ pattern: { type: "string", description: "\uAC80\uC0C9 \uD328\uD134 (\uC815\uADDC\uC2DD)" },
1392
+ path: { type: "string", description: "\uAC80\uC0C9 \uB514\uB809\uD1A0\uB9AC \uB610\uB294 \uD30C\uC77C (\uAE30\uBCF8: .)" },
1393
+ glob: { type: "string", description: "\uD30C\uC77C \uD544\uD130 (\uC608: *.ts)" }
1394
+ },
1395
+ required: ["pattern"]
1396
+ }
1397
+ }
1398
+ };
1399
+ async function execute5(args) {
1400
+ const pattern = args.pattern;
1401
+ const path = args.path || ".";
1402
+ const glob = args.glob;
1403
+ try {
1404
+ let cmd = `grep -rn --color=never "${pattern.replace(/"/g, '\\"')}" "${path}"`;
1405
+ if (glob) cmd += ` --include="${glob}"`;
1406
+ cmd += " | head -50";
1407
+ const output = execSync2(cmd, {
1408
+ encoding: "utf-8",
1409
+ timeout: 1e4,
1410
+ maxBuffer: 512 * 1024,
1411
+ stdio: ["pipe", "pipe", "pipe"]
1412
+ });
1413
+ return output || "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
1414
+ } catch {
1415
+ return "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC \uC5C6\uC74C";
1416
+ }
1417
+ }
1418
+
1419
+ // src/agent/tools/list-files.ts
1420
+ var list_files_exports = {};
1421
+ __export(list_files_exports, {
1422
+ definition: () => definition6,
1423
+ execute: () => execute6
1424
+ });
1425
+ import { execSync as execSync3 } from "child_process";
1426
+ var definition6 = {
1427
+ type: "function",
1428
+ function: {
1429
+ name: "list_files",
1430
+ description: "\uB514\uB809\uD1A0\uB9AC\uC758 \uD30C\uC77C/\uD3F4\uB354 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. glob \uD328\uD134 \uC9C0\uC6D0.",
1431
+ parameters: {
1432
+ type: "object",
1433
+ properties: {
1434
+ path: { type: "string", description: "\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8: .)" },
1435
+ pattern: { type: "string", description: "glob \uD328\uD134 (\uC608: **/*.ts)" }
1436
+ }
1437
+ }
1438
+ }
1439
+ };
1440
+ async function execute6(args) {
1441
+ const path = args.path || ".";
1442
+ const pattern = args.pattern;
1443
+ try {
1444
+ let cmd;
1445
+ if (pattern) {
1446
+ cmd = `find "${path}" -name "${pattern}" -type f | head -100`;
1447
+ } else {
1448
+ cmd = `ls -la "${path}"`;
1449
+ }
1450
+ const output = execSync3(cmd, {
1451
+ encoding: "utf-8",
1452
+ timeout: 1e4,
1453
+ stdio: ["pipe", "pipe", "pipe"]
1454
+ });
1455
+ return output || "(empty)";
1456
+ } catch (err) {
1457
+ return `Error: ${err.message}`;
1458
+ }
1459
+ }
1460
+
1461
+ // src/agent/tools/sandbox.ts
1462
+ var sandbox_exports = {};
1463
+ __export(sandbox_exports, {
1464
+ definition: () => definition7,
1465
+ execute: () => execute7
1466
+ });
1467
+ import { execSync as execSync4 } from "child_process";
1468
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync2, rmSync } from "fs";
1469
+ import { join as join2 } from "path";
1470
+ import { tmpdir } from "os";
1471
+ var SANDBOX_DIR = join2(tmpdir(), "xgen-sandbox");
1472
+ function ensureSandbox() {
1473
+ if (!existsSync2(SANDBOX_DIR)) {
1474
+ mkdirSync3(SANDBOX_DIR, { recursive: true });
1475
+ }
1476
+ return SANDBOX_DIR;
1477
+ }
1478
+ var definition7 = {
1479
+ type: "function",
1480
+ function: {
1481
+ name: "sandbox_run",
1482
+ 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.",
1483
+ parameters: {
1484
+ type: "object",
1485
+ properties: {
1486
+ language: {
1487
+ type: "string",
1488
+ enum: ["javascript", "typescript", "python"],
1489
+ description: "\uC2E4\uD589\uD560 \uC5B8\uC5B4"
1490
+ },
1491
+ code: { type: "string", description: "\uC2E4\uD589\uD560 \uCF54\uB4DC" },
1492
+ packages: {
1493
+ type: "array",
1494
+ items: { type: "string" },
1495
+ description: "\uC124\uCE58\uD560 \uD328\uD0A4\uC9C0 (npm \uB610\uB294 pip)"
1496
+ }
1497
+ },
1498
+ required: ["language", "code"]
1499
+ }
1500
+ }
1501
+ };
1502
+ async function execute7(args) {
1503
+ const language = args.language;
1504
+ const code = args.code;
1505
+ const packages = args.packages ?? [];
1506
+ const dir = ensureSandbox();
1507
+ const runId = `run_${Date.now()}`;
1508
+ const runDir = join2(dir, runId);
1509
+ mkdirSync3(runDir, { recursive: true });
1510
+ try {
1511
+ if (packages.length > 0) {
1512
+ if (language === "python") {
1513
+ const pkgList = packages.join(" ");
1514
+ execSync4(`pip install ${pkgList}`, {
1515
+ cwd: runDir,
1516
+ encoding: "utf-8",
1517
+ timeout: 6e4,
1518
+ stdio: ["pipe", "pipe", "pipe"]
1519
+ });
1520
+ } else {
1521
+ execSync4("npm init -y", { cwd: runDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
1522
+ const pkgList = packages.join(" ");
1523
+ execSync4(`npm install ${pkgList}`, {
1524
+ cwd: runDir,
1525
+ encoding: "utf-8",
1526
+ timeout: 6e4,
1527
+ stdio: ["pipe", "pipe", "pipe"]
1528
+ });
1529
+ }
1530
+ }
1531
+ let cmd;
1532
+ let filename;
1533
+ if (language === "python") {
1534
+ filename = "script.py";
1535
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
1536
+ cmd = `python3 ${filename}`;
1537
+ } else if (language === "typescript") {
1538
+ filename = "script.ts";
1539
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
1540
+ cmd = `npx tsx ${filename}`;
1541
+ } else {
1542
+ filename = "script.mjs";
1543
+ writeFileSync4(join2(runDir, filename), code, "utf-8");
1544
+ cmd = `node ${filename}`;
1545
+ }
1546
+ const output = execSync4(cmd, {
1547
+ cwd: runDir,
1548
+ encoding: "utf-8",
1549
+ timeout: 3e4,
1550
+ maxBuffer: 1024 * 1024,
1551
+ stdio: ["pipe", "pipe", "pipe"]
1552
+ });
1553
+ return output || "(no output)";
1554
+ } catch (err) {
1555
+ const e = err;
1556
+ return (e.stdout || "") + (e.stderr || "") || `Error: ${e.message}`;
1557
+ } finally {
1558
+ try {
1559
+ rmSync(runDir, { recursive: true, force: true });
1560
+ } catch {
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+ // src/agent/tools/index.ts
1566
+ var tools = [file_read_exports, file_write_exports, file_edit_exports, bash_exports, grep_exports, list_files_exports, sandbox_exports];
1567
+ var toolMap = /* @__PURE__ */ new Map();
1568
+ for (const t of tools) {
1569
+ toolMap.set(t.definition.function.name, t);
1570
+ }
1571
+ function getAllToolDefs() {
1572
+ return tools.map((t) => t.definition);
1573
+ }
1574
+ async function executeTool(name, args) {
1575
+ const tool = toolMap.get(name);
1576
+ if (!tool) return `Unknown tool: ${name}`;
1577
+ return tool.execute(args);
1578
+ }
1579
+ function getToolNames() {
1580
+ return tools.map((t) => t.definition.function.name);
1581
+ }
1582
+
1583
+ // src/mcp/client.ts
1584
+ import { spawn } from "child_process";
1585
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
1586
+ import { join as join3 } from "path";
1587
+ import { createInterface as createInterface4 } from "readline";
1588
+ var McpClient = class {
1589
+ process = null;
1590
+ requestId = 0;
1591
+ pending = /* @__PURE__ */ new Map();
1592
+ serverName;
1593
+ config;
1594
+ tools = [];
1595
+ constructor(serverName, config) {
1596
+ this.serverName = serverName;
1597
+ this.config = config;
1598
+ }
1599
+ async start() {
1600
+ this.process = spawn(this.config.command, this.config.args ?? [], {
1601
+ stdio: ["pipe", "pipe", "pipe"],
1602
+ env: { ...process.env, ...this.config.env }
1603
+ });
1604
+ const rl = createInterface4({ input: this.process.stdout });
1605
+ rl.on("line", (line) => {
1606
+ try {
1607
+ const msg = JSON.parse(line);
1608
+ if (msg.id !== void 0 && this.pending.has(msg.id)) {
1609
+ const p = this.pending.get(msg.id);
1610
+ this.pending.delete(msg.id);
1611
+ if (msg.error) {
1612
+ p.reject(new Error(msg.error.message));
1613
+ } else {
1614
+ p.resolve(msg.result);
1615
+ }
1616
+ }
1617
+ } catch {
1618
+ }
1619
+ });
1620
+ this.process.on("error", (err) => {
1621
+ console.error(`MCP [${this.serverName}] \uD504\uB85C\uC138\uC2A4 \uC624\uB958:`, err.message);
1622
+ });
1623
+ await this.send("initialize", {
1624
+ protocolVersion: "2024-11-05",
1625
+ capabilities: {},
1626
+ clientInfo: { name: "open-xgen", version: "0.3.0" }
1627
+ });
1628
+ await this.send("notifications/initialized", {});
1629
+ }
1630
+ send(method, params) {
1631
+ return new Promise((resolve, reject) => {
1632
+ const id = ++this.requestId;
1633
+ const request = { jsonrpc: "2.0", id, method, params };
1634
+ this.pending.set(id, { resolve, reject });
1635
+ const timeout = setTimeout(() => {
1636
+ this.pending.delete(id);
1637
+ reject(new Error(`MCP \uC694\uCCAD \uD0C0\uC784\uC544\uC6C3: ${method}`));
1638
+ }, 15e3);
1639
+ this.pending.set(id, {
1640
+ resolve: (v) => {
1641
+ clearTimeout(timeout);
1642
+ resolve(v);
1643
+ },
1644
+ reject: (e) => {
1645
+ clearTimeout(timeout);
1646
+ reject(e);
1647
+ }
1648
+ });
1649
+ this.process?.stdin?.write(JSON.stringify(request) + "\n");
1650
+ });
1651
+ }
1652
+ async listTools() {
1653
+ const result = await this.send("tools/list", {});
1654
+ this.tools = result.tools ?? [];
1655
+ return this.tools;
1656
+ }
1657
+ async callTool(name, args) {
1658
+ const result = await this.send("tools/call", { name, arguments: args });
1659
+ return result.content?.map((c) => c.text ?? "").join("\n") ?? "";
1660
+ }
1661
+ getOpenAITools() {
1662
+ return this.tools.map((t) => ({
1663
+ type: "function",
1664
+ function: {
1665
+ name: `mcp_${this.serverName}_${t.name}`,
1666
+ description: `[MCP:${this.serverName}] ${t.description ?? t.name}`,
1667
+ parameters: t.inputSchema ?? { type: "object", properties: {} }
1668
+ }
1669
+ }));
1670
+ }
1671
+ stop() {
1672
+ this.process?.kill();
1673
+ this.process = null;
1674
+ }
1675
+ };
1676
+ function loadMcpConfig(dir) {
1677
+ const searchPaths = [
1678
+ dir ? join3(dir, ".mcp.json") : null,
1679
+ join3(process.cwd(), ".mcp.json"),
1680
+ join3(process.env.HOME ?? "", ".mcp.json")
1681
+ ].filter(Boolean);
1682
+ for (const p of searchPaths) {
1683
+ if (existsSync3(p)) {
1684
+ try {
1685
+ return JSON.parse(readFileSync4(p, "utf-8"));
1686
+ } catch {
1687
+ continue;
1688
+ }
1689
+ }
1690
+ }
1691
+ return null;
1692
+ }
1693
+ var McpManager = class {
1694
+ clients = /* @__PURE__ */ new Map();
1695
+ async startAll(config) {
1696
+ for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
1697
+ if (serverConfig.type !== "stdio") continue;
1698
+ try {
1699
+ const client2 = new McpClient(name, serverConfig);
1700
+ await client2.start();
1701
+ await client2.listTools();
1702
+ this.clients.set(name, client2);
1703
+ } catch (err) {
1704
+ console.error(`MCP [${name}] \uC2DC\uC791 \uC2E4\uD328:`, err.message);
1705
+ }
1706
+ }
1707
+ }
1708
+ getAllTools() {
1709
+ const tools2 = [];
1710
+ for (const client2 of this.clients.values()) {
1711
+ tools2.push(...client2.getOpenAITools());
1712
+ }
1713
+ return tools2;
1714
+ }
1715
+ async callTool(fullName, args) {
1716
+ const parts = fullName.split("_");
1717
+ if (parts.length < 3 || parts[0] !== "mcp") return `Unknown MCP tool: ${fullName}`;
1718
+ const serverName = parts[1];
1719
+ const toolName = parts.slice(2).join("_");
1720
+ const client2 = this.clients.get(serverName);
1721
+ if (!client2) return `MCP \uC11C\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${serverName}`;
1722
+ return client2.callTool(toolName, args);
1723
+ }
1724
+ isMcpTool(name) {
1725
+ return name.startsWith("mcp_");
1726
+ }
1727
+ stopAll() {
1728
+ for (const client2 of this.clients.values()) {
1729
+ client2.stop();
1730
+ }
1731
+ this.clients.clear();
1732
+ }
1733
+ get serverCount() {
1734
+ return this.clients.size;
1735
+ }
1736
+ getServerNames() {
1737
+ return [...this.clients.keys()];
1738
+ }
1739
+ };
1740
+
1741
+ // src/commands/agent.ts
1742
+ var SYSTEM_PROMPT = `You are OPEN XGEN Agent, an AI coding assistant running in the user's terminal.
1743
+ You have access to tools for reading/writing files, executing commands, searching code, and running sandboxed code.
1744
+ You can also use MCP (Model Context Protocol) tools if available.
1745
+ Always respond in the same language as the user.
1746
+ When using tools, be concise about what you're doing.
1747
+ For file edits, show what you changed briefly.
1748
+ For sandbox_run, you can install npm/pip packages and run isolated code.`;
1749
+ var mcpManager = null;
1750
+ async function agentRepl() {
1751
+ const provider = getDefaultProvider();
1752
+ if (!provider) {
1753
+ printError("\uD504\uB85C\uBC14\uC774\uB354\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
1754
+ console.log(` ${chalk11.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00`);
1755
+ process.exit(1);
1756
+ }
1757
+ const client2 = createLLMClient(provider);
1758
+ const builtinTools = getAllToolDefs();
1759
+ const allTools = [...builtinTools];
1760
+ const allToolNames = [...getToolNames()];
1761
+ const mcpConfig = loadMcpConfig();
1762
+ if (mcpConfig && Object.keys(mcpConfig.mcpServers).length > 0) {
1763
+ mcpManager = new McpManager();
1764
+ try {
1765
+ await mcpManager.startAll(mcpConfig);
1766
+ if (mcpManager.serverCount > 0) {
1767
+ const mcpTools = mcpManager.getAllTools();
1768
+ allTools.push(...mcpTools);
1769
+ allToolNames.push(...mcpTools.map((t) => t.function.name));
1770
+ }
1771
+ } catch {
1772
+ }
1773
+ }
1774
+ const messages = [{ role: "system", content: SYSTEM_PROMPT }];
1775
+ console.log(chalk11.cyan.bold("\n OPEN XGEN Agent"));
1776
+ console.log(chalk11.gray(" \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"));
1777
+ console.log(chalk11.gray(` \uD504\uB85C\uBC14\uC774\uB354: ${provider.name} (${provider.model})`));
1778
+ console.log(chalk11.gray(` \uB3C4\uAD6C: ${getToolNames().join(", ")}`));
1779
+ if (mcpManager && mcpManager.serverCount > 0) {
1780
+ console.log(chalk11.gray(` MCP: ${mcpManager.getServerNames().join(", ")} (${mcpManager.getAllTools().length}\uAC1C \uB3C4\uAD6C)`));
1781
+ }
1782
+ console.log(chalk11.gray(` \uC885\uB8CC: exit | Ctrl+C`));
1783
+ console.log();
1784
+ const rl = createInterface5({ input: process.stdin, output: process.stdout });
1785
+ const ask = () => new Promise((resolve) => rl.question(chalk11.green("\u276F "), (a) => resolve(a.trim())));
1786
+ process.on("SIGINT", () => {
1787
+ console.log(chalk11.gray("\n\uC885\uB8CC\uD569\uB2C8\uB2E4."));
1788
+ mcpManager?.stopAll();
1789
+ rl.close();
1790
+ process.exit(0);
1791
+ });
1792
+ while (true) {
1793
+ const input = await ask();
1794
+ if (!input) continue;
1795
+ if (input === "exit" || input === "/exit") {
1796
+ console.log(chalk11.gray("\uC885\uB8CC\uD569\uB2C8\uB2E4."));
1797
+ mcpManager?.stopAll();
1798
+ rl.close();
1799
+ break;
1800
+ }
1801
+ if (input === "/clear") {
1802
+ messages.length = 1;
1803
+ console.log(chalk11.gray("\uB300\uD654 \uCD08\uAE30\uD654\uB428.\n"));
1804
+ continue;
1805
+ }
1806
+ if (input === "/tools") {
1807
+ console.log(chalk11.bold("\n\uB0B4\uC7A5 \uB3C4\uAD6C:"), getToolNames().join(", "));
1808
+ if (mcpManager && mcpManager.serverCount > 0) {
1809
+ console.log(chalk11.bold("MCP \uB3C4\uAD6C:"), mcpManager.getAllTools().map((t) => t.function.name).join(", "));
1810
+ }
1811
+ console.log();
1812
+ continue;
1813
+ }
1814
+ if (input === "/provider") {
1815
+ console.log(chalk11.gray(`\uD604\uC7AC: ${provider.name} (${provider.model})
1816
+ `));
1817
+ continue;
1818
+ }
1819
+ if (input === "/mcp") {
1820
+ if (mcpManager && mcpManager.serverCount > 0) {
1821
+ console.log(chalk11.bold("\nMCP \uC11C\uBC84:"), mcpManager.getServerNames().join(", "));
1822
+ console.log(chalk11.gray("\uB3C4\uAD6C:"), mcpManager.getAllTools().map((t) => t.function.name).join(", "));
1823
+ } else {
1824
+ console.log(chalk11.gray("MCP \uC11C\uBC84 \uC5C6\uC74C. .mcp.json\uC744 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0 \uCD94\uAC00\uD558\uC138\uC694."));
1825
+ }
1826
+ console.log();
1827
+ continue;
1828
+ }
1829
+ messages.push({ role: "user", content: input });
1830
+ try {
1831
+ await runAgentLoop(client2, provider.model, messages, allTools);
1832
+ } catch (err) {
1833
+ console.log(chalk11.red(`
1834
+ \uC624\uB958: ${err.message}
1835
+ `));
1836
+ }
1837
+ }
1838
+ }
1839
+ async function runAgentLoop(client2, model, messages, tools2) {
1840
+ const MAX_ITERATIONS = 20;
1841
+ for (let i = 0; i < MAX_ITERATIONS; i++) {
1842
+ const result = await streamChat(client2, model, messages, tools2, (delta) => {
1843
+ process.stdout.write(delta);
1844
+ });
1845
+ if (result.content) {
1846
+ process.stdout.write("\n\n");
1847
+ }
1848
+ if (result.toolCalls.length === 0) {
1849
+ if (result.content) {
1850
+ messages.push({ role: "assistant", content: result.content });
1851
+ }
1852
+ return;
1853
+ }
1854
+ messages.push({
1855
+ role: "assistant",
1856
+ content: result.content || null,
1857
+ tool_calls: result.toolCalls.map((tc) => ({
1858
+ id: tc.id,
1859
+ type: "function",
1860
+ function: { name: tc.name, arguments: tc.arguments }
1861
+ }))
1862
+ });
1863
+ for (const tc of result.toolCalls) {
1864
+ let args;
1865
+ try {
1866
+ args = JSON.parse(tc.arguments);
1867
+ } catch {
1868
+ args = {};
1869
+ }
1870
+ console.log(chalk11.gray(` \u2699 ${tc.name}(`), chalk11.dim(summarizeArgs(args)), chalk11.gray(")"));
1871
+ let toolResult;
1872
+ if (mcpManager?.isMcpTool(tc.name)) {
1873
+ toolResult = await mcpManager.callTool(tc.name, args);
1874
+ } else {
1875
+ toolResult = await executeTool(tc.name, args);
1876
+ }
1877
+ const truncated = toolResult.length > 4e3 ? toolResult.slice(0, 4e3) + "\n...(truncated)" : toolResult;
1878
+ messages.push({
1879
+ role: "tool",
1880
+ tool_call_id: tc.id,
1881
+ content: truncated
1882
+ });
1883
+ }
1884
+ }
1885
+ console.log(chalk11.yellow("\n\uCD5C\uB300 \uBC18\uBCF5 \uD69F\uC218\uC5D0 \uB3C4\uB2EC\uD588\uC2B5\uB2C8\uB2E4.\n"));
1886
+ }
1887
+ function summarizeArgs(args) {
1888
+ const parts = [];
1889
+ for (const [k, v] of Object.entries(args)) {
1890
+ const s = String(v);
1891
+ parts.push(`${k}: ${s.length > 40 ? s.slice(0, 40) + "..." : s}`);
1892
+ }
1893
+ return parts.join(", ");
1894
+ }
1895
+ function registerAgentCommand(program2) {
1896
+ program2.command("agent").description("OPEN XGEN AI \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8").action(async () => {
1897
+ await agentRepl();
1898
+ });
1899
+ }
1900
+
1901
+ // src/commands/doc.ts
1902
+ init_store();
1903
+ import chalk12 from "chalk";
1904
+
1905
+ // src/api/document.ts
1906
+ import { createReadStream, statSync } from "fs";
1907
+ import { basename } from "path";
1908
+ async function listDocuments(collectionId) {
1909
+ const client2 = getClient();
1910
+ const params = {};
1911
+ if (collectionId) params.collection_id = collectionId;
1912
+ const res = await client2.get("/api/documents/list", { params });
1913
+ return res.data.documents ?? res.data ?? [];
1914
+ }
1915
+ async function uploadDocument(filePath, collectionId, name) {
1916
+ const client2 = getClient();
1917
+ const stat = statSync(filePath);
1918
+ const fileName = name || basename(filePath);
1919
+ const FormData = (await import("buffer")).Blob ? globalThis.FormData : null;
1920
+ if (!FormData) throw new Error("FormData not available");
1921
+ const form = new FormData();
1922
+ const fileBlob = new Blob([createReadStream(filePath)]);
1923
+ form.append("file", fileBlob, fileName);
1924
+ if (collectionId) form.append("collection_id", collectionId);
1925
+ const res = await client2.post("/api/documents/upload", form, {
1926
+ headers: { "Content-Type": "multipart/form-data" },
1927
+ maxBodyLength: stat.size + 1024 * 1024
1928
+ });
1929
+ return res.data;
1930
+ }
1931
+ async function getDocumentInfo(docId) {
1932
+ const client2 = getClient();
1933
+ const res = await client2.get(`/api/documents/${docId}`);
1934
+ return res.data;
1935
+ }
1936
+
1937
+ // src/commands/doc.ts
1938
+ function registerDocCommand(program2) {
1939
+ const doc = program2.command("doc").description("\uBB38\uC11C \uAD00\uB9AC");
1940
+ doc.command("list").alias("ls").description("\uBB38\uC11C \uBAA9\uB85D \uC870\uD68C").option("-c, --collection <id>", "\uCEEC\uB809\uC158 ID").action(async (opts) => {
1941
+ requireAuth();
1942
+ try {
1943
+ const docs = await listDocuments(opts.collection);
1944
+ if (!docs.length) {
1945
+ console.log(chalk12.yellow("\n\uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
1946
+ return;
1947
+ }
1948
+ printHeader(`\uBB38\uC11C \uBAA9\uB85D (${docs.length}\uAC1C)`);
1949
+ console.log();
1950
+ printTable(
1951
+ ["#", "ID", "\uD30C\uC77C\uBA85", "\uD0C0\uC785", "\uC0C1\uD0DC", "\uC0DD\uC131\uC77C"],
1952
+ docs.map((d, i) => [
1953
+ String(i + 1),
1954
+ (d.document_id ?? d.id ?? "-").toString().slice(0, 10),
1955
+ d.file_name ?? d.name ?? "-",
1956
+ d.file_type ?? "-",
1957
+ d.status ?? "-",
1958
+ formatDate(d.created_at)
1959
+ ])
1960
+ );
1961
+ console.log();
1962
+ } catch (err) {
1963
+ printError(`\uBB38\uC11C \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${err.message}`);
1964
+ }
1965
+ });
1966
+ doc.command("upload <file>").description("\uBB38\uC11C \uC5C5\uB85C\uB4DC").option("-c, --collection <id>", "\uCEEC\uB809\uC158 ID").option("-n, --name <name>", "\uD30C\uC77C\uBA85").action(async (file, opts) => {
1967
+ requireAuth();
1968
+ try {
1969
+ console.log(chalk12.gray(`\uC5C5\uB85C\uB4DC \uC911: ${file}`));
1970
+ const result = await uploadDocument(file, opts.collection, opts.name);
1971
+ console.log(chalk12.green("\u2713 \uC5C5\uB85C\uB4DC \uC644\uB8CC"));
1972
+ console.log(chalk12.gray(JSON.stringify(result, null, 2)));
1973
+ } catch (err) {
1974
+ printError(`\uC5C5\uB85C\uB4DC \uC2E4\uD328: ${err.message}`);
1975
+ }
1976
+ });
1977
+ doc.command("info <id>").description("\uBB38\uC11C \uC0C1\uC138 \uC815\uBCF4").action(async (id) => {
1978
+ requireAuth();
1979
+ try {
1980
+ const d = await getDocumentInfo(id);
1981
+ printHeader("\uBB38\uC11C \uC815\uBCF4");
1982
+ console.log(chalk12.gray(JSON.stringify(d, null, 2)));
1983
+ } catch (err) {
1984
+ printError(`\uC870\uD68C \uC2E4\uD328: ${err.message}`);
1985
+ }
1986
+ });
1987
+ }
1988
+
1989
+ // src/commands/ontology.ts
1990
+ init_store();
1991
+ import chalk13 from "chalk";
1992
+ import { createInterface as createInterface6 } from "readline";
1993
+
1994
+ // src/api/ontology.ts
1995
+ async function queryGraphRAG(query, graphId, opts) {
1996
+ const client2 = getClient();
1997
+ const res = await client2.post("/api/graph-rag", {
1998
+ query,
1999
+ graph_id: graphId,
2000
+ use_scs: opts?.scs ?? true
2001
+ });
2002
+ return res.data;
2003
+ }
2004
+ async function queryGraphRAGMultiTurn(query, sessionId, graphId, opts) {
2005
+ const client2 = getClient();
2006
+ const res = await client2.post("/api/graph-rag/multi-turn", {
2007
+ query,
2008
+ session_id: sessionId,
2009
+ graph_id: graphId,
2010
+ max_turns: opts?.maxTurns ?? 5
2011
+ });
2012
+ return res.data;
2013
+ }
2014
+ async function getGraphStats(graphId) {
2015
+ const client2 = getClient();
2016
+ const res = await client2.get(`/api/graph/${graphId}/stats`);
2017
+ return res.data;
2018
+ }
2019
+
2020
+ // src/commands/ontology.ts
2021
+ import { randomUUID as randomUUID3 } from "crypto";
2022
+ function registerOntologyCommand(program2) {
2023
+ const ont = program2.command("ontology").alias("ont").description("\uC628\uD1A8\uB85C\uC9C0 GraphRAG \uC9C8\uC758");
2024
+ ont.command("query <question>").alias("q").description("GraphRAG \uC6D0\uC0F7 \uC9C8\uC758").option("-g, --graph <id>", "\uADF8\uB798\uD504 ID").option("--no-scs", "SCS \uCEE8\uD14D\uC2A4\uD2B8 \uBE44\uD65C\uC131\uD654").action(async (question, opts) => {
2025
+ requireAuth();
2026
+ try {
2027
+ console.log(chalk13.gray("\n\uC9C8\uC758 \uC911...\n"));
2028
+ const result = await queryGraphRAG(question, opts.graph, { scs: opts.scs });
2029
+ if (result.answer) {
2030
+ console.log(chalk13.bold("\uB2F5\uBCC0:"));
2031
+ console.log(result.answer);
2032
+ }
2033
+ if (result.sources?.length) {
2034
+ console.log(chalk13.bold("\n\uCD9C\uCC98:"));
2035
+ result.sources.forEach((s) => console.log(chalk13.gray(` - ${s}`)));
2036
+ }
2037
+ if (result.triples_used?.length) {
2038
+ console.log(chalk13.bold("\n\uC0AC\uC6A9\uB41C \uD2B8\uB9AC\uD50C:"));
2039
+ result.triples_used.forEach((t) => console.log(chalk13.dim(` ${t}`)));
2040
+ }
2041
+ console.log();
2042
+ } catch (err) {
2043
+ printError(`\uC9C8\uC758 \uC2E4\uD328: ${err.message}`);
2044
+ }
2045
+ });
2046
+ ont.command("chat").description("\uBA40\uD2F0\uD134 GraphRAG \uB300\uD654").option("-g, --graph <id>", "\uADF8\uB798\uD504 ID").action(async (opts) => {
2047
+ requireAuth();
2048
+ const sessionId = randomUUID3();
2049
+ printHeader("Ontology Chat");
2050
+ console.log(chalk13.gray("\uBA40\uD2F0\uD134 GraphRAG \uB300\uD654. exit\uB85C \uC885\uB8CC.\n"));
2051
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
2052
+ const ask = () => new Promise((resolve) => rl.question(chalk13.green("\u276F "), (a) => resolve(a.trim())));
2053
+ while (true) {
2054
+ const input = await ask();
2055
+ if (!input) continue;
2056
+ if (input === "exit") {
2057
+ rl.close();
2058
+ break;
2059
+ }
2060
+ try {
2061
+ const result = await queryGraphRAGMultiTurn(input, sessionId, opts.graph);
2062
+ if (result.answer) console.log(`
2063
+ ${result.answer}
2064
+ `);
2065
+ } catch (err) {
2066
+ console.log(chalk13.red(`\uC624\uB958: ${err.message}
2067
+ `));
2068
+ }
2069
+ }
2070
+ });
2071
+ ont.command("stats <graph-id>").description("\uADF8\uB798\uD504 \uD1B5\uACC4").action(async (graphId) => {
2072
+ requireAuth();
2073
+ try {
2074
+ const stats = await getGraphStats(graphId);
2075
+ printHeader("\uADF8\uB798\uD504 \uD1B5\uACC4");
2076
+ console.log(chalk13.gray(JSON.stringify(stats, null, 2)));
2077
+ console.log();
2078
+ } catch (err) {
2079
+ printError(`\uD1B5\uACC4 \uC870\uD68C \uC2E4\uD328: ${err.message}`);
2080
+ }
2081
+ });
2082
+ }
2083
+
2084
+ // src/index.ts
2085
+ init_store();
2086
+ var VERSION = "0.3.0";
2087
+ var LOGO = chalk14.cyan(`
2088
+ \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
2089
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
2090
+ \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
2091
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
2092
+ \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
2093
+ `) + chalk14.white.bold(`
2094
+ \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588
2095
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588
2096
+ \u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
2097
+ \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588
2098
+ \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588
2099
+ `) + chalk14.gray(` v${VERSION}
2100
+ `);
2101
+ var BANNER = LOGO;
2102
+ var program = new Command();
2103
+ program.name("xgen").description("OPEN XGEN \u2014 AI Coding Agent + XGEN Platform CLI").version(VERSION).addHelpText("before", BANNER).addHelpText(
2104
+ "after",
2105
+ `
2106
+ ${chalk14.bold("\uC2DC\uC791\uD558\uAE30:")}
2107
+ ${chalk14.cyan("xgen provider add")} AI \uD504\uB85C\uBC14\uC774\uB354 \uC124\uC815
2108
+ ${chalk14.cyan("xgen agent")} AI \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8
2109
+ ${chalk14.cyan("xgen config set-server")} <url> XGEN \uC11C\uBC84 \uC5F0\uACB0
2110
+ ${chalk14.cyan("xgen login")} \uC11C\uBC84 \uB85C\uADF8\uC778
2111
+
2112
+ ${chalk14.bold("AI \uC5D0\uC774\uC804\uD2B8:")}
2113
+ ${chalk14.cyan("xgen agent")} \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8 (\uD30C\uC77C, \uD130\uBBF8\uB110, \uAC80\uC0C9)
2114
+ ${chalk14.cyan("xgen provider ls")} \uD504\uB85C\uBC14\uC774\uB354 \uBAA9\uB85D
2115
+ ${chalk14.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
2116
+
2117
+ ${chalk14.bold("XGEN \uD50C\uB7AB\uD3FC:")}
2118
+ ${chalk14.cyan("xgen chat")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB300\uD654
2119
+ ${chalk14.cyan("xgen wf ls")} \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA9\uB85D
2120
+ ${chalk14.cyan("xgen wf run")} <id> "\uC9C8\uBB38" \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC2E4\uD589
2121
+ ${chalk14.cyan("xgen doc ls")} \uBB38\uC11C \uBAA9\uB85D
2122
+ ${chalk14.cyan("xgen ont query")} "\uC9C8\uBB38" \uC628\uD1A8\uB85C\uC9C0 \uC9C8\uC758
2123
+ `
2124
+ );
2125
+ registerConfigCommand(program);
2126
+ registerLoginCommand(program);
2127
+ registerWorkflowCommand(program);
2128
+ registerChatCommand(program);
2129
+ registerProviderCommand(program);
2130
+ registerAgentCommand(program);
2131
+ registerDocCommand(program);
2132
+ registerOntologyCommand(program);
2133
+ if (process.argv.length <= 2) {
2134
+ const auth = getAuth();
2135
+ const server = getServer();
2136
+ const provider = getDefaultProvider();
2137
+ if (provider) {
2138
+ agentRepl().catch((err) => {
2139
+ console.error(chalk14.red(`\uC624\uB958: ${err.message}`));
2140
+ process.exit(1);
2141
+ });
2142
+ } else if (auth && server) {
2143
+ chat().catch((err) => {
2144
+ console.error(chalk14.red(`\uC624\uB958: ${err.message}`));
2145
+ process.exit(1);
2146
+ });
2147
+ } else {
2148
+ console.log(BANNER);
2149
+ console.log(chalk14.yellow(" \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.\n"));
2150
+ console.log(chalk14.bold(" AI \uC5D0\uC774\uC804\uD2B8:"));
2151
+ console.log(` ${chalk14.cyan("xgen provider add")} \uD504\uB85C\uBC14\uC774\uB354 \uCD94\uAC00
2152
+ `);
2153
+ console.log(chalk14.bold(" XGEN \uD50C\uB7AB\uD3FC:"));
2154
+ console.log(` ${chalk14.cyan("xgen config set-server")} <url> \uC11C\uBC84 \uC124\uC815`);
2155
+ console.log(` ${chalk14.cyan("xgen login")} \uB85C\uADF8\uC778
2156
+ `);
2157
+ }
2158
+ } else {
2159
+ program.parse();
2160
+ }
2161
+ //# sourceMappingURL=index.js.map