惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
MongoDB | Blog
MongoDB | Blog
V
V2EX
博客园 - 【当耐特】
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
I
InfoQ
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
B
Blog
V
Visual Studio Blog
D
DataBreaches.Net
C
Check Point Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
F
Fortinet All Blogs

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: cover legacy runtime deps update recovery (#75288) ...
steipete · 2026-05-01 · via Recent Commits to openclaw:main

@@ -46,6 +46,26 @@ describe("stageBundledPluginRuntimeDeps", () => {

4646

return path.join(repoRoot, ".artifacts", "bundled-runtime-deps-stamps", `${pluginId}.json`);

4747

}

484849+

function legacyRuntimeDepsNodeModulesPath(

50+

repoRoot: string,

51+

stageKey = "fixture-plugin-1234567890abcdef",

52+

) {

53+

return path.join(repoRoot, ".local", "bundled-plugin-runtime-deps", stageKey, "node_modules");

54+

}

55+56+

function writeLegacyRuntimeDepsNodeModulesSymlink(params: {

57+

pluginDir: string;

58+

repoRoot: string;

59+

stageKey?: string;

60+

}) {

61+

const legacyNodeModulesDir = legacyRuntimeDepsNodeModulesPath(params.repoRoot, params.stageKey);

62+

const nodeModulesDir = path.join(params.pluginDir, "node_modules");

63+

fs.mkdirSync(legacyNodeModulesDir, { recursive: true });

64+

fs.writeFileSync(path.join(legacyNodeModulesDir, "legacy.js"), "module.exports = 0;\n", "utf8");

65+

fs.symlinkSync(legacyNodeModulesDir, nodeModulesDir);

66+

return { legacyNodeModulesDir, nodeModulesDir };

67+

}

68+4969

it("pins fallback install specs to exact installed versions", () => {

5070

const { repoRoot } = createBundledPluginFixture({

5171

packageJson: {

@@ -718,32 +738,81 @@ describe("stageBundledPluginRuntimeDeps", () => {

718738

},

719739

});

720740

const directDir = path.join(repoRoot, "node_modules", "direct");

721-

const legacyNodeModulesDir = path.join(

741+

fs.mkdirSync(directDir, { recursive: true });

742+

fs.writeFileSync(

743+

path.join(directDir, "package.json"),

744+

'{ "name": "direct", "version": "1.0.0" }\n',

745+

"utf8",

746+

);

747+

fs.writeFileSync(path.join(directDir, "index.js"), "module.exports = 'direct';\n", "utf8");

748+

const { legacyNodeModulesDir, nodeModulesDir } = writeLegacyRuntimeDepsNodeModulesSymlink({

749+

pluginDir,

750+

repoRoot,

751+

});

752+753+

stageBundledPluginRuntimeDeps({ cwd: repoRoot });

754+755+

expect(fs.lstatSync(nodeModulesDir).isSymbolicLink()).toBe(false);

756+

expect(fs.readFileSync(path.join(nodeModulesDir, "direct", "index.js"), "utf8")).toBe(

757+

"module.exports = 'direct';\n",

758+

);

759+

expect(fs.existsSync(path.join(legacyNodeModulesDir, "legacy.js"))).toBe(true);

760+

});

761+762+

it("removes legacy OpenClaw-owned symlinked plugin node_modules when deps converge to empty", () => {

763+

const { pluginDir, repoRoot } = createBundledPluginFixture({

764+

packageJson: {

765+

name: "@openclaw/fixture-plugin",

766+

version: "1.0.0",

767+

optionalDependencies: { optional: "1.0.0" },

768+

openclaw: { bundle: { stageRuntimeDependencies: true } },

769+

},

770+

});

771+

const rootNodeModulesDir = path.join(repoRoot, "node_modules");

772+

fs.mkdirSync(rootNodeModulesDir, { recursive: true });

773+

const { legacyNodeModulesDir, nodeModulesDir } = writeLegacyRuntimeDepsNodeModulesSymlink({

774+

pluginDir,

775+

repoRoot,

776+

});

777+778+

stageBundledPluginRuntimeDeps({ cwd: repoRoot });

779+780+

expect(fs.existsSync(nodeModulesDir)).toBe(false);

781+

expect(fs.existsSync(path.join(legacyNodeModulesDir, "legacy.js"))).toBe(true);

782+

});

783+784+

it("refuses nested symlink targets under the legacy runtime deps root", () => {

785+

const { pluginDir, repoRoot } = createBundledPluginFixture({

786+

packageJson: {

787+

name: "@openclaw/fixture-plugin",

788+

version: "1.0.0",

789+

dependencies: { direct: "1.0.0" },

790+

openclaw: { bundle: { stageRuntimeDependencies: true } },

791+

},

792+

});

793+

const directDir = path.join(repoRoot, "node_modules", "direct");

794+

const nestedLegacyNodeModulesDir = path.join(

722795

repoRoot,

723796

".local",

724797

"bundled-plugin-runtime-deps",

725798

"fixture-plugin-1234567890abcdef",

799+

"nested",

726800

"node_modules",

727801

);

728802

const nodeModulesDir = path.join(pluginDir, "node_modules");

729803

fs.mkdirSync(directDir, { recursive: true });

730-

fs.mkdirSync(legacyNodeModulesDir, { recursive: true });

804+

fs.mkdirSync(nestedLegacyNodeModulesDir, { recursive: true });

731805

fs.writeFileSync(

732806

path.join(directDir, "package.json"),

733807

'{ "name": "direct", "version": "1.0.0" }\n',

734808

"utf8",

735809

);

736810

fs.writeFileSync(path.join(directDir, "index.js"), "module.exports = 'direct';\n", "utf8");

737-

fs.writeFileSync(path.join(legacyNodeModulesDir, "legacy.js"), "module.exports = 0;\n", "utf8");

738-

fs.symlinkSync(legacyNodeModulesDir, nodeModulesDir);

811+

fs.symlinkSync(nestedLegacyNodeModulesDir, nodeModulesDir);

739812740-

stageBundledPluginRuntimeDeps({ cwd: repoRoot });

741-742-

expect(fs.lstatSync(nodeModulesDir).isSymbolicLink()).toBe(false);

743-

expect(fs.readFileSync(path.join(nodeModulesDir, "direct", "index.js"), "utf8")).toBe(

744-

"module.exports = 'direct';\n",

813+

expect(() => stageBundledPluginRuntimeDeps({ cwd: repoRoot })).toThrow(

814+

/refusing to replace runtime deps via symlinked path/u,

745815

);

746-

expect(fs.existsSync(path.join(legacyNodeModulesDir, "legacy.js"))).toBe(true);

747816

});

748817749818

it("refuses to write a runtime deps stamp through a symlink", () => {