

























@@ -308,6 +308,78 @@ describe("agentCliCommand", () => {
308308});
309309});
310310311+it("reads a UTF-8 message file for gateway dispatch", async () => {
312+await withTempStore(async ({ dir }) => {
313+const messageFile = path.join(dir, "task.md");
314+const messageBody = 'first line\n```json\n{"ok":true}\n```\nsecond line\n';
315+fs.writeFileSync(messageFile, `\uFEFF${messageBody}`, "utf8");
316+mockGatewaySuccessReply();
317+318+await agentCliCommand({ messageFile, sessionKey: "agent:main:incident-42" }, runtime);
319+320+expect(callGateway).toHaveBeenCalledTimes(1);
321+const request = requireRecord(requireFirstCallArg(callGateway, "gateway"), "gateway request");
322+const params = requireRecord(request.params, "gateway request params");
323+expect(params.message).toBe(messageBody);
324+});
325+});
326+327+it("reads a UTF-8 message file for local embedded dispatch", async () => {
328+await withTempStore(async ({ dir }) => {
329+const messageFile = path.join(dir, "task.md");
330+const messageBody = 'first line\n```json\n{"ok":true}\n```\nsecond line\n';
331+fs.writeFileSync(messageFile, `\uFEFF${messageBody}`, "utf8");
332+mockLocalAgentReply();
333+334+await agentCliCommand(
335+{ messageFile, sessionKey: "agent:main:incident-42", local: true },
336+runtime,
337+);
338+339+expect(callGateway).not.toHaveBeenCalled();
340+expect(agentCommand).toHaveBeenCalledTimes(1);
341+const opts = requireRecord(
342+requireFirstCallArg(agentCommand, "embedded agent"),
343+"embedded agent options",
344+);
345+expect(opts.message).toBe(messageBody);
346+expect(opts).not.toHaveProperty("messageFile");
347+});
348+});
349+350+it("rejects inline and file messages together", async () => {
351+await expect(
352+agentCliCommand(
353+{ message: "inline", messageFile: "task.md", sessionKey: "agent:main:incident-42" },
354+runtime,
355+),
356+).rejects.toThrow("Use either --message or --message-file, not both");
357+expect(callGateway).not.toHaveBeenCalled();
358+});
359+360+it("reports missing message files before dispatch", async () => {
361+await withTempStore(async ({ dir }) => {
362+const messageFile = path.join(dir, "missing.md");
363+364+await expect(
365+agentCliCommand({ messageFile, sessionKey: "agent:main:incident-42" }, runtime),
366+).rejects.toThrow("Message file not found");
367+expect(callGateway).not.toHaveBeenCalled();
368+});
369+});
370+371+it("rejects message files that are not valid UTF-8", async () => {
372+await withTempStore(async ({ dir }) => {
373+const messageFile = path.join(dir, "task.bin");
374+fs.writeFileSync(messageFile, Buffer.from([0xff]));
375+376+await expect(
377+agentCliCommand({ messageFile, sessionKey: "agent:main:incident-42" }, runtime),
378+).rejects.toThrow("Message file must be valid UTF-8");
379+expect(callGateway).not.toHaveBeenCalled();
380+});
381+});
382+311383it.each(["/new", "/RESET", "/reset check status"] as const)(
312384"uses backend admin authority for %s gateway commands",
313385async (message) => {
@@ -1694,6 +1766,27 @@ describe("agentCliCommand", () => {
16941766});
16951767});
169617681769+it("preserves inline message whitespace for local embedded runs", async () => {
1770+await withTempStore(async () => {
1771+mockLocalAgentReply();
1772+1773+await agentCliCommand(
1774+{
1775+message: " keep spaces ",
1776+to: "+1555",
1777+local: true,
1778+},
1779+runtime,
1780+);
1781+1782+const localOpts = requireRecord(
1783+requireFirstCallArg(agentCommand, "embedded agent"),
1784+"embedded agent options",
1785+);
1786+expect(localOpts.message).toBe(" keep spaces ");
1787+});
1788+});
1789+16971790it("passes explicit session keys to local embedded runs", async () => {
16981791await withTempStore(async () => {
16991792mockLocalAgentReply();
@@ -1817,6 +1910,26 @@ describe("agentCliCommand", () => {
18171910});
18181911}
181919121913+it("rejects /compact from --message-file before any gateway or embedded turn", async () => {
1914+await withTempStore(async ({ dir }) => {
1915+const messageFile = path.join(dir, "compact.md");
1916+fs.writeFileSync(messageFile, "/compact:Keep recent decisions.", "utf8");
1917+callGateway.mockRejectedValue(createGatewayTimeoutError());
1918+1919+await agentCliCommand(
1920+{ messageFile, sessionId: "locked-session", runId: "locked-run", timeout: "0" },
1921+runtime,
1922+);
1923+});
1924+1925+expect(callGateway).not.toHaveBeenCalled();
1926+expect(agentCommand).not.toHaveBeenCalled();
1927+expect(runtime.exit).toHaveBeenCalledWith(1);
1928+const errorMessages = mockMessages(runtime.error);
1929+expect(errorMessages.some((m) => m.includes("openclaw sessions compact"))).toBe(true);
1930+expect(errorMessages.some((m) => m.includes("EMBEDDED FALLBACK"))).toBe(false);
1931+});
1932+18201933it("does not mistake a /compacting-prefixed message for the /compact control command", async () => {
18211934await withTempStore(async () => {
18221935mockGatewaySuccessReply();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。