@team-semicolon/semo-cli 4.7.3 → 4.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1705,9 +1705,13 @@ kbCmd
1705
1705
  kbCmd
1706
1706
  .command("ontology")
1707
1707
  .description("온톨로지 조회 — 도메인/타입/스키마/라우팅 테이블")
1708
- .option("--action <type>", "조회 동작 (list|show|services|types|instances|schema|routing-table)", "list")
1709
- .option("--domain <name>", "action=show 시 도메인")
1710
- .option("--type <name>", "action=schema 시 타입 키")
1708
+ .option("--action <type>", "동작 (list|show|services|types|instances|schema|routing-table|register)", "list")
1709
+ .option("--domain <name>", "action=show|register 시 도메인")
1710
+ .option("--type <name>", "action=schema|register 시 타입 키")
1711
+ .option("--description <text>", "action=register 시 설명")
1712
+ .option("--service <name>", "action=register 시 서비스 그룹")
1713
+ .option("--tags <tags>", "action=register 시 태그 (쉼표 구분)")
1714
+ .option("--no-init", "action=register 시 필수 KB entry 자동 생성 건너뛰기")
1711
1715
  .option("--format <type>", "출력 형식 (json|table)", "table")
1712
1716
  .action(async (options) => {
1713
1717
  try {
@@ -1852,8 +1856,48 @@ kbCmd
1852
1856
  console.log();
1853
1857
  }
1854
1858
  }
1859
+ else if (action === "register") {
1860
+ if (!options.domain) {
1861
+ console.log(chalk_1.default.red("--domain 옵션이 필요합니다."));
1862
+ process.exit(1);
1863
+ }
1864
+ if (!options.type) {
1865
+ console.log(chalk_1.default.red("--type 옵션이 필요합니다. (예: --type service, --type team, --type person)"));
1866
+ const types = await (0, kb_1.ontoListTypes)(pool);
1867
+ console.log(chalk_1.default.gray(`사용 가능한 타입: ${types.map(t => t.type_key).join(", ")}`));
1868
+ process.exit(1);
1869
+ }
1870
+ const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : undefined;
1871
+ const result = await (0, kb_1.ontoRegister)(pool, {
1872
+ domain: options.domain,
1873
+ entity_type: options.type,
1874
+ description: options.description,
1875
+ service: options.service,
1876
+ tags,
1877
+ init_required: options.init !== false,
1878
+ });
1879
+ if (options.format === "json") {
1880
+ console.log(JSON.stringify(result, null, 2));
1881
+ }
1882
+ else {
1883
+ if (result.success) {
1884
+ console.log(chalk_1.default.green(`\n✅ 도메인 '${options.domain}' 등록 완료 (타입: ${options.type})`));
1885
+ if (result.created_entries && result.created_entries.length > 0) {
1886
+ console.log(chalk_1.default.gray(` 초기 KB entry ${result.created_entries.length}건 생성:`));
1887
+ for (const e of result.created_entries) {
1888
+ console.log(chalk_1.default.gray(` - ${e.key}`));
1889
+ }
1890
+ }
1891
+ console.log(chalk_1.default.gray(`\n 다음 단계: semo kb upsert ${options.domain} <key> --content "..." 으로 데이터 입력\n`));
1892
+ }
1893
+ else {
1894
+ console.log(chalk_1.default.red(`\n❌ 등록 실패: ${result.error}\n`));
1895
+ process.exit(1);
1896
+ }
1897
+ }
1898
+ }
1855
1899
  else {
1856
- console.log(chalk_1.default.red(`알 수 없는 action: '${action}'. 사용 가능: list, show, services, types, instances, schema, routing-table`));
1900
+ console.log(chalk_1.default.red(`알 수 없는 action: '${action}'. 사용 가능: list, show, services, types, instances, schema, routing-table, register`));
1857
1901
  process.exit(1);
1858
1902
  }
1859
1903
  await (0, database_1.closeConnection)();
@@ -2033,6 +2077,54 @@ ontoCmd
2033
2077
  process.exit(1);
2034
2078
  }
2035
2079
  });
