From 4a62f4f13acbd4bbcbe768eea217d5ea60ac997b Mon Sep 17 00:00:00 2001 From: Chengjie Wang Date: Tue, 7 Jul 2026 18:18:15 +0800 Subject: [PATCH 1/2] fix(messaging): tolerate verbose npm metadata output Signed-off-by: Chengjie Wang --- .../applier/build/messaging-build-applier.mts | 4 ++ test/messaging-build-applier.test.ts | 68 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/lib/messaging/applier/build/messaging-build-applier.mts b/src/lib/messaging/applier/build/messaging-build-applier.mts index 67afb5e1b8e..7062defa4e2 100755 --- a/src/lib/messaging/applier/build/messaging-build-applier.mts +++ b/src/lib/messaging/applier/build/messaging-build-applier.mts @@ -138,6 +138,8 @@ export const OPENCLAW_MESSAGING_PLUGIN_ARCHIVE_PROVENANCE_POLICY = Object.freeze registryTarballUrl: "must-match-committed-url", } as const); +const NPM_METADATA_MAX_BUFFER = 16 * 1024 * 1024; + type HermesUvPackageInstall = { readonly spec: string; }; @@ -1160,6 +1162,7 @@ function npmViewString(packageSpec: string, field: string, env: Env): string { const result = spawnSync("npm", ["view", packageSpec, field], { encoding: "utf-8", env: env as NodeJS.ProcessEnv, + maxBuffer: NPM_METADATA_MAX_BUFFER, stdio: ["ignore", "pipe", "pipe"], }); if (result.error) throw result.error; @@ -1211,6 +1214,7 @@ function packNpmArchive( const result = spawnSync("npm", ["pack", packageSpec, "--pack-destination", rootDir, "--json"], { encoding: "utf-8", env: env as NodeJS.ProcessEnv, + maxBuffer: NPM_METADATA_MAX_BUFFER, stdio: ["ignore", "pipe", "pipe"], }); if (result.error) { diff --git a/test/messaging-build-applier.test.ts b/test/messaging-build-applier.test.ts index 0c4fad9a6cf..3fb9f64ddcd 100644 --- a/test/messaging-build-applier.test.ts +++ b/test/messaging-build-applier.test.ts @@ -614,6 +614,74 @@ describe("messaging-build-applier.mts: agent-install", () => { } }); + it("tolerates verbose npm metadata output when installing the Teams plugin", async () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-openclaw-teams-npm-buffer-")); + const tracePath = path.join(tmp, "openclaw.trace"); + fs.writeFileSync( + path.join(tmp, "npm"), + [ + "#!/usr/bin/env node", + "const fs = require('node:fs');", + "const path = require('node:path');", + "const [command, packageSpec, fieldOrFlag, destination] = process.argv.slice(2);", + "fs.appendFileSync(process.env.OPENCLAW_TRACE, `npm|${command}|${packageSpec}|${fieldOrFlag || ''}\\n`);", + "process.stderr.write('npm notice verbose teams metadata '.repeat(50000));", + "if (command === 'view' && packageSpec === '@openclaw/msteams@2026.6.10' && fieldOrFlag === 'dist.integrity') {", + " process.stdout.write(`${process.env.OPENCLAW_MSTEAMS_2026_6_10_INTEGRITY}\\n`);", + " process.exit(0);", + "}", + "if (command === 'view' && packageSpec === '@openclaw/msteams@2026.6.10' && fieldOrFlag === 'dist.tarball') {", + " process.stdout.write('https://registry.npmjs.org/@openclaw/msteams/-/msteams-2026.6.10.tgz\\n');", + " process.exit(0);", + "}", + "if (command === 'pack' && packageSpec === '@openclaw/msteams@2026.6.10') {", + " const packFile = 'msteams-2026.6.10.tgz';", + " fs.writeFileSync(path.join(destination, packFile), 'fake plugin tarball');", + " process.stdout.write(JSON.stringify([{ filename: packFile, integrity: process.env.OPENCLAW_MSTEAMS_2026_6_10_INTEGRITY }]) + '\\n');", + " process.exit(0);", + "}", + "process.exit(1);", + "", + ].join("\n"), + { mode: 0o755 }, + ); + fs.writeFileSync( + path.join(tmp, "openclaw"), + [ + "#!/bin/sh", + 'printf \'openclaw|%s|%s|%s|%s\\n\' "$1" "$2" "$3" "$4" >> "$OPENCLAW_TRACE"', + "exit 0", + "", + ].join("\n"), + { mode: 0o755 }, + ); + + try { + const env = await withLegacyMessagingPlanEnvDirect( + { + PATH: `${tmp}:${TEST_PATH}`, + OPENCLAW_TRACE: tracePath, + OPENCLAW_MSTEAMS_2026_6_10_INTEGRITY, + OPENCLAW_VERSION: "2026.6.10", + NEMOCLAW_MESSAGING_CHANNELS_B64: channelsB64(["teams"]), + NEMOCLAW_TEAMS_CONFIG_B64: teamsConfigB64(), + }, + "openclaw", + ); + const plan = readMessagingBuildPlanFromEnv(env, "openclaw"); + + expect(applyMessagingBuildPhase(plan, "agent-install", env)).toEqual([]); + const trace = fs.readFileSync(tracePath, "utf-8"); + expect(trace).toContain("npm|view|@openclaw/msteams@2026.6.10|dist.integrity"); + expect(trace).toContain("npm|view|@openclaw/msteams@2026.6.10|dist.tarball"); + expect(trace).toContain("npm|pack|@openclaw/msteams@2026.6.10|--pack-destination"); + expect(trace).toContain("openclaw|plugins|install|"); + expect(trace).toContain("msteams-2026.6.10.tgz|--pin"); + } finally { + fs.rmSync(tmp, { recursive: true, force: true }); + } + }); + it("fails closed before installing reviewed OpenClaw plugins absent from active channel manifests", () => { const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-openclaw-package-plan-")); const tracePath = path.join(tmp, "openclaw.trace"); From f62c5760d4cee0b76b2043aa090eda1b4f431520 Mon Sep 17 00:00:00 2001 From: Chengjie Wang Date: Tue, 7 Jul 2026 18:28:33 +0800 Subject: [PATCH 2/2] test(messaging): tag Teams npm buffer regression Signed-off-by: Chengjie Wang --- test/messaging-build-applier.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/messaging-build-applier.test.ts b/test/messaging-build-applier.test.ts index 3fb9f64ddcd..73bb841b6c8 100644 --- a/test/messaging-build-applier.test.ts +++ b/test/messaging-build-applier.test.ts @@ -614,7 +614,7 @@ describe("messaging-build-applier.mts: agent-install", () => { } }); - it("tolerates verbose npm metadata output when installing the Teams plugin", async () => { + it("tolerates verbose npm metadata output when installing the Teams plugin (#6389)", async () => { const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-openclaw-teams-npm-buffer-")); const tracePath = path.join(tmp, "openclaw.trace"); fs.writeFileSync(