Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions extensions/background-terminals/src/ui/ps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
panelFrame,
screenTitleLine,
} from "../../../shared/screen-chrome.ts";
import { spinnerFrame } from "../../../shared/spinner.ts";
import {
formatDuration,
formatElapsed,
Expand All @@ -43,18 +44,30 @@ function configuredKeys(
return keybindings.getKeys(binding).join("/") || "unbound";
}

function statusGlyph(snap: TerminalSnapshot, theme: Theme) {
/**
* One status indicator per state, shared by the picker rows and the detail
* header. Running spins, in step with every other OpenPI surface. A selected
* row keeps its state glyph and borrows the accent tone.
*/
function statusGlyph(
snap: TerminalSnapshot,
theme: Theme,
now = Date.now(),
selected = false,
) {
const tone = (color: "warning" | "success" | "error" | "muted") =>
selected ? ("accent" as const) : color;
switch (snap.status) {
case "running":
return theme.fg("warning", "■");
return theme.fg(tone("warning"), spinnerFrame(now));
case "done":
return theme.fg("success", "");
return theme.fg(tone("success"), "");
case "failed":
return theme.fg("error", "");
return theme.fg(tone("error"), "");
case "killed":
return theme.fg("muted", "");
return theme.fg(tone("muted"), "");
case "timed_out":
return theme.fg("error", "");
return theme.fg(tone("error"), "");
}
}

Expand Down Expand Up @@ -92,13 +105,13 @@ export async function openTerminalPicker(
new TerminalDashboard(tui, theme, keybindings, view, selection, done),
{
overlay: true,
// Dock the picker just above the editor (editor + strip + footer ≈ 6
// Dock the picker just above the editor (editor + strip + footer ≈ 5
// rows) like a command palette, instead of blanking the conversation.
overlayOptions: {
anchor: "bottom-center",
width: "100%",
maxHeight: "60%",
margin: { bottom: 6 },
margin: { bottom: 5 },
},
},
);
Expand Down Expand Up @@ -246,6 +259,8 @@ class TerminalDashboard implements Component {
configuredKeys(this.keybindings, binding);

return [
// One empty row of air between the conversation and the docked panel.
"",
screenTitleLine(
theme,
"Background terminals",
Expand Down Expand Up @@ -294,12 +309,13 @@ class TerminalDashboard implements Component {
const index = start + i;
const isSelected = index === this.selection.index;

// Left: marker, status square, title, dim id
const marker = isSelected ? theme.fg("accent", "❯") : " ";
// Left: one glyph — a selected row tints its status glyph instead of
// stacking a marker — then title and dim id.
const glyph = statusGlyph(snap, theme, Date.now(), isSelected);
const title = isSelected
? theme.fg("accent", oneLine(snap.title))
: theme.fg("text", oneLine(snap.title));
const left = ` ${marker} ${statusGlyph(snap, theme)} ${title} ${theme.fg("dim", snap.id)}`;
const left = ` ${glyph} ${title} ${theme.fg("dim", snap.id)}`;

// Right: pid · elapsed · exit/status
const dot = theme.fg("dim", " · ");
Expand Down
6 changes: 3 additions & 3 deletions extensions/subagents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,10 +810,10 @@ export default function (pi: ExtensionAPI) {
const meta = [details.harness, details.model]
.filter(Boolean)
.join(" \u00b7 ");
// A spawn is a beginning, not a success: keep the marker quiet and let
// the strip's spinner carry the running state from here on.
// A spawn adds an agent to the pool: a quiet plus, then the strip's
// spinner carries the running state from here on.
return new Text(
`${theme.fg("dim", "\u25cf")} ${theme.bold(details.title ?? details.id)} ${theme.fg("dim", meta)}`,
`${theme.fg("dim", "+")} ${theme.bold(details.title ?? details.id)} ${theme.fg("dim", meta)}`,
0,
0,
);
Expand Down
2 changes: 1 addition & 1 deletion extensions/subagents/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function statusGlyph(snapshot: SubagentSnapshot, theme: Theme, now: number) {
if (snapshot.status === "running")
return theme.fg("warning", spinnerFrame(now));
if (snapshot.status === "done") return theme.fg("success", "✓");
return theme.fg("error", "x");
return theme.fg("error", "");
}

/** One-line subagent manager entry with the same affordance as Workflow. */
Expand Down
23 changes: 16 additions & 7 deletions extensions/subagents/src/ui/takeover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,19 @@ function statusGlyph(
snap: SubagentSnapshot,
theme: Theme,
now = Date.now(),
selected = false,
): string {
// A selected row keeps its state glyph and borrows the accent tone, so the
// list never hides what is still running behind a selection marker.
const tone = (color: "warning" | "success" | "error") =>
selected ? ("accent" as const) : color;
switch (snap.status) {
case "running":
return theme.fg("warning", spinnerFrame(now));
return theme.fg(tone("warning"), spinnerFrame(now));
case "done":
return theme.fg("success", "✓");
return theme.fg(tone("success"), "✓");
case "error":
return theme.fg("error", "✗");
return theme.fg(tone("error"), "✗");
}
}

Expand Down Expand Up @@ -132,13 +137,13 @@ export async function openSubagentPicker(
new SubagentDashboard(tui, theme, keybindings, view, selection, done),
{
overlay: true,
// Dock the picker just above the editor (editor + strip + footer ≈ 6
// Dock the picker just above the editor (editor + strip + footer ≈ 5
// rows) like a command palette, instead of covering the conversation.
overlayOptions: {
anchor: "bottom-center",
width: "100%",
maxHeight: "60%",
margin: { bottom: 6 },
margin: { bottom: 5 },
},
},
);
Expand Down Expand Up @@ -306,6 +311,8 @@ export class SubagentDashboard implements Component {
// /workflows. The frame is padded to the rows it was given, which keeps
// this view's content-fit height rather than reintroducing a fixed one.
return [
// One empty row of air between the conversation and the docked panel.
"",
...panelFrame(theme, {
label: `Subagents · ${summary}`,
rows: rowLines,
Expand Down Expand Up @@ -353,13 +360,15 @@ export class SubagentDashboard implements Component {
const index = start + i;
const isSelected = index === this.selection.index;

const marker = isSelected ? theme.fg("accent", "❯") : " ";
// One glyph column: a selected row tints its status glyph with the
// accent tone instead of stacking a second marker.
const glyph = statusGlyph(snap, theme, now, isSelected);
const safeTitle = sanitizeSubagentDisplayLine(snap.title) || snap.id;
const title = isSelected
? theme.fg("accent", safeTitle)
: theme.fg("text", safeTitle);
const activity = runningActivity(snap);
const prefix = ` ${marker} ${statusGlyph(snap, theme, now)} `;
const prefix = ` ${glyph} `;

const utilization = formatContextUtilization(snap.usage);
const metadata = [
Expand Down
2 changes: 1 addition & 1 deletion extensions/subagents/takeover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ test("dashboard box height follows its subagents and retains the old maximum", (
const one = dashboard([snap("one")], 10);
try {
const lines = one.render(100);
assert.equal(lines.length, 4); // border, one agent, border, hints
assert.equal(lines.length, 5); // air, border, one agent, border, hints
assert.equal(lines.filter((line) => line.includes("agent one")).length, 1);
} finally {
one.dispose();
Expand Down
2 changes: 1 addition & 1 deletion extensions/workflows/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function cleanLine(value: string) {
function statusGlyph(status: WorkflowStatus, theme: Theme, now: number) {
if (status === "completed") return theme.fg("success", "✓");
if (status === "running") return theme.fg("warning", spinnerFrame(now));
return theme.fg("error", "x");
return theme.fg("error", "");
}

/** Live, one-line Claude-style workflow entry rendered below the editor. */
Expand Down
Loading