@get-bb/plugin-sdk 0.4.16 → 0.4.17

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.
@@ -467,6 +467,12 @@ interface AcpClassifiedToolCall {
467
467
  item: DeltaItemShape;
468
468
  presentation: DeltaPresentation;
469
469
  }
470
+ interface AcpCommandResult {
471
+ /** The process exit code the agent reported; absent when it reported none. */
472
+ exitCode?: number;
473
+ /** The command's output text; absent when the agent reported none. */
474
+ output?: string;
475
+ }
470
476
 
471
477
  /**
472
478
  * Per-agent dialects: the vendor side channels of an ACP agent.
@@ -525,6 +531,17 @@ interface AcpDialect {
525
531
  * the shared classifier in charge — which is the normal answer.
526
532
  */
527
533
  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
+ 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
+ normalizeCommandEvent?(event: AcpToolCallUpdateEvent): AcpToolCallUpdateEvent;
528
545
  /**
529
546
  * A vendor JSON-RPC request the agent sends to the client. A dialect that
530
547
  * answers one returns the JSON-RPC result to reply with (`{}` is a valid
@@ -10233,6 +10233,15 @@ declare const sendMessageRequestSchema: z$1.ZodObject<{
10233
10233
  }>>;
10234
10234
  }, z$1.core.$strip>;
10235
10235
  type SendMessageRequest = z$1.infer<typeof sendMessageRequestSchema>;
10236
+ declare const sendMessageResponseSchema: z$1.ZodObject<{
10237
+ delivery: z$1.ZodEnum<{
10238
+ deferred: "deferred";
10239
+ queued: "queued";
10240
+ sent: "sent";
10241
+ }>;
10242
+ ok: z$1.ZodLiteral<true>;
10243
+ }, z$1.core.$strip>;
10244
+ type SendMessageResponse = z$1.infer<typeof sendMessageResponseSchema>;
10236
10245
  declare const editMessageRequestSchema: z$1.ZodObject<{
10237
10246
  executionInputSources: z$1.ZodOptional<z$1.ZodObject<{
10238
10247
  model: z$1.ZodOptional<z$1.ZodEnum<{
@@ -15194,9 +15203,7 @@ type ThreadPaneActionResult = ThreadPaneActionResponse;
15194
15203
  type ThreadDeleteResult = {
15195
15204
  ok: true;
15196
15205
  };
15197
- type ThreadSendResult = {
15198
- ok: true;
15199
- };
15206
+ type ThreadSendResult = SendMessageResponse;
15200
15207
  type ThreadEditMessageResult = EditMessageResponse;
15201
15208
  type ThreadStopResult = {
15202
15209
  ok: true;
@@ -3116,7 +3116,7 @@ var deltaItemShapeSchema = z24.discriminatedUnion("type", [
3116
3116
  }),
3117
3117
  z24.object({
3118
3118
  type: z24.literal("fileChange"),
3119
- /** Empty only on bare close-without-open fallbacks (path unknown). */
3119
+ /** Empty while a path is not yet known, including bare close fallbacks. */
3120
3120
  changes: z24.array(deltaFileChangeSchema)
3121
3121
  }),
