@kolisachint/hoocode-agent 0.4.44 → 0.4.45
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 +15 -0
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/task-store.d.ts +53 -1
- package/dist/core/task-store.d.ts.map +1 -1
- package/dist/core/task-store.js +77 -1
- package/dist/core/task-store.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +33 -2
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/modes/interactive/command-executor.d.ts.map +1 -1
- package/dist/modes/interactive/command-executor.js +2 -0
- package/dist/modes/interactive/command-executor.js.map +1 -1
- package/dist/modes/interactive/components/task-panel.d.ts +17 -0
- package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-panel.js +176 -15
- package/dist/modes/interactive/components/task-panel.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -24,6 +24,27 @@ const SPINNER_INTERVAL_MS = 80;
|
|
|
24
24
|
const RAIL = "▎";
|
|
25
25
|
/** Cells in the deterministic progress bar (matches the design's 14-cell track). */
|
|
26
26
|
const PROGRESS_CELLS = 14;
|
|
27
|
+
const VIEW_ORDER = ["flat", "subagents", "teams"];
|
|
28
|
+
const VIEW_LABEL = { flat: "tasks", subagents: "subagents", teams: "teams" };
|
|
29
|
+
/** Owner glyphs: main agent a filled diamond, spawned subagents a plus-in-circle, team roles a triangle. */
|
|
30
|
+
const AGENT_GLYPH = { main: "◆", subagent: "⊕", role: "▸" };
|
|
31
|
+
const AGENT_GLYPH_COLOR = {
|
|
32
|
+
main: "accent",
|
|
33
|
+
subagent: "accent",
|
|
34
|
+
role: "borderAccent",
|
|
35
|
+
};
|
|
36
|
+
/** Color for an agent's lifecycle `[state]` tag (mirrors the design's .ast-* classes). */
|
|
37
|
+
const AGENT_STATE_COLOR = {
|
|
38
|
+
active: "warning",
|
|
39
|
+
running: "warning",
|
|
40
|
+
done: "success",
|
|
41
|
+
queued: "dim",
|
|
42
|
+
idle: "dim",
|
|
43
|
+
waiting: "mdLink",
|
|
44
|
+
failed: "error",
|
|
45
|
+
};
|
|
46
|
+
/** Two-cell indent under a group header, with a faint vertical guide. */
|
|
47
|
+
const GROUP_INDENT_PLAIN = "│ ";
|
|
27
48
|
const STATE_PRESENTATION = {
|
|
28
49
|
working: { icon: "◐", label: "working", color: "warning" },
|
|
29
50
|
reviewed: { icon: "✓", label: "reviewed", color: "success" },
|
|
@@ -93,12 +114,23 @@ function progressBar(done, active, total) {
|
|
|
93
114
|
styled: theme.fg("success", fill) + theme.fg("dim", track),
|
|
94
115
|
};
|
|
95
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* View switcher rendered at the right edge of the ledger header: the three
|
|
119
|
+
* lens labels joined by `·`, the active one in bold accent. Purely an
|
|
120
|
+
* indicator in the TUI — the bound key cycles it (see app.tasks.cycleView).
|
|
121
|
+
*/
|
|
122
|
+
function formatViewSwitcher(view) {
|
|
123
|
+
const plain = VIEW_ORDER.map((v) => VIEW_LABEL[v]).join(" · ");
|
|
124
|
+
const styled = VIEW_ORDER.map((v) => v === view ? theme.bold(theme.fg("accent", VIEW_LABEL[v])) : theme.fg("dim", VIEW_LABEL[v])).join(theme.fg("dim", " · "));
|
|
125
|
+
return { plain, styled };
|
|
126
|
+
}
|
|
96
127
|
/**
|
|
97
128
|
* Ledger header: a state stamp (◐ working / ✓ reviewed / ✗ stopped) + a
|
|
98
129
|
* deterministic progress bar and done/total count on the left, and the per-turn
|
|
99
|
-
* token + elapsed + cost delta (summed across the tasks below)
|
|
130
|
+
* token + elapsed + cost delta (summed across the tasks below) plus the view
|
|
131
|
+
* switcher on the right.
|
|
100
132
|
*/
|
|
101
|
-
function formatHeader(tasks, width, state, totalSecs) {
|
|
133
|
+
function formatHeader(tasks, width, state, totalSecs, view) {
|
|
102
134
|
const total = tasks.length;
|
|
103
135
|
const done = tasks.filter((t) => t.status === "done").length;
|
|
104
136
|
const active = tasks.filter((t) => t.status === "in_progress").length;
|
|
@@ -134,14 +166,29 @@ function formatHeader(tasks, width, state, totalSecs) {
|
|
|
134
166
|
theme.fg("muted", elapsed) +
|
|
135
167
|
(showCost ? theme.fg("dim", " · ") + theme.bold(costStr) : "");
|
|
136
168
|
}
|
|
169
|
+
// Right cluster: turn delta, then the view switcher at the far edge. The
|
|
170
|
+
// switcher is the first thing dropped when the terminal narrows; the turn
|
|
171
|
+
// delta next; the stamp/count survive to the end.
|
|
172
|
+
const switcher = formatViewSwitcher(view);
|
|
173
|
+
const rightVariants = [];
|
|
137
174
|
if (turnPlain) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
175
|
+
rightVariants.push({
|
|
176
|
+
plain: `${turnPlain} ${switcher.plain}`,
|
|
177
|
+
styled: `${turnText} ${switcher.styled}`,
|
|
178
|
+
});
|
|
179
|
+
rightVariants.push({ plain: turnPlain, styled: turnText });
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
rightVariants.push(switcher);
|
|
183
|
+
}
|
|
184
|
+
for (const right of rightVariants) {
|
|
185
|
+
if (visibleWidth(leftFullPlain) + 2 + visibleWidth(right.plain) <= width) {
|
|
186
|
+
const pad = Math.max(2, width - visibleWidth(leftFullPlain) - visibleWidth(right.plain));
|
|
187
|
+
return leftFull + " ".repeat(pad) + right.styled;
|
|
141
188
|
}
|
|
142
|
-
if (visibleWidth(leftMinPlain) + 2 + visibleWidth(
|
|
143
|
-
const pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(
|
|
144
|
-
return leftMin + " ".repeat(pad) +
|
|
189
|
+
if (visibleWidth(leftMinPlain) + 2 + visibleWidth(right.plain) <= width) {
|
|
190
|
+
const pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(right.plain));
|
|
191
|
+
return leftMin + " ".repeat(pad) + right.styled;
|
|
145
192
|
}
|
|
146
193
|
}
|
|
147
194
|
if (visibleWidth(leftFullPlain) <= width)
|
|
@@ -157,16 +204,20 @@ function formatTokens(count) {
|
|
|
157
204
|
return `${Math.round(count / 1000)}k`;
|
|
158
205
|
return `${(count / 1000000).toFixed(1)}M`;
|
|
159
206
|
}
|
|
160
|
-
function formatTaskLine(task, width, frame, idColWidth) {
|
|
207
|
+
function formatTaskLine(task, width, frame, idColWidth, options = {}) {
|
|
161
208
|
const isProgress = task.status === "in_progress";
|
|
162
209
|
const iconGlyph = isProgress
|
|
163
210
|
? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)
|
|
164
211
|
: TASK_STATUS_ICON[task.status];
|
|
165
212
|
const icon = theme.fg(taskStatusColor(task.status), iconGlyph);
|
|
213
|
+
// In grouped views the group header already carries the row's origin, so the
|
|
214
|
+
// source glyph and tag are suppressed; the rows sit on a faint indent guide.
|
|
215
|
+
const grouped = options.grouped === true;
|
|
216
|
+
const indent = grouped ? theme.fg("borderMuted", GROUP_INDENT_PLAIN) : "";
|
|
166
217
|
// Source marker between the status icon and the id. Reserve the cell (blank) for
|
|
167
218
|
// plain tasks so ids stay column-aligned whether or not a glyph is present.
|
|
168
219
|
const sourceGlyph = task.source ? TASK_SOURCE_GLYPH[task.source] : " ";
|
|
169
|
-
const styledSource = task.source ? theme.fg("dim", sourceGlyph) : " ";
|
|
220
|
+
const styledSource = !grouped && task.source ? theme.fg("dim", sourceGlyph) : grouped ? "" : " ";
|
|
170
221
|
// Right-pad the id to the shared column width so titles line up across rows even
|
|
171
222
|
// when ids differ in digit count (#1 vs #10). Padding is plain spaces inside the
|
|
172
223
|
// dim styling, so it adds no visible color.
|
|
@@ -174,7 +225,7 @@ function formatTaskLine(task, width, frame, idColWidth) {
|
|
|
174
225
|
// Source tag prefixed to the title: the subagent mode (e.g. "[explore]") for
|
|
175
226
|
// subagent rows, "[MCP]" for MCP rows. Drawn in accent so it reads as the row's
|
|
176
227
|
// origin label, parallel to the chat's `Agent [explore]` / `MCP [server › tool]`.
|
|
177
|
-
const tag = task.source === "mcp" ? "[MCP]" : task.subagentMode ? `[${task.subagentMode}]` : "";
|
|
228
|
+
const tag = grouped ? "" : task.source === "mcp" ? "[MCP]" : task.subagentMode ? `[${task.subagentMode}]` : "";
|
|
178
229
|
const styledTag = tag ? `${theme.fg("accent", tag)} ` : "";
|
|
179
230
|
const title = task.title;
|
|
180
231
|
// The id recedes (dim); the title carries the line. Done titles fade to muted
|
|
@@ -239,12 +290,90 @@ function formatTaskLine(task, width, frame, idColWidth) {
|
|
|
239
290
|
// truncateToWidth measures visible width (ANSI-aware), so the styled left can be
|
|
240
291
|
// truncated against the full left budget directly. Subtracting the prefix here
|
|
241
292
|
// (as a prior version did) truncated titles early and unevenly per id width.
|
|
242
|
-
const
|
|
293
|
+
const leftBody = grouped
|
|
294
|
+
? `${indent}${icon} ${styledId} ${styledTitle}`
|
|
295
|
+
: `${icon} ${styledSource} ${styledId} ${styledTag}${styledTitle}`;
|
|
296
|
+
const left = truncateToWidth(leftBody, leftWidth, "…");
|
|
243
297
|
if (!rightPlain)
|
|
244
298
|
return left;
|
|
245
299
|
const pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));
|
|
246
300
|
return left + " ".repeat(pad) + rightStyled;
|
|
247
301
|
}
|
|
302
|
+
/** Fallback group metadata when a task's owner has no roster entry. */
|
|
303
|
+
function defaultAgentMeta(id) {
|
|
304
|
+
return id === "main"
|
|
305
|
+
? { id, name: "main", role: "orchestrator", kind: "main" }
|
|
306
|
+
: { id, name: id, role: "subagent", kind: "subagent" };
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Partition the flat task list into owner groups. An explicit task.agent wins;
|
|
310
|
+
* otherwise a subagent-sourced task falls into a generic "subagent" group and
|
|
311
|
+
* everything else into "main". Group order is deterministic — main first, then
|
|
312
|
+
* roster order, then stragglers — never reordered by status.
|
|
313
|
+
*/
|
|
314
|
+
function groupTasks(tasks, agents) {
|
|
315
|
+
const meta = new Map(agents.map((a) => [a.id, a]));
|
|
316
|
+
const groups = new Map();
|
|
317
|
+
for (const task of tasks) {
|
|
318
|
+
const owner = task.agent ?? (task.source === "subagent" ? "subagent" : "main");
|
|
319
|
+
const items = groups.get(owner);
|
|
320
|
+
if (items)
|
|
321
|
+
items.push(task);
|
|
322
|
+
else
|
|
323
|
+
groups.set(owner, [task]);
|
|
324
|
+
}
|
|
325
|
+
const order = [];
|
|
326
|
+
if (groups.has("main"))
|
|
327
|
+
order.push("main");
|
|
328
|
+
for (const agent of agents) {
|
|
329
|
+
if (groups.has(agent.id) && !order.includes(agent.id))
|
|
330
|
+
order.push(agent.id);
|
|
331
|
+
}
|
|
332
|
+
for (const id of groups.keys()) {
|
|
333
|
+
if (!order.includes(id))
|
|
334
|
+
order.push(id);
|
|
335
|
+
}
|
|
336
|
+
return order.map((id) => ({
|
|
337
|
+
id,
|
|
338
|
+
meta: meta.get(id) ?? defaultAgentMeta(id),
|
|
339
|
+
items: groups.get(id) ?? [],
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Group header for the grouped views: owner glyph + bold name + role, the
|
|
344
|
+
* agent's lifecycle `[state]` tag, an optional handoff arrow (teams), then the
|
|
345
|
+
* agent's own token/cost totals + done/total on the right. Mirrors the footer's
|
|
346
|
+
* "every number accounted for" stance, but per agent.
|
|
347
|
+
*/
|
|
348
|
+
function formatGroupHeader(meta, items, width) {
|
|
349
|
+
const glyph = theme.fg(AGENT_GLYPH_COLOR[meta.kind], AGENT_GLYPH[meta.kind] ?? AGENT_GLYPH.subagent);
|
|
350
|
+
const name = theme.bold(meta.name);
|
|
351
|
+
// Roles read as a dim "· role" suffix for spawned/team agents; the main
|
|
352
|
+
// orchestrator's role sits brighter (muted), matching the design's .grp-role.
|
|
353
|
+
const role = meta.role
|
|
354
|
+
? meta.kind === "main"
|
|
355
|
+
? ` ${theme.fg("muted", meta.role)}`
|
|
356
|
+
: theme.fg("dim", ` · ${meta.role}`)
|
|
357
|
+
: "";
|
|
358
|
+
const state = meta.state ? ` ${theme.fg(AGENT_STATE_COLOR[meta.state] ?? "dim", `[${meta.state}]`)}` : "";
|
|
359
|
+
const handoff = meta.handoff ? ` ${theme.fg("dim", meta.handoff)}` : "";
|
|
360
|
+
const done = items.filter((t) => t.status === "done").length;
|
|
361
|
+
const countPlain = `${done}/${items.length}`;
|
|
362
|
+
const count = theme.fg("muted", `${done}`) + theme.fg("dim", "/") + theme.fg("muted", `${items.length}`);
|
|
363
|
+
const stats = meta.stats;
|
|
364
|
+
let rightPlain = countPlain;
|
|
365
|
+
let rightStyled = count;
|
|
366
|
+
if (stats && (stats.input > 0 || stats.output > 0 || stats.cost > 0)) {
|
|
367
|
+
const statsPlain = `↑${formatTokens(stats.input)} ↓${formatTokens(stats.output)} · $${stats.cost.toFixed(3)}`;
|
|
368
|
+
rightPlain = `${statsPlain} ${countPlain}`;
|
|
369
|
+
rightStyled = `${theme.fg("dim", statsPlain)} ${count}`;
|
|
370
|
+
}
|
|
371
|
+
const rightWidth = visibleWidth(rightPlain) + 1;
|
|
372
|
+
const leftWidth = Math.max(0, width - rightWidth);
|
|
373
|
+
const left = truncateToWidth(`${glyph} ${name}${role}${state}${handoff}`, leftWidth, "…");
|
|
374
|
+
const pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));
|
|
375
|
+
return left + " ".repeat(pad) + rightStyled;
|
|
376
|
+
}
|
|
248
377
|
/**
|
|
249
378
|
* Task panel rendered just above the editor prompt.
|
|
250
379
|
*
|
|
@@ -257,6 +386,11 @@ function formatTaskLine(task, width, frame, idColWidth) {
|
|
|
257
386
|
* - A single-cell source glyph (⚙ subagent / ⧉ MCP) sits before the id so the two
|
|
258
387
|
* kinds of background work are distinguishable, and a text origin tag is shown
|
|
259
388
|
* before the title: the subagent mode (e.g. "[explore]") or "[MCP]".
|
|
389
|
+
* - Three views over the same list (cycled via app.tasks.cycleView, shown as a
|
|
390
|
+
* `tasks · subagents · teams` switcher in the header): flat, grouped by owning
|
|
391
|
+
* agent (subagents), or grouped by named role-agent with handoffs (teams).
|
|
392
|
+
* Grouped rows drop their origin glyph/tag (the group header carries it) and
|
|
393
|
+
* sit on a faint `│` indent guide.
|
|
260
394
|
* - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).
|
|
261
395
|
* - Finished tasks carry their wall-clock cost and stay visible until the next
|
|
262
396
|
* user message arrives (see taskStore.reset()), not the moment they finish.
|
|
@@ -266,12 +400,27 @@ export class TaskPanelComponent {
|
|
|
266
400
|
ui;
|
|
267
401
|
frame = 0;
|
|
268
402
|
animationTimer = null;
|
|
403
|
+
view = "flat";
|
|
269
404
|
constructor(ui) {
|
|
270
405
|
this.ui = ui ?? null;
|
|
271
406
|
}
|
|
272
407
|
invalidate() {
|
|
273
408
|
// No cached rendering state.
|
|
274
409
|
}
|
|
410
|
+
getView() {
|
|
411
|
+
return this.view;
|
|
412
|
+
}
|
|
413
|
+
setView(view) {
|
|
414
|
+
this.view = view;
|
|
415
|
+
this.ui?.requestRender();
|
|
416
|
+
}
|
|
417
|
+
/** Advance to the next view lens (flat → subagents → teams → flat). */
|
|
418
|
+
cycleView() {
|
|
419
|
+
const idx = VIEW_ORDER.indexOf(this.view);
|
|
420
|
+
this.view = VIEW_ORDER[(idx + 1) % VIEW_ORDER.length] ?? "flat";
|
|
421
|
+
this.ui?.requestRender();
|
|
422
|
+
return this.view;
|
|
423
|
+
}
|
|
275
424
|
/** Run the spinner timer only while a task is active, ticking re-renders. */
|
|
276
425
|
ensureAnimation(active) {
|
|
277
426
|
if (active && this.ui && !this.animationTimer) {
|
|
@@ -310,9 +459,21 @@ export class TaskPanelComponent {
|
|
|
310
459
|
// Width of the id column, sized to the widest id on screen, so every title
|
|
311
460
|
// starts at the same column regardless of digit count (#1 vs #10 vs #100).
|
|
312
461
|
const idColWidth = tasks.reduce((max, t) => Math.max(max, `#${t.id}`.length), 0);
|
|
313
|
-
const lines = [gutter + formatHeader(tasks, inner, state, totalSecs)];
|
|
314
|
-
|
|
315
|
-
|
|
462
|
+
const lines = [gutter + formatHeader(tasks, inner, state, totalSecs, this.view)];
|
|
463
|
+
if (this.view === "flat") {
|
|
464
|
+
for (const task of tasks) {
|
|
465
|
+
lines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth));
|
|
466
|
+
}
|
|
467
|
+
return lines;
|
|
468
|
+
}
|
|
469
|
+
// Grouped lenses (subagents / teams): a header line per owning agent, its
|
|
470
|
+
// tasks indented beneath on a faint guide. Hierarchy is carried by the
|
|
471
|
+
// indent and owner glyph alone — no fills, no boxes.
|
|
472
|
+
for (const group of groupTasks(tasks, taskStore.agents())) {
|
|
473
|
+
lines.push(gutter + formatGroupHeader(group.meta, group.items, inner));
|
|
474
|
+
for (const task of group.items) {
|
|
475
|
+
lines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth, { grouped: true }));
|
|
476
|
+
}
|
|
316
477
|
}
|
|
317
478
|
return lines;
|
|
318
479
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-panel.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, TUI } from \"@kolisachint/hoocode-tui\";\nimport { truncateToWidth, visibleWidth } from \"@kolisachint/hoocode-tui\";\nimport type { Task, TaskSource, TaskStatus } from \"../../../core/task-store.js\";\nimport { taskStore } from \"../../../core/task-store.js\";\nimport { theme } from \"../theme/theme.js\";\n\nconst TASK_STATUS_ICON: Record<TaskStatus, string> = {\n\tpending: \"●\",\n\tin_progress: \"◐\",\n\tdone: \"✓\",\n\tfailed: \"✗\",\n};\n\n/**\n * A single-cell source marker placed before the id so a subagent row and an MCP\n * row are distinguishable at a glance. Plain tasks reserve the cell (blank) to keep\n * the id column aligned. The glyph says *where the work came from* at a glance; the\n * row also carries a text origin tag before the title (see formatTaskLine).\n */\nconst TASK_SOURCE_GLYPH: Record<TaskSource, string> = {\n\tsubagent: \"⚙\",\n\tmcp: \"⧉\",\n};\n\n/** Braille spinner frames + cadence, matched to the TUI Loader so the active row animates in step. */\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 80;\n\n/** A thin colored left rail groups the pane without a box, the way the design's `border-left` does. */\nconst RAIL = \"▎\";\n\n/** Cells in the deterministic progress bar (matches the design's 14-cell track). */\nconst PROGRESS_CELLS = 14;\n\n/** Overall pane state, derived from the task statuses. Drives the rail color + header stamp. */\ntype PanelState = \"working\" | \"reviewed\" | \"stopped\";\n\ninterface StatePresentation {\n\treadonly icon: string;\n\treadonly label: string;\n\treadonly color: \"warning\" | \"success\" | \"error\";\n}\n\nconst STATE_PRESENTATION: Record<PanelState, StatePresentation> = {\n\tworking: { icon: \"◐\", label: \"working\", color: \"warning\" },\n\treviewed: { icon: \"✓\", label: \"reviewed\", color: \"success\" },\n\tstopped: { icon: \"✗\", label: \"stopped\", color: \"error\" },\n};\n\nfunction panelState(tasks: readonly Task[]): PanelState {\n\tif (tasks.some((t) => t.status === \"failed\")) return \"stopped\";\n\tconst active = tasks.some((t) => t.status === \"in_progress\" || t.status === \"pending\");\n\treturn active ? \"working\" : \"reviewed\";\n}\n\nfunction taskStatusColor(status: TaskStatus): \"dim\" | \"warning\" | \"success\" | \"error\" {\n\tswitch (status) {\n\t\tcase \"in_progress\":\n\t\t\treturn \"warning\";\n\t\tcase \"done\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\n/** Format a duration in seconds into a compact, terminal-friendly string. */\nfunction formatDuration(secs: number): string {\n\tconst s = Math.max(0, secs);\n\tif (s < 10) return `${s.toFixed(1)}s`;\n\tif (s < 60) return `${Math.round(s)}s`;\n\tconst mins = Math.floor(s / 60);\n\tconst rem = Math.round(s % 60);\n\treturn `${mins}m${rem.toString().padStart(2, \"0\")}s`;\n}\n\n/** Wall-clock time a task occupied, derived from its create/update stamps. */\nfunction taskElapsedSecs(task: Task): number {\n\treturn Math.max(0, (task.updatedAt - task.createdAt) / 1000);\n}\n\n/** Sum the token + cost usage reported by the tasks shown this turn. */\nfunction sumTurnUsage(tasks: readonly Task[]): { input: number; output: number; cost: number } | null {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cost = 0;\n\tfor (const task of tasks) {\n\t\tif (!task.usage) continue;\n\t\tinput += task.usage.input;\n\t\toutput += task.usage.output;\n\t\tcost += task.usage.cost;\n\t}\n\tif (input === 0 && output === 0 && cost === 0) return null;\n\treturn { input, output, cost };\n}\n\n/**\n * Deterministic block-glyph progress bar: a heavy run (━) for the completed\n * fraction over a dim track. In-progress tasks count as half, so the bar moves\n * the moment work starts. Fraction is the only input — no animation, no guess.\n */\nfunction progressBar(done: number, active: number, total: number): { plain: string; styled: string } {\n\tconst ratio = total > 0 ? Math.max(0, Math.min(1, (done + active * 0.5) / total)) : 0;\n\tconst filled = Math.round(ratio * PROGRESS_CELLS);\n\tconst fill = \"━\".repeat(filled);\n\tconst track = \"━\".repeat(PROGRESS_CELLS - filled);\n\treturn {\n\t\tplain: fill + track,\n\t\tstyled: theme.fg(\"success\", fill) + theme.fg(\"dim\", track),\n\t};\n}\n\n/**\n * Ledger header: a state stamp (◐ working / ✓ reviewed / ✗ stopped) + a\n * deterministic progress bar and done/total count on the left, and the per-turn\n * token + elapsed + cost delta (summed across the tasks below) on the right.\n */\nfunction formatHeader(tasks: readonly Task[], width: number, state: PanelState, totalSecs: number): string {\n\tconst total = tasks.length;\n\tconst done = tasks.filter((t) => t.status === \"done\").length;\n\tconst active = tasks.filter((t) => t.status === \"in_progress\").length;\n\n\tconst { icon, label, color } = STATE_PRESENTATION[state];\n\tconst stampPlain = `${icon} ${label.toUpperCase()}`;\n\tconst stamp = `${theme.fg(color, icon)} ${theme.bold(theme.fg(color, label.toUpperCase()))}`;\n\n\tconst bar = progressBar(done, active, total);\n\tconst countPlain = `${done}/${total}`;\n\tconst count = theme.fg(\"muted\", `${done}`) + theme.fg(\"dim\", \"/\") + theme.fg(\"muted\", `${total}`);\n\n\t// Left cluster has a full form (stamp · bar · count) and a compact fallback\n\t// (stamp · count) that drops the bar when the terminal is too narrow.\n\tconst leftFullPlain = `${stampPlain} ${bar.plain} ${countPlain}`;\n\tconst leftFull = `${stamp} ${bar.styled} ${count}`;\n\tconst leftMinPlain = `${stampPlain} ${countPlain}`;\n\tconst leftMin = `${stamp} ${count}`;\n\n\tconst turn = sumTurnUsage(tasks);\n\tlet turnPlain = \"\";\n\tlet turnText = \"\";\n\tif (turn) {\n\t\tconst inTok = formatTokens(turn.input);\n\t\tconst outTok = formatTokens(turn.output);\n\t\tconst elapsed = formatDuration(totalSecs);\n\t\tconst showCost = turn.cost > 0;\n\t\tconst costStr = showCost ? `$${turn.cost.toFixed(3)}` : \"\";\n\t\tturnPlain = `turn ↑${inTok} ↓${outTok} · ${elapsed}${showCost ? ` · ${costStr}` : \"\"}`;\n\t\t// Turn delta: muted framing, numbers one step brighter (bold), separators dim.\n\t\tturnText =\n\t\t\ttheme.fg(\"muted\", \"turn ↑\") +\n\t\t\ttheme.bold(inTok) +\n\t\t\ttheme.fg(\"muted\", \" ↓\") +\n\t\t\ttheme.bold(outTok) +\n\t\t\ttheme.fg(\"dim\", \" · \") +\n\t\t\ttheme.fg(\"muted\", elapsed) +\n\t\t\t(showCost ? theme.fg(\"dim\", \" · \") + theme.bold(costStr) : \"\");\n\t}\n\n\tif (turnPlain) {\n\t\tif (visibleWidth(leftFullPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftFullPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftFull + \" \".repeat(pad) + turnText;\n\t\t}\n\t\tif (visibleWidth(leftMinPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftMin + \" \".repeat(pad) + turnText;\n\t\t}\n\t}\n\tif (visibleWidth(leftFullPlain) <= width) return leftFull;\n\treturn truncateToWidth(leftMin, width, \"…\");\n}\n\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\treturn `${(count / 1000000).toFixed(1)}M`;\n}\n\nfunction formatTaskLine(task: Task, width: number, frame: number, idColWidth: number): string {\n\tconst isProgress = task.status === \"in_progress\";\n\tconst iconGlyph = isProgress\n\t\t? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)\n\t\t: TASK_STATUS_ICON[task.status];\n\tconst icon = theme.fg(taskStatusColor(task.status), iconGlyph);\n\n\t// Source marker between the status icon and the id. Reserve the cell (blank) for\n\t// plain tasks so ids stay column-aligned whether or not a glyph is present.\n\tconst sourceGlyph = task.source ? TASK_SOURCE_GLYPH[task.source] : \" \";\n\tconst styledSource = task.source ? theme.fg(\"dim\", sourceGlyph) : \" \";\n\n\t// Right-pad the id to the shared column width so titles line up across rows even\n\t// when ids differ in digit count (#1 vs #10). Padding is plain spaces inside the\n\t// dim styling, so it adds no visible color.\n\tconst idLabel = `#${task.id}`.padEnd(idColWidth);\n\t// Source tag prefixed to the title: the subagent mode (e.g. \"[explore]\") for\n\t// subagent rows, \"[MCP]\" for MCP rows. Drawn in accent so it reads as the row's\n\t// origin label, parallel to the chat's `Agent [explore]` / `MCP [server › tool]`.\n\tconst tag = task.source === \"mcp\" ? \"[MCP]\" : task.subagentMode ? `[${task.subagentMode}]` : \"\";\n\tconst styledTag = tag ? `${theme.fg(\"accent\", tag)} ` : \"\";\n\tconst title = task.title;\n\t// The id recedes (dim); the title carries the line. Done titles fade to muted\n\t// (settled work), pending dim (not started), active goes bold, failed turns red.\n\tconst styledId = theme.fg(\"dim\", idLabel);\n\tlet styledTitle: string;\n\tswitch (task.status) {\n\t\tcase \"done\":\n\t\t\tstyledTitle = theme.fg(\"muted\", title);\n\t\t\tbreak;\n\t\tcase \"pending\":\n\t\t\tstyledTitle = theme.fg(\"dim\", title);\n\t\t\tbreak;\n\t\tcase \"failed\":\n\t\t\tstyledTitle = theme.fg(\"error\", title);\n\t\t\tbreak;\n\t\tcase \"in_progress\":\n\t\t\tstyledTitle = theme.bold(title);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstyledTitle = title;\n\t}\n\n\t// Right column: settled rows carry their audit stamp (tokens + elapsed); the\n\t// active row reads `running…`, pending rows read `queued`.\n\tlet rightPlain = \"\";\n\tlet rightStyled = \"\";\n\tif (task.status === \"done\" || task.status === \"failed\") {\n\t\tconst parts: string[] = [];\n\t\tlet tokenText = \"\";\n\t\tif (task.usage) {\n\t\t\tconst totalTok = task.usage.input + task.usage.output;\n\t\t\tif (totalTok > 0) tokenText = formatTokens(totalTok);\n\t\t}\n\t\tconst elapsed = formatDuration(taskElapsedSecs(task));\n\t\tif (tokenText) {\n\t\t\tparts.push(tokenText, elapsed);\n\t\t\trightStyled = theme.fg(\"muted\", tokenText) + theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t} else {\n\t\t\tparts.push(elapsed);\n\t\t\trightStyled = theme.fg(\"dim\", elapsed);\n\t\t}\n\t\trightPlain = parts.join(\" · \");\n\t} else if (task.status === \"in_progress\") {\n\t\trightPlain = \"running…\";\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t} else if (task.status === \"pending\") {\n\t\trightPlain = \"queued\";\n\t\trightStyled = theme.fg(\"dim\", rightPlain);\n\t}\n\n\t// A warning note (e.g. inherited-model fallback, exhaustion skip) takes over the\n\t// right column as a ⚠ cue, replacing the usage/status stamp for that row.\n\tif (task.note) {\n\t\trightPlain = `⚠ ${task.note}`;\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t}\n\n\tconst rightWidth = rightPlain ? visibleWidth(rightPlain) + 1 : 0;\n\tconst leftWidth = Math.max(0, width - rightWidth);\n\n\t// truncateToWidth measures visible width (ANSI-aware), so the styled left can be\n\t// truncated against the full left budget directly. Subtracting the prefix here\n\t// (as a prior version did) truncated titles early and unevenly per id width.\n\tconst left = truncateToWidth(`${icon} ${styledSource} ${styledId} ${styledTag}${styledTitle}`, leftWidth, \"…\");\n\n\tif (!rightPlain) return left;\n\n\tconst pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));\n\treturn left + \" \".repeat(pad) + rightStyled;\n}\n\n/**\n * Task panel rendered just above the editor prompt.\n *\n * - A state-colored left rail groups the pane (working=warning, reviewed=success,\n * stopped=error) without drawing a box.\n * - A ledger header tops the list: a state stamp + deterministic progress bar +\n * done/total count on the left, the per-turn token/elapsed/cost delta on the right.\n * - Shows all tasks with all statuses (pending / in_progress / done / failed).\n * The active row animates a braille spinner; pending rows read `queued`.\n * - A single-cell source glyph (⚙ subagent / ⧉ MCP) sits before the id so the two\n * kinds of background work are distinguishable, and a text origin tag is shown\n * before the title: the subagent mode (e.g. \"[explore]\") or \"[MCP]\".\n * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).\n * - Finished tasks carry their wall-clock cost and stay visible until the next\n * user message arrives (see taskStore.reset()), not the moment they finish.\n * - Collapses to zero lines when there are no tasks.\n */\nexport class TaskPanelComponent implements Component {\n\tprivate readonly ui: TUI | null;\n\tprivate frame = 0;\n\tprivate animationTimer: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(ui?: TUI) {\n\t\tthis.ui = ui ?? null;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached rendering state.\n\t}\n\n\t/** Run the spinner timer only while a task is active, ticking re-renders. */\n\tprivate ensureAnimation(active: boolean): void {\n\t\tif (active && this.ui && !this.animationTimer) {\n\t\t\tthis.animationTimer = setInterval(() => {\n\t\t\t\tthis.frame = (this.frame + 1) % SPINNER_FRAMES.length;\n\t\t\t\tthis.ui?.requestRender();\n\t\t\t}, SPINNER_INTERVAL_MS);\n\t\t\tthis.animationTimer.unref?.();\n\t\t} else if (!active && this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t\tthis.frame = 0;\n\t\t}\n\t}\n\n\t/** Stop the spinner timer. Call on teardown. */\n\tdispose(): void {\n\t\tif (this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tasks = taskStore.list();\n\t\tif (tasks.length === 0) {\n\t\t\tthis.ensureAnimation(false);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasActive = tasks.some((t) => t.status === \"in_progress\");\n\t\tthis.ensureAnimation(hasActive);\n\n\t\tconst state = panelState(tasks);\n\t\tconst totalSecs = tasks.reduce((sum, t) => sum + taskElapsedSecs(t), 0);\n\t\tconst railColor = STATE_PRESENTATION[state].color;\n\t\tconst gutter = `${theme.fg(railColor, RAIL)} `;\n\t\tconst inner = Math.max(0, width - visibleWidth(RAIL) - 1);\n\n\t\t// Width of the id column, sized to the widest id on screen, so every title\n\t\t// starts at the same column regardless of digit count (#1 vs #10 vs #100).\n\t\tconst idColWidth = tasks.reduce((max, t) => Math.max(max, `#${t.id}`.length), 0);\n\n\t\tconst lines: string[] = [gutter + formatHeader(tasks, inner, state, totalSecs)];\n\t\tfor (const task of tasks) {\n\t\t\tlines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth));\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-panel.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, TUI } from \"@kolisachint/hoocode-tui\";\nimport { truncateToWidth, visibleWidth } from \"@kolisachint/hoocode-tui\";\nimport type {\n\tTask,\n\tTaskAgent,\n\tTaskAgentKind,\n\tTaskAgentState,\n\tTaskSource,\n\tTaskStatus,\n} from \"../../../core/task-store.js\";\nimport { taskStore } from \"../../../core/task-store.js\";\nimport type { ThemeColor } from \"../theme/theme.js\";\nimport { theme } from \"../theme/theme.js\";\n\nconst TASK_STATUS_ICON: Record<TaskStatus, string> = {\n\tpending: \"●\",\n\tin_progress: \"◐\",\n\tdone: \"✓\",\n\tfailed: \"✗\",\n};\n\n/**\n * A single-cell source marker placed before the id so a subagent row and an MCP\n * row are distinguishable at a glance. Plain tasks reserve the cell (blank) to keep\n * the id column aligned. The glyph says *where the work came from* at a glance; the\n * row also carries a text origin tag before the title (see formatTaskLine).\n */\nconst TASK_SOURCE_GLYPH: Record<TaskSource, string> = {\n\tsubagent: \"⚙\",\n\tmcp: \"⧉\",\n};\n\n/** Braille spinner frames + cadence, matched to the TUI Loader so the active row animates in step. */\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 80;\n\n/** A thin colored left rail groups the pane without a box, the way the design's `border-left` does. */\nconst RAIL = \"▎\";\n\n/** Cells in the deterministic progress bar (matches the design's 14-cell track). */\nconst PROGRESS_CELLS = 14;\n\n/**\n * How the same task list is presented:\n * - flat → one ungrouped list (default)\n * - subagents → grouped by owning agent (◆ main orchestrator + ⊕ workers)\n * - teams → grouped by named role-agent (▸), with handoff arrows\n */\nexport type TaskPanelView = \"flat\" | \"subagents\" | \"teams\";\n\nconst VIEW_ORDER: readonly TaskPanelView[] = [\"flat\", \"subagents\", \"teams\"];\nconst VIEW_LABEL: Record<TaskPanelView, string> = { flat: \"tasks\", subagents: \"subagents\", teams: \"teams\" };\n\n/** Owner glyphs: main agent a filled diamond, spawned subagents a plus-in-circle, team roles a triangle. */\nconst AGENT_GLYPH: Record<TaskAgentKind, string> = { main: \"◆\", subagent: \"⊕\", role: \"▸\" };\nconst AGENT_GLYPH_COLOR: Record<TaskAgentKind, ThemeColor> = {\n\tmain: \"accent\",\n\tsubagent: \"accent\",\n\trole: \"borderAccent\",\n};\n\n/** Color for an agent's lifecycle `[state]` tag (mirrors the design's .ast-* classes). */\nconst AGENT_STATE_COLOR: Record<TaskAgentState, ThemeColor> = {\n\tactive: \"warning\",\n\trunning: \"warning\",\n\tdone: \"success\",\n\tqueued: \"dim\",\n\tidle: \"dim\",\n\twaiting: \"mdLink\",\n\tfailed: \"error\",\n};\n\n/** Two-cell indent under a group header, with a faint vertical guide. */\nconst GROUP_INDENT_PLAIN = \"│ \";\n\n/** Overall pane state, derived from the task statuses. Drives the rail color + header stamp. */\ntype PanelState = \"working\" | \"reviewed\" | \"stopped\";\n\ninterface StatePresentation {\n\treadonly icon: string;\n\treadonly label: string;\n\treadonly color: \"warning\" | \"success\" | \"error\";\n}\n\nconst STATE_PRESENTATION: Record<PanelState, StatePresentation> = {\n\tworking: { icon: \"◐\", label: \"working\", color: \"warning\" },\n\treviewed: { icon: \"✓\", label: \"reviewed\", color: \"success\" },\n\tstopped: { icon: \"✗\", label: \"stopped\", color: \"error\" },\n};\n\nfunction panelState(tasks: readonly Task[]): PanelState {\n\tif (tasks.some((t) => t.status === \"failed\")) return \"stopped\";\n\tconst active = tasks.some((t) => t.status === \"in_progress\" || t.status === \"pending\");\n\treturn active ? \"working\" : \"reviewed\";\n}\n\nfunction taskStatusColor(status: TaskStatus): \"dim\" | \"warning\" | \"success\" | \"error\" {\n\tswitch (status) {\n\t\tcase \"in_progress\":\n\t\t\treturn \"warning\";\n\t\tcase \"done\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\n/** Format a duration in seconds into a compact, terminal-friendly string. */\nfunction formatDuration(secs: number): string {\n\tconst s = Math.max(0, secs);\n\tif (s < 10) return `${s.toFixed(1)}s`;\n\tif (s < 60) return `${Math.round(s)}s`;\n\tconst mins = Math.floor(s / 60);\n\tconst rem = Math.round(s % 60);\n\treturn `${mins}m${rem.toString().padStart(2, \"0\")}s`;\n}\n\n/** Wall-clock time a task occupied, derived from its create/update stamps. */\nfunction taskElapsedSecs(task: Task): number {\n\treturn Math.max(0, (task.updatedAt - task.createdAt) / 1000);\n}\n\n/** Sum the token + cost usage reported by the tasks shown this turn. */\nfunction sumTurnUsage(tasks: readonly Task[]): { input: number; output: number; cost: number } | null {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cost = 0;\n\tfor (const task of tasks) {\n\t\tif (!task.usage) continue;\n\t\tinput += task.usage.input;\n\t\toutput += task.usage.output;\n\t\tcost += task.usage.cost;\n\t}\n\tif (input === 0 && output === 0 && cost === 0) return null;\n\treturn { input, output, cost };\n}\n\n/**\n * Deterministic block-glyph progress bar: a heavy run (━) for the completed\n * fraction over a dim track. In-progress tasks count as half, so the bar moves\n * the moment work starts. Fraction is the only input — no animation, no guess.\n */\nfunction progressBar(done: number, active: number, total: number): { plain: string; styled: string } {\n\tconst ratio = total > 0 ? Math.max(0, Math.min(1, (done + active * 0.5) / total)) : 0;\n\tconst filled = Math.round(ratio * PROGRESS_CELLS);\n\tconst fill = \"━\".repeat(filled);\n\tconst track = \"━\".repeat(PROGRESS_CELLS - filled);\n\treturn {\n\t\tplain: fill + track,\n\t\tstyled: theme.fg(\"success\", fill) + theme.fg(\"dim\", track),\n\t};\n}\n\n/**\n * View switcher rendered at the right edge of the ledger header: the three\n * lens labels joined by `·`, the active one in bold accent. Purely an\n * indicator in the TUI — the bound key cycles it (see app.tasks.cycleView).\n */\nfunction formatViewSwitcher(view: TaskPanelView): { plain: string; styled: string } {\n\tconst plain = VIEW_ORDER.map((v) => VIEW_LABEL[v]).join(\" · \");\n\tconst styled = VIEW_ORDER.map((v) =>\n\t\tv === view ? theme.bold(theme.fg(\"accent\", VIEW_LABEL[v])) : theme.fg(\"dim\", VIEW_LABEL[v]),\n\t).join(theme.fg(\"dim\", \" · \"));\n\treturn { plain, styled };\n}\n\n/**\n * Ledger header: a state stamp (◐ working / ✓ reviewed / ✗ stopped) + a\n * deterministic progress bar and done/total count on the left, and the per-turn\n * token + elapsed + cost delta (summed across the tasks below) plus the view\n * switcher on the right.\n */\nfunction formatHeader(\n\ttasks: readonly Task[],\n\twidth: number,\n\tstate: PanelState,\n\ttotalSecs: number,\n\tview: TaskPanelView,\n): string {\n\tconst total = tasks.length;\n\tconst done = tasks.filter((t) => t.status === \"done\").length;\n\tconst active = tasks.filter((t) => t.status === \"in_progress\").length;\n\n\tconst { icon, label, color } = STATE_PRESENTATION[state];\n\tconst stampPlain = `${icon} ${label.toUpperCase()}`;\n\tconst stamp = `${theme.fg(color, icon)} ${theme.bold(theme.fg(color, label.toUpperCase()))}`;\n\n\tconst bar = progressBar(done, active, total);\n\tconst countPlain = `${done}/${total}`;\n\tconst count = theme.fg(\"muted\", `${done}`) + theme.fg(\"dim\", \"/\") + theme.fg(\"muted\", `${total}`);\n\n\t// Left cluster has a full form (stamp · bar · count) and a compact fallback\n\t// (stamp · count) that drops the bar when the terminal is too narrow.\n\tconst leftFullPlain = `${stampPlain} ${bar.plain} ${countPlain}`;\n\tconst leftFull = `${stamp} ${bar.styled} ${count}`;\n\tconst leftMinPlain = `${stampPlain} ${countPlain}`;\n\tconst leftMin = `${stamp} ${count}`;\n\n\tconst turn = sumTurnUsage(tasks);\n\tlet turnPlain = \"\";\n\tlet turnText = \"\";\n\tif (turn) {\n\t\tconst inTok = formatTokens(turn.input);\n\t\tconst outTok = formatTokens(turn.output);\n\t\tconst elapsed = formatDuration(totalSecs);\n\t\tconst showCost = turn.cost > 0;\n\t\tconst costStr = showCost ? `$${turn.cost.toFixed(3)}` : \"\";\n\t\tturnPlain = `turn ↑${inTok} ↓${outTok} · ${elapsed}${showCost ? ` · ${costStr}` : \"\"}`;\n\t\t// Turn delta: muted framing, numbers one step brighter (bold), separators dim.\n\t\tturnText =\n\t\t\ttheme.fg(\"muted\", \"turn ↑\") +\n\t\t\ttheme.bold(inTok) +\n\t\t\ttheme.fg(\"muted\", \" ↓\") +\n\t\t\ttheme.bold(outTok) +\n\t\t\ttheme.fg(\"dim\", \" · \") +\n\t\t\ttheme.fg(\"muted\", elapsed) +\n\t\t\t(showCost ? theme.fg(\"dim\", \" · \") + theme.bold(costStr) : \"\");\n\t}\n\n\t// Right cluster: turn delta, then the view switcher at the far edge. The\n\t// switcher is the first thing dropped when the terminal narrows; the turn\n\t// delta next; the stamp/count survive to the end.\n\tconst switcher = formatViewSwitcher(view);\n\tconst rightVariants: Array<{ plain: string; styled: string }> = [];\n\tif (turnPlain) {\n\t\trightVariants.push({\n\t\t\tplain: `${turnPlain} ${switcher.plain}`,\n\t\t\tstyled: `${turnText} ${switcher.styled}`,\n\t\t});\n\t\trightVariants.push({ plain: turnPlain, styled: turnText });\n\t} else {\n\t\trightVariants.push(switcher);\n\t}\n\n\tfor (const right of rightVariants) {\n\t\tif (visibleWidth(leftFullPlain) + 2 + visibleWidth(right.plain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftFullPlain) - visibleWidth(right.plain));\n\t\t\treturn leftFull + \" \".repeat(pad) + right.styled;\n\t\t}\n\t\tif (visibleWidth(leftMinPlain) + 2 + visibleWidth(right.plain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(right.plain));\n\t\t\treturn leftMin + \" \".repeat(pad) + right.styled;\n\t\t}\n\t}\n\tif (visibleWidth(leftFullPlain) <= width) return leftFull;\n\treturn truncateToWidth(leftMin, width, \"…\");\n}\n\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\treturn `${(count / 1000000).toFixed(1)}M`;\n}\n\nfunction formatTaskLine(\n\ttask: Task,\n\twidth: number,\n\tframe: number,\n\tidColWidth: number,\n\toptions: { grouped?: boolean } = {},\n): string {\n\tconst isProgress = task.status === \"in_progress\";\n\tconst iconGlyph = isProgress\n\t\t? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)\n\t\t: TASK_STATUS_ICON[task.status];\n\tconst icon = theme.fg(taskStatusColor(task.status), iconGlyph);\n\n\t// In grouped views the group header already carries the row's origin, so the\n\t// source glyph and tag are suppressed; the rows sit on a faint indent guide.\n\tconst grouped = options.grouped === true;\n\tconst indent = grouped ? theme.fg(\"borderMuted\", GROUP_INDENT_PLAIN) : \"\";\n\n\t// Source marker between the status icon and the id. Reserve the cell (blank) for\n\t// plain tasks so ids stay column-aligned whether or not a glyph is present.\n\tconst sourceGlyph = task.source ? TASK_SOURCE_GLYPH[task.source] : \" \";\n\tconst styledSource = !grouped && task.source ? theme.fg(\"dim\", sourceGlyph) : grouped ? \"\" : \" \";\n\n\t// Right-pad the id to the shared column width so titles line up across rows even\n\t// when ids differ in digit count (#1 vs #10). Padding is plain spaces inside the\n\t// dim styling, so it adds no visible color.\n\tconst idLabel = `#${task.id}`.padEnd(idColWidth);\n\t// Source tag prefixed to the title: the subagent mode (e.g. \"[explore]\") for\n\t// subagent rows, \"[MCP]\" for MCP rows. Drawn in accent so it reads as the row's\n\t// origin label, parallel to the chat's `Agent [explore]` / `MCP [server › tool]`.\n\tconst tag = grouped ? \"\" : task.source === \"mcp\" ? \"[MCP]\" : task.subagentMode ? `[${task.subagentMode}]` : \"\";\n\tconst styledTag = tag ? `${theme.fg(\"accent\", tag)} ` : \"\";\n\tconst title = task.title;\n\t// The id recedes (dim); the title carries the line. Done titles fade to muted\n\t// (settled work), pending dim (not started), active goes bold, failed turns red.\n\tconst styledId = theme.fg(\"dim\", idLabel);\n\tlet styledTitle: string;\n\tswitch (task.status) {\n\t\tcase \"done\":\n\t\t\tstyledTitle = theme.fg(\"muted\", title);\n\t\t\tbreak;\n\t\tcase \"pending\":\n\t\t\tstyledTitle = theme.fg(\"dim\", title);\n\t\t\tbreak;\n\t\tcase \"failed\":\n\t\t\tstyledTitle = theme.fg(\"error\", title);\n\t\t\tbreak;\n\t\tcase \"in_progress\":\n\t\t\tstyledTitle = theme.bold(title);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstyledTitle = title;\n\t}\n\n\t// Right column: settled rows carry their audit stamp (tokens + elapsed); the\n\t// active row reads `running…`, pending rows read `queued`.\n\tlet rightPlain = \"\";\n\tlet rightStyled = \"\";\n\tif (task.status === \"done\" || task.status === \"failed\") {\n\t\tconst parts: string[] = [];\n\t\tlet tokenText = \"\";\n\t\tif (task.usage) {\n\t\t\tconst totalTok = task.usage.input + task.usage.output;\n\t\t\tif (totalTok > 0) tokenText = formatTokens(totalTok);\n\t\t}\n\t\tconst elapsed = formatDuration(taskElapsedSecs(task));\n\t\tif (tokenText) {\n\t\t\tparts.push(tokenText, elapsed);\n\t\t\trightStyled = theme.fg(\"muted\", tokenText) + theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t} else {\n\t\t\tparts.push(elapsed);\n\t\t\trightStyled = theme.fg(\"dim\", elapsed);\n\t\t}\n\t\trightPlain = parts.join(\" · \");\n\t} else if (task.status === \"in_progress\") {\n\t\trightPlain = \"running…\";\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t} else if (task.status === \"pending\") {\n\t\trightPlain = \"queued\";\n\t\trightStyled = theme.fg(\"dim\", rightPlain);\n\t}\n\n\t// A warning note (e.g. inherited-model fallback, exhaustion skip) takes over the\n\t// right column as a ⚠ cue, replacing the usage/status stamp for that row.\n\tif (task.note) {\n\t\trightPlain = `⚠ ${task.note}`;\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t}\n\n\tconst rightWidth = rightPlain ? visibleWidth(rightPlain) + 1 : 0;\n\tconst leftWidth = Math.max(0, width - rightWidth);\n\n\t// truncateToWidth measures visible width (ANSI-aware), so the styled left can be\n\t// truncated against the full left budget directly. Subtracting the prefix here\n\t// (as a prior version did) truncated titles early and unevenly per id width.\n\tconst leftBody = grouped\n\t\t? `${indent}${icon} ${styledId} ${styledTitle}`\n\t\t: `${icon} ${styledSource} ${styledId} ${styledTag}${styledTitle}`;\n\tconst left = truncateToWidth(leftBody, leftWidth, \"…\");\n\n\tif (!rightPlain) return left;\n\n\tconst pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));\n\treturn left + \" \".repeat(pad) + rightStyled;\n}\n\n/** Fallback group metadata when a task's owner has no roster entry. */\nfunction defaultAgentMeta(id: string): TaskAgent {\n\treturn id === \"main\"\n\t\t? { id, name: \"main\", role: \"orchestrator\", kind: \"main\" }\n\t\t: { id, name: id, role: \"subagent\", kind: \"subagent\" };\n}\n\n/**\n * Partition the flat task list into owner groups. An explicit task.agent wins;\n * otherwise a subagent-sourced task falls into a generic \"subagent\" group and\n * everything else into \"main\". Group order is deterministic — main first, then\n * roster order, then stragglers — never reordered by status.\n */\nfunction groupTasks(\n\ttasks: readonly Task[],\n\tagents: readonly TaskAgent[],\n): Array<{ id: string; meta: TaskAgent; items: Task[] }> {\n\tconst meta = new Map<string, TaskAgent>(agents.map((a) => [a.id, a]));\n\tconst groups = new Map<string, Task[]>();\n\tfor (const task of tasks) {\n\t\tconst owner = task.agent ?? (task.source === \"subagent\" ? \"subagent\" : \"main\");\n\t\tconst items = groups.get(owner);\n\t\tif (items) items.push(task);\n\t\telse groups.set(owner, [task]);\n\t}\n\tconst order: string[] = [];\n\tif (groups.has(\"main\")) order.push(\"main\");\n\tfor (const agent of agents) {\n\t\tif (groups.has(agent.id) && !order.includes(agent.id)) order.push(agent.id);\n\t}\n\tfor (const id of groups.keys()) {\n\t\tif (!order.includes(id)) order.push(id);\n\t}\n\treturn order.map((id) => ({\n\t\tid,\n\t\tmeta: meta.get(id) ?? defaultAgentMeta(id),\n\t\titems: groups.get(id) ?? [],\n\t}));\n}\n\n/**\n * Group header for the grouped views: owner glyph + bold name + role, the\n * agent's lifecycle `[state]` tag, an optional handoff arrow (teams), then the\n * agent's own token/cost totals + done/total on the right. Mirrors the footer's\n * \"every number accounted for\" stance, but per agent.\n */\nfunction formatGroupHeader(meta: TaskAgent, items: readonly Task[], width: number): string {\n\tconst glyph = theme.fg(AGENT_GLYPH_COLOR[meta.kind], AGENT_GLYPH[meta.kind] ?? AGENT_GLYPH.subagent);\n\tconst name = theme.bold(meta.name);\n\t// Roles read as a dim \"· role\" suffix for spawned/team agents; the main\n\t// orchestrator's role sits brighter (muted), matching the design's .grp-role.\n\tconst role = meta.role\n\t\t? meta.kind === \"main\"\n\t\t\t? ` ${theme.fg(\"muted\", meta.role)}`\n\t\t\t: theme.fg(\"dim\", ` · ${meta.role}`)\n\t\t: \"\";\n\tconst state = meta.state ? ` ${theme.fg(AGENT_STATE_COLOR[meta.state] ?? \"dim\", `[${meta.state}]`)}` : \"\";\n\tconst handoff = meta.handoff ? ` ${theme.fg(\"dim\", meta.handoff)}` : \"\";\n\n\tconst done = items.filter((t) => t.status === \"done\").length;\n\tconst countPlain = `${done}/${items.length}`;\n\tconst count = theme.fg(\"muted\", `${done}`) + theme.fg(\"dim\", \"/\") + theme.fg(\"muted\", `${items.length}`);\n\tconst stats = meta.stats;\n\tlet rightPlain = countPlain;\n\tlet rightStyled = count;\n\tif (stats && (stats.input > 0 || stats.output > 0 || stats.cost > 0)) {\n\t\tconst statsPlain = `↑${formatTokens(stats.input)} ↓${formatTokens(stats.output)} · $${stats.cost.toFixed(3)}`;\n\t\trightPlain = `${statsPlain} ${countPlain}`;\n\t\trightStyled = `${theme.fg(\"dim\", statsPlain)} ${count}`;\n\t}\n\n\tconst rightWidth = visibleWidth(rightPlain) + 1;\n\tconst leftWidth = Math.max(0, width - rightWidth);\n\tconst left = truncateToWidth(`${glyph} ${name}${role}${state}${handoff}`, leftWidth, \"…\");\n\tconst pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));\n\treturn left + \" \".repeat(pad) + rightStyled;\n}\n\n/**\n * Task panel rendered just above the editor prompt.\n *\n * - A state-colored left rail groups the pane (working=warning, reviewed=success,\n * stopped=error) without drawing a box.\n * - A ledger header tops the list: a state stamp + deterministic progress bar +\n * done/total count on the left, the per-turn token/elapsed/cost delta on the right.\n * - Shows all tasks with all statuses (pending / in_progress / done / failed).\n * The active row animates a braille spinner; pending rows read `queued`.\n * - A single-cell source glyph (⚙ subagent / ⧉ MCP) sits before the id so the two\n * kinds of background work are distinguishable, and a text origin tag is shown\n * before the title: the subagent mode (e.g. \"[explore]\") or \"[MCP]\".\n * - Three views over the same list (cycled via app.tasks.cycleView, shown as a\n * `tasks · subagents · teams` switcher in the header): flat, grouped by owning\n * agent (subagents), or grouped by named role-agent with handoffs (teams).\n * Grouped rows drop their origin glyph/tag (the group header carries it) and\n * sit on a faint `│` indent guide.\n * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).\n * - Finished tasks carry their wall-clock cost and stay visible until the next\n * user message arrives (see taskStore.reset()), not the moment they finish.\n * - Collapses to zero lines when there are no tasks.\n */\nexport class TaskPanelComponent implements Component {\n\tprivate readonly ui: TUI | null;\n\tprivate frame = 0;\n\tprivate animationTimer: ReturnType<typeof setInterval> | null = null;\n\tprivate view: TaskPanelView = \"flat\";\n\n\tconstructor(ui?: TUI) {\n\t\tthis.ui = ui ?? null;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached rendering state.\n\t}\n\n\tgetView(): TaskPanelView {\n\t\treturn this.view;\n\t}\n\n\tsetView(view: TaskPanelView): void {\n\t\tthis.view = view;\n\t\tthis.ui?.requestRender();\n\t}\n\n\t/** Advance to the next view lens (flat → subagents → teams → flat). */\n\tcycleView(): TaskPanelView {\n\t\tconst idx = VIEW_ORDER.indexOf(this.view);\n\t\tthis.view = VIEW_ORDER[(idx + 1) % VIEW_ORDER.length] ?? \"flat\";\n\t\tthis.ui?.requestRender();\n\t\treturn this.view;\n\t}\n\n\t/** Run the spinner timer only while a task is active, ticking re-renders. */\n\tprivate ensureAnimation(active: boolean): void {\n\t\tif (active && this.ui && !this.animationTimer) {\n\t\t\tthis.animationTimer = setInterval(() => {\n\t\t\t\tthis.frame = (this.frame + 1) % SPINNER_FRAMES.length;\n\t\t\t\tthis.ui?.requestRender();\n\t\t\t}, SPINNER_INTERVAL_MS);\n\t\t\tthis.animationTimer.unref?.();\n\t\t} else if (!active && this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t\tthis.frame = 0;\n\t\t}\n\t}\n\n\t/** Stop the spinner timer. Call on teardown. */\n\tdispose(): void {\n\t\tif (this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tasks = taskStore.list();\n\t\tif (tasks.length === 0) {\n\t\t\tthis.ensureAnimation(false);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasActive = tasks.some((t) => t.status === \"in_progress\");\n\t\tthis.ensureAnimation(hasActive);\n\n\t\tconst state = panelState(tasks);\n\t\tconst totalSecs = tasks.reduce((sum, t) => sum + taskElapsedSecs(t), 0);\n\t\tconst railColor = STATE_PRESENTATION[state].color;\n\t\tconst gutter = `${theme.fg(railColor, RAIL)} `;\n\t\tconst inner = Math.max(0, width - visibleWidth(RAIL) - 1);\n\n\t\t// Width of the id column, sized to the widest id on screen, so every title\n\t\t// starts at the same column regardless of digit count (#1 vs #10 vs #100).\n\t\tconst idColWidth = tasks.reduce((max, t) => Math.max(max, `#${t.id}`.length), 0);\n\n\t\tconst lines: string[] = [gutter + formatHeader(tasks, inner, state, totalSecs, this.view)];\n\t\tif (this.view === \"flat\") {\n\t\t\tfor (const task of tasks) {\n\t\t\t\tlines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth));\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Grouped lenses (subagents / teams): a header line per owning agent, its\n\t\t// tasks indented beneath on a faint guide. Hierarchy is carried by the\n\t\t// indent and owner glyph alone — no fills, no boxes.\n\t\tfor (const group of groupTasks(tasks, taskStore.agents())) {\n\t\t\tlines.push(gutter + formatGroupHeader(group.meta, group.items, inner));\n\t\t\tfor (const task of group.items) {\n\t\t\t\tlines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth, { grouped: true }));\n\t\t\t}\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}
|