@get-bb/plugin-sdk 0.4.4 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,14 @@ Any mounted plugin component can use
21
21
  same plugin's registered thread-panel actions; it returns false when the
22
22
  current surface has no thread side panel.
23
23
 
24
+ Every panel-open entry point reports the same way: `openThreadPanel` and the
25
+ `openPanel` handed to `threadPanelAction`, `experimental_newThreadPanelAction`,
26
+ and `messageAction` `run` callbacks all return `boolean` — true when the host
27
+ accepted the open, false when it declined (non-JSON `params`, an unavailable
28
+ action id, or a surface with no side panel). A decline is a return value, never
29
+ a thrown error, so a plugin registering several kinds of action can share one
30
+ open routine and branch on the result.
31
+
24
32
  See the
25
33
  [`composer-customization` reference plugin](../../examples/plugins/composer-customization/README.md)
26
34
  for every region in one small app. The deprecated pre-1.0
@@ -17,7 +17,7 @@ interface PluginRpcValidationIssue {
17
17
  path?: PluginRpcIssuePathSegment[];
18
18
  }
19
19
  /** Stable wire error categories for plugin RPC. */
20
- type PluginRpcErrorCode = "invalid_json" | "invalid_input" | "handler_error" | "invalid_output" | "non_json_result" | "unknown_method";
20
+ type PluginRpcErrorCode = "handler_error" | "invalid_input" | "invalid_json" | "invalid_output" | "non_json_result" | "unknown_method";
21
21
  /** Structured RPC failure returned as `{ ok: false, error }`. */
