@bahulam/code 0.1.11 → 0.1.12

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.
@@ -34,8 +34,8 @@ import * as queue from '../ui/render-queue.mjs';
34
34
  // queue active) → coalesced last-wins status that can never interleave
35
35
  // with content. Legacy dock path and bare-TTY inPlace stay as fallbacks
36
36
  // until their write-sites migrate onto the queue too.
37
- // Max inner-tool lines shown under the spinner during a sub-agent run.
38
- const SUB_AGENT_WINDOW_ROWS = 7;
37
+ // Max live-window lines under the spinner during a sub-agent run.
38
+ const SUB_AGENT_WINDOW_ROWS = 8;
39
39
 
40
40
  function statusWidth() {
41
41
  return Math.max(8, (process.stderr.columns || process.stdout.columns || 120) - 1);
@@ -49,6 +49,18 @@ function fitStatusLines(lines) {
49
49
  return (Array.isArray(lines) ? lines : [lines]).map(fitStatusLine);
50
50
  }
51
51
 
52
+ function subAgentWindowLines(win) {
53
+ if (win?.groups instanceof Map && win.groups.size) {
54
+ const lines = [];
55
+ for (const group of win.groups.values()) {
56
+ if (group?.header) lines.push(group.header);
57
+ for (const line of group?.lines || []) lines.push(line);
58
+ }
59
+ return lines;
60
+ }
61
+ return (win?.lines || []).slice(-SUB_AGENT_WINDOW_ROWS);
62
+ }
63
+
52
64
  function presentStatus(rendered) {
53
65
  // Watch panel override: when active, render the watch panel entries as a
54
66
  // multi-line status block instead of the normal spinner/status line.
@@ -69,10 +81,11 @@ function presentStatus(rendered) {
69
81
  const fitted = fitStatusLine(rendered);
70
82
  if (queue.isActive()) {
71
83
  const win = runtime.subAgentWindow;
72
- if (win?.active && win.lines.length) {
84
+ const subAgentLines = subAgentWindowLines(win);
85
+ if (win?.active && subAgentLines.length) {
73
86
  queue.statusBlock([
74
87
  fitted,
75
- ...fitStatusLines(win.lines.slice(-SUB_AGENT_WINDOW_ROWS).map(l => ` ${c.dim(l)}`)),
88
+ ...fitStatusLines(subAgentLines.map(l => ` ${c.dim(l)}`)),
76
89
  ]);
77
90
  return;
78
91
  }
@@ -95,7 +108,7 @@ export function pushSubAgentWindowLine(line) {
95
108
  }
96
109
 
97
110
  export function setSubAgentWindowActive(active) {
98
- runtime.subAgentWindow = { active: Boolean(active), lines: [] };
111
+ runtime.subAgentWindow = { active: Boolean(active), lines: [], groups: new Map() };
99
112
  }
100
113
 
101
114
  /**
@@ -109,6 +122,25 @@ export function rebuildSubAgentWindow(lines) {
109
122
  const win = runtime.subAgentWindow;
110
123
  if (!win?.active) return;
111
124
  win.lines = Array.isArray(lines) ? lines.slice() : [];
125
+ win.groups = new Map();
126
+ repaintSpinnerStatus();
127
+ }
128
+
129
+ export function rebuildSubAgentWindowGroups(groups) {
130
+ const win = runtime.subAgentWindow;
131
+ if (!win?.active) return;
132
+ win.groups = new Map();
133
+ win.lines = [];
134
+ for (const group of Array.isArray(groups) ? groups : []) {
135
+ const key = group?.runId || group?.key || group?.label;
136
+ if (!key) continue;
137
+ win.groups.set(key, {
138
+ runId: group.runId || null,
139
+ label: group.label || 'sub-agent',
140
+ header: group.header || group.label || 'sub-agent',
141
+ lines: Array.isArray(group.lines) ? group.lines.slice() : [],
142
+ });
143
+ }
112
144
  repaintSpinnerStatus();
113
145
  }
114
146
 
@@ -308,11 +340,27 @@ export function renderToolCall(data) {
308
340
  const args = data?.args || {};
309
341
  const indent = subAgentIndent();
310
342
  const callId = data?.call_id || data?._callId || `${tool}:${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
343
+ const fromSubAgent = Boolean(data?.internal || data?.sub_agent || data?.sub_agent_label || data?.sub_agent_run_id);
311
344
 
312
345
  // If a previous head is still pending (no result yet), flush it as a
313
346
  // regular two-line shape before starting the next one.
314
347
  flushPendingHead();
315
348
 
349
+ // Sub-agent live window (queue mode): inner tool calls stream into the
350
+ // fixed-height status block instead of appending transcript lines. Keep
351
+ // this ahead of explore-collapse so parallel explores do not merge into
352
+ // one global read/search spinner.
353
+ if (fromSubAgent && queue.isActive() && runtime.subAgentWindow?.active) {
354
+ recordCard({ id: callId, tool, args, startedAt: Date.now() });
355
+ session.toolCounts[tool] = (session.toolCounts[tool] || 0) + 1;
356
+ const label = readToolLabel(tool, { args });
357
+ const runId = data?.run_id || data?.sub_agent_run_id || '';
358
+ const runSuffix = runId ? ` run ${String(runId).slice(0, 8)}` : '';
359
+ const lane = data?.sub_agent_label ? `[${data.sub_agent_label}${runSuffix}] ` : '';
360
+ pushSubAgentWindowLine(label ? `${lane}→ ${tool} · ${label}` : `${lane}→ ${tool}`);
361
+ return; // the spinner tick paints the window block
362
+ }
363
+
316
364
  // ── Explore-run collapse ────────────────────────────────────────────────
317
365
  // For list/read/search/index tools, skip the per-call head entirely and
318
366
  // update a single animated summary spinner. The transcript stays clean;
@@ -328,9 +376,8 @@ export function renderToolCall(data) {
328
376
  return;
329
377
  }
330
378
 
331
- // Sub-agent live window (queue mode): inner tool calls stream into the
332
- // fixed-height status block instead of appending transcript lines. The
333
- // card is still recorded so /expand, /last, and `d` show full detail.
379
+ // Legacy sub-agent live window fallback for events without explicit
380
+ // sub-agent metadata.
334
381
  if (queue.isActive() && runtime.subAgentWindow?.active && inSubAgentBlock()) {
335
382
  recordCard({ id: callId, tool, args, startedAt: Date.now() });
336
383
  session.toolCounts[tool] = (session.toolCounts[tool] || 0) + 1;
@@ -410,6 +457,14 @@ export function renderToolResult(data, eventType = 'tool_result') {
410
457
  indent: gutter,
411
458
  columns: process.stderr.columns || 120,
412
459
  });
460
+ const fromSubAgent = Boolean(data?.internal || data?.sub_agent || data?.sub_agent_label || data?.sub_agent_run_id);
461
+
462
+ // Sub-agent live window: the call line is already streaming in the
463
+ // status block; the result stays card-only (close card summarizes). This
464
+ // must run before explore-collapse for read/search tools used by explores.
465
+ if (fromSubAgent && queue.isActive() && runtime.subAgentWindow?.active) {
466
+ return;
467
+ }
413
468
 
414
469
  // Explore tools: the call already updated the summary spinner. Refresh
415
470
  // the "latest" hint with the result's file if we have one, and skip the
@@ -421,8 +476,8 @@ export function renderToolResult(data, eventType = 'tool_result') {
421
476
  return;
422
477
  }
423
478
 
424
- // Sub-agent live window: the call line is already streaming in the
425
- // status block; the result stays card-only (close card summarizes).
479
+ // Legacy sub-agent live window fallback for events without explicit
480
+ // sub-agent metadata.
426
481
  if (queue.isActive() && runtime.subAgentWindow?.active && inSubAgentBlock()) {
427
482
  return;
428
483
  }
@@ -43,7 +43,8 @@ export const runtime = {
43
43
 
44
44
  // Explore-run collapse (read/list/search/index bursts as concise progress).
45
45
  exploreRun: { counts: {}, recent: [], lineActive: false, lastPrintedSummary: '', lastPrintedTotal: 0, lastPrintedAt: 0 },
46
- foldedSubAgentTools: null, // { agentType, entries, startedAt } for default/quiet folded sub-agent tools
46
+ foldedSubAgentTools: null, // current folded sub-agent tool bucket
47
+ foldedSubAgentToolMap: new Map(), // run-aware buckets for parallel sub-agents
47
48
 
48
49
  // Animated spinner state (single shared interval; text/frame drive inPlace).
49
50
  spinInterval: null,
@@ -61,7 +62,7 @@ export const runtime = {
61
62
  // its inner tool calls stream into a fixed-height status block (last
62
63
  // N lines under the spinner) instead of appending to the transcript.
63
64
  // Full detail stays on the recorded cards (/expand, /last, `d`).
64
- subAgentWindow: { active: false, lines: [] },
65
+ subAgentWindow: { active: false, lines: [], groups: new Map() },
65
66
 
66
67
  // PRD-092: Watch panel — toggled by /watch. When active, the spinner
67
68
  // area renders a compact agent-activity summary instead of the spinner.
@@ -106,6 +107,7 @@ export const session = {
106
107
  lastTurnDuration: 0,
107
108
  toolCounts: {}, // per-tool histogram (mission report)
108
109
  subAgentCounts: {}, // per-sub-agent histogram (mission report)
110
+ activeSubAgentRuns: new Map(), // run_id -> active sub-agent lane
109
111
  savedUsd: 0, // total sub-agent cost (for "saved by routing")
110
112
  lastTask: '', // most recent user prompt (mission report title)
111
113
  lastReasoning: '', // captured from agent for /why