@fradser/pi-agent-teams 0.5.0 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fradser/pi-agent-teams",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Multi-agent team system for Pi — DAG orchestration, leader inbox, and one-way worker reports",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -36,5 +36,8 @@
36
36
  "extensions": [
37
37
  "./src/index.ts"
38
38
  ]
39
+ },
40
+ "dependencies": {
41
+ "@fradser/pi-kit": "0.1.0"
39
42
  }
40
43
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fradser/pi-agent-teams — Pi extension for run-centric agent teams.
2
+ * pi-agent-teams-fradser — Pi extension for run-centric agent teams.
3
3
  *
4
4
  * The entry point is composition only: worker capability registration,
5
5
  * session lifecycle, and delegation to tools.ts. Scheduling lives in
package/src/spawner.ts CHANGED
@@ -12,6 +12,7 @@ import * as fs from "node:fs";
12
12
  import * as os from "node:os";
13
13
  import * as path from "node:path";
14
14
  import { fileURLToPath } from "node:url";
15
+ import { extractTextContent } from "@fradser/pi-kit";
15
16
  import type { WorkerUsage } from "./types";
16
17
 
17
18
  /**
@@ -307,10 +308,7 @@ function applyWorkerJsonLine(state: WorkerStreamState, line: string): boolean {
307
308
  if (event.type !== "message_end" || event.message?.role !== "assistant") return false;
308
309
  state.turns++;
309
310
  if (event.message.stopReason === "stop") state.finalResponse = true;
310
- const parts = (event.message.content ?? [])
311
- .filter((part) => part.type === "text" && typeof part.text === "string")
312
- .map((part) => part.text as string)
313
- .join("");
311
+ const parts = extractTextContent(event.message.content, "");
314
312
  if (parts.trim()) state.text = parts;
315
313
  const u = event.message.usage;
316
314
  if (u) {
package/src/ui.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /** Passive teammate widget and interactive full-screen console. */
2
2
 
3
3
  import { truncateToWidth, Key, matchesKey } from "@earendil-works/pi-tui";
4
+ import { createPiThemeStyle, PI_SPINNER_FRAMES, PI_SPINNER_INTERVAL_MS } from "@fradser/pi-kit";
4
5
  import type { ExtensionUIContext, Theme, ThemeColor } from "@earendil-works/pi-coding-agent";
5
6
  import { truncateTail, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "@earendil-works/pi-coding-agent";
6
7
  import {
@@ -23,8 +24,6 @@ function cap(text: string | undefined, maxBytes = DEFAULT_MAX_BYTES): string {
23
24
 
24
25
  const TEAM_COLORS = ["accent", "success", "warning", "error", "toolTitle", "mdLink"] as const;
25
26
  const PANEL_IDLE_COLLAPSE_MS = 30_000;
26
- const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
27
- const SPINNER_MS = 120;
28
27
 
29
28
  let panelRequestRender: (() => void) | undefined;
30
29
  let spinnerTimer: ReturnType<typeof setInterval> | undefined;
@@ -50,7 +49,7 @@ function buildPanelRows(): PanelRow[] {
50
49
  }
51
50
 
52
51
  function runningTeammateLabel(node: Node): string {
53
- const frame = SPINNER_FRAMES[spinnerFrame];
52
+ const frame = PI_SPINNER_FRAMES[spinnerFrame];
54
53
  const tool = node.spawn?.activeTool;
55
54
  const thinking = (node.spawn?.liveThinking ?? "").split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "";
56
55
  const live = (node.spawn?.liveText ?? "").split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "";
@@ -71,9 +70,9 @@ function ensureSpinner(): void {
71
70
  const running = listNodes().some((node) => node.status === "running");
72
71
  if (running && !spinnerTimer) {
73
72
  spinnerTimer = setInterval(() => {
74
- spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
73
+ spinnerFrame = (spinnerFrame + 1) % PI_SPINNER_FRAMES.length;
75
74
  panelRequestRender?.();
76
- }, SPINNER_MS);
75
+ }, PI_SPINNER_INTERVAL_MS);
77
76
  spinnerTimer.unref?.();
78
77
  } else if (!running && spinnerTimer) {
79
78
  clearInterval(spinnerTimer);
@@ -245,7 +244,7 @@ export function openTeamConsole(ctx: { ui: ExtensionUIContext }): Promise<void>
245
244
  };
246
245
  const startLiveRefresh = () => {
247
246
  if (renderTimer) return;
248
- renderTimer = setInterval(requestRender, SPINNER_MS);
247
+ renderTimer = setInterval(requestRender, PI_SPINNER_INTERVAL_MS);
249
248
  renderTimer.unref?.();
250
249
  };
251
250
  const stopLiveRefresh = () => {
@@ -255,15 +254,8 @@ export function openTeamConsole(ctx: { ui: ExtensionUIContext }): Promise<void>
255
254
  };
256
255
  startLiveRefresh();
257
256
 
258
- // btw-style callbacks (same accent/muted/dim/border/success/error language as @fradser/pi-btw).
259
- const style = {
260
- accent: (s: string) => theme.fg("accent", s),
261
- muted: (s: string) => theme.fg("muted", s),
262
- dim: (s: string) => theme.fg("dim", s),
263
- border: (s: string) => theme.fg("border", s),
264
- success: (s: string) => theme.fg("success", s),
265
- error: (s: string) => theme.fg("error", s),
266
- };
257
+ // btw-style callbacks (same accent/muted/dim/border/success/error language as pi-btw-fradser).
258
+ const style = createPiThemeStyle(theme);
267
259
 
268
260
  const windowLines = (full: string[], width: number): { lines: string[]; range: string } => {
269
261
  const wrapped = wrapConsoleDetail(full, width);
@@ -341,7 +333,7 @@ export function openTeamConsole(ctx: { ui: ExtensionUIContext }): Promise<void>
341
333
  }
342
334
  const detail = wrapConsoleDetail(buildNodeDetail(detailKey), tui.terminal.columns);
343
335
  const viewport = maxConsoleBody(tui.terminal.rows);
344
- // Mouse-wheel scrolling (SGR wheel events, same as @fradser/pi-btw).
336
+ // Mouse-wheel scrolling (SGR wheel events, same as pi-btw-fradser).
345
337
  const sgrWheel = /^\x1b\[<(\d+);(\d+);(\d+)[Mm]$/.exec(data);
346
338
  if (sgrWheel) {
347
339
  const button = Number.parseInt(sgrWheel[1], 10);