feat(core): agnostic background task UI with CompletionBehavior (#22740)

Co-authored-by: mkorwel <matt.korwel@gmail.com>
This commit is contained in:
Adam Weidman
2026-03-28 17:27:51 -04:00
committed by GitHub
parent 07ab16dbbe
commit 3eebb75b7a
54 changed files with 1467 additions and 875 deletions

View File

@@ -19,7 +19,7 @@ import {
resolveExecutable,
type ShellType,
} from '../utils/shell-utils.js';
import { isBinary } from '../utils/textUtils.js';
import { isBinary, truncateString } from '../utils/textUtils.js';
import pkg from '@xterm/headless';
import { debugLogger } from '../utils/debugLogger.js';
import { Storage } from '../config/storage.js';
@@ -102,6 +102,7 @@ export interface ShellExecutionConfig {
scrollback?: number;
maxSerializedLines?: number;
sandboxConfig?: SandboxConfig;
backgroundCompletionBehavior?: 'inject' | 'notify' | 'silent';
}
/**
@@ -239,6 +240,23 @@ export class ShellExecutionService {
return path.join(Storage.getGlobalTempDir(), 'background-processes');
}
private static formatShellBackgroundCompletion(
pid: number,
behavior: string,
output: string,
error?: Error,
): string {
const logPath = ShellExecutionService.getLogFilePath(pid);
const status = error ? `with error: ${error.message}` : 'successfully';
if (behavior === 'inject') {
const truncated = truncateString(output, 5000);
return `[Background command completed ${status}. Output saved to ${logPath}]\n\n${truncated}`;
}
return `[Background command completed ${status}. Output saved to ${logPath}]`;
}
static getLogFilePath(pid: number): string {
return path.join(this.getLogDir(), `background-${pid}.log`);
}
@@ -532,6 +550,15 @@ export class ShellExecutionService {
return false;
}
},
formatInjection: (output, error) =>
ShellExecutionService.formatShellBackgroundCompletion(
child.pid!,
shellExecutionConfig.backgroundCompletionBehavior || 'silent',
output,
error ?? undefined,
),
completionBehavior:
shellExecutionConfig.backgroundCompletionBehavior || 'silent',
})
: undefined;
@@ -862,6 +889,15 @@ export class ShellExecutionService {
);
return bufferData.length > 0 ? bufferData : undefined;
},
formatInjection: (output, error) =>
ShellExecutionService.formatShellBackgroundCompletion(
ptyPid,
shellExecutionConfig.backgroundCompletionBehavior || 'silent',
output,
error ?? undefined,
),
completionBehavior:
shellExecutionConfig.backgroundCompletionBehavior || 'silent',
}).result;
let processingChain = Promise.resolve();