2080
+ ontoCmd
2081
+ .command("register <domain>")
2082
+ .description("새 온톨로지 도메인 등록")
2083
+ .requiredOption("--type <type>", "엔티티 타입 (예: service, team, person, bot)")
2084
+ .option("--description <text>", "도메인 설명")
2085
+ .option("--service <name>", "서비스 그룹")
2086
+ .option("--tags <tags>", "태그 (쉼표 구분)")
2087
+ .option("--no-init", "필수 KB entry 자동 생성 건너뛰기")
2088
+ .option("--format <type>", "출력 형식 (json|table)", "table")
2089
+ .action(async (domain, options) => {
2090
+ try {
2091
+ const pool = (0, database_1.getPool)();
2092
+ const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : undefined;
2093
+ const result = await (0, kb_1.ontoRegister)(pool, {
2094
+ domain,
2095
+ entity_type: options.type,
2096
+ description: options.description,
2097
+ service: options.service,
2098
+ tags,
2099
+ init_required: options.init !== false,
2100
+ });
2101
+ if (options.format === "json") {
2102
+ console.log(JSON.stringify(result, null, 2));
2103
+ }
2104
+ else {
2105
+ if (result.success) {
2106
+ console.log(chalk_1.default.green(`\n✅ 도메인 '${domain}' 등록 완료 (타입: ${options.type})`));
2107
+ if (result.created_entries && result.created_entries.length > 0) {
2108
+ console.log(chalk_1.default.gray(` 초기 KB entry ${result.created_entries.length}건 생성:`));
2109
+ for (const e of result.created_entries) {
2110
+ console.log(chalk_1.default.gray(` - ${e.key}`));
2111
+ }
2112
+ }
2113
+ console.log(chalk_1.default.gray(`\n 다음 단계: semo kb upsert ${domain} <key> --content "..." 으로 데이터 입력\n`));
2114
+ }
2115
+ else {
2116
+ console.log(chalk_1.default.red(`\n❌ 등록 실패: ${result.error}\n`));
2117
+ process.exit(1);
2118
+ }
2119
+ }
2120
+ await (0, database_1.closeConnection)();
2121
+ }
2122
+ catch (err) {
2123
+ console.error(chalk_1.default.red(`등록 실패: ${err}`));
2124
+ await (0, database_1.closeConnection)();
2125
+ process.exit(1);
2126
+ }
2127
+ });
2036
2128
  // === 신규 v4 커맨드 그룹 등록 ===
2037
2129
  (0, context_1.registerContextCommands)(program);
2038
2130
  (0, bots_1.registerBotsCommands)(program);
package/dist/kb.d.ts CHANGED
@@ -198,6 +198,31 @@ export declare function ontoListServices(pool: Pool): Promise<ServiceInfo[]>;
198
198
  * List service instances (entity_type = 'service')
199
199
  */
200
200
  export declare function ontoListInstances(pool: Pool): Promise<ServiceInstance[]>;
201
+ export interface OntoRegisterOptions {
202
+ domain: string;
203
+ entity_type: string;
204
+ description?: string;
205
+ service?: string;
206
+ tags?: string[];
207
+ init_required?: boolean;
208
+ }
209
+ export interface OntoRegisterResult {
210
+ success: boolean;
211
+ error?: string;
212
+ created_entries?: Array<{
213
+ key: string;
214
+ sub_key: string;
215
+ }>;
216
+ }
217
+ /**
218
+ * Register a new ontology domain with optional initial required KB entries.
219
+ *
220
+ * 1. Validate entity_type exists in ontology_types
221
+ * 2. Check domain doesn't already exist
222
+ * 3. INSERT into semo.ontology
223
+ * 4. If init_required (default true), create KB entries for required keys in kb_type_schema
224
+ */
225
+ export declare function ontoRegister(pool: Pool, opts: OntoRegisterOptions): Promise<OntoRegisterResult>;
201
226
  /**
202
227
  * Write ontology schemas to local cache
203
228
  */
package/dist/kb.js CHANGED
@@ -60,6 +60,7 @@ exports.ontoListSchema = ontoListSchema;
60
60
  exports.ontoRoutingTable = ontoRoutingTable;
61
61
  exports.ontoListServices = ontoListServices;
62
62
  exports.ontoListInstances = ontoListInstances;
63
+ exports.ontoRegister = ontoRegister;
63
64
  exports.ontoPullToLocal = ontoPullToLocal;
64
65
  const fs = __importStar(require("fs"));
65
66
  const path = __importStar(require("path"));
