@gjczone/pi-swarm 0.3.5 → 0.5.0

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 (53) hide show
  1. package/README.md +33 -71
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +8 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/shared/controller.d.ts +10 -4
  6. package/dist/shared/controller.d.ts.map +1 -1
  7. package/dist/shared/controller.js +139 -6
  8. package/dist/shared/controller.js.map +1 -1
  9. package/dist/shared/render.d.ts +0 -11
  10. package/dist/shared/render.d.ts.map +1 -1
  11. package/dist/shared/render.js +3 -36
  12. package/dist/shared/render.js.map +1 -1
  13. package/dist/shared/spawner.d.ts.map +1 -1
  14. package/dist/shared/spawner.js +212 -17
  15. package/dist/shared/spawner.js.map +1 -1
  16. package/dist/shared/types.d.ts +58 -0
  17. package/dist/shared/types.d.ts.map +1 -1
  18. package/dist/shared/types.js.map +1 -1
  19. package/dist/shared/worktree.d.ts +81 -0
  20. package/dist/shared/worktree.d.ts.map +1 -0
  21. package/dist/shared/worktree.js +417 -0
  22. package/dist/shared/worktree.js.map +1 -0
  23. package/dist/shared/xml.d.ts +18 -0
  24. package/dist/shared/xml.d.ts.map +1 -0
  25. package/dist/shared/xml.js +31 -0
  26. package/dist/shared/xml.js.map +1 -0
  27. package/dist/swarm/tool.d.ts.map +1 -1
  28. package/dist/swarm/tool.js +69 -15
  29. package/dist/swarm/tool.js.map +1 -1
  30. package/dist/team/mailbox.d.ts +5 -0
  31. package/dist/team/mailbox.d.ts.map +1 -1
  32. package/dist/team/mailbox.js +43 -2
  33. package/dist/team/mailbox.js.map +1 -1
  34. package/dist/team/supervisor.d.ts +27 -2
  35. package/dist/team/supervisor.d.ts.map +1 -1
  36. package/dist/team/supervisor.js +93 -50
  37. package/dist/team/supervisor.js.map +1 -1
  38. package/dist/team/task-graph.d.ts +5 -2
  39. package/dist/team/task-graph.d.ts.map +1 -1
  40. package/dist/team/task-graph.js +27 -1
  41. package/dist/team/task-graph.js.map +1 -1
  42. package/dist/team/tool.d.ts.map +1 -1
  43. package/dist/team/tool.js +102 -18
  44. package/dist/team/tool.js.map +1 -1
  45. package/dist/tui/progress.d.ts +56 -44
  46. package/dist/tui/progress.d.ts.map +1 -1
  47. package/dist/tui/progress.js +497 -179
  48. package/dist/tui/progress.js.map +1 -1
  49. package/dist/tui/team-dashboard.d.ts +39 -23
  50. package/dist/tui/team-dashboard.d.ts.map +1 -1
  51. package/dist/tui/team-dashboard.js +506 -143
  52. package/dist/tui/team-dashboard.js.map +1 -1
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -1,32 +1,29 @@
1
- # @gjczone/pi-swarm
1
+ # pi-swarm
2
2
 
3
- > **Early release stability not guaranteed.** This is an initial version. Expect rough edges. Bug reports, feedback, feature requests, and PRs are very welcome.
3
+ Agent Swarm & Team extension for pi-coding-agent. Run 1 to 128 parallel subagents or collaborative role-based teams no preset configuration needed.
4
4
 
5
- Think of it as **kimi-code's AgentSwarm + Claude Code's agent teams** — inside pi. Parallel swarm agents and collaborative role-based teams, all dynamically spawned with no preset configuration.
6
-
7
- ## What It Does
8
-
9
- **Swarm** — 1 to 128 parallel agents. Like kimi-code's AgentSwarm: one template, many items, running simultaneously. Also works for single subagent delegation. Each agent is an isolated `pi --print` child process with its own context window.
10
-
11
- **Team** — collaborative agents. Like Claude Code's agent teams or pi-crew: role-based agents (explorer, planner, coder, reviewer, tester) working in sequence. Each phase agent receives context from previous phases via a shared mailbox. Every agent runs as an independent child process. Optional per-role model tier routing: use a cheaper/faster model for exploration while keeping reasoning-heavy roles on the default model.
12
-
13
- All agents are created on-the-fly. No `agents/*.md` files. The main agent decides what to spawn based on the task.
14
-
15
- ## Install
5
+ ## Installation
16
6
 
