@dungle-scrubs/tallow 0.8.21 → 0.8.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +35 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/interactive-mode-patch.d.ts +2 -0
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +82 -0
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +68 -1
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-relay.d.ts +40 -7
- package/dist/workspace-transition-relay.d.ts.map +1 -1
- package/dist/workspace-transition-relay.js +81 -16
- package/dist/workspace-transition-relay.js.map +1 -1
- package/extensions/__integration__/background-task-widget-ownership.test.ts +216 -0
- package/extensions/__integration__/claude-hooks-compat.test.ts +156 -0
- package/extensions/__integration__/slash-command-bridge.test.ts +169 -23
- package/extensions/_shared/atomic-write.ts +1 -1
- package/extensions/_shared/bordered-box.ts +102 -0
- package/extensions/_shared/interop-events.ts +5 -0
- package/extensions/_shared/pid-registry.ts +1 -1
- package/extensions/agent-commands-tool/index.ts +4 -1
- package/extensions/background-task-tool/__tests__/lifecycle.test.ts +50 -25
- package/extensions/background-task-tool/index.ts +139 -221
- package/extensions/bash-tool-enhanced/index.ts +1 -75
- package/extensions/cd-tool/index.ts +2 -2
- package/extensions/context-fork/spawn.ts +4 -1
- package/extensions/health/index.ts +6 -6
- package/extensions/hooks/__tests__/claude-compat.test.ts +35 -0
- package/extensions/hooks/__tests__/subprocess-hardening.test.ts +73 -0
- package/extensions/hooks/index.ts +27 -4
- package/extensions/loop/__tests__/loop.test.ts +168 -4
- package/extensions/loop/extension.json +6 -5
- package/extensions/loop/index.ts +242 -31
- package/extensions/plan-mode-tool/__tests__/agent-end-execution.test.ts +373 -0
- package/extensions/plan-mode-tool/index.ts +103 -41
- package/extensions/prompt-suggestions/__tests__/editor-compatibility.test.ts +42 -0
- package/extensions/prompt-suggestions/index.ts +41 -6
- package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +267 -671
- package/extensions/slash-command-bridge/extension.json +1 -1
- package/extensions/slash-command-bridge/index.ts +230 -116
- package/extensions/subagent-tool/index.ts +2 -2
- package/extensions/subagent-tool/process.ts +4 -5
- package/extensions/tasks/commands/register-tasks-extension.ts +41 -0
- package/extensions/teams-tool/__tests__/peer-messaging.test.ts +29 -24
- package/extensions/teams-tool/dashboard.ts +3 -5
- package/extensions/teams-tool/dispatch/auto-dispatch.ts +18 -1
- package/extensions/teams-tool/tools/teammate-tools.ts +9 -6
- package/extensions/wezterm-pane-control/__tests__/index.test.ts +88 -4
- package/extensions/wezterm-pane-control/index.ts +113 -8
- package/package.json +6 -4
- package/packages/tallow-tui/README.md +51 -0
- package/packages/tallow-tui/dist/autocomplete.d.ts +48 -0
- package/packages/tallow-tui/dist/autocomplete.d.ts.map +1 -0
- package/packages/tallow-tui/dist/autocomplete.js +564 -0
- package/packages/tallow-tui/dist/autocomplete.js.map +1 -0
- package/packages/tallow-tui/dist/border-styles.d.ts +32 -0
- package/packages/tallow-tui/dist/border-styles.d.ts.map +1 -0
- package/packages/tallow-tui/dist/border-styles.js +46 -0
- package/packages/tallow-tui/dist/border-styles.js.map +1 -0
- package/packages/tallow-tui/dist/components/bordered-box.d.ts +52 -0
- package/packages/tallow-tui/dist/components/bordered-box.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/bordered-box.js +89 -0
- package/packages/tallow-tui/dist/components/bordered-box.js.map +1 -0
- package/packages/tallow-tui/dist/components/box.d.ts +22 -0
- package/packages/tallow-tui/dist/components/box.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/box.js +104 -0
- package/packages/tallow-tui/dist/components/box.js.map +1 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.d.ts +22 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.js +35 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.js.map +1 -0
- package/packages/tallow-tui/dist/components/editor.d.ts +240 -0
- package/packages/tallow-tui/dist/components/editor.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/editor.js +1766 -0
- package/packages/tallow-tui/dist/components/editor.js.map +1 -0
- package/packages/tallow-tui/dist/components/image.d.ts +126 -0
- package/packages/tallow-tui/dist/components/image.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/image.js +245 -0
- package/packages/tallow-tui/dist/components/image.js.map +1 -0
- package/packages/tallow-tui/dist/components/input.d.ts +37 -0
- package/packages/tallow-tui/dist/components/input.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/input.js +439 -0
- package/packages/tallow-tui/dist/components/input.js.map +1 -0
- package/packages/tallow-tui/dist/components/loader.d.ts +88 -0
- package/packages/tallow-tui/dist/components/loader.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/loader.js +146 -0
- package/packages/tallow-tui/dist/components/loader.js.map +1 -0
- package/packages/tallow-tui/dist/components/markdown.d.ts +95 -0
- package/packages/tallow-tui/dist/components/markdown.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/markdown.js +633 -0
- package/packages/tallow-tui/dist/components/markdown.js.map +1 -0
- package/packages/tallow-tui/dist/components/select-list.d.ts +32 -0
- package/packages/tallow-tui/dist/components/select-list.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/select-list.js +156 -0
- package/packages/tallow-tui/dist/components/select-list.js.map +1 -0
- package/packages/tallow-tui/dist/components/settings-list.d.ts +50 -0
- package/packages/tallow-tui/dist/components/settings-list.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/settings-list.js +189 -0
- package/packages/tallow-tui/dist/components/settings-list.js.map +1 -0
- package/packages/tallow-tui/dist/components/spacer.d.ts +12 -0
- package/packages/tallow-tui/dist/components/spacer.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/spacer.js +23 -0
- package/packages/tallow-tui/dist/components/spacer.js.map +1 -0
- package/packages/tallow-tui/dist/components/text.d.ts +19 -0
- package/packages/tallow-tui/dist/components/text.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/text.js +91 -0
- package/packages/tallow-tui/dist/components/text.js.map +1 -0
- package/packages/tallow-tui/dist/components/truncated-text.d.ts +13 -0
- package/packages/tallow-tui/dist/components/truncated-text.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/truncated-text.js +51 -0
- package/packages/tallow-tui/dist/components/truncated-text.js.map +1 -0
- package/packages/tallow-tui/dist/editor-component.d.ts +50 -0
- package/packages/tallow-tui/dist/editor-component.d.ts.map +1 -0
- package/packages/tallow-tui/dist/editor-component.js +2 -0
- package/packages/tallow-tui/dist/editor-component.js.map +1 -0
- package/packages/tallow-tui/dist/fuzzy.d.ts +16 -0
- package/packages/tallow-tui/dist/fuzzy.d.ts.map +1 -0
- package/packages/tallow-tui/dist/fuzzy.js +107 -0
- package/packages/tallow-tui/dist/fuzzy.js.map +1 -0
- package/packages/tallow-tui/dist/index.d.ts +25 -0
- package/packages/tallow-tui/dist/index.d.ts.map +1 -0
- package/packages/tallow-tui/dist/index.js +35 -0
- package/packages/tallow-tui/dist/index.js.map +1 -0
- package/packages/tallow-tui/dist/keybindings.d.ts +39 -0
- package/packages/tallow-tui/dist/keybindings.d.ts.map +1 -0
- package/packages/tallow-tui/dist/keybindings.js +114 -0
- package/packages/tallow-tui/dist/keybindings.js.map +1 -0
- package/packages/tallow-tui/dist/keys.d.ts +168 -0
- package/packages/tallow-tui/dist/keys.d.ts.map +1 -0
- package/packages/tallow-tui/dist/keys.js +971 -0
- package/packages/tallow-tui/dist/keys.js.map +1 -0
- package/packages/tallow-tui/dist/kill-ring.d.ts +28 -0
- package/packages/tallow-tui/dist/kill-ring.d.ts.map +1 -0
- package/packages/tallow-tui/dist/kill-ring.js +44 -0
- package/packages/tallow-tui/dist/kill-ring.js.map +1 -0
- package/packages/tallow-tui/dist/stdin-buffer.d.ts +48 -0
- package/packages/tallow-tui/dist/stdin-buffer.d.ts.map +1 -0
- package/packages/tallow-tui/dist/stdin-buffer.js +317 -0
- package/packages/tallow-tui/dist/stdin-buffer.js.map +1 -0
- package/packages/tallow-tui/dist/terminal-image.d.ts +161 -0
- package/packages/tallow-tui/dist/terminal-image.d.ts.map +1 -0
- package/packages/tallow-tui/dist/terminal-image.js +460 -0
- package/packages/tallow-tui/dist/terminal-image.js.map +1 -0
- package/packages/tallow-tui/dist/terminal.d.ts +102 -0
- package/packages/tallow-tui/dist/terminal.d.ts.map +1 -0
- package/packages/tallow-tui/dist/terminal.js +263 -0
- package/packages/tallow-tui/dist/terminal.js.map +1 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.d.ts +14 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.d.ts.map +1 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.js +55 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.js.map +1 -0
- package/packages/tallow-tui/dist/tui.d.ts +239 -0
- package/packages/tallow-tui/dist/tui.d.ts.map +1 -0
- package/packages/tallow-tui/dist/tui.js +1058 -0
- package/packages/tallow-tui/dist/tui.js.map +1 -0
- package/packages/tallow-tui/dist/undo-stack.d.ts +17 -0
- package/packages/tallow-tui/dist/undo-stack.d.ts.map +1 -0
- package/packages/tallow-tui/dist/undo-stack.js +25 -0
- package/packages/tallow-tui/dist/undo-stack.js.map +1 -0
- package/packages/tallow-tui/dist/utils.d.ts +96 -0
- package/packages/tallow-tui/dist/utils.d.ts.map +1 -0
- package/packages/tallow-tui/dist/utils.js +843 -0
- package/packages/tallow-tui/dist/utils.js.map +1 -0
- package/packages/tallow-tui/package.json +24 -0
- package/packages/tallow-tui/src/__tests__/__snapshots__/render.test.ts.snap +121 -0
- package/packages/tallow-tui/src/__tests__/editor-border.test.ts +72 -0
- package/packages/tallow-tui/src/__tests__/editor-change-listener.test.ts +121 -0
- package/packages/tallow-tui/src/__tests__/editor-ghost-text.test.ts +112 -0
- package/packages/tallow-tui/src/__tests__/fuzzy.test.ts +91 -0
- package/packages/tallow-tui/src/__tests__/image-component.test.ts +113 -0
- package/packages/tallow-tui/src/__tests__/keys.test.ts +141 -0
- package/packages/tallow-tui/src/__tests__/render.test.ts +179 -0
- package/packages/tallow-tui/src/__tests__/stdin-buffer.test.ts +82 -0
- package/packages/tallow-tui/src/__tests__/terminal-image.test.ts +363 -0
- package/packages/tallow-tui/src/__tests__/tui-diff-regression.test.ts +454 -0
- package/packages/tallow-tui/src/__tests__/tui-render-scheduling.test.ts +256 -0
- package/packages/tallow-tui/src/__tests__/utils.test.ts +259 -0
- package/packages/tallow-tui/src/autocomplete.ts +716 -0
- package/packages/tallow-tui/src/border-styles.ts +60 -0
- package/packages/tallow-tui/src/components/bordered-box.ts +113 -0
- package/packages/tallow-tui/src/components/box.ts +137 -0
- package/packages/tallow-tui/src/components/cancellable-loader.ts +40 -0
- package/packages/tallow-tui/src/components/editor.ts +2143 -0
- package/packages/tallow-tui/src/components/image.ts +315 -0
- package/packages/tallow-tui/src/components/input.ts +522 -0
- package/packages/tallow-tui/src/components/loader.ts +187 -0
- package/packages/tallow-tui/src/components/markdown.ts +780 -0
- package/packages/tallow-tui/src/components/select-list.ts +197 -0
- package/packages/tallow-tui/src/components/settings-list.ts +264 -0
- package/packages/tallow-tui/src/components/spacer.ts +28 -0
- package/packages/tallow-tui/src/components/text.ts +113 -0
- package/packages/tallow-tui/src/components/truncated-text.ts +65 -0
- package/packages/tallow-tui/src/editor-component.ts +92 -0
- package/packages/tallow-tui/src/fuzzy.ts +133 -0
- package/packages/tallow-tui/src/index.ts +118 -0
- package/packages/tallow-tui/src/keybindings.ts +183 -0
- package/packages/tallow-tui/src/keys.ts +1189 -0
- package/packages/tallow-tui/src/kill-ring.ts +46 -0
- package/packages/tallow-tui/src/stdin-buffer.ts +386 -0
- package/packages/tallow-tui/src/terminal-image.ts +619 -0
- package/packages/tallow-tui/src/terminal.ts +350 -0
- package/packages/tallow-tui/src/test-utils/capability-env.ts +56 -0
- package/packages/tallow-tui/src/tui.ts +1336 -0
- package/packages/tallow-tui/src/undo-stack.ts +28 -0
- package/packages/tallow-tui/src/utils.ts +948 -0
- package/packages/tallow-tui/tsconfig.build.json +21 -0
- package/runtime/agent-runner.ts +20 -0
- package/runtime/atomic-write.ts +8 -0
- package/runtime/otel.ts +12 -0
- package/runtime/resolve-module.ts +23 -0
- package/runtime/runtime-path-provider.ts +12 -0
- package/runtime/runtime-provenance.ts +17 -0
- package/runtime/workspace-transition-relay.ts +21 -0
- package/runtime/workspace-transition.ts +29 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - `task_output` tool: Retrieve output from a background task
|
|
9
9
|
* - `task_status` tool: Check if a task is running or completed
|
|
10
10
|
* - `/bg` command: List and manage background tasks
|
|
11
|
-
* -
|
|
11
|
+
* - Live widget shows running background tasks when the tasks extension is not presenting them
|
|
12
12
|
*
|
|
13
13
|
* Usage:
|
|
14
14
|
* Ask the agent to "run npm test in the background"
|
|
@@ -25,9 +25,7 @@ import {
|
|
|
25
25
|
type Theme,
|
|
26
26
|
} from "@mariozechner/pi-coding-agent";
|
|
27
27
|
import {
|
|
28
|
-
Container,
|
|
29
28
|
Key,
|
|
30
|
-
Loader,
|
|
31
29
|
matchesKey,
|
|
32
30
|
Text,
|
|
33
31
|
type TUI,
|
|
@@ -35,7 +33,7 @@ import {
|
|
|
35
33
|
visibleWidth,
|
|
36
34
|
} from "@mariozechner/pi-tui";
|
|
37
35
|
import { Type } from "@sinclair/typebox";
|
|
38
|
-
import { getIcon
|
|
36
|
+
import { getIcon } from "../_icons/index.js";
|
|
39
37
|
import { extractPreview, isInlineResultsEnabled } from "../_shared/inline-preview.js";
|
|
40
38
|
import {
|
|
41
39
|
emitInteropEvent,
|
|
@@ -43,6 +41,7 @@ import {
|
|
|
43
41
|
INTEROP_EVENT_NAMES,
|
|
44
42
|
type InteropBackgroundTaskView,
|
|
45
43
|
onInteropEvent,
|
|
44
|
+
requestInteropState,
|
|
46
45
|
} from "../_shared/interop-events.js";
|
|
47
46
|
import { registerPid, unregisterPid } from "../_shared/pid-registry.js";
|
|
48
47
|
import {
|
|
@@ -128,15 +127,14 @@ let piRef: ExtensionAPI | null = null;
|
|
|
128
127
|
*/
|
|
129
128
|
const promotedAbortControllers = new Map<string, AbortController>();
|
|
130
129
|
|
|
131
|
-
// TUI reference captured at session_start for
|
|
130
|
+
// TUI reference captured at session_start for widgets
|
|
132
131
|
let tuiRef: TUI | null = null;
|
|
133
132
|
|
|
134
|
-
// Persistent Loader instances per streaming task (avoids leaking intervals)
|
|
135
|
-
const activeLoaders = new Map<string, InstanceType<typeof Loader>>();
|
|
136
|
-
|
|
137
133
|
// In-memory task registry (published via typed interop events)
|
|
138
134
|
const tasks = new Map<string, BackgroundTask>();
|
|
139
135
|
let taskCounter = 0;
|
|
136
|
+
let backgroundTaskPresenterActive = false;
|
|
137
|
+
let interopPresenterStateCleanup: (() => void) | undefined;
|
|
140
138
|
let interopStateRequestCleanup: (() => void) | undefined;
|
|
141
139
|
|
|
142
140
|
/** Shared mutable state for live-updating anchor components during consecutive polls. */
|
|
@@ -465,7 +463,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
465
463
|
piEventsRef = pi.events;
|
|
466
464
|
piRef = pi;
|
|
467
465
|
|
|
468
|
-
// Register inline result renderer for
|
|
466
|
+
// Register inline result renderer for background task completions
|
|
469
467
|
pi.registerMessageRenderer<BgTaskCompleteDetails>(
|
|
470
468
|
"background-task-complete",
|
|
471
469
|
(message, _options, theme) => {
|
|
@@ -511,10 +509,8 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
511
509
|
);
|
|
512
510
|
|
|
513
511
|
/**
|
|
514
|
-
* Post an inline notification when a
|
|
515
|
-
*
|
|
512
|
+
* Post an inline notification when a background task completes.
|
|
516
513
|
* Checks the inlineAgentResults setting before posting.
|
|
517
|
-
* Only fires for fire-and-forget tasks (background: true).
|
|
518
514
|
*
|
|
519
515
|
* @param task - Completed background task
|
|
520
516
|
* @returns void
|
|
@@ -544,12 +540,36 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
544
540
|
});
|
|
545
541
|
}
|
|
546
542
|
|
|
543
|
+
/** Debounce timer for widget updates during rapid output. */
|
|
544
|
+
let widgetDebounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
545
|
+
|
|
546
|
+
/** Minimum interval between widget re-renders (milliseconds). */
|
|
547
|
+
const WIDGET_DEBOUNCE_MS = 150;
|
|
548
|
+
|
|
549
|
+
/** Maximum tail lines per task in the widget. */
|
|
550
|
+
const WIDGET_TAIL_LINES = 3;
|
|
551
|
+
|
|
552
|
+
/** Most recent UI context used for widget/status updates. */
|
|
553
|
+
let lastWidgetContext: ExtensionContext | null = null;
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Whether the tasks extension currently owns background-task presentation.
|
|
557
|
+
*
|
|
558
|
+
* When true, background-task-tool suppresses its duplicate live widget and
|
|
559
|
+
* lets the tasks widget render the canonical summary row.
|
|
560
|
+
*
|
|
561
|
+
* @returns True when the tasks widget should be the only presenter
|
|
562
|
+
*/
|
|
563
|
+
function shouldSuppressTaskWidget(): boolean {
|
|
564
|
+
return backgroundTaskPresenterActive;
|
|
565
|
+
}
|
|
566
|
+
|
|
547
567
|
/**
|
|
548
568
|
* Updates the status bar indicator for running background tasks.
|
|
569
|
+
*
|
|
549
570
|
* @param ctx - Extension context for UI access
|
|
550
571
|
*/
|
|
551
|
-
function
|
|
552
|
-
// Guard: ctx.ui may be undefined if context is stale (e.g., from async callback after shutdown)
|
|
572
|
+
function updateStatusBar(ctx: ExtensionContext): void {
|
|
553
573
|
if (!ctx?.ui) return;
|
|
554
574
|
|
|
555
575
|
const running = [...tasks.values()].filter((t) => t.status === "running");
|
|
@@ -559,10 +579,62 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
559
579
|
return;
|
|
560
580
|
}
|
|
561
581
|
|
|
562
|
-
// Status bar only - widget is rendered by tasks extension
|
|
563
582
|
ctx.ui.setStatus("bg-tasks", `${FG_PURPLE}⚙ ${running.length} bg${RESET_ALL}`);
|
|
564
583
|
}
|
|
565
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Render the bottom widget showing live output from running background tasks.
|
|
587
|
+
* Shows each running task with a compact command preview and tail output.
|
|
588
|
+
* Placed above the editor so async work is visible without cluttering the chat.
|
|
589
|
+
*
|
|
590
|
+
* @param ctx - Extension context for widget access
|
|
591
|
+
*/
|
|
592
|
+
function updateTaskWidget(ctx: ExtensionContext): void {
|
|
593
|
+
if (!ctx?.ui) return;
|
|
594
|
+
|
|
595
|
+
const running = [...tasks.values()].filter((t) => t.status === "running");
|
|
596
|
+
|
|
597
|
+
if (running.length === 0 || shouldSuppressTaskWidget()) {
|
|
598
|
+
ctx.ui.setWidget("bg-tasks", undefined);
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const lines: string[] = [];
|
|
603
|
+
for (const task of running) {
|
|
604
|
+
const elapsed = formatDuration(Date.now() - task.startTime);
|
|
605
|
+
const cmd = truncateCommand(task.command, 50);
|
|
606
|
+
const lineCount = task.output.join("").split("\n").length;
|
|
607
|
+
const header = `${FG_PURPLE}⚙${RESET_ALL} ${FG_WHITE}${cmd}${RESET_ALL} ${FG_PURPLE_MUTED}(${elapsed}, ${lineCount} lines)${RESET_ALL}`;
|
|
608
|
+
lines.push(header);
|
|
609
|
+
|
|
610
|
+
// Show tail output lines
|
|
611
|
+
const fullOutput = task.output.join("");
|
|
612
|
+
if (fullOutput.length > 0) {
|
|
613
|
+
const outputLines = fullOutput.split("\n").filter((l) => l.trim().length > 0);
|
|
614
|
+
const tail = outputLines.slice(-WIDGET_TAIL_LINES);
|
|
615
|
+
for (const line of tail) {
|
|
616
|
+
const clean = line.length > 80 ? `${line.slice(0, 79)}…` : line;
|
|
617
|
+
lines.push(` ${FG_PURPLE_MUTED}│${RESET_ALL} ${FG_PURPLE_MUTED}${clean}${RESET_ALL}`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
ctx.ui.setWidget("bg-tasks", lines, { placement: "aboveEditor" });
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Debounced widget update — called from onData to avoid thrashing renders.
|
|
627
|
+
*
|
|
628
|
+
* @param ctx - Extension context for widget access
|
|
629
|
+
*/
|
|
630
|
+
function debouncedWidgetUpdate(ctx: ExtensionContext): void {
|
|
631
|
+
if (widgetDebounceTimer) return;
|
|
632
|
+
widgetDebounceTimer = setTimeout(() => {
|
|
633
|
+
widgetDebounceTimer = null;
|
|
634
|
+
updateTaskWidget(ctx);
|
|
635
|
+
}, WIDGET_DEBOUNCE_MS);
|
|
636
|
+
}
|
|
637
|
+
|
|
566
638
|
/**
|
|
567
639
|
* Sync background-task state to both local UI and cross-extension event consumers.
|
|
568
640
|
*
|
|
@@ -570,10 +642,25 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
570
642
|
* @returns void
|
|
571
643
|
*/
|
|
572
644
|
function syncTaskState(ctx: ExtensionContext): void {
|
|
573
|
-
|
|
645
|
+
lastWidgetContext = ctx;
|
|
646
|
+
updateStatusBar(ctx);
|
|
647
|
+
updateTaskWidget(ctx);
|
|
574
648
|
publishBackgroundTaskSnapshot(pi.events);
|
|
575
649
|
}
|
|
576
650
|
|
|
651
|
+
interopPresenterStateCleanup?.();
|
|
652
|
+
interopPresenterStateCleanup = onInteropEvent(
|
|
653
|
+
pi.events,
|
|
654
|
+
INTEROP_EVENT_NAMES.backgroundTasksPresenterState,
|
|
655
|
+
(payload) => {
|
|
656
|
+
backgroundTaskPresenterActive = payload.active;
|
|
657
|
+
const currentContext = lastWidgetContext;
|
|
658
|
+
if (currentContext?.ui) {
|
|
659
|
+
updateTaskWidget(currentContext);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
);
|
|
663
|
+
|
|
577
664
|
interopStateRequestCleanup?.();
|
|
578
665
|
interopStateRequestCleanup = onInteropEvent(pi.events, INTEROP_EVENT_NAMES.stateRequest, () => {
|
|
579
666
|
publishBackgroundTaskSnapshot(pi.events);
|
|
@@ -608,7 +695,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
608
695
|
name: "bg_bash",
|
|
609
696
|
label: "bg_bash",
|
|
610
697
|
description:
|
|
611
|
-
"Run a bash command in the background.
|
|
698
|
+
"Run a bash command in the background. Returns immediately without blocking. When the tasks extension is active, progress appears in the Background Tasks widget; otherwise background-task-tool shows its own live widget.\n\nWHEN TO USE:\n- Starting daemons or servers\n- Long-running builds or tests\n- Any process you want to run independently\n\nThe command runs asynchronously. Use task_status/task_output to check results.\n\nWARNING: Never use bash tool with & to background processes - it will hang. Use bg_bash instead.",
|
|
612
699
|
parameters: Type.Object({
|
|
613
700
|
command: Type.String({
|
|
614
701
|
description: "Bash command to run in background",
|
|
@@ -620,15 +707,13 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
620
707
|
),
|
|
621
708
|
background: Type.Optional(
|
|
622
709
|
Type.Boolean({
|
|
623
|
-
description:
|
|
624
|
-
"If true, return immediately without streaming output. Use for daemons/servers.",
|
|
710
|
+
description: "Deprecated — bg_bash always runs in background. Ignored.",
|
|
625
711
|
})
|
|
626
712
|
),
|
|
627
713
|
}),
|
|
628
|
-
async execute(_toolCallId, params,
|
|
714
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
629
715
|
const taskId = generateTaskId();
|
|
630
716
|
const cwd = ctx.cwd;
|
|
631
|
-
const fireAndForget = params.background === true;
|
|
632
717
|
|
|
633
718
|
const task: BackgroundTask = {
|
|
634
719
|
id: taskId,
|
|
@@ -658,7 +743,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
658
743
|
registerPid(child.pid, params.command);
|
|
659
744
|
}
|
|
660
745
|
|
|
661
|
-
// Buffer output
|
|
746
|
+
// Buffer output and update widget (never blocks the agent)
|
|
662
747
|
const onData = (data: Buffer) => {
|
|
663
748
|
// Guard: ignore data arriving after task is no longer running
|
|
664
749
|
if (task.status !== "running") return;
|
|
@@ -673,14 +758,8 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
673
758
|
}
|
|
674
759
|
}
|
|
675
760
|
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
const output = task.output.join("");
|
|
679
|
-
onUpdate?.({
|
|
680
|
-
content: [{ type: "text", text: output || "(no output yet)" }],
|
|
681
|
-
details: { taskId },
|
|
682
|
-
});
|
|
683
|
-
}
|
|
761
|
+
// Update the bottom widget with live output (debounced)
|
|
762
|
+
debouncedWidgetUpdate(ctx);
|
|
684
763
|
};
|
|
685
764
|
|
|
686
765
|
const lifecycle = createProcessLifecycle({
|
|
@@ -702,7 +781,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
702
781
|
task.process = null;
|
|
703
782
|
syncTaskState(ctx);
|
|
704
783
|
},
|
|
705
|
-
signal:
|
|
784
|
+
signal: undefined,
|
|
706
785
|
timeoutMs: params.timeout && params.timeout > 0 ? params.timeout * 1000 : undefined,
|
|
707
786
|
});
|
|
708
787
|
|
|
@@ -746,65 +825,25 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
746
825
|
syncTaskState(ctx);
|
|
747
826
|
};
|
|
748
827
|
|
|
749
|
-
//
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
type: result.type,
|
|
756
|
-
});
|
|
757
|
-
postInlineResult(task);
|
|
828
|
+
// Always non-blocking: return immediately, process runs in background
|
|
829
|
+
void lifecycle.waitForExit().then((result) => {
|
|
830
|
+
applyLifecycleResult({
|
|
831
|
+
...(result.type === "close" ? { code: result.code } : {}),
|
|
832
|
+
...(result.type === "error" ? { error: result.error } : {}),
|
|
833
|
+
type: result.type,
|
|
758
834
|
});
|
|
759
|
-
|
|
760
|
-
syncTaskState(ctx);
|
|
761
|
-
lastCompletedPoll = null;
|
|
762
|
-
|
|
763
|
-
return {
|
|
764
|
-
details: { taskId, command: params.command, fireAndForget: true },
|
|
765
|
-
content: [
|
|
766
|
-
{
|
|
767
|
-
type: "text",
|
|
768
|
-
text: `Background task started (fire-and-forget).\nTask ID: ${taskId}\nCommand: ${params.command}\nUse task_output("${taskId}") to check later.`,
|
|
769
|
-
},
|
|
770
|
-
],
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// Streaming mode: wait for process to complete
|
|
775
|
-
syncTaskState(ctx);
|
|
776
|
-
|
|
777
|
-
const lifecycleResult = await lifecycle.waitForExit();
|
|
778
|
-
applyLifecycleResult({
|
|
779
|
-
...(lifecycleResult.type === "close" ? { code: lifecycleResult.code } : {}),
|
|
780
|
-
...(lifecycleResult.type === "error" ? { error: lifecycleResult.error } : {}),
|
|
781
|
-
type: lifecycleResult.type,
|
|
835
|
+
postInlineResult(task);
|
|
782
836
|
});
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
const loader = activeLoaders.get(taskId);
|
|
786
|
-
if (loader) {
|
|
787
|
-
loader.stop();
|
|
788
|
-
activeLoaders.delete(taskId);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
const output = task.output.join("");
|
|
792
|
-
const duration = formatDuration((task.endTime || Date.now()) - task.startTime);
|
|
837
|
+
lifecycle.detach();
|
|
838
|
+
syncTaskState(ctx);
|
|
793
839
|
lastCompletedPoll = null;
|
|
794
840
|
|
|
795
841
|
return {
|
|
796
|
-
details: {
|
|
797
|
-
taskId,
|
|
798
|
-
command: params.command,
|
|
799
|
-
status: task.status,
|
|
800
|
-
duration,
|
|
801
|
-
exitCode: task.exitCode,
|
|
802
|
-
output,
|
|
803
|
-
},
|
|
842
|
+
details: { taskId, command: params.command },
|
|
804
843
|
content: [
|
|
805
844
|
{
|
|
806
845
|
type: "text",
|
|
807
|
-
text:
|
|
846
|
+
text: `Background task started.\nTask ID: ${taskId}\nCommand: ${params.command}\nUse task_status("${taskId}") to check progress.\nUse task_output("${taskId}") to retrieve output.`,
|
|
808
847
|
},
|
|
809
848
|
],
|
|
810
849
|
};
|
|
@@ -812,149 +851,22 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
812
851
|
|
|
813
852
|
renderCall(args, theme) {
|
|
814
853
|
const cmd = truncateCommand(args.command as string, 60);
|
|
815
|
-
const bg = args.background ? formatPresentationText(theme, "meta", " (detached)") : "";
|
|
816
854
|
return new Text(
|
|
817
855
|
formatPresentationText(theme, "title", "bg_bash ") +
|
|
818
|
-
formatPresentationText(theme, "action", cmd)
|
|
819
|
-
bg,
|
|
856
|
+
formatPresentationText(theme, "action", cmd),
|
|
820
857
|
0,
|
|
821
858
|
0
|
|
822
859
|
);
|
|
823
860
|
},
|
|
824
861
|
|
|
825
|
-
renderResult(result,
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
}
|
|
834
|
-
| undefined;
|
|
835
|
-
|
|
836
|
-
// Fire-and-forget: compact one-liner
|
|
837
|
-
if (details?.fireAndForget) {
|
|
838
|
-
return renderLines([
|
|
839
|
-
formatPresentationText(theme, "status_success", "⚙ Started (detached)"),
|
|
840
|
-
]);
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
const COLLAPSED_LINES = 10;
|
|
844
|
-
const EXPANDED_LINES = 50;
|
|
845
|
-
|
|
846
|
-
// Extract output (available during streaming via onUpdate and after completion)
|
|
847
|
-
const text = result.content[0];
|
|
848
|
-
const output = text?.type === "text" ? text.text : "";
|
|
849
|
-
|
|
850
|
-
// While running: show streamed output + loader spinner at bottom
|
|
851
|
-
if (isPartial) {
|
|
852
|
-
const container = new Container();
|
|
853
|
-
|
|
854
|
-
if (output) {
|
|
855
|
-
const allLines = output.split("\n").filter((l: string) => l.length > 0);
|
|
856
|
-
const maxLines = COLLAPSED_LINES;
|
|
857
|
-
const truncated = allLines.length > maxLines;
|
|
858
|
-
const tail = truncated ? allLines.slice(-maxLines) : allLines;
|
|
859
|
-
const lines: string[] = [];
|
|
860
|
-
if (truncated) {
|
|
861
|
-
appendSection(lines, [
|
|
862
|
-
formatPresentationText(
|
|
863
|
-
theme,
|
|
864
|
-
"meta",
|
|
865
|
-
`... ${allLines.length - maxLines} more lines above`
|
|
866
|
-
),
|
|
867
|
-
]);
|
|
868
|
-
}
|
|
869
|
-
appendSection(
|
|
870
|
-
lines,
|
|
871
|
-
tail.map((line) => styleBackgroundOutputLine(theme, line))
|
|
872
|
-
);
|
|
873
|
-
container.addChild(renderLines(lines, { wrap: true }));
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// Reuse persistent Loader (one per task, avoids leaking intervals)
|
|
877
|
-
const tid = details?.taskId ?? "__bg_default";
|
|
878
|
-
let loader = activeLoaders.get(tid);
|
|
879
|
-
if (!loader && tuiRef) {
|
|
880
|
-
loader = new Loader(
|
|
881
|
-
tuiRef,
|
|
882
|
-
(s) => theme.fg("warning", s),
|
|
883
|
-
(s) => theme.fg("muted", s),
|
|
884
|
-
"Running..."
|
|
885
|
-
);
|
|
886
|
-
(loader as unknown as Record<string, string[]>).frames = getSpinner();
|
|
887
|
-
activeLoaders.set(tid, loader);
|
|
888
|
-
}
|
|
889
|
-
if (loader) {
|
|
890
|
-
container.addChild(loader);
|
|
891
|
-
} else {
|
|
892
|
-
container.addChild(
|
|
893
|
-
new Text(formatPresentationText(theme, "status_warning", "Running..."), 0, 0)
|
|
894
|
-
);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
return container;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
// Completed: show output
|
|
901
|
-
if (!output) return renderLines([formatPresentationText(theme, "meta", "(no output)")]);
|
|
902
|
-
|
|
903
|
-
const allLines = output.split("\n").filter((l: string) => l.length > 0);
|
|
904
|
-
const maxLines = expanded ? EXPANDED_LINES : COLLAPSED_LINES;
|
|
905
|
-
const truncated = allLines.length > maxLines;
|
|
906
|
-
const tail = truncated ? allLines.slice(-maxLines) : allLines;
|
|
907
|
-
const lines: string[] = [];
|
|
908
|
-
|
|
909
|
-
if (truncated) {
|
|
910
|
-
appendSection(lines, [
|
|
911
|
-
formatPresentationText(
|
|
912
|
-
theme,
|
|
913
|
-
"meta",
|
|
914
|
-
`... ${allLines.length - maxLines} more lines above`
|
|
915
|
-
),
|
|
916
|
-
]);
|
|
917
|
-
}
|
|
918
|
-
appendSection(
|
|
919
|
-
lines,
|
|
920
|
-
tail.map((line) => styleBackgroundOutputLine(theme, line))
|
|
921
|
-
);
|
|
922
|
-
if (truncated && !expanded) {
|
|
923
|
-
appendSection(lines, [
|
|
924
|
-
`${formatPresentationText(theme, "meta", `... ${allLines.length - maxLines} more lines`)} ${formatPresentationText(theme, "hint", keyHint("expandTools", "to expand"))}`,
|
|
925
|
-
]);
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
if (details?.status) {
|
|
929
|
-
const statusIcon =
|
|
930
|
-
details.status === "completed"
|
|
931
|
-
? getIcon("success")
|
|
932
|
-
: details.status === "running"
|
|
933
|
-
? getIcon("in_progress")
|
|
934
|
-
: getIcon("error");
|
|
935
|
-
const statusRole =
|
|
936
|
-
details.status === "completed"
|
|
937
|
-
? "status_success"
|
|
938
|
-
: details.status === "running"
|
|
939
|
-
? "status_warning"
|
|
940
|
-
: "status_error";
|
|
941
|
-
const statusMetaParts: string[] = [];
|
|
942
|
-
if (details.exitCode !== null && details.exitCode !== undefined) {
|
|
943
|
-
statusMetaParts.push(`exit ${details.exitCode}`);
|
|
944
|
-
}
|
|
945
|
-
if (details.duration) statusMetaParts.push(details.duration);
|
|
946
|
-
const statusMeta = statusMetaParts.length > 0 ? ` (${statusMetaParts.join(", ")})` : "";
|
|
947
|
-
appendSection(
|
|
948
|
-
lines,
|
|
949
|
-
[
|
|
950
|
-
formatPresentationText(theme, statusRole, `${statusIcon} bg_bash ${details.status}`) +
|
|
951
|
-
formatPresentationText(theme, "meta", statusMeta),
|
|
952
|
-
],
|
|
953
|
-
{ blankBefore: true }
|
|
954
|
-
);
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
return renderLines(lines, { wrap: expanded });
|
|
862
|
+
renderResult(result, _opts, theme) {
|
|
863
|
+
// bg_bash always returns immediately — compact one-liner
|
|
864
|
+
const details = result.details as { taskId?: string; command?: string } | undefined;
|
|
865
|
+
const taskId = details?.taskId ?? "?";
|
|
866
|
+
return renderLines([
|
|
867
|
+
formatPresentationText(theme, "status_success", `⚙ Started`) +
|
|
868
|
+
formatPresentationText(theme, "meta", ` → task_output("${taskId}")`),
|
|
869
|
+
]);
|
|
958
870
|
},
|
|
959
871
|
});
|
|
960
872
|
|
|
@@ -1807,23 +1719,29 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
|
|
|
1807
1719
|
promotedAbortControllers.clear();
|
|
1808
1720
|
pollStates.clear();
|
|
1809
1721
|
lastCompletedPoll = null;
|
|
1722
|
+
backgroundTaskPresenterActive = false;
|
|
1723
|
+
lastWidgetContext = null;
|
|
1810
1724
|
publishBackgroundTaskSnapshot(pi.events);
|
|
1725
|
+
interopPresenterStateCleanup?.();
|
|
1726
|
+
interopPresenterStateCleanup = undefined;
|
|
1811
1727
|
interopStateRequestCleanup?.();
|
|
1812
1728
|
interopStateRequestCleanup = undefined;
|
|
1813
1729
|
});
|
|
1814
1730
|
|
|
1815
|
-
// Capture TUI reference and
|
|
1731
|
+
// Capture TUI reference and initialize on session start
|
|
1816
1732
|
pi.on("session_start", async (_event, ctx) => {
|
|
1817
|
-
|
|
1733
|
+
backgroundTaskPresenterActive = false;
|
|
1734
|
+
|
|
1735
|
+
// Capture TUI via a throwaway widget for requestRender access
|
|
1818
1736
|
ctx.ui.setWidget("bg-tasks-tui-capture", (tui, _theme) => {
|
|
1819
1737
|
tuiRef = tui;
|
|
1820
1738
|
return { render: () => [], invalidate: () => {} };
|
|
1821
1739
|
});
|
|
1822
|
-
// Immediately remove — we just needed the reference
|
|
1823
1740
|
ctx.ui.setWidget("bg-tasks-tui-capture", undefined);
|
|
1824
1741
|
|
|
1825
1742
|
ctx.ui.setStatus("bg-tasks", undefined);
|
|
1826
1743
|
syncTaskState(ctx);
|
|
1744
|
+
requestInteropState(pi.events, "background-task-tool");
|
|
1827
1745
|
});
|
|
1828
1746
|
|
|
1829
1747
|
// Register Ctrl+Shift+B shortcut for background tasks
|
|
@@ -185,15 +185,6 @@ function handleBashError(err: unknown): AgentToolResult<BashToolDetails | undefi
|
|
|
185
185
|
throw err;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
/** Maximum number of output tail lines shown in the working message. */
|
|
189
|
-
const PROGRESS_TAIL_LINES = 3;
|
|
190
|
-
|
|
191
|
-
/** Maximum character width per progress line before truncation. */
|
|
192
|
-
const PROGRESS_LINE_WIDTH = 60;
|
|
193
|
-
|
|
194
|
-
/** Minimum interval between working message updates (milliseconds). */
|
|
195
|
-
const PROGRESS_DEBOUNCE_MS = 100;
|
|
196
|
-
|
|
197
188
|
/** Visual prefix for output lines in the progress message. */
|
|
198
189
|
const PROGRESS_LINE_PREFIX = "│ ";
|
|
199
190
|
|
|
@@ -380,75 +371,14 @@ export default function bashLive(pi: ExtensionAPI): void {
|
|
|
380
371
|
}
|
|
381
372
|
|
|
382
373
|
const cmd = params.command ?? "";
|
|
383
|
-
const firstLine = cmd.split("\n")[0];
|
|
384
|
-
const preview = firstLine.length > 60 ? `${firstLine.slice(0, 57)}...` : firstLine;
|
|
385
|
-
ctx.ui.setWorkingMessage(`Bash: ${preview}`);
|
|
386
|
-
|
|
387
|
-
// Progress: surface output tail in the working message area
|
|
388
|
-
let lastProgressTime = 0;
|
|
389
|
-
let progressTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Debounced update of the working message with the latest output tail.
|
|
393
|
-
*
|
|
394
|
-
* @param text - Full output text so far
|
|
395
|
-
*/
|
|
396
|
-
const updateProgress = (text: string): void => {
|
|
397
|
-
const now = Date.now();
|
|
398
|
-
const doUpdate = (): void => {
|
|
399
|
-
lastProgressTime = Date.now();
|
|
400
|
-
const tail = extractTailLines(text, PROGRESS_TAIL_LINES);
|
|
401
|
-
ctx.ui.setWorkingMessage(formatProgressMessage(preview, tail, PROGRESS_LINE_WIDTH));
|
|
402
|
-
};
|
|
403
|
-
if (now - lastProgressTime >= PROGRESS_DEBOUNCE_MS) {
|
|
404
|
-
if (progressTimeout) {
|
|
405
|
-
clearTimeout(progressTimeout);
|
|
406
|
-
progressTimeout = null;
|
|
407
|
-
}
|
|
408
|
-
doUpdate();
|
|
409
|
-
} else if (!progressTimeout) {
|
|
410
|
-
progressTimeout = setTimeout(
|
|
411
|
-
() => {
|
|
412
|
-
progressTimeout = null;
|
|
413
|
-
doUpdate();
|
|
414
|
-
},
|
|
415
|
-
PROGRESS_DEBOUNCE_MS - (now - lastProgressTime)
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
/** Clear any pending progress update timeout. */
|
|
421
|
-
const clearProgressTimeout = (): void => {
|
|
422
|
-
if (progressTimeout) {
|
|
423
|
-
clearTimeout(progressTimeout);
|
|
424
|
-
progressTimeout = null;
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Wraps onUpdate to surface output progress in the working message.
|
|
430
|
-
*
|
|
431
|
-
* @param partialResult - Partial tool result from bash execution
|
|
432
|
-
*/
|
|
433
|
-
const progressOnUpdate: typeof onUpdate = (partialResult) => {
|
|
434
|
-
onUpdate?.(partialResult);
|
|
435
|
-
const text = partialResult?.content?.find((c: { type: string }) => c.type === "text") as
|
|
436
|
-
| { text: string }
|
|
437
|
-
| undefined;
|
|
438
|
-
if (text?.text) updateProgress(text.text);
|
|
439
|
-
};
|
|
440
|
-
|
|
441
374
|
const autoTimeout = readAutoBackgroundTimeout();
|
|
442
375
|
|
|
443
376
|
// Fast path: auto-background disabled or user-provided timeout shorter
|
|
444
377
|
if (autoTimeout <= 0 || (params.timeout && params.timeout * 1000 <= autoTimeout)) {
|
|
445
378
|
try {
|
|
446
|
-
return await scopedBashTool.execute(toolCallId, params, signal,
|
|
379
|
+
return await scopedBashTool.execute(toolCallId, params, signal, onUpdate);
|
|
447
380
|
} catch (err) {
|
|
448
381
|
return handleBashError(err);
|
|
449
|
-
} finally {
|
|
450
|
-
clearProgressTimeout();
|
|
451
|
-
ctx.ui.setWorkingMessage();
|
|
452
382
|
}
|
|
453
383
|
}
|
|
454
384
|
|
|
@@ -481,8 +411,6 @@ export default function bashLive(pi: ExtensionAPI): void {
|
|
|
481
411
|
if (text?.text) promotedHandle.replaceOutput(text.text);
|
|
482
412
|
} else {
|
|
483
413
|
onUpdate?.(partialResult);
|
|
484
|
-
// Update progress message while still in foreground
|
|
485
|
-
if (text?.text) updateProgress(text.text);
|
|
486
414
|
}
|
|
487
415
|
};
|
|
488
416
|
|
|
@@ -503,8 +431,6 @@ export default function bashLive(pi: ExtensionAPI): void {
|
|
|
503
431
|
});
|
|
504
432
|
|
|
505
433
|
const winner = await Promise.race([bashPromise, timeoutPromise]);
|
|
506
|
-
clearProgressTimeout();
|
|
507
|
-
ctx.ui.setWorkingMessage();
|
|
508
434
|
|
|
509
435
|
if (winner.type === "completed") {
|
|
510
436
|
return winner.result;
|
|
@@ -14,11 +14,11 @@ import type {
|
|
|
14
14
|
ExtensionContext,
|
|
15
15
|
} from "@mariozechner/pi-coding-agent";
|
|
16
16
|
import { Type } from "@sinclair/typebox";
|
|
17
|
-
import { getWorkspaceTransitionHost } from "../../
|
|
17
|
+
import { getWorkspaceTransitionHost } from "../../runtime/workspace-transition.js";
|
|
18
18
|
import {
|
|
19
19
|
getRelaySocketPath,
|
|
20
20
|
requestTransitionViaRelay,
|
|
21
|
-
} from "../../
|
|
21
|
+
} from "../../runtime/workspace-transition-relay.js";
|
|
22
22
|
import { getTallowSettingsPath } from "../_shared/tallow-paths.js";
|
|
23
23
|
|
|
24
24
|
/** Details returned from the cd tool. */
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
import * as fs from "node:fs";
|
|
10
10
|
import * as os from "node:os";
|
|
11
11
|
import * as path from "node:path";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_AGENT_RUNNER_ENV,
|
|
14
|
+
spawnWithResolvedAgentRunner,
|
|
15
|
+
} from "../../runtime/agent-runner.js";
|
|
13
16
|
import { expandFileReferences } from "../file-reference/index.js";
|
|
14
17
|
|
|
15
18
|
/** Configuration for spawning a forked subprocess. */
|