diff --git a/scripts/e2e/lib/live-plugin-tool/assertions.mjs b/scripts/e2e/lib/live-plugin-tool/assertions.mjs index 5e9338388259..49d5e36d7080 100644 --- a/scripts/e2e/lib/live-plugin-tool/assertions.mjs +++ b/scripts/e2e/lib/live-plugin-tool/assertions.mjs @@ -52,15 +52,16 @@ function agentErrorPath() { return process.env.OPENCLAW_LIVE_PLUGIN_TOOL_AGENT_ERROR_PATH || "/tmp/openclaw-agent.err"; } -function scanFileForNeedles(file, pendingNeedles) { +function scanFileForNeedles(file, needles) { + const pendingNeedles = new Set(needles); let stat; try { stat = fs.statSync(file); } catch { - return; + return pendingNeedles; } if (!stat.isFile() || stat.size <= 0 || pendingNeedles.size === 0) { - return; + return pendingNeedles; } const maxNeedleLength = Math.max(...Array.from(pendingNeedles, (needle) => needle.length)); @@ -88,6 +89,7 @@ function scanFileForNeedles(file, pendingNeedles) { } finally { fs.closeSync(fd); } + return pendingNeedles; } function scanSessionTranscripts(sessionsDir, needles) { @@ -105,7 +107,7 @@ function scanSessionTranscripts(sessionsDir, needles) { } const pendingDirs = [sessionsDir]; - while (pendingDirs.length > 0 && pendingNeedles.size > 0) { + while (pendingDirs.length > 0) { const dir = pendingDirs.pop(); const entries = fs .readdirSync(dir, { withFileTypes: true }) @@ -123,9 +125,9 @@ function scanSessionTranscripts(sessionsDir, needles) { if (checkedFiles.length < SESSION_FILE_LIST_LIMIT) { checkedFiles.push(path.relative(sessionsDir, entryPath)); } - scanFileForNeedles(entryPath, pendingNeedles); - if (pendingNeedles.size === 0) { - break; + if (scanFileForNeedles(entryPath, needles).size === 0) { + pendingNeedles.clear(); + return { checkedFiles, filesChecked, missingDir: false, pendingNeedles }; } } } diff --git a/test/scripts/live-plugin-tool-assertions.test.ts b/test/scripts/live-plugin-tool-assertions.test.ts index e4cd6b9b08c7..d042f4c88565 100644 --- a/test/scripts/live-plugin-tool-assertions.test.ts +++ b/test/scripts/live-plugin-tool-assertions.test.ts @@ -87,13 +87,11 @@ describe("live plugin tool assertions", () => { }); mkdirSync(sessionsDir, { recursive: true }); writeFileSync( - path.join(sessionsDir, "tool.jsonl"), - `${"x".repeat(64 * 1024 - "e2e_slug_".length)}e2e_slug_probe\n`, - "utf8", - ); - writeFileSync( - path.join(sessionsDir, "reply.jsonl"), - `${"x".repeat(64 * 1024 - "live-plugin-".length)}live-plugin-slug\n`, + path.join(sessionsDir, "session.jsonl"), + [ + `${"x".repeat(64 * 1024 - "e2e_slug_".length)}e2e_slug_probe`, + `${"x".repeat(64 * 1024 - "live-plugin-".length)}live-plugin-slug`, + ].join("\n"), "utf8", ); @@ -106,6 +104,28 @@ describe("live plugin tool assertions", () => { } }); + it("rejects split transcript evidence across unrelated files", () => { + const root = mkdtempSync(path.join(tmpdir(), "openclaw-live-plugin-tool-")); + const sessionsDir = path.join(root, "state", "agents", "main", "sessions"); + + try { + writeJson(path.join(root, "agent.json"), { + payloads: [{ text: "live-plugin-slug" }], + }); + mkdirSync(sessionsDir, { recursive: true }); + writeFileSync(path.join(sessionsDir, "tool.jsonl"), "e2e_slug_probe\n", "utf8"); + writeFileSync(path.join(sessionsDir, "reply.jsonl"), "live-plugin-slug\n", "utf8"); + + const result = runAssertion(root); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("session transcript did not show"); + expect(result.stderr).toContain("after checking 2 jsonl file(s)"); + } finally { + rmSync(root, { force: true, recursive: true }); + } + }); + it("bounds agent output diagnostics on missing reply slug", () => { const root = mkdtempSync(path.join(tmpdir(), "openclaw-live-plugin-tool-"));