@team-semicolon/semo-cli 3.14.1 → 4.0.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/commands/bots.d.ts +11 -0
- package/dist/commands/bots.js +382 -0
- package/dist/commands/context.d.ts +8 -0
- package/dist/commands/context.js +302 -0
- package/dist/commands/get.d.ts +12 -0
- package/dist/commands/get.js +433 -0
- package/dist/database.d.ts +2 -0
- package/dist/database.js +26 -10
- package/dist/index.d.ts +6 -9
- package/dist/index.js +750 -1298
- package/dist/kb.d.ts +134 -0
- package/dist/kb.js +627 -0
- package/package.json +1 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* semo get <resource> — 세션 중 실시간 DB 쿼리
|
|
4
|
+
*
|
|
5
|
+
* semo get projects [--active]
|
|
6
|
+
* semo get bots [--status online|offline]
|
|
7
|
+
* semo get kb [--domain <d>] [--key <k>] [--search <text>]
|
|
8
|
+
* semo get ontology [--domain <d>]
|
|
9
|
+
* semo get tasks [--project <p>] [--status <s>]
|
|
10
|
+
* semo get sessions [--bot <n>]
|
|
11
|
+
*/
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.registerGetCommands = registerGetCommands;
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
const ora_1 = __importDefault(require("ora"));
|
|
19
|
+
const database_1 = require("../database");
|
|
20
|
+
const kb_1 = require("../kb");
|
|
21
|
+
// ============================================================
|
|
22
|
+
// Formatters
|
|
23
|
+
// ============================================================
|
|
24
|
+
function printTable(headers, rows, title) {
|
|
25
|
+
if (title)
|
|
26
|
+
console.log(chalk_1.default.cyan.bold(`\n${title}\n`));
|
|
27
|
+
if (rows.length === 0) {
|
|
28
|
+
console.log(chalk_1.default.yellow(" 결과 없음\n"));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Column widths
|
|
32
|
+
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => String(r[i] || "").length)));
|
|
33
|
+
const divider = " " + widths.map(w => "─".repeat(w + 2)).join("┬");
|
|
34
|
+
const header = " " + headers.map((h, i) => ` ${h.padEnd(widths[i])} `).join("│");
|
|
35
|
+
console.log(chalk_1.default.gray(divider));
|
|
36
|
+
console.log(chalk_1.default.gray(header));
|
|
37
|
+
console.log(chalk_1.default.gray(divider));
|
|
38
|
+
for (const row of rows) {
|
|
39
|
+
const line = " " + row.map((cell, i) => ` ${String(cell || "").padEnd(widths[i])} `).join("│");
|
|
40
|
+
console.log(line);
|
|
41
|
+
}
|
|
42
|
+
console.log(chalk_1.default.gray(divider));
|
|
43
|
+
console.log(chalk_1.default.gray(` ${rows.length}행\n`));
|
|
44
|
+
}
|
|
45
|
+
// ============================================================
|
|
46
|
+
// Command registration
|
|
47
|
+
// ============================================================
|
|
48
|
+
function registerGetCommands(program) {
|
|
49
|
+
const getCmd = program
|
|
50
|
+
.command("get")
|
|
51
|
+
.description("Core DB에서 리소스 실시간 조회");
|
|
52
|
+
// ── semo get projects ───────────────────────────────────────
|
|
53
|
+
getCmd
|
|
54
|
+
.command("projects")
|
|
55
|
+
.description("프로젝트 목록 조회")
|
|
56
|
+
.option("--active", "활성 프로젝트만")
|
|
57
|
+
.option("--format <type>", "출력 형식 (table|json|md)", "table")
|
|
58
|
+
.action(async (options) => {
|
|
59
|
+
const spinner = (0, ora_1.default)("프로젝트 조회 중...").start();
|
|
60
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
61
|
+
if (!connected) {
|
|
62
|
+
// Fallback: show KB entries with domain=project
|
|
63
|
+
try {
|
|
64
|
+
const pool = (0, database_1.getPool)();
|
|
65
|
+
const { shared } = await (0, kb_1.kbList)(pool, { domain: "project", limit: 100 });
|
|
66
|
+
spinner.stop();
|
|
67
|
+
if (options.format === "json") {
|
|
68
|
+
console.log(JSON.stringify(shared, null, 2));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
printTable(["key", "content"], shared.map(e => [e.key, e.content.substring(0, 80)]), "📁 프로젝트 (KB 기반)");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
spinner.fail("DB 연결 실패");
|
|
76
|
+
}
|
|
77
|
+
await (0, database_1.closeConnection)();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const pool = (0, database_1.getPool)();
|
|
82
|
+
const client = await pool.connect();
|
|
83
|
+
let query = `
|
|
84
|
+
SELECT id, name, display_name, status, description, updated_at::text
|
|
85
|
+
FROM semo.projects
|
|
86
|
+
`;
|
|
87
|
+
const params = [];
|
|
88
|
+
if (options.active) {
|
|
89
|
+
query += " WHERE status = 'active'";
|
|
90
|
+
}
|
|
91
|
+
query += " ORDER BY updated_at DESC";
|
|
92
|
+
let rows = [];
|
|
93
|
+
try {
|
|
94
|
+
const result = await client.query(query, params);
|
|
95
|
+
rows = result.rows;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// semo.projects table may not exist — fallback to KB
|
|
99
|
+
client.release();
|
|
100
|
+
const { shared } = await (0, kb_1.kbList)(pool, { domain: "project", limit: 100 });
|
|
101
|
+
spinner.stop();
|
|
102
|
+
if (options.format === "json") {
|
|
103
|
+
console.log(JSON.stringify(shared, null, 2));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
printTable(["key", "content"], shared.map(e => [e.key, e.content.substring(0, 80)]), "📁 프로젝트 (KB 기반)");
|
|
107
|
+
}
|
|
108
|
+
await (0, database_1.closeConnection)();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
client.release();
|
|
112
|
+
spinner.stop();
|
|
113
|
+
if (options.format === "json") {
|
|
114
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
printTable(["ID", "이름", "상태", "설명"], rows.map(r => [r.id, r.display_name || r.name, r.status || "-", (r.description || "").substring(0, 60)]), "📁 프로젝트");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
await (0, database_1.closeConnection)();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
// ── semo get bots ───────────────────────────────────────────
|
|
129
|
+
getCmd
|
|
130
|
+
.command("bots")
|
|
131
|
+
.description("봇 상태 조회")
|
|
132
|
+
.option("--status <filter>", "상태 필터 (online|offline)")
|
|
133
|
+
.option("--format <type>", "출력 형식 (table|json)", "table")
|
|
134
|
+
.action(async (options) => {
|
|
135
|
+
const spinner = (0, ora_1.default)("봇 상태 조회 중...").start();
|
|
136
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
137
|
+
if (!connected) {
|
|
138
|
+
spinner.fail("DB 연결 실패");
|
|
139
|
+
await (0, database_1.closeConnection)();
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const pool = (0, database_1.getPool)();
|
|
144
|
+
const client = await pool.connect();
|
|
145
|
+
let query = `
|
|
146
|
+
SELECT bot_id, name, emoji, role, status,
|
|
147
|
+
last_active::text, session_count, synced_at::text
|
|
148
|
+
FROM semo.bot_status
|
|
149
|
+
`;
|
|
150
|
+
const params = [];
|
|
151
|
+
if (options.status) {
|
|
152
|
+
query += " WHERE status = $1";
|
|
153
|
+
params.push(options.status);
|
|
154
|
+
}
|
|
155
|
+
query += " ORDER BY bot_id";
|
|
156
|
+
const result = await client.query(query, params);
|
|
157
|
+
client.release();
|
|
158
|
+
spinner.stop();
|
|
159
|
+
if (options.format === "json") {
|
|
160
|
+
console.log(JSON.stringify(result.rows, null, 2));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
printTable(["bot_id", "이름", "status", "last_active", "sessions"], result.rows.map((r) => [
|
|
164
|
+
r.bot_id,
|
|
165
|
+
[r.emoji, r.name].filter(Boolean).join(" ") || r.bot_id,
|
|
166
|
+
r.status || "-",
|
|
167
|
+
r.last_active ? new Date(r.last_active).toLocaleString("ko-KR") : "-",
|
|
168
|
+
String(r.session_count || 0),
|
|
169
|
+
]), "🤖 봇 상태");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
await (0, database_1.closeConnection)();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
// ── semo get kb ─────────────────────────────────────────────
|
|
181
|
+
getCmd
|
|
182
|
+
.command("kb")
|
|
183
|
+
.description("Knowledge Base 조회")
|
|
184
|
+
.option("--domain <name>", "도메인 필터")
|
|
185
|
+
.option("--key <name>", "키 검색")
|
|
186
|
+
.option("--search <text>", "하이브리드 검색")
|
|
187
|
+
.option("--limit <n>", "최대 결과 수", "20")
|
|
188
|
+
.option("--format <type>", "출력 형식 (table|json|md)", "table")
|
|
189
|
+
.action(async (options) => {
|
|
190
|
+
const spinner = (0, ora_1.default)("KB 조회 중...").start();
|
|
191
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
192
|
+
if (!connected) {
|
|
193
|
+
spinner.fail("DB 연결 실패");
|
|
194
|
+
await (0, database_1.closeConnection)();
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
const pool = (0, database_1.getPool)();
|
|
198
|
+
try {
|
|
199
|
+
let entries = [];
|
|
200
|
+
const limit = parseInt(options.limit);
|
|
201
|
+
if (options.search) {
|
|
202
|
+
const results = await (0, kb_1.kbSearch)(pool, options.search, {
|
|
203
|
+
domain: options.domain,
|
|
204
|
+
limit,
|
|
205
|
+
});
|
|
206
|
+
entries = results;
|
|
207
|
+
}
|
|
208
|
+
else if (options.key) {
|
|
209
|
+
const client = await pool.connect();
|
|
210
|
+
const result = await client.query(`SELECT domain, key, content, metadata, updated_at::text
|
|
211
|
+
FROM semo.knowledge_base
|
|
212
|
+
WHERE key ILIKE $1${options.domain ? " AND domain = $2" : ""}
|
|
213
|
+
ORDER BY domain, key LIMIT $${options.domain ? 3 : 2}`, options.domain
|
|
214
|
+
? [`%${options.key}%`, options.domain, limit]
|
|
215
|
+
: [`%${options.key}%`, limit]);
|
|
216
|
+
client.release();
|
|
217
|
+
entries = result.rows;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const { shared } = await (0, kb_1.kbList)(pool, {
|
|
221
|
+
domain: options.domain,
|
|
222
|
+
limit,
|
|
223
|
+
});
|
|
224
|
+
entries = shared;
|
|
225
|
+
}
|
|
226
|
+
spinner.stop();
|
|
227
|
+
if (options.format === "json") {
|
|
228
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
229
|
+
}
|
|
230
|
+
else if (options.format === "md") {
|
|
231
|
+
for (const e of entries) {
|
|
232
|
+
console.log(`\n## ${e["domain"]}/${e["key"]}\n`);
|
|
233
|
+
console.log(e["content"]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
printTable(["domain", "key", "content"], entries.map(e => [
|
|
238
|
+
e["domain"] || "",
|
|
239
|
+
e["key"] || "",
|
|
240
|
+
(e["content"] || "").substring(0, 60),
|
|
241
|
+
]), "📚 Knowledge Base");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
await (0, database_1.closeConnection)();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
// ── semo get ontology ───────────────────────────────────────
|
|
253
|
+
getCmd
|
|
254
|
+
.command("ontology")
|
|
255
|
+
.description("온톨로지 도메인 조회")
|
|
256
|
+
.option("--domain <name>", "특정 도메인 상세")
|
|
257
|
+
.option("--format <type>", "출력 형식 (table|json)", "table")
|
|
258
|
+
.action(async (options) => {
|
|
259
|
+
const spinner = (0, ora_1.default)("온톨로지 조회 중...").start();
|
|
260
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
261
|
+
if (!connected) {
|
|
262
|
+
spinner.fail("DB 연결 실패");
|
|
263
|
+
await (0, database_1.closeConnection)();
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
const pool = (0, database_1.getPool)();
|
|
267
|
+
try {
|
|
268
|
+
if (options.domain) {
|
|
269
|
+
const onto = await (0, kb_1.ontoShow)(pool, options.domain);
|
|
270
|
+
spinner.stop();
|
|
271
|
+
if (!onto) {
|
|
272
|
+
console.log(chalk_1.default.red(`\n 온톨로지 '${options.domain}'을 찾을 수 없습니다.\n`));
|
|
273
|
+
}
|
|
274
|
+
else if (options.format === "json") {
|
|
275
|
+
console.log(JSON.stringify(onto, null, 2));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.log(chalk_1.default.cyan.bold(`\n📐 ${onto.domain} (v${onto.version})\n`));
|
|
279
|
+
if (onto.description)
|
|
280
|
+
console.log(chalk_1.default.gray(` ${onto.description}\n`));
|
|
281
|
+
console.log(JSON.stringify(onto.schema, null, 2).split("\n").map(l => " " + l).join("\n"));
|
|
282
|
+
console.log();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const domains = await (0, kb_1.ontoList)(pool);
|
|
287
|
+
spinner.stop();
|
|
288
|
+
if (options.format === "json") {
|
|
289
|
+
console.log(JSON.stringify(domains, null, 2));
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
printTable(["domain", "version", "description"], domains.map(d => [d.domain, String(d.version), d.description || "-"]), "📐 온톨로지 도메인");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
await (0, database_1.closeConnection)();
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
// ── semo get tasks ──────────────────────────────────────────
|
|
305
|
+
getCmd
|
|
306
|
+
.command("tasks")
|
|
307
|
+
.description("태스크 조회 (semo.tasks)")
|
|
308
|
+
.option("--project <name>", "프로젝트 필터")
|
|
309
|
+
.option("--status <s>", "상태 필터 (open|in_progress|done)")
|
|
310
|
+
.option("--limit <n>", "최대 결과 수", "20")
|
|
311
|
+
.option("--format <type>", "출력 형식 (table|json)", "table")
|
|
312
|
+
.action(async (options) => {
|
|
313
|
+
const spinner = (0, ora_1.default)("태스크 조회 중...").start();
|
|
314
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
315
|
+
if (!connected) {
|
|
316
|
+
spinner.fail("DB 연결 실패");
|
|
317
|
+
await (0, database_1.closeConnection)();
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const pool = (0, database_1.getPool)();
|
|
322
|
+
const client = await pool.connect();
|
|
323
|
+
let query = "SELECT id, title, status, project_id, assignee_name, updated_at::text FROM semo.tasks";
|
|
324
|
+
const params = [];
|
|
325
|
+
const conditions = [];
|
|
326
|
+
let idx = 1;
|
|
327
|
+
if (options.project) {
|
|
328
|
+
conditions.push(`project_id = $${idx++}`);
|
|
329
|
+
params.push(options.project);
|
|
330
|
+
}
|
|
331
|
+
if (options.status) {
|
|
332
|
+
conditions.push(`status = $${idx++}`);
|
|
333
|
+
params.push(options.status);
|
|
334
|
+
}
|
|
335
|
+
if (conditions.length > 0) {
|
|
336
|
+
query += " WHERE " + conditions.join(" AND ");
|
|
337
|
+
}
|
|
338
|
+
query += ` ORDER BY updated_at DESC LIMIT $${idx++}`;
|
|
339
|
+
params.push(parseInt(options.limit));
|
|
340
|
+
let rows = [];
|
|
341
|
+
try {
|
|
342
|
+
const result = await client.query(query, params);
|
|
343
|
+
rows = result.rows;
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
client.release();
|
|
347
|
+
spinner.warn("semo.tasks 테이블이 없거나 접근 불가");
|
|
348
|
+
await (0, database_1.closeConnection)();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
client.release();
|
|
352
|
+
spinner.stop();
|
|
353
|
+
if (options.format === "json") {
|
|
354
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
printTable(["id", "title", "status", "assignee"], rows.map(r => [r.id, (r.title || "").substring(0, 50), r.status, r.assignee_name || "-"]), "📋 태스크");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
await (0, database_1.closeConnection)();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
// ── semo get sessions ───────────────────────────────────────
|
|
369
|
+
getCmd
|
|
370
|
+
.command("sessions")
|
|
371
|
+
.description("봇 세션 조회 (semo.bot_sessions)")
|
|
372
|
+
.option("--bot <name>", "봇 ID 필터")
|
|
373
|
+
.option("--limit <n>", "최대 결과 수", "10")
|
|
374
|
+
.option("--format <type>", "출력 형식 (table|json)", "table")
|
|
375
|
+
.action(async (options) => {
|
|
376
|
+
const spinner = (0, ora_1.default)("세션 조회 중...").start();
|
|
377
|
+
const connected = await (0, database_1.isDbConnected)();
|
|
378
|
+
if (!connected) {
|
|
379
|
+
spinner.fail("DB 연결 실패");
|
|
380
|
+
await (0, database_1.closeConnection)();
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
const pool = (0, database_1.getPool)();
|
|
385
|
+
const client = await pool.connect();
|
|
386
|
+
let query = `
|
|
387
|
+
SELECT bot_id, session_key, label, kind, chat_type,
|
|
388
|
+
last_activity::text, message_count
|
|
389
|
+
FROM semo.bot_sessions
|
|
390
|
+
`;
|
|
391
|
+
const params = [];
|
|
392
|
+
let idx = 1;
|
|
393
|
+
if (options.bot) {
|
|
394
|
+
query += ` WHERE bot_id = $${idx++}`;
|
|
395
|
+
params.push(options.bot);
|
|
396
|
+
}
|
|
397
|
+
query += ` ORDER BY last_activity DESC NULLS LAST LIMIT $${idx++}`;
|
|
398
|
+
params.push(parseInt(options.limit));
|
|
399
|
+
let rows = [];
|
|
400
|
+
try {
|
|
401
|
+
const result = await client.query(query, params);
|
|
402
|
+
rows = result.rows;
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
client.release();
|
|
406
|
+
spinner.warn("semo.bot_sessions 테이블이 없거나 접근 불가");
|
|
407
|
+
await (0, database_1.closeConnection)();
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
client.release();
|
|
411
|
+
spinner.stop();
|
|
412
|
+
if (options.format === "json") {
|
|
413
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
printTable(["bot_id", "session_key", "label", "last_activity", "msgs"], rows.map(r => [
|
|
417
|
+
r.bot_id,
|
|
418
|
+
r.session_key || "-",
|
|
419
|
+
r.label || "-",
|
|
420
|
+
r.last_activity ? new Date(r.last_activity).toLocaleString("ko-KR") : "-",
|
|
421
|
+
String(r.message_count || 0),
|
|
422
|
+
]), "📋 봇 세션");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
spinner.fail(`조회 실패: ${err}`);
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
await (0, database_1.closeConnection)();
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
package/dist/database.d.ts
CHANGED
package/dist/database.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* - 문서 내용을 DB에서 직접 조회
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.getPool = getPool;
|
|
13
14
|
exports.getActiveSkills = getActiveSkills;
|
|
14
15
|
exports.getActiveSkillNames = getActiveSkillNames;
|
|
15
16
|
exports.getCommands = getCommands;
|
|
@@ -20,16 +21,31 @@ exports.closeConnection = closeConnection;
|
|
|
20
21
|
exports.isDbConnected = isDbConnected;
|
|
21
22
|
const pg_1 = require("pg");
|
|
22
23
|
// PostgreSQL 연결 정보 (팀 코어)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
24
|
+
// DATABASE_URL 우선, 없으면 개별 SEMO_DB_* 변수 사용
|
|
25
|
+
function buildDbConfig() {
|
|
26
|
+
if (process.env.DATABASE_URL) {
|
|
27
|
+
return {
|
|
28
|
+
connectionString: process.env.DATABASE_URL,
|
|
29
|
+
ssl: process.env.DATABASE_URL.includes("sslmode=require") ? { rejectUnauthorized: false } : false,
|
|
30
|
+
connectionTimeoutMillis: 5000,
|
|
31
|
+
idleTimeoutMillis: 30000,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (!process.env.SEMO_DB_HOST && !process.env.DATABASE_URL) {
|
|
35
|
+
throw new Error("DB 연결 정보가 없습니다. DATABASE_URL 또는 SEMO_DB_HOST 환경변수를 설정하세요.");
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
host: process.env.SEMO_DB_HOST,
|
|
39
|
+
port: parseInt(process.env.SEMO_DB_PORT || "5432"),
|
|
40
|
+
user: process.env.SEMO_DB_USER || "app",
|
|
41
|
+
password: process.env.SEMO_DB_PASSWORD,
|
|
42
|
+
database: process.env.SEMO_DB_NAME || "appdb",
|
|
43
|
+
ssl: false,
|
|
44
|
+
connectionTimeoutMillis: 5000,
|
|
45
|
+
idleTimeoutMillis: 30000,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const DB_CONFIG = buildDbConfig();
|
|
33
49
|
// PostgreSQL Pool (싱글톤)
|
|
34
50
|
let pool = null;
|
|
35
51
|
function getPool() {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* SEMO CLI
|
|
3
|
+
* SEMO CLI v4.0
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Core DB 기반 컨텍스트 동기화 시스템
|
|
6
6
|
*
|
|
7
7
|
* 사용법:
|
|
8
|
-
* npx @team-semicolon/semo-cli init # 기본 설치
|
|
9
|
-
* npx @team-semicolon/semo-cli
|
|
10
|
-
* npx @team-semicolon/semo-cli
|
|
11
|
-
*
|
|
12
|
-
* 구조:
|
|
13
|
-
* - Standard: semo-core + semo-skills (필수)
|
|
14
|
-
* - Extensions: packages/next, packages/backend 등 (선택)
|
|
8
|
+
* npx @team-semicolon/semo-cli init # 기본 설치 (훅 등록 포함)
|
|
9
|
+
* npx @team-semicolon/semo-cli context sync # DB → .claude/memory/
|
|
10
|
+
* npx @team-semicolon/semo-cli bots status # 봇 상태 조회
|
|
11
|
+
* npx @team-semicolon/semo-cli get kb # KB 실시간 쿼리
|
|
15
12
|
*/
|
|
16
13
|
export {};
|