3122
3122
  /**
@@ -5235,13 +5235,126 @@ var CURSOR_ACP_DIALECT = {
5235
5235
  handleClientRequest: cursorHandleClientRequest,
5236
5236
  maintenance: CURSOR_ACP_MAINTENANCE
5237
5237
  };
5238
+ var ompBashRawInputSchema = z35.object({
5239
+ command: z35.string(),
5240
+ async: z35.boolean().optional()
5241
+ }).passthrough();
5242
+ var ompBashRawOutputSchema = z35.object({
5243
+ content: z35.array(
5244
+ z35.object({
5245
+ type: z35.literal("text"),
5246
+ text: z35.string()
5247
+ }).passthrough()
5248
+ ),
5249
+ details: z35.object({
5250
+ exitCode: z35.number().int().optional(),
5251
+ wallTimeMs: z35.number().nonnegative().optional(),
5252
+ timedOut: z35.boolean().optional(),
5253
+ signal: z35.unknown().optional(),
5254
+ async: z35.unknown().optional()
5255
+ }).passthrough(),
5256
+ // If an OMP version emits generic ACP result fields, the shared parser
5257
+ // owns those exit/output/timeout/signal semantics.
5258
+ exitCode: z35.number().int().nullable().optional(),
5259
+ exit_code: z35.number().int().nullable().optional(),
5260
+ stdout: z35.string().optional(),
5261
+ stderr: z35.string().optional(),
5262
+ output_for_prompt: z35.string().optional(),
5263
+ signal: z35.string().nullable().optional(),
5264
+ timed_out: z35.boolean().optional()
5265
+ }).passthrough();
5266
+ function stripOmpTrailingNotice(text, notice) {
5267
+ const suffix = `
5268
+
5269
+ ${notice}`;
5270
+ return text.endsWith(suffix) ? text.slice(0, -suffix.length) : text;
5271
+ }
5272
+ function ompCommandResult(event) {
5273
+ if (event.kind !== "execute") {
5274
+ return void 0;
5275
+ }
5276
+ const parsedInput = ompBashRawInputSchema.safeParse(event.rawInput);
5277
+ const parsedOutput = ompBashRawOutputSchema.safeParse(event.rawOutput);
5278
+ if (!parsedInput.success || parsedInput.data.command.trim().length === 0 || !parsedOutput.success) {
5279
+ return void 0;
5280
+ }
5281
+ const rawOutput = parsedOutput.data;
5282
+ const details = rawOutput.details;
5283
+ const hasGenericCommandResult = rawOutput.exitCode !== void 0 || rawOutput.exit_code !== void 0 || rawOutput.stdout !== void 0 || rawOutput.stderr !== void 0 || rawOutput.output_for_prompt !== void 0 || rawOutput.signal !== void 0 && rawOutput.signal !== null || rawOutput.timed_out === true;
5284
+ if (parsedInput.data.async === true || details.async !== void 0 || hasGenericCommandResult) {
5285
+ return void 0;
5286
+ }
5287
+ if (details.exitCode === void 0 && details.wallTimeMs === void 0) {
5288
+ return void 0;
5289
+ }
5290
+ let output = rawOutput.content.map((block) => block.text).join("\n");
5291
+ if (details.exitCode !== void 0) {
5292
+ output = stripOmpTrailingNotice(
5293
+ output,
5294
+ `Command exited with code ${String(details.exitCode)}`
5295
+ );
5296
+ }
5297
+ if (details.wallTimeMs !== void 0) {
5298
+ output = stripOmpTrailingNotice(
5299
+ output,
5300
+ `Wall time: ${(details.wallTimeMs / 1e3).toFixed(2)} seconds`
5301
+ );
5302
+ }
5303
+ const isCompletedForegroundBash = event.status === "completed" && details.timedOut !== true && (details.signal === void 0 || details.signal === null);
5304
+ const exitCode = details.exitCode ?? (isCompletedForegroundBash ? 0 : void 0);
5305
+ return {
5306
+ ...exitCode === void 0 ? {} : { exitCode },
5307
+ ...output.length === 0 ? {} : { output }
5308
+ };
5309
+ }
5310
+ var OMP_ACP_DIALECT = {
5311
+ id: "omp",
5312
+ commandResult: ompCommandResult
5313
+ };
5314
+ var openCodeCommandRawOutputSchema = z35.object({
5315
+ output: z35.unknown().optional(),
5316
+ metadata: z35.object({
5317
+ exit: z35.number().int().nullable().optional(),
5318
+ output: z35.string().optional()
5319
+ }).passthrough().optional()
5320
+ }).passthrough();
5321
+ function normalizeOpenCodeCommandEvent(event) {
5322
+ const parsed = openCodeCommandRawOutputSchema.safeParse(event.rawOutput);
5323
+ if (!parsed.success) {
5324
+ return event;
5325
+ }
5326
+ const rawOutput = parsed.data;
5327
+ const output = typeof rawOutput.output === "string" ? rawOutput.output : rawOutput.metadata?.output;
5328
+ const hasSharedOutput = rawOutput["stdout"] !== void 0 || rawOutput["stderr"] !== void 0 || rawOutput["output_for_prompt"] !== void 0;
5329
+ const hasSharedExitCode = rawOutput["exitCode"] !== void 0 || rawOutput["exit_code"] !== void 0;
5330
+ const exitCode = rawOutput.metadata?.exit ?? void 0;
5331
+ if ((output === void 0 || hasSharedOutput) && (exitCode === void 0 || hasSharedExitCode)) {
5332
+ return event;
5333
+ }
5334
+ return {
5335
+ ...event,
5336
+ rawOutput: {
5337
+ ...rawOutput,
5338
+ ...output === void 0 || hasSharedOutput ? {} : { stdout: output },
5339
+ ...exitCode === void 0 || hasSharedExitCode ? {} : { exitCode }
5340
+ }
5341
+ };
5342
+ }
5343
+ var OPENCODE_ACP_DIALECT = {
5344
+ id: "opencode",
5345
+ normalizeCommandEvent: normalizeOpenCodeCommandEvent
5346
+ };
5238
5347
  var DIALECTS_BY_ID = /* @__PURE__ */ new Map([
5239
5348
  [CURSOR_ACP_DIALECT.id, CURSOR_ACP_DIALECT],
5240
- [GROK_ACP_DIALECT.id, GROK_ACP_DIALECT]
5349
+ [GROK_ACP_DIALECT.id, GROK_ACP_DIALECT],
5350
+ [OMP_ACP_DIALECT.id, OMP_ACP_DIALECT],
5351
+ [OPENCODE_ACP_DIALECT.id, OPENCODE_ACP_DIALECT]
5241
5352
  ]);
