Nest the latest 3 child activities under each delegate row

5be79def3a08 · AtlantisPleb · · parent 2f9cb16d76e1

Nest the latest 3 child activities under each delegate row

Instead of a single shared activity box, every child in a running
delegate now carries its own last three tool uses directly under its
status row. This keeps each child's recent work visible alongside its
name.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified packages/openagents-cli/src/coder-ui.ts
  • modified packages/openagents-cli/test/coder-ui.test.ts

Diff

2 files changed, +19 -19

packages/openagents-cli/src/coder-ui.ts modified +11 -14

@@ -470,28 +470,25 @@ export function runCoderUi(session: CoderSession, options: CoderUiOptions): Prom

470 470
                ...tasks.filter((task) => task.status !== "running" && task.status !== "pending"),
471 471
              ].slice(0, FLEET_ROWS_MAX);
472 472
473
        for (const child of fleetRows(shown, Math.max(20, width - 9))) {
473
        const childRows = fleetRows(shown, Math.max(20, width - 9));
474
        for (const [index, task] of shown.entries()) {
475
          const child = childRows[index];
476
          if (child === undefined) continue;
474 477
          const color = fleetColor(child.status);
475 478
          rows.push(
476 479
            `${DIM}${child.branch}${RESET} ${color}${child.mark}${RESET} ${DIM}${child.text}${RESET}`,
477 480
          );
481
482
          // Three lines of the child's own latest activity, nested under it.
483
          const activities = latestActivities([task], PREVIEW_ROWS);
484
          for (const activity of activities) {
485
            const text = truncate(activityPhrase(activity), Math.max(4, width - 12));
486
            rows.push(`${DIM}  → ${text}${RESET}`);
487
          }
478 488
        }
479 489
480 490
        const hidden = tasks.length - shown.length;
481 491
        if (hidden > 0) rows.push(`${DIM}   +${String(hidden)} more${RESET}`);
482
483
        const activities = latestActivities(tasks, PREVIEW_ROWS);
484
        if (activities.length > 0) {
485
          const boxWidth = Math.max(10, width - 4);
486
          const frame = `${DIM}╭${"─".repeat(boxWidth + 2)}╮${RESET}`;
487
          const floor = `${DIM}╰${"─".repeat(boxWidth + 2)}╯${RESET}`;
488
          const lines = activities.map((activity) => {
489
            const text = truncate(activityPhrase(activity), boxWidth);
490
            const pad = " ".repeat(Math.max(0, boxWidth - [...text].length));
491
            return `${DIM}│${RESET} ${text}${pad} ${DIM}│${RESET}`;
492
          });
493
          rows.push(frame, ...lines, floor);
494
        }
495 492
      }
496 493
497 494
      if (open) {
packages/openagents-cli/test/coder-ui.test.ts modified +8 -5

@@ -1001,9 +1001,12 @@ describe("the delegate preview inline under the tool call", () => {

1001 1001
      registry.recordToolUse(id, { toolName: "shell", target: "mix test" });
1002 1002
    });
1003 1003
1004
    const boxed = rows.filter((row) => /[╭╰]/.test(row) || row.includes(" │ "));
1005
    expect(boxed).toHaveLength(5); // top border, three activity rows, floor.
1006
    const text = boxed.join("\n");
1004
    const delegateRow = rows.findIndex((row) => row.includes("delegate"));
1005
    expect(delegateRow).toBeGreaterThan(0);
1006
    const childRow = delegateRow + 1;
1007
    const previews = rows.slice(childRow + 1, childRow + 4);
1008
    expect(previews).toHaveLength(3);
1009
    const text = previews.join("\n");
1007 1010
    expect(text).toContain("shell(mix test)");
1008 1011
    expect(text).toContain("edit(src/b.ts)");
1009 1012
    expect(text).toContain("bash(pnpm test)");

@@ -1012,7 +1015,7 @@ describe("the delegate preview inline under the tool call", () => {

1012 1015
    expect(text).not.toContain("grep(needle)");
1013 1016
1014 1017
    // Newest last, so reading down is reading forward in time.
1015
    const at = (phrase: string) => boxed.findIndex((row) => row.includes(phrase));
1018
    const at = (phrase: string) => previews.findIndex((row) => row.includes(phrase));
1016 1019
    expect(at("bash(pnpm test)")).toBeLessThan(at("edit(src/b.ts)"));
1017 1020
    expect(at("edit(src/b.ts)")).toBeLessThan(at("shell(mix test)"));
1018 1021
  });

@@ -1022,6 +1025,6 @@ describe("the delegate preview inline under the tool call", () => {

1022 1025
      registerChild(registry);
1023 1026
    });
1024 1027
1025
    expect(rows.join("\n")).not.toContain("╭");
1028
    expect(rows.join("\n")).not.toContain(" → ");
1026 1029
  });
1027 1030
});

This page updates live while a promote is in flight · changelog