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:
can1357
2026-04-07 22:08:57 +02:00
parent 3f60675662
commit 70fa7a9d25
5 changed files with 17 additions and 163 deletions
+2
View File
@@ -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;
}