@get-bb/plugin-sdk 0.4.24 → 0.4.28
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/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +0 -25
- package/bundled-types/bb-plugin-sdk-provider-bridge-acp.d.ts +0 -200
- package/bundled-types/bb-plugin-sdk-provider-bridge-testing.d.ts +1 -440
- package/bundled-types/bb-plugin-sdk-provider-bridge.d.ts +0 -665
- package/bundled-types/bb-plugin-sdk-testing.d.ts +0 -16
- package/bundled-types/bb-plugin-sdk.d.ts +37 -295
- package/dist/ai-services.js +5 -1
- package/dist/internal/host-policy.js +95 -108
- package/dist/provider-bridge-acp.js +74 -616
- package/dist/provider-bridge-testing.js +177 -580
- package/dist/provider-bridge-worker-entry.mjs +15 -9
- package/dist/provider-bridge.js +64 -558
- package/dist/testing/index.js +133 -114
- package/package.json +1 -1
|
@@ -7,15 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Core `bb` CLI top-level command names (plus commander's built-in help).
|
|
12
|
-
* Core commands win these names; plugin scaffolding rejects them. Maintained
|
|
13
|
-
* by hand and checked against the real Commander program by
|
|
14
|
-
* apps/cli/src/__tests__/plugin-cli-proxy.test.ts.
|
|
15
|
-
*
|
|
16
|
-
* "automation" and "connect" are intentionally absent: builtin plugins own
|
|
17
|
-
* those top-level commands and the CLI proxies them.
|
|
18
|
-
*/
|
|
19
10
|
declare const RESERVED_BB_CLI_COMMANDS: readonly string[];
|
|
20
11
|
|
|
21
12
|
/** Input-form entry: a path, or a path with options. */
|
|
@@ -70,22 +61,6 @@ interface ProviderNativeRootsInputLike {
|
|
|
70
61
|
readonly project?: readonly ProviderNativeRootInput[];
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
/**
|
|
74
|
-
* How completely a provider can clone one of its sessions — the single
|
|
75
|
-
* vocabulary shared by the provider declaration
|
|
76
|
-
* (`bb.providers.register`), the server→daemon
|
|
77
|
-
* `bridgeLaunch`, and the bridge's `initialize` handshake.
|
|
78
|
-
*
|
|
79
|
-
* - `"none"`: sessions cannot be cloned at all.
|
|
80
|
-
* - `"tip"`: only the current end of a session can be cloned (ACP
|
|
81
|
-
* `session/fork`), so thread fork works but edit-past-message rewind
|
|
82
|
-
* cannot.
|
|
83
|
-
* - `"checkpoint"`: a session can be recreated at an earlier point, which is
|
|
84
|
-
* what edit-past-message rewind needs.
|
|
85
|
-
*
|
|
86
|
-
* The values are ordered least to most capable: a declaration is a ceiling
|
|
87
|
-
* the handshake may narrow but never widen.
|
|
88
|
-
*/
|
|
89
64
|
declare const PROVIDER_FORK_VALUES: readonly ["none", "tip", "checkpoint"];
|
|
90
65
|
type ProviderFork = (typeof PROVIDER_FORK_VALUES)[number];
|
|
91
66
|
|
|
@@ -62,20 +62,6 @@ declare const availableModelSchema: z.ZodObject<{
|
|
|
62
62
|
}, z.core.$strip>;
|
|
63
63
|
type AvailableModel = z.infer<typeof availableModelSchema>;
|
|
64
64
|
|
|
65
|
-
/**
|
|
66
|
-
* Declarative presentation a bridge attaches to an item at `item.open` (and
|
|
67
|
-
* re-states on `item.close`, whose item is the full terminal shape). The
|
|
68
|
-
* assembler persists it on the canonical item so the row renders after the
|
|
69
|
-
* plugin is uninstalled or upgraded, and so mobile renders every kind without
|
|
70
|
-
* plugin code. The same schema as the persisted field
|
|
71
|
-
* (`threadEventItemPresentationSchema` in @bb/domain) — one vocabulary, no
|
|
72
|
-
* translation.
|
|
73
|
-
*
|
|
74
|
-
* Optional in grammar v3 while rows persisted before bridges stamped it are
|
|
75
|
-
* upgraded at read time; it becomes required together with the
|
|
76
|
-
* `legacy-tool-item-backfill` migration that stamps those rows and retires
|
|
77
|
-
* that adapter.
|
|
78
|
-
*/
|
|
79
65
|
declare const deltaPresentationSchema: z.ZodObject<{
|
|
80
66
|
detail: z.ZodOptional<z.ZodString>;
|
|
81
67
|
icon: z.ZodObject<{
|
|
@@ -250,30 +236,19 @@ declare const deltaItemShapeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
250
236
|
}, z.core.$strip>], "type">;
|
|
251
237
|
type DeltaItemShape = z.infer<typeof deltaItemShapeSchema>;
|
|
252
238
|
|
|
253
|
-
/** Where this bridge process may keep files, scoped to the owning plugin. */
|
|
254
239
|
interface ProviderBridgeContext {
|
|
255
|
-
/** The plugin that ships this bridge. */
|
|
256
240
|
pluginId: string;
|
|
257
|
-
/** Persistent, per-plugin, survives daemon restarts and plugin updates. */
|
|
258
241
|
dataDir: string;
|
|
259
|
-
/** This process only; removed when it exits. */
|
|
260
242
|
tempDir: string;
|
|
261
243
|
}
|
|
262
244
|
interface ProviderBridgeDefinition {
|
|
263
|
-
/** One decoded stdin line of the Provider Bridge Protocol. */
|
|
264
245
|
handleLine: (line: string) => void;
|
|
265
|
-
/**
|
|
266
|
-
* Called once before the first line is read, with the process's
|
|
267
|
-
* plugin-scoped directories. Omit it when the bridge keeps no files.
|
|
268
|
-
*/
|
|
269
246
|
start?: (context: ProviderBridgeContext) => void;
|
|
270
|
-
/** Stdin closed: the runtime is gone and the bridge must shut down. */
|
|
271
247
|
onClose?: () => void;
|
|
272
248
|
onSigterm?: () => void;
|
|
273
249
|
onSigint?: () => void;
|
|
274
250
|
}
|
|
275
251
|
interface ProviderBridgeEntry extends ProviderBridgeDefinition {
|
|
276
|
-
/** Bumped when the bootstrap↔bridge contract changes incompatibly. */
|
|
277
252
|
experimental_apiVersion: 1;
|
|
278
253
|
}
|
|
279
254
|
|
|
@@ -311,37 +286,19 @@ type ProviderUsageResult = z.infer<typeof providerUsageResultSchema>;
|
|
|
311
286
|
|
|
312
287
|
declare const experimental_providerBridge: ProviderBridgeEntry;
|
|
313
288
|
|
|
314
|
-
/**
|
|
315
|
-
* What an agent's own dialect knows about keeping it healthy: how a user
|
|
316
|
-
* signs in, whether bb can install it, and where its account and usage live.
|
|
317
|
-
* ACP standardizes none of it, so a generic bridge can only report whether
|
|
318
|
-
* the executable exists — everything richer belongs to the agent, and is
|
|
319
|
-
* therefore the dialect's (see `dialect.ts`), never a bb provider id's.
|
|
320
|
-
*/
|
|
321
289
|
interface AcpMaintenanceDialect {
|
|
322
|
-
/** The shell command that signs the user in. */
|
|
323
290
|
loginCommand: string;
|
|
324
|
-
/** How bb installs or updates the agent, when it can. */
|
|
325
291
|
installer(): {
|
|
326
292
|
command: string;
|
|
327
293
|
args: string[];
|
|
328
294
|
displayCommand: string;
|
|
329
295
|
};
|
|
330
|
-
/** The signed-in account, or null when the agent is not signed in. */
|
|
331
296
|
readAccount(): Promise<{
|
|
332
297
|
email: string | null;
|
|
333
298
|
} | null>;
|
|
334
|
-
/** The agent's usage windows, for the usage surfaces. */
|
|
335
299
|
readUsage(): Promise<ProviderUsageResult>;
|
|
336
300
|
}
|
|
337
301
|
|
|
338
|
-
/**
|
|
339
|
-
* Zod schemas for the subset of the Agent Client Protocol (ACP) that BB
|
|
340
|
-
* consumes — https://agentclientprotocol.com. The bridge validates agent
|
|
341
|
-
* traffic with these before forwarding, and the adapter re-validates the
|
|
342
|
-
* `update` payloads it translates into thread events.
|
|
343
|
-
*/
|
|
344
|
-
|
|
345
302
|
declare const acpToolKindSchema: z.ZodEnum<{
|
|
346
303
|
delete: "delete";
|
|
347
304
|
edit: "edit";
|
|
@@ -440,170 +397,53 @@ declare const acpToolCallUpdateEventSchema: z.ZodPipe<z.ZodTransform<unknown, un
|
|
|
440
397
|
}, z.core.$loose>>;
|
|
441
398
|
type AcpToolCallUpdateEvent = z.infer<typeof acpToolCallUpdateEventSchema>;
|
|
442
399
|
|
|
443
|
-
/**
|
|
444
|
-
* ACP tool call → grammar v3 item shape + presentation.
|
|
445
|
-
*
|
|
446
|
-
* An ACP agent describes a tool call with a native kind enum and a human
|
|
447
|
-
* title. The kind maps straight onto the core kinds: `execute` → `command`,
|
|
448
|
-
* `edit`/`delete` → `fileChange`, `read` → `fileRead`, `search` → `search`,
|
|
449
|
-
* `fetch` → `webFetch`, `think` → `reasoning`; everything else — `other`,
|
|
450
|
-
* `move`, an agent that sent no kind — is a generic `tool` whose `tool` slot
|
|
451
|
-
* names the kind. The title is never a tool name: it rides
|
|
452
|
-
* `presentation.title`.
|
|
453
|
-
*
|
|
454
|
-
* A core shape has required fields the agent does not always fill (Cursor's
|
|
455
|
-
* `read` and `fetch` calls carry an empty `rawInput` and no `locations`). A
|
|
456
|
-
* kind whose shape cannot be built honestly stays a generic `tool` that
|
|
457
|
-
* presents as its kind ("Reading file" with the agent's title), so a row is
|
|
458
|
-
* never a `fileRead` without a path or a `webFetch` without a URL.
|
|
459
|
-
*
|
|
460
|
-
* The command / file-change decision is `tool-call-operation.ts`'s, which the
|
|
461
|
-
* permission mapping shares, so an approval row and its timeline item never
|
|
462
|
-
* disagree (#1803).
|
|
463
|
-
*/
|
|
464
|
-
|
|
465
|
-
/** A tool call's item shape plus the presentation that rides its lifecycle. */
|
|
466
400
|
interface AcpClassifiedToolCall {
|
|
467
401
|
item: DeltaItemShape;
|
|
468
402
|
presentation: DeltaPresentation;
|
|
469
403
|
}
|
|
470
404
|
interface AcpCommandResult {
|
|
471
|
-
/** The process exit code the agent reported; absent when it reported none. */
|
|
472
405
|
exitCode?: number;
|
|
473
|
-
/** The command's output text; absent when the agent reported none. */
|
|
474
406
|
output?: string;
|
|
475
407
|
}
|
|
476
408
|
|
|
477
|
-
/**
|
|
478
|
-
* Per-agent dialects: the vendor side channels of an ACP agent.
|
|
479
|
-
*
|
|
480
|
-
* The ACP wire schema (`wire.ts`) parses only the protocol. What an agent
|
|
481
|
-
* puts beside the protocol is a dialect: grok stamps `_meta["x.ai/tool"]` on
|
|
482
|
-
* every tool event, Cursor reports its sub-agents through a vendor JSON-RPC
|
|
483
|
-
* request (`cursor/task`) that the protocol has no place for. A dialect is a
|
|
484
|
-
* small, per-agent module that reads those channels and answers the few
|
|
485
|
-
* questions the shared translator asks. The shared schema never learns a
|
|
486
|
-
* vendor key, and a dialect never changes what a protocol field means.
|
|
487
|
-
*
|
|
488
|
-
* Version 1 of the protocol has no sub-agent concept at all (`session/fork`
|
|
489
|
-
* is unstable and unrelated), so every delegation an ACP agent reports is
|
|
490
|
-
* vendor-specific and belongs here rather than in the classifier.
|
|
491
|
-
*
|
|
492
|
-
* The dialect is selected per session from the agent's launch command. An
|
|
493
|
-
* agent with no dialect of its own gets the generic one, which answers
|
|
494
|
-
* nothing and leaves every decision to the protocol fields.
|
|
495
|
-
*/
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* The programmatic identity of a tool call, when the agent reports one
|
|
499
|
-
* outside the protocol's unstable `name` field: the tool's own name and, for
|
|
500
|
-
* an agent that sends the `kind` late (grok puts it on the first update, a
|
|
501
|
-
* few milliseconds after the `tool_call`), the kind at open, so the opened
|
|
502
|
-
* shape and the closed shape agree.
|
|
503
|
-
*/
|
|
504
409
|
interface AcpToolIdentity {
|
|
505
410
|
name?: string;
|
|
506
411
|
kind?: AcpToolKind;
|
|
507
412
|
}
|
|
508
|
-
/** What a dialect learned about a sub-agent the agent launched. */
|
|
509
413
|
interface AcpDelegationReport {
|
|
510
|
-
/** The tool call the delegation belongs to. */
|
|
511
414
|
toolCallId: string;
|
|
512
|
-
/** The child's provider-native id. */
|
|
513
415
|
childRef: string;
|
|
514
|
-
/** The row headline: what the sub-agent was asked to do. */
|
|
515
416
|
label: string;
|
|
516
|
-
/** A sub-agent type or model the row can name, when the agent says. */
|
|
517
417
|
detail?: string;
|
|
518
418
|
}
|
|
519
419
|
interface AcpDialect {
|
|
520
|
-
/** Stable id, for logs and tests. */
|
|
521
420
|
readonly id: string;
|
|
522
|
-
/**
|
|
523
|
-
* The tool identity a tool_call / tool_call_update carries in the agent's
|
|
524
|
-
* side channel, if any. The translator fills an absent protocol `name` and
|
|
525
|
-
* `kind` from it; a protocol value always wins over the dialect's.
|
|
526
|
-
*/
|
|
527
421
|
toolIdentity?(event: AcpToolCallUpdateEvent): AcpToolIdentity | undefined;
|
|
528
|
-
/**
|
|
529
|
-
* The agent's own classification of a tool call, when its side channel
|
|
530
|
-
* says something the protocol fields cannot. Returning `undefined` leaves
|
|
531
|
-
* the shared classifier in charge — which is the normal answer.
|
|
532
|
-
*/
|
|
533
422
|
classifyToolCall?(event: AcpToolCallUpdateEvent): AcpClassifiedToolCall | undefined;
|
|
534
|
-
/**
|
|
535
|
-
* A command result carried in the agent's non-standard rawOutput shape.
|
|
536
|
-
* Returning `undefined` leaves the shared ACP result parser in charge.
|
|
537
|
-
*/
|
|
538
423
|
commandResult?(event: AcpToolCallUpdateEvent): AcpCommandResult | undefined;
|
|
539
|
-
/**
|
|
540
|
-
* A command event with the agent's non-standard result fields normalized
|
|
541
|
-
* into the shared ACP result shapes. The hook runs only after the call has
|
|
542
|
-
* classified as a command; existing shared result fields must win.
|
|
543
|
-
*/
|
|
544
424
|
normalizeCommandEvent?(event: AcpToolCallUpdateEvent): AcpToolCallUpdateEvent;
|
|
545
|
-
/**
|
|
546
|
-
* A vendor JSON-RPC request the agent sends to the client. A dialect that
|
|
547
|
-
* answers one returns the JSON-RPC result to reply with (`{}` is a valid
|
|
548
|
-
* acknowledgement) and, optionally, what the request reported. A request
|
|
549
|
-
* no dialect claims stays an unsupported method.
|
|
550
|
-
*/
|
|
551
425
|
handleClientRequest?(method: string, params: unknown): AcpClientRequestOutcome | undefined;
|
|
552
|
-
/**
|
|
553
|
-
* How bb keeps this agent healthy: sign-in, installation, account and
|
|
554
|
-
* usage. ACP standardizes none of it, so an agent without one reports only
|
|
555
|
-
* whether its executable exists.
|
|
556
|
-
*/
|
|
557
426
|
maintenance?: AcpMaintenanceDialect;
|
|
558
427
|
}
|
|
559
428
|
interface AcpClientRequestOutcome {
|
|
560
|
-
/** The JSON-RPC result the bridge replies with. */
|
|
561
429
|
result: Record<string, unknown>;
|
|
562
|
-
/** A sub-agent the request reported, if it reported one. */
|
|
563
430
|
delegation?: AcpDelegationReport;
|
|
564
431
|
}
|
|
565
432
|
|
|
566
|
-
/**
|
|
567
|
-
* What one installed ACP agent can actually do (Q21).
|
|
568
|
-
*
|
|
569
|
-
* A provider declaration states its capabilities before any agent has spoken,
|
|
570
|
-
* so bb declared one answer for every ACP agent and got them wrong: the ACP
|
|
571
|
-
* tier offered `session/fork` for five agents, of which the two bb has since
|
|
572
|
-
* read the wire for support none of it. A declaration above what the agent
|
|
573
|
-
* answers is not a missing feature — the bridge refuses the fork only after
|
|
574
|
-
* bb created the fork thread, so the thread dies on start (get-bb/bb#1833).
|
|
575
|
-
*
|
|
576
|
-
* The agent already reports the truth: `initialize` returns
|
|
577
|
-
* `agentCapabilities`. This probe asks it. It runs on the host, because the
|
|
578
|
-
* agent is a host-local executable, and it is deliberately cheap and
|
|
579
|
-
* disposable: spawn, initialize, read the reply, kill. It never starts a
|
|
580
|
-
* session and never prompts.
|
|
581
|
-
*/
|
|
582
|
-
|
|
583
433
|
interface AcpAgentProbeRequest {
|
|
584
434
|
command: string;
|
|
585
435
|
args: readonly string[];
|
|
586
|
-
/** Extra environment the agent's launch spec asks for. */
|
|
587
436
|
env?: Record<string, string>;
|
|
588
|
-
/** Where to run the probe; the agent may refuse to start without one. */
|
|
589
437
|
cwd: string;
|
|
590
438
|
timeoutMs?: number;
|
|
591
439
|
}
|
|
592
|
-
/** What the agent said about itself, or why bb could not ask. */
|
|
593
440
|
type AcpAgentProbe = {
|
|
594
441
|
reachable: true;
|
|
595
|
-
/** The agent implements the unstable `session/fork`. */
|
|
596
442
|
fork: boolean;
|
|
597
443
|
} | {
|
|
598
444
|
reachable: false;
|
|
599
445
|
reason: string;
|
|
600
446
|
};
|
|
601
|
-
/**
|
|
602
|
-
* Ask one agent what it supports. Never throws: an agent that is missing,
|
|
603
|
-
* broken, or too slow is a `reachable: false` answer with the reason, which
|
|
604
|
-
* the caller reports as "bb could not verify this agent" rather than as a
|
|
605
|
-
* capability.
|
|
606
|
-
*/
|
|
607
447
|
declare function probeAcpAgent(request: AcpAgentProbeRequest): Promise<AcpAgentProbe>;
|
|
608
448
|
declare const acpAgentProbeSchema: z.ZodType<AcpAgentProbe>;
|
|
609
449
|
|
|
@@ -717,48 +557,8 @@ declare const acpLaunchSpecSchema: z.ZodObject<{
|
|
|
717
557
|
}, z.core.$strict>;
|
|
718
558
|
type AcpLaunchSpec = z.infer<typeof acpLaunchSpecSchema>;
|
|
719
559
|
|
|
720
|
-
/**
|
|
721
|
-
* Agent CLI model catalog.
|
|
722
|
-
*
|
|
723
|
-
* Cursor's `cursor-agent --list-models` prints one
|
|
724
|
-
* `id - Display Name` line per model,
|
|
725
|
-
* OpenCode's `opencode models` prints one bare id per line, and Grok's
|
|
726
|
-
* `grok models` prints a bulleted list. These ids can encode reasoning effort:
|
|
727
|
-
* `gpt-5.3-codex-low`, bare `gpt-5.3-codex` for medium, `gpt-5.5-extra-high`
|
|
728
|
-
* as an alternate xhigh spelling, with an optional `-fast` service tail after
|
|
729
|
-
* the effort token (`gpt-5.3-codex-low-fast`). This module groups those raw
|
|
730
|
-
* variants into bb model families so the picker offers one clean entry per
|
|
731
|
-
* family with selectable reasoning efforts, and resolves a (family, effort,
|
|
732
|
-
* serviceTier) selection back to the exact raw id at session launch — by table
|
|
733
|
-
* lookup, never string synthesis, because effort spellings vary per family.
|
|
734
|
-
*
|
|
735
|
-
* The `-fast` tail is a service tier, not a separate model: both the normal
|
|
736
|
-
* and fast raw ids for a given effort collapse into one family, and the bb
|
|
737
|
-
* "Fast mode" toggle (serviceTier) selects between them at launch.
|
|
738
|
-
*
|
|
739
|
-
* Cursor's "thinking" marker (appearing as an infix `…-thinking-medium` or a
|
|
740
|
-
* suffix `…-medium-thinking` / `…-thinking`) is folded into the reasoning
|
|
741
|
-
* ladder too: thinking variants keep their effort, and the model's
|
|
742
|
-
* non-thinking variants collapse onto a single "none" (thinking-off) level at
|
|
743
|
-
* the bottom of the ladder. So one "Opus 4.8" entry offers None, Low … Max
|
|
744
|
-
* instead of separate "Opus 4.8" and "Opus 4.8 Thinking" rows. An explicit
|
|
745
|
-
* `-none` effort id (e.g. `gpt-5.5-none`) is the same "none" level.
|
|
746
|
-
*
|
|
747
|
-
* Display names are stripped of noise the picker renders elsewhere or doesn't
|
|
748
|
-
* need — the per-model effort word and "Thinking" marker (reasoning has its
|
|
749
|
-
* own control), the redundant `1M` context tag, the `(NO ZDR)` data-retention
|
|
750
|
-
* marker, and Cursor's own `(default)`/`(current)` annotations.
|
|
751
|
-
*/
|
|
752
|
-
|
|
753
560
|
interface AgentModelCatalog {
|
|
754
561
|
models: AvailableModel[];
|
|
755
|
-
/**
|
|
756
|
-
* Exact raw agent id for the family identified by its default-variant id
|
|
757
|
-
* (`AvailableModel.id`) at the given effort and service tier. Picks the
|
|
758
|
-
* `-fast` id when `serviceTier` is "fast" and the family has one, otherwise
|
|
759
|
-
* the normal id. `reasoningLevel` omitted falls back to the family's default
|
|
760
|
-
* effort. Returns undefined when the family or requested effort is unknown.
|
|
761
|
-
*/
|
|
762
562
|
resolveVariant(args: {
|
|
763
563
|
model: string;
|
|
764
564
|
reasoningLevel?: ReasoningLevel;
|