@robota-sdk/agent-transport 3.0.0-beta.83 → 3.0.0-beta.85

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +80 -118
  3. package/dist/browser/client.d.ts +1 -1
  4. package/dist/browser/client.js +1 -1
  5. package/dist/browser/index.d.ts +60 -6
  6. package/dist/browser/index.d.ts.map +1 -1
  7. package/dist/browser/index.js +1 -1
  8. package/dist/browser/index.js.map +1 -1
  9. package/dist/browser/observer-messages-CEeisRaF.js +2 -0
  10. package/dist/browser/observer-messages-CEeisRaF.js.map +1 -0
  11. package/dist/browser/{observer-messages-DC_8VHk9.d.ts → observer-messages-Dnff2Tdb.d.ts} +125 -3
  12. package/dist/browser/observer-messages-Dnff2Tdb.d.ts.map +1 -0
  13. package/dist/node/index.cjs +1 -1
  14. package/dist/node/index.d.cts +181 -6
  15. package/dist/node/index.d.cts.map +1 -1
  16. package/dist/node/index.d.ts +181 -6
  17. package/dist/node/index.d.ts.map +1 -1
  18. package/dist/node/index.js +1 -1
  19. package/dist/node/index.js.map +1 -1
  20. package/package.json +12 -11
  21. package/src/__tests__/handoff-chunking.test.ts +44 -1
  22. package/src/__tests__/message-decoders.test.ts +295 -1
  23. package/src/__tests__/project-read-messages.test.ts +118 -0
  24. package/src/__tests__/session-directory-messages.test.ts +130 -0
  25. package/src/__tests__/session-error-classification.test.ts +113 -0
  26. package/src/__tests__/session-message-handler-observe.test.ts +25 -1
  27. package/src/__tests__/session-message-handler.test.ts +57 -3
  28. package/src/__tests__/settings-messages.test.ts +193 -0
  29. package/src/handoff-chunking.ts +52 -12
  30. package/src/index.ts +4 -0
  31. package/src/message-decoders.ts +157 -3
  32. package/src/observer-messages.ts +11 -0
  33. package/src/project-read-messages.ts +74 -0
  34. package/src/protocol-session.ts +17 -1
  35. package/src/session-directory-messages.ts +78 -1
  36. package/src/session-error-classification.ts +91 -0
  37. package/src/session-events.ts +7 -1
  38. package/src/session-message-handler.ts +58 -8
  39. package/src/session-query-messages.ts +18 -1
  40. package/src/session-resume-bridge.ts +8 -0
  41. package/src/settings-messages.ts +103 -0
  42. package/src/wire-messages.ts +133 -4
  43. package/dist/browser/observer-messages-Bx-xReUQ.js +0 -2
  44. package/dist/browser/observer-messages-Bx-xReUQ.js.map +0 -1
  45. package/dist/browser/observer-messages-DC_8VHk9.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,67 @@
1
1
  # @robota-sdk/agent-transport
2
2
 
3
+ ## 3.0.0-beta.85
4
+
5
+ ### Patch Changes
6
+
7
+ - 9a01e78: `chunkHandoffPayload` and `HandoffChunkAssembler`, exported from the package root that also builds for the browser, no longer use Node's `Buffer`; they use `Uint8Array`, `TextEncoder`/`TextDecoder` and `btoa`/`atob`, with the same chunks and the same refusal of non-canonical base64.
8
+ - Updated dependencies [41cca13]
9
+ - Updated dependencies [193a0bc]
10
+ - Updated dependencies [ada3841]
11
+ - Updated dependencies [5093a30]
12
+ - Updated dependencies [94b2c87]
13
+ - Updated dependencies [3ab2eca]
14
+ - @robota-sdk/agent-core@3.0.0-beta.85
15
+ - @robota-sdk/agent-interface-command@3.0.0-beta.85
16
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.85
17
+ - @robota-sdk/agent-interface-session@3.0.0-beta.85
18
+ - @robota-sdk/agent-interface-session-mobility@3.0.0-beta.85
19
+ - @robota-sdk/agent-interface-transport@3.0.0-beta.85
20
+ - @robota-sdk/agent-interface-analytics@3.0.0-beta.85
21
+
22
+ ## 3.0.0-beta.84
23
+
24
+ ### Patch Changes
25
+
26
+ - 9c6a8db: The wire protocol gained several request/reply pairs so a GUI never has to scrape command output for
27
+ data it can read directly.
28
+
29
+ `get-settings`/`update-settings` read and write the Settings screen; a patch applies through the same
30
+ function its matching slash command uses, so the two paths cannot drift. `list-models` returns the
31
+ configured models grouped by provider profile, with the current profile and model. `get-agent-definitions`
32
+ returns the agent switcher's roster and current selection. `project-status`, `project-diff` and
33
+ `project-memory` back the Project panel's git status, one file's diff, and project memory; a host
34
+ without this capability answers `protocol_error` instead of hanging. `rename-session` and
35
+ `delete-session` rename or remove a stored session from the list, current or not, each with its own
36
+ success/failure reply.
37
+
38
+ The `messages` frame gained an optional `display` field — the same history projected into display
39
+ segments (text runs and finished tool calls, diffs included) — and the connection's own `driverId`, so
40
+ a reload, reconnect or resume shows tool rows and tells a co-driver's turns from its own. The `error`
41
+ frame gained optional `code`, `provider`, `retryAfterSeconds` and `model` fields so a renderer can say
42
+ what kind of failure happened (`auth`, `rate_limit`, `model_unavailable`, `network`, `provider`) instead
43
+ of showing only raw text; a session error this classification does not recognize is unchanged.
44
+
45
+ `TCommandSurfaceLocality` names whether a `'remote'`-sourced command is provably on this machine. The
46
+ WebRTC/device-mesh transport now forwards `'remote'` for it (it proves no locality, the same rule
47
+ already applied to pairing), and both the WS and WebRTC transports forward it into the Settings
48
+ read/write path, so a command that refuses a remote surface (installing a plugin) refuses identically
49
+ regardless of which transport carried it.
50
+
51
+ - Updated dependencies [9f46375]
52
+ - Updated dependencies [e8d70ac]
53
+ - Updated dependencies [9c6a8db]
54
+ - Updated dependencies [9c6a8db]
55
+ - Updated dependencies [9c6a8db]
56
+ - Updated dependencies [9c6a8db]
57
+ - @robota-sdk/agent-core@3.0.0-beta.84
58
+ - @robota-sdk/agent-interface-session@3.0.0-beta.84
59
+ - @robota-sdk/agent-interface-analytics@3.0.0-beta.84
60
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.84
61
+ - @robota-sdk/agent-interface-command@3.0.0-beta.84
62
+ - @robota-sdk/agent-interface-session-mobility@3.0.0-beta.84
63
+ - @robota-sdk/agent-interface-transport@3.0.0-beta.84
64
+
3
65
  ## 3.0.0-beta.83
4
66
 
5
67
  ### Major Changes
package/README.md CHANGED
@@ -1,42 +1,11 @@
1
- # Agent Transport
1
+ # @robota-sdk/agent-transport
2
2
 
3
- Browser-safe transport protocol and delivery substrate for the Robota SDK. The root exports shared
4
- wire messages, session bridging, channel codecs, and delivery helpers. Browser decoders are also
5
- available from `./client`; Node-only admission and handoff integrity helpers are available from
6
- `./node`.
7
-
8
- ## Handoff offer migration
9
-
10
- `@robota-sdk/agent-transport/node` no longer exports `buildHandoffManifest`,
11
- `IBuildManifestInput`, `ISourceRuntimeState`, or `TManifestResult`. Handoff readiness and inventory
12
- classification belong to `@robota-sdk/agent-interface-session-mobility`. A host composing a handoff
13
- should check readiness before serializing, then pass the integrity of those exact bytes to the
14
- mobility offer policy:
15
-
16
- ```typescript
17
- import {
18
- assessHandoffReadiness,
19
- prepareHandoffOffer,
20
- type IPrepareHandoffOfferInput,
21
- } from '@robota-sdk/agent-interface-session-mobility';
22
- import { sealHandoffRecord } from '@robota-sdk/agent-transport/node';
23
-
24
- function buildOffer(request: Omit<IPrepareHandoffOfferInput, 'integrity'>) {
25
- const readiness = assessHandoffReadiness(request.runtime);
26
- if (!readiness.ready) return readiness;
27
-
28
- const { serialized, integrity } = sealHandoffRecord(request.record);
29
- const offer = prepareHandoffOffer({ ...request, integrity });
30
- if (!offer.built) return offer;
31
-
32
- // Send serialized unchanged: offer.manifest.integrity describes these exact bytes.
33
- return { manifest: offer.manifest, serialized };
34
- }
35
- ```
36
-
37
- For types, use `ISourceRuntimeState`, `IPrepareHandoffOfferInput`, and `THandoffOfferResult` from
38
- session mobility. `IPrepareHandoffOfferInput` includes the integrity metadata produced by
39
- `sealHandoffRecord`; the serialized payload remains a separate transport value.
3
+ The shared protocol layer under every Robota transport. It defines the transport-neutral wire messages
4
+ (`TClientMessage` / `TServerMessage`), the session bridge that turns those messages into calls on a live
5
+ session, and the delivery helpers a carrier needs (backpressure, resumable delivery, channel framing,
6
+ handoff payload chunking). The WebSocket and WebRTC transports carry its wire protocol, and the HTTP and
7
+ MCP transports use its admission and token-verification helpers. It opens no socket or listener of its
8
+ own.
40
9
 
41
10
  ## Installation
42
11
 
@@ -44,115 +13,108 @@ session mobility. `IPrepareHandoffOfferInput` includes the integrity metadata pr
44
13
  npm install @robota-sdk/agent-transport
45
14
  ```
46
15
 
47
- ## Available Transports
16
+ Requires Node.js 22.12 or later. The root and `./client` entry points also run in the browser.
48
17
 
49
- Headless execution belongs to `agent-framework`. HTTP, WebSocket, MCP, and WebRTC ship as standalone
50
- transport packages.
18
+ ## Entry points
51
19
 
52
- | Transport | Package / Sub-path | Description |
53
- | --------- | ------------------------------------ | ------------------------------------------------------- |
54
- | Headless | `@robota-sdk/agent-framework` | Non-interactive text / JSON / stream-JSON output |
55
- | HTTP | `@robota-sdk/agent-transport-http` | Hono-based REST adapter (Node.js / CF Workers / Lambda) |
56
- | WebSocket | `@robota-sdk/agent-transport-ws` | Framework-agnostic real-time bidirectional adapter |
57
- | MCP | `@robota-sdk/agent-transport-mcp` | Model Context Protocol server adapter |
58
- | WebRTC | `@robota-sdk/agent-transport-webrtc` | Peer-to-peer data-channel adapter |
20
+ | Import path | Environment | What it contains |
21
+ | ------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
22
+ | `@robota-sdk/agent-transport` | browser and Node | Wire message types, runtime decoders, `createSessionMessageHandler`, `createOutboundDelivery`, `SessionResumeBridge`, channel frame codec, peer-message ledger, handoff chunking |
23
+ | `@robota-sdk/agent-transport/client` | browser and Node | Only the wire message types and the runtime decoders (`decodeServerMessage`, `decodeClientMessage`, `decodeFrame`) |
24
+ | `@robota-sdk/agent-transport/node` | Node only | Transport admission (`resolveAdmission`, `mintTransportToken`, `credentialMatches`), OAuth access-token verification (`createAccessTokenVerifier`), the bearer resource-server gate, file transfer, handoff integrity (`sealHandoffRecord`, `verifyHandoffPayload`) |
59
25
 
60
- Scripted-provider test fixtures live in `@robota-sdk/agent-core/testing` (the former `./testing`
61
- pass-through was removed, issue #2052).
26
+ Anything that needs `node:crypto` or the network lives under `./node`, so a browser bundle that imports
27
+ the root or `./client` never pulls in a Node built-in.
62
28
 
63
- All session-owning entry points treat `cwd` as provenance, not project trust. Pass a host-issued
64
- `TWorkspaceProjectAccess` decision through `projectAccess`; omitting it creates a Restricted session
65
- that does not load project contributions.
29
+ ## Usage: bridging a connection to a session
66
30
 
67
- ## Quick Start
68
-
69
- ### Headless
31
+ A carrier (your socket, data channel, or stream) turns each connection into three things: an outbound
32
+ sink, a failure policy, and a feed of inbound text frames. The package does the rest.
70
33
 
71
34
  ```typescript
