fix: restore gateway watch boot path

This commit is contained in:
Peter Steinberger 2026-04-04 01:09:14 +01:00
parent fe72474153
commit 5bea93fd63
No known key found for this signature in database
6 changed files with 93 additions and 8 deletions

View File

@ -82,7 +82,7 @@ export async function runWatchMain(params = {}) {
env: childEnv,
stdio: "inherit",
});
watchProcess.on("exit", () => {
watchProcess.on("exit", (exitCode, exitSignal) => {
watchProcess = null;
if (shuttingDown) {
return;
@ -90,7 +90,9 @@ export async function runWatchMain(params = {}) {
if (restartRequested) {
restartRequested = false;
startRunner();
return;
}
settle(exitSignal ? 1 : (exitCode ?? 1));
});
};

View File

@ -127,6 +127,25 @@ describe("watch-node script", () => {
expect(fakeProcess.listenerCount("SIGTERM")).toBe(0);
});
it("returns the child exit code when the runner exits on its own", async () => {
const { child, spawn, watcher, createWatcher, fakeProcess } = createWatchHarness();
const runPromise = runWatchMain({
args: ["gateway", "--force", "--help"],
createWatcher,
process: fakeProcess,
spawn,
});
child.emit("exit", 0, null);
const exitCode = await runPromise;
expect(exitCode).toBe(0);
expect(watcher.close).toHaveBeenCalledTimes(1);
expect(fakeProcess.listenerCount("SIGINT")).toBe(0);
expect(fakeProcess.listenerCount("SIGTERM")).toBe(0);
});
it("ignores test-only changes and restarts on non-test source changes", async () => {
const childA = Object.assign(new EventEmitter(), {
kill: vi.fn(function () {

View File

@ -168,6 +168,20 @@ describe("resolveBundledPluginsDir", () => {
expectedRelativeDir: path.join("dist", "extensions"),
},
],
[
"prefers built dist/extensions in a git checkout outside vitest",
{
prefix: "openclaw-bundled-dir-git-built-",
hasExtensions: true,
hasSrc: true,
hasDistRuntimeExtensions: true,
hasDistExtensions: true,
hasGitCheckout: true,
},
{
expectedRelativeDir: path.join("dist-runtime", "extensions"),
},
],
[
"prefers source extensions under vitest to avoid stale staged plugins",
{
@ -182,13 +196,11 @@ describe("resolveBundledPluginsDir", () => {
},
],
[
"prefers source extensions in a git checkout even without vitest env",
"falls back to source extensions in a git checkout when built trees are missing",
{
prefix: "openclaw-bundled-dir-git-",
hasExtensions: true,
hasSrc: true,
hasDistRuntimeExtensions: true,
hasDistExtensions: true,
hasGitCheckout: true,
},
{

View File

@ -31,10 +31,7 @@ function resolveBundledDirFromPackageRoot(
): string | undefined {
const sourceExtensionsDir = path.join(packageRoot, "extensions");
const builtExtensionsDir = path.join(packageRoot, "dist", "extensions");
if (
(preferSourceCheckout || isSourceCheckoutRoot(packageRoot)) &&
fs.existsSync(sourceExtensionsDir)
) {
if (preferSourceCheckout && fs.existsSync(sourceExtensionsDir)) {
return sourceExtensionsDir;
}
// Local source checkouts stage a runtime-complete bundled plugin tree under
@ -47,6 +44,9 @@ function resolveBundledDirFromPackageRoot(
if (fs.existsSync(builtExtensionsDir)) {
return builtExtensionsDir;
}
if (isSourceCheckoutRoot(packageRoot) && fs.existsSync(sourceExtensionsDir)) {
return sourceExtensionsDir;
}
return undefined;
}

View File

@ -385,6 +385,43 @@ describe("discoverOpenClawPlugins", () => {
expectCandidateOrder(candidates, ["opik-openclaw"]);
});
it("skips dependency and build directories while scanning workspace roots", () => {
const stateDir = makeTempDir();
const workspaceDir = path.join(stateDir, "workspace");
const workspacePluginDir = path.join(workspaceDir, "packages", "workspace-plugin");
const nestedNodeModulesDir = path.join(workspaceDir, "node_modules", "openclaw");
const nestedDistDir = path.join(workspaceDir, "dist", "extensions", "diffs");
mkdirSafe(path.join(workspacePluginDir, "src"));
mkdirSafe(path.join(nestedNodeModulesDir, "src"));
mkdirSafe(nestedDistDir);
createPackagePluginWithEntry({
packageDir: workspacePluginDir,
packageName: "@openclaw/workspace-plugin",
pluginId: "workspace-plugin",
});
createPackagePluginWithEntry({
packageDir: nestedNodeModulesDir,
packageName: "openclaw",
pluginId: "node-modules-copy",
});
writePluginManifest({ pluginDir: nestedDistDir, id: "dist-copy" });
fs.writeFileSync(
path.join(nestedDistDir, "index.js"),
"module.exports = { id: 'dist-copy', register() {} };",
"utf-8",
);
const { candidates } = discoverOpenClawPlugins({
workspaceDir,
env: buildDiscoveryEnv(stateDir),
});
expectCandidateOrder(candidates, ["workspace-plugin"]);
});
it.each([
{
name: "derives unscoped ids for scoped packages",

View File

@ -17,6 +17,18 @@ import { resolvePluginCacheInputs, resolvePluginSourceRoots } from "./roots.js";
import type { PluginBundleFormat, PluginDiagnostic, PluginFormat, PluginOrigin } from "./types.js";
const EXTENSION_EXTS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]);
const SCANNED_DIRECTORY_IGNORE_NAMES = new Set([
".git",
".hg",
".svn",
".turbo",
".yarn",
".yarn-cache",
"build",
"coverage",
"dist",
"node_modules",
]);
export type PluginCandidate = {
idHint: string;
@ -292,6 +304,9 @@ function shouldIgnoreScannedDirectory(dirName: string): boolean {
if (!normalized) {
return true;
}
if (SCANNED_DIRECTORY_IGNORE_NAMES.has(normalized)) {
return true;
}
if (normalized.endsWith(".bak")) {
return true;
}