Skip to content

Release v6.9.8 - #68

Merged
code-crusher merged 2 commits into
mainfrom
release/v6.9.8
Oct 9, 2026
Merged

code-crusher merged 2 commits into
mainfrom
release/v6.9.8

Conversation

@code-crusher

Copy link
Copy Markdown
Member

Changes

  • Background commands: Bash gains a background parameter for detached long-running commands (downloads, builds, tests, installs)
  • check_background tool: Poll status, exit code, and output of background shells
  • kill_background tool: Send SIGTERM to background shell process groups
  • Background shells panel: Status bar shows running shells; expand with ctrl+b
  • Remove queued messages: Clickable [remove] action in queue panel

Version

6.9.8

Each queued message now shows a clickable [remove] action next to the
existing [send now] action, letting users drop messages they no longer
want to send without waiting for them to be drained.

Bumps version to 6.9.8.
- Background commands: Bash gains background parameter for detached long-running commands
- check_background and kill_background tools for managing background shells
- Background shells panel in status bar (ctrl+b)
- Remove queued messages action in queue panel
@matterai-app

matterai-app Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Code Quality

Summary By MatterAI MatterAI logo ### 🔄 What Changed (very crisp summary on what this pull request is changing in the codebase), This release introduces non-blocking background command execution for long-running shell tasks (background: true), complete with process management, temp-file log capture, status polling, termination tools, a new TUI panel (BackgroundShells), status bar indicators, and comprehensive test coverage. ### 🔍 Impact of the Change (very crisp summary on how this pull request change is impacting the feature, product or business logic), Empowers the AI agent to run long tasks (builds, tests, downloads) asynchronously without blocking the main interaction thread or terminal UI. Users gain real-time visibility and control over background processes via status bar indicators and interactive TUI panels. ### 📁 Total Files Changed
Click to Expand

File ChangeLog
Version Bump (package.json) Bumped version to v6.9.8 and added background test script.
Agent Integration (src/core/agent.ts) Injected background command completion notices into agent turn context.
Prompt Update (src/prompts/system.ts) Updated system instructions to guide the agent on background execution.
Process Manager (src/tools/executors/backgroundCommands.ts) Created robust background process registry, spawning, output stream capture, and cleanup logic.
Status Check (src/tools/executors/checkBackground.ts) Added executor to poll running/completed background command status and output.
Command Execution (src/tools/executors/executeCommand.ts) Updated executeCommand to delegate background tasks to the process manager.
Process Termination (src/tools/executors/killBackground.ts) Added executor to send SIGTERM/SIGKILL signals to background processes.
Tool Registration (src/tools/index.ts) Registered check_background and kill_background tools in the central dispatcher.
Tool Schemas (src/tools/schemas/) Added JSON schemas for background tools and updated Bash schema definition.
Context Types (src/tools/types.ts) Added optional taskId to ToolContext for task-scoped background processes.
TUI Updates (src/ui/) Added BackgroundShells component, status bar integration, queue management fixes, and Ctrl+B toggle.
Test Suite (test/background-commands.test.ts) Added comprehensive unit and integration tests covering all background command behaviors.
### 🧪 Test Added/Recommended#### Added - `test/background-commands.test.ts`: Complete test suite covering async execution, completion status, error codes, output tails, task scoping, process cleanup, cancellation, and UI state synchronization. #### Recommended - Add end-to-end integration tests simulating terminal keyboard shortcuts (Ctrl+B) with active background processes. ### 🔒Security Vulnerabilities 🔒 No critical security vulnerabilities detected. Background processes use detached process groups and proper SIGTERM/SIGKILL escalation with automatic temp file cleanup.

⏳ Estimated code review effort

HIGH (~30 minutes)

Tip

Quality Recommendations

  1. Ensure maximum output truncation limits in checkBackground are configurable for memory safety under heavy logging.

  2. Add validation to prevent excessively large command strings from spawning background processes.

♫ Tanka Poem

