@get-bb/plugin-sdk 0.4.24 → 0.4.27

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.
@@ -17,26 +17,6 @@ declare const threadEventItemPresentationLabelSchema: z.ZodObject<{
17
17
  pending: z.ZodString;
18
18
  }, z.core.$strip>;
19
19
  type ThreadEventItemPresentationLabel = z.infer<typeof threadEventItemPresentationLabelSchema>;
20
- /**
21
- * The row's leading icon, by name. Two vocabularies share the one field:
22
- *
23
- * - a host glyph (`{ glyph: "FileText" }`), the same names the plugin
24
- * branding and provider declaration icons use;
25
- * - a plugin-declared icon (`{ glyph: "echo-provider/receipt" }`), the
26
- * namespaced form `"<pluginId>/<name>"` that names an entry of the
27
- * plugin's manifest map `bb.branding.experimental_icons`
28
- * (`NAMESPACED_GLYPH_PATTERN` in plugin-icon.ts). The server rejects at
29
- * ingest a namespaced glyph that is not the emitting plugin's own declared
30
- * icon; clients resolve the name against the plugin inventory they hold
31
- * and draw the SVG tinted with `currentColor`.
32
- *
33
- * Both are names, never bytes or paths: the row persists the name and
34
- * follows the plugin's current map at render time. If the plugin is gone or
35
- * the name is unknown when the row renders, the icon is simply not found and
36
- * the per-kind fallback glyph draws instead — accepted, so a persisted row
37
- * never depends on a file that may have moved. The schema stays a plain
38
- * non-blank string on purpose: persisted rows must parse forever.
39
- */
40
20
  declare const threadEventItemPresentationIconSchema: z.ZodObject<{
41
21
  glyph: z.ZodString;
42
22
  }, z.core.$strip>;
@@ -114,15 +94,6 @@ declare const threadEventWebFetchItemSchema: z.ZodObject<{
114
94
  url: z.ZodString;
115
95
  }, z.core.$strip>;
116
96
  type ThreadEventWebFetchItem = z.infer<typeof threadEventWebFetchItemSchema>;
