@team-semicolon/semo-cli 4.10.0 → 4.11.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 +128 -2
- package/dist/kb.d.ts +11 -0
- package/dist/kb.js +45 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1733,7 +1733,7 @@ kbCmd
|
|
|
1733
1733
|
kbCmd
|
|
1734
1734
|
.command("ontology")
|
|
1735
1735
|
.description("온톨로지 조회 — 도메인/타입/스키마/라우팅 테이블")
|
|
1736
|
-
.option("--action <type>", "동작 (list|show|services|types|instances|schema|routing-table|register|create-type|add-key|remove-key)", "list")
|
|
1736
|
+
.option("--action <type>", "동작 (list|show|services|types|instances|schema|routing-table|register|unregister|create-type|add-key|remove-key)", "list")
|
|
1737
1737
|
.option("--domain <name>", "action=show|register 시 도메인")
|
|
1738
1738
|
.option("--type <name>", "action=schema|register|add-key|remove-key 시 타입 키")
|
|
1739
1739
|
.option("--key <name>", "action=add-key|remove-key 시 스키마 키")
|
|
@@ -1744,6 +1744,8 @@ kbCmd
|
|
|
1744
1744
|
.option("--service <name>", "action=register 시 서비스 그룹")
|
|
1745
1745
|
.option("--tags <tags>", "action=register 시 태그 (쉼표 구분)")
|
|
1746
1746
|
.option("--no-init", "action=register 시 필수 KB entry 자동 생성 건너뛰기")
|
|
1747
|
+
.option("--force", "action=unregister 시 잔존 KB 항목도 모두 삭제")
|
|
1748
|
+
.option("--yes", "action=unregister 시 확인 프롬프트 건너뛰기")
|
|
1747
1749
|
.option("--format <type>", "출력 형식 (json|table)", "table")
|
|
1748
1750
|
.action(async (options) => {
|
|
1749
1751
|
try {
|
|
@@ -1989,8 +1991,64 @@ kbCmd
|
|
|
1989
1991
|
process.exit(1);
|
|
1990
1992
|
}
|
|
1991
1993
|
}
|
|
1994
|
+
else if (action === "unregister") {
|
|
1995
|
+
if (!options.domain) {
|
|
1996
|
+
console.log(chalk_1.default.red("--domain 옵션이 필요합니다."));
|
|
1997
|
+
process.exit(1);
|
|
1998
|
+
}
|
|
1999
|
+
// 도메인 정보 조회
|
|
2000
|
+
const domainInfo = await (0, kb_1.ontoShow)(pool, options.domain);
|
|
2001
|
+
if (!domainInfo) {
|
|
2002
|
+
console.log(chalk_1.default.red(`\n❌ 도메인 '${options.domain}'은(는) 존재하지 않습니다.\n`));
|
|
2003
|
+
process.exit(1);
|
|
2004
|
+
}
|
|
2005
|
+
// KB 엔트리 수 확인
|
|
2006
|
+
const countRes = await pool.query("SELECT COUNT(*)::int AS cnt FROM semo.knowledge_base WHERE domain = $1", [options.domain]);
|
|
2007
|
+
const kbCount = countRes.rows[0].cnt;
|
|
2008
|
+
// 확인 프롬프트
|
|
2009
|
+
if (!options.yes) {
|
|
2010
|
+
const typeStr = domainInfo.entity_type ? ` [${domainInfo.entity_type}]` : "";
|
|
2011
|
+
const svcStr = domainInfo.service && domainInfo.service !== "_global" ? ` (${domainInfo.service})` : "";
|
|
2012
|
+
if (kbCount > 0 && options.force) {
|
|
2013
|
+
console.log(chalk_1.default.yellow(`\n⚠️ 도메인 '${options.domain}'에 KB 항목 ${kbCount}건이 남아있습니다.`));
|
|
2014
|
+
console.log(chalk_1.default.yellow(` --force 옵션으로 모두 삭제됩니다.\n`));
|
|
2015
|
+
}
|
|
2016
|
+
else {
|
|
2017
|
+
console.log(chalk_1.default.cyan(`\n📐 삭제 대상 도메인: ${options.domain}${typeStr}${svcStr}`));
|
|
2018
|
+
console.log(chalk_1.default.gray(` KB 항목: ${kbCount}건\n`));
|
|
2019
|
+
}
|
|
2020
|
+
const { createInterface } = await import("readline");
|
|
2021
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2022
|
+
const answer = await new Promise((resolve) => {
|
|
2023
|
+
rl.question(chalk_1.default.yellow(" 정말 삭제하시겠습니까? (y/N): "), resolve);
|
|
2024
|
+
});
|
|
2025
|
+
rl.close();
|
|
2026
|
+
if (answer.toLowerCase() !== "y") {
|
|
2027
|
+
console.log(chalk_1.default.gray(" 취소됨.\n"));
|
|
2028
|
+
await (0, database_1.closeConnection)();
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
const result = await (0, kb_1.ontoUnregister)(pool, options.domain, !!options.force);
|
|
2033
|
+
if (options.format === "json") {
|
|
2034
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2035
|
+
}
|
|
2036
|
+
else {
|
|
2037
|
+
if (result.success) {
|
|
2038
|
+
console.log(chalk_1.default.green(`\n✅ 도메인 '${options.domain}' 삭제 완료`));
|
|
2039
|
+
if (result.deleted_entries && result.deleted_entries > 0) {
|
|
2040
|
+
console.log(chalk_1.default.gray(` KB 항목 ${result.deleted_entries}건 함께 삭제됨`));
|
|
2041
|
+
}
|
|
2042
|
+
console.log();
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
console.log(chalk_1.default.red(`\n❌ 삭제 실패: ${result.error}\n`));
|
|
2046
|
+
process.exit(1);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
1992
2050
|
else {
|
|
1993
|
-
console.log(chalk_1.default.red(`알 수 없는 action: '${action}'. 사용 가능: list, show, services, types, instances, schema, routing-table, register, create-type, add-key, remove-key`));
|
|
2051
|
+
console.log(chalk_1.default.red(`알 수 없는 action: '${action}'. 사용 가능: list, show, services, types, instances, schema, routing-table, register, create-type, add-key, remove-key, unregister`));
|
|
1994
2052
|
process.exit(1);
|
|
1995
2053
|
}
|
|
1996
2054
|
await (0, database_1.closeConnection)();
|
|
@@ -2218,6 +2276,74 @@ ontoCmd
|
|
|
2218
2276
|
process.exit(1);
|
|
2219
2277
|
}
|
|
2220
2278
|
});
|
|
2279
|
+
ontoCmd
|
|
2280
|
+
.command("unregister <domain>")
|
|
2281
|
+
.description("온톨로지 도메인 삭제 (KB 데이터 포함)")
|
|
2282
|
+
.option("--force", "잔존 KB 항목이 있어도 모두 삭제 후 도메인 제거")
|
|
2283
|
+
.option("--yes", "확인 프롬프트 건너뛰기")
|
|
2284
|
+
.option("--format <type>", "출력 형식 (json|table)", "table")
|
|
2285
|
+
.action(async (domain, options) => {
|
|
2286
|
+
try {
|
|
2287
|
+
const pool = (0, database_1.getPool)();
|
|
2288
|
+
// 도메인 정보 조회
|
|
2289
|
+
const domainInfo = await (0, kb_1.ontoShow)(pool, domain);
|
|
2290
|
+
if (!domainInfo) {
|
|
2291
|
+
console.log(chalk_1.default.red(`\n❌ 도메인 '${domain}'은(는) 존재하지 않습니다.\n`));
|
|
2292
|
+
await (0, database_1.closeConnection)();
|
|
2293
|
+
process.exit(1);
|
|
2294
|
+
}
|
|
2295
|
+
// KB 엔트리 수 확인
|
|
2296
|
+
const countRes = await pool.query("SELECT COUNT(*)::int AS cnt FROM semo.knowledge_base WHERE domain = $1", [domain]);
|
|
2297
|
+
const kbCount = countRes.rows[0].cnt;
|
|
2298
|
+
// 확인 프롬프트
|
|
2299
|
+
if (!options.yes) {
|
|
2300
|
+
const typeStr = domainInfo.entity_type ? ` [${domainInfo.entity_type}]` : "";
|
|
2301
|
+
const svcStr = domainInfo.service && domainInfo.service !== "_global" ? ` (${domainInfo.service})` : "";
|
|
2302
|
+
if (kbCount > 0 && options.force) {
|
|
2303
|
+
console.log(chalk_1.default.yellow(`\n⚠️ 도메인 '${domain}'에 KB 항목 ${kbCount}건이 남아있습니다.`));
|
|
2304
|
+
console.log(chalk_1.default.yellow(` --force 옵션으로 모두 삭제됩니다.\n`));
|
|
2305
|
+
}
|
|
2306
|
+
else {
|
|
2307
|
+
console.log(chalk_1.default.cyan(`\n📐 삭제 대상 도메인: ${domain}${typeStr}${svcStr}`));
|
|
2308
|
+
console.log(chalk_1.default.gray(` KB 항목: ${kbCount}건\n`));
|
|
2309
|
+
}
|
|
2310
|
+
const { createInterface } = await import("readline");
|
|
2311
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2312
|
+
const answer = await new Promise((resolve) => {
|
|
2313
|
+
rl.question(chalk_1.default.yellow(" 정말 삭제하시겠습니까? (y/N): "), resolve);
|
|
2314
|
+
});
|
|
2315
|
+
rl.close();
|
|
2316
|
+
if (answer.toLowerCase() !== "y") {
|
|
2317
|
+
console.log(chalk_1.default.gray(" 취소됨.\n"));
|
|
2318
|
+
await (0, database_1.closeConnection)();
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
const result = await (0, kb_1.ontoUnregister)(pool, domain, !!options.force);
|
|
2323
|
+
if (options.format === "json") {
|
|
2324
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2325
|
+
}
|
|
2326
|
+
else {
|
|
2327
|
+
if (result.success) {
|
|
2328
|
+
console.log(chalk_1.default.green(`\n✅ 도메인 '${domain}' 삭제 완료`));
|
|
2329
|
+
if (result.deleted_entries && result.deleted_entries > 0) {
|
|
2330
|
+
console.log(chalk_1.default.gray(` KB 항목 ${result.deleted_entries}건 함께 삭제됨`));
|
|
2331
|
+
}
|
|
2332
|
+
console.log();
|
|
2333
|
+
}
|
|
2334
|
+
else {
|
|
2335
|
+
console.log(chalk_1.default.red(`\n❌ 삭제 실패: ${result.error}\n`));
|
|
2336
|
+
process.exit(1);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
await (0, database_1.closeConnection)();
|
|
2340
|
+
}
|
|
2341
|
+
catch (err) {
|
|
2342
|
+
console.error(chalk_1.default.red(`삭제 실패: ${err}`));
|
|
2343
|
+
await (0, database_1.closeConnection)();
|
|
2344
|
+
process.exit(1);
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2221
2347
|
// === 신규 v4 커맨드 그룹 등록 ===
|
|
2222
2348
|
(0, context_1.registerContextCommands)(program);
|
|
2223
2349
|
(0, bots_1.registerBotsCommands)(program);
|
package/dist/kb.d.ts
CHANGED
|
@@ -232,6 +232,17 @@ export interface OntoRegisterResult {
|
|
|
232
232
|
* 4. If init_required (default true), create KB entries for required keys in kb_type_schema
|
|
233
233
|
*/
|
|
234
234
|
export declare function ontoRegister(pool: Pool, opts: OntoRegisterOptions): Promise<OntoRegisterResult>;
|
|
235
|
+
export interface OntoUnregisterResult {
|
|
236
|
+
success: boolean;
|
|
237
|
+
deleted_entries?: number;
|
|
238
|
+
error?: string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Unregister an ontology domain.
|
|
242
|
+
* If force=false and KB entries exist, returns error with count.
|
|
243
|
+
* If force=true, deletes all KB entries in a transaction, then removes the domain.
|
|
244
|
+
*/
|
|
245
|
+
export declare function ontoUnregister(pool: Pool, domain: string, force: boolean): Promise<OntoUnregisterResult>;
|
|
235
246
|
/**
|
|
236
247
|
* Add a key to a type schema
|
|
237
248
|
*/
|
package/dist/kb.js
CHANGED
|
@@ -62,6 +62,7 @@ exports.ontoRoutingTable = ontoRoutingTable;
|
|
|
62
62
|
exports.ontoListServices = ontoListServices;
|
|
63
63
|
exports.ontoListInstances = ontoListInstances;
|
|
64
64
|
exports.ontoRegister = ontoRegister;
|
|
65
|
+
exports.ontoUnregister = ontoUnregister;
|
|
65
66
|
exports.ontoAddKey = ontoAddKey;
|
|
66
67
|
exports.ontoCreateType = ontoCreateType;
|
|
67
68
|
exports.ontoRemoveKey = ontoRemoveKey;
|
|
@@ -1011,6 +1012,50 @@ async function ontoRegister(pool, opts) {
|
|
|
1011
1012
|
client.release();
|
|
1012
1013
|
}
|
|
1013
1014
|
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Unregister an ontology domain.
|
|
1017
|
+
* If force=false and KB entries exist, returns error with count.
|
|
1018
|
+
* If force=true, deletes all KB entries in a transaction, then removes the domain.
|
|
1019
|
+
*/
|
|
1020
|
+
async function ontoUnregister(pool, domain, force) {
|
|
1021
|
+
const client = await pool.connect();
|
|
1022
|
+
try {
|
|
1023
|
+
// 1. Check domain exists
|
|
1024
|
+
const domainCheck = await client.query("SELECT domain, entity_type, service FROM semo.ontology WHERE domain = $1", [domain]);
|
|
1025
|
+
if (domainCheck.rows.length === 0) {
|
|
1026
|
+
return { success: false, error: `도메인 '${domain}'은(는) 존재하지 않습니다.` };
|
|
1027
|
+
}
|
|
1028
|
+
// 2. Count KB entries
|
|
1029
|
+
const countResult = await client.query("SELECT COUNT(*)::int AS cnt FROM semo.knowledge_base WHERE domain = $1", [domain]);
|
|
1030
|
+
const entryCount = countResult.rows[0].cnt;
|
|
1031
|
+
// 3. If entries exist and no force → error
|
|
1032
|
+
if (entryCount > 0 && !force) {
|
|
1033
|
+
return {
|
|
1034
|
+
success: false,
|
|
1035
|
+
error: `도메인 '${domain}'에 KB 항목 ${entryCount}건이 남아있습니다. --force 옵션으로 모두 삭제 후 제거할 수 있습니다.`,
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
// 4. Transaction: delete KB entries (if any) → delete ontology
|
|
1039
|
+
await client.query("BEGIN");
|
|
1040
|
+
try {
|
|
1041
|
+
let deletedEntries = 0;
|
|
1042
|
+
if (entryCount > 0) {
|
|
1043
|
+
const delResult = await client.query("DELETE FROM semo.knowledge_base WHERE domain = $1", [domain]);
|
|
1044
|
+
deletedEntries = delResult.rowCount ?? 0;
|
|
1045
|
+
}
|
|
1046
|
+
await client.query("DELETE FROM semo.ontology WHERE domain = $1", [domain]);
|
|
1047
|
+
await client.query("COMMIT");
|
|
1048
|
+
return { success: true, deleted_entries: deletedEntries };
|
|
1049
|
+
}
|
|
1050
|
+
catch (err) {
|
|
1051
|
+
await client.query("ROLLBACK");
|
|
1052
|
+
return { success: false, error: String(err) };
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
finally {
|
|
1056
|
+
client.release();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1014
1059
|
/**
|
|
1015
1060
|
* Add a key to a type schema
|
|
1016
1061
|
*/
|