diff --git a/scripts/build-discord-activity-sdk.d.mts b/scripts/build-discord-activity-sdk.d.mts new file mode 100644 index 000000000000..0ef6c01ea904 --- /dev/null +++ b/scripts/build-discord-activity-sdk.d.mts @@ -0,0 +1,20 @@ +type DiscordActivitySdkBuild = (options: { + absWorkingDir: string; + bundle: boolean; + entryPoints: string[]; + format: string; + legalComments: string; + minify: boolean; + outfile: string; + platform: string; + target: string; + write: false; +}) => Promise<{ + outputFiles?: Array<{ text: string }>; +}>; + +/** Builds the browser SDK bundle and returns whether the generated asset changed. */ +export function buildDiscordActivitySdk(params?: { + build?: DiscordActivitySdkBuild; + outputPath?: string; +}): Promise; diff --git a/scripts/run-node-watch-paths.d.mts b/scripts/run-node-watch-paths.d.mts new file mode 100644 index 000000000000..aceec2963e3f --- /dev/null +++ b/scripts/run-node-watch-paths.d.mts @@ -0,0 +1,15 @@ +/** Source roots whose changes require the root dev build pipeline. */ +export const runNodeSourceRoots: string[]; +/** Root config files whose changes invalidate the dev build. */ +export const runNodeConfigFiles: string[]; +/** Combined watch list used by the run-node wrapper. */ +export const runNodeWatchedPaths: string[]; +/** Plugin metadata files that require a runtime restart even without source edits. */ +export const extensionRestartMetadataFiles: Set; + +/** Normalizes watch paths to repository-style POSIX separators. */ +export function normalizeRunNodePath(filePath: unknown): string; +/** Returns true when a repo path should trigger a dev rebuild. */ +export function isBuildRelevantRunNodePath(repoPath: unknown): boolean; +/** Returns true when a repo path should restart the running dev process. */ +export function isRestartRelevantRunNodePath(repoPath: unknown): boolean; diff --git a/test/scripts/bundled-plugin-assets.test.ts b/test/scripts/bundled-plugin-assets.test.ts index 7a565a532781..9480d2c93f78 100644 --- a/test/scripts/bundled-plugin-assets.test.ts +++ b/test/scripts/bundled-plugin-assets.test.ts @@ -1,8 +1,7 @@ // Bundled Plugin Assets tests cover bundled plugin assets script behavior. import fs from "node:fs"; -import os from "node:os"; import path from "node:path"; -import { describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { buildDiscordActivitySdk } from "../../scripts/build-discord-activity-sdk.mjs"; import { parseBundledPluginAssetArgs, @@ -12,64 +11,59 @@ import { isBuildRelevantRunNodePath, isRestartRelevantRunNodePath, } from "../../scripts/run-node-watch-paths.mjs"; +import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js"; + +const tempDirs = useAutoCleanupTempDirTracker(afterEach); async function withPluginAssetFixture(run: (rootDir: string) => Promise) { - const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-assets-")); - try { - fs.mkdirSync(path.join(rootDir, "extensions", "canvas"), { recursive: true }); - fs.writeFileSync( - path.join(rootDir, "extensions", "canvas", "package.json"), - JSON.stringify( - { - name: "@openclaw/canvas-plugin", - openclaw: { - assetScripts: { - build: "node scripts/bundle-a2ui.mjs", - copy: "node scripts/copy-a2ui.mjs", - }, + const rootDir = tempDirs.make("openclaw-plugin-assets-"); + fs.mkdirSync(path.join(rootDir, "extensions", "canvas"), { recursive: true }); + fs.writeFileSync( + path.join(rootDir, "extensions", "canvas", "package.json"), + JSON.stringify( + { + name: "@openclaw/canvas-plugin", + openclaw: { + assetScripts: { + build: "node scripts/bundle-a2ui.mjs", + copy: "node scripts/copy-a2ui.mjs", }, }, - null, - 2, - ), - ); - fs.writeFileSync( - path.join(rootDir, "extensions", "canvas", "openclaw.plugin.json"), - JSON.stringify({ id: "canvas" }, null, 2), - ); - await run(rootDir); - } finally { - fs.rmSync(rootDir, { force: true, recursive: true }); - } + }, + null, + 2, + ), + ); + fs.writeFileSync( + path.join(rootDir, "extensions", "canvas", "openclaw.plugin.json"), + JSON.stringify({ id: "canvas" }, null, 2), + ); + await run(rootDir); } describe("bundled plugin assets", () => { it("creates a missing Discord SDK bundle without rewriting it when unchanged", async () => { - const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-discord-sdk-")); + const rootDir = tempDirs.make("openclaw-discord-sdk-"); const outputPath = path.join(rootDir, "embedded-app-sdk.mjs"); const build = vi.fn(async () => ({ outputFiles: [{ text: "export const sdk = true;\n" }], })); - try { - await expect(buildDiscordActivitySdk({ build, outputPath })).resolves.toBe(true); - expect(fs.readFileSync(outputPath, "utf8")).toBe("export const sdk = true;\n"); + await expect(buildDiscordActivitySdk({ build, outputPath })).resolves.toBe(true); + expect(fs.readFileSync(outputPath, "utf8")).toBe("export const sdk = true;\n"); - const initialTime = new Date("2026-07-16T12:00:00.000Z"); - fs.utimesSync(outputPath, initialTime, initialTime); + const initialTime = new Date("2026-07-16T12:00:00.000Z"); + fs.utimesSync(outputPath, initialTime, initialTime); - await expect(buildDiscordActivitySdk({ build, outputPath })).resolves.toBe(false); - expect(fs.statSync(outputPath).mtimeMs).toBe(initialTime.getTime()); - expect(build).toHaveBeenCalledWith( - expect.objectContaining({ - absWorkingDir: path.join(process.cwd(), "extensions/discord"), - outfile: outputPath, - write: false, - }), - ); - } finally { - fs.rmSync(rootDir, { force: true, recursive: true }); - } + await expect(buildDiscordActivitySdk({ build, outputPath })).resolves.toBe(false); + expect(fs.statSync(outputPath).mtimeMs).toBe(initialTime.getTime()); + expect(build).toHaveBeenCalledWith( + expect.objectContaining({ + absWorkingDir: path.join(process.cwd(), "extensions/discord"), + outfile: outputPath, + write: false, + }), + ); }); it("discovers the Discord Embedded App SDK build hook", async () => {