@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
|
2 | 2 | import { existsSync } from "node:fs"; |
3 | 3 | import { Container, Text, truncateToWidth } from "@earendil-works/pi-tui"; |
4 | 4 | import { Type } from "typebox"; |
| 5 | +import { resolveTimerTimeoutMs } from "../../../shared/number-coercion.js"; |
5 | 6 | import { keyHint } from "../../modes/interactive/components/keybinding-hints.js"; |
6 | 7 | import { truncateToVisualLines } from "../../modes/interactive/components/visual-truncate.js"; |
7 | 8 | import { theme } from "../../modes/interactive/theme/theme.js"; |
@@ -32,6 +33,17 @@ export type { BashToolDetails, BashToolInput } from "./tool-contracts.js";
|
32 | 33 | |
33 | 34 | export type { BashOperations } from "./bash-operations.js"; |
34 | 35 | |
| 36 | +export function resolveBashTimeoutMs(timeoutSeconds: unknown): number | undefined { |
| 37 | +if ( |
| 38 | +typeof timeoutSeconds !== "number" || |
| 39 | +!Number.isFinite(timeoutSeconds) || |
| 40 | +timeoutSeconds <= 0 |
| 41 | +) { |
| 42 | +return undefined; |
| 43 | +} |
| 44 | +return resolveTimerTimeoutMs(timeoutSeconds * 1000, 1); |
| 45 | +} |
| 46 | + |
35 | 47 | /** |
36 | 48 | * Create bash operations using OpenClaw runtime's built-in local shell execution backend. |
37 | 49 | * |
@@ -61,14 +73,14 @@ export function createLocalBashOperations(options?: { shellPath?: string }): Bas
|
61 | 73 | } |
62 | 74 | let timedOut = false; |
63 | 75 | let timeoutHandle: NodeJS.Timeout | undefined; |
64 | | -// Set timeout if provided. |
65 | | -if (timeout !== undefined && timeout > 0) { |
| 76 | +const timeoutMs = resolveBashTimeoutMs(timeout); |
| 77 | +if (timeoutMs !== undefined) { |
66 | 78 | timeoutHandle = setTimeout(() => { |
67 | 79 | timedOut = true; |
68 | 80 | if (child.pid) { |
69 | 81 | killProcessTree(child.pid); |
70 | 82 | } |
71 | | -}, timeout * 1000); |
| 83 | +}, timeoutMs); |
72 | 84 | } |
73 | 85 | // Stream stdout and stderr. |
74 | 86 | child.stdout?.on("data", onData); |
|