refactor(natives): simplified native module loader and removed validation overhead
- Removed native binding validation function that checked required exports at load time. - Enhanced native module loader to check XDG_DATA_HOME environment variable before ~/.omp/natives fallback. - Removed dependency on @oh-my-pi/pi-utils from native module loader by inlining helper functions. - Migrated child process termination from waitForChildProcess utility to killTree native binding.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Chunk read formatting: `anchorStyle` (full / kind / bare), `read.anchorstyle` setting, and `chunked` flag on file display mode
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `waitForChildProcess` utility (child process termination now handled by native `killTree` from pi-natives)
|
||||
- `grep-chunk.md` (folded into unified grep template)
|
||||
- `startMacAppearanceObserver` export (use `MacAppearanceObserver.start()`)
|
||||
- `copyToClipboard` export from pi-natives
|
||||
|
||||
@@ -49,8 +49,8 @@ import {
|
||||
modelsAreEqual,
|
||||
parseRateLimitReason,
|
||||
} from "@oh-my-pi/pi-ai";
|
||||
import { MacOSPowerAssertion, type SearchDb } from "@oh-my-pi/pi-natives";
|
||||
import { abortableSleep, getAgentDbPath, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
||||
import { killTree, MacOSPowerAssertion, type SearchDb } from "@oh-my-pi/pi-natives";
|
||||
import { abortableSleep, getAgentDbPath, isEnoent, logger, setNativeKillTree } from "@oh-my-pi/pi-utils";
|
||||
import type { AsyncJob, AsyncJobManager } from "../async";
|
||||
import type { Rule } from "../capability/rule";
|
||||
import { MODEL_ROLE_IDS, type ModelRegistry } from "../config/model-registry";
|
||||
@@ -535,6 +535,8 @@ export class AgentSession {
|
||||
}
|
||||
|
||||
constructor(config: AgentSessionConfig) {
|
||||
setNativeKillTree(killTree);
|
||||
|
||||
this.agent = config.agent;
|
||||
this.sessionManager = config.sessionManager;
|
||||
this.settings = config.settings;
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import type { ChildProcess } from "node:child_process";
|
||||
|
||||
const EXIT_STDIO_GRACE_MS = 100;
|
||||
|
||||
/**
|
||||
* Wait for a child process to terminate without hanging on inherited stdio handles.
|
||||
*
|
||||
* Daemonized descendants can inherit the child's stdout/stderr pipe handles. In that
|
||||
* case the child emits `exit`, but `close` can hang forever even though the original
|
||||
* process is already gone. We wait briefly for stdio to end, then forcibly stop
|
||||
* tracking the inherited handles.
|
||||
*/
|
||||
export function waitForChildProcess(child: ChildProcess): Promise<number | null> {
|
||||
const { promise, resolve, reject } = Promise.withResolvers<number | null>();
|
||||
|
||||
let settled = false;
|
||||
let exited = false;
|
||||
let exitCode: number | null = null;
|
||||
let postExitTimer: NodeJS.Timeout | undefined;
|
||||
let stdoutEnded = child.stdout === null;
|
||||
let stderrEnded = child.stderr === null;
|
||||
|
||||
const cleanup = () => {
|
||||
if (postExitTimer) {
|
||||
clearTimeout(postExitTimer);
|
||||
postExitTimer = undefined;
|
||||
}
|
||||
child.removeListener("error", onError);
|
||||
child.removeListener("exit", onExit);
|
||||
child.removeListener("close", onClose);
|
||||
child.stdout?.removeListener("end", onStdoutEnd);
|
||||
child.stderr?.removeListener("end", onStderrEnd);
|
||||
};
|
||||
|
||||
const finalize = (code: number | null) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
child.stdout?.destroy();
|
||||
child.stderr?.destroy();
|
||||
resolve(code);
|
||||
};
|
||||
|
||||
const maybeFinalizeAfterExit = () => {
|
||||
if (!exited || settled) return;
|
||||
if (stdoutEnded && stderrEnded) {
|
||||
finalize(exitCode);
|
||||
}
|
||||
};
|
||||
|
||||
const onStdoutEnd = () => {
|
||||
stdoutEnded = true;
|
||||
maybeFinalizeAfterExit();
|
||||
};
|
||||
|
||||
const onStderrEnd = () => {
|
||||
stderrEnded = true;
|
||||
maybeFinalizeAfterExit();
|
||||
};
|
||||
|
||||
const onError = (err: Error) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
reject(err);
|
||||
};
|
||||
|
||||
const onExit = (code: number | null) => {
|
||||
exited = true;
|
||||
exitCode = code;
|
||||
maybeFinalizeAfterExit();
|
||||
if (!settled) {
|
||||
postExitTimer = setTimeout(() => finalize(code), EXIT_STDIO_GRACE_MS);
|
||||
}
|
||||
};
|
||||
|
||||
const onClose = (code: number | null) => {
|
||||
finalize(code);
|
||||
};
|
||||
|
||||
child.stdout?.once("end", onStdoutEnd);
|
||||
child.stderr?.once("end", onStderrEnd);
|
||||
child.once("error", onError);
|
||||
child.once("exit", onExit);
|
||||
child.once("close", onClose);
|
||||
|
||||
return promise;
|
||||
}
|
||||
Reference in New Issue
Block a user