refactor(plugin): extract no-reply child process lifecycle module
This commit is contained in:
51
plugin/core/no-reply-process.ts
Normal file
51
plugin/core/no-reply-process.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { spawn, type ChildProcess } from "node:child_process";
|
||||||
|
|
||||||
|
let noReplyProcess: ChildProcess | null = null;
|
||||||
|
|
||||||
|
export function startNoReplyApi(
|
||||||
|
logger: { info: (m: string) => void; warn: (m: string) => void },
|
||||||
|
pluginDir: string,
|
||||||
|
port = 8787,
|
||||||
|
): void {
|
||||||
|
logger.info(`dirigent: startNoReplyApi called, pluginDir=${pluginDir}`);
|
||||||
|
|
||||||
|
if (noReplyProcess) {
|
||||||
|
logger.info("dirigent: no-reply API already running, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverPath = path.resolve(pluginDir, "..", "no-reply-api", "server.mjs");
|
||||||
|
logger.info(`dirigent: resolved serverPath=${serverPath}`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(serverPath)) {
|
||||||
|
logger.warn(`dirigent: no-reply API server not found at ${serverPath}, skipping`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("dirigent: no-reply API server found, spawning process...");
|
||||||
|
|
||||||
|
noReplyProcess = spawn(process.execPath, [serverPath], {
|
||||||
|
env: { ...process.env, PORT: String(port) },
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
detached: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
noReplyProcess.stdout?.on("data", (d: Buffer) => logger.info(`dirigent: no-reply-api: ${d.toString().trim()}`));
|
||||||
|
noReplyProcess.stderr?.on("data", (d: Buffer) => logger.warn(`dirigent: no-reply-api: ${d.toString().trim()}`));
|
||||||
|
|
||||||
|
noReplyProcess.on("exit", (code, signal) => {
|
||||||
|
logger.info(`dirigent: no-reply API exited (code=${code}, signal=${signal})`);
|
||||||
|
noReplyProcess = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`dirigent: no-reply API started (pid=${noReplyProcess.pid}, port=${port})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopNoReplyApi(logger: { info: (m: string) => void }): void {
|
||||||
|
if (!noReplyProcess) return;
|
||||||
|
logger.info("dirigent: stopping no-reply API");
|
||||||
|
noReplyProcess.kill("SIGTERM");
|
||||||
|
noReplyProcess = null;
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { spawn, type ChildProcess } from "node:child_process";
|
|
||||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||||
import type { Decision, DirigentConfig } from "./rules.js";
|
import type { Decision, DirigentConfig } from "./rules.js";
|
||||||
import { startModeratorPresence, stopModeratorPresence } from "./moderator-presence.js";
|
import { startModeratorPresence, stopModeratorPresence } from "./moderator-presence.js";
|
||||||
@@ -18,51 +17,7 @@ import { extractMentionedUserIds, getModeratorUserId } from "./core/mentions.js"
|
|||||||
import { ensureTurnOrder, recordChannelAccount } from "./core/turn-bootstrap.js";
|
import { ensureTurnOrder, recordChannelAccount } from "./core/turn-bootstrap.js";
|
||||||
import { debugCtxSummary, pickDefined, shouldDebugLog } from "./core/utils.js";
|
import { debugCtxSummary, pickDefined, shouldDebugLog } from "./core/utils.js";
|
||||||
import { resolveDiscordUserId, sendModeratorMessage } from "./core/moderator-discord.js";
|
import { resolveDiscordUserId, sendModeratorMessage } from "./core/moderator-discord.js";
|
||||||
|
import { startNoReplyApi, stopNoReplyApi } from "./core/no-reply-process.js";
|
||||||
// ── No-Reply API child process lifecycle ──────────────────────────────
|
|
||||||
let noReplyProcess: ChildProcess | null = null;
|
|
||||||
|
|
||||||
function startNoReplyApi(logger: { info: (m: string) => void; warn: (m: string) => void }, pluginDir: string, port = 8787): void {
|
|
||||||
logger.info(`dirigent: startNoReplyApi called, pluginDir=${pluginDir}`);
|
|
||||||
|
|
||||||
if (noReplyProcess) {
|
|
||||||
logger.info("dirigent: no-reply API already running, skipping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverPath = path.resolve(pluginDir, "..", "no-reply-api", "server.mjs");
|
|
||||||
logger.info(`dirigent: resolved serverPath=${serverPath}`);
|
|
||||||
|
|
||||||
if (!fs.existsSync(serverPath)) {
|
|
||||||
logger.warn(`dirigent: no-reply API server not found at ${serverPath}, skipping`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(`dirigent: no-reply API server found, spawning process...`);
|
|
||||||
|
|
||||||
noReplyProcess = spawn(process.execPath, [serverPath], {
|
|
||||||
env: { ...process.env, PORT: String(port) },
|
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
|
||||||
detached: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
noReplyProcess.stdout?.on("data", (d: Buffer) => logger.info(`dirigent: no-reply-api: ${d.toString().trim()}`));
|
|
||||||
noReplyProcess.stderr?.on("data", (d: Buffer) => logger.warn(`dirigent: no-reply-api: ${d.toString().trim()}`));
|
|
||||||
|
|
||||||
noReplyProcess.on("exit", (code, signal) => {
|
|
||||||
logger.info(`dirigent: no-reply API exited (code=${code}, signal=${signal})`);
|
|
||||||
noReplyProcess = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.info(`dirigent: no-reply API started (pid=${noReplyProcess.pid}, port=${port})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopNoReplyApi(logger: { info: (m: string) => void }): void {
|
|
||||||
if (!noReplyProcess) return;
|
|
||||||
logger.info("dirigent: stopping no-reply API");
|
|
||||||
noReplyProcess.kill("SIGTERM");
|
|
||||||
noReplyProcess = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DecisionRecord = {
|
type DecisionRecord = {
|
||||||
decision: Decision;
|
decision: Decision;
|
||||||
|
|||||||
Reference in New Issue
Block a user