@get-bb/plugin-sdk 0.5.31 → 0.6.9

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/dist/app.js CHANGED
@@ -90,6 +90,7 @@ var experimental_useFixedTabTarget = runtimeFunction(
90
90
  "experimental_useFixedTabTarget"
91
91
  );
92
92
  var useComposer = runtimeFunction("useComposer");
93
+ var useComposers = runtimeFunction("useComposers");
93
94
  var useComposerView = runtimeFunction("useComposerView");
94
95
  var experimental_useSidebarThreads = runtimeFunction(
95
96
  "experimental_useSidebarThreads"
@@ -171,6 +172,7 @@ export {
171
172
  useBbNavigate,
172
173
  useComposer,
173
174
  useComposerView,
175
+ useComposers,
174
176
  useEnvironmentProviders,
175
177
  useRealtime,
176
178
  useRealtimeConnectionState,
@@ -123,6 +123,30 @@ function parseContributionArray(kind, value, onRejected, parse) {
123
123
  }
124
124
  return parsed;
125
125
  }
126
+ function parseMenuItem(entryKind, value) {
127
+ const entry = value;
128
+ const id = requireSlotId(entryKind, entry?.id);
129
+ const icon = requireOptionalString(entryKind, "icon", entry?.icon);
130
+ const description = requireOptionalString(
131
+ entryKind,
132
+ "description",
133
+ entry?.description
134
+ );
135
+ const disabled = entry?.disabled;
136
+ if (disabled !== void 0 && typeof disabled !== "boolean" && typeof disabled !== "function") {
137
+ throw new Error(
138
+ `${entryKind}: "disabled" must be a boolean or function when set`
139
+ );
140
+ }
141
+ return {
142
+ id,
143
+ label: requireNonEmptyString(entryKind, "label", entry?.label),
144
+ ...icon !== void 0 ? { icon } : {},
145
+ ...description !== void 0 ? { description } : {},
146
+ ...disabled !== void 0 ? { disabled } : {},
147
+ run: requireFunction(entryKind, "run", entry?.run)
148
+ };
149
+ }
126
150
  function parseRegions(kind, registration, onRejected) {
127
151
  const actions = parseContributionArray(`${kind}.actions`, registration.actions, onRejected, (entryKind, value) => {
128
152
  const entry = value;
@@ -150,32 +174,13 @@ function parseRegions(kind, registration, onRejected) {
150
174
  `${kind}.plusMenu`,
151
175
  registration.plusMenu,
152
176
  onRejected,
153
- (entryKind, value) => {
154
- const entry = value;
155
- const id = requireSlotId(entryKind, entry?.id);
156
- const icon = requireOptionalString(entryKind, "icon", entry?.icon);
157
- const description = requireOptionalString(
158
- entryKind,
159
- "description",
160
- entry?.description
161
- );
162
- const disabled = entry?.disabled;
163
- if (disabled !== void 0 && typeof disabled !== "boolean" && typeof disabled !== "function") {
164
- throw new Error(
165
- `${entryKind}: "disabled" must be a boolean or function when set`
166
- );
167
- }
168
- return {
169
- id,
170
- label: requireNonEmptyString(entryKind, "label", entry?.label),
171
- ...icon !== void 0 ? { icon } : {},
172
- ...description !== void 0 ? { description } : {},
173
- ...disabled !== void 0 ? {
174
- disabled
175
- } : {},
176
- run: requireFunction(entryKind, "run", entry?.run)
177
- };
178
- }
177
+ parseMenuItem
178
+ );
179
+ const sendMenu = parseContributionArray(
180
+ `${kind}.sendMenu`,
181
+ registration.sendMenu,
182
+ onRejected,
183
+ parseMenuItem
179
184
  );
180
185
  let richText;
181
186
  if (registration.richText !== void 0) {
@@ -218,6 +223,7 @@ function parseRegions(kind, registration, onRejected) {
218
223
  ...actions !== void 0 ? { actions } : {},
219
224
  ...banners !== void 0 ? { banners } : {},
220
225
  ...plusMenu !== void 0 ? { plusMenu } : {},
226
+ ...sendMenu !== void 0 ? { sendMenu } : {},
221
227
  ...richText !== void 0 ? { richText } : {}
222
228
  };
223
229
  }
@@ -242,7 +248,11 @@ function collectComposerCustomization(registration, seenIds, onRejected) {
242
248
  requireUniqueId(kind, seenIds, id);
243
249
  return {
244
250
  id,
245
- ...scopes !== void 0 ? { scopes: [...scopes] } : {},
251
+ ...scopes !== void 0 ? {
252
+ scopes: scopes.filter(
253
+ (scope) => scope !== "side-chat"
254
+ )
255
+ } : {},
246
256
  ...parseRegions(`${kind}(${id})`, raw ?? {}, onRejected)
247
257
  };
248
258
  } catch (error) {
@@ -0,0 +1,531 @@
1
+ // src/internal/composer-draft-transforms.ts
2
+ function removeComposerMentions(draft, matches) {
3
+ const removed = draft.mentions.filter(matches).sort((a, b) => a.from - b.from);
4
+ if (removed.length === 0) return draft;
5
+ let text = "";
6
+ let cursor = 0;
7
+ for (const mention of removed) {
8
+ text += draft.text.slice(cursor, mention.from);
9
+ cursor = mention.to;
10
+ }
11
+ const removedSet = new Set(removed);
12
+ const mentions = draft.mentions.filter((mention) => !removedSet.has(mention)).map((mention) => {
13
+ const offset = removed.reduce(
14
+ (sum, item) => sum + (item.to <= mention.from ? item.to - item.from : 0),
15
+ 0
16
+ );
17
+ return offset === 0 ? mention : { ...mention, from: mention.from - offset, to: mention.to - offset };
18
+ });
19
+ return { ...draft, text: text + draft.text.slice(cursor), mentions };
20
+ }
21
+ function setComposerText(draft, text) {
22
+ if (text === draft.text) return draft;
23
+ return {
24
+ ...draft,
25
+ text,
26
+ mentions: reconcileComposerMentions(draft.text, text, draft.mentions)
27
+ };
28
+ }
29
+ function reconcileComposerMentions(currentText, nextText, mentions) {
30
+ if (currentText === nextText) return [...mentions];
31
+ let unchangedPrefixLength = 0;
32
+ const maximumPrefixLength = Math.min(currentText.length, nextText.length);
33
+ while (unchangedPrefixLength < maximumPrefixLength && currentText[unchangedPrefixLength] === nextText[unchangedPrefixLength]) {
34
+ unchangedPrefixLength += 1;
35
+ }
36
+ let unchangedSuffixLength = 0;
37
+ while (unchangedSuffixLength < currentText.length - unchangedPrefixLength && unchangedSuffixLength < nextText.length - unchangedPrefixLength && currentText[currentText.length - unchangedSuffixLength - 1] === nextText[nextText.length - unchangedSuffixLength - 1]) {
38
+ unchangedSuffixLength += 1;
39
+ }
40
+ const replacedCurrentEnd = currentText.length - unchangedSuffixLength;
41
+ const replacementDelta = nextText.length - currentText.length;
42
+ return mentions.flatMap((mention) => {
43
+ if (mention.to <= unchangedPrefixLength) return [mention];
44
+ if (mention.from >= replacedCurrentEnd) {
45
+ return [
46
+ {
47
+ ...mention,
48
+ from: mention.from + replacementDelta,
49
+ to: mention.to + replacementDelta
50
+ }
51
+ ];
52
+ }
53
+ return [];
54
+ });
55
+ }
56
+
57
+ // src/internal/composer-draft-actions.ts
58
+ import { z } from "zod";
59
+ var range = {
60
+ from: z.number().int().nonnegative(),
61
+ to: z.number().int().nonnegative(),
62
+ label: z.string()
63
+ };
64
+ var mentionSchema = z.discriminatedUnion("kind", [
65
+ z.object({
66
+ ...range,
67
+ kind: z.literal("thread"),
68
+ threadId: z.string(),
69
+ projectId: z.string().optional()
70
+ }),
71
+ z.object({ ...range, kind: z.literal("project"), projectId: z.string() }),
72
+ z.object({ ...range, kind: z.literal("section"), sectionId: z.string() }),
73
+ z.object({
74
+ ...range,
75
+ kind: z.literal("path"),
76
+ path: z.string(),
77
+ source: z.enum(["workspace", "thread-storage"]),
78
+ entryKind: z.enum(["file", "directory"])
79
+ }),
80
+ z.object({
81
+ ...range,
82
+ kind: z.literal("command"),
83
+ trigger: z.enum(["/", "$"]),
84
+ name: z.string(),
85
+ source: z.enum(["skill", "command"]),
86
+ origin: z.enum(["builtin", "project", "user"]),
87
+ argumentHint: z.string().nullable()
88
+ }),
89
+ z.object({
90
+ ...range,
91
+ kind: z.literal("plugin"),
92
+ pluginId: z.string(),
93
+ provider: z.string().min(1).refine((value) => !value.includes(":")),
94
+ id: z.string(),
95
+ icon: z.string().nullable().optional()
96
+ })
97
+ ]);
98
+ var attachmentsSchema = z.array(
99
+ z.object({
100
+ type: z.enum(["localImage", "localFile"]),
101
+ path: z.string().min(1),
102
+ name: z.string(),
103
+ mimeType: z.string().optional(),
104
+ sizeBytes: z.number().nonnegative()
105
+ })
106
+ );
107
+ var replacementSchema = z.object({
108
+ text: z.string(),
109
+ mentions: z.array(mentionSchema),
110
+ attachments: attachmentsSchema.optional()
111
+ }).superRefine((draft, context) => {
112
+ let end = 0;
113
+ for (const mention of [...draft.mentions].sort((a, b) => a.from - b.from)) {
114
+ if (mention.from < end || mention.to <= mention.from || mention.to > draft.text.length) {
115
+ context.addIssue({
116
+ code: "custom",
117
+ message: "Mention ranges must be non-overlapping and inside the draft text."
118
+ });
119
+ }
120
+ end = mention.to;
121
+ }
122
+ });
123
+ function createComposerDraftActions(target) {
124
+ let cached = null;
125
+ const snapshotOf = (current) => {
126
+ const content = current.getDraft();
127
+ if (cached?.content === content) return cached.snapshot;
128
+ const snapshot = Object.freeze({
129
+ text: content.text,
130
+ mentions: Object.freeze(
131
+ content.mentions.map((mention) => Object.freeze({ ...mention }))
132
+ ),
133
+ attachments: Object.freeze(
134
+ content.attachments.map(
135
+ (attachment) => Object.freeze({ ...attachment })
136
+ )
137
+ )
138
+ });
139
+ cached = { content, snapshot };
140
+ return snapshot;
141
+ };
142
+ const requireAvailable = (current) => {
143
+ if (!current.isAvailable())
144
+ throw new Error("This composer is no longer available.");
145
+ };
146
+ return {
147
+ get draft() {
148
+ return snapshotOf(target());
149
+ },
150
+ replace(next) {
151
+ const current = target();
152
+ requireAvailable(current);
153
+ const snapshot = snapshotOf(current);
154
+ const result = typeof next === "function" ? next(snapshot) : next;
155
+ requireAvailable(current);
156
+ if (result === snapshot) return;
157
+ const parsed = replacementSchema.safeParse(result);
158
+ if (!parsed.success)
159
+ throw new Error(
160
+ "Invalid composer draft: text, mention ranges, or attachments are invalid."
161
+ );
162
+ current.setDraft(parsed.data);
163
+ },
164
+ focus() {
165
+ const current = target();
166
+ requireAvailable(current);
167
+ current.focus();
168
+ }
169
+ };
170
+ }
171
+
172
+ // src/internal/composer-handle.ts
173
+ var UNAVAILABLE_MESSAGE = "This composer is no longer available.";
174
+ var OFF_SCREEN_MESSAGE = "This composer isn't on screen.";
175
+ var OFF_SCREEN_EDITOR_STATE = {
176
+ layout: "expanded",
177
+ isRunning: false,
178
+ isSubmitting: false,
179
+ isSubmittingBlocked: true,
180
+ submittingBlockedReason: OFF_SCREEN_MESSAGE,
181
+ isAttaching: false,
182
+ attachmentError: null
183
+ };
184
+ var warnedAliases = /* @__PURE__ */ new Set();
185
+ function warnDeprecatedComposerMember(oldName, newName) {
186
+ if (warnedAliases.has(oldName)) return;
187
+ warnedAliases.add(oldName);
188
+ console.warn(
189
+ `useComposer().${oldName} is deprecated; use useComposer().${newName}.`
190
+ );
191
+ }
192
+ function appendComposerDraft(current, value, block) {
193
+ const base = block ? current.text.replace(/\s+$/u, "") : current.text;
194
+ const separator = block && base.length > 0 ? "\n\n" : "";
195
+ const offset = base.length + separator.length;
196
+ return {
197
+ text: `${base}${separator}${value.text}`,
198
+ mentions: [
199
+ ...current.mentions.filter((mention) => mention.to <= base.length),
200
+ ...value.mentions.map((mention) => ({
201
+ ...mention,
202
+ from: mention.from + offset,
203
+ to: mention.to + offset
204
+ }))
205
+ ]
206
+ };
207
+ }
208
+ function validProviderId(provider) {
209
+ const trimmed = provider.trim();
210
+ return trimmed.length === 0 || trimmed.includes(":") ? null : trimmed;
211
+ }
212
+ function insertValue(parts, controller) {
213
+ const list = Array.isArray(parts) ? parts : [parts];
214
+ let text = "";
215
+ const mentions = [];
216
+ for (const part of list) {
217
+ if (typeof part === "string") {
218
+ text += part;
219
+ continue;
220
+ }
221
+ let mention;
222
+ if ("kind" in part) {
223
+ mention = part;
224
+ } else {
225
+ const provider = validProviderId(part.provider);
226
+ if (provider === null) {
227
+ throw new Error(`Invalid mention provider id "${part.provider}".`);
228
+ }
229
+ mention = {
230
+ from: 0,
231
+ to: 0,
232
+ label: part.label.trim() || part.id,
233
+ kind: "plugin",
234
+ pluginId: controller.pluginId,
235
+ provider,
236
+ id: part.id,
237
+ icon: null
238
+ };
239
+ }
240
+ const serialized = controller.mentionText(mention);
241
+ mentions.push({
242
+ ...mention,
243
+ from: text.length,
244
+ to: text.length + serialized.length
245
+ });
246
+ text += serialized;
247
+ }
248
+ return { text, mentions };
249
+ }
250
+ function isDraftEmpty(draft, attachmentCount) {
251
+ return draft.text.trim().length === 0 && draft.mentions.length === 0 && attachmentCount === 0;
252
+ }
253
+ var legacyDrafts = /* @__PURE__ */ new WeakMap();
254
+ function withLegacyDraftFields(draft, attachmentCount) {
255
+ const cached = legacyDrafts.get(draft);
256
+ if (cached) return cached;
257
+ const snapshot = { ...draft };
258
+ Object.defineProperties(snapshot, {
259
+ isEmpty: { value: isDraftEmpty(draft, attachmentCount), enumerable: false },
260
+ attachmentCount: { value: attachmentCount, enumerable: false }
261
+ });
262
+ Object.freeze(snapshot);
263
+ legacyDrafts.set(draft, snapshot);
264
+ return snapshot;
265
+ }
266
+ function waitForUploads(target) {
267
+ return new Promise((resolve) => {
268
+ if (!target.getEditorState().isAttaching) {
269
+ resolve();
270
+ return;
271
+ }
272
+ const unsubscribe = target.subscribeEditorState(() => {
273
+ if (target.getEditorState().isAttaching) return;
274
+ unsubscribe();
275
+ resolve();
276
+ });
277
+ });
278
+ }
279
+ function createComposerHandleBinding(key, initial) {
280
+ let controller = initial;
281
+ const target = () => controller.target;
282
+ const editorState = () => target().getEditorState();
283
+ const requireAvailable = () => {
284
+ if (!target().isAvailable()) throw new Error(UNAVAILABLE_MESSAGE);
285
+ };
286
+ const legacyAvailable = (method) => {
287
+ if (target().isAvailable()) return true;
288
+ console.warn(
289
+ `[plugin:${controller.pluginId}] useComposer().${method}: ${UNAVAILABLE_MESSAGE}`
290
+ );
291
+ return false;
292
+ };
293
+ const replaceText = (nextText) => {
294
+ const current = target().getDraft();
295
+ if (nextText === current.text) return;
296
+ target().setDraft(setComposerText(current, nextText));
297
+ };
298
+ const insertMention = (mention) => {
299
+ warnDeprecatedComposerMember("insertMention", "insert");
300
+ const provider = validProviderId(mention.provider);
301
+ if (provider === null) {
302
+ console.warn(
303
+ `[plugin:${controller.pluginId}] useComposer().insertMention: invalid provider id "${mention.provider}"`
304
+ );
305
+ return;
306
+ }
307
+ if (!legacyAvailable("insertMention")) return;
308
+ const label = mention.label.trim() || mention.id;
309
+ const current = target().getDraft();
310
+ const separator = current.text.length === 0 || /\s$/u.test(current.text) ? "" : " ";
311
+ const from = current.text.length + separator.length;
312
+ target().setDraft({
313
+ text: `${current.text}${separator}${label} `,
314
+ mentions: [
315
+ ...current.mentions,
316
+ {
317
+ from,
318
+ to: from + label.length,
319
+ label,
320
+ kind: "plugin",
321
+ pluginId: controller.pluginId,
322
+ provider,
323
+ id: mention.id,
324
+ icon: null
325
+ }
326
+ ]
327
+ });
328
+ target().focus();
329
+ };
330
+ const removeMentionFrom = (mention) => {
331
+ const current = target().getDraft();
332
+ const next = removeComposerMentions(
333
+ current,
334
+ (item) => item.kind === "plugin" && item.pluginId === controller.pluginId && item.provider === mention.provider && item.id === mention.id
335
+ );
336
+ if (next !== current) target().setDraft(next);
337
+ };
338
+ const removeMention = (mention) => {
339
+ warnDeprecatedComposerMember("removeMention", "replace");
340
+ requireAvailable();
341
+ removeMentionFrom(mention);
342
+ };
343
+ const insert = (parts, options = {}) => {
344
+ requireAvailable();
345
+ const value = insertValue(parts, controller);
346
+ const block = options.block === true;
347
+ if ((options.at ?? "cursor") === "cursor") {
348
+ if (!target().insertAtCursor(value, block)) {
349
+ throw new Error(OFF_SCREEN_MESSAGE);
350
+ }
351
+ return;
352
+ }
353
+ target().setDraft(appendComposerDraft(target().getDraft(), value, block));
354
+ };
355
+ const submit = async (options) => {
356
+ requireAvailable();
357
+ const hostSubmit = target().submit;
358
+ if (hostSubmit === void 0) {
359
+ throw new Error("This composer cannot submit programmatically.");
360
+ }
361
+ if (options.sendAt !== void 0 && (!Number.isFinite(options.sendAt) || options.sendAt <= Date.now())) {
362
+ throw new Error("Pick a time in the future.");
363
+ }
364
+ const errorBefore = editorState().attachmentError;
365
+ await waitForUploads(target());
366
+ const state = editorState();
367
+ if (state.attachmentError !== null && state.attachmentError !== errorBefore) {
368
+ throw new Error(state.attachmentError);
369
+ }
370
+ if (state.isSubmittingBlocked) {
371
+ throw new Error(
372
+ state.submittingBlockedReason ?? "This composer can't submit right now."
373
+ );
374
+ }
375
+ await hostSubmit(
376
+ options,
377
+ options.experimental_data === void 0 ? void 0 : { pluginId: controller.pluginId, data: options.experimental_data }
378
+ );
379
+ };
380
+ const setSelection = async (selection) => {
381
+ requireAvailable();
382
+ const hostSetSelection = target().setSelection;
383
+ if (hostSetSelection === void 0) {
384
+ throw new Error("This composer has no pickers to set.");
385
+ }
386
+ return hostSetSelection(selection);
387
+ };
388
+ const submittedListeners = /* @__PURE__ */ new Set();
389
+ let submittedSubscription = null;
390
+ const syncSubmittedSubscription = () => {
391
+ const scope = submittedListeners.size === 0 ? null : JSON.stringify(target().scope);
392
+ if (submittedSubscription?.scope === scope) return;
393
+ submittedSubscription?.unsubscribe();
394
+ submittedSubscription = scope === null ? null : {
395
+ scope,
396
+ unsubscribe: controller.onSubmitted(() => {
397
+ for (const listener of [...submittedListeners]) {
398
+ try {
399
+ listener();
400
+ } catch (error) {
401
+ console.error("Composer submission listener failed", error);
402
+ }
403
+ }
404
+ })
405
+ };
406
+ };
407
+ const onSubmitted = (listener) => {
408
+ const entry = () => listener();
409
+ submittedListeners.add(entry);
410
+ syncSubmittedSubscription();
411
+ return () => {
412
+ submittedListeners.delete(entry);
413
+ syncSubmittedSubscription();
414
+ };
415
+ };
416
+ const draftActions = createComposerDraftActions(target);
417
+ const handle = {
418
+ replace: draftActions.replace,
419
+ get scope() {
420
+ return target().scope;
421
+ },
422
+ get key() {
423
+ return target().key;
424
+ },
425
+ get layout() {
426
+ return editorState().layout;
427
+ },
428
+ get isRunning() {
429
+ return editorState().isRunning;
430
+ },
431
+ get isSubmitting() {
432
+ return editorState().isSubmitting;
433
+ },
434
+ get isSubmittingBlocked() {
435
+ return editorState().isSubmittingBlocked;
436
+ },
437
+ get submittingBlockedReason() {
438
+ return editorState().submittingBlockedReason;
439
+ },
440
+ get isEmpty() {
441
+ return isDraftEmpty(target().getDraft(), target().getAttachmentCount());
442
+ },
443
+ get attachmentCount() {
444
+ return target().getAttachmentCount();
445
+ },
446
+ get text() {
447
+ return target().getDraft().text;
448
+ },
449
+ get draft() {
450
+ return withLegacyDraftFields(
451
+ draftActions.draft,
452
+ target().getAttachmentCount()
453
+ );
454
+ },
455
+ get selection() {
456
+ return target().getSelection();
457
+ },
458
+ setText: (next) => {
459
+ warnDeprecatedComposerMember("setText", "replace");
460
+ if (legacyAvailable("setText")) replaceText(next);
461
+ },
462
+ updateText: (updater) => {
463
+ warnDeprecatedComposerMember("updateText", "replace");
464
+ if (legacyAvailable("updateText")) {
465
+ replaceText(updater(target().getDraft().text));
466
+ }
467
+ },
468
+ clear: () => {
469
+ warnDeprecatedComposerMember("clear", "replace");
470
+ if (legacyAvailable("clear")) replaceText("");
471
+ },
472
+ insert,
473
+ setTextEffect: (effect) => controller.setTextEffect(effect),
474
+ setInputLock: (locked) => controller.setInputLock(locked),
475
+ addQuote: (text) => {
476
+ warnDeprecatedComposerMember("addQuote", "replace");
477
+ if (!legacyAvailable("addQuote")) return;
478
+ target().addQuote(text);
479
+ target().focus();
480
+ },
481
+ insertMention,
482
+ removeMention,
483
+ onSubmitted,
484
+ focus: () => target().focus(),
485
+ submit,
486
+ setSelection,
487
+ experimental_removeMention: (mention) => {
488
+ warnDeprecatedComposerMember("experimental_removeMention", "replace");
489
+ if (!legacyAvailable("experimental_removeMention")) return;
490
+ removeMentionFrom(mention);
491
+ },
492
+ experimental_onSubmitted: (listener) => {
493
+ warnDeprecatedComposerMember("experimental_onSubmitted", "onSubmitted");
494
+ return onSubmitted(listener);
495
+ },
496
+ experimental_submit: (options) => {
497
+ warnDeprecatedComposerMember("experimental_submit", "submit");
498
+ return submit(options);
499
+ },
500
+ experimental_setSelection: (selection) => {
501
+ warnDeprecatedComposerMember("experimental_setSelection", "setSelection");
502
+ return setSelection(selection);
503
+ }
504
+ };
505
+ Object.defineProperties(handle, {
506
+ run: {
507
+ enumerable: false,
508
+ get: () => {
509
+ const state = editorState();
510
+ return { isRunning: state.isRunning, isSubmitting: state.isSubmitting };
511
+ }
512
+ },
513
+ setThreadRowStatus: { enumerable: false, value: () => {
514
+ } }
515
+ });
516
+ return {
517
+ key,
518
+ handle,
519
+ update(next) {
520
+ controller = next;
521
+ syncSubmittedSubscription();
522
+ }
523
+ };
524
+ }
525
+ export {
526
+ OFF_SCREEN_EDITOR_STATE,
527
+ appendComposerDraft,
528
+ createComposerDraftActions,
529
+ createComposerHandleBinding,
530
+ reconcileComposerMentions
531
+ };
@@ -31,7 +31,6 @@ var RESERVED_BB_CLI_COMMANDS = [
31
31
  "guide",
32
32
  "help",
33
33
  "machine",
34
- "manager",
35
34
  "marketplace",
36
35
  "plugin",
37
36
  "project",