@wolido/async-subagent-isolation 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +25 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wolido/async-subagent-isolation",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A pi extension that asynchronously delegates tasks to specialized subagents running in isolated pi processes.",
5
5
  "license": "MIT",
6
6
  "author": "Wolido",
package/src/index.ts CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  getAgentDir,
28
28
  parseFrontmatter,
29
29
  } from "@earendil-works/pi-coding-agent";
30
- import { Box, Container, Key, Markdown, matchesKey, Spacer, Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
30
+ import { Box, Container, Key, Markdown, matchesKey, Spacer, Text, truncateToWidth, visibleWidth, sliceByColumn } from "@earendil-works/pi-tui";
31
31
  import { Type } from "typebox";
32
32
 
33
33
  // ===== UUID v7 helper =====
@@ -545,6 +545,10 @@ interface AgentProgress {
545
545
  const PROGRESS_WIDGET_KEY = "async-subagent-isolation-progress";
546
546
  const MAX_WIDGET_LINES = 20;
547
547
  const MAX_RECENT_TOOLS = 3;
548
+ // Cap for the dynamic name column: wide enough for typical agent names
549
+ // (existing tests require a 20-char name to render in full), small enough
550
+ // to leave room for the phase/elapsed columns on narrow terminals.
551
+ const MAX_NAME_WIDTH = 30;
548
552
 
549
553
  /** Plain-text one-line summary of a tool call for the progress widget (no theme colors). */
550
554
  function summarizeToolCall(toolName: string, args: Record<string, any>): string {
@@ -561,6 +565,22 @@ function getRecentToolSummaries(messages: Message[]): string[] {
561
565
  .map((item) => summarizeToolCall(item.name, item.args));
562
566
  }
563
567
 
568
+ /**
569
+ * Fit an agent name into a fixed-width column: pad short names with spaces,
570
+ * truncate over-long names with a "..." suffix. Unlike truncateToWidth this
571
+ * never injects ANSI reset codes around the ellipsis (agent names carry no
572
+ * styling), so every row keeps the phase/elapsed columns at the same raw
573
+ * string offset as well as the same display column. Callers must pass
574
+ * width >= 4 so the ellipsis fits.
575
+ */
576
+ function fitNameColumn(name: string, width: number): string {
577
+ const nameWidth = visibleWidth(name);
578
+ if (nameWidth <= width) return name + " ".repeat(width - nameWidth);
579
+ // strict: never keep a wide char that would straddle the cut boundary
580
+ const cut = sliceByColumn(name, 0, width - 3, true);
581
+ return cut + "..." + " ".repeat(Math.max(0, width - 3 - visibleWidth(cut)));
582
+ }
583
+
564
584
  export function formatElapsed(startedAt: number): string {
565
585
  const totalSec = Math.max(0, Math.floor((Date.now() - startedAt) / 1000));
566
586
  const mm = String(Math.floor(totalSec / 60)).padStart(2, "0");
@@ -622,6 +642,9 @@ export class SubagentProgressManager {
622
642
  const maxAgentRows = Math.max(1, Math.min(process.stdout.rows || MAX_WIDGET_LINES, MAX_WIDGET_LINES));
623
643
  const visible = sorted.slice(-maxAgentRows);
624
644
  const total = sorted.length;
645
+ // Name column width adapts to the longest visible agent name (capped),
646
+ // so the phase and elapsed columns start at the same offset on every row.
647
+ const nameColWidth = Math.min(MAX_NAME_WIDTH, Math.max(...visible.map((a) => visibleWidth(a.name))));
625
648
  // Note: the factory closes over `theme`; between a theme change and the next
626
649
  // refresh (≤1s) the widget may briefly use the stale theme. The 1Hz timer
627
650
  // replaces the factory on every tick, so this self-heals.
@@ -640,7 +663,7 @@ export class SubagentProgressManager {
640
663
  return borderColor("─") + theme.fg("accent", label) + borderColor("─".repeat(width - labelWidth - 1));
641
664
  };
642
665
  const renderRow = (a: AgentProgress, width: number): string => {
643
- const nameCol = a.name;
666
+ const nameCol = fitNameColumn(a.name, nameColWidth);
644
667
  const phaseCol = truncateToWidth(formatPhase(a.phase), 20, "...", true);
645
668
  const toolHint = a.recentTools.length > 0 ? ` → ${a.recentTools[a.recentTools.length - 1]}` : "";
646
669
  const line =