mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-30 01:06:11 +00:00
scripts: split run-node rebuild and restart triggers
This commit is contained in:
@@ -103,7 +103,7 @@ pnpm build
|
||||
|
||||
pnpm openclaw onboard --install-daemon
|
||||
|
||||
# Dev loop (auto-reload on TS changes)
|
||||
# Dev loop (auto-reload on source/config changes)
|
||||
pnpm gateway:watch
|
||||
```
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ node scripts/watch-node.mjs gateway --force
|
||||
|
||||
The watcher restarts on build-relevant files under `src/`, extension source files,
|
||||
extension `package.json` and `openclaw.plugin.json` metadata, `tsconfig.json`,
|
||||
`package.json`, and `tsdown.config.ts`.
|
||||
`package.json`, and `tsdown.config.ts`. Extension metadata changes restart the
|
||||
gateway without forcing a `tsdown` rebuild; source and config changes still
|
||||
rebuild `dist` first.
|
||||
|
||||
Add any gateway CLI flags after `gateway:watch` and they will be passed through on
|
||||
each restart.
|
||||
|
||||
@@ -96,7 +96,8 @@ pnpm install
|
||||
pnpm gateway:watch
|
||||
```
|
||||
|
||||
`gateway:watch` runs the gateway in watch mode and reloads on TypeScript changes.
|
||||
`gateway:watch` runs the gateway in watch mode and reloads on relevant source,
|
||||
config, and bundled-plugin metadata changes.
|
||||
|
||||
### 2) Point the macOS app at your running Gateway
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const runNodeWatchedPaths: string[];
|
||||
export function isBuildRelevantRunNodePath(repoPath: string): boolean;
|
||||
export function isRestartRelevantRunNodePath(repoPath: string): boolean;
|
||||
|
||||
export function runNodeMain(params?: {
|
||||
spawn?: (
|
||||
|
||||
@@ -12,7 +12,7 @@ const runNodeSourceRoots = ["src", "extensions"];
|
||||
const runNodeConfigFiles = ["tsconfig.json", "package.json", "tsdown.config.ts"];
|
||||
export const runNodeWatchedPaths = [...runNodeSourceRoots, ...runNodeConfigFiles];
|
||||
const extensionSourceFilePattern = /\.(?:[cm]?[jt]sx?)$/;
|
||||
const extensionBuildMetadataFiles = new Set(["openclaw.plugin.json", "package.json"]);
|
||||
const extensionRestartMetadataFiles = new Set(["openclaw.plugin.json", "package.json"]);
|
||||
|
||||
const normalizePath = (filePath) => String(filePath ?? "").replaceAll("\\", "/");
|
||||
|
||||
@@ -25,11 +25,8 @@ const isIgnoredSourcePath = (relativePath) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isBuildRelevantExtensionPath = (relativePath) => {
|
||||
const isBuildRelevantSourcePath = (relativePath) => {
|
||||
const normalizedPath = normalizePath(relativePath);
|
||||
if (extensionBuildMetadataFiles.has(path.posix.basename(normalizedPath))) {
|
||||
return true;
|
||||
}
|
||||
return extensionSourceFilePattern.test(normalizedPath) && !isIgnoredSourcePath(normalizedPath);
|
||||
};
|
||||
|
||||
@@ -42,7 +39,29 @@ export const isBuildRelevantRunNodePath = (repoPath) => {
|
||||
return !isIgnoredSourcePath(normalizedPath.slice("src/".length));
|
||||
}
|
||||
if (normalizedPath.startsWith("extensions/")) {
|
||||
return isBuildRelevantExtensionPath(normalizedPath.slice("extensions/".length));
|
||||
return isBuildRelevantSourcePath(normalizedPath.slice("extensions/".length));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const isRestartRelevantExtensionPath = (relativePath) => {
|
||||
const normalizedPath = normalizePath(relativePath);
|
||||
if (extensionRestartMetadataFiles.has(path.posix.basename(normalizedPath))) {
|
||||
return true;
|
||||
}
|
||||
return isBuildRelevantSourcePath(normalizedPath);
|
||||
};
|
||||
|
||||
export const isRestartRelevantRunNodePath = (repoPath) => {
|
||||
const normalizedPath = normalizePath(repoPath).replace(/^\.\/+/, "");
|
||||
if (runNodeConfigFiles.includes(normalizedPath)) {
|
||||
return true;
|
||||
}
|
||||
if (normalizedPath.startsWith("src/")) {
|
||||
return !isIgnoredSourcePath(normalizedPath.slice("src/".length));
|
||||
}
|
||||
if (normalizedPath.startsWith("extensions/")) {
|
||||
return isRestartRelevantExtensionPath(normalizedPath.slice("extensions/".length));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import chokidar from "chokidar";
|
||||
import { isBuildRelevantRunNodePath, runNodeWatchedPaths } from "./run-node.mjs";
|
||||
import { isRestartRelevantRunNodePath, runNodeWatchedPaths } from "./run-node.mjs";
|
||||
|
||||
const WATCH_NODE_RUNNER = "scripts/run-node.mjs";
|
||||
const WATCH_RESTART_SIGNAL = "SIGTERM";
|
||||
@@ -25,7 +25,7 @@ const resolveRepoPath = (filePath, cwd) => {
|
||||
};
|
||||
|
||||
const isIgnoredWatchPath = (filePath, cwd) =>
|
||||
!isBuildRelevantRunNodePath(resolveRepoPath(filePath, cwd));
|
||||
!isRestartRelevantRunNodePath(resolveRepoPath(filePath, cwd));
|
||||
|
||||
export async function runWatchMain(params = {}) {
|
||||
const deps = {
|
||||
|
||||
@@ -220,7 +220,7 @@ describe("run-node script", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rebuilds when extension package metadata is newer than the build stamp", async () => {
|
||||
it("skips rebuilding when extension package metadata is newer than the build stamp", async () => {
|
||||
await withTempDir(async (tmp) => {
|
||||
const packagePath = path.join(tmp, "extensions", "demo", "package.json");
|
||||
const distEntryPath = path.join(tmp, "dist", "entry.js");
|
||||
@@ -273,10 +273,7 @@ describe("run-node script", () => {
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(spawnCalls).toEqual([
|
||||
expectedBuildSpawn(),
|
||||
[process.execPath, "openclaw.mjs", "status"],
|
||||
]);
|
||||
expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -343,7 +340,7 @@ describe("run-node script", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rebuilds for dirty extension manifests consumed by the build graph", async () => {
|
||||
it("skips rebuilding for dirty extension manifests that only affect runtime reload", async () => {
|
||||
await withTempDir(async (tmp) => {
|
||||
const srcPath = path.join(tmp, "src", "index.ts");
|
||||
const manifestPath = path.join(tmp, "extensions", "demo", "openclaw.plugin.json");
|
||||
@@ -402,10 +399,7 @@ describe("run-node script", () => {
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(spawnCalls).toEqual([
|
||||
expectedBuildSpawn(),
|
||||
[process.execPath, "openclaw.mjs", "status"],
|
||||
]);
|
||||
expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -132,13 +132,19 @@ describe("watch-node script", () => {
|
||||
}),
|
||||
});
|
||||
const childC = Object.assign(new EventEmitter(), {
|
||||
kill: vi.fn(function () {
|
||||
queueMicrotask(() => childC.emit("exit", 0, null));
|
||||
}),
|
||||
});
|
||||
const childD = Object.assign(new EventEmitter(), {
|
||||
kill: vi.fn(() => {}),
|
||||
});
|
||||
const spawn = vi
|
||||
.fn()
|
||||
.mockReturnValueOnce(childA)
|
||||
.mockReturnValueOnce(childB)
|
||||
.mockReturnValueOnce(childC);
|
||||
.mockReturnValueOnce(childC)
|
||||
.mockReturnValueOnce(childD);
|
||||
const watcher = Object.assign(new EventEmitter(), {
|
||||
close: vi.fn(async () => {}),
|
||||
});
|
||||
@@ -177,11 +183,16 @@ describe("watch-node script", () => {
|
||||
expect(childA.kill).toHaveBeenCalledWith("SIGTERM");
|
||||
expect(spawn).toHaveBeenCalledTimes(2);
|
||||
|
||||
watcher.emit("change", "src/infra/watch-node.ts");
|
||||
watcher.emit("change", "extensions/voice-call/package.json");
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
expect(childB.kill).toHaveBeenCalledWith("SIGTERM");
|
||||
expect(spawn).toHaveBeenCalledTimes(3);
|
||||
|
||||
watcher.emit("change", "src/infra/watch-node.ts");
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
expect(childC.kill).toHaveBeenCalledWith("SIGTERM");
|
||||
expect(spawn).toHaveBeenCalledTimes(4);
|
||||
|
||||
fakeProcess.emit("SIGINT");
|
||||
const exitCode = await runPromise;
|
||||
expect(exitCode).toBe(130);
|
||||
|
||||
Reference in New Issue
Block a user