@@ -886,6 +887,79 @@ async function ontoListInstances(pool) {
886
887
  client.release();
887
888
  }
888
889
  }
890
+ /**
891
+ * Register a new ontology domain with optional initial required KB entries.
892
+ *
893
+ * 1. Validate entity_type exists in ontology_types
894
+ * 2. Check domain doesn't already exist
895
+ * 3. INSERT into semo.ontology
896
+ * 4. If init_required (default true), create KB entries for required keys in kb_type_schema
897
+ */
898
+ async function ontoRegister(pool, opts) {
899
+ const client = await pool.connect();
900
+ try {
901
+ // 1. Validate entity_type
902
+ const typeCheck = await client.query("SELECT type_key FROM semo.ontology_types WHERE type_key = $1", [opts.entity_type]);
903
+ if (typeCheck.rows.length === 0) {
904
+ const known = await client.query("SELECT type_key FROM semo.ontology_types ORDER BY type_key");
905
+ const knownTypes = known.rows.map((r) => r.type_key);
906
+ return {
907
+ success: false,
908
+ error: `타입 '${opts.entity_type}'은(는) 존재하지 않습니다. 사용 가능한 타입: [${knownTypes.join(", ")}]`,
909
+ };
910
+ }
911
+ // 2. Check domain doesn't already exist
912
+ const existCheck = await client.query("SELECT domain FROM semo.ontology WHERE domain = $1", [opts.domain]);
913
+ if (existCheck.rows.length > 0) {
914
+ return { success: false, error: `도메인 '${opts.domain}'은(는) 이미 등록되어 있습니다.` };
915
+ }
916
+ // 3. INSERT into ontology
917
+ await client.query(`INSERT INTO semo.ontology (domain, entity_type, description, service, tags, schema)
918
+ VALUES ($1, $2, $3, $4, $5, $6)`, [
919
+ opts.domain,
920
+ opts.entity_type,
921
+ opts.description || null,
922
+ opts.service || "_global",
923
+ opts.tags || [opts.entity_type],
924
+ JSON.stringify({}),
925
+ ]);
926
+ // 4. Create required KB entries
927
+ const createdEntries = [];
928
+ const initRequired = opts.init_required !== false;
929
+ if (initRequired) {
930
+ const schemaResult = await client.query(`SELECT scheme_key, scheme_description, COALESCE(key_type, 'singleton') as key_type, value_hint
931
+ FROM semo.kb_type_schema
932
+ WHERE type_key = $1 AND required = true
933
+ ORDER BY sort_order`, [opts.entity_type]);
934
+ for (const s of schemaResult.rows) {
935
+ if (s.key_type === "collection")
936
+ continue; // collection은 sub_key가 필요하므로 스킵
937
+ const placeholder = s.value_hint
938
+ ? `(미입력 — hint: ${s.value_hint})`
939
+ : `(미입력)`;
940
+ const text = `${s.scheme_key}: ${placeholder}`;
941
+ const embedding = await generateEmbedding(text);
942
+ const embeddingStr = embedding ? `[${embedding.join(",")}]` : null;
943
+ try {
944
+ await client.query(`INSERT INTO semo.knowledge_base (domain, key, sub_key, content, metadata, created_by, embedding)
945
+ VALUES ($1, $2, '', $3, '{}', 'semo-cli:onto-register', $4::vector)
946
+ ON CONFLICT (domain, key, sub_key) DO NOTHING`, [opts.domain, s.scheme_key, placeholder, embeddingStr]);
947
+ createdEntries.push({ key: s.scheme_key, sub_key: "" });
948
+ }
949
+ catch {
950
+ // 개별 entry 실패는 무시 — 도메인 등록 자체는 성공
951
+ }
952
+ }
953
+ }
954
+ return { success: true, created_entries: createdEntries };
955
+ }
956
+ catch (err) {
957
+ return { success: false, error: String(err) };
958
+ }
959
+ finally {
960
+ client.release();
961
+ }
962
+ }
889
963
  /**
890
964
  * Write ontology schemas to local cache
891
965
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-semicolon/semo-cli",
3
- "version": "4.7.3",
3
+ "version": "4.7.4",
4
4
  "description": "SEMO CLI - AI Agent Orchestration Framework Installer",
5
5
  "main": "dist/index.js",
6
6
  "bin": {