17
7
  ```bash
18
8
  pi install npm:@gjczone/pi-swarm@latest
19
9
  ```
20
10
 
21
- ## How to Use
11
+ ## Core Features
22
12
 
23
- ### Swarm "Do this to all of these" (or just one)
13
+ | Feature | When to Use | What It Does |
14
+ |---------|-------------|--------------|
15
+ | **AgentSwarm** | Run the same task across many items in parallel | Spawns 1-128 isolated subagents from an item template. Each runs in its own `pi --print` process. |
16
+ | **SwarmTeam** | Execute multi-step workflows with specialized roles | Role-based agents (explorer, planner, coder, reviewer, tester) collaborate in phases with a shared mailbox. Each phase receives context from previous phases. |
17
+ | **/swarm command** | Trigger a swarm from the chat | Shortcut for the AgentSwarm tool. `on` / `off` to toggle swarm mode. |
18
+ | **/swarm-team command** | Trigger a team from the chat | Shortcut for the SwarmTeam tool. |
19
+ | **Worktree Isolation** | Parallel agents modifying the same repo | Each subagent runs in a temporary git worktree. Changes commit to named branches for safe merging. Non-git repos fall back to regular directories. |
20
+ | **Live TUI Progress** | Monitor long-running swarms or teams | Braille progress bars for swarm agents, phase dashboard for teams. Updates in real time. |
21
+ | **Rate-Limit Retry** | Avoid API quota exhaustion | Auto-suspends on rate-limit errors and retries with exponential backoff (3s, 6s, 12s...). |
22
+ | **Crash Recovery** | Survive unexpected termination | Durable file-based state. Resume incomplete runs automatically. Completed runs auto-clean after 7 days. |
24
23
 
25
- Use for 1 to 128 items — same interface, same isolation.
24
+ ## Usage Examples
26
25
 
27
- ```
28
- Audit src/auth.ts for security issues — use a subagent
29
- ```
26
+ ### Swarm — run the same task across many items
30
27
 
31
28
  ```
32
29
  Review every file in src/ for bugs — use a swarm
@@ -36,13 +33,7 @@ Review every file in src/ for bugs — use a swarm
36
33
  Run a security audit on these five packages in parallel: auth, api, db, cache, middleware
37
34
  ```
38
35
 
39
- Or the slash command:
40
-
41
- ```
42
- /swarm Find deprecated API usage across the codebase
43
- ```
44
-
45
- ### Team — "Plan this, build it, review it"
36
+ ### Team plan, build, and review in phases
46
37
 
47
38
  ```
48
39
  Implement user login with JWT — use a team with planner, coder, and reviewer
@@ -52,52 +43,21 @@ Implement user login with JWT — use a team with planner, coder, and reviewer
52
43
  Add Redis caching — explore the codebase first, then plan, implement, review, test
53
44
  ```
54
45
 
55
- Or:
56
-
57
- ```
58
- /swarm-team Refactor the auth module end-to-end
59
- ```
60
-
61
- ### Resume Failed Work
46
+ ### Resume failed work
62
47
 
63
- If agents fail, the LLM gets `resume_agent_ids` and can retry:
48
+ If agents fail, the LLM receives `resume_agent_ids` and can retry:
64
49
 
65
50
  ```
66
51
  Two of the five swarm reviews failed — retry those
67
52
  ```
68
53
 
69
- ### Cancel Mid-Run
70
-
71
- Press `Ctrl+C` during a swarm or team run. Completed agents are preserved and results are final (no post-cancellation mutation). In-progress agents are cancelled gracefully and their partial work discarded. For teams, completed phases are saved and returned as partial results. Timeout errors are correctly surfaced instead of being lost in abort/exit races.
72
-
73
- ## Runtime Files
74
-
75
- State is stored under `.pi/swarm/state/`. The extension auto-creates `.pi/` if it doesn't exist, and auto-appends `.pi/swarm/state/` to the project's `.gitignore`.
76
-
77
- ```
78
- .pi/swarm/state/runs/{runId}/
79
- manifest.json # Run metadata, agent IDs, timestamps
80
- tasks.json # Task graph, per-phase status
81
- events.jsonl # Append-only event log
82
- agents/{agentId}/
83
- status.json # Per-agent status snapshot
84
- output.log # Full agent session output (header, raw stdout, footer)
85
- mailbox/ # Team inter-agent messages
86
- inbox.jsonl
87
- outbox.jsonl
88
- delivery.json
89
- ```
54
+ ### Cancel mid-run
90
55
 
