| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- import fs from 'node:fs';
- import path from 'node:path';
- import { createRequire } from 'node:module';
- import { PACKAGE_ROOT } from './config-loader.mjs';
- const require = createRequire(import.meta.url);
- const { outputsRoot } = require(path.join(PACKAGE_ROOT, 'mcp', 'src', 'core', 'output-paths.js'));
- const SECRET_KEY = /(token|secret|private.?key|authorization|credential|password)/i;
- function redactState(value) {
- if (Array.isArray(value)) return value.map(redactState);
- if (!value || typeof value !== 'object') return value;
- const output = {};
- for (const [key, item] of Object.entries(value)) {
- if (SECRET_KEY.test(key)) continue;
- output[key] = redactState(item);
- }
- return output;
- }
- export function runtimeStatePath(customPath = '') {
- return customPath || path.join(outputsRoot(), 'runtime', 'qiwei-runtime.json');
- }
- export function runtimeStopRequestPath(customPath = '') {
- return runtimeStatePath(customPath).replace(/\.json$/i, '.stop.json');
- }
- export function readRuntimeState(customPath = '') {
- const filePath = runtimeStatePath(customPath);
- try {
- return JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, ''));
- } catch {
- return {};
- }
- }
- export function writeRuntimeState(state, customPath = '') {
- const filePath = runtimeStatePath(customPath);
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
- const safe = redactState({ ...state, updatedAt: new Date().toISOString() });
- const temporary = `${filePath}.${process.pid}.tmp`;
- fs.writeFileSync(temporary, `${JSON.stringify(safe, null, 2)}\n`, 'utf8');
- fs.renameSync(temporary, filePath);
- return safe;
- }
- export function isProcessAlive(pid) {
- const numericPid = Number(pid);
- if (!Number.isInteger(numericPid) || numericPid <= 0) return false;
- try {
- process.kill(numericPid, 0);
- return true;
- } catch {
- return false;
- }
- }
- export function assertRuntimeAvailable(customPath = '') {
- const current = readRuntimeState(customPath);
- if (current.pid && current.pid !== process.pid && current.status !== 'stopped' && isProcessAlive(current.pid)) {
- throw new Error(`Qiwei runtime is already running (pid=${current.pid}, mode=${current.mode || 'unknown'}).`);
- }
- return current;
- }
- export function readRuntimeStopRequest(customPath = '') {
- try {
- return JSON.parse(fs.readFileSync(runtimeStopRequestPath(customPath), 'utf8').replace(/^\uFEFF/, ''));
- } catch {
- return {};
- }
- }
- export function clearRuntimeStopRequest(customPath = '') {
- try { fs.unlinkSync(runtimeStopRequestPath(customPath)); } catch {}
- }
- export function requestRuntimeStop(customPath = '') {
- const current = readRuntimeState(customPath);
- const filePath = runtimeStopRequestPath(customPath);
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
- fs.writeFileSync(filePath, `${JSON.stringify({
- targetPid: Number(current.pid) || null,
- requestedAt: new Date().toISOString(),
- }, null, 2)}\n`, 'utf8');
- return { requested: true, pid: Number(current.pid) || null };
- }
- export function stopRuntimeProcess(customPath = '') {
- const current = readRuntimeState(customPath);
- if (!isProcessAlive(current.pid)) {
- writeRuntimeState({ ...current, status: 'stopped', stoppedAt: new Date().toISOString() }, customPath);
- return { stopped: false, reason: 'not-running', pid: current.pid || null };
- }
- return requestRuntimeStop(customPath);
- }
- export { redactState };
|