@astralyn/pi 0.84.5 → 0.84.7
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/CHANGELOG.md +35 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/extensions/background/index.d.ts +95 -20
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +470 -136
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/background/manager.d.ts +14 -0
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +125 -24
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/registry.d.ts +82 -0
- package/dist/extensions/background/registry.d.ts.map +1 -1
- package/dist/extensions/background/registry.js +237 -6
- package/dist/extensions/background/registry.js.map +1 -1
- package/dist/extensions/background/render.d.ts +35 -11
- package/dist/extensions/background/render.d.ts.map +1 -1
- package/dist/extensions/background/render.js +180 -30
- package/dist/extensions/background/render.js.map +1 -1
- package/dist/extensions/router/dialog-host.d.ts +60 -0
- package/dist/extensions/router/dialog-host.d.ts.map +1 -0
- package/dist/extensions/router/dialog-host.js +196 -0
- package/dist/extensions/router/dialog-host.js.map +1 -0
- package/dist/extensions/router/probe.d.ts.map +1 -1
- package/dist/extensions/router/probe.js +2 -0
- package/dist/extensions/router/probe.js.map +1 -1
- package/dist/extensions/router/ui.d.ts.map +1 -1
- package/dist/extensions/router/ui.js +117 -67
- package/dist/extensions/router/ui.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +3 -5
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +8 -89
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
- package/dist/extensions/subagent/agents-command.js +391 -161
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts +2 -0
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +7 -1
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/budget.d.ts +15 -0
- package/dist/extensions/subagent/budget.d.ts.map +1 -0
- package/dist/extensions/subagent/budget.js +96 -0
- package/dist/extensions/subagent/budget.js.map +1 -0
- package/dist/extensions/subagent/cancellation.d.ts +29 -0
- package/dist/extensions/subagent/cancellation.d.ts.map +1 -0
- package/dist/extensions/subagent/cancellation.js +73 -0
- package/dist/extensions/subagent/cancellation.js.map +1 -0
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +5 -22
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/model-selection.d.ts +16 -0
- package/dist/extensions/subagent/model-selection.d.ts.map +1 -0
- package/dist/extensions/subagent/model-selection.js +51 -0
- package/dist/extensions/subagent/model-selection.js.map +1 -0
- package/dist/extensions/subagent/render.d.ts +6 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +23 -12
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +2 -21
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +4 -5
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +71 -264
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts +13 -11
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +167 -148
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +11 -4
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/state.d.ts +89 -0
- package/dist/extensions/subagent/state.d.ts.map +1 -0
- package/dist/extensions/subagent/state.js +294 -0
- package/dist/extensions/subagent/state.js.map +1 -0
- package/dist/extensions/subagent/text.d.ts +4 -0
- package/dist/extensions/subagent/text.d.ts.map +1 -1
- package/dist/extensions/subagent/text.js +75 -0
- package/dist/extensions/subagent/text.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +3 -8
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/subagent/ui/choices.d.ts +36 -0
- package/dist/extensions/subagent/ui/choices.d.ts.map +1 -0
- package/dist/extensions/subagent/ui/choices.js +54 -0
- package/dist/extensions/subagent/ui/choices.js.map +1 -0
- package/dist/extensions/subagent/ui/model-list.d.ts +1 -0
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +15 -18
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/background.md +55 -20
- package/docs/extensions.md +13 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/extensions/subagent/retry.d.ts +0 -17
- package/dist/extensions/subagent/retry.d.ts.map +0 -1
- package/dist/extensions/subagent/retry.js +0 -41
- package/dist/extensions/subagent/retry.js.map +0 -1
|
@@ -1,20 +1,63 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Transcript rendering for the background extension:
|
|
3
|
-
*
|
|
4
|
-
* presentation: a `$` prompt row
|
|
2
|
+
* Transcript rendering for the background extension: the single bg tool's
|
|
3
|
+
* call/result rows (dispatched on action) and the completion-notification
|
|
4
|
+
* message. Style follows the built-in bash presentation: a `$` prompt row
|
|
5
|
+
* with an `&` marker for the background call.
|
|
5
6
|
*/
|
|
6
7
|
import { Container, Text, TruncatedText } from "@earendil-works/pi-tui";
|
|
8
|
+
import { formatSize } from "../../core/tools/truncate.js";
|
|
7
9
|
import { highlightCode } from "../../modes/interactive/theme/theme.js";
|
|
8
|
-
import { firstCommandLine, formatDuration } from "./registry.js";
|
|
10
|
+
import { BG_WAIT_DEFAULT_MS, BG_WAIT_MAX_MS, BG_WAIT_MIN_MS, firstCommandLine, formatDuration, } from "./registry.js";
|
|
9
11
|
const COMMAND_PREVIEW_LIMIT = 120;
|
|
10
12
|
const NOTIFY_TAIL_LIMIT = 4000;
|
|
13
|
+
/** Cap for expanded transcript views of tool-result text (already bounded at the source). */
|
|
14
|
+
const RESULT_EXPAND_LIMIT = 4000;
|
|
15
|
+
/** Live pending-wait line refresh cadence; the first settled render clears the timer. */
|
|
16
|
+
const WAIT_REFRESH_MS = 1000;
|
|
17
|
+
/**
|
|
18
|
+
* Arm a one-shot 1s refresh while a wait call is pending, clear it once
|
|
19
|
+
* settled. The timer fires → context.invalidate() → renderCall re-runs →
|
|
20
|
+
* re-arms, so at most one armed timer exists per tool row. Unref'd: it can
|
|
21
|
+
* never hold the process open.
|
|
22
|
+
*/
|
|
23
|
+
export function scheduleWaitRefresh(context, pending) {
|
|
24
|
+
const state = context.state;
|
|
25
|
+
if (state === undefined)
|
|
26
|
+
return; // Standalone render without shell state: nothing to schedule.
|
|
27
|
+
if (pending) {
|
|
28
|
+
if (state.refreshTimer === undefined) {
|
|
29
|
+
state.refreshTimer = setTimeout(() => {
|
|
30
|
+
state.refreshTimer = undefined;
|
|
31
|
+
context.invalidate();
|
|
32
|
+
}, WAIT_REFRESH_MS);
|
|
33
|
+
state.refreshTimer.unref?.();
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (state.refreshTimer !== undefined) {
|
|
38
|
+
clearTimeout(state.refreshTimer);
|
|
39
|
+
state.refreshTimer = undefined;
|
|
40
|
+
}
|
|
41
|
+
state.waitStartedAt = undefined;
|
|
42
|
+
state.waitBaselineBytes = undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Basename of a path, slash-normalized — compact display of output files. */
|
|
45
|
+
export function fileNameOf(path) {
|
|
46
|
+
return path.replace(/\\/g, "/").split("/").at(-1) ?? path;
|
|
47
|
+
}
|
|
11
48
|
function bgPrompt(theme) {
|
|
12
49
|
return theme.fg("toolTitle", theme.bold("$ "));
|
|
13
50
|
}
|
|
14
51
|
function timeoutSuffix(timeout, theme) {
|
|
15
52
|
return timeout ? theme.fg("muted", ` (timeout ${timeout}s)`) : "";
|
|
16
53
|
}
|
|
17
|
-
|
|
54
|
+
/** Keep the END of oversized text — that is where the outcome lives. */
|
|
55
|
+
function capForTranscript(text, limit) {
|
|
56
|
+
return text.length > limit ? `…${text.slice(-limit)}` : text;
|
|
57
|
+
}
|
|
58
|
+
export function statusGlyph(status, stalled) {
|
|
59
|
+
if (stalled)
|
|
60
|
+
return "…";
|
|
18
61
|
switch (status) {
|
|
19
62
|
case "completed":
|
|
20
63
|
return "✓";
|
|
@@ -27,7 +70,9 @@ export function statusGlyph(status) {
|
|
|
27
70
|
return "●";
|
|
28
71
|
}
|
|
29
72
|
}
|
|
30
|
-
export function statusColor(status) {
|
|
73
|
+
export function statusColor(status, stalled) {
|
|
74
|
+
if (stalled)
|
|
75
|
+
return "warning";
|
|
31
76
|
switch (status) {
|
|
32
77
|
case "completed":
|
|
33
78
|
return "success";
|
|
@@ -45,9 +90,72 @@ export function commandLabel(command, width) {
|
|
|
45
90
|
const characters = [...firstCommandLine(command)];
|
|
46
91
|
return characters.length <= width ? characters.join("") : `${characters.slice(0, Math.max(0, width - 1)).join("")}…`;
|
|
47
92
|
}
|
|
48
|
-
|
|
93
|
+
// ── tool call ─────────────────────────────────────────────────────────────
|
|
94
|
+
export function renderBgCall(args, theme, context, getTaskLive) {
|
|
95
|
+
switch (args.action) {
|
|
96
|
+
case "create":
|
|
97
|
+
return typeof args.command === "string"
|
|
98
|
+
? renderCreateCall(args, theme, context)
|
|
99
|
+
: new Text(theme.fg("toolTitle", theme.bold("bg create")), 0, 0);
|
|
100
|
+
case "read": {
|
|
101
|
+
const mode = args.mode ?? "tail";
|
|
102
|
+
const size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : "";
|
|
103
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg read "))}${theme.fg("accent", args.taskId ?? "")}${theme.fg("muted", ` ${mode}${size}`)}`, 0, 0);
|
|
104
|
+
}
|
|
105
|
+
case "wait":
|
|
106
|
+
return renderWaitCall(args, theme, context, getTaskLive);
|
|
107
|
+
case "kill":
|
|
108
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg kill "))}${theme.fg("accent", args.taskId ?? "")}`, 0, 0);
|
|
109
|
+
case "list":
|
|
110
|
+
return new Text(theme.fg("toolTitle", theme.bold("bg list")), 0, 0);
|
|
111
|
+
default: {
|
|
112
|
+
// Tool arguments arrive incrementally while the model is still emitting
|
|
113
|
+
// JSON. Keep the call row renderable until `action` becomes valid.
|
|
114
|
+
const action = typeof args.action === "string" ? ` ${theme.fg("dim", args.action)}` : "";
|
|
115
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg"))}${action}`, 0, 0);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Mirror the execution-side clamp so the shown window matches the real one. */
|
|
120
|
+
export function clampWaitMs(waitMs) {
|
|
121
|
+
return Math.min(BG_WAIT_MAX_MS, Math.max(BG_WAIT_MIN_MS, Math.floor(waitMs ?? BG_WAIT_DEFAULT_MS)));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Pending wait call: elapsed/wait-window and the new-output delta since the
|
|
125
|
+
* wait began, refreshed once per second by scheduleWaitRefresh until the
|
|
126
|
+
* result settles and takes over the row.
|
|
127
|
+
*/
|
|
128
|
+
function renderWaitCall(args, theme, context, getTaskLive) {
|
|
129
|
+
const taskId = typeof args.taskId === "string" ? args.taskId.trim() : "";
|
|
130
|
+
const live = getTaskLive !== undefined && taskId ? getTaskLive(taskId) : undefined;
|
|
131
|
+
// The live display needs shell-owned state; without it (standalone renders)
|
|
132
|
+
// fall back to the static line.
|
|
133
|
+
const pending = context.isPartial === true && context.state !== undefined && taskId.length > 0;
|
|
134
|
+
scheduleWaitRefresh(context, pending);
|
|
135
|
+
if (!pending) {
|
|
136
|
+
const ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : "";
|
|
137
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg wait "))}${theme.fg("accent", args.taskId ?? "")}${theme.fg("muted", ms)}`, 0, 0);
|
|
138
|
+
}
|
|
139
|
+
const state = context.state;
|
|
140
|
+
if (state.waitStartedAt === undefined)
|
|
141
|
+
state.waitStartedAt = Date.now();
|
|
142
|
+
const startedAt = state.waitStartedAt;
|
|
143
|
+
let liveBase;
|
|
144
|
+
if (live) {
|
|
145
|
+
if (state.waitBaselineBytes === undefined)
|
|
146
|
+
state.waitBaselineBytes = live.outputBytes;
|
|
147
|
+
liveBase = state.waitBaselineBytes;
|
|
148
|
+
}
|
|
149
|
+
const parts = [`waiting ${formatDuration(Date.now() - startedAt)}/${formatDuration(clampWaitMs(args.waitMs))}`];
|
|
150
|
+
if (live && live.status === "running" && liveBase !== undefined && live.outputBytes > liveBase) {
|
|
151
|
+
parts.push(`+${formatSize(live.outputBytes - liveBase)} new output`);
|
|
152
|
+
}
|
|
153
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg wait "))}${theme.fg("accent", taskId)} ${theme.fg("muted", parts.join(" · "))}`, 0, 0);
|
|
154
|
+
}
|
|
155
|
+
function renderCreateCall(args, theme, context) {
|
|
49
156
|
const lines = args.command.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
50
|
-
const
|
|
157
|
+
const label = args.description ? theme.fg("muted", ` · ${args.description}`) : "";
|
|
158
|
+
const suffix = theme.fg("muted", " &") + timeoutSuffix(args.timeout, theme) + label;
|
|
51
159
|
if (context.expanded && lines.length > 1) {
|
|
52
160
|
const body = highlightCode(args.command, "bash").join("\n");
|
|
53
161
|
return new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);
|
|
@@ -60,35 +168,74 @@ export function renderBgBashCall(args, theme, context) {
|
|
|
60
168
|
}
|
|
61
169
|
return new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);
|
|
62
170
|
}
|
|
63
|
-
|
|
64
|
-
|
|
171
|
+
// ── tool result ───────────────────────────────────────────────────────────
|
|
172
|
+
export function renderBgResult(result, options, theme, context) {
|
|
173
|
+
// bg results are always settled today; clear defensively so no live-refresh
|
|
174
|
+
// timer can outlive its row if a host ever streams partial results.
|
|
175
|
+
if (context.args?.action === "wait" && !options.isPartial)
|
|
176
|
+
scheduleWaitRefresh(context, false);
|
|
177
|
+
const details = result.details;
|
|
178
|
+
if (context.isError || !details) {
|
|
65
179
|
const text = result.content.find((part) => part.type === "text")?.text ?? "";
|
|
66
180
|
return new Text(theme.fg("toolOutput", text.trimEnd()), 0, 0);
|
|
67
181
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const size = args.bytes !== undefined ? ` ${args.bytes}B` : "";
|
|
77
|
-
return new Text(`${theme.fg("toolTitle", theme.bold("bg logs "))}${theme.fg("accent", args.taskId)}${theme.fg("muted", ` ${mode}${size}`)}`, 0, 0);
|
|
182
|
+
const container = new Container();
|
|
183
|
+
container.addChild(new TruncatedText(resultSummaryLine(details, theme), 1, 0));
|
|
184
|
+
if (options.expanded) {
|
|
185
|
+
const text = result.content.find((part) => part.type === "text")?.text ?? "";
|
|
186
|
+
container.addChild(new Text("", 0, 0));
|
|
187
|
+
container.addChild(new Text(theme.fg("toolOutput", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));
|
|
188
|
+
}
|
|
189
|
+
return container;
|
|
78
190
|
}
|
|
79
|
-
|
|
80
|
-
|
|
191
|
+
function resultSummaryLine(details, theme) {
|
|
192
|
+
switch (details.action) {
|
|
193
|
+
case "create": {
|
|
194
|
+
const label = details.description ? ` (${details.description})` : "";
|
|
195
|
+
return `${theme.fg("muted", "→ task ")}${theme.fg("accent", `${details.taskId}${label}`)}${theme.fg("muted", ` started · ${details.outputPath}`)}`;
|
|
196
|
+
}
|
|
197
|
+
case "read": {
|
|
198
|
+
const size = details.sliceBytes !== details.totalBytes
|
|
199
|
+
? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`
|
|
200
|
+
: formatSize(details.totalBytes);
|
|
201
|
+
return `${theme.fg("muted", "→ ")}${theme.fg("accent", details.taskId)}${theme.fg("muted", ` ${size} · ${details.outputPath}`)}`;
|
|
202
|
+
}
|
|
203
|
+
case "wait": {
|
|
204
|
+
if (details.timedOut) {
|
|
205
|
+
return `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg("accent", details.taskId)}${theme.fg("muted", ` still running · waited ${formatDuration(details.waitedMs)} · ${formatSize(details.totalBytes)}`)}`;
|
|
206
|
+
}
|
|
207
|
+
const exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : "";
|
|
208
|
+
return `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg("accent", details.taskId)}${theme.fg("muted", ` ${details.status}${exit} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;
|
|
209
|
+
}
|
|
210
|
+
case "kill":
|
|
211
|
+
return `${theme.fg(statusColor("killed"), statusGlyph("killed"))} ${theme.fg("accent", details.taskId)}${theme.fg("muted", " stopped")}`;
|
|
212
|
+
case "list": {
|
|
213
|
+
const hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : "";
|
|
214
|
+
return theme.fg("muted", `${details.running} running · ${details.finished} finished${hidden}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
81
217
|
}
|
|
218
|
+
// ── completion notification ───────────────────────────────────────────────
|
|
82
219
|
/** One-line summary of a finished task, shared by the notification renderer. */
|
|
83
220
|
function taskSummaryLine(details, theme) {
|
|
84
221
|
const runtime = formatDuration(details.runtimeMs);
|
|
85
222
|
const exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : "";
|
|
223
|
+
if (details.stalled) {
|
|
224
|
+
const glyph = theme.fg("warning", "…");
|
|
225
|
+
const label = details.description
|
|
226
|
+
? `${details.description} (${commandLabel(details.command, 40)})`
|
|
227
|
+
: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);
|
|
228
|
+
return `${glyph} ${theme.fg("accent", details.taskId)} ${label} ${theme.fg("muted", `— waiting for input (${runtime})`)}`;
|
|
229
|
+
}
|
|
86
230
|
const outcome = theme.fg(statusColor(details.status), `${details.status}${exit} in ${runtime}`);
|
|
87
231
|
const glyph = theme.fg(statusColor(details.status), statusGlyph(details.status));
|
|
88
|
-
|
|
232
|
+
const label = details.description
|
|
233
|
+
? `${details.description} (${commandLabel(details.command, 40)})`
|
|
234
|
+
: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);
|
|
235
|
+
return `${glyph} ${theme.fg("accent", details.taskId)} ${label} ${theme.fg("muted", `— ${outcome}`)}`;
|
|
89
236
|
}
|
|
90
237
|
/**
|
|
91
|
-
* Collapsed: status glyph, task id,
|
|
238
|
+
* Collapsed: status glyph, task id, label, and outcome on one line, output
|
|
92
239
|
* path below. Expanded adds the embedded output tail. Returns undefined for
|
|
93
240
|
* malformed details so the default custom-message rendering takes over.
|
|
94
241
|
*/
|
|
@@ -98,21 +245,24 @@ export function renderBackgroundNotification(message, options, theme) {
|
|
|
98
245
|
return undefined;
|
|
99
246
|
const container = new Container();
|
|
100
247
|
container.addChild(new TruncatedText(taskSummaryLine(details, theme), 1, 0));
|
|
101
|
-
|
|
248
|
+
// Collapsed keeps the row compact with the file name; the full path
|
|
249
|
+
// (model-relevant, human-rarely) shows when expanded.
|
|
250
|
+
const shownPath = options.expanded ? details.outputPath : fileNameOf(details.outputPath);
|
|
251
|
+
container.addChild(new Text(theme.fg("muted", shownPath), 1, 0));
|
|
102
252
|
if (details.tailError) {
|
|
103
253
|
container.addChild(new Text(theme.fg("error", `Output unavailable: ${details.tailError}`), 1, 0));
|
|
104
254
|
}
|
|
105
255
|
else if (options.expanded && details.tailText) {
|
|
106
256
|
container.addChild(new Text("", 0, 0));
|
|
107
|
-
|
|
108
|
-
const tail = details.tailText.length > NOTIFY_TAIL_LIMIT
|
|
109
|
-
? `…${details.tailText.slice(-NOTIFY_TAIL_LIMIT)}`
|
|
110
|
-
: details.tailText;
|
|
257
|
+
const tail = capForTranscript(details.tailText, NOTIFY_TAIL_LIMIT);
|
|
111
258
|
const truncatedNote = details.tailTruncated
|
|
112
|
-
? `\n[showing tail of ${details.totalBytes} bytes; full output: ${details.outputPath}]`
|
|
259
|
+
? `\n[showing tail of ${formatSize(details.totalBytes)} bytes; full output: ${details.outputPath}]`
|
|
113
260
|
: "";
|
|
114
261
|
container.addChild(new Text(`${theme.fg("toolOutput", tail.trimEnd())}${theme.fg("muted", truncatedNote)}`, 1, 0));
|
|
115
262
|
}
|
|
263
|
+
if (details.stalled && options.expanded) {
|
|
264
|
+
container.addChild(new Text(theme.fg("warning", "Blocked on interactive input — kill (bg action kill) and re-run with piped input or a non-interactive flag."), 1, 0));
|
|
265
|
+
}
|
|
116
266
|
return container;
|
|
117
267
|
}
|
|
118
268
|
//# sourceMappingURL=render.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Transcript rendering for the background extension: tool call/result rows\n * and the completion-notification message. Style follows the built-in bash\n * presentation: a `$` prompt row with an `&` marker for the background call.\n */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type {\n\tAgentToolResult,\n\tMessageRenderOptions,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { BgBashDetails, BgBashInput, BgKillInput, BgLogsInput, BgNotificationDetails } from \"./index.ts\";\nimport { type BgTaskStatus, firstCommandLine, formatDuration } from \"./registry.ts\";\n\nconst COMMAND_PREVIEW_LIMIT = 120;\nconst NOTIFY_TAIL_LIMIT = 4000;\n\nfunction bgPrompt(theme: Theme): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(\"$ \"));\n}\n\nfunction timeoutSuffix(timeout: number | undefined, theme: Theme): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\n\nexport function statusGlyph(status: BgTaskStatus): string {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"✓\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\t\treturn \"✗\";\n\t\tcase \"killed\":\n\t\t\treturn \"○\";\n\t\tdefault:\n\t\t\treturn \"●\";\n\t}\n}\n\nexport function statusColor(status: BgTaskStatus): \"success\" | \"error\" | \"warning\" | \"accent\" {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tcase \"timeout\":\n\t\tcase \"killed\":\n\t\t\treturn \"warning\";\n\t\tdefault:\n\t\t\treturn \"accent\";\n\t}\n}\n\n/** First command line truncated to a visible-character budget with an ellipsis. */\nexport function commandLabel(command: string, width: number): string {\n\tconst characters = [...firstCommandLine(command)];\n\treturn characters.length <= width ? characters.join(\"\") : `${characters.slice(0, Math.max(0, width - 1)).join(\"\")}…`;\n}\n\nexport function renderBgBashCall(args: BgBashInput, theme: Theme, context: ToolRenderContext): Component {\n\tconst lines = args.command.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n\tconst suffix = theme.fg(\"muted\", \" &\") + timeoutSuffix(args.timeout, theme);\n\tif (context.expanded && lines.length > 1) {\n\t\tconst body = highlightCode(args.command, \"bash\").join(\"\\n\");\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n\t}\n\tconst body = highlightCode(firstCommandLine(args.command), \"bash\").join(\"\\n\");\n\tif (lines.length > 1) {\n\t\tconst hidden = lines.length - 1;\n\t\tconst more = theme.fg(\"muted\", ` (+${hidden} line${hidden === 1 ? \"\" : \"s\"})`);\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}${more}`, 0, 0);\n\t}\n\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n}\n\nexport function renderBgBashResult(\n\tresult: AgentToolResult<BgBashDetails | undefined>,\n\t_options: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext,\n): Component {\n\tif (context.isError) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\tconst details = result.details;\n\tif (!details) return new Text(theme.fg(\"toolOutput\", \"Background task started.\"), 0, 0);\n\tconst line = `${theme.fg(\"muted\", \"→ task \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\n\t\t\"muted\",\n\t\t` started · ${details.outputPath}`,\n\t)}`;\n\treturn new Text(line, 0, 0);\n}\n\nexport function renderBgLogsCall(args: BgLogsInput, theme: Theme): Component {\n\tconst mode = args.mode ?? \"tail\";\n\tconst size = args.bytes !== undefined ? ` ${args.bytes}B` : \"\";\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg logs \"))}${theme.fg(\"accent\", args.taskId)}${theme.fg(\"muted\", ` ${mode}${size}`)}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nexport function renderBgKillCall(args: BgKillInput, theme: Theme): Component {\n\treturn new Text(`${theme.fg(\"toolTitle\", theme.bold(\"bg kill \"))}${theme.fg(\"accent\", args.taskId)}`, 0, 0);\n}\n\n/** One-line summary of a finished task, shared by the notification renderer. */\nfunction taskSummaryLine(details: BgNotificationDetails, theme: Theme): string {\n\tconst runtime = formatDuration(details.runtimeMs);\n\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\tconst outcome = theme.fg(statusColor(details.status), `${details.status}${exit} in ${runtime}`);\n\tconst glyph = theme.fg(statusColor(details.status), statusGlyph(details.status));\n\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${commandLabel(details.command, COMMAND_PREVIEW_LIMIT)} ${theme.fg(\"muted\", `— ${outcome}`)}`;\n}\n\n/**\n * Collapsed: status glyph, task id, command, and outcome on one line, output\n * path below. Expanded adds the embedded output tail. Returns undefined for\n * malformed details so the default custom-message rendering takes over.\n */\nexport function renderBackgroundNotification(\n\tmessage: CustomMessage<BgNotificationDetails>,\n\toptions: MessageRenderOptions,\n\ttheme: Theme,\n): Component | undefined {\n\tconst details = message.details;\n\tif (!details || typeof details.taskId !== \"string\") return undefined;\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(taskSummaryLine(details, theme), 1, 0));\n\tcontainer.addChild(new Text(theme.fg(\"muted\", details.outputPath), 1, 0));\n\n\tif (details.tailError) {\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Output unavailable: ${details.tailError}`), 1, 0));\n\t} else if (options.expanded && details.tailText) {\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\t// Keep the END of the tail when over budget — that is where the outcome lives.\n\t\tconst tail =\n\t\t\tdetails.tailText.length > NOTIFY_TAIL_LIMIT\n\t\t\t\t? `…${details.tailText.slice(-NOTIFY_TAIL_LIMIT)}`\n\t\t\t\t: details.tailText;\n\t\tconst truncatedNote = details.tailTruncated\n\t\t\t? `\\n[showing tail of ${details.totalBytes} bytes; full output: ${details.outputPath}]`\n\t\t\t: \"\";\n\t\tcontainer.addChild(\n\t\t\tnew Text(`${theme.fg(\"toolOutput\", tail.trimEnd())}${theme.fg(\"muted\", truncatedNote)}`, 1, 0),\n\t\t);\n\t}\n\treturn container;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Transcript rendering for the background extension: the single bg tool's\n * call/result rows (dispatched on action) and the completion-notification\n * message. Style follows the built-in bash presentation: a `$` prompt row\n * with an `&` marker for the background call.\n */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type {\n\tAgentToolResult,\n\tMessageRenderOptions,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { BgCreateInput, BgDetails, BgInput, BgNotificationDetails } from \"./index.ts\";\nimport {\n\tBG_WAIT_DEFAULT_MS,\n\tBG_WAIT_MAX_MS,\n\tBG_WAIT_MIN_MS,\n\ttype BgTaskStatus,\n\tfirstCommandLine,\n\tformatDuration,\n} from \"./registry.ts\";\n\nconst COMMAND_PREVIEW_LIMIT = 120;\nconst NOTIFY_TAIL_LIMIT = 4000;\n/** Cap for expanded transcript views of tool-result text (already bounded at the source). */\nconst RESULT_EXPAND_LIMIT = 4000;\n/** Live pending-wait line refresh cadence; the first settled render clears the timer. */\nconst WAIT_REFRESH_MS = 1000;\n\n/** Live peek at a waited-on task, fed from the registry by the call renderer. */\nexport interface BgTaskLive {\n\tstatus: BgTaskStatus;\n\toutputBytes: number;\n}\n\nexport type WaitLiveProbe = (taskId: string) => BgTaskLive | undefined;\n\n/** Per-call live-refresh state owned by the shell's render context. */\nexport interface BgRenderState {\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n\t/** First pending render of a wait call; anchors the elapsed display. */\n\twaitStartedAt?: number;\n\t/** outputBytes snapshot at wait start; anchors the \"+new output\" display. */\n\twaitBaselineBytes?: number;\n}\n\n/**\n * Arm a one-shot 1s refresh while a wait call is pending, clear it once\n * settled. The timer fires → context.invalidate() → renderCall re-runs →\n * re-arms, so at most one armed timer exists per tool row. Unref'd: it can\n * never hold the process open.\n */\nexport function scheduleWaitRefresh(context: ToolRenderContext<BgRenderState>, pending: boolean): void {\n\tconst state = context.state;\n\tif (state === undefined) return; // Standalone render without shell state: nothing to schedule.\n\tif (pending) {\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, WAIT_REFRESH_MS);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\tstate.waitStartedAt = undefined;\n\tstate.waitBaselineBytes = undefined;\n}\n\n/** Basename of a path, slash-normalized — compact display of output files. */\nexport function fileNameOf(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").split(\"/\").at(-1) ?? path;\n}\n\nfunction bgPrompt(theme: Theme): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(\"$ \"));\n}\n\nfunction timeoutSuffix(timeout: number | undefined, theme: Theme): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\n\n/** Keep the END of oversized text — that is where the outcome lives. */\nfunction capForTranscript(text: string, limit: number): string {\n\treturn text.length > limit ? `…${text.slice(-limit)}` : text;\n}\n\nexport function statusGlyph(status: BgTaskStatus, stalled?: boolean): string {\n\tif (stalled) return \"…\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"✓\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\t\treturn \"✗\";\n\t\tcase \"killed\":\n\t\t\treturn \"○\";\n\t\tdefault:\n\t\t\treturn \"●\";\n\t}\n}\n\nexport function statusColor(status: BgTaskStatus, stalled?: boolean): \"success\" | \"error\" | \"warning\" | \"accent\" {\n\tif (stalled) return \"warning\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tcase \"timeout\":\n\t\tcase \"killed\":\n\t\t\treturn \"warning\";\n\t\tdefault:\n\t\t\treturn \"accent\";\n\t}\n}\n\n/** First command line truncated to a visible-character budget with an ellipsis. */\nexport function commandLabel(command: string, width: number): string {\n\tconst characters = [...firstCommandLine(command)];\n\treturn characters.length <= width ? characters.join(\"\") : `${characters.slice(0, Math.max(0, width - 1)).join(\"\")}…`;\n}\n\n// ── tool call ─────────────────────────────────────────────────────────────\n\nexport function renderBgCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive?: WaitLiveProbe,\n): Component {\n\tswitch (args.action) {\n\t\tcase \"create\":\n\t\t\treturn typeof args.command === \"string\"\n\t\t\t\t? renderCreateCall(args as BgCreateInput, theme, context)\n\t\t\t\t: new Text(theme.fg(\"toolTitle\", theme.bold(\"bg create\")), 0, 0);\n\t\tcase \"read\": {\n\t\t\tconst mode = args.mode ?? \"tail\";\n\t\t\tconst size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : \"\";\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg read \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ` ${mode}${size}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t\tcase \"wait\":\n\t\t\treturn renderWaitCall(args, theme, context, getTaskLive);\n\t\tcase \"kill\":\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg kill \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(\"bg list\")), 0, 0);\n\t\tdefault: {\n\t\t\t// Tool arguments arrive incrementally while the model is still emitting\n\t\t\t// JSON. Keep the call row renderable until `action` becomes valid.\n\t\t\tconst action = typeof args.action === \"string\" ? ` ${theme.fg(\"dim\", args.action)}` : \"\";\n\t\t\treturn new Text(`${theme.fg(\"toolTitle\", theme.bold(\"bg\"))}${action}`, 0, 0);\n\t\t}\n\t}\n}\n\n/** Mirror the execution-side clamp so the shown window matches the real one. */\nexport function clampWaitMs(waitMs: number | undefined): number {\n\treturn Math.min(BG_WAIT_MAX_MS, Math.max(BG_WAIT_MIN_MS, Math.floor(waitMs ?? BG_WAIT_DEFAULT_MS)));\n}\n\n/**\n * Pending wait call: elapsed/wait-window and the new-output delta since the\n * wait began, refreshed once per second by scheduleWaitRefresh until the\n * result settles and takes over the row.\n */\nfunction renderWaitCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive: WaitLiveProbe | undefined,\n): Component {\n\tconst taskId = typeof args.taskId === \"string\" ? args.taskId.trim() : \"\";\n\tconst live = getTaskLive !== undefined && taskId ? getTaskLive(taskId) : undefined;\n\t// The live display needs shell-owned state; without it (standalone renders)\n\t// fall back to the static line.\n\tconst pending = context.isPartial === true && context.state !== undefined && taskId.length > 0;\n\tscheduleWaitRefresh(context, pending);\n\tif (!pending) {\n\t\tconst ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ms)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst state = context.state;\n\tif (state.waitStartedAt === undefined) state.waitStartedAt = Date.now();\n\tconst startedAt = state.waitStartedAt;\n\tlet liveBase: number | undefined;\n\tif (live) {\n\t\tif (state.waitBaselineBytes === undefined) state.waitBaselineBytes = live.outputBytes;\n\t\tliveBase = state.waitBaselineBytes;\n\t}\n\tconst parts = [`waiting ${formatDuration(Date.now() - startedAt)}/${formatDuration(clampWaitMs(args.waitMs))}`];\n\tif (live && live.status === \"running\" && liveBase !== undefined && live.outputBytes > liveBase) {\n\t\tparts.push(`+${formatSize(live.outputBytes - liveBase)} new output`);\n\t}\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", taskId)} ${theme.fg(\"muted\", parts.join(\" · \"))}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nfunction renderCreateCall(args: BgCreateInput, theme: Theme, context: ToolRenderContext): Component {\n\tconst lines = args.command.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n\tconst label = args.description ? theme.fg(\"muted\", ` · ${args.description}`) : \"\";\n\tconst suffix = theme.fg(\"muted\", \" &\") + timeoutSuffix(args.timeout, theme) + label;\n\tif (context.expanded && lines.length > 1) {\n\t\tconst body = highlightCode(args.command, \"bash\").join(\"\\n\");\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n\t}\n\tconst body = highlightCode(firstCommandLine(args.command), \"bash\").join(\"\\n\");\n\tif (lines.length > 1) {\n\t\tconst hidden = lines.length - 1;\n\t\tconst more = theme.fg(\"muted\", ` (+${hidden} line${hidden === 1 ? \"\" : \"s\"})`);\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}${more}`, 0, 0);\n\t}\n\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n}\n\n// ── tool result ───────────────────────────────────────────────────────────\n\nexport function renderBgResult(\n\tresult: AgentToolResult<BgDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n): Component {\n\t// bg results are always settled today; clear defensively so no live-refresh\n\t// timer can outlive its row if a host ever streams partial results.\n\tif (context.args?.action === \"wait\" && !options.isPartial) scheduleWaitRefresh(context, false);\n\tconst details = result.details;\n\tif (context.isError || !details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(resultSummaryLine(details, theme), 1, 0));\n\tif (options.expanded) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tcontainer.addChild(new Text(theme.fg(\"toolOutput\", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));\n\t}\n\treturn container;\n}\n\nfunction resultSummaryLine(details: BgDetails, theme: Theme): string {\n\tswitch (details.action) {\n\t\tcase \"create\": {\n\t\t\tconst label = details.description ? ` (${details.description})` : \"\";\n\t\t\treturn `${theme.fg(\"muted\", \"→ task \")}${theme.fg(\"accent\", `${details.taskId}${label}`)}${theme.fg(\"muted\", ` started · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"read\": {\n\t\t\tconst size =\n\t\t\t\tdetails.sliceBytes !== details.totalBytes\n\t\t\t\t\t? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`\n\t\t\t\t\t: formatSize(details.totalBytes);\n\t\t\treturn `${theme.fg(\"muted\", \"→ \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${size} · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"wait\": {\n\t\t\tif (details.timedOut) {\n\t\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` still running · waited ${formatDuration(details.waitedMs)} · ${formatSize(details.totalBytes)}`)}`;\n\t\t\t}\n\t\t\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${details.status}${exit} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;\n\t\t}\n\t\tcase \"kill\":\n\t\t\treturn `${theme.fg(statusColor(\"killed\"), statusGlyph(\"killed\"))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", \" stopped\")}`;\n\t\tcase \"list\": {\n\t\t\tconst hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : \"\";\n\t\t\treturn theme.fg(\"muted\", `${details.running} running · ${details.finished} finished${hidden}`);\n\t\t}\n\t}\n}\n\n// ── completion notification ───────────────────────────────────────────────\n\n/** One-line summary of a finished task, shared by the notification renderer. */\nfunction taskSummaryLine(details: BgNotificationDetails, theme: Theme): string {\n\tconst runtime = formatDuration(details.runtimeMs);\n\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\tif (details.stalled) {\n\t\tconst glyph = theme.fg(\"warning\", \"…\");\n\t\tconst label = details.description\n\t\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\t\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— waiting for input (${runtime})`)}`;\n\t}\n\tconst outcome = theme.fg(statusColor(details.status), `${details.status}${exit} in ${runtime}`);\n\tconst glyph = theme.fg(statusColor(details.status), statusGlyph(details.status));\n\tconst label = details.description\n\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— ${outcome}`)}`;\n}\n\n/**\n * Collapsed: status glyph, task id, label, and outcome on one line, output\n * path below. Expanded adds the embedded output tail. Returns undefined for\n * malformed details so the default custom-message rendering takes over.\n */\nexport function renderBackgroundNotification(\n\tmessage: CustomMessage<BgNotificationDetails>,\n\toptions: MessageRenderOptions,\n\ttheme: Theme,\n): Component | undefined {\n\tconst details = message.details;\n\tif (!details || typeof details.taskId !== \"string\") return undefined;\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(taskSummaryLine(details, theme), 1, 0));\n\t// Collapsed keeps the row compact with the file name; the full path\n\t// (model-relevant, human-rarely) shows when expanded.\n\tconst shownPath = options.expanded ? details.outputPath : fileNameOf(details.outputPath);\n\tcontainer.addChild(new Text(theme.fg(\"muted\", shownPath), 1, 0));\n\n\tif (details.tailError) {\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Output unavailable: ${details.tailError}`), 1, 0));\n\t} else if (options.expanded && details.tailText) {\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tconst tail = capForTranscript(details.tailText, NOTIFY_TAIL_LIMIT);\n\t\tconst truncatedNote = details.tailTruncated\n\t\t\t? `\\n[showing tail of ${formatSize(details.totalBytes)} bytes; full output: ${details.outputPath}]`\n\t\t\t: \"\";\n\t\tcontainer.addChild(\n\t\t\tnew Text(`${theme.fg(\"toolOutput\", tail.trimEnd())}${theme.fg(\"muted\", truncatedNote)}`, 1, 0),\n\t\t);\n\t}\n\tif (details.stalled && options.expanded) {\n\t\tcontainer.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"warning\",\n\t\t\t\t\t\"Blocked on interactive input — kill (bg action kill) and re-run with piped input or a non-interactive flag.\",\n\t\t\t\t),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n\treturn container;\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */
|
|
2
|
+
import { type Component, Container, type Focusable, type TUI } from "@earendil-works/pi-tui";
|
|
3
|
+
import type { ExtensionCommandContext } from "../../core/extensions/types.ts";
|
|
4
|
+
import type { KeybindingsManager } from "../../core/keybindings.ts";
|
|
5
|
+
import type { Theme } from "../../modes/interactive/theme/theme.ts";
|
|
6
|
+
export type RouterComponent = Component & {
|
|
7
|
+
dispose?(): void;
|
|
8
|
+
};
|
|
9
|
+
export type RouterComponentFactory<T> = (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: T) => void) => RouterComponent | Promise<RouterComponent>;
|
|
10
|
+
interface RouterDialogBase {
|
|
11
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
12
|
+
confirm(title: string, message: string): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface RouterNativeDialogs extends RouterDialogBase {
|
|
15
|
+
readonly kind: "native";
|
|
16
|
+
select(title: string, options: string[]): Promise<string | undefined>;
|
|
17
|
+
}
|
|
18
|
+
export interface RouterTuiDialogs extends RouterDialogBase {
|
|
19
|
+
readonly kind: "tui";
|
|
20
|
+
show<T>(factory: RouterComponentFactory<T>): Promise<T>;
|
|
21
|
+
}
|
|
22
|
+
export type RouterDialogs = RouterNativeDialogs | RouterTuiDialogs;
|
|
23
|
+
export declare class RouterTuiSessionClosedError extends Error {
|
|
24
|
+
constructor();
|
|
25
|
+
}
|
|
26
|
+
export declare function createNativeRouterDialogs(ctx: ExtensionCommandContext): RouterNativeDialogs;
|
|
27
|
+
/**
|
|
28
|
+
* Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve
|
|
29
|
+
* without closing this root, so async flow continuations can replace them
|
|
30
|
+
* without exposing the main editor between pages.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RouterTuiSession extends Container implements Focusable, RouterTuiDialogs {
|
|
33
|
+
readonly kind: "tui";
|
|
34
|
+
private readonly tui;
|
|
35
|
+
private readonly theme;
|
|
36
|
+
private readonly keybindings;
|
|
37
|
+
private readonly onTransitionClose;
|
|
38
|
+
private activeScreen;
|
|
39
|
+
private pendingReject;
|
|
40
|
+
private transitionTimer;
|
|
41
|
+
private acceptsInput;
|
|
42
|
+
private closeRequested;
|
|
43
|
+
private disposed;
|
|
44
|
+
private _focused;
|
|
45
|
+
constructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager, onTransitionClose: () => void);
|
|
46
|
+
get focused(): boolean;
|
|
47
|
+
set focused(value: boolean);
|
|
48
|
+
show<T>(factory: RouterComponentFactory<T>): Promise<T>;
|
|
49
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
50
|
+
confirm(title: string, message: string): Promise<boolean>;
|
|
51
|
+
handleInput(data: string): void;
|
|
52
|
+
dispose(): void;
|
|
53
|
+
private beginTransition;
|
|
54
|
+
private clearTransitionTimer;
|
|
55
|
+
private setActiveScreen;
|
|
56
|
+
private disposeActiveScreen;
|
|
57
|
+
private disposeScreen;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=dialog-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-host.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/dialog-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */
|
|
2
|
+
import { Container, isFocusable, Spacer, Text } from "@earendil-works/pi-tui";
|
|
3
|
+
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
4
|
+
import { ExtensionInputComponent } from "../../modes/interactive/components/extension-input.js";
|
|
5
|
+
import { ExtensionSelectorComponent } from "../../modes/interactive/components/extension-selector.js";
|
|
6
|
+
import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
|
|
7
|
+
export class RouterTuiSessionClosedError extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super("Router TUI session is closed.");
|
|
10
|
+
this.name = "RouterTuiSessionClosedError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function createNativeRouterDialogs(ctx) {
|
|
14
|
+
return {
|
|
15
|
+
kind: "native",
|
|
16
|
+
select: (title, options) => ctx.ui.select(title, options),
|
|
17
|
+
input: (title, placeholder) => ctx.ui.input(title, placeholder),
|
|
18
|
+
confirm: (title, message) => ctx.ui.confirm(title, message),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve
|
|
23
|
+
* without closing this root, so async flow continuations can replace them
|
|
24
|
+
* without exposing the main editor between pages.
|
|
25
|
+
*/
|
|
26
|
+
export class RouterTuiSession extends Container {
|
|
27
|
+
constructor(tui, theme, keybindings, onTransitionClose) {
|
|
28
|
+
super();
|
|
29
|
+
this.kind = "tui";
|
|
30
|
+
this.acceptsInput = false;
|
|
31
|
+
this.closeRequested = false;
|
|
32
|
+
this.disposed = false;
|
|
33
|
+
this._focused = false;
|
|
34
|
+
this.tui = tui;
|
|
35
|
+
this.theme = theme;
|
|
36
|
+
this.keybindings = keybindings;
|
|
37
|
+
this.onTransitionClose = onTransitionClose;
|
|
38
|
+
const loading = new Container();
|
|
39
|
+
loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
|
|
40
|
+
loading.addChild(new Spacer(1));
|
|
41
|
+
loading.addChild(new Text(theme.fg("muted", "Loading router…"), 1, 0));
|
|
42
|
+
loading.addChild(new Spacer(1));
|
|
43
|
+
loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
|
|
44
|
+
this.activeScreen = loading;
|
|
45
|
+
this.addChild(loading);
|
|
46
|
+
}
|
|
47
|
+
get focused() {
|
|
48
|
+
return this._focused;
|
|
49
|
+
}
|
|
50
|
+
set focused(value) {
|
|
51
|
+
this._focused = value;
|
|
52
|
+
if (this.activeScreen && isFocusable(this.activeScreen)) {
|
|
53
|
+
this.activeScreen.focused = value && this.acceptsInput;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
show(factory) {
|
|
57
|
+
this.clearTransitionTimer();
|
|
58
|
+
if (this.disposed || this.closeRequested)
|
|
59
|
+
return Promise.reject(new RouterTuiSessionClosedError());
|
|
60
|
+
if (this.pendingReject)
|
|
61
|
+
return Promise.reject(new Error("Router TUI session already has an active dialog."));
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
let settled = false;
|
|
64
|
+
const fail = (error) => {
|
|
65
|
+
if (settled || this.disposed)
|
|
66
|
+
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
this.acceptsInput = false;
|
|
69
|
+
if (this.pendingReject === reject)
|
|
70
|
+
this.pendingReject = undefined;
|
|
71
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
72
|
+
};
|
|
73
|
+
const done = (result) => {
|
|
74
|
+
if (settled || this.disposed)
|
|
75
|
+
return;
|
|
76
|
+
settled = true;
|
|
77
|
+
this.acceptsInput = false;
|
|
78
|
+
if (this.activeScreen && isFocusable(this.activeScreen))
|
|
79
|
+
this.activeScreen.focused = false;
|
|
80
|
+
if (this.pendingReject === reject)
|
|
81
|
+
this.pendingReject = undefined;
|
|
82
|
+
this.tui.setFocus(this);
|
|
83
|
+
this.beginTransition();
|
|
84
|
+
resolve(result);
|
|
85
|
+
};
|
|
86
|
+
this.pendingReject = reject;
|
|
87
|
+
let pending;
|
|
88
|
+
try {
|
|
89
|
+
pending = factory(this.tui, this.theme, this.keybindings, done);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
fail(error);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
void Promise.resolve(pending).then((component) => {
|
|
96
|
+
if (settled || this.disposed) {
|
|
97
|
+
this.disposeScreen(component);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
this.setActiveScreen(component);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
this.disposeScreen(component);
|
|
105
|
+
fail(error);
|
|
106
|
+
}
|
|
107
|
+
}, fail);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
input(title, placeholder) {
|
|
111
|
+
return this.show((tui, _theme, _keybindings, done) => new ExtensionInputComponent(title, placeholder, done, () => done(undefined), { tui }));
|
|
112
|
+
}
|
|
113
|
+
async confirm(title, message) {
|
|
114
|
+
const selected = await this.show((tui, _theme, _keybindings, done) => new ExtensionSelectorComponent(title, ["Yes", "No"], done, () => done(undefined), {
|
|
115
|
+
tui,
|
|
116
|
+
subtitle: message,
|
|
117
|
+
}));
|
|
118
|
+
return selected === "Yes";
|
|
119
|
+
}
|
|
120
|
+
handleInput(data) {
|
|
121
|
+
if (this.acceptsInput) {
|
|
122
|
+
this.activeScreen?.handleInput?.(data);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (this.closeRequested || !this.keybindings.matches(data, "tui.select.cancel"))
|
|
126
|
+
return;
|
|
127
|
+
this.closeRequested = true;
|
|
128
|
+
this.onTransitionClose();
|
|
129
|
+
}
|
|
130
|
+
dispose() {
|
|
131
|
+
if (this.disposed)
|
|
132
|
+
return;
|
|
133
|
+
this.disposed = true;
|
|
134
|
+
this.acceptsInput = false;
|
|
135
|
+
this.clearTransitionTimer();
|
|
136
|
+
const reject = this.pendingReject;
|
|
137
|
+
this.pendingReject = undefined;
|
|
138
|
+
this.disposeActiveScreen();
|
|
139
|
+
this.clear();
|
|
140
|
+
reject?.(new RouterTuiSessionClosedError());
|
|
141
|
+
}
|
|
142
|
+
beginTransition() {
|
|
143
|
+
this.clearTransitionTimer();
|
|
144
|
+
this.transitionTimer = setTimeout(() => {
|
|
145
|
+
this.transitionTimer = undefined;
|
|
146
|
+
if (this.disposed || this.closeRequested || this.acceptsInput)
|
|
147
|
+
return;
|
|
148
|
+
const working = new Container();
|
|
149
|
+
working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
|
|
150
|
+
working.addChild(new Spacer(1));
|
|
151
|
+
const cancelKey = keyLabel("tui.select.cancel", { keybindings: this.keybindings });
|
|
152
|
+
const closeHint = cancelKey ? `${cancelKey} closes /router` : "Close /router to continue";
|
|
153
|
+
working.addChild(new Text(this.theme.fg("muted", `Working… ${closeHint}`), 1, 0));
|
|
154
|
+
working.addChild(new Spacer(1));
|
|
155
|
+
working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
|
|
156
|
+
this.disposeActiveScreen();
|
|
157
|
+
this.clear();
|
|
158
|
+
this.activeScreen = working;
|
|
159
|
+
this.addChild(working);
|
|
160
|
+
this.tui.requestRender();
|
|
161
|
+
}, 150);
|
|
162
|
+
}
|
|
163
|
+
clearTransitionTimer() {
|
|
164
|
+
if (this.transitionTimer === undefined)
|
|
165
|
+
return;
|
|
166
|
+
clearTimeout(this.transitionTimer);
|
|
167
|
+
this.transitionTimer = undefined;
|
|
168
|
+
}
|
|
169
|
+
setActiveScreen(component) {
|
|
170
|
+
this.disposeActiveScreen();
|
|
171
|
+
this.clear();
|
|
172
|
+
this.activeScreen = component;
|
|
173
|
+
this.addChild(component);
|
|
174
|
+
this.acceptsInput = true;
|
|
175
|
+
this.tui.setFocus(component);
|
|
176
|
+
this.tui.requestRender();
|
|
177
|
+
}
|
|
178
|
+
disposeActiveScreen() {
|
|
179
|
+
const screen = this.activeScreen;
|
|
180
|
+
this.activeScreen = undefined;
|
|
181
|
+
if (screen)
|
|
182
|
+
this.disposeScreen(screen);
|
|
183
|
+
}
|
|
184
|
+
disposeScreen(screen) {
|
|
185
|
+
const dispose = screen.dispose;
|
|
186
|
+
if (isFocusable(screen))
|
|
187
|
+
screen.focused = false;
|
|
188
|
+
try {
|
|
189
|
+
dispose?.call(screen);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// A child cleanup failure must not strand the outer custom lifecycle.
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=dialog-host.js.map
|