72
- import { createHeadlessTransport } from '@robota-sdk/agent-framework';
35
+ import { createOutboundDelivery, createSessionMessageHandler } from '@robota-sdk/agent-transport';
36
+ import type { IProtocolSession, TServerMessage } from '@robota-sdk/agent-transport';
73
37
 
74
- const transport = createHeadlessTransport({ outputFormat: 'text', prompt: 'Hello!' });
75
- ```
38
+ declare const session: IProtocolSession; // e.g. an InteractiveSession from @robota-sdk/agent-framework
39
+ declare const socket: { send(text: string): void; close(): void }; // one client connection
76
40
 
77
- ### WebSocket
41
+ // Outbound: every frame to this connection goes through one delivery boundary. A failed send, or a
42
+ // peer that stops reading, calls the error handler once; the carrier then closes the connection.
43
+ const deliver = createOutboundDelivery(
44
+ (message: TServerMessage) => socket.send(JSON.stringify(message)),
45
+ () => socket.close(),
46
+ );
78
47
 
79
- ```typescript
80
- import { WsTransport } from '@robota-sdk/agent-transport-ws';
48
+ const handler = createSessionMessageHandler({ session, deliver });
81
49
 
82
- const transport = new WsTransport({ port: 3001 });
50
+ // Inbound: pass each raw text frame from the client; call cleanup when the connection closes.
51
+ handler.onMessage(JSON.stringify({ type: 'submit', prompt: 'Hello' }));
52
+ handler.cleanup();
83
53
  ```
84
54
 
85
- ### HTTP
55
+ `onMessage` decodes and validates the frame itself; malformed input is answered with a protocol error,
56
+ not thrown. Pass `role: 'observe'` for a read-only connection: it can read the session's conversation
57
+ and state but cannot submit, answer prompts or control the session.
86
58
 
87
- ```typescript
88
- import { createHttpTransport } from '@robota-sdk/agent-transport-http';
89
-
90
- const transport = createHttpTransport({ basePath: '/agent' }); // mount on your own server
91
- ```
59
+ ## Composing a handoff offer
92
60
 
93
- ### MCP
61
+ Moving a session to another device is split between two packages. Readiness and the offer policy
62
+ belong to `@robota-sdk/agent-interface-session-mobility`; this package seals the serialized record so
63
+ the receiver can verify it arrived intact. Check readiness first, then pass the integrity of those
64
+ exact bytes to the offer:
94
65
 
95
66
  ```typescript
96
- import { createMcpTransport } from '@robota-sdk/agent-transport-mcp';
97
-
98
- const transport = createMcpTransport({ name: 'my-agent', version: '1.0.0' });
99
- ```
67
+ import {
68
+ assessHandoffReadiness,
69
+ prepareHandoffOffer,
70
+ type IPrepareHandoffOfferInput,
71
+ } from '@robota-sdk/agent-interface-session-mobility';
72
+ import { sealHandoffRecord } from '@robota-sdk/agent-transport/node';
100
73
 
101
- ### TUI presentation (Ink/React)
74
+ function buildOffer(request: Omit<IPrepareHandoffOfferInput, 'integrity'>) {
75
+ const readiness = assessHandoffReadiness(request.runtime);
76
+ if (!readiness.ready) return readiness;
102
77
 
103
- ```typescript
104
- import { renderApp } from '@robota-sdk/agent-ui-terminal';
105
- import type { IRenderOptions } from '@robota-sdk/agent-ui-terminal';
78
+ const { serialized, integrity } = sealHandoffRecord(request.record);
79
+ const offer = prepareHandoffOffer({ ...request, integrity });
80
+ if (!offer.built) return offer;
106
81
 
