@team-semicolon/semo-cli 4.0.0 → 4.0.2

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.
@@ -345,4 +345,38 @@ function registerBotsCommands(program) {
345
345
  await (0, database_1.closeConnection)();
346
346
  }
347
347
  });
348
+ // ── semo bots set-status ─────────────────────────────────────
349
+ botsCmd
350
+ .command("set-status <bot_id> <status>")
351
+ .description("봇 온라인 상태 수동 설정 (online|offline)")
352
+ .action(async (botId, status) => {
353
+ if (status !== "online" && status !== "offline") {
354
+ console.log(chalk_1.default.red("❌ status는 'online' 또는 'offline'만 가능합니다."));
355
+ process.exit(1);
356
+ }
357
+ const connected = await (0, database_1.isDbConnected)();
358
+ if (!connected) {
359
+ console.log(chalk_1.default.red("❌ DB 연결 실패"));
360
+ await (0, database_1.closeConnection)();
361
+ process.exit(1);
362
+ }
363
+ try {
364
+ const pool = (0, database_1.getPool)();
365
+ const client = await pool.connect();
366
+ await client.query(`INSERT INTO semo.bot_status (bot_id, status, synced_at)
367
+ VALUES ($1, $2, NOW())
368
+ ON CONFLICT (bot_id) DO UPDATE SET
369
+ status = EXCLUDED.status,
370
+ synced_at = NOW()`, [botId, status]);
371
+ client.release();
372
+ console.log(chalk_1.default.green(`✔ ${botId} → ${status}`));
373
+ }
374
+ catch (err) {
375
+ console.log(chalk_1.default.red(`❌ 실패: ${err}`));
376
+ process.exit(1);
377
+ }
378
+ finally {
379
+ await (0, database_1.closeConnection)();
380
+ }
381
+ });
348
382
  }
package/dist/database.js CHANGED
@@ -31,23 +31,25 @@ function buildDbConfig() {
31
31
  idleTimeoutMillis: 30000,
32
32
  };
33
33
  }
34
+ if (!process.env.SEMO_DB_HOST && !process.env.DATABASE_URL) {
35
+ throw new Error("DB 연결 정보가 없습니다. DATABASE_URL 또는 SEMO_DB_HOST 환경변수를 설정하세요.");
36
+ }
34
37
  return {
35
- host: process.env.SEMO_DB_HOST || "3.38.162.21",
38
+ host: process.env.SEMO_DB_HOST,
36
39
  port: parseInt(process.env.SEMO_DB_PORT || "5432"),
37
40
  user: process.env.SEMO_DB_USER || "app",
38
- password: process.env.SEMO_DB_PASSWORD || "ProductionPassword2024!@#",
41
+ password: process.env.SEMO_DB_PASSWORD,
39
42
  database: process.env.SEMO_DB_NAME || "appdb",
40
43
  ssl: false,
41
44
  connectionTimeoutMillis: 5000,
42
45
  idleTimeoutMillis: 30000,
43
46
  };
44
47
  }
45
- const DB_CONFIG = buildDbConfig();
46
- // PostgreSQL Pool (싱글톤)
48
+ // PostgreSQL Pool (싱글톤) — 최초 getPool() 호출 시점에 config 평가
47
49
  let pool = null;
48
50
  function getPool() {
49
51
  if (!pool) {
50
- pool = new pg_1.Pool(DB_CONFIG);
52
+ pool = new pg_1.Pool(buildDbConfig());
51
53
  }
52
54
  return pool;
53
55
  }
package/dist/index.js CHANGED
@@ -2644,14 +2644,14 @@ kbCmd
2644
2644
  });
2645
2645
  kbCmd
2646
2646
  .command("embed")
2647
- .description("기존 KB 항목에 임베딩 벡터 생성 (VOYAGE_API_KEY 필요)")
2647
+ .description("기존 KB 항목에 임베딩 벡터 생성 (OPENAI_API_KEY 필요)")
2648
2648
  .option("--bot <name>", "봇 KB도 임베딩", detectBotId())
2649
2649
  .option("--domain <name>", "도메인 필터")
2650
2650
  .option("--force", "이미 임베딩된 항목도 재생성")
