-
Notifications
You must be signed in to change notification settings - Fork 0
promote: dev -> main (background-shell disk capture + completion notifications) #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
82b71f0
1592c59
a4c81b2
d697ddf
da4928f
e973040
6613a6e
1744889
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # Stop Background Shell (`bg_stop`) | ||
|
|
||
| Stops a long-running background shell task spawned by [`run_shell_command`](./shell) with `is_background: true`. Sends SIGTERM to the process group, escalating to SIGKILL after a 3-second grace. | ||
|
|
||
| ## Parameters | ||
|
|
||
| | Parameter | Required | Description | | ||
| | --------- | -------- | ---------------------------------------------------------------------- | | ||
| | `task_id` | Yes | The opaque ID returned by the original shell tool result | | ||
| | `reason` | No | Free-form reason; recorded for audit and surfaced in the result string | | ||
|
|
||
| ## Behavior | ||
|
|
||
| 1. Looks up the task in the in-session registry. | ||
| 2. If the task already finished, returns its current status without signaling — no-op. | ||
| 3. Sends `SIGTERM` to the process group (negative pid). Falls back to signaling the leader directly on `EPERM`. | ||
| 4. Schedules a `SIGKILL` to the process group after **3 seconds** if the leader is still alive. | ||
| 5. Optimistically marks the task `killed` in the registry. The watcher sees the same exit and is a no-op once the status flipped. | ||
| 6. The next user prompt is prefixed with a `<task_notification>` block carrying `status: killed`. | ||
|
|
||
| ## Output | ||
|
|
||
| ``` | ||
| Background task "7f9c…" stopped (SIGTERM: <reason if provided>). | ||
| ``` | ||
|
|
||
| If the task was not found: | ||
|
|
||
| ``` | ||
| No background task with ID "<task_id>". | ||
| ``` | ||
|
|
||
| ## Finding `task_id` | ||
|
|
||
| The shell tool's return value for a backgrounded command lists the task ID and output path: | ||
|
|
||
| ``` | ||
| Background command started. | ||
| Task ID: 7f9c… | ||
| Output file: /tmp/proto/<project-hash>/<session>/tasks/7f9c…output | ||
| PID: 54322 | ||
| ``` | ||
|
|
||
| You can also list current background tasks from the TUI with the `/bg` slash command. | ||
|
|
||
| ## Confirmation | ||
|
|
||
| `bg_stop` is classified as a `think`-kind tool — no user confirmation is required for the tool call itself. The signal still goes to the process group with the user's permissions. | ||
|
|
||
| ## See Also | ||
|
|
||
| - [`run_shell_command`](./shell) — the `is_background: true` parameter | ||
| - `/bg` slash command — list current background tasks | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,10 +30,29 @@ Executes a shell command. On macOS/Linux, runs with `bash -c`. On Windows, runs | |
| - Build watchers (`webpack --watch`) | ||
| - Database servers (`mongod`, `redis-server`) | ||
| - Any process that runs indefinitely | ||
| - Long batch jobs whose stdout you want to inspect later (evals, data processing) | ||
|
|
||
| ## Output | ||
|
|
||
| Returns `Command`, `Directory`, `Stdout`, `Stderr`, `Error`, `Exit Code`, `Signal`, and `Background PIDs`. | ||
| For **foreground** commands, the tool returns `Command`, `Directory`, `Stdout`, `Stderr`, `Error`, `Exit Code`, `Signal`, and `Process Group PGID`. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Foreground output keys are documented incorrectly. The tool does not return separate 🤖 Prompt for AI Agents |
||
|
|
||
| For **background** commands on non-Windows, the tool returns: | ||
|
|
||
| - `Task ID` — opaque stable ID used to refer to the task later | ||
| - `Output file` — absolute path where stdout+stderr is captured (writes continue after the wrapper exits) | ||
| - `PID` — actual subprocess PID | ||
|
|
||
| Read the output file at any time with the [`read_file`](./read-file) tool to inspect progress or final results — there is no need to poll. When the process exits, the **next user prompt** is prefixed with a `<task_notification>` block carrying `task_id`, `output_file`, `status` (`completed`/`failed`/`killed`), `exit_code`, and a human summary. | ||
|
|
||
| ## Background tasks | ||
|
|
||
| Output files live at `<projectTempDir>/<sessionId>/tasks/<taskId>.output` and are written via shell-level redirection (`( cmd ) > file 2>&1 &`). The OS keeps writing even after the parent shell exits, so detached processes never silently lose output. | ||
|
|
||
| To stop a runaway background task, use the [`bg_stop`](./bg-stop) tool with the `task_id`. It SIGTERMs the process group and escalates to SIGKILL after a 3-second grace. | ||
|
|
||
| To list running and recently-completed background tasks from the TUI, run `/bg`. | ||
|
|
||
| > **Windows.** Background tasks rely on POSIX shell redirection and process-group signaling. On Windows, `is_background: true` falls back to the simpler "fire and return" path used in earlier versions; output is not captured to disk. | ||
|
|
||
| ## Confirmation | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2025 protoLabs Studio | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| import type { | ||
| CommandContext, | ||
| SlashCommand, | ||
| SlashCommandActionReturn, | ||
| } from './types.js'; | ||
| import { CommandKind } from './types.js'; | ||
|
|
||
| function formatDuration(ms: number): string { | ||
| if (ms < 1000) return `${ms}ms`; | ||
| const s = Math.floor(ms / 1000); | ||
| if (s < 60) return `${s}s`; | ||
| const m = Math.floor(s / 60); | ||
| const rs = s % 60; | ||
| if (m < 60) return `${m}m${rs > 0 ? ` ${rs}s` : ''}`; | ||
| const h = Math.floor(m / 60); | ||
| const rm = m % 60; | ||
| return `${h}h${rm > 0 ? ` ${rm}m` : ''}`; | ||
| } | ||
|
|
||
| function listAction(context: CommandContext): SlashCommandActionReturn { | ||
| const config = context.services.config; | ||
| if (!config) { | ||
| return { | ||
| type: 'message', | ||
| messageType: 'error', | ||
| content: 'Config not available.', | ||
| }; | ||
| } | ||
| const registry = config.getBackgroundShellRegistry(); | ||
| const tasks = registry.list(); | ||
|
|
||
| if (tasks.length === 0) { | ||
| return { | ||
| type: 'message', | ||
| messageType: 'info', | ||
| content: | ||
| 'No background tasks. Run a shell command with is_background: true to start one.', | ||
| }; | ||
| } | ||
|
|
||
| const now = Date.now(); | ||
| const lines: string[] = ['Background shell tasks (newest first):', '']; | ||
| for (const t of tasks) { | ||
| const ageMs = (t.endTime ?? now) - t.startTime; | ||
| const status = | ||
| t.status === 'running' | ||
| ? `running (${formatDuration(ageMs)})` | ||
| : `${t.status}${t.exitCode != null ? ` exit=${t.exitCode}` : ''} (ran ${formatDuration(ageMs)})`; | ||
| lines.push(` ${t.id} ${status}`); | ||
| lines.push(` cmd: ${t.command}`); | ||
| lines.push(` out: ${t.outputPath}`); | ||
| if (t.pid != null) lines.push(` pid: ${t.pid}`); | ||
| lines.push(''); | ||
| } | ||
| lines.push( | ||
| 'Stop a running task with the bg_stop tool (or kill <pid> manually).', | ||
| ); | ||
| return { | ||
| type: 'message', | ||
| messageType: 'info', | ||
| content: lines.join('\n'), | ||
| }; | ||
| } | ||
|
|
||
| export const bgCommand: SlashCommand = { | ||
| name: 'bg', | ||
| description: 'List long-running background shell tasks', | ||
| kind: CommandKind.BUILT_IN, | ||
| subCommands: [ | ||
| { | ||
| name: 'list', | ||
| description: 'List background tasks', | ||
| kind: CommandKind.BUILT_IN, | ||
| action: listAction, | ||
| }, | ||
| ], | ||
| action: listAction, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add languages to the fenced examples.
markdownlint-cli2is already flagging these three blocks with MD040, so this page will stay lint-noisy until each fence has a language (textis enough here).Suggested fix
-
+textNo background task with ID "<task_id>".
Verify each finding against the current code and only fix it if needed.
In
@docs/reference/tools/bg-stop.mdaround lines 23 - 25, Add a language tag(use "text") to each fenced code block examples that are currently untagged: the
block containing
Background task "7f9c…" stopped (SIGTERM: <reason if provided>)., the block containingNo background task with ID "<task_id>".,and the multi-line block beginning with
Background command started.(includingTask ID/Output file/PID lines); update each opening
totext somarkdownlint MD040 is resolved.