22
22
  interface PluginRpcError {
23
23
  code: PluginRpcErrorCode;
@@ -67,14 +67,14 @@ type PluginRpcCallArgs<Method extends PluginRpcMethodContract> = null extends Pl
67
67
  type PluginRpcResult<Method extends PluginRpcMethodContract> = StandardSchemaV1InferOutput<Method["output"]>;
68
68
 
69
69
  declare const reasoningLevelSchema: z.ZodEnum<{
70
- none: "none";
71
- low: "low";
72
- medium: "medium";
73
70
  high: "high";
74
- xhigh: "xhigh";
75
- ultracode: "ultracode";
71
+ low: "low";
76
72
  max: "max";
73
+ medium: "medium";
74
+ none: "none";
77
75
  ultra: "ultra";
76
+ ultracode: "ultracode";
77
+ xhigh: "xhigh";
78
78
  }>;
79
79
  type ReasoningLevel = z.infer<typeof reasoningLevelSchema>;
80
80
  declare const serviceTierSchema: z.ZodEnum<{
@@ -83,118 +83,118 @@ declare const serviceTierSchema: z.ZodEnum<{
83
83
  }>;
84
84
  type ServiceTier = z.infer<typeof serviceTierSchema>;
85
85
  declare const permissionModeSchema: z.ZodEnum<{
86
- full: "full";
87
- auto: "auto";
88
86
  "accept-edits": "accept-edits";
87
+ auto: "auto";
88
+ full: "full";
89
89
  }>;
90
90
  type PermissionMode = z.infer<typeof permissionModeSchema>;
91
91
  declare const promptInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
92
- visibility: z.ZodOptional<z.ZodEnum<{
93
- "agent-only": "agent-only";
94
- }>>;
95
- type: z.ZodLiteral<"text">;
96
- text: z.ZodString;
97
92
  mentions: z.ZodDefault<z.ZodArray<z.ZodObject<{
98
- start: z.ZodNumber;
99
93
  end: z.ZodNumber;
100
94
  resource: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodDiscriminatedUnion<[z.ZodObject<{
101
95
  kind: z.ZodLiteral<"thread">;
102
- threadId: z.ZodString;
103
- projectId: z.ZodOptional<z.ZodString>;
104
96
  label: z.ZodString;
97
+ projectId: z.ZodOptional<z.ZodString>;
98
+ threadId: z.ZodString;
105
99
  }, z.core.$strip>, z.ZodObject<{
106
100
  kind: z.ZodLiteral<"project">;
107
- projectId: z.ZodString;
108
101
  label: z.ZodString;
102
+ projectId: z.ZodString;
109
103
  }, z.core.$strip>, z.ZodObject<{
110
104
  kind: z.ZodLiteral<"section">;
111
- sectionId: z.ZodString;
112
105
  label: z.ZodString;
106
+ sectionId: z.ZodString;
113
107
  }, z.core.$strip>, z.ZodObject<{
114
- kind: z.ZodLiteral<"path">;
115
- source: z.ZodEnum<{
116
- workspace: "workspace";
117
- "thread-storage": "thread-storage";
118
- }>;
119
108
  entryKind: z.ZodEnum<{
120
- file: "file";
121
109
  directory: "directory";
110
+ file: "file";
122
111
  }>;
123
- path: z.ZodString;
112
+ kind: z.ZodLiteral<"path">;
124
113
  label: z.ZodString;
114
+ path: z.ZodString;
115
+ source: z.ZodEnum<{
116
+ "thread-storage": "thread-storage";
117
+ workspace: "workspace";
118
+ }>;
125
119
  }, z.core.$strip>, z.ZodObject<{
120
+ argumentHint: z.ZodNullable<z.ZodString>;
126
121
  kind: z.ZodLiteral<"command">;
127
- trigger: z.ZodEnum<{
128
- "/": "/";
129
- }>;
122
+ label: z.ZodString;
130
123
  name: z.ZodString;
124
+ origin: z.ZodEnum<{
125
+ builtin: "builtin";
126
+ project: "project";
127
+ user: "user";
128
+ }>;
131
129
  source: z.ZodEnum<{
132
130
  command: "command";
133
131
  skill: "skill";
134
132
  }>;
135
- origin: z.ZodEnum<{
136
- user: "user";
137
- project: "project";
138
- builtin: "builtin";
133
+ trigger: z.ZodEnum<{
134
+ "/": "/";
139
135
  }>;
140
- label: z.ZodString;
141
- argumentHint: z.ZodNullable<z.ZodString>;
142
136
  }, z.core.$strip>, z.ZodObject<{
143
- kind: z.ZodLiteral<"plugin">;
144
- pluginId: z.ZodString;
145
137
  icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
146
138
  itemId: z.ZodString;
139
+ kind: z.ZodLiteral<"plugin">;
147
140
  label: z.ZodString;
141
+ pluginId: z.ZodString;
148
142
  }, z.core.$strip>], "kind">>;
143
+ start: z.ZodNumber;
149
144
  }, z.core.$strip>>>;
150
- }, z.core.$strip>, z.ZodObject<{
145
+ text: z.ZodString;
146
+ type: z.ZodLiteral<"text">;
151
147
  visibility: z.ZodOptional<z.ZodEnum<{
152
148
  "agent-only": "agent-only";
153
149
  }>>;
150
+ }, z.core.$strip>, z.ZodObject<{
154
151
  type: z.ZodLiteral<"image">;
155
152
  url: z.ZodString;
156
- }, z.core.$strip>, z.ZodObject<{
157
153
  visibility: z.ZodOptional<z.ZodEnum<{
158
154
  "agent-only": "agent-only";
159
155
  }>>;
160
- type: z.ZodLiteral<"localImage">;
161
- path: z.ZodString;
162
156
  }, z.core.$strip>, z.ZodObject<{
157
+ path: z.ZodString;
158
+ type: z.ZodLiteral<"localImage">;
163
159
  visibility: z.ZodOptional<z.ZodEnum<{
164
160
  "agent-only": "agent-only";
165
161
  }>>;
166
- type: z.ZodLiteral<"localFile">;
167
- path: z.ZodString;
162
+ }, z.core.$strip>, z.ZodObject<{
163
+ mimeType: z.ZodOptional<z.ZodString>;
168
164
  name: z.ZodOptional<z.ZodString>;
165
+ path: z.ZodString;
169
166
  sizeBytes: z.ZodOptional<z.ZodNumber>;
170
- mimeType: z.ZodOptional<z.ZodString>;
167
+ type: z.ZodLiteral<"localFile">;
168
+ visibility: z.ZodOptional<z.ZodEnum<{
169
+ "agent-only": "agent-only";
170
+ }>>;
171
171
  }, z.core.$strip>], "type">;
172
172
  type PromptInput = z.infer<typeof promptInputSchema>;
173
173
 
174
174
  declare const createThreadEnvironmentArgsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
175
- type: z.ZodLiteral<"reuse">;
176
175
  environmentId: z.ZodString;
176
+ type: z.ZodLiteral<"reuse">;
177
177
  }, z.core.$strip>, z.ZodObject<{
178
- type: z.ZodLiteral<"host">;
179
178
  hostId: z.ZodOptional<z.ZodString>;
179
+ type: z.ZodLiteral<"host">;
180
180
  workspace: z.ZodDiscriminatedUnion<[z.ZodObject<{
181
- type: z.ZodLiteral<"unmanaged">;
182
- path: z.ZodNullable<z.ZodString>;
183
181
  branch: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
184
182
  kind: z.ZodLiteral<"existing">;
185
183
  name: z.ZodString;
186
184
  }, z.core.$strict>, z.ZodObject<{
187
- kind: z.ZodLiteral<"new">;
188
185
  baseBranch: z.ZodString;
186
+ kind: z.ZodLiteral<"new">;
189
187
  }, z.core.$strict>], "kind">>;
188
+ path: z.ZodNullable<z.ZodString>;
189
+ type: z.ZodLiteral<"unmanaged">;
190
190
  }, z.core.$strip>, z.ZodObject<{
191
- type: z.ZodLiteral<"managed-worktree">;
192
191
  baseBranch: z.ZodDiscriminatedUnion<[z.ZodObject<{
193
192
  kind: z.ZodLiteral<"named">;
194
193
  name: z.ZodString;
195
194
  }, z.core.$strip>, z.ZodObject<{
196
195
  kind: z.ZodLiteral<"default">;
197
196
  }, z.core.$strip>], "kind">;
197
+ type: z.ZodLiteral<"managed-worktree">;
198
198
  }, z.core.$strip>, z.ZodObject<{
199
199
  type: z.ZodLiteral<"personal">;
200
200
  }, z.core.$strip>], "type">;