Terminal breathes free now,
Long tasks run out of sight, yet
We watch their live logs,
Controlled with a simple keystroke,
Code flows without interruption. ⚡️

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as OrbCode TUI
    participant Agent
    participant Exec as ExecuteCommand
    participant BG as BackgroundManager
    
    User->>CLI: Type command with background=true
    CLI->>Agent: Submit prompt
    Agent->>Exec: executeCommand(command, background=true, cwd)
    Exec->>BG: startBackgroundCommand()
    BG-->>Exec: Return BackgroundCommand (id, pid)
    Exec-->>Agent: Background command started response
    Agent-->>CLI: Update UI & Status Bar
    Note over BG: Process runs asynchronously in background
    BG->>Agent: Notification on completion (<background_commands>)
    User->>CLI: Press Ctrl+B or check status
    CLI->>BG: listBackgroundCommands() / killBackgroundCommand()
Loading

@matterai-app matterai-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧪 PR Review is completed: Well-structured background-command feature; the critical catch is the Bash schema adding background to properties without adding it to required (strict-mode providers reject the whole tool schema), plus Windows cmd.exe quoting parity, an unhandled write-stream error, temp-file cleanup on exit, and unbounded log reads. Reviewed src/core/agent.ts: no issues found. Reviewed src/ui/App.tsx: no issues found. Reviewed src/ui/components/BackgroundShells.tsx: no issues found. Reviewed src/tools/executors/executeCommand.ts: no issues found. Reviewed src/tools/executors/checkBackground.ts: no issues found. Reviewed src/tools/executors/killBackground.ts: no issues found. Reviewed test/background-commands.test.ts: no issues found. Reviewed src/prompts/system.ts: no issues found. Reviewed src/ui/components/StatusBar.tsx: no issues found. Reviewed src/ui/components/QueuedMessages.tsx: no issues found. Reviewed src/tools/index.ts: no issues found. Reviewed src/tools/schemas/index.ts: no issues found. Reviewed src/tools/schemas/check_background.ts: no issues found. Reviewed src/tools/schemas/kill_background.ts: no issues found. Reviewed src/tools/types.ts: no issues found. Reviewed package.json: no issues found.

Skipped files
  • CHANGELOG.md: Skipped file pattern
⬇️ Low Priority Suggestions (4)
src/tools/executors/backgroundCommands.ts (4 suggestions)

Location: src/tools/executors/backgroundCommands.ts (Lines 127-132)

🟠 Platform Parity Bug

Issue: The foreground spawn in executeCommand.ts sets windowsVerbatimArguments for cmd.exe because "cmd.exe parses the command string itself; pre-quoting would corrupt it". The background spawn here omits that option, so on Windows without Git Bash (cmd.exe fallback), Node's default MSVCRT argument escaping mangles any command containing quotes (e.g. echo "hi" reaches cmd as \"hi\"), silently corrupting background commands.

Fix: Apply the same verbatim-arguments rule to the background spawn (add import { isCmdShell } from "../../utils/shell.js").

Impact: Background commands behave identically to foreground ones under cmd.exe.

-  	const child = spawn(shell, shellArgs, {
-  		cwd,
-  		env: { ...process.env, TERM: "dumb" },
-  		stdio: ["ignore", "pipe", "pipe"],
-  		detached: process.platform !== "win32",
-  	})
+  	const child = spawn(shell, shellArgs, {
+  		cwd,
+  		env: { ...process.env, TERM: "dumb" },
+  		stdio: ["ignore", "pipe", "pipe"],
+  		detached: process.platform !== "win32",
+  		windowsVerbatimArguments: process.platform === "win32" && isCmdShell(shell),
+  	})

Location: src/tools/executors/backgroundCommands.ts (Lines 137-139)

🟠 Crash Risk

Issue: fs.createWriteStream(outputFile) has no 'error' listener. If the log write fails — disk full during a long build (the exact use case for background commands), tmpdir removed, or EMFILE — the stream emits an unhandled 'error' event, which throws an uncaught exception and kills the whole CLI mid-turn. Every other filesystem helper in this file (deleteOutputFile, readOutput, readBackgroundOutputTail) is best-effort, but this one is not.

