@diousk/pi-subagents-fast 0.20.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 (183) hide show
  1. package/CHANGELOG.md +808 -0
  2. package/CONTRIBUTING.md +72 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1034 -0
  5. package/SECURITY.md +95 -0
  6. package/dist/abortable.d.ts +12 -0
  7. package/dist/abortable.js +42 -0
  8. package/dist/agent-color.d.ts +35 -0
  9. package/dist/agent-color.js +123 -0
  10. package/dist/agent-file-toggle.d.ts +125 -0
  11. package/dist/agent-file-toggle.js +260 -0
  12. package/dist/agent-manager.d.ts +472 -0
  13. package/dist/agent-manager.js +1338 -0
  14. package/dist/agent-runner.d.ts +312 -0
  15. package/dist/agent-runner.js +1034 -0
  16. package/dist/agent-types.d.ts +119 -0
  17. package/dist/agent-types.js +286 -0
  18. package/dist/child-context.d.ts +2 -0
  19. package/dist/child-context.js +12 -0
  20. package/dist/context.d.ts +12 -0
  21. package/dist/context.js +56 -0
  22. package/dist/cross-extension-rpc.d.ts +66 -0
  23. package/dist/cross-extension-rpc.js +138 -0
  24. package/dist/custom-agents.d.ts +54 -0
  25. package/dist/custom-agents.js +316 -0
  26. package/dist/default-agents.d.ts +7 -0
  27. package/dist/default-agents.js +122 -0
  28. package/dist/enabled-models.d.ts +49 -0
  29. package/dist/enabled-models.js +145 -0
  30. package/dist/env.d.ts +6 -0
  31. package/dist/env.js +28 -0
  32. package/dist/group-join.d.ts +32 -0
  33. package/dist/group-join.js +116 -0
  34. package/dist/index.d.ts +50 -0
  35. package/dist/index.js +3682 -0
  36. package/dist/invocation-config.d.ts +107 -0
  37. package/dist/invocation-config.js +83 -0
  38. package/dist/memory.d.ts +53 -0
  39. package/dist/memory.js +165 -0
  40. package/dist/mention-clone.d.ts +87 -0
  41. package/dist/mention-clone.js +153 -0
  42. package/dist/mention.d.ts +81 -0
  43. package/dist/mention.js +131 -0
  44. package/dist/model-resolver.d.ts +36 -0
  45. package/dist/model-resolver.js +95 -0
  46. package/dist/model-scope.d.ts +49 -0
  47. package/dist/model-scope.js +48 -0
  48. package/dist/nested-tools.d.ts +55 -0
  49. package/dist/nested-tools.js +299 -0
  50. package/dist/output-file.d.ts +43 -0
  51. package/dist/output-file.js +142 -0
  52. package/dist/prompts.d.ts +55 -0
  53. package/dist/prompts.js +91 -0
  54. package/dist/schedule-store.d.ts +38 -0
  55. package/dist/schedule-store.js +155 -0
  56. package/dist/schedule.d.ts +109 -0
  57. package/dist/schedule.js +359 -0
  58. package/dist/settings.d.ts +360 -0
  59. package/dist/settings.js +251 -0
  60. package/dist/skill-loader.d.ts +24 -0
  61. package/dist/skill-loader.js +93 -0
  62. package/dist/status-note.d.ts +61 -0
  63. package/dist/status-note.js +85 -0
  64. package/dist/structured-output.d.ts +61 -0
  65. package/dist/structured-output.js +112 -0
  66. package/dist/types.d.ts +371 -0
  67. package/dist/types.js +5 -0
  68. package/dist/ui/agent-mention.d.ts +82 -0
  69. package/dist/ui/agent-mention.js +187 -0
  70. package/dist/ui/agent-widget.d.ts +219 -0
  71. package/dist/ui/agent-widget.js +592 -0
  72. package/dist/ui/conversation-viewer.d.ts +120 -0
  73. package/dist/ui/conversation-viewer.js +578 -0
  74. package/dist/ui/fleet-list.d.ts +195 -0
  75. package/dist/ui/fleet-list.js +471 -0
  76. package/dist/ui/schedule-menu.d.ts +16 -0
  77. package/dist/ui/schedule-menu.js +94 -0
  78. package/dist/ui/select-item.d.ts +27 -0
  79. package/dist/ui/select-item.js +34 -0
  80. package/dist/ui/viewer-keys.d.ts +20 -0
  81. package/dist/ui/viewer-keys.js +17 -0
  82. package/dist/ui/workflow-card.d.ts +175 -0
  83. package/dist/ui/workflow-card.js +332 -0
  84. package/dist/ui/workflow-dialog.d.ts +305 -0
  85. package/dist/ui/workflow-dialog.js +843 -0
  86. package/dist/ui/workflow-menu.d.ts +60 -0
  87. package/dist/ui/workflow-menu.js +147 -0
  88. package/dist/usage.d.ts +135 -0
  89. package/dist/usage.js +120 -0
  90. package/dist/workflow/collisions.d.ts +95 -0
  91. package/dist/workflow/collisions.js +88 -0
  92. package/dist/workflow/entry.d.ts +32 -0
  93. package/dist/workflow/entry.js +29 -0
  94. package/dist/workflow/host.d.ts +62 -0
  95. package/dist/workflow/host.js +362 -0
  96. package/dist/workflow/journal.d.ts +97 -0
  97. package/dist/workflow/journal.js +120 -0
  98. package/dist/workflow/json-schema.d.ts +51 -0
  99. package/dist/workflow/json-schema.js +111 -0
  100. package/dist/workflow/meta.d.ts +67 -0
  101. package/dist/workflow/meta.js +317 -0
  102. package/dist/workflow/progress.d.ts +224 -0
  103. package/dist/workflow/progress.js +361 -0
  104. package/dist/workflow/runtime.d.ts +334 -0
  105. package/dist/workflow/runtime.js +830 -0
  106. package/dist/workflow/saved.d.ts +90 -0
  107. package/dist/workflow/saved.js +203 -0
  108. package/dist/workflow/task.d.ts +136 -0
  109. package/dist/workflow/task.js +207 -0
  110. package/dist/workflow/tool-description.d.ts +38 -0
  111. package/dist/workflow/tool-description.js +199 -0
  112. package/dist/workflow/worker-source.d.ts +47 -0
  113. package/dist/workflow/worker-source.js +778 -0
  114. package/dist/worktree.d.ts +52 -0
  115. package/dist/worktree.js +164 -0
  116. package/dist/xml.d.ts +10 -0
  117. package/dist/xml.js +12 -0
  118. package/docs/rpc.md +183 -0
  119. package/docs/workflows.md +437 -0
  120. package/examples/agent-tool-description.md +42 -0
  121. package/examples/workflows/compose.js +51 -0
  122. package/examples/workflows/fan-out-audit.js +47 -0
  123. package/examples/workflows/gated-fix.js +60 -0
  124. package/examples/workflows/lib/count-child.js +27 -0
  125. package/examples/workflows/review-panel.js +63 -0
  126. package/examples/workflows/structured-findings.js +78 -0
  127. package/package.json +68 -0
  128. package/src/abortable.ts +43 -0
  129. package/src/agent-color.ts +161 -0
  130. package/src/agent-file-toggle.ts +270 -0
  131. package/src/agent-manager.ts +1581 -0
  132. package/src/agent-runner.ts +1286 -0
  133. package/src/agent-types.ts +346 -0
  134. package/src/child-context.ts +15 -0
  135. package/src/context.ts +58 -0
  136. package/src/cross-extension-rpc.ts +198 -0
  137. package/src/custom-agents.ts +333 -0
  138. package/src/default-agents.ts +126 -0
  139. package/src/enabled-models.ts +180 -0
  140. package/src/env.ts +33 -0
  141. package/src/group-join.ts +141 -0
  142. package/src/index.ts +3991 -0
  143. package/src/invocation-config.ts +155 -0
  144. package/src/memory.ts +179 -0
  145. package/src/mention-clone.ts +196 -0
  146. package/src/mention.ts +141 -0
  147. package/src/model-resolver.ts +118 -0
  148. package/src/model-scope.ts +70 -0
  149. package/src/nested-tools.ts +422 -0
  150. package/src/output-file.ts +155 -0
  151. package/src/prompts.ts +142 -0
  152. package/src/schedule-store.ts +153 -0
  153. package/src/schedule.ts +386 -0
  154. package/src/settings.ts +587 -0
  155. package/src/skill-loader.ts +102 -0
  156. package/src/status-note.ts +90 -0
  157. package/src/structured-output.ts +130 -0
  158. package/src/types.ts +384 -0
  159. package/src/ui/agent-mention.ts +216 -0
  160. package/src/ui/agent-widget.ts +664 -0
  161. package/src/ui/conversation-viewer.ts +589 -0
  162. package/src/ui/fleet-list.ts +543 -0
  163. package/src/ui/schedule-menu.ts +105 -0
  164. package/src/ui/select-item.ts +45 -0
  165. package/src/ui/viewer-keys.ts +39 -0
  166. package/src/ui/workflow-card.ts +470 -0
  167. package/src/ui/workflow-dialog.ts +1115 -0
  168. package/src/ui/workflow-menu.ts +193 -0
  169. package/src/usage.ts +167 -0
  170. package/src/workflow/collisions.ts +123 -0
  171. package/src/workflow/entry.ts +47 -0
  172. package/src/workflow/host.ts +403 -0
  173. package/src/workflow/journal.ts +164 -0
  174. package/src/workflow/json-schema.ts +128 -0
  175. package/src/workflow/meta.ts +325 -0
  176. package/src/workflow/progress.ts +550 -0
  177. package/src/workflow/runtime.ts +1219 -0
  178. package/src/workflow/saved.ts +217 -0
  179. package/src/workflow/task.ts +302 -0
  180. package/src/workflow/tool-description.ts +200 -0
  181. package/src/workflow/worker-source.ts +781 -0
  182. package/src/worktree.ts +205 -0
  183. package/src/xml.ts +13 -0
