Skip to content

Commit 6246b6e

Browse files
author
OpenClaw Assistant
committed
Fix bash bang detection for markdown images
1 parent 0ae5876 commit 6246b6e

3 files changed

Lines changed: 52 additions & 2 deletions

File tree

src/auto-reply/reply/bash-command.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ function formatOutputBlock(text: string) {
6161

6262
function parseBashRequest(raw: string): BashRequest | null {
6363
const trimmed = raw.trimStart();
64+
if (trimmed.startsWith("![")) {
65+
return null;
66+
}
6467
let restSource = "";
6568
if (trimmed.toLowerCase().startsWith("/bash")) {
6669
const match = trimmed.match(/^\/bash(?:\s*:\s*|\s+|$)([\s\S]*)$/i);

src/auto-reply/reply/commands-bash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const handleBashCommand: CommandHandler = async (params, allowTextCommand
99
const { command } = params;
1010
const bashSlashRequested =
1111
command.commandBodyNormalized === "/bash" || command.commandBodyNormalized.startsWith("/bash ");
12-
const bashBangRequested = command.commandBodyNormalized.startsWith("!");
12+
const bashBangRequested = /^!(?:\s|:|[a-z0-9]|$)/i.test(command.commandBodyNormalized);
1313
if (!bashSlashRequested && !(bashBangRequested && command.isAuthorizedSender)) {
1414
return null;
1515
}

src/auto-reply/reply/commands.test.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ vi.mock("../../agents/pi-embedded.js", () => {
9292
};
9393
});
9494

95+
const execToolExecuteMock = vi.hoisted(() => vi.fn());
96+
vi.mock("../../agents/bash-tools.js", () => ({
97+
createExecTool: () => ({ execute: execToolExecuteMock }),
98+
}));
99+
95100
vi.mock("../../infra/system-events.js", () => ({
96101
enqueueSystemEvent: vi.fn(),
97102
}));
@@ -657,14 +662,56 @@ describe("handleCommands bash alias", () => {
657662
commands: { bash: true, text: true },
658663
whatsapp: { allowFrom: ["*"] },
659664
} as OpenClawConfig;
660-
for (const aliasCommand of ["!poll", "!stop"]) {
665+
for (const aliasCommand of ["!poll", "! poll", "!stop"]) {
661666
resetBashChatCommandForTests();
662667
const params = buildParams(aliasCommand, cfg);
663668
const result = await handleCommands(params);
664669
expect(result.shouldContinue).toBe(false);
665670
expect(result.reply?.text).toContain("No active bash job");
666671
}
667672
});
673+
674+
it("does not treat markdown image syntax as a bash command", async () => {
675+
const cfg = {
676+
commands: { bash: true, text: true },
677+
whatsapp: { allowFrom: ["*"] },
678+
} as OpenClawConfig;
679+
resetBashChatCommandForTests();
680+
const params = buildParams("![image] hello", cfg);
681+
const result = await handleCommands(params);
682+
expect(result.shouldContinue).toBe(true);
683+
expect(result.reply).toBeUndefined();
684+
});
685+
686+
it("accepts bang aliases and /bash run commands", async () => {
687+
const cfg = {
688+
commands: { bash: true, text: true },
689+
whatsapp: { allowFrom: ["*"] },
690+
} as OpenClawConfig;
691+
execToolExecuteMock.mockResolvedValue({
692+
details: { status: "completed", exitCode: 0, aggregated: "ok" },
693+
content: [],
694+
});
695+
696+
const cases = [
697+
{ commandBody: "!ls", expectedCommand: "ls" },
698+
{ commandBody: "!: ls", expectedCommand: "ls" },
699+
{ commandBody: "/bash echo hi", expectedCommand: "echo hi" },
700+
];
701+
702+
for (const testCase of cases) {
703+
resetBashChatCommandForTests();
704+
execToolExecuteMock.mockClear();
705+
const params = buildParams(testCase.commandBody, cfg);
706+
const result = await handleCommands(params);
707+
expect(result.shouldContinue).toBe(false);
708+
expect(result.reply?.text).toContain(`bash: ${testCase.expectedCommand}`);
709+
expect(execToolExecuteMock).toHaveBeenCalledWith(
710+
"chat-bash",
711+
expect.objectContaining({ command: testCase.expectedCommand }),
712+
);
713+
}
714+
});
668715
});
669716

670717
function buildPolicyParams(

0 commit comments

Comments
 (0)