@multiclawcli/core 0.3.2 → 0.4.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.
@@ -0,0 +1,720 @@
1
+ type ToolName = "Read" | "Write" | "Edit" | "MultiEdit" | "Bash" | "Glob" | "Grep" | "WebFetch";
2
+ interface AgentDefinition {
3
+ id: string;
4
+ name: string;
5
+ icon?: string;
6
+ runtime?: string;
7
+ /**
8
+ * Agent product (e.g. "claude", "opencode", "codex", "cursor").
9
+ * Distinct from `runtime` (the protocol, always "acp" today).
10
+ * When absent it is inferred from `command` or config defaults.
11
+ */
12
+ provider?: string;
13
+ /**
14
+ * Command to launch for this agent's runtime, when the runtime talks to an
15
+ * external process (e.g. ACP). Generic — "which binary to start", not a
16
+ * protocol detail — so a built-in runtime simply ignores it.
17
+ */
18
+ command?: string;
19
+ /** Arguments for {@link command}. */
20
+ args?: string[];
21
+ model?: string;
22
+ /**
23
+ * Map of provider ids (or the legacy alias "acp") to model names.
24
+ * Provider id is preferred; "acp" is kept for backward compatibility.
25
+ */
26
+ models?: Partial<Record<string, string>>;
27
+ /**
28
+ * Model tier preference. Used when `model` and `models` are absent.
29
+ * The catalog maps each tier to a provider-specific model id.
30
+ */
31
+ modelTier?: "strong" | "balanced" | "fast";
32
+ systemPrompt: string;
33
+ taskPrompt: string;
34
+ /**
35
+ * One-line role, for display. Every built-in agent declares one.
36
+ *
37
+ * Distinct from {@link taskTitle}, which the orchestrator fills in per turn
38
+ * from the leader's task plan — "what this agent was asked to do *this* run".
39
+ * A `description` is "what this agent is for", so it is the one that is still
40
+ * available before the first turn has been planned.
41
+ */
42
+ description?: string;
43
+ taskTitle?: string;
44
+ agentScope?: string;
45
+ agentPlan?: string;
46
+ tools?: ToolName[];
47
+ dependsOn?: string[];
48
+ timeout?: number;
49
+ retries?: number;
50
+ workDir?: string;
51
+ }
52
+ type AgentStatus = "pending" | "running" | "retrying" | "success" | "failed" | "skipped";
53
+ interface AgentResult {
54
+ agentId: string;
55
+ agentName: string;
56
+ status: AgentStatus;
57
+ output: string;
58
+ duration: number;
59
+ attempts: number;
60
+ error?: string;
61
+ startTime: string;
62
+ endTime: string;
63
+ }
64
+ interface SubTask {
65
+ id: string;
66
+ title: string;
67
+ scope: string;
68
+ plan?: string[];
69
+ dependsOn?: string[];
70
+ }
71
+ interface TaskPlan {
72
+ projectName: string;
73
+ requirement: string;
74
+ tasks: SubTask[];
75
+ }
76
+
77
+ type Overrides$b = Partial<AgentDefinition>;
78
+ declare function archDesignReviewer(overrides?: Overrides$b): AgentDefinition;
79
+
80
+ type Overrides$a = Partial<AgentDefinition>;
81
+ declare function architect(overrides?: Overrides$a): AgentDefinition;
82
+
83
+ type Overrides$9 = Partial<AgentDefinition>;
84
+ declare function backendDeveloper(overrides?: Overrides$9): AgentDefinition;
85
+
86
+ type Overrides$8 = Partial<AgentDefinition>;
87
+ declare function codeReviewer(overrides?: Overrides$8): AgentDefinition;
88
+
89
+ type Overrides$7 = Partial<AgentDefinition>;
90
+ declare function devops(overrides?: Overrides$7): AgentDefinition;
91
+
92
+ type Overrides$6 = Partial<AgentDefinition>;
93
+ declare function frontendDeveloper(overrides?: Overrides$6): AgentDefinition;
94
+
95
+ type Overrides$5 = Partial<AgentDefinition>;
96
+ declare function leader(overrides?: Overrides$5): AgentDefinition;
97
+
98
+ type Overrides$4 = Partial<AgentDefinition>;
99
+ declare function productManager(overrides?: Overrides$4): AgentDefinition;
100
+
101
+ type Overrides$3 = Partial<AgentDefinition>;
102
+ declare function reviewer(overrides?: Overrides$3): AgentDefinition;
103
+
104
+ type Overrides$2 = Partial<AgentDefinition>;
105
+ declare function tester(overrides?: Overrides$2): AgentDefinition;
106
+
107
+ type Overrides$1 = Partial<AgentDefinition>;
108
+ declare function uiDesignReviewer(overrides?: Overrides$1): AgentDefinition;
109
+
110
+ type Overrides = Partial<AgentDefinition>;
111
+ declare function uiDesigner(overrides?: Overrides): AgentDefinition;
112
+
113
+ declare const agents: {
114
+ leader: typeof leader;
115
+ architect: typeof architect;
116
+ productManager: typeof productManager;
117
+ backendDeveloper: typeof backendDeveloper;
118
+ frontendDeveloper: typeof frontendDeveloper;
119
+ tester: typeof tester;
120
+ reviewer: typeof reviewer;
121
+ archDesignReviewer: typeof archDesignReviewer;
122
+ uiDesigner: typeof uiDesigner;
123
+ uiDesignReviewer: typeof uiDesignReviewer;
124
+ codeReviewer: typeof codeReviewer;
125
+ devops: typeof devops;
126
+ };
127
+
128
+ /**
129
+ * What the leader decided a request needs.
130
+ *
131
+ * The leader is the only agent that runs before the pipeline exists, which makes
132
+ * it the only place where "does this even need the team?" can be answered. `run`
133
+ * is the familiar case; the other two exist so that a greeting or a question is
134
+ * answered instead of spinning up every agent in the config.
135
+ */
136
+ type LeaderMode = "run" | "reply" | "ask";
137
+ type LeaderDecision = {
138
+ mode: "run";
139
+ run: string[];
140
+ } | {
141
+ mode: "reply" | "ask";
142
+ message: string;
143
+ };
144
+ /**
145
+ * A turn that ended in words rather than in a pipeline.
146
+ *
147
+ * Carried on {@link OrchestratorResult} so a caller can tell "the team ran and
148
+ * succeeded" from "the leader answered you" — both of which are `success: true`
149
+ * with an empty `agentResults`.
150
+ */
151
+ interface LeaderMessage {
152
+ mode: "reply" | "ask";
153
+ message: string;
154
+ }
155
+
156
+ /**
157
+ * One finished turn of a session, as dialogue the leader can read back.
158
+ *
159
+ * A requirement alone is not always interpretable: when the leader asked "which
160
+ * database?" and the user answered "Postgres", turn two's requirement is the
161
+ * bare word "Postgres". Paired with the turn that produced the question it is
162
+ * obvious; on its own it is not.
163
+ */
164
+ interface TurnRecord {
165
+ /** What the user asked for. */
166
+ requirement: string;
167
+ /** How the turn ended in words, when it ended that way. */
168
+ reply?: LeaderMessage;
169
+ }
170
+ interface MultiClawConfig {
171
+ name: string;
172
+ workDir: string;
173
+ leader?: AgentDefinition;
174
+ agents: AgentDefinition[];
175
+ context?: Record<string, string>;
176
+ /**
177
+ * Earlier turns of this session, oldest first.
178
+ *
179
+ * Core has no notion of a session — the orchestrator is built fresh per turn —
180
+ * so whoever runs several turns in a row (the console) is the one that has to
181
+ * carry them. Rendered into the leader's prompt; a single-turn run leaves it
182
+ * unset and sees no conversation at all.
183
+ */
184
+ history?: TurnRecord[];
185
+ logDir?: string;
186
+ continueOnError?: boolean;
187
+ maxConcurrency?: number;
188
+ useLeader?: boolean;
189
+ /**
190
+ * Project-level defaults applied to every agent that does not override them.
191
+ * Keeps generated configs readable: one line instead of 12 repeated parameters.
192
+ */
193
+ defaults?: {
194
+ provider?: string;
195
+ model?: string;
196
+ command?: string;
197
+ };
198
+ }
199
+ interface OrchestratorResult {
200
+ name: string;
201
+ success: boolean;
202
+ totalDuration: number;
203
+ agentResults: AgentResult[];
204
+ startTime: string;
205
+ endTime: string;
206
+ /**
207
+ * Set when the run was stopped via its AbortSignal. Cancellation is a third
208
+ * outcome, not a flavour of failure: the team stopped because it was told to.
209
+ * It still reports `success: false` — a run that never finished must not exit
210
+ * 0 — but the console says "cancelled" rather than "failed", and the CLI can
211
+ * exit with the conventional 130.
212
+ */
213
+ cancelled?: boolean;
214
+ /**
215
+ * Set when the turn ended in words instead of a pipeline — the leader answered
216
+ * or asked a question, so no agent ran. Without it, "the team worked and
217
+ * succeeded" and "nobody worked" look identical: both are `success: true` with
218
+ * an empty `agentResults`.
219
+ */
220
+ reply?: LeaderMessage;
221
+ }
222
+
223
+ declare function defineConfig(config: MultiClawConfig): MultiClawConfig;
224
+
225
+ /**
226
+ * Everything a runtime emits about a run carries the same envelope. `seq` is a
227
+ * per-run monotonic counter so a consumer can order events without trusting the
228
+ * clock; `runId` is fresh for every `execute()` call.
229
+ */
230
+ interface RuntimeEventBase {
231
+ runId: string;
232
+ agentId: string;
233
+ seq: number;
234
+ }
235
+ /**
236
+ * The structured stream a runtime produces while an agent runs.
237
+ *
238
+ * This is deliberately wider than any single adapter implements: a runtime only
239
+ * emits the variants it can actually produce, and `RuntimeInfo.capabilities`
240
+ * tells the caller which those are. `raw` is the escape hatch for vendor output
241
+ * we recognise the shape of but have not modelled yet — it must never be the
242
+ * reason a run fails.
243
+ */
244
+ type RuntimeEvent = (RuntimeEventBase & {
245
+ type: "run_started";
246
+ model?: string;
247
+ }) | (RuntimeEventBase & {
248
+ type: "message_delta";
249
+ role: "agent" | "thought" | "user";
250
+ text: string;
251
+ }) | (RuntimeEventBase & {
252
+ type: "message";
253
+ role: "agent" | "thought" | "user";
254
+ text: string;
255
+ }) | (RuntimeEventBase & {
256
+ type: "tool_call";
257
+ id: string;
258
+ name: string;
259
+ input: unknown;
260
+ }) | (RuntimeEventBase & {
261
+ type: "tool_result";
262
+ id: string;
263
+ output: string;
264
+ isError: boolean;
265
+ }) | (RuntimeEventBase & {
266
+ type: "plan";
267
+ entries: string[];
268
+ }) | (RuntimeEventBase & {
269
+ type: "usage";
270
+ inputTokens?: number;
271
+ outputTokens?: number;
272
+ contextTokens?: number;
273
+ contextSize?: number;
274
+ }) | (RuntimeEventBase & {
275
+ type: "cost";
276
+ costUsd?: number;
277
+ modelBreakdown?: Record<string, unknown>;
278
+ amount?: number;
279
+ currency?: string;
280
+ }) | (RuntimeEventBase & {
281
+ type: "raw";
282
+ vendor: string;
283
+ payload: unknown;
284
+ }) | (RuntimeEventBase & {
285
+ type: "run_finished";
286
+ stopReason: "success" | "max_turns" | "cancelled" | "timeout" | "error";
287
+ }) | (RuntimeEventBase & {
288
+ type: "run_error";
289
+ message: string;
290
+ code?: string;
291
+ });
292
+ /**
293
+ * What a *runtime adapter* implements — not what the upstream binary is capable
294
+ * of. A flag is only `true` when this adapter actually wires the behaviour; an
295
+ * unhonoured `true` would make callers pass options that are silently dropped.
296
+ */
297
+ interface RuntimeCapabilities {
298
+ streaming: boolean;
299
+ sessions: boolean;
300
+ resume: boolean;
301
+ permissions: boolean;
302
+ tools: boolean;
303
+ models: boolean;
304
+ images: boolean;
305
+ usage: boolean;
306
+ cost: boolean;
307
+ sandbox: boolean;
308
+ }
309
+ /** The result of capability negotiation, returned by `AgentRuntime.describe()`. */
310
+ interface RuntimeInfo {
311
+ name: string;
312
+ version?: string;
313
+ available: boolean;
314
+ capabilities: RuntimeCapabilities;
315
+ }
316
+ /** Caller-supplied context for {@link AgentRuntime.describe}. */
317
+ interface RuntimeQuery {
318
+ /** Binary this runtime would launch, when the caller knows it. */
319
+ command?: string;
320
+ }
321
+ interface AgentTask {
322
+ agentId: string;
323
+ systemPrompt: string;
324
+ prompt: string;
325
+ tools: string[];
326
+ workDir: string;
327
+ timeout: number;
328
+ signal?: AbortSignal;
329
+ onEvent?: (event: RuntimeEvent) => void;
330
+ /** Ask the runtime to run under a specific session id, if it supports sessions. */
331
+ sessionId?: string;
332
+ /** How to treat an existing session: continue it in place, or fork a copy. */
333
+ resume?: "continue" | "fork";
334
+ model?: string;
335
+ /**
336
+ * Command to launch, for runtimes that drive an external process (e.g. ACP).
337
+ * Generic — it names a binary, not a protocol — so runtimes that do not spawn
338
+ * anything ignore it.
339
+ */
340
+ command?: string;
341
+ /** Arguments for {@link command}. */
342
+ args?: string[];
343
+ }
344
+ interface AgentOutput {
345
+ output: string;
346
+ exitCode: number;
347
+ sessionId?: string;
348
+ usage?: {
349
+ inputTokens?: number;
350
+ outputTokens?: number;
351
+ contextTokens?: number;
352
+ contextSize?: number;
353
+ };
354
+ costUsd?: number;
355
+ stopReason?: string;
356
+ }
357
+ interface AgentRuntime {
358
+ readonly name: string;
359
+ describe(options?: RuntimeQuery): Promise<RuntimeInfo>;
360
+ execute(task: AgentTask): Promise<AgentOutput>;
361
+ }
362
+
363
+ interface StageInfo {
364
+ stageIndex: number;
365
+ agents: Array<{
366
+ id: string;
367
+ name: string;
368
+ icon?: string;
369
+ model?: string;
370
+ description?: string;
371
+ taskTitle?: string;
372
+ }>;
373
+ }
374
+ type MultiClawEvent = {
375
+ type: "orchestration:start";
376
+ timestamp: string;
377
+ payload: {
378
+ name: string;
379
+ requirement?: string;
380
+ totalAgents: number;
381
+ stages: StageInfo[];
382
+ };
383
+ } | {
384
+ /**
385
+ * The stage list changed after the turn had already started.
386
+ *
387
+ * The leader plans first, so `orchestration:start` necessarily carries the
388
+ * *pre-plan* grouping. Once the architect's task plan is applied the team is
389
+ * regrouped, and consumers that drew the first grouping need to be told —
390
+ * otherwise the console shows a pipeline that never ran.
391
+ */
392
+ type: "orchestration:stages";
393
+ timestamp: string;
394
+ payload: {
395
+ totalAgents: number;
396
+ stages: StageInfo[];
397
+ };
398
+ } | {
399
+ type: "orchestration:complete";
400
+ timestamp: string;
401
+ payload: OrchestratorResult;
402
+ } | {
403
+ type: "orchestration:warning";
404
+ timestamp: string;
405
+ payload: {
406
+ message: string;
407
+ };
408
+ } | {
409
+ type: "stage:start";
410
+ timestamp: string;
411
+ payload: {
412
+ stageIndex: number;
413
+ agentIds: string[];
414
+ };
415
+ } | {
416
+ type: "stage:complete";
417
+ timestamp: string;
418
+ payload: {
419
+ stageIndex: number;
420
+ };
421
+ } | {
422
+ type: "agent:start";
423
+ timestamp: string;
424
+ payload: {
425
+ agentId: string;
426
+ agentName: string;
427
+ icon?: string;
428
+ model?: string;
429
+ taskTitle?: string;
430
+ };
431
+ } | {
432
+ type: "agent:output";
433
+ timestamp: string;
434
+ payload: {
435
+ agentId: string;
436
+ chunk: string;
437
+ };
438
+ } | {
439
+ type: "agent:complete";
440
+ timestamp: string;
441
+ payload: AgentResult;
442
+ } | {
443
+ type: "agent:failed";
444
+ timestamp: string;
445
+ payload: AgentResult;
446
+ } | {
447
+ type: "agent:skipped";
448
+ timestamp: string;
449
+ payload: {
450
+ agentId: string;
451
+ agentName: string;
452
+ icon?: string;
453
+ };
454
+ } | {
455
+ type: "agent:retrying";
456
+ timestamp: string;
457
+ payload: {
458
+ agentId: string;
459
+ agentName: string;
460
+ attempt: number;
461
+ maxAttempts: number;
462
+ error: string;
463
+ };
464
+ };
465
+ type EventListener = (event: MultiClawEvent) => void;
466
+
467
+ declare class EventBus {
468
+ private listeners;
469
+ subscribe(listener: EventListener): () => void;
470
+ emit(event: MultiClawEvent): void;
471
+ clear(): void;
472
+ }
473
+
474
+ declare class Orchestrator {
475
+ private config;
476
+ readonly eventBus: EventBus;
477
+ private contextManager;
478
+ private runner;
479
+ private workDir;
480
+ constructor(config: MultiClawConfig);
481
+ run(options?: {
482
+ signal?: AbortSignal;
483
+ }): Promise<OrchestratorResult>;
484
+ /**
485
+ * Order the agents into stages, degrading to declaration order if the graph is
486
+ * broken.
487
+ *
488
+ * `buildStages` throws on a missing dependency and on a cycle. Letting that
489
+ * escape would reject `run()` before `orchestration:complete` is emitted, so
490
+ * the caller sees an unhandled rejection instead of a structured failure. A
491
+ * bad ordering is not a reason to run nothing.
492
+ */
493
+ private buildStagesOrFallback;
494
+ /**
495
+ * Drop last run's task plan before the architect gets a chance to write one.
496
+ *
497
+ * The console runs every turn against the same workspace, so the plan file
498
+ * survives between turns. If a turn's architect fails to write a new one,
499
+ * `applyTaskPlan` would silently re-apply the previous turn's titles, scopes
500
+ * and dependencies to a completely different requirement.
501
+ */
502
+ private clearStaleTaskPlan;
503
+ /**
504
+ * Decide what this turn is: a pipeline, an answer, or a question.
505
+ *
506
+ * Only the leader can answer that, so without one the configured team is the
507
+ * whole story. With one, its prose output is *not* a failure mode to be papered
508
+ * over by running everybody — a leader that answers a greeting has done its
509
+ * job, and that is what `message` records.
510
+ */
511
+ private resolveTurn;
512
+ /**
513
+ * The configured team, as copies.
514
+ *
515
+ * `applyTaskPlan` writes `taskTitle` / `dependsOn` / `agentScope` onto whatever
516
+ * objects it is handed. The console reuses a single config across turns, so
517
+ * returning the config's own objects would leak turn 1's dependency graph into
518
+ * turn 2 — the exact cross-turn contamination `clearStaleTaskPlan` exists to
519
+ * prevent, but for the in-memory fields rather than the file.
520
+ */
521
+ private configuredAgents;
522
+ /**
523
+ * Narrow the configured team to the ids the leader named.
524
+ *
525
+ * Always a subset: an id that is not in the config is reported and dropped
526
+ * rather than added, so a typo in a prompt cannot conjure an agent that has no
527
+ * definition behind it.
528
+ */
529
+ private selectAgents;
530
+ private runStage;
531
+ private applyTaskPlan;
532
+ /**
533
+ * Close out a turn the leader answered rather than planned.
534
+ *
535
+ * `success: true` on purpose: the user asked something and got an answer. What
536
+ * keeps that from reading as a completed pipeline is `reply`, which the console
537
+ * uses to say "answered" instead of "done".
538
+ */
539
+ private finishWithMessage;
540
+ private warn;
541
+ /**
542
+ * Close out a turn that scheduled no agents.
543
+ *
544
+ * Reported as a failure rather than a no-op: the user asked for work, and the
545
+ * only honest outcome is to say that none was done. Running the whole team
546
+ * instead would contradict the leader's explicit choice.
547
+ */
548
+ private finishEmpty;
549
+ }
550
+
551
+ declare function buildStages(agents: AgentDefinition[]): AgentDefinition[][];
552
+
553
+ /**
554
+ * ACP bridges that multiclaw bundles and resolves from its own `node_modules`
555
+ * rather than requiring the user to install them globally.
556
+ *
557
+ * Key = the binary name used in an agent's `command`; value = the npm package
558
+ * that provides it. `opencode` is deliberately absent: it speaks ACP natively,
559
+ * so it *is* the user's agent and is installed by the user.
560
+ */
561
+ declare const BRIDGE_PACKAGES: Record<string, string>;
562
+ /** True when `command` names an executable file on PATH. */
563
+ declare function resolvesOnPath(command: string): boolean;
564
+ /**
565
+ * Resolve a bundled bridge binary to an absolute path inside multiclaw's
566
+ * installed `node_modules`. Returns null when `command` is not a bridge we
567
+ * bundle (e.g. a user-supplied binary such as `opencode`).
568
+ *
569
+ * This lets multiclaw drive the ACP bridge without it being on the user's PATH:
570
+ * the user only installs their own agent (`claude` / `codex` / `opencode`), and
571
+ * multiclaw supplies the thin bridge in front of it.
572
+ */
573
+ declare function resolveBridgeBinary(command: string): string | null;
574
+ /**
575
+ * Resolve the executable multiclaw should spawn for `command`.
576
+ *
577
+ * Prefers the user's own install on PATH (this is also what the test suite
578
+ * relies on — fake binaries are placed on PATH), and falls back to a bridge
579
+ * multiclaw bundles. Returns null when neither is available.
580
+ */
581
+ declare function resolveExecutable(command: string): string | null;
582
+
583
+ type ProviderId = "claude" | "opencode" | "codex" | "cursor" | (string & {});
584
+ type ModelTier = "strong" | "balanced" | "fast";
585
+ interface ProviderModel {
586
+ id: string;
587
+ label: string;
588
+ tier?: ModelTier;
589
+ /** True when this model is the default for its tier within this provider. */
590
+ defaultForTier?: boolean;
591
+ }
592
+ type ModelSelectionMode = "config-option" | "arg" | "none";
593
+ interface ProviderSpec {
594
+ id: ProviderId;
595
+ label: string;
596
+ /** Binary to spawn. */
597
+ command: string;
598
+ /** Arguments after the binary. */
599
+ args: string[];
600
+ /** Additional binary names that resolve to this provider (for detection). */
601
+ aliases?: string[];
602
+ /**
603
+ * Build the `_meta` payload for a session-defining request.
604
+ * Returns `undefined` when there is nothing to say — the role prompt
605
+ * then falls back to a prompt prefix.
606
+ */
607
+ meta?: (task: AgentTask) => Record<string, unknown> | undefined;
608
+ /** Whether this provider honours a tool allowlist at all. */
609
+ tools: boolean;
610
+ /** How model selection is communicated to the agent. */
611
+ modelSelection: ModelSelectionMode;
612
+ /** Models offered by this provider. */
613
+ models: ProviderModel[];
614
+ /** Fallback when no tier or explicit model is configured. */
615
+ defaultModel: string;
616
+ install: {
617
+ hint: string;
618
+ url?: string;
619
+ };
620
+ /** Auth prerequisite — shown as a hint, not a hard gate (v1). */
621
+ auth: {
622
+ kind: "ambient" | "login" | "api-key" | "none";
623
+ hint: string;
624
+ };
625
+ /**
626
+ * When the binary name is ambiguous (e.g. cursor's `agent`),
627
+ * use `--version` output to confirm identity. Mandatory for generic names.
628
+ */
629
+ confirm?: (versionOutput: string) => boolean;
630
+ }
631
+ declare const PROVIDERS: readonly ProviderSpec[];
632
+ /** Lookup a provider by its id. */
633
+ declare function specForProvider(id: string): ProviderSpec | undefined;
634
+ /**
635
+ * Lookup a provider by the binary name it is launched with.
636
+ * Keys on basename (strips paths and Windows suffixes) so
637
+ * `/opt/bin/claude-agent-acp` and `claude-agent-acp.exe` both hit.
638
+ */
639
+ declare function specForCommand(command: string): ProviderSpec | undefined;
640
+ /** All provider ids known to the catalog. */
641
+ declare function providerIds(): string[];
642
+ /** All commands (primary + aliases) that map to a provider. */
643
+ declare function providerCommands(): string[];
644
+ /** Resolve a tier to a concrete model id for a given provider. */
645
+ declare function tierModel(spec: ProviderSpec, tier: ModelTier): string | undefined;
646
+
647
+ type ProviderStatus = "present" | "missing";
648
+ interface DetectedProvider {
649
+ id: string;
650
+ label: string;
651
+ command: string;
652
+ status: ProviderStatus;
653
+ version?: string;
654
+ note?: string;
655
+ }
656
+ /**
657
+ * Discover which providers are installed on this machine.
658
+ *
659
+ * Availability comes from PATH lookups (fast, no spawn). When
660
+ * `withVersion` is true, ambiguous binary names (e.g. cursor's `agent`)
661
+ * are confirmed via `--version` output.
662
+ */
663
+ declare function detectProviders(opts?: {
664
+ withVersion?: boolean;
665
+ }): Promise<DetectedProvider[]>;
666
+ /** Just the ids of providers that are present. */
667
+ declare function presentProviders(detected: DetectedProvider[]): string[];
668
+
669
+ /** Resolve the provider id for an agent, falling back through config defaults. */
670
+ declare function resolveProvider(agent: AgentDefinition, config: MultiClawConfig): string;
671
+ /** Resolve the launch command for an agent. */
672
+ declare function resolveCommand(agent: AgentDefinition, config: MultiClawConfig): string;
673
+ /**
674
+ * Resolve the launch arguments for an agent.
675
+ *
676
+ * Paired with {@link resolveCommand}: the catalog carries per-provider args
677
+ * (`opencode acp` needs `["acp"]`, the bundled bridges need `[]`), so leaving
678
+ * `args` undefined would let the runtime fall back to its `["acp"]` default and
679
+ * launch e.g. `claude-agent-acp acp`. Returns undefined for a truly custom
680
+ * command so the runtime's default still applies.
681
+ */
682
+ declare function resolveArgs(agent: AgentDefinition, config: MultiClawConfig): string[] | undefined;
683
+ /** Resolve the model id an agent will actually run with. */
684
+ declare function resolveModel(agent: AgentDefinition, config: MultiClawConfig): string | undefined;
685
+ /** Convenience: full resolution in one call. */
686
+ declare function resolveAgentRuntime(agent: AgentDefinition, config: MultiClawConfig): {
687
+ provider: string;
688
+ command: string;
689
+ model: string | undefined;
690
+ spec: ProviderSpec | undefined;
691
+ };
692
+
693
+ declare abstract class RuntimeBase implements AgentRuntime {
694
+ abstract readonly name: string;
695
+ abstract describe(options?: RuntimeQuery): Promise<RuntimeInfo>;
696
+ abstract execute(task: AgentTask): Promise<AgentOutput>;
697
+ }
698
+
699
+ declare class AcpRuntime extends RuntimeBase {
700
+ readonly name = "acp";
701
+ describe(options?: RuntimeQuery): Promise<RuntimeInfo>;
702
+ execute(task: AgentTask): Promise<AgentOutput>;
703
+ }
704
+
705
+ declare class RuntimeRegistry {
706
+ private runtimes;
707
+ constructor();
708
+ register(r: AgentRuntime): void;
709
+ get(name: string): AgentRuntime;
710
+ has(name: string): boolean;
711
+ list(): string[];
712
+ }
713
+ declare const runtimeRegistry: RuntimeRegistry;
714
+
715
+ /** Error name used for cooperative cancellation across the orchestrator. */
716
+ declare const ABORT_ERROR_NAME = "AbortError";
717
+ declare function abortError(message?: string): Error;
718
+ declare function isAbortError(err: unknown): boolean;
719
+
720
+ export { ABORT_ERROR_NAME, AcpRuntime, type AgentDefinition, type AgentOutput, type AgentResult, type AgentRuntime, type AgentStatus, type AgentTask, BRIDGE_PACKAGES, type DetectedProvider, EventBus, type EventListener, type LeaderDecision, type LeaderMessage, type LeaderMode, type ModelSelectionMode, type ModelTier, type MultiClawConfig, type MultiClawEvent, Orchestrator, type OrchestratorResult, PROVIDERS, type ProviderId, type ProviderModel, type ProviderSpec, type ProviderStatus, RuntimeBase, type RuntimeCapabilities, type RuntimeEvent, type RuntimeEventBase, type RuntimeInfo, type RuntimeQuery, type StageInfo, type SubTask, type TaskPlan, type ToolName, type TurnRecord, abortError, agents, buildStages, defineConfig, detectProviders, isAbortError, presentProviders, providerCommands, providerIds, resolveAgentRuntime, resolveArgs, resolveBridgeBinary, resolveCommand, resolveExecutable, resolveModel, resolveProvider, resolvesOnPath, runtimeRegistry, specForCommand, specForProvider, tierModel };