@@ -204,25 +204,25 @@ declare const createThreadEnvironmentArgsSchema: z.ZodDiscriminatedUnion<[z.ZodO
204
204
  type CreateThreadEnvironmentArgs = z.infer<typeof createThreadEnvironmentArgsSchema>;
205
205
 
206
206
  declare const createExecutionInputSourcesSchema: z.ZodObject<{
207
- providerId: z.ZodOptional<z.ZodEnum<{
208
- explicit: "explicit";
209
- "client-preference": "client-preference";
210
- }>>;
211
207
  model: z.ZodOptional<z.ZodEnum<{
212
- explicit: "explicit";
213
208
  "client-preference": "client-preference";
209
+ explicit: "explicit";
214
210
  }>>;
215
- serviceTier: z.ZodOptional<z.ZodEnum<{
211
+ permissionMode: z.ZodOptional<z.ZodEnum<{
212
+ "client-preference": "client-preference";
216
213
  explicit: "explicit";
214
+ }>>;
215
+ providerId: z.ZodOptional<z.ZodEnum<{
217
216
  "client-preference": "client-preference";
217
+ explicit: "explicit";
218
218
  }>>;
219
219
  reasoningLevel: z.ZodOptional<z.ZodEnum<{
220
- explicit: "explicit";
221
220
  "client-preference": "client-preference";
222
- }>>;
223
- permissionMode: z.ZodOptional<z.ZodEnum<{
224
221
  explicit: "explicit";
222
+ }>>;
223
+ serviceTier: z.ZodOptional<z.ZodEnum<{
225
224
  "client-preference": "client-preference";
225
+ explicit: "explicit";
226
226
  }>>;
227
227
  }, z.core.$strict>;
228
228
  type CreateExecutionInputSources = z.infer<typeof createExecutionInputSourcesSchema>;
@@ -337,6 +337,13 @@ interface PluginThreadListProps {
337
337
  * shipping a second search box.
338
338
  */
339
339
  searchQuery: string;
340
+ /**
341
+ * BB's thread list, bound to this sidebar instance. Render it to delegate
342
+ * conditionally without re-entering plugin replacement resolution.
343
+ *
344
+ * @experimental Audit before relying on this as a stable contract.
345
+ */
346
+ experimental_Original: ComponentType;
340
347
  }
341
348
  /**
342
349
  * Props passed to an `experimental_threadHeaderAction` component, rendered in
@@ -365,7 +372,7 @@ interface PluginThreadHeaderActionProps {
365
372
  * are absolute on the thread's host.
366
373
  */
367
374
  interface PluginFileOpenerSource {
368
- kind: "workspace" | "host" | "thread-storage";
375
+ kind: "host" | "thread-storage" | "workspace";
369
376
  threadId: string | null;
370
377
  environmentId: string | null;
371
378
  projectId: string | null;
@@ -374,6 +381,13 @@ interface PluginFileOpenerSource {
374
381
  interface PluginFileOpenerProps {
375
382
  path: string;
376
383
  source: PluginFileOpenerSource;
384
+ /**
385
+ * BB's file preview, bound to this file. Render it to delegate conditionally
386
+ * without re-entering plugin replacement resolution.
387
+ *
388
+ * @experimental Audit before relying on this as a stable contract.
389
+ */
390
+ experimental_Original: ComponentType;
377
391
  }
378
392
  /**
379
393
  * Message context passed to a `messageDirective` component — the assistant
@@ -434,6 +448,25 @@ interface PluginNavPanelRegistration {
434
448
  /** URL segment under `/plugins/<pluginId>/`; letters, digits, `-`, `_`. */
435
449
  path: string;
436
450
  component: ComponentType<PluginNavPanelProps>;
451
+ /**
452
+ * Ordered, non-closable tabs shown in this page's host-owned right panel.
453
+ * BB owns selection and persistence and always includes its native Browser
454
+ * and Terminal tools beside them. Components mount only while their tab is
455
+ * active and the panel is open, and receive the same `subPath` as the page
456
+ * component.
457
+ *
458
+ * Experimental: see docs/api_to_audit.md.
459
+ */
460
+ experimental_fixedTabs?: readonly {
461
+ /** Unique within this nav panel; letters, digits, `-`, `_`. */
462
+ id: string;
463
+ title: string;
464
+ /** Icon hint (BB icon name); unknown names fall back to a generic icon. */
465
+ icon: string;
466
+ component: ComponentType<PluginNavPanelProps>;
467
+ /** `flush` lets the component own padding and scrolling. */
468
+ layout?: "flush" | "padded";
469
+ }[];
437
470
  /**
438
471
  * Optional presentational component rendered at the trailing edge of this
439
472
  * panel's sidebar row. It receives no props so it can own a narrow live
@@ -453,6 +486,22 @@ interface PluginNavPanelRegistration {
453
486
  */
454
487
  headerContent?: ComponentType<PluginNavPanelProps>;
455
488
  }
489
+ /**
490
+ * What a plugin action passes when it asks the host to open one of its panel
491
+ * tabs. Shared by every `openPanel` entry point so a plugin registering more
492
+ * than one kind of action can write a single open routine;
493
+ * `PluginTargetedPanelActionOpenOptions` adds the `actionId` a caller
494
+ * outside a panel action must pass to name the panel it wants.
495
+ */
496
+ interface PluginPanelActionOpenOptions {
497
+ /** Tab label. Default: the action's `title`. */
498
+ title?: string;
499
+ /**
500
+ * Persisted with the tab and handed to the component as its `params` prop.
501
+ * Must be a JSON value; anything else is a declined open.
502
+ */
503
+ params?: JsonValue;
504
+ }
456
505
  /**
457
506
  * Context handed to a `threadPanelAction`'s `run`.
458
507
  *
@@ -470,11 +519,15 @@ interface PluginThreadPanelActionContext {
470
519
  * identical to an already-open tab of this action focuses that tab
471
520
  * (updating its title) instead of duplicating it. May be called more than
472
521
  * once (different params ⇒ multiple tabs) or not at all.
522
+ *
523
+ * Returns true when the host accepted the open; false when it declined —
524
+ * from this launcher, only a `params` that is not a JSON value. The true /
525
+ * false contract is shared with `messageAction`'s `openPanel` and
526
+ * `useBbNavigate().openThreadPanel` (which decline for more reasons) so one
527
+ * open routine can serve every action kind. A decline is never thrown: the
528
+ * host logs it and reports it here.
473
529
  */
474
- openPanel(options?: {
475
- title?: string;
476
- params?: JsonValue;
477
- }): void;
530
+ openPanel(options?: PluginPanelActionOpenOptions): boolean;
478
531
  }
479
532
  interface PluginThreadPanelActionRegistration {
480
533
  /** Unique within the plugin; letters, digits, `-`, `_`. */
@@ -496,7 +549,7 @@ interface PluginThreadPanelActionRegistration {
496
549
  * app-like content that manages its own layout, such as
497
550
  * `ThreadChat`.
498
551
  */
499
- layout?: "padded" | "flush";
552
+ layout?: "flush" | "padded";
500
553
  /**
501
554
  * Runs when the user activates the action: call your RPC methods, show a
502
555
  * toast, and/or open panel tabs via `context.openPanel`. Omitted =
@@ -511,13 +564,10 @@ interface PluginNewThreadPanelActionContext {
511
564
  projectId: string | null;
512
565
  /**
513
566
  * Open a tab in the root New thread screen's side panel rendering this
514
- * action's `component`. The title, params, deduplication, and error
515
- * semantics match `threadPanelAction`.
567
+ * action's `component`. The title, params, deduplication, return value, and
568
+ * error semantics match `threadPanelAction`.
516
569
  */
517
- openPanel(options?: {
518
- title?: string;
519
- params?: JsonValue;
520
- }): void;
570
+ openPanel(options?: PluginPanelActionOpenOptions): boolean;
521
571
  }
522
572
  /** Registration for the root New thread screen's panel Actions list. */
523
573
  interface PluginNewThreadPanelActionRegistration {
@@ -530,7 +580,7 @@ interface PluginNewThreadPanelActionRegistration {
530
580
  /** Rendered inside every panel tab this action opens. */
531
581
  component: ComponentType<PluginNewThreadPanelProps>;
532
582
  /** Host framing; matches `threadPanelAction`. */
533
- layout?: "padded" | "flush";
583
+ layout?: "flush" | "padded";
534
584
  /**
535
585
  * Runs when the user activates the action. Omitted = immediately open a
536
586
  * panel tab with defaults. Errors are contained and logged.
@@ -582,12 +632,12 @@ interface PluginSidebarFooterActionRegistration {
582
632
  * cannot. A thread holding a draft reports whatever it would report without
583
633
  * one.
584
634
  */
585
- type PluginSidebarThreadIndicator = "unread-error" | "waiting-for-input" | "working-draft" | "workflow" | "background-agent" | "background-command" | "plan-mode" | "goal" | "runtime" | "draft" | "unread-success" | "none";
635
+ type PluginSidebarThreadIndicator = "background-agent" | "background-command" | "draft" | "goal" | "none" | "plan-mode" | "runtime" | "unread-error" | "unread-success" | "waiting-for-input" | "workflow" | "working-draft";
586
636
  /**
587
637
  * How a thread's environment presents its workspace: a worktree bb manages,
588
638
  * a worktree the user manages, or anything else (a plain checkout).
589
639
  */
590
- type PluginSidebarWorkspaceKind = "managed-worktree" | "unmanaged-worktree" | "other";
640
+ type PluginSidebarWorkspaceKind = "managed-worktree" | "other" | "unmanaged-worktree";
591
641
  /** Live work counts on a thread. All zero means nothing is running. */
592
642
  interface PluginSidebarThreadActivity {
593
643
  workflows: number;
@@ -661,8 +711,8 @@ interface PluginSidebarPullRequest {
661
711
  number: number;
662
712
  title: string;
663
713
  url: string;
664
- state: "draft" | "open" | "merged" | "closed";
665
- attention: "checks_failed" | "checks_pending" | "changes_requested" | "review_requested" | "conflicts" | "blocked" | "draft" | "ready_to_merge" | "merged" | "closed" | "none";
714
+ state: "closed" | "draft" | "merged" | "open";
715
+ attention: "blocked" | "changes_requested" | "checks_failed" | "checks_pending" | "closed" | "conflicts" | "draft" | "merged" | "none" | "ready_to_merge" | "review_requested";
666
716
  }
667
717
  interface PluginSidebarThreadPullRequestState {
668
718
  /** True while the first lookup for this thread's environment is in flight. */
@@ -682,7 +732,7 @@ interface PluginSidebarProject {
682
732
  isPersonal: boolean;
683
733
  }
684
734
  interface PluginSidebarThreadsState {
685
- status: "loading" | "ready" | "error";
735
+ status: "error" | "loading" | "ready";
686
736
  threads: readonly PluginSidebarThread[];
687
737
  projects: readonly PluginSidebarProject[];
688
738
  }
@@ -794,10 +844,13 @@ interface PluginSidebarThreadSplit {
794
844
  * Replace the sidebar's thread list with a plugin component.
795
845
  *
796
846
  * Unlike every other slot, this one is EXCLUSIVE: two lists cannot share one
797
- * scroll area. The built-in list stays the default; the user picks a provider
798
- * in Settings Appearance, stored per client. A provider that is uninstalled,
799
- * disabled, or crashing falls back to the built-in list rather than leaving
800
- * the user with no sidebar.
847
+ * scroll area. Registering activates the replacement while the plugin is
848
+ * enabled. If multiple plugins register one, the first in deterministic slot
849
+ * order is active by default; removing it reveals the next. The user can pin
850
+ * BB's list or a specific provider under Settings → Appearance. A plugin can
851
+ * also use its own setting and render `experimental_Original` conditionally.
852
+ * An absent or crashing replacement falls back to BB's list rather than
853
+ * leaving the user with no sidebar.
801
854
  *
802
855
  * The plugin gets the scrolling list and nothing else. The New-thread button,
803
856
  * the search field, the plugin nav rows, and the footer stay host-rendered in
@@ -807,20 +860,21 @@ interface PluginSidebarThreadSplit {
807
860
  interface PluginThreadListRegistration {
808
861
  /** Unique within the plugin; letters, digits, `-`, `_`. */
809
862
  id: string;
810
- /** Label in the Settings → Appearance Sidebar picker. */
863
+ /** Label shown in Settings → Appearance and capability details. */
811
864
  title: string;
812
- /** Optional one-line description under the title in that picker. */
865
+ /** Optional one-line description shown with the provider choice. */
813
866
  description?: string;
814
867
  component: ComponentType<PluginThreadListProps>;
815
868
  }
816
869
  /**
817
- * Register this plugin as a viewer/editor for file extensions. The user
818
- * picks (and can set as default) an opener per extension via the file tab's
819
- * "Open with" menu; matching files opened in the panel then render
820
- * `component` in a plugin tab instead of the built-in preview. Applies to
821
- * working-tree, host, and thread-storage files never to git-ref snapshots
822
- * (diff views always use the built-in preview). The built-in preview stays
823
- * one menu click away, and a missing/disabled opener falls back to it.
870
+ * Register this plugin as a viewer/editor for file extensions. By default,
871
+ * matching files render the first applicable opener in deterministic slot
872
+ * order. The user can pin BB's preview or a specific opener per extension
873
+ * under Settings Files. The file tab's "Open with" menu can override that
874
+ * choice for one open. A plugin can also use its own setting and render
875
+ * `experimental_Original` conditionally. Applies to working-tree, host, and
876
+ * thread-storage files never to git-ref snapshots (diff views always use
877
+ * BB's preview).
824
878
  */
825
879
  interface PluginFileOpenerRegistration {
826
880
  /** Unique within the plugin; letters, digits, `-`, `_`. */
@@ -851,16 +905,20 @@ interface PluginMessageDirectiveRegistration {
851
905
  interface ThreadChatMessageReference {
852
906
  id: string;
853
907
  threadId: string;
854
- role: "user" | "assistant";
908
+ role: "assistant" | "user";
855
909
  /** Visible text of the message. */
856
910
  text: string;
857
911
  sourceSeqEnd: number;
858
912
  }
859
- interface PluginMessageActionThreadPanelOptions {
913
+ /**
914
+ * What a caller that is *not* itself a panel action passes to open one — a
915
+ * `messageAction`'s `run`, or any component via `useBbNavigate()`. A panel
916
+ * action opening its own tab is already the target, so it passes the bare
917
+ * {@link PluginPanelActionOpenOptions} instead.
918
+ */
919
+ interface PluginTargetedPanelActionOpenOptions extends PluginPanelActionOpenOptions {
860
920
  /** A `threadPanelAction` id registered by this same plugin. */
861
921
  actionId: string;
862
- title?: string;
863
- params?: JsonValue;
864
922
  }
865
923
  /** Context handed to a `messageAction`'s `run`. */
866
924
  interface PluginMessageActionContext {
@@ -875,11 +933,15 @@ interface PluginMessageActionContext {
875
933
  /**
876
934
  * Open one of this plugin's `threadPanelAction` components in the current
877
935
  * thread's side panel — the registration-callback equivalent of
878
- * `useBbNavigate().openThreadPanel`. Returns true when the host
879
- * accepted (the action id exists and the surface has a panel); false
880
- * otherwise.
936
+ * `useBbNavigate().openThreadPanel`.
937
+ *
938
+ * Returns true when the host accepted the open; false when it declined —
939
+ * `params` was not a JSON value, the action id names no `threadPanelAction`
940
+ * of this plugin, or the surface has no side panel (only the main thread
941
+ * view does; a `ThreadChat` embedded in a plugin panel does not). A decline
942
+ * is never thrown: the host logs it and reports it here.
881
943
  */
882
- openPanel(options: PluginMessageActionThreadPanelOptions): boolean;
944
+ openPanel(options: PluginTargetedPanelActionOpenOptions): boolean;
883
945
  }
884
946
  /**
885
947
  * An action on chat messages: an icon button in the per-message action bar
@@ -900,6 +962,32 @@ interface PluginMessageActionRegistration {
900
962
  */
901
963
  run(context: PluginMessageActionContext): void | Promise<void>;
902
964
  }
965
+ /**
966
+ * Supply the inline React mark bb draws for one agent provider.
967
+ *
968
+ * A manifest `branding.icon` (or a provider's `logoUrl`) is fetched and drawn
969
+ * through `<img>`, a separate document where `currentColor` resolves to black
970
+ * — invisible on dark themes and unreachable from app CSS. A component is
971
+ * rendered inline, so it inherits the app's theme colors and the host's sizing
972
+ * classes. Register a static color logo as a file and a theme-aware mark here.
973
+ *
974
+ * The host passes only `className` (sizing plus the provider's color class);
975
+ * the component must render an inline SVG (or other inline markup) and must
976
+ * not fetch. One registration per provider id per plugin; when two plugins
977
+ * claim the same provider id the host keeps the first by plugin id and warns.
978
+ */
979
+ interface PluginProviderIconRegistration {
980
+ /**
981
+ * The provider this mark is for — the id bb knows the provider by (the
982
+ * provider declaration's id, e.g. `codex` or `acp-cursor`), not the plugin
983
+ * id. Letters, digits, `-`, `_`.
984
+ */
985
+ providerId: string;
986
+ /** Inline, theme-aware mark. Receives the host's sizing/color className. */
987
+ icon: ComponentType<{
988
+ className?: string;
989
+ }>;
990
+ }
903
991
  interface PluginAppSlots {
904
992
  homepageSection(registration: PluginHomepageSectionRegistration): void;
905
993
  settingsSection(registration: PluginSettingsSectionRegistration): void;
@@ -932,6 +1020,13 @@ interface PluginAppSlots {
932
1020
  fileOpener(registration: PluginFileOpenerRegistration): void;
933
1021
  messageDirective(registration: PluginMessageDirectiveRegistration): void;
934
1022
  messageAction(registration: PluginMessageActionRegistration): void;
1023
+ /**
1024
+ * Draw one agent provider's icon with an inline React component instead of
1025
+ * its `<img>`-rendered logo file (see
1026
+ * {@link PluginProviderIconRegistration}). Experimental: see
1027
+ * docs/api_to_audit.md.
1028
+ */
1029
+ experimental_providerIcon(registration: PluginProviderIconRegistration): void;
935
1030
  }
936
1031
  interface PluginAppComposer {
937
1032
  customize(registration: ComposerCustomization): void;
@@ -1010,7 +1105,7 @@ interface PluginSettingsState {
1010
1105
  isLoading: boolean;
1011
1106
  }
1012
1107
  /** State of the app's shared realtime connection to the bb server. */
1013
- type PluginRealtimeConnectionState = "connecting" | "connected" | "reconnecting";
1108
+ type PluginRealtimeConnectionState = "connected" | "connecting" | "reconnecting";
1014
1109
  /** Where `useComposer()` writes. */
1015
1110
  type PluginComposerScope = {
1016
1111
  kind: "thread";
@@ -1043,7 +1138,7 @@ interface ComposerCustomization {
1043
1138
  banners?: readonly {
1044
1139
  id: string;
1045
1140
  /** Host chrome around the banner. Defaults to `"card"`. */
1046
- chrome?: "card" | "bare";
1141
+ chrome?: "bare" | "card";
1047
1142
  component: ComponentType;
1048
1143
  }[];
1049
1144
  plusMenu?: readonly ComposerPlusMenuItem[];
@@ -1066,7 +1161,7 @@ interface ComposerPlusMenuItem {
1066
1161
  /** Reactive read-side of the composer a plugin surface is mounted in. */
1067
1162
  interface ComposerView {
1068
1163
  scope: PluginComposerScope;
1069
- layout: "expanded" | "compact" | "zen";
1164
+ layout: "compact" | "expanded" | "zen";
1070
1165
  draft: {
1071
1166
  text: string;
1072
1167
  isEmpty: boolean;
@@ -1116,7 +1211,7 @@ interface PluginComposerThreadRowStatus {
1116
1211
  * shimmers; terminal `success` and `error` tones are static. Defaults to the
1117
1212
  * neutral tone.
1118
1213
  */
1119
- tone?: "default" | "running" | "success" | "error";
1214
+ tone?: "default" | "error" | "running" | "success";
1120
1215
  }
1121
1216
  /** An @-mention pill bound to one of the calling plugin's mention providers. */
1122
1217
  interface PluginComposerMention {
@@ -1197,7 +1292,7 @@ interface ThreadChatMessageAction {
1197
1292
  * Message roles the action applies to. Omitted = both user and assistant
1198
1293
  * messages.
1199
1294
  */
1200
- roles?: readonly ("user" | "assistant")[];
1295
+ roles?: readonly ("assistant" | "user")[];
1201
1296
  /**
1202
1297
  * Runs when the user activates the action. Errors (sync or async) are
1203
1298
  * contained and logged; they never break the timeline.
@@ -1220,7 +1315,7 @@ interface ThreadChatProps {
1220
1315
  * "compact" is the side-panel presentation; "timeline" renders the
1221
1316
  * transcript without a composer.
1222
1317
  */
1223
- variant?: "full" | "compact" | "timeline";
1318
+ variant?: "compact" | "full" | "timeline";
1224
1319
  /**
1225
1320
  * "contained" (default) fills and scrolls inside a bounded parent;
1226
1321
  * "document" grows with its content and defers scrolling to the page.
@@ -1236,7 +1331,7 @@ interface ThreadChatProps {
1236
1331
  * lower permissions for this thread independently of the thread it was
1237
1332
  * forked from. Ignored by `variant: "timeline"` (no composer).
1238
1333
  */
1239
- permissionPolicy?: "inherit" | "editable";
1334
+ permissionPolicy?: "editable" | "inherit";
1240
1335
  className?: string;
1241
1336
  /** Rendered above the conversation, scrolling with it. */
1242
1337
  leadingContent?: ReactNode;
@@ -1260,6 +1355,13 @@ interface ThreadChatProps {
1260
1355
  * composer props.
1261
1356
  */
1262
1357
  interface NewThreadRequest {
1358
+ /**
1359
+ * The selected project id. Choosing "Don't work in a project" submits BB's
1360
+ * personal-project id (not `null`) together with a `personal` workspace
1361
+ * environment. Forward those fields unchanged to `threads.spawn`; if the
1362
+ * plugin needs project metadata, request it from the plugin backend with
1363
+ * `bb.sdk.projects.list({ includePersonal: true })`.
1364
+ */
1263
1365
  projectId: string;
1264
1366
  providerId: string;
1265
1367
  model: string;
@@ -1287,7 +1389,11 @@ interface NewThreadRequest {
1287
1389
  * exception to the no-host-components rule (§5.5), same additive versioning.
1288
1390
  */
1289
1391
  interface NewThreadComposerProps {
1290
- /** Seeds the project picker. The user can change it. */
1392
+ /**
1393
+ * Seeds the project picker. The user can change it, including choosing
1394
+ * "Don't work in a project"; see {@link NewThreadRequest.projectId} for the
1395
+ * submitted projectless shape.
1396
+ */
1291
1397
  defaultProjectId?: string;
1292
1398
  /**
1293
1399
  * Seeds the provider picker. Like every `default*` prop this is a SEED, not
@@ -1421,11 +1527,7 @@ interface BbNavigate {
1421
1527
  * thread surface. Returns false when the surface has no thread side panel or
1422
1528
  * the action is unavailable.
1423
1529
  */
1424
- openThreadPanel(options: {
1425
- actionId: string;
1426
- title?: string;
1427
- params?: JsonValue;
1428
- }): boolean;
1530
+ openThreadPanel(options: PluginTargetedPanelActionOpenOptions): boolean;
1429
1531
  }
1430
1532
  /**
1431
1533
  * Everything `@get-bb/plugin-sdk/app` resolves to at runtime. The BB app builds
@@ -1516,4 +1618,4 @@ declare const experimental_useSidebarThreadPullRequest: (threadId: string) => Pl
1516
1618
  declare const experimental_useSidebarThreadSplit: (threadId: string) => PluginSidebarThreadSplit;
1517
1619
 
1518
1620
  export { Markdown, ThreadChat, definePluginApp, experimental_NewThreadComposer, experimental_useSidebarThreadActions, experimental_useSidebarThreadPullRequest, experimental_useSidebarThreadSplit, experimental_useSidebarThreads, useBbContext, useBbNavigate, useComposer, useComposerView, useRealtime, useRealtimeConnectionState, useRpc, useSettings };
1519
- export type { BbContext, BbNavigate, ComposerCustomization, ComposerPlusMenuItem, ComposerRichTextSpec, ComposerStructuredDraft, ComposerView, JsonValue, MarkdownProps, NewThreadComposerProps, NewThreadRequest, PluginAppBuilder, PluginAppComposer, PluginAppContentScripts, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginComposerTextEffect, PluginComposerThreadRowStatus, PluginContentScriptContext, PluginContentScriptDisposer, PluginContentScriptRegistration, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginMessageActionContext, PluginMessageActionRegistration, PluginMessageActionThreadPanelOptions, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginNavPanelProps, PluginNavPanelRegistration, PluginNewThreadPanelActionContext, PluginNewThreadPanelActionRegistration, PluginNewThreadPanelProps, PluginPendingInteractionProps, PluginPendingInteractionRegistration, PluginPendingInteractionView, PluginRealtimeConnectionState, PluginRpcCallArgs, PluginRpcClient, PluginRpcContract, PluginRpcError, PluginRpcErrorCode, PluginRpcHandlers, PluginRpcIssuePathSegment, PluginRpcMethodContract, PluginRpcResult, PluginRpcValidationIssue, PluginSdkApp, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsState, PluginSidebarFooterActionContext, PluginSidebarFooterActionProps, PluginSidebarFooterActionRegistration, PluginSidebarProject, PluginSidebarPullRequest, PluginSidebarSplitPane, PluginSidebarThread, PluginSidebarThreadActions, PluginSidebarThreadActivity, PluginSidebarThreadIndicator, PluginSidebarThreadPullRequestState, PluginSidebarThreadSplit, PluginSidebarThreadsState, PluginSidebarWorkspaceKind, PluginThreadHeaderActionProps, PluginThreadHeaderActionRegistration, PluginThreadListProps, PluginThreadListRegistration, PluginThreadPanelActionContext, PluginThreadPanelActionRegistration, PluginThreadPanelProps, StandardSchemaV1, StandardSchemaV1InferInput, StandardSchemaV1InferOutput, StandardSchemaV1Issue, StandardSchemaV1Result, ThreadChatMessageAction, ThreadChatMessageReference, ThreadChatProps };
1621
+ export type { BbContext, BbNavigate, ComposerCustomization, ComposerPlusMenuItem, ComposerRichTextSpec, ComposerStructuredDraft, ComposerView, JsonValue, MarkdownProps, NewThreadComposerProps, NewThreadRequest, PluginAppBuilder, PluginAppComposer, PluginAppContentScripts, PluginAppDefinition, PluginAppSetup, PluginAppSlots, PluginComposerApi, PluginComposerMention, PluginComposerScope, PluginComposerTextEffect, PluginComposerThreadRowStatus, PluginContentScriptContext, PluginContentScriptDisposer, PluginContentScriptRegistration, PluginFileOpenerProps, PluginFileOpenerRegistration, PluginFileOpenerSource, PluginHomepageSectionProps, PluginHomepageSectionRegistration, PluginMessageActionContext, PluginMessageActionRegistration, PluginMessageDirectiveMessage, PluginMessageDirectiveOpenWorkspaceFile, PluginMessageDirectiveProps, PluginMessageDirectiveRegistration, PluginNavPanelProps, PluginNavPanelRegistration, PluginNewThreadPanelActionContext, PluginNewThreadPanelActionRegistration, PluginNewThreadPanelProps, PluginPanelActionOpenOptions, PluginPendingInteractionProps, PluginPendingInteractionRegistration, PluginPendingInteractionView, PluginProviderIconRegistration, PluginRealtimeConnectionState, PluginRpcCallArgs, PluginRpcClient, PluginRpcContract, PluginRpcError, PluginRpcErrorCode, PluginRpcHandlers, PluginRpcIssuePathSegment, PluginRpcMethodContract, PluginRpcResult, PluginRpcValidationIssue, PluginSdkApp, PluginSettingsSectionProps, PluginSettingsSectionRegistration, PluginSettingsState, PluginSidebarFooterActionContext, PluginSidebarFooterActionProps, PluginSidebarFooterActionRegistration, PluginSidebarProject, PluginSidebarPullRequest, PluginSidebarSplitPane, PluginSidebarThread, PluginSidebarThreadActions, PluginSidebarThreadActivity, PluginSidebarThreadIndicator, PluginSidebarThreadPullRequestState, PluginSidebarThreadSplit, PluginSidebarThreadsState, PluginSidebarWorkspaceKind, PluginTargetedPanelActionOpenOptions, PluginThreadHeaderActionProps, PluginThreadHeaderActionRegistration, PluginThreadListProps, PluginThreadListRegistration, PluginThreadPanelActionContext, PluginThreadPanelActionRegistration, PluginThreadPanelProps, StandardSchemaV1, StandardSchemaV1InferInput, StandardSchemaV1InferOutput, StandardSchemaV1Issue, StandardSchemaV1Result, ThreadChatMessageAction, ThreadChatMessageReference, ThreadChatProps };