117
- /**
118
- * A file the agent read. The single most common generic tool in the
119
- * production corpus (Claude `Read`: 7,568 calls across 141 threads rendered
120
- * as an opaque `toolCall`), so it earns a core kind: clients show the path,
121
- * the permission matrix treats it as a read, and no tool-name table is
122
- * needed to recognise it. `cmd` carries the native shell form when the
123
- * provider read through a command (`cat`, `sed -n`) rather than a structured
124
- * tool, so the row can still show what actually ran.
125
- */
126
97
  declare const threadEventFileReadItemSchema: z.ZodObject<{
127
98
  cmd: z.ZodOptional<z.ZodString>;
128
99
  id: z.ZodString;
@@ -153,16 +124,6 @@ declare const threadEventFileReadItemSchema: z.ZodObject<{
153
124
  type: z.ZodLiteral<"fileRead">;
154
125
  }, z.core.$strip>;
155
126
  type ThreadEventFileReadItem = z.infer<typeof threadEventFileReadItemSchema>;
156
- /**
157
- * One kind for every exploration tool that is not a file read: grep, glob,
158
- * and directory listing, discriminated by `mode`. Claude `Grep` + `Glob` and
159
- * the shell `rg`/`ls`/`find` commands bridges already classify into
160
- * `command` activity intents all fold into it. `query` is the pattern: text
161
- * or a regex for `content`, a glob for `path`, and an optional filter for
162
- * `list` (empty when the whole directory is listed). `path` is the root the
163
- * search ran under when the provider named one. `cmd` carries the native
164
- * shell form when the provider searched through a command.
165
- */
166
127
  declare const threadEventSearchItemSchema: z.ZodObject<{
167
128
  cmd: z.ZodOptional<z.ZodString>;
168
129
  id: z.ZodString;
@@ -199,22 +160,6 @@ declare const threadEventSearchItemSchema: z.ZodObject<{
199
160
  type: z.ZodLiteral<"search">;
200
161
  }, z.core.$strip>;
201
162
  type ThreadEventSearchItem = z.infer<typeof threadEventSearchItemSchema>;
202
- /**
203
- * The agent delegated work to a child agent. One kind replaces the three
204
- * encodings in the production data — codex `spawnAgent`/`wait` tool calls,
205
- * the Claude `Agent` tool call with nested child turns, and backgrounded
206
- * `local_agent` background tasks — and the `thread/openWork` notification:
207
- * an open delegation IS open work.
208
- *
209
- * `childRef` is the provider-native id of the child (a codex agent id, a
210
- * Claude subagent id, a bb child thread id when the delegation became a bb
211
- * thread); child turns link back through their `parentToolCallId`.
212
- * `background: true` marks a delegation that outlives its spawning turn, in
213
- * which case its progress and terminal state ride the thread-scoped
214
- * `item/delegation/progress` and `item/delegation/completed` events exactly
215
- * as `backgroundTask` does; a foreground delegation settles through the
216
- * ordinary turn-scoped `item/completed`.
217
- */
218
163
  declare const threadEventDelegationItemSchema: z.ZodObject<{
219
164
  background: z.ZodBoolean;
220
165
  childRef: z.ZodString;
@@ -247,14 +192,6 @@ declare const threadEventDelegationItemSchema: z.ZodObject<{
247
192
  type: z.ZodLiteral<"delegation">;
248
193
  }, z.core.$strip>;
249
194
  type ThreadEventDelegationItem = z.infer<typeof threadEventDelegationItemSchema>;
250
- /**
251
- * A structured plan snapshot the agent maintains as an item: codex
252
- * `update_plan` (its `turn/plan/updated` notification reaches 295 threads in
253
- * the production corpus and the UI discards it today) and the Claude
254
- * `TaskCreate`/`TaskUpdate`/`TodoWrite` family. Each snapshot carries the
255
- * full step list; a later snapshot supersedes an earlier one. Distinct from
256
- * the `plan` item, which is the free-text plan-mode document.
257
- */
258
195
  declare const threadEventPlanStepsItemSchema: z.ZodObject<{
259
196
  explanation: z.ZodOptional<z.ZodString>;
260
197
  id: z.ZodString;
@@ -293,14 +230,6 @@ declare const threadEventPlanStepsItemSchema: z.ZodObject<{
293
230
  type: z.ZodLiteral<"planSteps">;
294
231
  }, z.core.$strip>;
295
232
  type ThreadEventPlanStepsItem = z.infer<typeof threadEventPlanStepsItemSchema>;
296
- /**
297
- * A plugin-defined item kind outside the core vocabulary
298
- * (`"<pluginId>/<name>"`, see provider-extension-kind.ts). The payload is
299
- * opaque JSON here; the server validates it against the owning plugin's
300
- * declared schema at ingest. `presentation` is REQUIRED — an
301
- * extension item has no core renderer to fall back on, so the declarative
302
- * base is the only thing every client can show.
303
- */
304
233
  declare const threadEventExtensionItemSchema: z.ZodObject<{
305
234
  id: z.ZodString;
306
235
  kind: z.ZodString & z.ZodType<`${string}/${string}`, string, z.core.$ZodTypeInternals<`${string}/${string}`, string>>;
@@ -331,13 +260,6 @@ declare const threadEventExtensionItemSchema: z.ZodObject<{
331
260
  type: z.ZodLiteral<"extension">;
332
261
  }, z.core.$strip>;
333
262
  type ThreadEventExtensionItem = z.infer<typeof threadEventExtensionItemSchema>;
334
- /**
335
- * A materialized provider background task. Dynamic workflows (taskType
336
- * "local_workflow"), backgrounded shell commands (taskType "local_bash"), and
337
- * backgrounded subagents (taskType "local_agent" / "local_subagent") become
338
- * items. The item id is derived from the provider task id and stays stable
339
- * across the started → progress* → completed lifecycle.
340
- */
341
263
  declare const threadEventBackgroundTaskItemSchema: z.ZodObject<{
342
264
  description: z.ZodString;
343
265
  error: z.ZodOptional<z.ZodString>;
@@ -982,7 +904,6 @@ declare const threadEventItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
982
904
  type: z.ZodLiteral<"extension">;
983
905
  }, z.core.$strip>], "type">;
984
906
  type ThreadEventItem = z.infer<typeof threadEventItemSchema>;
985
- /** All thread events — provider-originated or system-originated. */
986
907
  declare const threadEventSchema: z.ZodPipe<z.ZodUnknown, z.ZodUnion<readonly [z.ZodIntersection<z.ZodDiscriminatedUnion<[z.ZodObject<{
987
908
  threadId: z.ZodString;
988
909
  type: z.ZodLiteral<"thread/started">;
@@ -3394,12 +3315,6 @@ declare const promptInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3394
3315
  }, z.core.$strip>], "type">;
3395
3316
  type PromptInput = z.infer<typeof promptInputSchema>;
3396
3317
 
3397
- /**
3398
- * The inclusive `[min, max]` range of `thread/delta` grammar versions a bridge
3399
- * speaks. Distinct from the JSON-RPC `protocolVersion`: the envelope can stay
3400
- * put while the delta vocabulary grows, and a bridge that speaks both v2 and
3401
- * v3 says so here instead of forcing a daemon bump.
3402
- */
3403
3318
  declare const bridgeGrammarVersionsSchema: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
3404
3319
  type BridgeGrammarVersions = z.infer<typeof bridgeGrammarVersionsSchema>;
3405
3320
 
@@ -4185,15 +4100,6 @@ declare const threadDeltaSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4185
4100
  }, z.core.$strip>], "kind">;
4186
4101
  type ThreadDelta = z.infer<typeof threadDeltaSchema>;
4187
4102
 
4188
- /**
4189
- * The `thread/delta` grammar range this assembler speaks, reported to every
4190
- * bridge in the `initialize` params so the two sides negotiate a version
4191
- * (see `negotiateGrammarVersion` in the protocol). `[3, 3]`: the v2 dialects
4192
- * (`message.*`, `usage.turn`/`usage.exact`) are deleted, so a bridge whose
4193
- * range lacks 3 — including one that predates `grammarVersions` and reads as
4194
- * `[2, 2]` — is refused at the handshake with a legible error instead of
4195
- * connecting to an assembler that would drop its every stream.
4196
- */
4197
4103
  declare const ASSEMBLER_GRAMMAR_VERSIONS: BridgeGrammarVersions;
4198
4104
  interface DiffCumulativeTextArgs {
4199
4105
  nextText: string;
@@ -4205,35 +4111,10 @@ interface DiffCumulativeTextResult {
4205
4111
  reset: boolean;
4206
4112
  }
4207
4113
  interface CreateDeltaAssemblerOptions {
4208
- /** Provider id stamped onto provider/unhandled events. */
4209
4114
  providerId: string;
4210
- /**
4211
- * Entropy prefix for minted turn/item ids. Defaults to fresh per-assembler
4212
- * entropy so ids never collide across assembler (process) restarts; tests
4213
- * inject a fixed prefix for determinism.
4214
- */
4215
4115
  entropyPrefix?: string;
4216
- /**
4217
- * Minimum gap between emitted `item.progress` events per item key
4218
- * (`flush: true` bypasses it; `item.close` always emits). 500ms default —
4219
- * the cadence the claude bridge hand-rolled for background-task snapshots,
4220
- * now the central policy for every provider's progress stream.
4221
- */
4222
4116
  progressThrottleMs?: number;
4223
- /**
4224
- * Coalescing window for streamed-text events (assistant/reasoning/plan
4225
- * deltas and command/fileChange output deltas) per stream. Within the
4226
- * window consecutive deltas concatenate into one emitted event of the same
4227
- * type; the buffer flushes trailing-edge with no timers — on the thread's
4228
- * next traffic once the window elapsed, on stream close, and before ANY
4229
- * non-batchable event for the thread (the ordering barrier: coalescing
4230
- * never reorders text relative to item opens/closes, turn events, errors,
4231
- * or other streams' flushes). The first delta of a fresh stream always
4232
- * emits immediately, keeping time-to-first-token unchanged. 100ms default;
4233
- * 0 disables batching (one event per delta).
4234
- */
4235
4117
  textDeltaFlushMs?: number;
4236
- /** Clock override for tests. */
4237
4118
  now?: () => number;
4238
4119
  }
4239
4120
  interface AssembleDeltasArgs {
@@ -4242,87 +4123,37 @@ interface AssembleDeltasArgs {
4242
4123
  }
4243
4124
  interface DeltaAssembler {
4244
4125
  assemble(args: AssembleDeltasArgs): ThreadEvent[];
4245
- /** bb item id minted for a provider item id (command-plane lookup). */
4246
4126
  getBbItemId(threadId: string, providerItemId: string): string | undefined;
4247
- /** Provider item id behind a bb item id (reverse command-plane lookup). */
4248
4127
  getProviderItemId(threadId: string, bbItemId: string): string | undefined;
4249
- /** bb turn id minted for a vouched provider turn id. */
4250
4128
  getBbTurnId(threadId: string, providerTurnId: string): string | undefined;
4251
- /** Provider turn id behind a bb turn id (steer/interrupt reverse lookup). */
4252
4129
  getProviderTurnId(threadId: string, bbTurnId: string): string | undefined;
4253
4130
  getOpenTurnId(threadId: string): string | undefined;
4254
4131
  }
4255
4132
  declare function createDeltaAssembler(options: CreateDeltaAssemblerOptions): DeltaAssembler;
4256
4133
 
4257
- /**
4258
- * Test-side view of the runtime's delta assembly: bridge tests capture raw
4259
- * JSON-RPC output, and bridges emit `thread/delta` notifications rather than
4260
- * finished `ThreadEvent`s. These helpers run captured notifications through
4261
- * the real delta assembler — the exact translation the bridge protocol
4262
- * adapter performs — so assertions keep working against canonical
4263
- * `ThreadEvent`s.
4264
- */
4265
-
4266
4134
  interface CapturedBridgeNotification {
4267
4135
  method?: string;
4268
4136
  params?: unknown;
4269
4137
  }
4270
4138
  interface BridgeDeltaEventCollector {
4271
4139
  assembler: DeltaAssembler;
4272
- /** Canonical events for one captured notification (empty for non-deltas). */
4273
4140
  assembleMessage(message: CapturedBridgeNotification): ThreadEvent[];
4274
4141
  }
4275
4142
  declare function createBridgeDeltaEventCollector(providerId?: string): BridgeDeltaEventCollector;
4276
- /**
4277
- * All canonical events an ordered capture of bridge notifications assembles
4278
- * to. Builds a fresh assembler per call, so feed it the full capture (not an
4279
- * incremental slice) for deterministic ids.
4280
- */
4281
4143
  declare function assembleCapturedThreadEvents(messages: readonly CapturedBridgeNotification[], providerId?: string): ThreadEvent[];
4282
- /**
4283
- * Removed (SDK 0.4.16): the conformance kit assembles `thread/delta` itself.
4284
- * A transport hands `runBridgeConformance` the raw captured messages
4285
- * (`CapturedBridgeJsonRpcOutput.takeMessages`) and the run names its
4286
- * `providerId`; this stub stays one release so a suite written against the
4287
- * old transport shape fails with the replacement named, not a missing export.
4288
- */
4289
4144
  declare function toConformanceMessages(): never;
4290
4145
 
4291
- /**
4292
- * Transport abstraction the conformance kit drives. Black-box at the message
4293
- * level: lines in, JSON-RPC messages out. Two expected implementations — an
4294
- * in-process bridge (`send` = the bridge's exported line handler,
4295
- * `takeMessages` = the captured output's drain) and a spawned bridge binary
4296
- * (stdin write + stdout readline). The kit never sees which: it assembles
4297
- * the bridge's `thread/delta` notifications itself, through the runtime's
4298
- * real delta assembler, so the transport hands over raw wire messages only.
4299
- */
4300
4146
  interface BridgeConformanceTransport {
4301
- /** Deliver one raw line to the bridge. */
4302
4147
  send(line: string): void;
4303
- /**
4304
- * Every JSON-RPC message the bridge emitted since the last call, in order:
4305
- * responses, notifications (`thread/delta` included) and bridge-initiated
4306
- * requests, as parsed JSON.
4307
- */
4308
4148
  takeMessages(): unknown[];
4309
4149
  close?(): Promise<void> | void;
4310
4150
  }
4311
- /**
4312
- * Retired. The kit once read its canonical events from a notification the
4313
- * transport assembled under this method; it now assembles `thread/delta`
4314
- * itself and reads nothing under this name. Kept because SDK 0.4.x published
4315
- * it from `@get-bb/plugin-sdk/provider-bridge/testing`; removed at the next
4316
- * major version.
4317
- */
4318
4151
  declare const CONFORMANCE_ASSEMBLED_EVENT_METHOD = "conformance/assembledEvent";
4319
4152
  type ConformanceStatus = "fail" | "pass" | "skipped";
4320
4153
  interface ConformanceCheckResult {
4321
- /** Stable rule id, e.g. "rpc/unknown-method". */
4322
4154
  id: string;
4323
4155
  title: string;
4324
4156
  status: ConformanceStatus;
4325
- /** Failure or skip explanation; empty on pass. */
4326
4157
  detail: string;
4327
4158
  }
4328
4159
  interface ConformanceReport {
@@ -4331,119 +4162,35 @@ interface ConformanceReport {
4331
4162
  }
4332
4163
 
4333
4164
  interface ConformanceSessionFixture {
4334
- /** Workspace directory for the session under test. */
4335
4165
  cwd: string;
4336
- /** Prompt expected to elicit at least one assistant-message item. */
4337
4166
  promptInput: PromptInput[];
4338
- /**
4339
- * A prompt this provider accepts and completes locally, without producing
4340
- * any of the activity that opens a bb turn — Claude Code's `/clear` is the
4341
- * canonical example (#1431). Opting in enables
4342
- * `turn/settles-without-activity`.
4343
- *
4344
- * The kit cannot elicit this shape generically: only the bridge knows what
4345
- * its provider handles as zero work. A fixture that omits it produces no
4346
- * result for that rule rather than a skip, so bridges that have not opted in
4347
- * keep a fully green report.
4348
- */
4349
4167
  zeroWorkPromptInput?: PromptInput[];
4350
- /**
4351
- * A prompt that opens a turn and never settles it on its own, so the kit
4352
- * can interrupt it. Opting in enables `session/threads-independent` and
4353
- * `stop/interrupt-settles-before-result` (the kit names the turn to the
4354
- * bridge through its own assembler's reverse map). A fixture that omits it
4355
- * produces no result for those rules.
4356
- */
4357
4168
  interruptiblePromptInput?: PromptInput[];
4358
- /** Execution options for the session; the kit defaults to full mode. */
4359
4169
  options?: Record<string, unknown>;
4360
- /**
4361
- * The plugin's declared icons (`bb.branding.experimental_icons`): its
4362
- * plugin id and the declared names. Opting in enables
4363
- * `presentation/icon-namespaced-declared`, which fails when any item's
4364
- * `presentation.icon.glyph` is a namespaced glyph (`"<pluginId>/<name>"`)
4365
- * that names another plugin or an undeclared name — what the server
4366
- * would refuse at ingest with `provider/unhandled`. A `server: "bb"` tool
4367
- * row is not inspected: its presentation came from the plugin that
4368
- * registered the tool, and the server checks it against that plugin. A
4369
- * fixture that omits `icons` produces no result for the rule, like the
4370
- * other opt-in rules, so a bridge whose plugin declares no icons keeps a
4371
- * fully green report.
4372
- */
4373
4170
  icons?: {
4374
4171
  pluginId: string;
4375
4172
  names: readonly string[];
4376
4173
  };
4377
4174
  }
4378
4175
 
4379
- /**
4380
- * Recorded-traffic conformance.
4381
- *
4382
- * The scripted scenarios in `scenarios.ts` drive a bridge with a fake
4383
- * provider the kit authors wrote. This set drives it with what the provider
4384
- * CLI really emitted: a committed recording (`recordings/<provider>/<cell>`),
4385
- * replayed through the bridge by `testing/parity.ts`, checked with the same
4386
- * grammar rules. A bridge passes when the replay reproduces a complete,
4387
- * schema-valid, grammar-clean session for every recorded cell — so a
4388
- * translation change that only the real dialect exercises fails conformance,
4389
- * not just a golden.
4390
- *
4391
- * Pure over a replay's output, like `checkItemOpensBeforeDelta`: the caller
4392
- * owns the bridge transport and the replay; this module owns the verdicts.
4393
- */
4394
-
4395
- /** The cells every bridge is expected to reproduce (the live-QA matrix core). */
4396
4176
  declare const RECORDED_CONFORMANCE_CELLS: readonly ["turn-tools", "steer", "stop-interrupt", "approval-allow", "approval-deny", "user-question", "resume", "fork"];
4397
4177
  type RecordedConformanceCell = (typeof RECORDED_CONFORMANCE_CELLS)[number];
4398
4178
  interface RecordedCellReplay {
4399
4179
  provider: string;
4400
4180
  cell: string;
4401
- /** Events the replayed bridge output assembled to, in order. */
4402
4181
  events: readonly ThreadEvent[];
4403
- /**
4404
- * Events the recording's own bridge output assembled to: the turn count the
4405
- * replay must reach. A provider that legitimately refused a cell (an ACP
4406
- * agent without `session/fork`) recorded no turns, and the replay must
4407
- * reproduce that rather than invent one.
4408
- */
4409
4182
  recordedEvents: readonly ThreadEvent[];
4410
- /** Requests the harness had to answer for the bridge, or gates that timed out. */
4411
4183
  stalls: readonly string[];
4412
4184
  }
4413
- /**
4414
- * The verdicts for one replayed cell. Rule ids are `recorded/<cell>/<rule>`
4415
- * so a report lists every cell and a regression names the one it broke.
4416
- */
4417
4185
  declare function checkRecordedCellReplay(replay: RecordedCellReplay): ConformanceCheckResult[];
4418
4186
 
4419
4187
  interface RunBridgeConformanceOptions {
4420
4188
  transport: BridgeConformanceTransport;
4421
4189
  session: ConformanceSessionFixture;
4422
- /**
4423
- * The provider id the bridge's plugin registers. The kit assembles the
4424
- * bridge's `thread/delta` stream through the runtime's real delta
4425
- * assembler, and the canonical events it builds carry this id, as the
4426
- * runtime's would.
4427
- */
4428
4190
  providerId: string;
4429
- /** Per-wait timeout. Conformant bridges answer fast; keep this tight. */
4430
4191
  timeoutMs?: number;
4431
4192
  }
4432
- /**
4433
- * Drive one bridge through the conformance scenarios: JSON-RPC hygiene, the
4434
- * initialize handshake, then a shared session lifecycle (start → turn →
4435
- * grammar checks → release stop → resume with its identity → id-uniqueness
4436
- * → fork with its identity when the handshake declares fork → the opt-in
4437
- * rules), released at the end the way the runtime releases a thread it
4438
- * detaches. One transport for the whole run, mirroring a real bridge
4439
- * lifetime.
4440
- *
4441
- * Against a conformant bridge every result passes. Against a bridge that is
4442
- * not yet protocol-pure, the failures ARE the migration work list — run it
4443
- * before migrating and pin the report, then make it shrink.
4444
- */
4445
4193
  declare function runBridgeConformance(options: RunBridgeConformanceOptions): Promise<ConformanceReport>;
4446
- /** Compact single-line-per-rule rendering for test snapshots and logs. */
4447
4194
  declare function formatConformanceReport(report: ConformanceReport): string;
4448
4195
 
4449
4196
  type BridgeJsonRpcId = string | number;
@@ -4465,16 +4212,11 @@ interface BridgeJsonRpcOutputMessage {
4465
4212
  }
4466
4213
  interface CapturedBridgeJsonRpcOutput {
4467
4214
  messages: BridgeJsonRpcOutputMessage[];
4468
- /**
4469
- * Every message since the last call: the conformance transport's drain
4470
- * (`{ send: handleLine, takeMessages: output.takeMessages }`).
4471
- */
4472
4215
  takeMessages(): BridgeJsonRpcOutputMessage[];
4473
4216
  restore(): void;
4474
4217
  }
4475
4218
  interface BridgeJsonRpcTestHarness {
4476
4219
  messages: BridgeJsonRpcOutputMessage[];
4477
- /** Every message since the last call: the conformance transport's drain. */
4478
4220
  takeMessages(): BridgeJsonRpcOutputMessage[];
4479
4221
  flushWork(): Promise<void>;
4480
4222
  hasResponse(id: BridgeJsonRpcId): boolean;
@@ -4482,64 +4224,22 @@ interface BridgeJsonRpcTestHarness {
4482
4224
  sendRequest(id: BridgeJsonRpcId, method: string, params: BridgeJsonRpcObject): void;
4483
4225
  waitForResponse(id: BridgeJsonRpcId): Promise<BridgeJsonRpcOutputMessage>;
4484
4226
  }
4485
- /**
4486
- * Capture everything a bridge writes to stdout as parsed JSON-RPC messages.
4487
- * Patches `process.stdout.write` directly (no test-framework spy), so the
4488
- * kit runs under any runner; `restore()` puts the original writer back.
4489
- */
4490
4227
  declare function captureBridgeJsonRpcOutput(): CapturedBridgeJsonRpcOutput;
4491
4228
  declare function createBridgeJsonRpcTestHarness(handleLine: BridgeJsonRpcLineHandler): BridgeJsonRpcTestHarness;
4492
4229
 
4493
- /**
4494
- * Dual-path calibration support.
4495
- *
4496
- * A calibration replays one scripted provider session through both the legacy
4497
- * adapter and the canonical bridge, then diffs the two ThreadEvent streams.
4498
- * Anything the diff reports is either a deliberate, documented protocol
4499
- * difference (the bridge synthesizes item/started, announces thread/identity,
4500
- * …) or a regression — there is no third category, which is what makes these
4501
- * suites a graduation gate.
4502
- *
4503
- * Ids legitimately differ between the paths: the legacy adapter numbers from
4504
- * its process-lifetime translator ("turn-1", "claude-assistant-2"), while a
4505
- * canonical session mints per-session entropy ("bt3f9a2b1c-1-…") so ids stay
4506
- * unique across resumes (#1224). Normalization interns them by first-seen
4507
- * order instead of matching either scheme, so a stream that *reused* an id
4508
- * still diffs.
4509
- */
4510
4230
  interface NormalizeCalibrationEventsOptions {
4511
- /**
4512
- * Ids the provider itself owns (tool call ids, checkpoints) are identical on
4513
- * both paths and are left alone. Anything reaching the intern table is a
4514
- * translator- or bridge-minted id.
4515
- */
4516
4231
  internedIdFields?: readonly string[];
4517
4232
  }
4518
- /**
4519
- * Normalize one path's stream. Each stream gets its own interner, so the token
4520
- * a given id receives depends only on the order ids first appear — identical
4521
- * across paths when the streams agree, different the moment they do not.
4522
- */
4523
4233
  declare function normalizeCalibrationEvents(events: readonly ThreadEvent[], options?: NormalizeCalibrationEventsOptions): unknown[];
4524
- /** Compact `type` (+ item type) rendering for asserting a known-divergence list. */
4525
4234
  declare function describeCalibrationEvents(events: readonly unknown[]): string[];
4526
4235
 
4527
4236
  declare const BRIDGE_RECORDING_DIRECTIONS: readonly ["runtime→bridge", "bridge→runtime", "provider→bridge", "bridge→provider"];
4528
4237
  type BridgeRecordingDirection = (typeof BRIDGE_RECORDING_DIRECTIONS)[number];
4529
4238
  interface BridgeRecordingEntry {
4530
- /** Wall-clock milliseconds when the line crossed. */
4531
4239
  ts: number;
4532
- /**
4533
- * The recorder's start time, identifying the bridge process that wrote the
4534
- * entry. A thread can span several bridge processes (the runtime restarts a
4535
- * bridge, or releases and later resumes the thread), each appending to the
4536
- * same files with its own `seq`; `(run, seq)` orders entries exactly.
4537
- */
4538
4240
  run: number;
4539
- /** Process-wide monotonic counter across all four lanes. */
4540
4241
  seq: number;
4541
4242
  dir: BridgeRecordingDirection;
4542
- /** The raw line, without its terminator. */
4543
4243
  line: string;
4544
4244
  }
4545
4245
 
@@ -4558,22 +4258,9 @@ interface BridgeRecordingManifest {
4558
4258
  interface BridgeRecording {
4559
4259
  dir: string;
4560
4260
  manifest: BridgeRecordingManifest | null;
4561
- /** Every lane merged back into wire order: by bridge process, then seq. */
4562
4261
  entries: BridgeRecordingEntry[];
4563
4262
  }
4564
- /**
4565
- * The file a bridge change re-records its side of the wire into
4566
- * (`pnpm rerecord`): the `bridge→runtime` lane as THIS checkout's bridge
4567
- * emits it for the recording's provider and runtime lanes. The recorded lane
4568
- * itself is never rewritten — it is the recording, and a pre-migration
4569
- * checkout paces its replay from it — so the current expectation lives
4570
- * beside it. Absent until a bridge change first needs one.
4571
- */
4572
4263
  declare const CURRENT_BRIDGE_LANE_FILE = "bridge\u2192runtime.current.ndjson";
4573
- /**
4574
- * The recording with its `bridge→runtime` lane replaced by the current
4575
- * expectation when one exists: what the self-suite pins and compares.
4576
- */
4577
4264
  declare function withCurrentBridgeLane(recording: BridgeRecording): BridgeRecording;
4578
4265
  declare function readBridgeRecording(dir: string): BridgeRecording;
4579
4266
  interface RecordedCell {
@@ -4581,13 +4268,8 @@ interface RecordedCell {
4581
4268
  cell: string;
4582
4269
  dir: string;
4583
4270
  }
4584
- /**
4585
- * Every `<provider>/<cell>` directory under a recordings root that holds at
4586
- * least one lane, sorted for stable iteration.
4587
- */
4588
4271
  declare function listRecordedCells(root: string): RecordedCell[];
4589
4272
 
4590
- /** One stateful assembler: `thread/delta` notifications in, events out. */
4591
4273
  interface ParityAssembler {
4592
4274
  assembleMessage(message: {
4593
4275
  method?: string;
@@ -4595,140 +4277,55 @@ interface ParityAssembler {
4595
4277
  }): ThreadEvent[];
4596
4278
  }
4597
4279
  type CreateParityAssembler = (providerId: string) => ParityAssembler;
4598
- /** Project canonical events into timeline rows (the server's projection). */
4599
4280
  type ParityRowProjector = (args: {
4600
4281
  events: readonly ThreadEvent[];
4601
4282
  providerId: string;
4602
4283
  }) => unknown[];
4603
- /** A bridge process, ready to spawn: the bootstrap, the module, its scope. */
4604
4284
  interface ProviderBridgeLaunch {
4605
4285
  command: string;
4606
4286
  args: string[];
4607
4287
  cwd: string;
4608
- /** Added to the harness's own environment for the bridge process. */
4609
4288
  env: Record<string, string>;
4610
4289
  }
4611
4290
  interface ResolveProviderBridgeLaunchOptions {
4612
- /**
4613
- * The bridge module: the file whose `experimental_providerBridge` export the
4614
- * bootstrap runs. Absolute; a built artifact (`host.mjs`) or, with a
4615
- * TypeScript loader among `nodeArgs`, the source file.
4616
- */
4617
4291
  modulePath: string;
4618
- /** The plugin the bridge belongs to (its data and temp directories). */
4619
4292
  pluginId: string;
4620
- /** Working directory of the bridge process; defaults to the caller's. */
4621
4293
  cwd?: string;
4622
- /**
4623
- * The plugin data directory the bootstrap hands the bridge; defaults to a
4624
- * fresh temp directory per launch.
4625
- */
4626
4294
  dataDir?: string;
4627
- /**
4628
- * The provider-bridge bootstrap (`bridge-worker-entry`) that runs the
4629
- * module; defaults to the kit's own — the source entry in a bb checkout,
4630
- * the bundled one in the published SDK.
4631
- */
4632
4295
  bootstrapPath?: string;
4633
- /**
4634
- * Node flags before the bootstrap. Defaults: in a bb checkout (source
4635
- * bootstrap) `--conditions=source` plus the tsx loader; otherwise the tsx
4636
- * loader for a TypeScript module and nothing for a built one.
4637
- */
4638
4296
  nodeArgs?: string[];
4639
4297
  }
4640
- /**
4641
- * The process that runs one bridge module through the bootstrap — exactly the
4642
- * shape the runtime spawns, so a replayed bridge sees the argv, stdin framing
4643
- * and signal handling it gets in production.
4644
- */
4645
4298
  declare function resolveProviderBridgeLaunch(options: ResolveProviderBridgeLaunchOptions): ProviderBridgeLaunch;
4646
4299
  type ReplayDialect = "claude-cli" | "json-rpc" | "pi-rpc";
4647
- /**
4648
- * How a provider's bridge is pointed at the replay child. Codex reads its
4649
- * app-server command from env, Claude its CLI path from env, pi its RPC
4650
- * command from env (`pi-rpc`: JSON lines plus the extension channel on fds
4651
- * 3/4), and an ACP bridge its agent command from the launch spec inside
4652
- * `thread/start`. A bridge with no provider child (the echo example) needs no
4653
- * profile at all.
4654
- */
4655
4300
  interface ReplayProviderProfile {
4656
- /** The protocol the replay child speaks on its pipe. */
4657
4301
  dialect: ReplayDialect;
4658
- /** Environment the bridge reads the child's command from. */
4659
4302
  env(args: {
4660
4303
  replayCommand: string[];
4661
4304
  wrapperPath: string;
4662
4305
  stateDir: string;
4663
4306
  }): Record<string, string>;
4664
- /** Rewrite a recorded runtime request that carries the child's command. */
4665
4307
  rewriteRuntimeLine?(line: string, args: {
4666
4308
  replayCommand: string[];
4667
4309
  }): string;
4668
- /**
4669
- * Provider state a bridge reads outside its provider pipe, seeded before
4670
- * the replay starts (the Claude SDK forks by copying the source session's
4671
- * transcript from disk).
4672
- */
4673
4310
  prepareState?(args: {
4674
4311
  recording: BridgeRecording;
4675
4312
  stateDir: string;
4676
4313
  workspaceDir: string;
4677
4314
  }): void;
4678
4315
  }
4679
- /** A bridge that spawns no provider, or one whose child command is fixed. */
4680
4316
  declare const DEFAULT_REPLAY_PROFILE: ReplayProviderProfile;
4681
4317
  interface ReplayRecordingOptions {
4682
4318
  recordingDir: string;
4683
- /** The provider the recording belongs to; keys the assembler's ids. */
4684
4319
  providerId: string;
4685
- /** The bridge process to replay through (see `resolveProviderBridgeLaunch`). */
4686
4320
  bridge: ProviderBridgeLaunch;
4687
- /** How the bridge reaches the replay child; `DEFAULT_REPLAY_PROFILE` when omitted. */
4688
4321
  profile?: ReplayProviderProfile;
4689
4322
  createAssembler: CreateParityAssembler;
4690
- /**
4691
- * The assembler that plans the replay's gates from the recorded
4692
- * `bridge→runtime` lane; defaults to `createAssembler`. A re-recording run
4693
- * on a checkout whose grammar no longer accepts the whole recorded lane
4694
- * plans with the recording-time checkout's assembler instead.
4695
- */
4696
4323
  createPlanAssembler?: CreateParityAssembler;
4697
- /**
4698
- * Plan the replay's gates from the cell's current bridge lane
4699
- * (`bridge→runtime.current.ndjson`, see `withCurrentBridgeLane`) when one
4700
- * exists, instead of the recorded lane. The leg whose bridge wrote that
4701
- * lane parses all of it; the recording-time leg parses the recorded lane.
4702
- */
4703
4324
  planFromCurrentLane?: boolean;
4704
- /** Per-wait timeout for a gate or a response. */
4705
4325
  timeoutMs?: number;
4706
- /**
4707
- * The quiet period after which a request is sent even though the bridge
4708
- * has emitted fewer lines than the recording had before it — a divergent
4709
- * bridge pays this once per request instead of stalling. Only a plan from
4710
- * the recorded lane can be short for that reason: a plan from the current
4711
- * lane (`planFromCurrentLane`) was written by this very bridge, so a
4712
- * shortfall there is latency, never divergence, and the request waits for
4713
- * its events up to `timeoutMs` instead — a starved bridge (a loaded CI
4714
- * runner) still has provider lines to read, and a request sent on quiet
4715
- * alone lands before them, at a point the recording never had.
4716
- */
4717
4326
  orderTimeoutMs?: number;
4718
- /**
4719
- * Quiet period after the last bridge output before the replay is closed.
4720
- * An exact current-lane replay first waits for every planned event.
4721
- */
4722
4327
  settleMs?: number;
4723
- /**
4724
- * Quiet period a request waits for once the gates are met. The replay child
4725
- * plays every provider line before the request's cursor point a couple of
4726
- * milliseconds apart, so a short silence means the bridge has emitted all
4727
- * that the pre-request stream produces; without it a request the bridge
4728
- * acknowledges at once (a steer) lands at a load-dependent point.
4729
- */
4730
4328
  drainMs?: number;
4731
- /** Mirror the bridge's stderr (and the replay child's logs) here. */
4732
4329
  onStderr?: (text: string) => void;
4733
4330
  }
4734
4331
  interface ParityGrammarViolation {
@@ -4739,39 +4336,21 @@ interface ParityGrammarViolation {
4739
4336
  interface ParityRun {
4740
4337
  providerId: string;
4741
4338
  recordingDir: string;
4742
- /** Raw `bridge→runtime` lines, in order. */
4743
4339
  lines: string[];
4744
- /** When each line arrived, ms since the replay started (diagnostics). */
4745
4340
  lineTimes: number[];
4746
- /**
4747
- * For each line, the recorded `runtime→bridge` entry written last before
4748
- * it arrived (null before any was sent) — where the line sits in the
4749
- * recording's wire order, for a lane re-recorded through this bridge.
4750
- */
4751
4341
  lineAfter: Array<{
4752
4342
  run: number;
4753
4343
  seq: number;
4754
4344
  ts: number;
4755
4345
  } | null>;
4756
- /** Assembled events, minus the ones the grammar dropped (as the runtime does). */
4757
4346
  events: ThreadEvent[];
4758
4347
  grammarViolations: ParityGrammarViolation[];
4759
- /** Gates that timed out or requests that were never answered. */
4760
4348
  stalls: string[];
4761
4349
  stderr: string;
4762
4350
  exitCode: number | null;
4763
4351
  }
4764
- /** The id of the harness's own `initialize` request; never part of a recording. */
4765
4352
  declare const PARITY_INITIALIZE_ID = "parity-initialize";
4766
- /**
4767
- * Replay one recording through one bridge. Resolves when the bridge exits
4768
- * after the last recorded runtime line has been sent and answered.
4769
- */
4770
4353
  declare function replayRecording(options: ReplayRecordingOptions): Promise<ParityRun>;
4771
- /**
4772
- * The events the recorded `bridge→runtime` lane assembles to, without any
4773
- * bridge in the loop: the recording's own view of what the bridge emitted.
4774
- */
4775
4354
  declare function assembleRecordedEvents(recording: BridgeRecording, createAssembler: CreateParityAssembler, providerId: string): {
4776
4355
  events: ThreadEvent[];
4777
4356
  grammarViolations: ParityGrammarViolation[];
@@ -4781,7 +4360,6 @@ interface ParityAllowlistEntry {
4781
4360
  provider: string | "*";
4782
4361
  cell: string | "*";
4783
4362
  layer: "events" | "rows";
4784
- /** A JSON pointer over the normalized list, with `*` and `**` wildcards. */
4785
4363
  path: string;
4786
4364
  pr: string;
4787
4365
  reason: string;
@@ -4795,16 +4373,13 @@ interface ParityComparison {
4795
4373
  cell: string;
4796
4374
  events: ParityLayerDiff;
4797
4375
  rows: ParityLayerDiff;
4798
- /** Grammar drops, compared as `rule:eventType` multisets. */
4799
4376
  grammar: ParityLayerDiff;
4800
- /** Allowlist entries that matched this cell but masked nothing. */
4801
4377
  staleAllowlist: ParityAllowlistEntry[];
4802
4378
  passed: boolean;
4803
4379
  }
4804
4380
  interface ParityInputs {
4805
4381
  events: readonly ThreadEvent[];
4806
4382
  rows: readonly unknown[];
4807
- /** Events the grammar dropped; a regression when the lists differ. */
4808
4383
  grammarViolations?: readonly ParityGrammarViolation[];
4809
4384
  }
4810
4385
  declare function compareParity(oldRun: ParityInputs, newRun: ParityInputs, allowlist: readonly ParityAllowlistEntry[], scope: {
@@ -4812,13 +4387,9 @@ declare function compareParity(oldRun: ParityInputs, newRun: ParityInputs, allow
4812
4387
  cell: string;
4813
4388
  }): ParityComparison;
4814
4389
  interface ReplayRecordedCellsOptions {
4815
- /** The `<provider>/<cell>` tree to read (see `listRecordedCells`). */
4816
4390
  recordingsRoot: string;
4817
- /** Which recorded providers this bridge serves (`acp` serves `acp-*`). */
4818
4391
  servesProvider: (providerId: string) => boolean;
4819
- /** Cell names to replay; defaults to every cell of those providers. */
4820
4392
  cells?: readonly string[];
4821
- /** The bridge process and replay profile for one cell's provider. */
4822
4393
  bridge: (cell: RecordedCell) => {
4823
4394
  launch: ProviderBridgeLaunch;
4824
4395
  profile?: ReplayProviderProfile;
@@ -4830,22 +4401,11 @@ interface ReplayRecordedCellsOptions {
4830
4401
 
4831
4402
  type RerecordCurrentBridgeLaneOptions = Omit<ReplayRecordingOptions, "planFromCurrentLane">;
4832
4403
  interface RerecordCurrentBridgeLaneResult {
4833
- /** The file written, or null when the replay stalled and nothing was. */
4834
4404
  file: string | null;
4835
- /** Lines in the new lane (the harness's own handshake excluded). */
4836
4405
  lines: number;
4837
- /** Events the replay assembled. */
4838
4406
  events: number;
4839
- /** A stalled replay leaves the current lane untouched. */
4840
4407
  stalls: string[];
4841
4408
  }
4842
- /**
4843
- * Replay one recording through a bridge and write what the bridge emitted
4844
- * as the recording's current bridge lane. The replay plans its gates from
4845
- * the recorded lane (or `createPlanAssembler`'s view of it), never from a
4846
- * previous current lane: the new lane must reproduce the recorded session,
4847
- * not the last re-recording of it.
4848
- */
4849
4409
  declare function rerecordCurrentBridgeLane(options: RerecordCurrentBridgeLaneOptions): Promise<RerecordCurrentBridgeLaneResult>;
4850
4410
 
4851
4411
  export { ASSEMBLER_GRAMMAR_VERSIONS, CONFORMANCE_ASSEMBLED_EVENT_METHOD, CURRENT_BRIDGE_LANE_FILE, DEFAULT_REPLAY_PROFILE, PARITY_INITIALIZE_ID, RECORDED_CONFORMANCE_CELLS, assembleCapturedThreadEvents as experimental_assembleCapturedThreadEvents, assembleRecordedEvents as experimental_assembleRecordedEvents, captureBridgeJsonRpcOutput as experimental_captureBridgeJsonRpcOutput, checkRecordedCellReplay as experimental_checkRecordedCellReplay, compareParity as experimental_compareParity, createBridgeDeltaEventCollector as experimental_createBridgeDeltaEventCollector, createBridgeJsonRpcTestHarness as experimental_createBridgeJsonRpcTestHarness, createDeltaAssembler as experimental_createDeltaAssembler, describeCalibrationEvents as experimental_describeCalibrationEvents, formatConformanceReport as experimental_formatConformanceReport, listRecordedCells as experimental_listRecordedCells, normalizeCalibrationEvents as experimental_normalizeCalibrationEvents, readBridgeRecording as experimental_readBridgeRecording, replayRecording as experimental_replayRecording, rerecordCurrentBridgeLane as experimental_rerecordCurrentBridgeLane, resolveProviderBridgeLaunch as experimental_resolveProviderBridgeLaunch, runBridgeConformance as experimental_runBridgeConformance, toConformanceMessages as experimental_toConformanceMessages, withCurrentBridgeLane as experimental_withCurrentBridgeLane };