2651
2651
  .action(async (options) => {
2652
- if (!process.env.VOYAGE_API_KEY) {
2653
- console.log(chalk_1.default.red("❌ VOYAGE_API_KEY 환경변수가 설정되지 않았습니다."));
2654
- console.log(chalk_1.default.gray(" export VOYAGE_API_KEY='pa-...'"));
2652
+ if (!process.env.OPENAI_API_KEY) {
2653
+ console.log(chalk_1.default.red("❌ OPENAI_API_KEY 환경변수가 설정되지 않았습니다."));
2654
+ console.log(chalk_1.default.gray(" export OPENAI_API_KEY='sk-...'"));
2655
2655
  process.exit(1);
2656
2656
  }
2657
2657
  const spinner = (0, ora_1.default)("임베딩 대상 조회 중...").start();
package/dist/kb.d.ts CHANGED
@@ -9,12 +9,12 @@
9
9
  */
10
10
  import { Pool } from "pg";
11
11
  /**
12
- * Generate embedding vector for text using OpenAI API
12
+ * Generate embedding vector for text using OpenAI Embeddings API
13
13
  * Requires OPENAI_API_KEY environment variable
14
14
  */
15
15
  export declare function generateEmbedding(text: string): Promise<number[] | null>;
16
16
  /**
17
- * Generate embeddings for multiple texts (batched)
17
+ * Generate embeddings for multiple texts (OpenAI는 단건 처리, 순차 호출)
18
18
  */
19
19
  export declare function generateEmbeddings(texts: string[]): Promise<(number[] | null)[]>;
20
20
  export interface KBEntry {
package/dist/kb.js CHANGED
@@ -59,18 +59,18 @@ const path = __importStar(require("path"));
59
59
  // ============================================================
60
60
  // Embedding
61
61
  // ============================================================
62
- const EMBEDDING_MODEL = "voyage-3";
63
- const EMBEDDING_DIMENSIONS = 1024;
62
+ const EMBEDDING_MODEL = "text-embedding-3-small";
63
+ const EMBEDDING_DIMENSIONS = 1024; // DB vector(1024) 유지 — OpenAI dimensions 파라미터로 축소
64
64
  /**
65
- * Generate embedding vector for text using OpenAI API
65
+ * Generate embedding vector for text using OpenAI Embeddings API
66
66
  * Requires OPENAI_API_KEY environment variable
67
67
  */
68
68
  async function generateEmbedding(text) {
69
- const apiKey = process.env.VOYAGE_API_KEY;
69
+ const apiKey = process.env.OPENAI_API_KEY;
70
70
  if (!apiKey)
71
71
  return null;
72
72
  try {
73
- const response = await fetch("https://api.voyageai.com/v1/embeddings", {
73
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
74
74
  method: "POST",
75
75
  headers: {
76
76
  "Authorization": `Bearer ${apiKey}`,
@@ -78,7 +78,7 @@ async function generateEmbedding(text) {
78
78
  },
79
79
  body: JSON.stringify({
80
80
  model: EMBEDDING_MODEL,
81
- input: text.substring(0, 8000), // truncate to avoid token limit
81
+ input: text.substring(0, 8000),
82
82
  dimensions: EMBEDDING_DIMENSIONS,
83
83
  }),
84
84
  });
@@ -96,14 +96,14 @@ async function generateEmbedding(text) {
96
96
  }
97
97
  }
98
98
  /**
99
- * Generate embeddings for multiple texts (batched)
99
+ * Generate embeddings for multiple texts (OpenAI는 단건 처리, 순차 호출)
100
100
  */
101
101
  async function generateEmbeddings(texts) {
102
- const apiKey = process.env.VOYAGE_API_KEY;
102
+ const apiKey = process.env.OPENAI_API_KEY;
103
103
  if (!apiKey)
104
104
  return texts.map(() => null);
105
105
  try {
106
- const response = await fetch("https://api.voyageai.com/v1/embeddings", {
106
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
107
107
  method: "POST",
108
108
  headers: {
109
109
  "Authorization": `Bearer ${apiKey}`,
@@ -111,8 +111,8 @@ async function generateEmbeddings(texts) {
111
111
  },
112
112
  body: JSON.stringify({
113
113
  model: EMBEDDING_MODEL,
114
- input: texts.map(t => t.substring(0, 16000)),
115
- output_dimension: EMBEDDING_DIMENSIONS,
114
+ input: texts.map(t => t.substring(0, 8000)),
115
+ dimensions: EMBEDDING_DIMENSIONS,
116
116
  }),
117
117
  });
118
118
  if (!response.ok)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-semicolon/semo-cli",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "SEMO CLI - AI Agent Orchestration Framework Installer",
5
5
  "main": "dist/index.js",
6
6
  "bin": {