107
- declare const options: IRenderOptions;
108
- await renderApp(options);
82
+ // Send serialized unchanged: offer.manifest.integrity describes these exact bytes.
83
+ return { manifest: offer.manifest, serialized };
84
+ }
109
85
  ```
110
86
 
111
- > React and Ink dependencies are confined to the standalone
112
- > `@robota-sdk/agent-ui-terminal` package. This core package stays React-free.
87
+ The receiver checks the bytes against `offer.manifest.integrity` with `verifyHandoffPayload` before
88
+ parsing them. A payload too large for one frame can be split with `chunkHandoffPayload` and reassembled
89
+ with `HandoffChunkAssembler`.
113
90
 
114
- ## Sub-path Imports
91
+ ## Transport packages
115
92
 
116
- Import only what you need to keep bundles small:
93
+ Each carrier is its own package, so an application installs only the protocol dependencies it uses.
117
94
 
118
- ```typescript
119
- import { createHeadlessTransport } from '@robota-sdk/agent-framework';
120
- import { WsTransport } from '@robota-sdk/agent-transport-ws';
121
- import type { TServerMessage } from '@robota-sdk/agent-transport';
122
- import { createHttpTransport } from '@robota-sdk/agent-transport-http';
123
- import { createMcpTransport } from '@robota-sdk/agent-transport-mcp';
124
- import { renderApp } from '@robota-sdk/agent-ui-terminal';
125
- ```
126
-
127
- The framework root owns headless and programmatic surfaces plus `TransportRegistry`. The transport
128
- root owns transport-neutral wire messages, session bridging, channel codecs, and delivery helpers;
129
- browser decoders are also available from `@robota-sdk/agent-transport/client`, while Node-only
130
- admission and handoff integrity helpers live under `@robota-sdk/agent-transport/node`.
131
-
132
- ```typescript
133
- import { createHeadlessTransport } from '@robota-sdk/agent-framework';
134
- ```
95
+ | Transport | Package | What it does |
96
+ | --------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
97
+ | WebSocket | [`@robota-sdk/agent-transport-ws`](../agent-transport-ws/README.md) | Serves a session on a loopback WebSocket server (token-authenticated by default) |
98
+ | HTTP | [`@robota-sdk/agent-transport-http`](../agent-transport-http/README.md) | Hono routes for submitting prompts and reading session state over HTTP + SSE |
99
+ | MCP | [`@robota-sdk/agent-transport-mcp`](../agent-transport-mcp/README.md) | Exposes a session as an MCP server over stdio or Streamable HTTP |
100
+ | WebRTC | [`@robota-sdk/agent-transport-webrtc`](../agent-transport-webrtc/README.md) | Carries a session peer-to-peer over a pairing-gated data channel (Node host side) |
135
101
 
136
- `TransportRegistry` accepts the discriminated base service/runner adapter union. It rejects active
137
- restart before mutation, rolls partial startup back in reverse order, reports real runner failure
138
- immediately, and returns a complete ordered aggregate whose pending runners become registry-owned
139
- `abandoned` records on stop or rollback.
102
+ The headless (non-interactive text / JSON / stream-JSON) transport and `TransportRegistry`, which
103
+ starts and stops a set of transports together, live in `@robota-sdk/agent-framework`. The terminal UI is
104
+ `@robota-sdk/agent-ui-terminal`; this package has no React or Ink dependency.
140
105
 
141
106
  ## Dependencies
142
107
 
143
- - `@robota-sdk/agent-interface-analytics`
144
- - `@robota-sdk/agent-interface-command`
145
- - `@robota-sdk/agent-interface-execution`
146
- - `@robota-sdk/agent-interface-session`
147
- - `@robota-sdk/agent-interface-session-mobility`
148
- - `@robota-sdk/agent-interface-transport`
108
+ - `@robota-sdk/agent-core`
109
+ - `@robota-sdk/agent-interface-analytics`, `-command`, `-execution`, `-session`, `-session-mobility`,
110
+ `-transport` (contract packages)
111
+ - `jose` (access-token signature verification under `./node`)
149
112
 
150
- The heavier protocol dependencies (`ws`, `hono`, `@modelcontextprotocol/sdk`,
151
- `react`, `ink`, and friends) now live in the split transport packages
152
- (`@robota-sdk/agent-transport-{http,ws,mcp}`) and presentation packages
153
- (`@robota-sdk/agent-ui-{terminal,web}`).
113
+ The protocol libraries (`ws`, `hono`, `@modelcontextprotocol/sdk`, `node-datachannel`) are
114
+ dependencies of the individual transport packages, not of this one.
154
115
 
155
- ## Links
116
+ ## Documentation
156
117
 
157
- - [npm](https://www.npmjs.com/package/@robota-sdk/agent-transport)
158
- - [GitHub](https://github.com/woojubb/robota)
118
+ - [docs/SPEC.md](./docs/SPEC.md) — package contract and boundaries
119
+ - [npm](https://www.npmjs.com/package/@robota-sdk/agent-transport) ·
120
+ [GitHub](https://github.com/woojubb/robota)
@@ -1,2 +1,2 @@
1
- import { a as decodeFrame, c as TClientMessage, d as TWireExecutionResult, i as decodeClientMessage, l as TSeqServerMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, s as IWireHistoryEntry, t as isObserverMessageType, u as TServerMessage } from "./observer-messages-DC_8VHk9.js";
1
+ import { a as decodeFrame, c as IWireHistoryEntry, d as TServerMessage, f as TWireExecutionResult, i as decodeClientMessage, l as TClientMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, t as isObserverMessageType, u as TSeqServerMessage } from "./observer-messages-Dnff2Tdb.js";
2
2
  export { type IWireHistoryEntry, MAX_INBOUND_FRAME_BYTES, type TClientMessage, type TMessageDecodeResult, type TSeqServerMessage, type TServerMessage, type TWireExecutionResult, decodeClientMessage, decodeFrame, decodeServerMessage, isObserverMessageType };
@@ -1 +1 @@
1
- import{a as e,i as t,n,r,t as i}from"./observer-messages-Bx-xReUQ.js";export{n as MAX_INBOUND_FRAME_BYTES,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,i as isObserverMessageType};
1
+ import{a as e,i as t,n,r,t as i}from"./observer-messages-CEeisRaF.js";export{n as MAX_INBOUND_FRAME_BYTES,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,i as isObserverMessageType};
@@ -1,6 +1,7 @@
1
- import { a as decodeFrame, c as TClientMessage, d as TWireExecutionResult, i as decodeClientMessage, l as TSeqServerMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, s as IWireHistoryEntry, t as isObserverMessageType, u as TServerMessage } from "./observer-messages-DC_8VHk9.js";
2
- import { ISessionBackgroundGroups, ISessionBackgroundTasks, ISessionCommands, ISessionConversationRead, ISessionDirectory, ISessionDriverAttribution, ISessionEvents, ISessionExecutionDetail, ISessionExecutionState, ISessionExecutionWorkspace, ISessionPromptResolution, ISessionSelfPacedLoopControl, ISessionStatusRead, ISessionTurnControl, ISessionTurnSubmission, TDriverId } from "@robota-sdk/agent-interface-session";
1
+ import { a as decodeFrame, c as IWireHistoryEntry, d as TServerMessage, f as TWireExecutionResult, i as decodeClientMessage, l as TClientMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, s as IWireAgentDefinitionSummary, t as isObserverMessageType, u as TSeqServerMessage } from "./observer-messages-Dnff2Tdb.js";
2
+ import { ISessionAgentJobs, ISessionBackgroundGroups, ISessionBackgroundTasks, ISessionCommands, ISessionConversationRead, ISessionDirectory, ISessionDriverAttribution, ISessionEvents, ISessionExecutionDetail, ISessionExecutionState, ISessionExecutionWorkspace, ISessionProjectRead, ISessionPromptResolution, ISessionSelfPacedLoopControl, ISessionStatusRead, ISessionTurnControl, ISessionTurnSubmission, ISettingsSnapshot, TDriverId, TSettingsPatch } from "@robota-sdk/agent-interface-session";
3
3
  import { IPersonalUsageReport, IPersonalUsageRequest, IUsageBySourceReport, TUsageSurface } from "@robota-sdk/agent-interface-analytics";
4
+ import { TCommandSurfaceLocality } from "@robota-sdk/agent-interface-command";
4
5
  import { IBinaryFrame, IChannelEventFrame, TChannelReceiveResult } from "@robota-sdk/agent-interface-transport";
5
6
  import { IHandoffIntegrity, IPeerMessage, IPeerMessageAck, TPeerDeliveryState } from "@robota-sdk/agent-interface-session-mobility";
6
7
  //#region src/outbound-delivery.d.ts
@@ -94,7 +95,48 @@ declare function createOutboundDelivery(send: (message: TServerMessage) => void,
94
95
  //#endregion
95
96
  //#region src/protocol-session.d.ts
96
97
  /** Session roles required by the shared WebSocket/WebRTC protocol. */
97
- interface IProtocolSession extends ISessionTurnSubmission, ISessionTurnControl, ISessionCommands, ISessionStatusRead, ISessionEvents, ISessionPromptResolution, ISessionConversationRead, ISessionExecutionState, ISessionDriverAttribution, ISessionBackgroundTasks, ISessionBackgroundGroups, ISessionExecutionWorkspace, ISessionExecutionDetail, ISessionSelfPacedLoopControl {}
98
+ interface IProtocolSession extends ISessionTurnSubmission, ISessionTurnControl, ISessionCommands, ISessionStatusRead, ISessionEvents, ISessionPromptResolution, ISessionConversationRead, ISessionExecutionState, ISessionDriverAttribution, ISessionBackgroundTasks, ISessionBackgroundGroups, ISessionExecutionWorkspace, ISessionExecutionDetail, ISessionSelfPacedLoopControl, ISessionAgentJobs {}
99
+ /**
100
+ * #3282 §4c: a protocol session that ALSO answers the Project panel's reads. `Partial` (not a fourth
101
+ * mandatory role on {@link IProtocolSession} itself) deliberately: every existing test double and
102
+ * every other host that builds an `IProtocolSession` keeps type-checking unchanged, and the panel's
103
+ * three methods are runtime-probed (`typeof session.readProjectStatus === 'function'`) rather than
104
+ * assumed — `InteractiveSession` (the one production implementation) provides all three, satisfying
105
+ * this type with no further wiring.
106
+ */
107
+ type TProjectReadCapableSession = IProtocolSession & Partial<ISessionProjectRead>;
108
+ //#endregion
109
+ //#region src/settings-messages.d.ts
110
+ type TSettingsMessage = Extract<TClientMessage, {
111
+ type: 'get-settings' | 'update-settings';
112
+ }>;
113
+ declare function isSettingsMessage(msg: TClientMessage): msg is TSettingsMessage;
114
+ /** What applying a patch did: the fresh snapshot, or why nothing was written. */
115
+ type TSettingsUpdateOutcome = {
116
+ readonly ok: true;
117
+ readonly settings: ISettingsSnapshot;
118
+ } | {
119
+ readonly ok: false;
120
+ readonly code: 'not_available' | 'invalid' | 'refused' | 'update_failed';
121
+ readonly message: string;
122
+ };
123
+ /**
124
+ * #3282 §4a: host-owned read/write for the Settings screen, supplied by the composition root the
125
+ * same way `IUsageQueryReporters` supplies usage reads — this package only correlates the request
126
+ * and carries the result. `updateSettings` applies through the SAME function the matching slash
127
+ * command uses (issue #3282 §4: "one code path, so the behavior matches the TUI"), so whatever a
128
+ * command would refuse on this surface is refused here too.
129
+ */
130
+ interface ISettingsReporter {
131
+ getSettings(session: IProtocolSession, locality?: TCommandSurfaceLocality): ISettingsSnapshot | Promise<ISettingsSnapshot>;
132
+ /**
133
+ * Applies through the SAME function the matching slash command uses. `locality` (#3282 §4 part
134
+ * b-2) is forwarded to that command exactly as the transport received it, so a command that
135
+ * refuses a remote surface (installing a plugin) refuses identically here.
136
+ */
137
+ updateSettings(session: IProtocolSession, patch: TSettingsPatch, locality?: TCommandSurfaceLocality): TSettingsUpdateOutcome | Promise<TSettingsUpdateOutcome>;
138
+ }
139
+ declare function handleSettingsMessage(session: IProtocolSession, deliver: TOutboundDeliver, msg: TSettingsMessage, reporter: ISettingsReporter | undefined, locality?: TCommandSurfaceLocality): void;
98
140
  //#endregion
99
141
  //#region src/usage-messages.d.ts
100
142
  interface IUsageQueryReporters {
@@ -145,8 +187,8 @@ declare const PROTOCOL_SESSION_EVENT_CLASSIFICATION: {
145
187
  */
146
188
  type TSessionSurfaceRole = 'drive' | 'observe';
147
189
  interface ISessionMessageHandlerOptions {
148
- /** IProtocolSession to expose. */
149
- session: IProtocolSession;
190
+ /** IProtocolSession to expose — `Partial<ISessionProjectRead>` is probed, not assumed (#3282 §4c). */
191
+ session: TProjectReadCapableSession;
150
192
  /**
151
193
  * ARCH-030: the CARRIER's connection-scoped outbound delivery boundary — not a raw `send`, and not a
152
194
  * `send` plus an error callback for this handler to assemble into one. The carrier owns both the sink
@@ -173,6 +215,15 @@ interface ISessionMessageHandlerOptions {
173
215
  storedSessionUsageReporter?: NonNullable<IUsageQueryReporters['storedSessionUsageReporter']>;
174
216
  /** Host-owned session directory (#3189): list, start and switch the host's sessions. */
175
217
  sessionDirectory?: ISessionDirectory;
218
+ /** #3282 §4a: host-owned read/write for the GUI Settings screen. */
219
+ settingsReporter?: ISettingsReporter;
220
+ /**
221
+ * #3282 §4 part b-2: carrier-decided, like `role` — whether THIS carrier's connections are
222
+ * provably on this machine. The loopback WS carrier is `'local'`; the device-mesh/WebRTC carrier
223
+ * sets `'remote'`. Absent → `'local'`, forwarded to `executeCommand` and the settings reporter so a
224
+ * command that runs code from outside the session (installing a plugin) can refuse a remote device.
225
+ */
226
+ commandSurfaceLocality?: TCommandSurfaceLocality;
176
227
  }
177
228
  /**
178
229
  * Create a carrier-neutral message handler for an IProtocolSession.
@@ -302,6 +353,8 @@ interface ISessionResumeBridgeOptions {
302
353
  readonly personalUsageReporter?: IUsageQueryReporters['personalUsageReporter'];
303
354
  readonly usageReporter?: IUsageQueryReporters['usageReporter'];
304
355
  readonly storedSessionUsageReporter?: IUsageQueryReporters['storedSessionUsageReporter'];
356
+ /** #3282 §4 part b-2: this bridge is the reconnectable WebRTC path, so it is always `'remote'`. */
357
+ readonly commandSurfaceLocality?: TCommandSurfaceLocality;
305
358
  }
306
359
  declare class SessionResumeBridge {
307
360
  private readonly session;
@@ -309,6 +362,7 @@ declare class SessionResumeBridge {
309
362
  private driverId?;
310
363
  private readonly reporters;
311
364
  private readonly surface?;
365
+ private readonly commandSurfaceLocality?;
312
366
  private readonly unsubscribe;
313
367
  private onDeliveryError?;
314
368
  /**
@@ -536,5 +590,5 @@ declare class HandoffChunkAssembler {
536
590
  */
537
591
  declare function chunkCountFor(integrity: IHandoffIntegrity, maxChunkBytes?: number): number;
538
592
  //#endregion
539
- export { ATTACHED_SURFACE_MAX_PENDING_BYTES, CHANNEL_FRAME_MAGIC, CHANNEL_FRAME_VERSION, DEFAULT_MAX_CHUNK_BYTES, DEFAULT_MAX_PENDING_BYTES, DEFAULT_MAX_PENDING_MS, HandoffChunkAssembler, type IAttachOptions, type IBufferedFrame, type IChunkResult, type IHandoffChunk, type IPeerMessageLedger, type IPeerMessageRejection, type IPeerMessageVerdict, type IPendingStallClock, type IProtocolSession, type IResumeBufferOptions, type ISessionMessageHandlerOptions, type ISessionResumeBridgeOptions, type IWireHistoryEntry, MAX_INBOUND_FRAME_BYTES, PROTOCOL_SESSION_EVENT_CLASSIFICATION, ResumeBuffer, SessionResumeBridge, type TChunkOutcome, type TChunkRejection, type TClientMessage, type TDeliveryErrorHandler, type TMessageDecodeResult, type TOutboundDeliver, type TProtocolSessionEventClassification, type TResumeSink, type TResumeTail, type TSeqServerMessage, type TServerMessage, type TSessionSurfaceRole, type TWireExecutionResult, acknowledgePeerMessage, admitPeerMessage, chunkCountFor, chunkHandoffPayload, createOutboundDelivery, createPeerMessageLedger, createPendingStallClock, createSessionMessageHandler, decodeChannelFrame, decodeClientMessage, decodeFrame, decodeServerMessage, encodeBinaryFrame, encodeChannelEventFrame, forgetPeerOrigin, isChannelFrame, isObserverMessageType, isOverPendingBudget };
593
+ export { ATTACHED_SURFACE_MAX_PENDING_BYTES, CHANNEL_FRAME_MAGIC, CHANNEL_FRAME_VERSION, DEFAULT_MAX_CHUNK_BYTES, DEFAULT_MAX_PENDING_BYTES, DEFAULT_MAX_PENDING_MS, HandoffChunkAssembler, type IAttachOptions, type IBufferedFrame, type IChunkResult, type IHandoffChunk, type IPeerMessageLedger, type IPeerMessageRejection, type IPeerMessageVerdict, type IPendingStallClock, type IProtocolSession, type IResumeBufferOptions, type ISessionMessageHandlerOptions, type ISessionResumeBridgeOptions, type ISettingsReporter, type IWireAgentDefinitionSummary, type IWireHistoryEntry, MAX_INBOUND_FRAME_BYTES, PROTOCOL_SESSION_EVENT_CLASSIFICATION, ResumeBuffer, SessionResumeBridge, type TChunkOutcome, type TChunkRejection, type TClientMessage, type TDeliveryErrorHandler, type TMessageDecodeResult, type TOutboundDeliver, type TProtocolSessionEventClassification, type TResumeSink, type TResumeTail, type TSeqServerMessage, type TServerMessage, type TSessionSurfaceRole, type TSettingsUpdateOutcome, type TWireExecutionResult, acknowledgePeerMessage, admitPeerMessage, chunkCountFor, chunkHandoffPayload, createOutboundDelivery, createPeerMessageLedger, createPendingStallClock, createSessionMessageHandler, decodeChannelFrame, decodeClientMessage, decodeFrame, decodeServerMessage, encodeBinaryFrame, encodeChannelEventFrame, forgetPeerOrigin, handleSettingsMessage, isChannelFrame, isObserverMessageType, isOverPendingBudget, isSettingsMessage };
540
594
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/outbound-delivery.ts","../../src/protocol-session.ts","../../src/usage-messages.ts","../../src/session-events.ts","../../src/session-message-handler.ts","../../src/resume-buffer.ts","../../src/channel-frames.ts","../../src/session-resume-bridge.ts","../../src/peer-message-ledger.ts","../../src/handoff-chunking.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/outbound-delivery.ts","../../src/protocol-session.ts","../../src/settings-messages.ts","../../src/usage-messages.ts","../../src/session-events.ts","../../src/session-message-handler.ts","../../src/resume-buffer.ts","../../src/channel-frames.ts","../../src/session-resume-bridge.ts","../../src/peer-message-ledger.ts","../../src/handoff-chunking.ts"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as e,i as t,n,r,t as i}from"./observer-messages-Bx-xReUQ.js";import{isSessionChangeRefusal as a}from"@robota-sdk/agent-interface-session";function o(e,t,n){if(n.type===`get-background-tasks`){t({type:`background_tasks`,tasks:e.listBackgroundTasks(n.filter)});return}if(n.type===`get-background-task`){c(e,t,n);return}if(n.type===`get-background-job-groups`){t({type:`background_job_groups`,groups:e.listBackgroundJobGroups()});return}if(n.type===`get-background-job-group`){u(e,t,n);return}if(n.type===`wait-background-job-group`){d(e,t,n);return}l(e,t,n)}function s(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}if(n.type===`cancel-background-task`){p(t,`cancel`,n.taskId,e.cancelBackgroundTask(n.taskId,n.reason));return}if(n.type===`close-background-task`){p(t,`close`,n.taskId,e.closeBackgroundTask(n.taskId));return}f(e,t,n)}function c(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}t({type:`background_task`,taskId:n.taskId,task:e.getBackgroundTask(n.taskId)??null})}function l(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}e.readBackgroundTaskLog(n.taskId,n.cursor).then(e=>t({type:`background_task_log`,taskId:n.taskId,page:e}),e=>t({type:`protocol_error`,message:e.message}))}function u(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}t({type:`background_job_group`,groupId:n.groupId,group:e.getBackgroundJobGroup(n.groupId)??null})}function d(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}e.waitBackgroundJobGroup(n.groupId).then(e=>t({type:`background_job_group`,groupId:n.groupId,group:e}),e=>t({type:`protocol_error`,message:e.message}))}function f(e,t,n){if(!n.input){t({type:`protocol_error`,message:`input is required`});return}p(t,`send`,n.taskId,e.sendBackgroundTask(n.taskId,n.input))}function p(e,t,n,r){r.then(()=>e({type:`background_task_control_result`,action:t,taskId:n,success:!0}),r=>e({type:`background_task_control_result`,action:t,taskId:n,success:!1,message:r.message}))}function m(e){return e.type===`stop-waiting-loop`}function h(e,t,n){let{requestId:r}=n;e.stopWaitingSelfPacedLoop().then(e=>t({type:`waiting_loop_stop`,requestId:r,outcome:e}),e=>t({type:`waiting_loop_stop`,requestId:r,outcome:{kind:`failed`,message:g(e)}}))}function g(e){return e instanceof Error?e.message:String(e)}function _(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function v(e){return typeof e==`string`&&e.length>0?e:void 0}function y(e){if(!(new TextEncoder().encode(e).byteLength>4194304))try{let t=JSON.parse(e);if(!_(t))return;let n=v(t.requestId);if(!n)return;if(t.type===`get-personal-usage-report`)return{type:`personal`,requestId:n};let r=v(t.sessionId);return t.type===`get-stored-session-usage-report`&&r?{type:`stored-session`,requestId:n,sessionId:r}:void 0}catch{return}}function b(e,t,n,r){return n.type===`get-personal-usage-report`?(w(t,n,r.personalUsageReporter),!0):n.type===`get-stored-session-usage-report`?(S(t,n,r.storedSessionUsageReporter),!0):n.type===`get-usage-report`?(x(e,t,r.usageReporter),!0):!1}function x(e,t,n){if(!n){t({type:`protocol_error`,message:`Per-session usage reporting is not available on this host.`});return}try{Promise.resolve(n(e)).then(e=>t({type:`usage_report`,report:e}),e=>t({type:`protocol_error`,message:E(e)}))}catch(e){t({type:`protocol_error`,message:E(e instanceof Error?e:String(e))})}}function S(e,t,n){if(!n){C(e,t,`not_available`,`Stored-session usage reporting is not available on this host.`);return}try{Promise.resolve(n(t.sessionId)).then(n=>e({type:`stored_session_usage_report`,requestId:t.requestId,sessionId:t.sessionId,report:n}),n=>C(e,t,`report_failed`,E(n)))}catch(n){C(e,t,`report_failed`,E(n instanceof Error?n:String(n)))}}function C(e,t,n,r){e({type:`stored_session_usage_report_error`,requestId:t.requestId,sessionId:t.sessionId,code:n,message:r})}function w(e,t,n){if(!n){T(e,t.requestId,`not_available`,`Personal usage reporting is not available on this host.`);return}try{Promise.resolve(n({period:t.period,timezone:t.timezone})).then(n=>e({type:`personal_usage_report`,requestId:t.requestId,report:n}),n=>T(e,t.requestId,`report_failed`,E(n)))}catch(n){T(e,t.requestId,`report_failed`,E(n instanceof Error?n:String(n)))}}function T(e,t,n,r){e({type:`personal_usage_report_error`,requestId:t,code:n,message:r})}function E(e){return e instanceof Error?e.message:String(e)}function D(e,n){let i=t(e,r);if(i.ok)return i.message;let a=y(e);return a?.type===`personal`?(n({type:`personal_usage_report_error`,requestId:a.requestId,code:`report_failed`,message:`Invalid personal usage report request.`}),null):a?.type===`stored-session`?(n({type:`stored_session_usage_report_error`,requestId:a.requestId,sessionId:a.sessionId,code:`report_failed`,message:`Invalid stored-session usage report request.`}),null):(n({type:`protocol_error`,message:i.reason}),null)}function O(e){return e.type===`list-sessions`||e.type===`new-session`||e.type===`switch-session`}function k(e,t,n){if(t.type===`list-sessions`){A(e,t.requestId,n);return}let r=t.requestId===void 0?{}:{requestId:t.requestId};if(!n){e({type:`session_change_failed`,code:`not_available`,message:`Sessions cannot be switched on this host.`,...r});return}Promise.resolve().then(()=>t.type===`new-session`?n.newSession():n.switchSession(t.sessionId)).catch(t=>e({type:`session_change_failed`,code:a(t)?t.code:`failed`,message:j(t),...r}))}function A(e,t,n){if(!n){e({type:`sessions_error`,requestId:t,code:`not_available`,message:`Session listing is not available on this host.`});return}try{e({type:`sessions`,requestId:t,listing:n.listSessions()})}catch(n){e({type:`sessions_error`,requestId:t,code:`list_failed`,message:j(n instanceof Error?n:String(n))})}}function j(e){return e instanceof Error?e.message:String(e)}const M=new WeakMap;function ee(e){let t=M.get(e);t===void 0&&(t={frames:new Map,holders:0},M.set(e,t));let n=t;n.holders+=1;let r=!1;return{record:e=>{r||n.frames.set(e.event.id,e)},forget:e=>{n.frames.delete(e)},clear:()=>{n.frames.clear()},release:()=>{r||(r=!0,--n.holders,n.holders===0&&M.get(e)===n&&M.delete(e))}}}function te(e){return[...M.get(e)?.frames.values()??[]]}const ne={text_delta:`forwarded`,tool_start:`forwarded`,tool_end:`forwarded`,thinking:`forwarded`,complete:`forwarded`,error:`forwarded`,context_update:`forwarded`,compact:`forwarded`,interrupted:`forwarded`,skill_activation:`forwarded`,background_task_event:`forwarded`,background_job_group_event:`forwarded`,execution_workspace_event:`forwarded`,user_message:`forwarded`,turn_source:`forwarded`,context_file_refreshed:`forwarded`,memory_event:`forwarded`,goal_event:`non-surface`,plan_event:`forwarded`,branch_event:`forwarded`,permission_request:`forwarded`,ask_request:`forwarded`,prompt_resolved:`forwarded`,ui_intent:`requester-routed`,session_renamed:`forwarded`,history_cleared:`forwarded`,session_switched:`forwarded`,status_changed:`forwarded`};function N(e,t,n={}){let r=()=>{let t=e.getActiveDriverId();return t?{driverId:t}:{}},i=e=>t({type:`user_message`,content:e,...r()}),a=e=>t({type:`text_delta`,delta:e,...r()}),o=e=>t({type:`tool_start`,state:e,...r()}),s=e=>t({type:`tool_end`,state:e,...r()}),c=e=>t({type:`thinking`,isThinking:e,...r()}),l=e=>t({type:`complete`,result:P(e),...r()}),u=e=>t({type:`interrupted`,result:P(e),...r()}),d=e=>t({type:`error`,message:e.message,...r()}),f=e=>t({type:`background_task_event`,event:e}),p=e=>t({type:`background_job_group_event`,event:e}),m=e=>t({type:`execution_workspace_event`,snapshot:e.snapshot}),h=e=>t({type:`plan_event`,event:e}),g=e=>t({type:`context_file_refreshed`,event:e}),_=e=>t({type:`branch_event`,event:e}),v=n.receivePrompts??!0,y=v?ee(e):void 0,b=e=>{let n={type:`permission_request`,event:e};y?.record(n),t(n)},x=e=>{let n={type:`ask_request`,event:e};y?.record(n),t(n)},S=e=>{y?.forget(e.id),t({type:`prompt_resolved`,event:e})},C=e=>{(e.requesterDriverId===void 0||e.requesterDriverId===n.getSurfaceDriverId?.())&&t({type:`ui_intent`,event:e})},w=e=>t({type:`session_renamed`,event:e}),T=()=>t({type:`history_cleared`}),E=e=>{y?.clear(),t({type:`session_switched`,event:e})},D=e=>t({type:`context`,state:e}),O=()=>t({type:`history_changed`}),k=e=>t({type:`turn_source`,source:e}),A=e=>t({type:`session_status`,status:e});return e.on(`user_message`,i),e.on(`text_delta`,a),e.on(`tool_start`,o),e.on(`tool_end`,s),e.on(`thinking`,c),e.on(`complete`,l),e.on(`interrupted`,u),e.on(`error`,d),e.on(`background_task_event`,f),e.on(`background_job_group_event`,p),e.on(`execution_workspace_event`,m),e.on(`plan_event`,h),e.on(`context_file_refreshed`,g),e.on(`branch_event`,_),v&&(e.on(`permission_request`,b),e.on(`ask_request`,x)),e.on(`prompt_resolved`,S),e.on(`ui_intent`,C),e.on(`session_renamed`,w),e.on(`history_cleared`,T),e.on(`session_switched`,E),e.on(`context_update`,D),e.on(`compact`,O),e.on(`skill_activation`,O),e.on(`memory_event`,O),e.on(`turn_source`,k),e.on(`status_changed`,A),()=>{e.off(`user_message`,i),e.off(`text_delta`,a),e.off(`tool_start`,o),e.off(`tool_end`,s),e.off(`thinking`,c),e.off(`complete`,l),e.off(`interrupted`,u),e.off(`error`,d),e.off(`background_task_event`,f),e.off(`background_job_group_event`,p),e.off(`execution_workspace_event`,m),e.off(`plan_event`,h),e.off(`context_file_refreshed`,g),e.off(`branch_event`,_),v&&(e.off(`permission_request`,b),e.off(`ask_request`,x)),e.off(`prompt_resolved`,S),e.off(`ui_intent`,C),e.off(`session_renamed`,w),e.off(`history_cleared`,T),e.off(`session_switched`,E),e.off(`context_update`,D),e.off(`compact`,O),e.off(`skill_activation`,O),e.off(`memory_event`,O),e.off(`turn_source`,k),e.off(`status_changed`,A),y?.release()}}function P(e){let{history:t,...n}=e;return n}const re=new TextEncoder;function ie(e){return e.type===`get-messages`||e.type===`get-history`||e.type===`get-prompts`||e.type===`get-context`||e.type===`get-commands`||e.type===`get-status`||e.type===`get-executing`||e.type===`get-pending`||e.type===`get-execution-workspace`||e.type===`read-execution-detail`}function ae(e,t,n){if(n.type===`get-messages`)t({type:`messages`,messages:e.getMessages()});else if(n.type===`get-history`)t(se(e,n.fromIndex??0));else if(n.type===`get-prompts`)for(let n of te(e))t(n);else n.type===`get-context`?t({type:`context`,state:e.getContextState()}):n.type===`get-commands`?t({type:`commands`,commands:e.listCommands(),skills:e.listSkills()}):n.type===`get-status`?t({type:`session_status`,status:e.getStatusSnapshot()}):n.type===`get-executing`?t({type:`executing`,executing:e.isExecuting()}):n.type===`get-execution-workspace`?t({type:`execution_workspace_event`,snapshot:e.getExecutionWorkspaceSnapshot()}):n.type===`read-execution-detail`?oe(e,t,n):t(F(e))}function oe(e,t,n){let{requestId:r}=n;e.readExecutionWorkspaceDetail(n.entryId,n.cursor).then(e=>t({type:`execution_detail`,requestId:r,page:e}),e=>t({type:`execution_detail_error`,requestId:r,message:e instanceof Error?e.message:String(e)}))}function F(e){return{type:`pending`,pending:e.getPendingPrompt(),pendingCount:e.getPendingCount()}}function se(e,t){let n=e.getFullHistory(),r=n.length,i=Math.min(t,r),a=[],o=0;for(let e=i;e<r;e+=1){let t=ce(n[e]),r=re.encode(JSON.stringify(t)).byteLength;if(a.length>0&&o+r>262144)break;a.push(t),o+=r}return{type:`history`,startIndex:i,total:r,entries:a}}function ce(e){return{...e,timestamp:le(e.timestamp)}}function le(e){return typeof e==`string`?e:e.toISOString()}function ue(e){let t=e.role??`drive`,n=N(e.session,e.deliver,{getSurfaceDriverId:()=>e.driverId,receivePrompts:t===`drive`});return{onMessage:de(e.session,e.deliver,e.driverId,{personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},e.surface,t,e.sessionDirectory),cleanup:n}}function de(e,t,n,r=I,a,o=`drive`,s){return c=>{let l=D(c,t);if(l){if(o===`observe`&&!i(l.type)){t({type:`protocol_error`,message:`Not permitted for an observer: ${l.type}`});return}L(e,t,l,n,r,a,s)}}}const I={personalUsageReporter:void 0,usageReporter:void 0,storedSessionUsageReporter:void 0};function L(e,t,n,r,i=I,a,c){if(b(e,t,n,i))return;if(O(n)){k(t,n,c);return}if(fe(n)){_e(e,t,n,r,a);return}if(m(n)){h(e,t,n);return}if(ie(n)){ae(e,t,n);return}if(pe(n)){o(e,t,n);return}if(me(n)){s(e,t,n);return}if(he(n)){ge(e,n,r);return}let l=n.type;t({type:`protocol_error`,message:`Unknown message type: ${l}`})}function fe(e){return e.type===`submit`||e.type===`command`||e.type===`abort`||e.type===`cancel-queue`}function pe(e){return e.type===`get-background-tasks`||e.type===`get-background-task`||e.type===`read-background-task-log`||e.type===`get-background-job-groups`||e.type===`get-background-job-group`||e.type===`wait-background-job-group`}function me(e){return e.type===`cancel-background-task`||e.type===`close-background-task`||e.type===`send-background-task`}function he(e){return e.type===`permission-response`||e.type===`ask-response`}function ge(e,t,n){t.type===`permission-response`?e.resolvePermission(t.id,t.result,n):e.resolveAsk(t.id,t.response,n)}function _e(e,t,n,r,i){if(n.type===`submit`){if(typeof n.prompt!=`string`||n.prompt.length===0){t({type:`protocol_error`,message:`prompt must be a non-empty string`});return}let a={...r?{driverId:r}:{},...i?{surface:i}:{}};e.submit(n.prompt,void 0,void 0,Object.keys(a).length>0?a:void 0).then(()=>t(F(e)),e=>t({type:`protocol_error`,message:e.message}))}else if(n.type===`command`){let i=n.requestId===void 0?{}:{requestId:n.requestId};if(!n.name){t({type:`protocol_error`,message:`name is required`,...i});return}e.executeCommand(n.name,n.args??``,`remote`,r).then(e=>{t({type:`command_result`,name:n.name,message:e?.message??`Unknown command: ${n.name}`,success:e?.success??!1,data:e?.data,...i})},e=>{t({type:`protocol_error`,message:e.message,...i})})}else n.type===`abort`?e.abort():e.cancelQueue()}const R=1024*1024,z=8*R,ve=R;function B(e,t=z){return e!==void 0&&e>t}const V=120*1e3;function H(e=V,t=Date.now){let n;return{maxPendingMs:e,observe(r){if(r===void 0)return;if(r===0){n=void 0;return}let i=t();n??=i;let a=i-n;return a>e?a:void 0}}}function U(e,t,n,r=z,i=H()){let a=!1,o=t=>{if(a)return;let o=n?.();if(B(o,r)){a=!0,s(Error(`outbound backpressure budget exceeded: ${o} byte(s) pending, limit ${r}. The peer has accepted frames it is not reading.`),t.type);return}let c=i.observe(o);if(c!==void 0){a=!0,s(Error(`outbound drain budget exceeded: ${o} byte(s) pending for ${c} ms, limit ${i.maxPendingMs} ms. The peer is reading too slowly to ever drain what it accepted.`),t.type);return}try{e(t)}catch(e){a=!0,s(e instanceof Error?e:Error(String(e)),t.type)}};function s(e,n){try{t(e,n)}catch{}}return Object.assign(o,{pendingBytes:()=>n?.()})}var W=class{frames=[];sizes=[];nextSeq=1;bytes=0;maxFrames;maxBytes;sizeOf;constructor(e={}){this.maxFrames=e.maxFrames??512,this.maxBytes=e.maxBytes??4194304,this.sizeOf=e.sizeOf??(e=>JSON.stringify(e).length)}append(e){let t=this.nextSeq;this.nextSeq+=1;let n=this.sizeOf(e);return this.frames.push({seq:t,message:e}),this.sizes.push(n),this.bytes+=n,this.evict(),t}ackThrough(e){let t=0;for(;t<this.frames.length&&this.frames[t].seq<=e;)t+=1;this.removeOldest(t)}tailAfter(e){return this.frames.length===0?e>=this.nextSeq-1?{kind:`tail`,frames:[]}:{kind:`overrun`}:e<this.frames[0].seq-1?{kind:`overrun`}:{kind:`tail`,frames:this.frames.filter(t=>t.seq>e)}}get lastSeq(){return this.nextSeq-1}get size(){return this.frames.length}evict(){let e=0,t=this.bytes;for(;this.frames.length-e>this.maxFrames||t>this.maxBytes&&this.frames.length-e>1;)t-=this.sizes[e],e+=1;this.removeOldest(e)}removeOldest(e){if(!(e<=0)){for(let t=0;t<e;t+=1)this.bytes-=this.sizes[t]??0;this.frames.splice(0,e),this.sizes.splice(0,e),this.frames.length===0&&(this.bytes=0)}}};const G=new TextEncoder,K=new TextDecoder,q=G.encode(`RBF`),ye=1,J=4294967295;function Y(e,t){let n=G.encode(e);if(n.byteLength===0||n.byteLength>255)throw Error(`channel name must be 1..255 UTF-8 bytes (got ${n.byteLength})`);if(!Number.isInteger(t)||t<0||t>J)throw Error(`seq must be an integer in 0..${J} (got ${t})`);return n}function X(e,t,n,r){e.set(q,0),e[3]=1,e[4]=t,e[5]=n.byteLength,e.set(n,6);let i=6+n.byteLength;return new DataView(e.buffer,e.byteOffset,e.byteLength).setUint32(i,r,!1),i+4}function be(e){let t=Y(e.channel,e.seq),n=new Uint8Array(6+t.byteLength+4+e.payload.byteLength),r=X(n,1,t,e.seq);return n.set(e.payload,r),n}function xe(e){let t=Y(e.channel,e.seq),n=G.encode(JSON.stringify({event:e.event,payload:e.payload})),r=new Uint8Array(6+t.byteLength+4+n.byteLength),i=X(r,2,t,e.seq);return r.set(n,i),r}function Z(e){return e.byteLength<q.length?!1:q.every((t,n)=>e[n]===t)}function Se(e){let t=K.decode(e),n;try{n=JSON.parse(t)}catch{return{ok:!1,error:`channel frame: malformed JSON body`}}if(typeof n!=`object`||!n||Array.isArray(n))return{ok:!1,error:`channel frame: event body must be a JSON object`};let{event:r,payload:i}=n;return typeof r!=`string`||r.length===0?{ok:!1,error:"channel frame: event body is missing a non-empty `event` name"}:{ok:!0,event:r,payload:i??null}}function Ce(e){if(!Z(e))return{ok:!1,error:`channel frame: bad magic (not a channel frame)`};if(e.byteLength<6)return{ok:!1,error:`channel frame: truncated header`};if(e[3]!==1)return{ok:!1,error:`channel frame: unsupported version ${String(e[3])}`};let t=e[4],n=e[5]??0;if(n===0)return{ok:!1,error:`channel frame: empty channel name`};let r=6+n,i=r+4;if(e.byteLength<i)return{ok:!1,error:`channel frame: truncated (header longer than the frame)`};let a=K.decode(e.subarray(6,r)),o=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(r,!1),s=e.subarray(i);if(t===1)return{ok:!0,frame:{kind:`binary`,channel:a,seq:o,payload:Uint8Array.from(s)}};if(t===2){let e=Se(s);return e.ok?{ok:!0,frame:{kind:`event`,channel:a,seq:o,event:e.event,payload:e.payload}}:{ok:!1,error:e.error}}return{ok:!1,error:`channel frame: unknown kind ${String(t)}`}}var we=class{session;buffer;driverId;reporters;surface;unsubscribe;onDeliveryError;outbound;emitBoundary;disposed=!1;holding=!1;constructor(e){this.session=e.session,this.buffer=new W(e.buffer),this.driverId=e.driverId,this.surface=e.surface,this.reporters={personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},this.emitBoundary=U(e=>this.emit(e),(e,t)=>this.reportDeliveryError(e,t)),this.unsubscribe=N(this.session,this.emitBoundary,{getSurfaceDriverId:()=>this.driverId})}attach(e,t){this.disposed||(this.onDeliveryError=t.onDeliveryError,this.outbound=U(t=>e(JSON.stringify(t)),(e,t)=>this.reportDeliveryError(e,t),t.pendingBytes),this.holding=t.awaitResume===!0)}detach(){this.outbound=void 0,this.onDeliveryError=void 0}setDriverId(e){this.driverId=e}onClientMessage(e){if(this.disposed)return;let t=D(e,this.emitBoundary);if(t){if(t.type===`resume`){this.replay(t.lastSeq);return}if(t.type===`ack`){this.buffer.ackThrough(t.seq);return}L(this.session,this.emitBoundary,t,this.driverId,this.reporters,this.surface)}}dispose(){this.disposed||(this.disposed=!0,this.detach(),this.unsubscribe())}get lastSeq(){return this.buffer.lastSeq}emit(e){if(this.disposed)return;let t=this.buffer.append(e);this.holding||this.deliverFrame({...e,seq:t})}replay(e){let t=this.buffer.tailAfter(e);if(t.kind===`overrun`){this.deliverFrame({type:`resume_gap`}),this.holding=!1;return}for(let e of t.frames)this.deliverFrame({...e.message,seq:e.seq});this.holding=!1}deliverFrame(e){this.outbound?.(e)}reportDeliveryError(e,t){let n=this.onDeliveryError;this.detach();try{n?.(e,t)}catch{}}};function Q(){return{origins:new Map}}function Te(e,t,n){let r=t.origin.sessionId,i=e.origins.get(r);i===void 0&&(i={highestSequence:0,delivered:new Set,issued:new Map},e.origins.set(r,i));let a=i.issued.get(t.id);if(a!==void 0)return{ack:{...a,state:`duplicate`},deliver:!1};if(n!==void 0){let e={id:t.id,sequence:t.sequence,state:n.state,reason:n.reason};return i.issued.set(t.id,e),{ack:e,deliver:!1}}if(i.delivered.has(t.sequence)){let e={id:t.id,sequence:t.sequence,state:`refused`,reason:`sequence ${t.sequence} was already delivered by this origin under a different message id. A retry must repeat its id; a new id on a delivered sequence cannot be ordered against what the receiver already has.`};return i.issued.set(t.id,e),{ack:e,deliver:!1}}let o=i.highestSequence+1,s=t.sequence>o?o:void 0,c={id:t.id,sequence:t.sequence,state:`delivered`};return i.issued.set(t.id,c),i.delivered.add(t.sequence),i.highestSequence=Math.max(i.highestSequence,t.sequence),s===void 0?{ack:c,deliver:!0}:{ack:c,deliver:!0,gapBefore:s}}function Ee(e,t,n){let r=e.origins.get(t),i=r?.issued.get(n);if(r===void 0||i===void 0||i.state!==`delivered`)return;let a={...i,state:`acknowledged`};return r.issued.set(n,a),a}function De(e,t){e.origins.delete(t)}const $=16*1024;function Oe(e,t,n=$){if(!Number.isInteger(n)||n<1)throw Error(`handoff chunking: maxChunkBytes must be a positive integer, got ${n}. A zero or negative budget produces an infinite sequence of empty chunks, which presents as a hang rather than as the configuration error it is.`);let r=Buffer.from(t,`utf8`),i=Math.max(1,Math.ceil(r.byteLength/n)),a=[];for(let t=0;t<i;t+=1){let o=r.subarray(t*n,(t+1)*n);a.push({handoffId:e,index:t,total:i,data:o.toString(`base64`)})}return a}var ke=class{handoffId;chunks=new Map;declaredTotal;constructor(e){this.handoffId=e}get received(){return this.chunks.size}get expected(){return this.declaredTotal}accept(e){let t=e=>({outcome:`refused`,rejection:e,received:this.chunks.size,...this.declaredTotal===void 0?{}:{expected:this.declaredTotal}});if(e.handoffId!==this.handoffId)return t(`wrong-handoff`);if(!Number.isInteger(e.total)||e.total<1||this.declaredTotal!==void 0&&e.total!==this.declaredTotal)return t(`inconsistent-total`);if(!Number.isInteger(e.index)||e.index<0||e.index>=e.total)return t(`out-of-range`);let n=Buffer.from(e.data,`base64`);if(n.toString(`base64`)!==e.data)return t(`undecodable`);this.declaredTotal=e.total;let r=this.chunks.get(e.index);return r===void 0?(this.chunks.set(e.index,n),this.chunks.size<e.total?{outcome:`accepted`,received:this.chunks.size,expected:e.total}:{outcome:`complete`,serialized:this.reassemble(e.total),received:this.chunks.size,expected:e.total}):r.equals(n)?{outcome:`duplicate`,received:this.chunks.size,expected:e.total}:t(`inconsistent-total`)}missing(){if(this.declaredTotal===void 0)return[];let e=[];for(let t=0;t<this.declaredTotal;t+=1)this.chunks.has(t)||e.push(t);return e}discard(){this.chunks.clear(),this.declaredTotal=void 0}reassemble(e){let t=[];for(let n=0;n<e;n+=1){let r=this.chunks.get(n);if(r===void 0)throw Error(`handoff chunking: chunk ${n} of ${e} is missing at reassembly.`);t.push(r)}return Buffer.concat(t).toString(`utf8`)}};function Ae(e,t=$){return Math.max(1,Math.ceil(e.byteLength/t))}export{ve as ATTACHED_SURFACE_MAX_PENDING_BYTES,q as CHANNEL_FRAME_MAGIC,ye as CHANNEL_FRAME_VERSION,$ as DEFAULT_MAX_CHUNK_BYTES,z as DEFAULT_MAX_PENDING_BYTES,V as DEFAULT_MAX_PENDING_MS,ke as HandoffChunkAssembler,n as MAX_INBOUND_FRAME_BYTES,ne as PROTOCOL_SESSION_EVENT_CLASSIFICATION,W as ResumeBuffer,we as SessionResumeBridge,Ee as acknowledgePeerMessage,Te as admitPeerMessage,Ae as chunkCountFor,Oe as chunkHandoffPayload,U as createOutboundDelivery,Q as createPeerMessageLedger,H as createPendingStallClock,ue as createSessionMessageHandler,Ce as decodeChannelFrame,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,be as encodeBinaryFrame,xe as encodeChannelEventFrame,De as forgetPeerOrigin,Z as isChannelFrame,i as isObserverMessageType,B as isOverPendingBudget};
1
+ import{a as e,i as t,n,r,t as i}from"./observer-messages-CEeisRaF.js";import{isSessionChangeRefusal as a,isSessionDeleteRefusal as o}from"@robota-sdk/agent-interface-session";import{AuthenticationError as s,ModelNotAvailableError as c,NetworkError as l,ProviderError as u,RateLimitError as d}from"@robota-sdk/agent-core";function f(e,t,n){if(n.type===`get-background-tasks`){t({type:`background_tasks`,tasks:e.listBackgroundTasks(n.filter)});return}if(n.type===`get-background-task`){m(e,t,n);return}if(n.type===`get-background-job-groups`){t({type:`background_job_groups`,groups:e.listBackgroundJobGroups()});return}if(n.type===`get-background-job-group`){g(e,t,n);return}if(n.type===`wait-background-job-group`){_(e,t,n);return}h(e,t,n)}function p(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}if(n.type===`cancel-background-task`){y(t,`cancel`,n.taskId,e.cancelBackgroundTask(n.taskId,n.reason));return}if(n.type===`close-background-task`){y(t,`close`,n.taskId,e.closeBackgroundTask(n.taskId));return}v(e,t,n)}function m(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}t({type:`background_task`,taskId:n.taskId,task:e.getBackgroundTask(n.taskId)??null})}function h(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}e.readBackgroundTaskLog(n.taskId,n.cursor).then(e=>t({type:`background_task_log`,taskId:n.taskId,page:e}),e=>t({type:`protocol_error`,message:e.message}))}function g(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}t({type:`background_job_group`,groupId:n.groupId,group:e.getBackgroundJobGroup(n.groupId)??null})}function _(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}e.waitBackgroundJobGroup(n.groupId).then(e=>t({type:`background_job_group`,groupId:n.groupId,group:e}),e=>t({type:`protocol_error`,message:e.message}))}function v(e,t,n){if(!n.input){t({type:`protocol_error`,message:`input is required`});return}y(t,`send`,n.taskId,e.sendBackgroundTask(n.taskId,n.input))}function y(e,t,n,r){r.then(()=>e({type:`background_task_control_result`,action:t,taskId:n,success:!0}),r=>e({type:`background_task_control_result`,action:t,taskId:n,success:!1,message:r.message}))}function b(e){return e.type===`stop-waiting-loop`}function x(e,t,n){let{requestId:r}=n;e.stopWaitingSelfPacedLoop().then(e=>t({type:`waiting_loop_stop`,requestId:r,outcome:e}),e=>t({type:`waiting_loop_stop`,requestId:r,outcome:{kind:`failed`,message:S(e)}}))}function S(e){return e instanceof Error?e.message:String(e)}function C(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function w(e){return typeof e==`string`&&e.length>0?e:void 0}function T(e){if(!(new TextEncoder().encode(e).byteLength>4194304))try{let t=JSON.parse(e);if(!C(t))return;let n=w(t.requestId);if(!n)return;if(t.type===`get-personal-usage-report`)return{type:`personal`,requestId:n};let r=w(t.sessionId);return t.type===`get-stored-session-usage-report`&&r?{type:`stored-session`,requestId:n,sessionId:r}:void 0}catch{return}}function E(e,t,n,r){return n.type===`get-personal-usage-report`?(A(t,n,r.personalUsageReporter),!0):n.type===`get-stored-session-usage-report`?(O(t,n,r.storedSessionUsageReporter),!0):n.type===`get-usage-report`?(D(e,t,r.usageReporter),!0):!1}function D(e,t,n){if(!n){t({type:`protocol_error`,message:`Per-session usage reporting is not available on this host.`});return}try{Promise.resolve(n(e)).then(e=>t({type:`usage_report`,report:e}),e=>t({type:`protocol_error`,message:M(e)}))}catch(e){t({type:`protocol_error`,message:M(e instanceof Error?e:String(e))})}}function O(e,t,n){if(!n){k(e,t,`not_available`,`Stored-session usage reporting is not available on this host.`);return}try{Promise.resolve(n(t.sessionId)).then(n=>e({type:`stored_session_usage_report`,requestId:t.requestId,sessionId:t.sessionId,report:n}),n=>k(e,t,`report_failed`,M(n)))}catch(n){k(e,t,`report_failed`,M(n instanceof Error?n:String(n)))}}function k(e,t,n,r){e({type:`stored_session_usage_report_error`,requestId:t.requestId,sessionId:t.sessionId,code:n,message:r})}function A(e,t,n){if(!n){j(e,t.requestId,`not_available`,`Personal usage reporting is not available on this host.`);return}try{Promise.resolve(n({period:t.period,timezone:t.timezone})).then(n=>e({type:`personal_usage_report`,requestId:t.requestId,report:n}),n=>j(e,t.requestId,`report_failed`,M(n)))}catch(n){j(e,t.requestId,`report_failed`,M(n instanceof Error?n:String(n)))}}function j(e,t,n,r){e({type:`personal_usage_report_error`,requestId:t,code:n,message:r})}function M(e){return e instanceof Error?e.message:String(e)}function ee(e,n){let i=t(e,r);if(i.ok)return i.message;let a=T(e);return a?.type===`personal`?(n({type:`personal_usage_report_error`,requestId:a.requestId,code:`report_failed`,message:`Invalid personal usage report request.`}),null):a?.type===`stored-session`?(n({type:`stored_session_usage_report_error`,requestId:a.requestId,sessionId:a.sessionId,code:`report_failed`,message:`Invalid stored-session usage report request.`}),null):(n({type:`protocol_error`,message:i.reason}),null)}function te(e){return e.type===`project-status`||e.type===`project-diff`||e.type===`project-memory`}function N(e,t){e({type:`protocol_error`,message:`This host does not support the Project panel.`,requestId:t})}function ne(e,t,n){let{requestId:r}=n;if(n.type===`project-status`){if(!e.readProjectStatus)return N(t,r);e.readProjectStatus().then(e=>t({type:`project_status`,requestId:r,result:e}),e=>t({type:`project_status`,requestId:r,result:{kind:`failed`,message:e instanceof Error?e.message:String(e)}}))}else if(n.type===`project-diff`){if(!e.readProjectDiff)return N(t,r);e.readProjectDiff(n.path).then(e=>t({type:`project_diff`,requestId:r,result:e}),e=>t({type:`project_diff`,requestId:r,result:{kind:`failed`,message:e instanceof Error?e.message:String(e)}}))}else{if(!e.readProjectMemory)return N(t,r);e.readProjectMemory().then(e=>t({type:`project_memory`,requestId:r,result:e}),e=>t({type:`project_memory`,requestId:r,result:{kind:`unavailable`,message:e instanceof Error?e.message:String(e)}}))}}function re(e){return e.type===`list-sessions`||e.type===`new-session`||e.type===`switch-session`}function ie(e){return e.type===`rename-session`}function ae(e){return e.type===`delete-session`}function oe(e,t,n){if(t.type===`list-sessions`){se(e,t.requestId,n);return}let r=t.requestId===void 0?{}:{requestId:t.requestId};if(!n){e({type:`session_change_failed`,code:`not_available`,message:`Sessions cannot be switched on this host.`,...r});return}Promise.resolve().then(()=>t.type===`new-session`?n.newSession():n.switchSession(t.sessionId)).catch(t=>e({type:`session_change_failed`,code:a(t)?t.code:`failed`,message:P(t),...r}))}function se(e,t,n){if(!n){e({type:`sessions_error`,requestId:t,code:`not_available`,message:`Session listing is not available on this host.`});return}try{e({type:`sessions`,requestId:t,listing:n.listSessions()})}catch(n){e({type:`sessions_error`,requestId:t,code:`list_failed`,message:P(n instanceof Error?n:String(n))})}}function P(e){return e instanceof Error?e.message:String(e)}function ce(e,t,n){if(!n){e({type:`session_rename_failed`,requestId:t.requestId,message:`Sessions cannot be renamed on this host.`});return}n.renameSession(t.sessionId,t.name).then(()=>e({type:`session_renamed_in_list`,requestId:t.requestId,sessionId:t.sessionId,name:t.name}),n=>e({type:`session_rename_failed`,requestId:t.requestId,message:P(n)}))}function le(e,t,n){if(!n){e({type:`session_delete_failed`,requestId:t.requestId,code:`not_available`,message:`Sessions cannot be deleted on this host.`});return}n.deleteSession(t.sessionId).then(()=>e({type:`session_deleted`,requestId:t.requestId,sessionId:t.sessionId}),n=>e({type:`session_delete_failed`,requestId:t.requestId,code:o(n)?n.code:`failed`,message:P(n)}))}const F=new WeakMap;function ue(e){let t=F.get(e);t===void 0&&(t={frames:new Map,holders:0},F.set(e,t));let n=t;n.holders+=1;let r=!1;return{record:e=>{r||n.frames.set(e.event.id,e)},forget:e=>{n.frames.delete(e)},clear:()=>{n.frames.clear()},release:()=>{r||(r=!0,--n.holders,n.holders===0&&F.get(e)===n&&F.delete(e))}}}function de(e){return[...F.get(e)?.frames.values()??[]]}function fe(e){let t=[],n=new Set,r=[e];for(let e=0;e<=8&&r.length>0;e++){let e=[];for(let i of r)if(!(i==null||n.has(i))&&(n.add(i),t.push(i),typeof i==`object`)){let t=i;e.push(t.originalError,t.cause)}r=e}return t}function pe(e){let t;for(let n of fe(e)){if(n instanceof s)return{code:`auth`,...n.provider!==void 0&&{provider:n.provider}};if(n instanceof d)return{code:`rate_limit`,...n.provider!==void 0&&{provider:n.provider},...n.retryAfter!==void 0&&{retryAfterSeconds:n.retryAfter}};if(n instanceof c)return{code:`model_unavailable`,provider:n.provider,...n.model!==void 0&&{model:n.model}};if(n instanceof l)return{code:`network`,...n.provider!==void 0&&{provider:n.provider}};t===void 0&&n instanceof u&&(t={code:`provider`,provider:n.provider})}return t??{}}const me={text_delta:`forwarded`,tool_start:`forwarded`,tool_end:`forwarded`,thinking:`forwarded`,complete:`forwarded`,error:`forwarded`,context_update:`forwarded`,compact:`forwarded`,interrupted:`forwarded`,skill_activation:`forwarded`,background_task_event:`forwarded`,background_job_group_event:`forwarded`,execution_workspace_event:`forwarded`,user_message:`forwarded`,turn_source:`forwarded`,context_file_refreshed:`forwarded`,memory_event:`forwarded`,goal_event:`non-surface`,plan_event:`forwarded`,branch_event:`forwarded`,permission_request:`forwarded`,ask_request:`forwarded`,prompt_resolved:`forwarded`,ui_intent:`requester-routed`,session_renamed:`forwarded`,history_cleared:`forwarded`,session_switched:`forwarded`,status_changed:`forwarded`};function he(e,t,n={}){let r=()=>{let t=e.getActiveDriverId();return t?{driverId:t}:{}},i=e=>t({type:`user_message`,content:e,...r()}),a=e=>t({type:`text_delta`,delta:e,...r()}),o=e=>t({type:`tool_start`,state:e,...r()}),s=e=>t({type:`tool_end`,state:e,...r()}),c=e=>t({type:`thinking`,isThinking:e,...r()}),l=e=>t({type:`complete`,result:I(e),...r()}),u=e=>t({type:`interrupted`,result:I(e),...r()}),d=e=>t({type:`error`,message:e.message,...pe(e),...r()}),f=e=>t({type:`background_task_event`,event:e}),p=e=>t({type:`background_job_group_event`,event:e}),m=e=>t({type:`execution_workspace_event`,snapshot:e.snapshot}),h=e=>t({type:`plan_event`,event:e}),g=e=>t({type:`context_file_refreshed`,event:e}),_=e=>t({type:`branch_event`,event:e}),v=n.receivePrompts??!0,y=v?ue(e):void 0,b=e=>{let n={type:`permission_request`,event:e};y?.record(n),t(n)},x=e=>{let n={type:`ask_request`,event:e};y?.record(n),t(n)},S=e=>{y?.forget(e.id),t({type:`prompt_resolved`,event:e})},C=e=>{(e.requesterDriverId===void 0||e.requesterDriverId===n.getSurfaceDriverId?.())&&t({type:`ui_intent`,event:e})},w=e=>t({type:`session_renamed`,event:e}),T=()=>t({type:`history_cleared`}),E=e=>{y?.clear(),t({type:`session_switched`,event:e})},D=e=>t({type:`context`,state:e}),O=()=>t({type:`history_changed`}),k=e=>t({type:`turn_source`,source:e}),A=e=>t({type:`session_status`,status:e});return e.on(`user_message`,i),e.on(`text_delta`,a),e.on(`tool_start`,o),e.on(`tool_end`,s),e.on(`thinking`,c),e.on(`complete`,l),e.on(`interrupted`,u),e.on(`error`,d),e.on(`background_task_event`,f),e.on(`background_job_group_event`,p),e.on(`execution_workspace_event`,m),e.on(`plan_event`,h),e.on(`context_file_refreshed`,g),e.on(`branch_event`,_),v&&(e.on(`permission_request`,b),e.on(`ask_request`,x)),e.on(`prompt_resolved`,S),e.on(`ui_intent`,C),e.on(`session_renamed`,w),e.on(`history_cleared`,T),e.on(`session_switched`,E),e.on(`context_update`,D),e.on(`compact`,O),e.on(`skill_activation`,O),e.on(`memory_event`,O),e.on(`turn_source`,k),e.on(`status_changed`,A),()=>{e.off(`user_message`,i),e.off(`text_delta`,a),e.off(`tool_start`,o),e.off(`tool_end`,s),e.off(`thinking`,c),e.off(`complete`,l),e.off(`interrupted`,u),e.off(`error`,d),e.off(`background_task_event`,f),e.off(`background_job_group_event`,p),e.off(`execution_workspace_event`,m),e.off(`plan_event`,h),e.off(`context_file_refreshed`,g),e.off(`branch_event`,_),v&&(e.off(`permission_request`,b),e.off(`ask_request`,x)),e.off(`prompt_resolved`,S),e.off(`ui_intent`,C),e.off(`session_renamed`,w),e.off(`history_cleared`,T),e.off(`session_switched`,E),e.off(`context_update`,D),e.off(`compact`,O),e.off(`skill_activation`,O),e.off(`memory_event`,O),e.off(`turn_source`,k),e.off(`status_changed`,A),y?.release()}}function I(e){let{history:t,...n}=e;return n}const ge=new TextEncoder;function _e(e){return e.type===`get-messages`||e.type===`get-history`||e.type===`get-prompts`||e.type===`get-context`||e.type===`get-commands`||e.type===`get-status`||e.type===`list-models`||e.type===`get-agent-definitions`||e.type===`get-executing`||e.type===`get-pending`||e.type===`get-execution-workspace`||e.type===`read-execution-detail`}function ve(e,t,n){if(n.type===`get-messages`)t({type:`messages`,messages:e.getMessages(),display:e.getMessagesDisplay()});else if(n.type===`get-history`)t(be(e,n.fromIndex??0));else if(n.type===`get-prompts`)for(let n of de(e))t(n);else if(n.type===`get-context`)t({type:`context`,state:e.getContextState()});else if(n.type===`get-commands`)t({type:`commands`,commands:e.listCommands(),skills:e.listSkills()});else if(n.type===`get-status`)t({type:`session_status`,status:e.getStatusSnapshot()});else if(n.type===`list-models`){let r=e.listModels();t({type:`model_list`,requestId:n.requestId,...r})}else n.type===`get-agent-definitions`?t({type:`agent_definitions`,requestId:n.requestId,agents:e.listAgentDefinitions(),current:e.getDefaultAgentType()}):n.type===`get-executing`?t({type:`executing`,executing:e.isExecuting()}):n.type===`get-execution-workspace`?t({type:`execution_workspace_event`,snapshot:e.getExecutionWorkspaceSnapshot()}):n.type===`read-execution-detail`?ye(e,t,n):t(L(e))}function ye(e,t,n){let{requestId:r}=n;e.readExecutionWorkspaceDetail(n.entryId,n.cursor).then(e=>t({type:`execution_detail`,requestId:r,page:e}),e=>t({type:`execution_detail_error`,requestId:r,message:e instanceof Error?e.message:String(e)}))}function L(e){return{type:`pending`,pending:e.getPendingPrompt(),pendingCount:e.getPendingCount()}}function be(e,t){let n=e.getFullHistory(),r=n.length,i=Math.min(t,r),a=[],o=0;for(let e=i;e<r;e+=1){let t=xe(n[e]),r=ge.encode(JSON.stringify(t)).byteLength;if(a.length>0&&o+r>262144)break;a.push(t),o+=r}return{type:`history`,startIndex:i,total:r,entries:a}}function xe(e){return{...e,timestamp:Se(e.timestamp)}}function Se(e){return typeof e==`string`?e:e.toISOString()}function R(e){return e.type===`get-settings`||e.type===`update-settings`}function Ce(e,t,n,r,i){if(!r){z(t,n.requestId,`not_available`,`Settings are not available on this host.`);return}try{if(n.type===`get-settings`){Promise.resolve(r.getSettings(e,i)).then(e=>t({type:`settings`,requestId:n.requestId,settings:e}),e=>z(t,n.requestId,`update_failed`,B(e)));return}Promise.resolve(r.updateSettings(e,n.patch,i)).then(e=>{e.ok?t({type:`settings`,requestId:n.requestId,settings:e.settings}):z(t,n.requestId,e.code,e.message)},e=>z(t,n.requestId,`update_failed`,B(e)))}catch(e){z(t,n.requestId,`update_failed`,B(e instanceof Error?e:String(e)))}}function z(e,t,n,r){e({type:`settings_error`,requestId:t,code:n,message:r})}function B(e){return e instanceof Error?e.message:String(e)}function we(e){let t=e.role??`drive`,n=he(e.session,e.deliver,{getSurfaceDriverId:()=>e.driverId,receivePrompts:t===`drive`});return{onMessage:Te(e.session,e.deliver,e.driverId,{personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},e.surface,t,e.sessionDirectory,e.settingsReporter,e.commandSurfaceLocality),cleanup:n}}function Te(e,t,n,r=Ee,a,o=`drive`,s,c,l){return u=>{let d=ee(u,t);if(d){if(o===`observe`&&!i(d.type)){t({type:`protocol_error`,message:`Not permitted for an observer: ${d.type}`});return}V(e,t,d,n,r,a,s,c,l)}}}const Ee={personalUsageReporter:void 0,usageReporter:void 0,storedSessionUsageReporter:void 0};function V(e,t,n,r,i=Ee,a,o,s,c){if(E(e,t,n,i))return;if(re(n)){oe(t,n,o);return}if(R(n)){Ce(e,t,n,s,c);return}if(ie(n)){ce(t,n,o);return}if(ae(n)){le(t,n,o);return}if(De(n)){Me(e,t,n,r,a,c);return}if(b(n)){x(e,t,n);return}if(_e(n)){ve(e,t,n);return}if(te(n)){ne(e,t,n);return}if(Oe(n)){f(e,t,n);return}if(ke(n)){p(e,t,n);return}if(Ae(n)){je(e,n,r);return}let l=n.type;t({type:`protocol_error`,message:`Unknown message type: ${l}`})}function De(e){return e.type===`submit`||e.type===`command`||e.type===`abort`||e.type===`cancel-queue`}function Oe(e){return e.type===`get-background-tasks`||e.type===`get-background-task`||e.type===`read-background-task-log`||e.type===`get-background-job-groups`||e.type===`get-background-job-group`||e.type===`wait-background-job-group`}function ke(e){return e.type===`cancel-background-task`||e.type===`close-background-task`||e.type===`send-background-task`}function Ae(e){return e.type===`permission-response`||e.type===`ask-response`}function je(e,t,n){t.type===`permission-response`?e.resolvePermission(t.id,t.result,n):e.resolveAsk(t.id,t.response,n)}function Me(e,t,n,r,i,a){if(n.type===`submit`){if(typeof n.prompt!=`string`||n.prompt.length===0){t({type:`protocol_error`,message:`prompt must be a non-empty string`});return}let a={...r?{driverId:r}:{},...i?{surface:i}:{}};e.submit(n.prompt,void 0,void 0,Object.keys(a).length>0?a:void 0).then(()=>t(L(e)),e=>t({type:`protocol_error`,message:e.message}))}else if(n.type===`command`){let i=n.requestId===void 0?{}:{requestId:n.requestId};if(!n.name){t({type:`protocol_error`,message:`name is required`,...i});return}e.executeCommand(n.name,n.args??``,`remote`,r,a).then(e=>{t({type:`command_result`,name:n.name,message:e?.message??`Unknown command: ${n.name}`,success:e?.success??!1,data:e?.data,...i})},e=>{t({type:`protocol_error`,message:e.message,...i})})}else n.type===`abort`?e.abort():e.cancelQueue()}const H=1024*1024,U=8*H,Ne=H;function W(e,t=U){return e!==void 0&&e>t}const G=120*1e3;function K(e=G,t=Date.now){let n;return{maxPendingMs:e,observe(r){if(r===void 0)return;if(r===0){n=void 0;return}let i=t();n??=i;let a=i-n;return a>e?a:void 0}}}function q(e,t,n,r=U,i=K()){let a=!1,o=t=>{if(a)return;let o=n?.();if(W(o,r)){a=!0,s(Error(`outbound backpressure budget exceeded: ${o} byte(s) pending, limit ${r}. The peer has accepted frames it is not reading.`),t.type);return}let c=i.observe(o);if(c!==void 0){a=!0,s(Error(`outbound drain budget exceeded: ${o} byte(s) pending for ${c} ms, limit ${i.maxPendingMs} ms. The peer is reading too slowly to ever drain what it accepted.`),t.type);return}try{e(t)}catch(e){a=!0,s(e instanceof Error?e:Error(String(e)),t.type)}};function s(e,n){try{t(e,n)}catch{}}return Object.assign(o,{pendingBytes:()=>n?.()})}var J=class{frames=[];sizes=[];nextSeq=1;bytes=0;maxFrames;maxBytes;sizeOf;constructor(e={}){this.maxFrames=e.maxFrames??512,this.maxBytes=e.maxBytes??4194304,this.sizeOf=e.sizeOf??(e=>JSON.stringify(e).length)}append(e){let t=this.nextSeq;this.nextSeq+=1;let n=this.sizeOf(e);return this.frames.push({seq:t,message:e}),this.sizes.push(n),this.bytes+=n,this.evict(),t}ackThrough(e){let t=0;for(;t<this.frames.length&&this.frames[t].seq<=e;)t+=1;this.removeOldest(t)}tailAfter(e){return this.frames.length===0?e>=this.nextSeq-1?{kind:`tail`,frames:[]}:{kind:`overrun`}:e<this.frames[0].seq-1?{kind:`overrun`}:{kind:`tail`,frames:this.frames.filter(t=>t.seq>e)}}get lastSeq(){return this.nextSeq-1}get size(){return this.frames.length}evict(){let e=0,t=this.bytes;for(;this.frames.length-e>this.maxFrames||t>this.maxBytes&&this.frames.length-e>1;)t-=this.sizes[e],e+=1;this.removeOldest(e)}removeOldest(e){if(!(e<=0)){for(let t=0;t<e;t+=1)this.bytes-=this.sizes[t]??0;this.frames.splice(0,e),this.sizes.splice(0,e),this.frames.length===0&&(this.bytes=0)}}};const Y=new TextEncoder,X=new TextDecoder,Z=Y.encode(`RBF`),Pe=1,Fe=4294967295;function Q(e,t){let n=Y.encode(e);if(n.byteLength===0||n.byteLength>255)throw Error(`channel name must be 1..255 UTF-8 bytes (got ${n.byteLength})`);if(!Number.isInteger(t)||t<0||t>Fe)throw Error(`seq must be an integer in 0..${Fe} (got ${t})`);return n}function Ie(e,t,n,r){e.set(Z,0),e[3]=1,e[4]=t,e[5]=n.byteLength,e.set(n,6);let i=6+n.byteLength;return new DataView(e.buffer,e.byteOffset,e.byteLength).setUint32(i,r,!1),i+4}function Le(e){let t=Q(e.channel,e.seq),n=new Uint8Array(6+t.byteLength+4+e.payload.byteLength),r=Ie(n,1,t,e.seq);return n.set(e.payload,r),n}function Re(e){let t=Q(e.channel,e.seq),n=Y.encode(JSON.stringify({event:e.event,payload:e.payload})),r=new Uint8Array(6+t.byteLength+4+n.byteLength),i=Ie(r,2,t,e.seq);return r.set(n,i),r}function ze(e){return e.byteLength<Z.length?!1:Z.every((t,n)=>e[n]===t)}function Be(e){let t=X.decode(e),n;try{n=JSON.parse(t)}catch{return{ok:!1,error:`channel frame: malformed JSON body`}}if(typeof n!=`object`||!n||Array.isArray(n))return{ok:!1,error:`channel frame: event body must be a JSON object`};let{event:r,payload:i}=n;return typeof r!=`string`||r.length===0?{ok:!1,error:"channel frame: event body is missing a non-empty `event` name"}:{ok:!0,event:r,payload:i??null}}function Ve(e){if(!ze(e))return{ok:!1,error:`channel frame: bad magic (not a channel frame)`};if(e.byteLength<6)return{ok:!1,error:`channel frame: truncated header`};if(e[3]!==1)return{ok:!1,error:`channel frame: unsupported version ${String(e[3])}`};let t=e[4],n=e[5]??0;if(n===0)return{ok:!1,error:`channel frame: empty channel name`};let r=6+n,i=r+4;if(e.byteLength<i)return{ok:!1,error:`channel frame: truncated (header longer than the frame)`};let a=X.decode(e.subarray(6,r)),o=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(r,!1),s=e.subarray(i);if(t===1)return{ok:!0,frame:{kind:`binary`,channel:a,seq:o,payload:Uint8Array.from(s)}};if(t===2){let e=Be(s);return e.ok?{ok:!0,frame:{kind:`event`,channel:a,seq:o,event:e.event,payload:e.payload}}:{ok:!1,error:e.error}}return{ok:!1,error:`channel frame: unknown kind ${String(t)}`}}var He=class{session;buffer;driverId;reporters;surface;commandSurfaceLocality;unsubscribe;onDeliveryError;outbound;emitBoundary;disposed=!1;holding=!1;constructor(e){this.session=e.session,this.buffer=new J(e.buffer),this.driverId=e.driverId,this.surface=e.surface,this.commandSurfaceLocality=e.commandSurfaceLocality,this.reporters={personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},this.emitBoundary=q(e=>this.emit(e),(e,t)=>this.reportDeliveryError(e,t)),this.unsubscribe=he(this.session,this.emitBoundary,{getSurfaceDriverId:()=>this.driverId})}attach(e,t){this.disposed||(this.onDeliveryError=t.onDeliveryError,this.outbound=q(t=>e(JSON.stringify(t)),(e,t)=>this.reportDeliveryError(e,t),t.pendingBytes),this.holding=t.awaitResume===!0)}detach(){this.outbound=void 0,this.onDeliveryError=void 0}setDriverId(e){this.driverId=e}onClientMessage(e){if(this.disposed)return;let t=ee(e,this.emitBoundary);if(t){if(t.type===`resume`){this.replay(t.lastSeq);return}if(t.type===`ack`){this.buffer.ackThrough(t.seq);return}V(this.session,this.emitBoundary,t,this.driverId,this.reporters,this.surface,void 0,void 0,this.commandSurfaceLocality)}}dispose(){this.disposed||(this.disposed=!0,this.detach(),this.unsubscribe())}get lastSeq(){return this.buffer.lastSeq}emit(e){if(this.disposed)return;let t=this.buffer.append(e);this.holding||this.deliverFrame({...e,seq:t})}replay(e){let t=this.buffer.tailAfter(e);if(t.kind===`overrun`){this.deliverFrame({type:`resume_gap`}),this.holding=!1;return}for(let e of t.frames)this.deliverFrame({...e.message,seq:e.seq});this.holding=!1}deliverFrame(e){this.outbound?.(e)}reportDeliveryError(e,t){let n=this.onDeliveryError;this.detach();try{n?.(e,t)}catch{}}};function Ue(){return{origins:new Map}}function We(e,t,n){let r=t.origin.sessionId,i=e.origins.get(r);i===void 0&&(i={highestSequence:0,delivered:new Set,issued:new Map},e.origins.set(r,i));let a=i.issued.get(t.id);if(a!==void 0)return{ack:{...a,state:`duplicate`},deliver:!1};if(n!==void 0){let e={id:t.id,sequence:t.sequence,state:n.state,reason:n.reason};return i.issued.set(t.id,e),{ack:e,deliver:!1}}if(i.delivered.has(t.sequence)){let e={id:t.id,sequence:t.sequence,state:`refused`,reason:`sequence ${t.sequence} was already delivered by this origin under a different message id. A retry must repeat its id; a new id on a delivered sequence cannot be ordered against what the receiver already has.`};return i.issued.set(t.id,e),{ack:e,deliver:!1}}let o=i.highestSequence+1,s=t.sequence>o?o:void 0,c={id:t.id,sequence:t.sequence,state:`delivered`};return i.issued.set(t.id,c),i.delivered.add(t.sequence),i.highestSequence=Math.max(i.highestSequence,t.sequence),s===void 0?{ack:c,deliver:!0}:{ack:c,deliver:!0,gapBefore:s}}function Ge(e,t,n){let r=e.origins.get(t),i=r?.issued.get(n);if(r===void 0||i===void 0||i.state!==`delivered`)return;let a={...i,state:`acknowledged`};return r.issued.set(n,a),a}function Ke(e,t){e.origins.delete(t)}const $=16*1024,qe=32768;function Je(e){let t=``;for(let n=0;n<e.length;n+=qe)t+=String.fromCharCode(...e.subarray(n,n+qe));return btoa(t)}function Ye(e){let t;try{t=atob(e)}catch{return}let n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.charCodeAt(e);return n}function Xe(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function Ze(e,t,n=$){if(!Number.isInteger(n)||n<1)throw Error(`handoff chunking: maxChunkBytes must be a positive integer, got ${n}. A zero or negative budget produces an infinite sequence of empty chunks, which presents as a hang rather than as the configuration error it is.`);let r=new TextEncoder().encode(t),i=Math.max(1,Math.ceil(r.byteLength/n)),a=[];for(let t=0;t<i;t+=1){let o=r.subarray(t*n,(t+1)*n);a.push({handoffId:e,index:t,total:i,data:Je(o)})}return a}var Qe=class{handoffId;chunks=new Map;declaredTotal;constructor(e){this.handoffId=e}get received(){return this.chunks.size}get expected(){return this.declaredTotal}accept(e){let t=e=>({outcome:`refused`,rejection:e,received:this.chunks.size,...this.declaredTotal===void 0?{}:{expected:this.declaredTotal}});if(e.handoffId!==this.handoffId)return t(`wrong-handoff`);if(!Number.isInteger(e.total)||e.total<1||this.declaredTotal!==void 0&&e.total!==this.declaredTotal)return t(`inconsistent-total`);if(!Number.isInteger(e.index)||e.index<0||e.index>=e.total)return t(`out-of-range`);let n=Ye(e.data);if(n===void 0||Je(n)!==e.data)return t(`undecodable`);this.declaredTotal=e.total;let r=this.chunks.get(e.index);return r===void 0?(this.chunks.set(e.index,n),this.chunks.size<e.total?{outcome:`accepted`,received:this.chunks.size,expected:e.total}:{outcome:`complete`,serialized:this.reassemble(e.total),received:this.chunks.size,expected:e.total}):Xe(r,n)?{outcome:`duplicate`,received:this.chunks.size,expected:e.total}:t(`inconsistent-total`)}missing(){if(this.declaredTotal===void 0)return[];let e=[];for(let t=0;t<this.declaredTotal;t+=1)this.chunks.has(t)||e.push(t);return e}discard(){this.chunks.clear(),this.declaredTotal=void 0}reassemble(e){let t=[];for(let n=0;n<e;n+=1){let r=this.chunks.get(n);if(r===void 0)throw Error(`handoff chunking: chunk ${n} of ${e} is missing at reassembly.`);t.push(r)}let n=new Uint8Array(t.reduce((e,t)=>e+t.length,0)),r=0;for(let e of t)n.set(e,r),r+=e.length;return new TextDecoder(`utf-8`,{ignoreBOM:!0}).decode(n)}};function $e(e,t=$){return Math.max(1,Math.ceil(e.byteLength/t))}export{Ne as ATTACHED_SURFACE_MAX_PENDING_BYTES,Z as CHANNEL_FRAME_MAGIC,Pe as CHANNEL_FRAME_VERSION,$ as DEFAULT_MAX_CHUNK_BYTES,U as DEFAULT_MAX_PENDING_BYTES,G as DEFAULT_MAX_PENDING_MS,Qe as HandoffChunkAssembler,n as MAX_INBOUND_FRAME_BYTES,me as PROTOCOL_SESSION_EVENT_CLASSIFICATION,J as ResumeBuffer,He as SessionResumeBridge,Ge as acknowledgePeerMessage,We as admitPeerMessage,$e as chunkCountFor,Ze as chunkHandoffPayload,q as createOutboundDelivery,Ue as createPeerMessageLedger,K as createPendingStallClock,we as createSessionMessageHandler,Ve as decodeChannelFrame,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,Le as encodeBinaryFrame,Re as encodeChannelEventFrame,Ke as forgetPeerOrigin,Ce as handleSettingsMessage,ze as isChannelFrame,i as isObserverMessageType,W as isOverPendingBudget,R as isSettingsMessage};
2
2
  //# sourceMappingURL=index.js.map