@@ -0,0 +1,472 @@
1
+ /**
2
+ * agent-manager.ts — Tracks agents, background execution, resume support.
3
+ *
4
+ * There are two independent concurrency pools, never one:
5
+ *
6
+ * - Background (`maxConcurrent`, default 10) bounds detached agents.
7
+ * - Foreground (`maxConcurrentForeground`, default 0 = unlimited) bounds
8
+ * agents a caller is blocking on inline — `spawnAndWait`.
9
+ *
10
+ * Independent by design: a foreground agent blocks the parent anyway, so
11
+ * charging it to the background pool would let a saturated pool starve the main
12
+ * session of work it could have done itself. Excess agents in either pool are
13
+ * queued and auto-started as slots free up. Nested children take no slot in
14
+ * either — see `occupiesPoolSlot` / `occupiesForegroundSlot`.
15
+ */
16
+ import type { Model } from "@earendil-works/pi-ai";
17
+ import type { AgentSession, ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
18
+ import { type ToolActivity } from "./agent-runner.js";
19
+ import type { AgentInvocation, AgentRecord, AgentTombstone, IsolationMode, MentionResolution, SubagentType, ThinkingLevel } from "./types.js";
20
+ import { type LifetimeUsage } from "./usage.js";
21
+ import type { CompiledSchema } from "./workflow/json-schema.js";
22
+ export type OnAgentComplete = (record: AgentRecord) => void;
23
+ export type OnAgentStart = (record: AgentRecord) => void;
24
+ export type OnAgentCompact = (record: AgentRecord, info: CompactionInfo) => void;
25
+ /**
26
+ * Fired once per assistant `message_end`, for EVERY agent this manager owns —
27
+ * top-level and nested alike, spawns and resumes. The one place where each
28
+ * message is seen exactly once: `AgentRecord.lifetimeUsage` is deliberately
29
+ * double-booked into ancestors (see `nested-tools.ts`) so a hidden child's spend
30
+ * shows up on the record a human can see, which makes those records useless as
31
+ * a basis for anything that must not count a message twice — parent-session
32
+ * accounting above all.
33
+ */
34
+ export type OnAgentUsage = (record: AgentRecord, usage: LifetimeUsage) => void;
35
+ export type CompactionInfo = {
36
+ reason: "manual" | "threshold" | "overflow";
37
+ tokensBefore: number;
38
+ };
39
+ /**
40
+ * Whether a record is one of the session's own agents, rather than something
41
+ * another agent or a workflow owns.
42
+ *
43
+ * The single definition behind every user-facing surface — the fleet list, the
44
+ * widget, the `/agents` menus, `@handle` resolution, and the completion events
45
+ * and session entries. An owned child reports through its owner, so surfacing
46
+ * it separately would double-count the same work in the places a person reads.
47
+ */
48
+ export declare function isTopLevelAgent(record: Pick<AgentRecord, "parentAgentId" | "workflowId">): boolean;
49
+ interface SpawnOptions {
50
+ description: string;
51
+ /**
52
+ * Optional memorable name for this instance, becoming a second handle
53
+ * (`@auth-audit`) alongside the type-derived one. Slugged, not validated —
54
+ * anything unusable degrades via `handleBase` rather than failing the spawn.
55
+ */
56
+ name?: string;
57
+ /**
58
+ * Reopen this pi session file instead of starting a fresh conversation, so a
59
+ * mention of an evicted agent continues where it left off. The agent's
60
+ * definition is still resolved from its type, so the continuation runs under
61
+ * the type's CURRENT config.
62
+ */
63
+ resumeSessionFile?: string;
64
+ /**
65
+ * Take an evicted agent's names back verbatim instead of allocating fresh
66
+ * ones, so a resumed conversation keeps the handle the user just typed —
67
+ * `handleBase(type)` cannot reproduce a numbered `explore-2`. Safe without an
68
+ * `assignHandle` pass because tombstoned names are excluded from allocation
69
+ * (`takenHandles`), so nothing live can be holding them.
70
+ *
71
+ * Internal capability, like `resumeSessionFile`: a forged handle would
72
+ * duplicate a live agent's name and make `resolveMention` ambiguous, so
73
+ * `spawnTopLevel` strips it from anything a caller sends.
74
+ */
75
+ reclaim?: {
76
+ handle: string;
77
+ alias?: string;
78
+ };
79
+ model?: Model<any>;
80
+ maxTurns?: number;
81
+ isolated?: boolean;
82
+ inheritContext?: boolean;
83
+ thinkingLevel?: ThinkingLevel;
84
+ isBackground?: boolean;
85
+ /**
86
+ * Skip whichever pool's queue check applies to this spawn — start immediately
87
+ * even if the configured concurrency limit would otherwise queue it. The slot
88
+ * is still COUNTED once the run starts, so a bypassing spawn transiently
89
+ * exceeds the limit rather than being invisible to it.
90
+ *
91
+ * Used by the scheduler, so a fired job can't be deferred past its trigger
92
+ * window, and by the `/agents` agent-file generator, which has no way to
93
+ * cancel a wait (see its call site).
94
+ */
95
+ bypassQueue?: boolean;
96
+ /**
97
+ * A caller is awaiting this record inline (`spawnAndWait`) — what
98
+ * `maxConcurrentForeground` bounds. Set only by `spawnAndWait`; stripped from
99
+ * caller-supplied options by `spawnTopLevel`, since a forged `blocking` would
100
+ * defer a detached start behind a queue its caller cannot see or release.
101
+ */
102
+ blocking?: boolean;
103
+ /**
104
+ * The workflow run this child belongs to, when a workflow spawned it.
105
+ *
106
+ * Ownership, not decoration. A workflow's children are the workflow's — they
107
+ * report through its card, its notification and its dialog, so they are
108
+ * filtered out of every top-level surface exactly as nested children are, and
109
+ * they take no `maxConcurrent` slot: the run has its own concurrency cap, and
110
+ * counting them twice would let one workflow starve the whole session.
111
+ */
112
+ workflowId?: string;
113
+ /**
114
+ * Make the child report through a `StructuredOutput` tool built from this
115
+ * compiled schema. Set only by the workflow host, for `agent({ schema })`.
116
+ */
117
+ structuredOutput?: CompiledSchema;
118
+ /** Isolation mode — "worktree" creates a temp git worktree for the agent. */
119
+ isolation?: IsolationMode;
120
+ /**
121
+ * Working directory for the agent (absolute path). Default: parent session
122
+ * cwd. The agent's tools operate here, but .pi config (extensions, skills,
123
+ * settings, memory) still loads from the parent session's project — the
124
+ * target directory's `.pi` extensions never execute. With isolation:
125
+ * "worktree", the worktree is created FROM this directory and the result
126
+ * branch lands in that repo.
127
+ */
128
+ cwd?: string;
129
+ /**
130
+ * Last chance to look at an isolated agent's worktree, awaited immediately
131
+ * before it is committed to a branch and removed.
132
+ *
133
+ * Exists because that removal happens inside the settle path, before
134
+ * `spawnAndWait` resolves: by the time a caller has the finished record, the
135
+ * directory the child actually wrote in is gone. Anything that must inspect
136
+ * or verify that tree — a workflow `gate` is the motivating case — has to run
137
+ * here or it silently inspects the main tree instead.
138
+ *
139
+ * Fires only on the normal settle path, and only when a worktree was created.
140
+ * Not on the error path and not on the stop-during-copy guard: those are
141
+ * already failing, and delaying cleanup there would leak a copy for no gain.
142
+ * A rejection is swallowed — the hook can never keep the worktree alive.
143
+ */
144
+ onBeforeWorktreeCleanup?: (worktreePath: string) => Promise<void>;
145
+ /** Resolved invocation snapshot captured for UI display. */
146
+ invocation?: AgentInvocation;
147
+ /** Parent abort signal — when aborted, the subagent is also stopped. */
148
+ signal?: AbortSignal;
149
+ /**
150
+ * Called synchronously once the record is in the map and its promise is set,
151
+ * before `onSessionCreated` fires — where callers attach the output file.
152
+ *
153
+ * Carried on the options rather than parked on the manager for the duration
154
+ * of a spawn: with a foreground queue, `startAgent` can run at drain time,
155
+ * long after any such field would have been restored, and the callback would
156
+ * silently never fire (or fire into an unrelated caller's closure).
157
+ */
158
+ onSpawned?: (id: string) => void;
159
+ /**
160
+ * Called synchronously when the spawn is queued instead of started, with how
161
+ * many entries in its own pool are ahead of it. The foreground UI uses it to
162
+ * say so while it waits; nothing else needs it.
163
+ */
164
+ onQueued?: (id: string, ahead: number) => void;
165
+ /** Called on tool start/end with activity info (for streaming progress to UI). */
166
+ onToolActivity?: (activity: ToolActivity) => void;
167
+ /** Called on streaming text deltas from the assistant response. */
168
+ onTextDelta?: (delta: string, fullText: string) => void;
169
+ /** Called when the agent session is created (for accessing session stats). */
170
+ onSessionCreated?: (session: AgentSession) => void;
171
+ /** Called at the end of each agentic turn with the cumulative count. */
172
+ onTurnEnd?: (turnCount: number) => void;
173
+ /** Called once per assistant message_end with that message's usage delta. */
174
+ onAssistantUsage?: (usage: {
175
+ input: number;
176
+ output: number;
177
+ cacheWrite: number;
178
+ }) => void;
179
+ /** Called when the session successfully compacts. */
180
+ onCompaction?: (info: CompactionInfo) => void;
181
+ /** Nesting depth: top-level subagent = 1. */
182
+ depth?: number;
183
+ /** Parent agent ID for ownership-scoped nested controls. */
184
+ parentAgentId?: string;
185
+ /** Effective inherited nesting cap for this branch. */
186
+ maxSubagentDepth?: number;
187
+ /** Config-discovery root inherited by nested launches when it differs from the working directory. */
188
+ configCwd?: string;
189
+ /** Root session id, inherited by nested launches so transcripts stay grouped. */
190
+ rootSessionId?: string;
191
+ }
192
+ interface ResumeOptions {
193
+ /**
194
+ * Run the resumed turn detached in the background: return immediately with
195
+ * the record still "running" (or "queued" at the concurrency limit) and
196
+ * notify on completion via onComplete, exactly like a background spawn.
197
+ * Default (false/undefined) runs the resume inline and returns the settled
198
+ * record — the historical behavior.
199
+ */
200
+ isBackground?: boolean;
201
+ /** Called on tool start/end with activity info (for streaming progress to UI). */
202
+ onToolActivity?: (activity: ToolActivity) => void;
203
+ /** Called once per assistant message_end with that message's usage delta. */
204
+ onAssistantUsage?: (usage: {
205
+ input: number;
206
+ output: number;
207
+ cacheWrite: number;
208
+ }) => void;
209
+ /** Called when the session successfully compacts. */
210
+ onCompaction?: (info: CompactionInfo) => void;
211
+ /**
212
+ * Background resume only: called synchronously when the run actually starts —
213
+ * immediately, or later from drainQueue. Callers wire per-run side effects
214
+ * (output-file streaming) here rather than at the call site, so a resume that
215
+ * is stopped while still queued never leaves a subscription behind: `abort()`
216
+ * drops a queued record without reaching `settle()`, which is what would have
217
+ * torn that subscription down.
218
+ */
219
+ onStarted?: () => void;
220
+ }
221
+ export declare class AgentManager {
222
+ private agents;
223
+ private cleanupInterval;
224
+ private onComplete?;
225
+ private onStart?;
226
+ private onCompact?;
227
+ private onUsage?;
228
+ private maxConcurrent;
229
+ private maxConcurrentForeground;
230
+ /** Base repos worktrees were created from — so dispose() can prune them all,
231
+ * not just the parent repo (caller-supplied cwd can target other repos). */
232
+ private worktreeRepos;
233
+ /**
234
+ * Startup phases, keyed by agent id. `spawn()` still returns synchronously,
235
+ * but an agent using worktree isolation is not running yet when it does —
236
+ * copying the repo is an awaited git call. This is what `awaitStartup` hands
237
+ * callers that must fail their tool call on a startup failure, and what
238
+ * `waitForAll` waits on while a record is "running" with no `promise` yet.
239
+ * Entries are dropped once the run is underway, and kept (rejected) after a
240
+ * startup failure so a late `awaitStartup` still sees it.
241
+ */
242
+ private startups;
243
+ /**
244
+ * Evicted agents that can still be reached by name, keyed by handle. Outlives
245
+ * the 10-minute record cleanup — that timer exists to bound memory, not to
246
+ * expire a conversation the user might still want — and is cleared alongside
247
+ * completed records on session start/switch.
248
+ */
249
+ private tombstones;
250
+ /**
251
+ * Agents waiting to start, tagged with the pool they wait on. One queue for
252
+ * both pools: `drainQueue` picks the earliest entry whose own pool has room,
253
+ * so neither can head-of-line-block the other, and every removal path
254
+ * (`abort`, `abortAll`, `dispose`) stays a single filter.
255
+ *
256
+ * `release` wakes a caller blocked in `spawnAndWait`, and is fired once the
257
+ * entry's `start` has SETTLED rather than at drain time: startup is async
258
+ * now, so releasing earlier would wake the caller before `record.promise`
259
+ * exists and it would read a still-starting agent as one that never ran.
260
+ * Removing an entry from this array MUST release it — a queued record has no
261
+ * promise to await, and pi has no tool-execution timeout to bail the caller
262
+ * out.
263
+ */
264
+ private queue;
265
+ /** Number of currently running background agents. */
266
+ private runningBackground;
267
+ /** Number of currently running foreground (blocking) agents. */
268
+ private runningForeground;
269
+ constructor(onComplete?: OnAgentComplete, maxConcurrent?: number, onStart?: OnAgentStart, onCompact?: OnAgentCompact, onUsage?: OnAgentUsage);
270
+ /** Update the max concurrent background agents limit. */
271
+ setMaxConcurrent(n: number): void;
272
+ getMaxConcurrent(): number;
273
+ /** Update the max concurrent foreground (blocking) agents limit. 0 = unlimited. */
274
+ setMaxConcurrentForeground(n: number): void;
275
+ getMaxConcurrentForeground(): number;
276
+ /**
277
+ * Which pool a spawn is charged to, or undefined for one that is charged to
278
+ * neither (nested children, detached non-background spawns).
279
+ *
280
+ * Nothing here queues when the limit is unset — `poolHasRoom` reports an
281
+ * unlimited pool as always having room, so that alone is what keeps the
282
+ * default path identical. The `> 0` guard is belt and braces on top: it also
283
+ * keeps the counter from churning and the settle path from calling a drain
284
+ * that would find nothing to do. Both are unobservable, which is why no test
285
+ * pins them; the observable half — that the default start stays synchronous —
286
+ * is pinned in `test/foreground-concurrency.test.ts`.
287
+ */
288
+ private poolFor;
289
+ private poolHasRoom;
290
+ /**
291
+ * Spawn an agent and return its ID immediately (for background use).
292
+ * If the concurrency limit is reached, the agent is queued.
293
+ *
294
+ * The id comes back synchronously, but with `isolation: "worktree"` the agent
295
+ * is not running yet when it does — the repo copy is an awaited git call.
296
+ * Callers that must fail a tool call on a startup failure await
297
+ * `awaitStartup(id)`; everyone else sees it on the record (status "error").
298
+ */
299
+ spawn(pi: ExtensionAPI, ctx: ExtensionContext, type: SubagentType, prompt: string, options: SpawnOptions): string;
300
+ /**
301
+ * Wire a parent abort signal for a record that is about to be QUEUED.
302
+ * `startAgent` does this for running agents, and a queued record never gets
303
+ * there, so without this Esc could not release a queue position.
304
+ *
305
+ * Returns false when the signal is ALREADY aborted, in which case the record
306
+ * is stopped here and must not be enqueued: `addEventListener` never fires on
307
+ * an aborted signal, so a `spawnAndWait` on it would wait forever — pi has no
308
+ * tool-execution timeout to bail it out.
309
+ *
310
+ * The listener is left in place when the agent starts. `startAgent` adds its
311
+ * own, so both fire on a later abort, but `abort()` on an already-stopped
312
+ * record is a no-op — so detaching would only be tidiness, and tidiness the
313
+ * `abortAll`/`dispose` paths could not offer anyway.
314
+ */
315
+ private armQueuedAbort;
316
+ /**
317
+ * Kick off an agent's startup and register it under `startups`. The returned
318
+ * promise never rejects — the failure is delivered through `awaitStartup`,
319
+ * and to the record.
320
+ *
321
+ * @param queuedPool - The pool this start was QUEUED on, or undefined for an
322
+ * immediate start. A queue drain can be minutes after `spawn()` returned,
323
+ * and nobody is awaiting `awaitStartup` by then, so a failure has to live
324
+ * on the record as status "error" — what drainQueue did when the throw was
325
+ * still synchronous. An immediate start instead drops the record, exactly
326
+ * as the throw out of `spawn()` did: no orphan in `listAgents()`, and the
327
+ * handle goes back.
328
+ */
329
+ private launch;
330
+ /**
331
+ * Resolves once the agent is actually running, and rejects with the startup
332
+ * failure (strict worktree isolation) that `spawn()` used to throw before the
333
+ * repo copy became async. Resolves immediately for an agent that is already
334
+ * running, still queued, or unknown — so callers can await it unconditionally.
335
+ *
336
+ * Call it in the same tick as the `spawn()` it belongs to: a failed startup
337
+ * takes its record (and this entry) with it, exactly as the throw did.
338
+ */
339
+ awaitStartup(id: string): Promise<void>;
340
+ /** Actually start an agent (called immediately or from queue drain). */
341
+ private startAgent;
342
+ /**
343
+ * The shared tail of both settle paths: release whatever pool slot the run
344
+ * held, notify, and let the queue drain into the freed slot.
345
+ *
346
+ * The decrement lives HERE and nowhere else. `abort()` on a running record
347
+ * only fires its controller and leaves the run to settle normally, so
348
+ * decrementing there too would double-free — permanently lifting the limit.
349
+ *
350
+ * Foreground agents fire `onComplete` for lifecycle symmetry, with
351
+ * `resultConsumed` set so the callback skips notifications the inline result
352
+ * already delivered.
353
+ *
354
+ * @param guardCallback swallow a throwing `onComplete` (the success path does;
355
+ * the error path historically did not, and keeps not doing so).
356
+ * @param pool the pool this run was CHARGED TO at start time — passed in, not
357
+ * recomputed, so a mid-run change to `maxConcurrentForeground` can't make
358
+ * the release disagree with the acquire.
359
+ */
360
+ private settleRun;
361
+ /**
362
+ * Stop the nested children a settled parent owns. Nested records are hidden
363
+ * from the UI and only their owner can consume them, so a child outliving its
364
+ * parent would burn tokens unseen with no way to reach it. Grandchildren are
365
+ * covered transitively — each abort lands in that child's own settle path.
366
+ */
367
+ private abortOwnedChildren;
368
+ /**
369
+ * Start queued agents up to each pool's concurrency limit.
370
+ *
371
+ * `findIndex` on the entry's OWN pool rather than `shift`: with one queue
372
+ * serving two independent limits, a saturated foreground pool at the head
373
+ * would otherwise stall every background agent behind it. Taking the earliest
374
+ * eligible entry keeps FIFO within each pool, which is what callers see.
375
+ */
376
+ private drainQueue;
377
+ /**
378
+ * Remove queued entries and wake anyone blocked on them. The single point
379
+ * that enforces "leaving the queue releases the waiter" — a missed release is
380
+ * an unbounded hang, not a failed call.
381
+ */
382
+ private dequeue;
383
+ /**
384
+ * Spawn an agent and wait for completion (foreground use).
385
+ * Charged to the foreground pool (`maxConcurrentForeground`), which is
386
+ * unlimited by default; never to the background one.
387
+ * Returns { id, record } so callers can access the agent ID.
388
+ *
389
+ * @param onSpawned - Called synchronously once the run is kicked off, before
390
+ * onSessionCreated fires. Use this to set record.outputFile so
391
+ * streamToOutputFile can pick it up.
392
+ */
393
+ spawnAndWait(pi: ExtensionAPI, ctx: ExtensionContext, type: SubagentType, prompt: string, options: Omit<SpawnOptions, "isBackground">, onSpawned?: (id: string) => void): Promise<{
394
+ id: string;
395
+ record: AgentRecord;
396
+ }>;
397
+ /**
398
+ * Resume an existing agent session with a new prompt.
399
+ */
400
+ resume(id: string, prompt: string, signal?: AbortSignal, options?: ResumeOptions): Promise<AgentRecord | undefined>;
401
+ /**
402
+ * Start a background resume run: detached, settling and notifying like
403
+ * startAgent's background path. Invoked immediately, or from drainQueue when
404
+ * a concurrency slot frees. The session already exists (resume reuses it), so
405
+ * there is no onSessionCreated to hang per-run wiring off — callers use
406
+ * `options.onStarted`, which fires on both the immediate and the drained path.
407
+ */
408
+ private startResume;
409
+ /**
410
+ * Send a steering message to an agent from the UI (mirrors the steer_subagent
411
+ * tool). A live session delivers it now — it interrupts the agent after its
412
+ * current tool execution and appears as a user message. If the session isn't
413
+ * ready yet, the message is queued on `pendingSteers` and flushed when the
414
+ * session is created. Returns false if the agent can't accept steering
415
+ * (unknown id, or no longer running/queued).
416
+ */
417
+ steer(id: string, message: string): boolean;
418
+ getRecord(id: string): AgentRecord | undefined;
419
+ /** Handles already in use, so a fresh spawn can pick an unclaimed one. */
420
+ private takenHandles;
421
+ /**
422
+ * Resolve an `@name` from the prompt. Matches a top-level agent's handle
423
+ * case-insensitively, preferring one that can still be steered and otherwise
424
+ * the most recently started (which is the one a resume should continue), then
425
+ * falls back to an exact agent id so `@<agentId>` works too.
426
+ */
427
+ resolveMention(name: string): MentionResolution | undefined;
428
+ /**
429
+ * Forget an evicted agent, by handle. For the case where its session file has
430
+ * gone: the entry can then only ever fail, while still holding the name
431
+ * against the type that would otherwise start a fresh agent under it.
432
+ *
433
+ * A *successful* resume does not drop its tombstone — the live record it
434
+ * creates already wins in `resolveMention`, and overwrites the entry in place
435
+ * when it is itself evicted.
436
+ */
437
+ dropTombstone(handle: string): void;
438
+ /** Evicted agents whose conversation can still be reopened, newest first. */
439
+ listTombstones(): AgentTombstone[];
440
+ listAgents(): AgentRecord[];
441
+ abort(id: string): boolean;
442
+ /** Dispose a record's session and remove it from the map. */
443
+ private removeRecord;
444
+ /**
445
+ * Preserve enough of a departing record for `@handle` to reopen its
446
+ * conversation later. Nothing to keep unless it has both a handle to be
447
+ * addressed by and a session file to reopen — an in-memory session leaves no
448
+ * transcript, so the mention would have nothing to continue from.
449
+ */
450
+ private tombstone;
451
+ private cleanup;
452
+ /**
453
+ * Remove all completed/stopped/errored records immediately.
454
+ * Called on session start/switch so tasks from a prior session don't persist.
455
+ * Pass skipUnconsumed=true to preserve records the LLM hasn't read yet
456
+ * (resultConsumed=false) — they will be evicted by the 10-minute cleanup timer instead.
457
+ */
458
+ clearCompleted(skipUnconsumed?: boolean): void;
459
+ /** Whether any agents are still running or queued. */
460
+ hasRunning(): boolean;
461
+ /** Abort all running and queued agents immediately. */
462
+ abortAll(): number;
463
+ /** Wait for all running and queued agents to complete (including queued ones). */
464
+ waitForAll(): Promise<void>;
465
+ /**
466
+ * @param pi - Needed to run `git worktree prune`, which is async now and so
467
+ * cannot be reached through a stored spawn argument at shutdown. Omitting
468
+ * it (tests, teardown of a manager that never spawned) skips the prune.
469
+ */
470
+ dispose(pi?: ExtensionAPI): Promise<void>;
471
+ }
472
+ export {};