91
- Runs auto-clean: completed runs deleted after 7 days, stale runs (30min no heartbeat) marked abandoned.
56
+ Press `Ctrl+C` during a swarm or team run. Completed agents are preserved, in-progress agents are cancelled gracefully.
92
57
 
93
58
  ## Settings
94
59
 
95
- Default max concurrency is **5**. Recommended: **3-10**. Can be set to any positive integer.
96
-
97
- | Settings file | Scope |
98
- | --------------------------- | --------------------------- |
99
- | `.pi/settings.json` | Project (current directory) |
100
- | `~/.pi/agent/settings.json` | Global (all projects) |
60
+ Default max concurrency is **5**. Adjust in `.pi/settings.json` (project) or `~/.pi/agent/settings.json` (global):
101
61
 
102
62
  ```json
103
63
  {
@@ -107,13 +67,7 @@ Default max concurrency is **5**. Recommended: **3-10**. Can be set to any posit
107
67
  }
108
68
  ```
109
69
 
110
- Priority: project settings > global settings > `PI_SWARM_MAX_CONCURRENCY` env var.
111
-
112
- Lower values (3-5) are safer for API rate limits. Values above 10 work if your provider allows high concurrent requests. No hard upper limit.
113
-
114
- ## Team Model Tier
115
-
116
- When using `SwarmTeam`, you can configure a lightweight model for exploration roles to reduce costs:
70
+ For team mode, configure a lightweight model for exploration roles to reduce costs:
117
71
 
118
72
  ```json
119
73
  {
@@ -123,12 +77,20 @@ When using `SwarmTeam`, you can configure a lightweight model for exploration ro
123
77
  }
124
78
  ```
125
79
 
126
- The `explorer` and `tester` roles (when assigned to a phase) automatically use the small model. Other roles (`planner`, `coder`, `reviewer`, `fixer`) use the default model unless overridden. No preset agents — you define phases and assign roles via the tool schema. Per-phase overrides are available via `modelTier` and `model` fields.
80
+ ## Supported Platforms
81
+
82
+ | Platform | Status |
83
+ |----------|--------|
84
+ | pi-coding-agent | Required runtime |
85
+ | Node.js >= 18 | Required |
86
+ | Linux / macOS / Windows | Supported |
127
87
 
128
88
  ## Credits
129
89
 
