Skip to content

Commit af6ad38

Browse files
authored
🤖 Add niceness parameter to executeBash for process priority control (#162)
Add optional `niceness` parameter to the `executeBash` IPC call for controlling process priority. This parameter is only available at the IPC level and is not exposed to agents in tool descriptions. ## Changes - **Add niceness parameter to IPC interface**: Added optional `niceness` parameter to `executeBash` options (accepts -20 to 19, where lower = higher priority) - **Wire through stack**: Parameter flows from IPC → ipcMain handler → bash tool → process spawn - **Bash tool implementation**: When niceness is specified, commands are wrapped with `nice -n <value>` - **Frontend git operations**: Set all git-related executeBash calls to use niceness 19 (lowest priority) to prevent background operations from interfering with user interactions - **Auto-dependency installation**: Added `ensure-deps` Makefile target that automatically runs `bun install` if `node_modules` doesn't exist ## Technical Details When niceness is provided, the bash tool wraps commands like: ```bash nice -n 19 bash -c "original command" ``` All git operations in GitStatusContext and GitStatusIndicator now run at lowest priority: - Git fetch (30s timeout) - Git status checks (5s timeout) - Git diff operations (5s timeout) _Generated with `cmux`_
1 parent 5014d0b commit af6ad38

File tree

7 files changed

+30
-8
lines changed

7 files changed

+30
-8
lines changed

‎Makefile‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e
2525
.PHONY: dist dist-mac dist-win dist-linux
2626
.PHONY: docs docs-build docs-watch
27+
.PHONY: ensure-deps
2728

2829
# Prettier patterns for formatting
2930
PRETTIER_PATTERNS := 'src/**/*.{ts,tsx,json}' 'tests/**/*.{ts,json}' 'docs/**/*.{md,mdx}' '*.{json,md}'
@@ -32,6 +33,13 @@ TS_SOURCES := $(shell find src -type f \( -name '*.ts' -o -name '*.tsx' \))
3233
# Default target
3334
all: build
3435

36+
# Ensure dependencies are installed
37+
ensure-deps:
38+
@if [ ! -d "node_modules" ]; then \
39+
echo "node_modules not found, running bun install..."; \
40+
bun install; \
41+
fi
42+
3543
## Help
3644
help: ## Show this help message
3745
@echo 'Usage: make [target]'
@@ -40,7 +48,7 @@ help: ## Show this help message
4048
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
4149

4250
## Development
43-
dev: build-main ## Start development server (Vite + TypeScript watcher)
51+
dev: ensure-deps build-main ## Start development server (Vite + TypeScript watcher)
4452
@bun x concurrently -k \
4553
"bun x concurrently \"bun x tsc -w -p tsconfig.main.json\" \"bun x tsc-alias -w -p tsconfig.main.json\"" \
4654
"vite"
@@ -49,16 +57,16 @@ start: build-main build-preload ## Build and start Electron app
4957
@bun x electron --remote-debugging-port=9222 .
5058

5159
## Build targets (can run in parallel)
52-
build: src/version.ts build-renderer build-main build-preload ## Build all targets
60+
build: ensure-deps src/version.ts build-renderer build-main build-preload ## Build all targets
5361

54-
build-main: dist/main.js ## Build main process
62+
build-main: ensure-deps dist/main.js ## Build main process
5563

5664
dist/main.js: src/version.ts tsconfig.main.json tsconfig.json $(TS_SOURCES)
5765
@echo "Building main process..."
5866
@NODE_ENV=production bun x tsc -p tsconfig.main.json
5967
@NODE_ENV=production bun x tsc-alias -p tsconfig.main.json
6068

61-
build-preload: dist/preload.js ## Build preload script
69+
build-preload: ensure-deps dist/preload.js ## Build preload script
6270

6371
dist/preload.js: src/preload.ts $(TS_SOURCES)
6472
@echo "Building preload script..."
@@ -69,7 +77,7 @@ dist/preload.js: src/preload.ts $(TS_SOURCES)
6977
--sourcemap=inline \
7078
--outfile=dist/preload.js
7179

72-
build-renderer: src/version.ts ## Build renderer process
80+
build-renderer: ensure-deps src/version.ts ## Build renderer process
7381
@echo "Building renderer..."
7482
@bun x vite build
7583

‎src/components/GitStatusIndicator.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ ${getDirtyFiles}
324324
const result = await window.api.workspace.executeBash(workspaceId, script, {
325325
timeout_secs: 5,
326326
max_lines: 100,
327+
niceness: 19, // Lowest priority - don't interfere with user operations
327328
});
328329

329330
if (!result.success) {

‎src/contexts/GitStatusContext.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export function GitStatusProvider({ workspaceMetadata, children }: GitStatusProv
7979
try {
8080
const result = await window.api.workspace.executeBash(workspaceId, GIT_FETCH_SCRIPT, {
8181
timeout_secs: 30,
82+
niceness: 19, // Lowest priority - don't interfere with user operations
8283
});
8384

8485
if (!result.success) {
@@ -204,6 +205,7 @@ export function GitStatusProvider({ workspaceMetadata, children }: GitStatusProv
204205
GIT_STATUS_SCRIPT,
205206
{
206207
timeout_secs: 5,
208+
niceness: 19, // Lowest priority - don't interfere with user operations
207209
}
208210
);
209211

‎src/services/ipcMain.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ export class IpcMain {
757757
_event,
758758
workspaceId: string,
759759
script: string,
760-
options?: { timeout_secs?: number; max_lines?: number; stdin?: string }
760+
options?: { timeout_secs?: number; max_lines?: number; stdin?: string; niceness?: number }
761761
) => {
762762
try {
763763
// Get workspace metadata to find workspacePath
@@ -778,6 +778,7 @@ export class IpcMain {
778778
const bashTool = createBashTool({
779779
cwd: workspacePath,
780780
secrets: secretsToRecord(projectSecrets),
781+
niceness: options?.niceness,
781782
});
782783

783784
// Execute the script with provided options

‎src/services/tools/bash.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,16 @@ export const createBashTool: ToolFactory = (config: ToolConfiguration) => {
9494
}
9595

9696
// Create the process with `using` for automatic cleanup
97+
// If niceness is specified, wrap the command with nice
98+
const finalScript =
99+
config.niceness !== undefined
100+
? `nice -n ${config.niceness} bash -c ${JSON.stringify(script)}`
101+
: script;
102+
const finalCommand =
103+
config.niceness !== undefined ? ["bash", "-c", finalScript] : ["bash", "-c", script];
104+
97105
using childProcess = new DisposableProcess(
98-
spawn("bash", ["-c", script], {
106+
spawn(finalCommand[0], finalCommand.slice(1), {
99107
cwd: config.cwd,
100108
env: {
101109
...process.env,

‎src/types/ipc.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export interface IPCApi {
192192
executeBash(
193193
workspaceId: string,
194194
script: string,
195-
options?: { timeout_secs?: number; max_lines?: number; stdin?: string }
195+
options?: { timeout_secs?: number; max_lines?: number; stdin?: string; niceness?: number }
196196
): Promise<Result<BashToolResult, string>>;
197197
openTerminal(workspacePath: string): Promise<void>;
198198

‎src/utils/tools/tools.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export interface ToolConfiguration {
1818
cwd: string;
1919
/** Environment secrets to inject (optional) */
2020
secrets?: Record<string, string>;
21+
/** Process niceness level (optional, -20 to 19, lower = higher priority) */
22+
niceness?: number;
2123
}
2224

2325
/**

0 commit comments

Comments
 (0)