diff --git a/skills/qmd-brain/handler.ts b/skills/qmd-brain/handler.ts index f0dda98..c265988 100644 --- a/skills/qmd-brain/handler.ts +++ b/skills/qmd-brain/handler.ts @@ -7,10 +7,10 @@ * - embed_to_pg.py (Python venv at /home/selig/apps/qmd-pg/) */ -import { exec, execFile } from 'child_process'; +import { spawn, execFile } from 'child_process'; import { promisify } from 'util'; +import { openSync, closeSync } from 'fs'; -const execAsync = promisify(exec); const execFileAsync = promisify(execFile); const QMD_CMD = '/home/selig/.nvm/versions/node/v24.13.1/bin/qmd'; @@ -66,12 +66,28 @@ function formatPgResults(results: SearchResult[]): string { /** 觸發向量索引更新 */ async function triggerEmbed(): Promise { + const env = { ...process.env, HOME: '/home/selig' }; + const logPath = '/tmp/qmd-embed.log'; + try { - // 背景執行,不等待完成 - exec( - `${QMD_CMD} embed 2>&1 >> /tmp/qmd-embed.log & ${EMBED_PY_BIN} ${EMBED_PY_SCRIPT} embed 2>&1 >> /tmp/qmd-embed.log &`, - { env: { ...process.env, HOME: '/home/selig' } } - ); + const fdQmd = openSync(logPath, 'a'); + const qmdProc = spawn(QMD_CMD, ['embed'], { + env, + detached: true, + stdio: ['ignore', fdQmd, fdQmd], + }); + qmdProc.unref(); + closeSync(fdQmd); + + const fdPg = openSync(logPath, 'a'); + const pgProc = spawn(EMBED_PY_BIN, [EMBED_PY_SCRIPT, 'embed'], { + env, + detached: true, + stdio: ['ignore', fdPg, fdPg], + }); + pgProc.unref(); + closeSync(fdPg); + return '✅ 索引更新已在背景啟動,約需 1-5 分鐘完成。'; } catch (e: any) { return `❌ 索引啟動失敗: ${e.message}`;