({
input,
abortController,
setAppState,
setToolJSX,
preventCwdChanges,
isMainThread,
toolUseId,
agentId
}: {
input: BashToolInput;
abortController: AbortController;
setAppState: (f: (prev: AppState) => AppState) => void;
setToolJSX?: SetToolJSXFn;
preventCwdChanges?: boolean;
isMainThread?: boolean;
toolUseId?: string;
agentId?: AgentId;
})
| 824 | } |
| 825 | } satisfies ToolDef<InputSchema, Out, BashProgress>); |
| 826 | async function* runShellCommand({ |
| 827 | input, |
| 828 | abortController, |
| 829 | setAppState, |
| 830 | setToolJSX, |
| 831 | preventCwdChanges, |
| 832 | isMainThread, |
| 833 | toolUseId, |
| 834 | agentId |
| 835 | }: { |
| 836 | input: BashToolInput; |
| 837 | abortController: AbortController; |
| 838 | setAppState: (f: (prev: AppState) => AppState) => void; |
| 839 | setToolJSX?: SetToolJSXFn; |
| 840 | preventCwdChanges?: boolean; |
| 841 | isMainThread?: boolean; |
| 842 | toolUseId?: string; |
| 843 | agentId?: AgentId; |
| 844 | }): AsyncGenerator<{ |
| 845 | type: 'progress'; |
| 846 | output: string; |
| 847 | fullOutput: string; |
| 848 | elapsedTimeSeconds: number; |
| 849 | totalLines: number; |
| 850 | totalBytes?: number; |
| 851 | taskId?: string; |
| 852 | timeoutMs?: number; |
| 853 | }, ExecResult, void> { |
| 854 | const { |
| 855 | command, |
| 856 | description, |
| 857 | timeout, |
| 858 | run_in_background |
| 859 | } = input; |
| 860 | const timeoutMs = timeout || getDefaultTimeoutMs(); |
| 861 | let fullOutput = ''; |
| 862 | let lastProgressOutput = ''; |
| 863 | let lastTotalLines = 0; |
| 864 | let lastTotalBytes = 0; |
| 865 | let backgroundShellId: string | undefined = undefined; |
| 866 | let assistantAutoBackgrounded = false; |
| 867 | |
| 868 | // Progress signal: resolved by onProgress callback from the shared poller, |
| 869 | // waking the generator to yield a progress update. |
| 870 | let resolveProgress: (() => void) | null = null; |
| 871 | function createProgressSignal(): Promise<null> { |
| 872 | return new Promise<null>(resolve => { |
| 873 | resolveProgress = () => resolve(null); |
| 874 | }); |
| 875 | } |
| 876 | |
| 877 | // Determine if auto-backgrounding should be enabled |
| 878 | // Only enable for commands that are allowed to be auto-backgrounded |
| 879 | // and when background tasks are not disabled |
| 880 | const shouldAutoBackground = !isBackgroundTasksDisabled && isAutobackgroundingAllowed(command); |
| 881 | const shellCommand = await exec(command, abortController.signal, 'bash', { |
| 882 | timeout: timeoutMs, |
| 883 | onProgress(lastLines, allLines, totalLines, totalBytes, isIncomplete) { |
no test coverage detected