@ferris1225/pi-subagents 4.2.5 → 4.2.8
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/README.md +375 -346
- package/agents/executor.md +53 -53
- package/package.json +3 -5
- package/src/agents.ts +237 -237
- package/src/announcements.ts +81 -78
- package/src/dispatch.ts +615 -541
- package/src/durable.ts +517 -510
- package/src/format.ts +181 -165
- package/src/index.ts +102 -100
- package/src/monitor.ts +1 -1
- package/src/prompt.ts +69 -69
- package/src/rpc-run.ts +987 -993
- package/src/runtime.ts +348 -312
- package/src/status.ts +66 -0
- package/src/thread-lifecycle.ts +1341 -1324
- package/src/tools.ts +384 -384
- package/src/widget.ts +268 -266
- package/src/worktree.ts +974 -943
package/src/status.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent footer status line for sub-agent progress.
|
|
3
|
+
*
|
|
4
|
+
* The above-editor widget is the detailed surface, but it only pays off when
|
|
5
|
+
* the user is looking at it: a parent turn that dispatches children and then
|
|
6
|
+
* keeps streaming leaves no trace that anything is still running. The footer
|
|
7
|
+
* is always visible, so one compact roll-up there answers "is anything still
|
|
8
|
+
* working?" without opening the widget or querying runs.
|
|
9
|
+
*
|
|
10
|
+
* It stays deliberately count-only — no elapsed time, no per-run detail — so
|
|
11
|
+
* it carries no time-varying field and needs no refresh timer: every monitor
|
|
12
|
+
* transition already pushes an update. Queued runs keep their wait word
|
|
13
|
+
* (`queued` for a process slot vs `repo lane` for write serialization) because
|
|
14
|
+
* a capacity wait and a serialization wait call for different reactions.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import { isRunActiveStatus, monitor, statusLabel, type RunView } from "./monitor.ts";
|
|
19
|
+
import { waitWord } from "./widget.ts";
|
|
20
|
+
|
|
21
|
+
export const SUBAGENTS_STATUS_ID = "pi-subagents";
|
|
22
|
+
|
|
23
|
+
const SEPARATOR = " · ";
|
|
24
|
+
|
|
25
|
+
/** Display order of the count segments: live work first, settled last. */
|
|
26
|
+
const SEGMENT_ORDER = ["running", "interrupting", "starting", "queued", "repo lane", "done", "stopped"];
|
|
27
|
+
|
|
28
|
+
type StatusContext = Pick<ExtensionContext, "hasUI" | "ui">;
|
|
29
|
+
|
|
30
|
+
/** One-line roll-up of the runs worth reporting — active ones plus the runs
|
|
31
|
+
* that settled during this turn — or undefined when there is nothing to say
|
|
32
|
+
* and the status entry should disappear instead of showing zeros. */
|
|
33
|
+
export function formatRunStatusLine(runs: readonly RunView[]): string | undefined {
|
|
34
|
+
const counts = new Map<string, number>();
|
|
35
|
+
for (const run of runs) {
|
|
36
|
+
const word = run.status === "queued"
|
|
37
|
+
? waitWord(run)
|
|
38
|
+
: isRunActiveStatus(run.status) || run.status === "done" || run.status === "failed"
|
|
39
|
+
? statusLabel(run.status)
|
|
40
|
+
: undefined;
|
|
41
|
+
if (word) counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
42
|
+
}
|
|
43
|
+
const segments = SEGMENT_ORDER.filter((word) => counts.has(word)).map((word) => `${counts.get(word)} ${word}`);
|
|
44
|
+
return segments.length > 0 ? `subagents ${segments.join(SEPARATOR)}` : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Subscription of the currently installed status line; module-level because
|
|
48
|
+
* the monitor it follows is itself a singleton. */
|
|
49
|
+
let unsubscribe: (() => void) | undefined;
|
|
50
|
+
|
|
51
|
+
/** Install the footer status line. Not installed without a UI host (print and
|
|
52
|
+
* json modes), where setStatus has nowhere to render. */
|
|
53
|
+
export function installActiveRunsStatus(ctx: StatusContext): void {
|
|
54
|
+
if (!ctx.hasUI) return;
|
|
55
|
+
// A second install must not orphan the first subscription.
|
|
56
|
+
clearActiveRunsStatus(ctx);
|
|
57
|
+
const render = (): void => ctx.ui.setStatus(SUBAGENTS_STATUS_ID, formatRunStatusLine(monitor.getRuns()));
|
|
58
|
+
unsubscribe = monitor.subscribe(render);
|
|
59
|
+
render();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function clearActiveRunsStatus(ctx: StatusContext): void {
|
|
63
|
+
unsubscribe?.();
|
|
64
|
+
unsubscribe = undefined;
|
|
65
|
+
if (ctx.hasUI) ctx.ui.setStatus(SUBAGENTS_STATUS_ID, undefined);
|
|
66
|
+
}
|