5242
5353
  var DIALECT_IDS_BY_COMMAND = {
5243
5354
  "cursor-agent": CURSOR_ACP_DIALECT.id,
5244
- grok: GROK_ACP_DIALECT.id
5355
+ grok: GROK_ACP_DIALECT.id,
5356
+ omp: OMP_ACP_DIALECT.id,
5357
+ opencode: OPENCODE_ACP_DIALECT.id
5245
5358
  };
5246
5359
  function resolveAcpDialect(launch) {
5247
5360
  if (launch.dialectId !== void 0) {
@@ -5317,9 +5430,6 @@ function classifyAcpToolCall(event, options) {
5317
5430
  }
5318
5431
  }
5319
5432
  const paths = extractAcpToolCallPaths(event, options);
5320
- if (paths.length === 0) {
5321
- return { kind: "generic" };
5322
- }
5323
5433
  const hasDiff = (event.content ?? []).some((entry) => entry.type === "diff");
5324
5434
  if (hasDiff || event.kind === "edit") {
5325
5435
  return { kind: "file_change", changeKind: "update", paths };
@@ -5553,7 +5663,10 @@ function urlFromTitle(title) {
5553
5663
  function looksLikePath(token) {
5554
5664
  return token.startsWith("/") || token.startsWith("~") || token.startsWith(".");
5555
5665
  }
5556
- function fileChangeVerb(changes) {
5666
+ function fileChangeVerb(changes, fallback) {
5667
+ if (changes.length === 0) {
5668
+ return fallback;
5669
+ }
5557
5670
  if (changes.every((change) => change.kind === "add")) {
5558
5671
  return "add";
5559
5672
  }
@@ -5582,11 +5695,11 @@ function buildAcpFileChanges(event, operation, options) {
5582
5695
  const [path5] = operation.paths;
5583
5696
  return path5 === void 0 ? [] : [{ path: path5, kind: operation.changeKind }];
5584
5697
  }
5585
- function fileChangeItem(changes) {
5698
+ function fileChangeItem(changes, fallbackVerb) {
5586
5699
  return {
5587
5700
  item: { type: "fileChange", changes },
5588
5701
  presentation: fileChangePresentation({
5589
- verb: fileChangeVerb(changes),
5702
+ verb: fileChangeVerb(changes, fallbackVerb),
5590
5703
  paths: changes.map((change) => change.path)
5591
5704
  })
5592
5705
  };
@@ -5697,9 +5810,7 @@ function classifyAcpToolCall2(event, injected, options) {
5697
5810
  }
5698
5811
  if (operation.kind === "file_change") {
5699
5812
  const changes = buildAcpFileChanges(event, operation, options);
5700
- if (changes.length > 0) {
5701
- return fileChangeItem(changes);
5702
- }
5813
+ return fileChangeItem(changes, operation.changeKind);
5703
5814
  }
5704
5815
  const title = toOptionalString(event.title);
5705
5816
  switch (event.kind) {
@@ -5920,6 +6031,73 @@ function createAcpDeltaTranslator(options = {}) {
5920
6031
  }
5921
6032
  return classifyAcpToolCall2(event, injected, pathOptions);
5922
6033
  }
6034
+ function withClientFileWrites(event, writes) {
6035
+ if (writes.length === 0) {
6036
+ return event;
6037
+ }
6038
+ const paths = new Set(
6039
+ writes.map((write) => resolveAcpToolCallPath(write.path, pathOptions))
6040
+ );
6041
+ return {
6042
+ ...event,
6043
+ content: [
6044
+ ...(event.content ?? []).filter(
6045
+ (entry) => entry.type !== "diff" || !paths.has(resolveAcpToolCallPath(entry.path, pathOptions))
6046
+ ),
6047
+ ...writes
6048
+ ]
6049
+ };
6050
+ }
6051
+ function mergeFsWriteIntoOpenToolCall(context, write) {
6052
+ const writePath = resolveAcpToolCallPath(write.path, pathOptions);
6053
+ const fileChangeCalls = threadCallEntries(context).flatMap(
6054
+ ([key, open]) => {
6055
+ if (open.openedType !== "fileChange") {
6056
+ return [];
6057
+ }
6058
+ const classified = classifyCall(context, open.event);
6059
+ return classified.item.type === "fileChange" ? [
6060
+ {
6061
+ key,
6062
+ open,
6063
+ paths: classified.item.changes.map((change) => change.path)
6064
+ }
6065
+ ] : [];
6066
+ }
6067
+ );
6068
+ const exactMatches = fileChangeCalls.filter(
6069
+ ({ paths }) => paths.includes(writePath)
6070
+ );
6071
+ const pathPendingMatches = fileChangeCalls.filter(
6072
+ ({ paths }) => paths.length === 0
6073
+ );
6074
+ const matching = exactMatches.length === 1 ? exactMatches[0] : exactMatches.length === 0 && pathPendingMatches.length === 1 ? pathPendingMatches[0] : void 0;
6075
+ if (matching === void 0) {
6076
+ return false;
6077
+ }
6078
+ const previous = matching.open.clientFileWrites?.find(
6079
+ (entry) => resolveAcpToolCallPath(entry.path, pathOptions) === writePath
6080
+ );
6081
+ const oldText = previous === void 0 ? write.oldText : previous.oldText;
6082
+ const diff = {
6083
+ type: "diff",
6084
+ path: write.path,
6085
+ ...oldText === void 0 ? {} : { oldText },
6086
+ newText: write.content
6087
+ };
6088
+ const clientFileWrites = [
6089
+ ...(matching.open.clientFileWrites ?? []).filter(
6090
+ (entry) => resolveAcpToolCallPath(entry.path, pathOptions) !== writePath
6091
+ ),
6092
+ diff
6093
+ ];
6094
+ mergedToolCalls.set(matching.key, {
6095
+ ...matching.open,
6096
+ clientFileWrites,
6097
+ event: withClientFileWrites(matching.open.event, clientFileWrites)
6098
+ });
6099
+ return true;
6100
+ }
5923
6101
  function toRawEvent(rawEvent) {
5924
6102
  const parsed = providerRawEventSchema.safeParse(rawEvent);
5925
6103
  if (parsed.success) {
@@ -6036,7 +6214,8 @@ function createAcpDeltaTranslator(options = {}) {
6036
6214
  };
6037
6215
  }
6038
6216
  function commandCloseFields(event, status) {
6039
- const result = extractAcpCommandResult(event);
6217
+ const normalizedEvent = dialect.normalizeCommandEvent?.(event) ?? event;
6218
+ const result = dialect.commandResult?.(normalizedEvent) ?? extractAcpCommandResult(normalizedEvent);
6040
6219
  const exitCode = result.exitCode ?? (status === "failed" ? 1 : void 0);
6041
6220
  return {
6042
6221
  ...result.output === void 0 ? {} : { aggregatedOutput: result.output, resultText: result.output },
@@ -6155,7 +6334,10 @@ function createAcpDeltaTranslator(options = {}) {
6155
6334
  const event = withDialectIdentity(parsed.data);
6156
6335
  const key = callKey(context, event.toolCallId);
6157
6336
  const open = mergedToolCalls.get(key);
6158
- const merged = mergeAcpToolCallEvents(open?.event, event);
6337
+ const merged = withClientFileWrites(
6338
+ mergeAcpToolCallEvents(open?.event, event),
6339
+ open?.clientFileWrites ?? []
6340
+ );
6159
6341
  if (isTerminalAcpStatus(merged.status)) {
6160
6342
  mergedToolCalls.delete(key);
6161
6343
  return [
@@ -6174,10 +6356,12 @@ function createAcpDeltaTranslator(options = {}) {
6174
6356
  event: merged,
6175
6357
  openedType: open?.openedType ?? mergedType,
6176
6358
  ...open?.permissionTitle === void 0 ? {} : { permissionTitle: open.permissionTitle },
6177
- ...open?.delegation === void 0 ? {} : { delegation: open.delegation }
6359
+ ...open?.delegation === void 0 ? {} : { delegation: open.delegation },
6360
+ ...open?.clientFileWrites === void 0 ? {} : { clientFileWrites: open.clientFileWrites }
6178
6361
  });
6179
6362
  if (event.status === "in_progress" && mergedType === "command" && open?.openedType === "command") {
6180
- const streamed = extractAcpStreamedCommandOutput(event);
6363
+ const normalizedEvent = dialect.normalizeCommandEvent?.(event) ?? event;
6364
+ const streamed = extractAcpStreamedCommandOutput(normalizedEvent);
6181
6365
  return streamed === void 0 ? suppressedUnhandled(rawEvent) : [
6182
6366
  {
6183
6367
  kind: "command.outputSnapshot",
@@ -6354,6 +6538,9 @@ function createAcpDeltaTranslator(options = {}) {
6354
6538
  if (!params.success) {
6355
6539
  return [];
6356
6540
  }
6541
+ if (mergeFsWriteIntoOpenToolCall(context, params.data)) {
6542
+ return [];
6543
+ }
6357
6544
  const rawEvent = {
6358
6545
  jsonrpc: "2.0",
6359
6546
  method: ACP_FS_WRITE_METHOD,
@@ -2246,7 +2246,7 @@ var deltaItemShapeSchema = z14.discriminatedUnion("type", [
2246
2246
  }),
2247
2247
  z14.object({
2248
2248
  type: z14.literal("fileChange"),
2249
- /** Empty only on bare close-without-open fallbacks (path unknown). */
2249
+ /** Empty while a path is not yet known, including bare close fallbacks. */
2250
2250
  changes: z14.array(deltaFileChangeSchema)
2251
2251
  }),
2252
2252
  /**
@@ -4693,7 +4693,7 @@ var deltaItemShapeSchema = z30.discriminatedUnion("type", [
4693
4693
  }),
4694
4694
  z30.object({
4695
4695
  type: z30.literal("fileChange"),
4696
- /** Empty only on bare close-without-open fallbacks (path unknown). */
4696
+ /** Empty while a path is not yet known, including bare close fallbacks. */
4697
4697
  changes: z30.array(deltaFileChangeSchema)
4698
4698
  }),
4699
4699
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@get-bb/plugin-sdk",
3
- "version": "0.4.16",
3
+ "version": "0.4.17",
4
4
  "homepage": "https://github.com/get-bb/bb#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/get-bb/bb/issues"