Skip to content

Commit d6cbe2e

Browse files
authored
🤖 Validate bash tool script parameter and fix typecheck target (#114)
## Changes **Bash tool validation:** - Empty or whitespace-only scripts now fail immediately with a clear error - Prevents confusing behavior from malformed tool calls - Returns `exitCode: -1` and `wall_duration_ms: 0` for instant feedback **Makefile fix:** - `make typecheck` now depends on `dist/version.txt` - Automatically generates version file before type checking - Eliminates "Cannot find module './version'" errors ## Testing Added two tests in `bash.test.ts`: - Empty script (`""`) - Whitespace-only script (`" \n\t "`) All 233 tests pass ✅ _Generated with `cmux`_
1 parent d93530e commit d6cbe2e

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fmt-check: ## Check code formatting
9191
fmt-shell: ## Format shell scripts with shfmt
9292
@./scripts/fmt.sh --shell
9393

94-
typecheck: ## Run TypeScript type checking
94+
typecheck: dist/version.txt ## Run TypeScript type checking
9595
@./scripts/typecheck.sh
9696

9797
## Testing

src/services/tools/bash.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,4 +560,42 @@ describe("bash tool", () => {
560560
expect(result.exitCode).toBe(-1);
561561
}
562562
});
563+
564+
it("should fail immediately when script is empty", async () => {
565+
const tool = createBashTool({ cwd: process.cwd() });
566+
const args: BashToolArgs = {
567+
script: "",
568+
timeout_secs: 5,
569+
max_lines: 100,
570+
};
571+
572+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
573+
574+
expect(result.success).toBe(false);
575+
if (!result.success) {
576+
expect(result.error).toContain("Script parameter is empty");
577+
expect(result.error).toContain("malformed tool call");
578+
expect(result.exitCode).toBe(-1);
579+
expect(result.wall_duration_ms).toBe(0);
580+
}
581+
});
582+
583+
it("should fail immediately when script is only whitespace", async () => {
584+
const tool = createBashTool({ cwd: process.cwd() });
585+
const args: BashToolArgs = {
586+
script: " \n\t ",
587+
timeout_secs: 5,
588+
max_lines: 100,
589+
};
590+
591+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
592+
593+
expect(result.success).toBe(false);
594+
if (!result.success) {
595+
expect(result.error).toContain("Script parameter is empty");
596+
expect(result.exitCode).toBe(-1);
597+
expect(result.wall_duration_ms).toBe(0);
598+
}
599+
});
600+
563601
});

src/services/tools/bash.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ export const createBashTool: ToolFactory = (config: ToolConfiguration) => {
4646
{ script, timeout_secs, max_lines = BASH_DEFAULT_MAX_LINES, stdin },
4747
{ abortSignal }
4848
): Promise<BashToolResult> => {
49+
// Validate script is not empty - likely indicates a malformed tool call
50+
if (!script || script.trim().length === 0) {
51+
return {
52+
success: false,
53+
error: "Script parameter is empty. This likely indicates a malformed tool call.",
54+
exitCode: -1,
55+
wall_duration_ms: 0,
56+
};
57+
}
58+
4959
const startTime = performance.now();
5060
const normalizedMaxLines = Math.max(1, Math.floor(max_lines));
5161
const effectiveMaxLines = Math.min(normalizedMaxLines, BASH_HARD_MAX_LINES);

0 commit comments

Comments
 (0)