130
- 100% vibe-coded with deepseek-v4-pro, doubao-seed-2.1-pro, and doubao-seed-2.1-turbo. Architecture ported from [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code). Code implementation patterns inspired by [pi-crew](https://github.com/baphuongna/pi-crew). Agent team workflow approach inspired by Claude Code. Thank you to all these projects for their excellent work.
90
+ Architecture ported from [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code). Team communication patterns inspired by [pi-crew](https://github.com/baphuongna/pi-crew). Agent team workflow approach inspired by Claude Code.
131
91
 
132
92
  ## License
133
93
 
134
94
  [MIT](LICENSE)
95
+
96
+
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA4FpE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAKxE;AAED,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAgH/C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA6FpE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAKxE;AAED,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAuH/C"}
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import { registerSwarmTeamTool } from "./team/tool.js";
14
14
  import { registerTeamCommand } from "./team/command.js";
15
15
  import { recoverRuns } from "./state/recovery.js";
16
16
  import { SwarmModeMarkerComponent, } from "./tui/swarm-markers.js";
17
+ import { pruneWorktrees } from "./shared/worktree.js";
17
18
  import * as fs from "node:fs";
18
19
  import * as path from "node:path";
19
20
  // ---------------------------------------------------------------------------
@@ -141,6 +142,13 @@ export default function (pi) {
141
142
  swarmMode = null;
142
143
  // Ensure .pi/swarm/state/ is gitignored
143
144
  ensureGitignore(process.cwd());
145
+ // Best-effort cleanup of orphaned worktrees from previous crashes
146
+ try {
147
+ pruneWorktrees(process.cwd());
148
+ }
149
+ catch {
150
+ // Non-git repos or worktree prune failures are non-fatal
151
+ }
144
152
  // Run recovery: detect stale/abandoned runs, clean up expired ones
145
153
  try {
146
154
  const result = recoverRuns(process.cwd());
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -35,8 +35,12 @@ export declare class SubagentBatchController<T> {
35
35
  private reject;
36
36
  private finished;
37
37
  private started;
38
+ private startedAt;
38
39
  private startedSuccessCount;
39
40
  private readonly onProgress?;
41
+ private eventLog;
42
+ private nextEventId;
43
+ private completionTimesMs;
40
44
  constructor(launcher: SubagentBatchLauncher, tasks: readonly QueuedSubagentTask<T>[], options?: SubagentBatchOptions);
41
45
  /**
42
46
  * Run the batch. Returns a promise that resolves when all tasks
@@ -59,6 +63,8 @@ export declare class SubagentBatchController<T> {
59
63
  private recoverRateLimitCapacity;
60
64
  private finishIfComplete;
61
65
  private emitProgress;
66
+ /** Add an event to the event log, keeping it bounded. */
67
+ private addEvent;
62
68
  private finish;
63
69
  private finishWithUserCancellation;
64
70
  private fail;
@@ -81,9 +87,9 @@ export declare class SubagentBatchController<T> {
81
87
  * 2. `~/.pi/agent/settings.json` → `pi-swarm.maxConcurrency` (global)
82
88
  * 3. `PI_SWARM_MAX_CONCURRENCY` env var
83
89
  *
84
- * Returns `undefined` when unset. A present value must be a positive
85
- * integer; invalid input throws so a misconfigured cap never silently
86
- * reverts to uncapped.
90
+ * Falls back to DEFAULT_MAX_CONCURRENCY (5) when unset. A present
91
+ * value must be a positive integer; invalid input throws so a
92
+ * misconfigured cap never silently reverts to uncapped.
87
93
  */
88
- export declare function resolveSwarmMaxConcurrency(cwd?: string): number | undefined;
94
+ export declare function resolveSwarmMaxConcurrency(cwd?: string): number;
89
95
  //# sourceMappingURL=controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/shared/controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EAOtB,MAAM,YAAY,CAAC;AAyFpB,qBAAa,uBAAuB,CAAC,CAAC;IAiClC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAhC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,iBAAiB,CAA4C;IAGrE,OAAO,CAAC,oBAAoB,CAA4C;IACxE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,oBAAoB,CAAqB;IACjD,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,qBAAqB,CAAK;IAGlC,OAAO,CAAC,OAAO,CAA4D;IAC3E,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAA4C;gBAGrD,QAAQ,EAAE,qBAAqB,EAChD,KAAK,EAAE,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAAE,EACvC,OAAO,GAAE,oBAAyB;IA8BpC;;;OAGG;IACH,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAmCxC,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,uBAAuB;IA2C/B,OAAO,CAAC,YAAY;YA0BN,UAAU;IA+ExB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,YAAY;IAuDpB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,0BAA0B;IAoClC,OAAO,CAAC,IAAI;IAsBZ,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAQvC,OAAO,CAAC,kBAAkB;CAsC3B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA4B3E"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/shared/controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EAUtB,MAAM,YAAY,CAAC;AA+FpB,qBAAa,uBAAuB,CAAC,CAAC;IAyClC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAxC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,iBAAiB,CAA4C;IAGrE,OAAO,CAAC,oBAAoB,CAA4C;IACxE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,oBAAoB,CAAqB;IACjD,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,qBAAqB,CAAK;IAGlC,OAAO,CAAC,OAAO,CAA4D;IAC3E,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAA4C;IAGxE,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,WAAW,CAAK;IAGxB,OAAO,CAAC,iBAAiB,CAAgB;gBAGtB,QAAQ,EAAE,qBAAqB,EAChD,KAAK,EAAE,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAAE,EACvC,OAAO,GAAE,oBAAyB;IAqCpC;;;OAGG;IACH,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAoCxC,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,uBAAuB;IA2C/B,OAAO,CAAC,YAAY;YAyCN,UAAU;IAoHxB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,oBAAoB;IAoC5B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,YAAY;IA8FpB,yDAAyD;IACzD,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,0BAA0B;IAoClC,OAAO,CAAC,IAAI;IAsBZ,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAQvC,OAAO,CAAC,kBAAkB;CAsC3B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CA4B/D"}
@@ -23,6 +23,7 @@ const RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2000;
23
23
  const RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS = 3 * 60 * 1000; // 3 minutes
24
24
  const AGENT_SWARM_MAX_CONCURRENCY_ENV = "PI_SWARM_MAX_CONCURRENCY";
25
25
  const DEFAULT_MAX_CONCURRENCY = 5;
26
+ const RATE_LIMIT_SUSPENDED_REASON = "Rate limit reached — agent suspended";
26
27
  // ---------------------------------------------------------------------------
27
28
  // Abort helpers
28
29
  // ---------------------------------------------------------------------------
@@ -88,8 +89,14 @@ export class SubagentBatchController {
88
89
  reject;
89
90
  finished = false;
90
91
  started = false;
92
+ startedAt = 0;
91
93
  startedSuccessCount = 0;
92
94
  onProgress;
95
+ // Event log
96
+ eventLog = [];
97
+ nextEventId = 1;
98
+ // ETA tracking: track completion timestamps for average calculation
99
+ completionTimesMs = [];
93
100
  constructor(launcher, tasks, options = {}) {
94
101
  this.launcher = launcher;
95
102
  this.maxConcurrency = options.maxConcurrency;
@@ -100,6 +107,13 @@ export class SubagentBatchController {
100
107
  retryCount: 0,
101
108
  retryReadyAt: 0,
102
109
  started: false,
110
+ usage: {
111
+ input: 0,
112
+ output: 0,
113
+ cacheRead: 0,
114
+ cacheWrite: 0,
115
+ totalTokens: 0,
116
+ },
103
117
  }));
104
118
  this.pending = [...this.states];
105
119
  this.results = Array.from({
@@ -126,6 +140,7 @@ export class SubagentBatchController {
126
140
  throw new Error("SubagentBatchController.run() can only be called once.");
127
141
  }
128
142
  this.started = true;
143
+ this.startedAt = Date.now();
129
144
  return new Promise((resolve, reject) => {
130
145
  this.resolve = resolve;
131
146
  this.reject = reject;
@@ -262,6 +277,21 @@ export class SubagentBatchController {
262
277
  attempt.cleanup = this.linkAttemptSignals(attempt, state.task);
263
278
  this.active.add(attempt);
264
279
  attempt.state.started = true;
280
+ attempt.state.startedAt = Date.now();
281
+ // Add event to log
282
+ this.addEvent({
283
+ id: this.nextEventId++,
284
+ agentId: undefined,
285
+ timestamp: Date.now(),
286
+ type: "started",
287
+ detail: state.task.swarmItem
288
+ ? `Started: ${state.task.swarmItem.slice(0, 60)}`
289
+ : `Started task ${state.index + 1}`,
290
+ });
291
+ // Trim event log to last 50 entries
292
+ if (this.eventLog.length > 50) {
293
+ this.eventLog = this.eventLog.slice(-50);
294
+ }
265
295
  // A task transitioned from queued to working
266
296
  this.emitProgress();
267
297
  this.runAttempt(attempt).then((outcome) => {
@@ -283,6 +313,16 @@ export class SubagentBatchController {
283
313
  onReady: () => {
284
314
  this.markAttemptReady(attempt);
285
315
  },
316
+ onUsage: (usage) => {
317
+ attempt.state.usage = { ...usage };
318
+ this.emitProgress();
319
+ },
320
+ onActivity: (tool, activity) => {
321
+ attempt.state.currentTool = tool;
322
+ attempt.state.activity = activity;
323
+ this.emitProgress();
324
+ },
325
+ onMessage: task.onMessage,
286
326
  suppressRateLimitFailureEvent: true,
287
327
  timeout: task.timeout,
288
328
  swarmRoot: task.swarmRoot,
@@ -291,6 +331,9 @@ export class SubagentBatchController {
291
331
  model: task.model,
292
332
  tools: task.tools,
293
333
  cwd: task.cwd,
334
+ useWorktree: task.useWorktree,
335
+ mailboxPath: task.mailboxPath,
336
+ roleName: task.roleName,
294
337
  };
295
338
  let handle;
296
339
  try {
@@ -308,6 +351,10 @@ export class SubagentBatchController {
308
351
  model: task.model,
309
352
  tools: task.tools,
310
353
  cwd: task.cwd,
354
+ useWorktree: task.useWorktree,
355
+ mailboxPath: task.mailboxPath,
356
+ roleName: task.roleName,
357
+ onMessage: task.onMessage,
311
358
  ...runOptions,
312
359
  };
313
360
  handle = await this.launcher.spawn(spawnOptions);
@@ -319,11 +366,31 @@ export class SubagentBatchController {
319
366
  attempt.state.agentId = handle.agentId;
320
367
  try {
321
368
  const completion = await handle.completion;
369
+ if (completion.usage) {
370
+ attempt.state.usage = { ...completion.usage };
371
+ }
372
+ const completedAt = Date.now();
373
+ attempt.state.completedAt = completedAt;
374
+ if (attempt.state.startedAt) {
375
+ this.completionTimesMs.push(completedAt - attempt.state.startedAt);
376
+ }
377
+ // Add event to log
378
+ this.addEvent({
379
+ id: this.nextEventId++,
380
+ agentId: handle.agentId,
381
+ timestamp: completedAt,
382
+ type: "completed",
383
+ detail: attempt.state.task.swarmItem
384
+ ? `Agent completed: ${attempt.state.task.swarmItem.slice(0, 60)}`
385
+ : `Agent completed`,
386
+ });
322
387
  return {
323
388
  task,
324
389
  agentId: handle.agentId,
325
390
  status: "completed",
326
391
  result: completion.result,
392
+ usage: attempt.state.usage,
393
+ worktreeBranch: completion.worktreeBranch,
327
394
  };
328
395
  }
329
396
  catch (error) {
@@ -382,6 +449,13 @@ export class SubagentBatchController {
382
449
  // Save agent id for retry and requeue at front
383
450
  state.retryAgentId = state.agentId ?? state.retryAgentId;
384
451
  state.retryCount += 1;
452
+ // Notify external listeners that this agent was suspended
453
+ if (state.agentId) {
454
+ this.launcher.suspended?.({
455
+ agentId: state.agentId,
456
+ reason: RATE_LIMIT_SUSPENDED_REASON,
457
+ });
458
+ }
385
459
  // Exponential backoff
386
460
  const delay = RATE_LIMIT_RETRY_BASE_MS *
387
461
  Math.pow(RATE_LIMIT_RETRY_FACTOR, state.retryCount - 1);
@@ -419,6 +493,7 @@ export class SubagentBatchController {
419
493
  status,
420
494
  state: attempt.state.started ? "started" : "not_started",
421
495
  error: errorMessage,
496
+ usage: { ...attempt.state.usage },
422
497
  };
423
498
  }
424
499
  // -----------------------------------------------------------------------
@@ -427,7 +502,10 @@ export class SubagentBatchController {
427
502
  enterRateLimitPhase() {
428
503
  this.rateLimitMode = true;
429
504
  this.clearNormalTimer();
430
- this.rateLimitCapacity = Math.max(1, this.countReadyActive());
505
+ // Use startedSuccessCount (count of agents that fully booted during
506
+ // the normal phase) so capacity reflects true past throughput rather
507
+ // than only currently-active attempts (which may already be finishing).
508
+ this.rateLimitCapacity = Math.max(1, this.startedSuccessCount);
431
509
  this.lastRateLimitAt = Date.now();
432
510
  this.globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
433
511
  this.nextRateLimitLaunchAt = Date.now() + RATE_LIMIT_RETRY_BASE_MS;
@@ -470,6 +548,13 @@ export class SubagentBatchController {
470
548
  let completed = 0;
471
549
  let failed = 0;
472
550
  let active = 0;
551
+ const totalUsage = {
552
+ input: 0,
553
+ output: 0,
554
+ cacheRead: 0,
555
+ cacheWrite: 0,
556
+ totalTokens: 0,
557
+ };
473
558
  const members = [];
474
559
  const activeIndices = new Set(Array.from(this.active, (a) => a.state.index));
475
560
  for (const state of this.states) {
@@ -477,6 +562,15 @@ export class SubagentBatchController {
477
562
  const isActiveState = activeIndices.has(state.index);
478
563
  let phase = "queued";
479
564
  let error;
565
+ // Accumulate usage from live state or completed result
566
+ const memberUsage = result?.usage ?? state.usage;
567
+ if (memberUsage) {
568
+ totalUsage.input += memberUsage.input;
569
+ totalUsage.output += memberUsage.output;
570
+ totalUsage.cacheRead += memberUsage.cacheRead;
571
+ totalUsage.cacheWrite += memberUsage.cacheWrite;
572
+ totalUsage.totalTokens += memberUsage.totalTokens;
573
+ }
480
574
  if (result) {
481
575
  if (result.status === "completed") {
482
576
  phase = "completed";
@@ -500,9 +594,25 @@ export class SubagentBatchController {
500
594
  phase,
501
595
  item: state.task.swarmItem,
502
596
  error,
597
+ usage: memberUsage,
598
+ currentTool: state.currentTool,
599
+ activity: state.activity,
503
600
  });
504
601
  }
505
602
  const queued = this.states.length - completed - failed - active;
603
+ // Calculate ETA based on average completion time
604
+ let estimatedRemainingMs;
605
+ const totalFinished = completed + failed;
606
+ const totalRemaining = queued + active;
607
+ if (totalFinished > 0 && totalRemaining > 0) {
608
+ const avgTimeMs = this.completionTimesMs.length > 0
609
+ ? this.completionTimesMs.reduce((a, b) => a + b, 0) /
610
+ this.completionTimesMs.length
611
+ : 0;
612
+ if (avgTimeMs > 0) {
613
+ estimatedRemainingMs = avgTimeMs * totalRemaining;
614
+ }
615
+ }
506
616
  this.onProgress({
507
617
  total: this.states.length,
508
618
  completed,
@@ -510,8 +620,20 @@ export class SubagentBatchController {
510
620
  active,
511
621
  queued,
512
622
  members,
623
+ totalUsage,
624
+ startedAt: this.startedAt,
625
+ estimatedRemainingMs,
626
+ eventLog: [...this.eventLog],
513
627
  });
514
628
  }
629
+ /** Add an event to the event log, keeping it bounded. */
630
+ addEvent(event) {
631
+ this.eventLog.push(event);
632
+ // Keep max 100 events
633
+ if (this.eventLog.length > 100) {
634
+ this.eventLog = this.eventLog.slice(-100);
635
+ }
636
+ }
515
637
  finish(results) {
516
638
  if (this.finished)
517
639
  return;
@@ -609,6 +731,17 @@ export class SubagentBatchController {
609
731
  return;
610
732
  attempt.ready = true;
611
733
  this.startedSuccessCount += 1;
734
+ // If we are in rate-limit mode, reset the global retry interval
735
+ // so the next launch uses the base delay rather than an accumulated
736
+ // exponential backoff, and re-arm the scheduler immediately.
737
+ if (this.rateLimitMode) {
738
+ this.globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
739
+ this.nextRateLimitLaunchAt = Date.now() + this.globalRetryIntervalMs;
740
+ // Clear any pending rate-limit timer so schedule() re-computes
741
+ // the next wakeup from the new (shorter) interval.
742
+ this.clearRateLimitTimer();
743
+ this.schedule();
744
+ }
612
745
  }
613
746
  countReadyActive() {
614
747
  let count = 0;
@@ -682,9 +815,9 @@ export class SubagentBatchController {
682
815
  * 2. `~/.pi/agent/settings.json` → `pi-swarm.maxConcurrency` (global)
683
816
  * 3. `PI_SWARM_MAX_CONCURRENCY` env var
684
817
  *
685
- * Returns `undefined` when unset. A present value must be a positive
686
- * integer; invalid input throws so a misconfigured cap never silently
687
- * reverts to uncapped.
818
+ * Falls back to DEFAULT_MAX_CONCURRENCY (5) when unset. A present
819
+ * value must be a positive integer; invalid input throws so a
820
+ * misconfigured cap never silently reverts to uncapped.
688
821
  */
689
822
  export function resolveSwarmMaxConcurrency(cwd) {
690
823
  // 1. Project-local settings
@@ -705,12 +838,12 @@ export function resolveSwarmMaxConcurrency(cwd) {
705
838
  if (raw !== undefined && raw.trim() !== "") {
706
839
  return validateConcurrency(Number(raw), AGENT_SWARM_MAX_CONCURRENCY_ENV);
707
840
  }
708
- // 4. Default
841
+ // 4. Default (always reached — value guaranteed)
709
842
  return DEFAULT_MAX_CONCURRENCY;
710
843
  }
711
844
  function validateConcurrency(value, source) {
712
845
  if (value === undefined || value === null)
713
- return undefined;
846
+ return DEFAULT_MAX_CONCURRENCY;
714
847
  const num = Number(value);
715
848
  if (!Number.isInteger(num) || num <= 0) {
716
849
  throw new Error(`pi-swarm.maxConcurrency in ${source} must be a positive integer, got ${JSON.stringify(value)}.`);