Fix: Attach an error listener so a failed log write degrades gracefully; output reads already fall back to cmd.output, and finalize's end callback still runs so status updates correctly.

Impact: A full disk or unwritable tmpdir no longer crashes the agent while a background command is running.

-  	const outStream = fs.createWriteStream(outputFile)
-  	child.stdout.on("data", (data) => outStream.write(data))
-  	child.stderr.on("data", (data) => outStream.write(data))
+  	const outStream = fs.createWriteStream(outputFile)
+  	outStream.on("error", () => {})
+  	child.stdout.on("data", (data) => outStream.write(data))
+  	child.stderr.on("data", (data) => outStream.write(data))

Location: src/tools/executors/backgroundCommands.ts (Lines 60-69)

🟠 Resource Leak

Issue: The exit hook SIGTERMs running commands but never deletes their temp output files, and neither pruneExpired nor resetBackgroundCommands runs at shutdown. Every session that uses background commands leaves orbcode-bg-*.log files — containing full command output, potentially sensitive — in the tmpdir indefinitely, accumulating across sessions.

Fix: Delete each command's output file in the exit hook; fs.rmSync inside deleteOutputFile is synchronous and safe within the 'exit' handler (children keep writing to the unlinked inode, which is harmless).

Impact: No orphaned log files accumulating in the tmpdir; command output no longer outlives the CLI process.

-  /** Detached children outlive us by default; take them down when we exit. */
-  function installExitHook() {
-  	if (exitHookInstalled) return
-  	exitHookInstalled = true
-  	process.once("exit", () => {
-  		for (const cmd of commands.values()) {
-  			if (cmd.status === "running") signalCommand(cmd, "SIGTERM")
-  		}
-  	})
-  }
+  /** Detached children outlive us by default; take them down when we exit. */
+  function installExitHook() {
+  	if (exitHookInstalled) return
+  	exitHookInstalled = true
+  	process.once("exit", () => {
+  		for (const cmd of commands.values()) {
+  			if (cmd.status === "running") signalCommand(cmd, "SIGTERM")
+  			deleteOutputFile(cmd)
+  		}
+  	})
+  }

Location: src/tools/executors/backgroundCommands.ts (Lines 71-77)

🟡 Performance

Issue: readOutput reads the entire log file into memory and getBackgroundCommand runs it on every call, so each check_background/kill_background synchronously loads the full output of a potentially huge build log, blocking the event loop and spiking memory. checkBackground only ever displays the first 30k chars, and the UI already uses the bounded readBackgroundOutputTail, so nothing needs the unbounded read.

Fix: Bound the read to the first MAX_OUTPUT_READ_BYTES (define const MAX_OUTPUT_READ_BYTES = 1024 * 1024 next to RETENTION_MS). This is behavior-preserving since all consumers truncate far below that bound.

Impact: check_background stays cheap and non-blocking no matter how chatty the background command is.

-  function readOutput(cmd: BackgroundCommand): string {
-  	try {
-  		return fs.readFileSync(cmd.outputFile, "utf-8")
-  	} catch {
-  		return cmd.output
-  	}
-  }
+  function readOutput(cmd: BackgroundCommand): string {
+  	try {
+  		const fd = fs.openSync(cmd.outputFile, "r")
+  		try {
+  			const length = Math.min(fs.fstatSync(fd).size, MAX_OUTPUT_READ_BYTES)
+  			const buffer = Buffer.alloc(length)
+  			fs.readSync(fd, buffer, 0, length, 0)
+  			return buffer.toString("utf-8")
+  		} finally {
+  			fs.closeSync(fd)
+  		}
+  	} catch {
+  		return cmd.output
+  	}
+  }

@code-crusher
code-crusher merged commit c82a79a into main Oct 9, 2026
1 check passed
@code-crusher
code-crusher deleted the release/v6.9.8 branch October 9, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant