xacpp 0.1.0

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.
@@ -0,0 +1,51 @@
1
+ /** 事件载荷类型。 */
2
+ import type { ContentPart } from "./content";
3
+ /** 内容分片事件载荷。 */
4
+ export interface ContentPartEvent {
5
+ round: string;
6
+ pair: string;
7
+ payload: ContentPart;
8
+ }
9
+ /** 内容增量事件载荷。 */
10
+ export interface ContentDeltaEvent {
11
+ round: string;
12
+ pair: string;
13
+ payload: ContentPart;
14
+ }
15
+ /** 可追踪事件载荷(Info/Warn/Error 共用)。 */
16
+ export interface TraceableEvent {
17
+ title: string;
18
+ content: string;
19
+ }
20
+ /** 授权请求 Alert 级别。 */
21
+ export type AlertLevel = "info" | "warn" | "critical";
22
+ /** 工具调用开始事件载荷。 */
23
+ export interface ToolUseEvent {
24
+ requestId: string;
25
+ toolName: string;
26
+ index: number;
27
+ arguments: string;
28
+ }
29
+ /** 工具调用结束事件载荷。 */
30
+ export interface ToolResultEvent {
31
+ requestId: string;
32
+ toolName: string;
33
+ index: number;
34
+ parts: ContentPart[];
35
+ }
36
+ /** 安全告警事件载荷。 */
37
+ export interface SecurityAlertEvent {
38
+ eventId: string;
39
+ toolName: string;
40
+ alertLevel: AlertLevel;
41
+ description: string;
42
+ threatType?: string;
43
+ matchedPattern?: string;
44
+ contextSnippet?: string;
45
+ }
46
+ /** SubActivity 任务启动事件载荷。 */
47
+ export interface ActivityStartEvent {
48
+ goal: string;
49
+ activityId: string;
50
+ metadata?: Record<string, string>;
51
+ }
@@ -0,0 +1,25 @@
1
+ /** 文件上传与令牌用量。 */
2
+ import type { FileRef } from "./content";
3
+ /** 文件上传事件。 */
4
+ export type UploadEvent = {
5
+ upload_event: "progress";
6
+ name: string;
7
+ uploaded: number;
8
+ total: number;
9
+ } | {
10
+ upload_event: "completed";
11
+ name: string;
12
+ mediaSource: FileRef;
13
+ } | {
14
+ upload_event: "error";
15
+ name: string;
16
+ error: string;
17
+ };
18
+ /** 令牌使用情况。 */
19
+ export interface TokenUsage {
20
+ id: string;
21
+ message: string;
22
+ promptTokens: number;
23
+ completionTokens: number;
24
+ totalTokens: number;
25
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ACPP protocol event union type.
3
+ *
4
+ * Standardized event stream between the initiator and the peer.
5
+ * The only terminal signal is `complete`; all other events carry no implicit termination semantics.
6
+ */
7
+ import type { ContentPart } from "./content";
8
+ import type { ActionRequestEvent, NotifyEvent, QuestionEvent, SensitiveInfoOperationEvent } from "./interaction";
9
+ import type { ActivityStartEvent, SecurityAlertEvent, ToolResultEvent, ToolUseEvent, TraceableEvent } from "./payload";
10
+ import type { TokenUsage, UploadEvent } from "./upload";
11
+ /** Unified multimodal content delta event. */
12
+ export interface ContentDeltaXacppEvent {
13
+ type: "content_delta";
14
+ round: string;
15
+ pair: string;
16
+ payload: ContentPart;
17
+ }
18
+ /** Unified multimodal content part event. */
19
+ export interface ContentPartXacppEvent {
20
+ type: "content_part";
21
+ round: string;
22
+ pair: string;
23
+ payload: ContentPart;
24
+ }
25
+ /** Thinking text output (delta). */
26
+ export interface ThinkXacppEvent {
27
+ type: "think";
28
+ content: string;
29
+ }
30
+ /** System info output. */
31
+ export interface InfoXacppEvent extends TraceableEvent {
32
+ type: "info";
33
+ }
34
+ /** System warning output. */
35
+ export interface WarnXacppEvent extends TraceableEvent {
36
+ type: "warn";
37
+ }
38
+ /** Structured error event (non-terminal). */
39
+ export interface ErrorXacppEvent extends TraceableEvent {
40
+ type: "error";
41
+ }
42
+ /** Tool call authorization request. */
43
+ export interface ActionRequestXacppEvent extends ActionRequestEvent {
44
+ type: "action_request";
45
+ }
46
+ /** User notification (one-way push). */
47
+ export interface NotifyXacppEvent extends NotifyEvent {
48
+ type: "notify";
49
+ }
50
+ /** User question. */
51
+ export interface QuestionXacppEvent extends QuestionEvent {
52
+ type: "question";
53
+ }
54
+ /** Sensitive information operation request. */
55
+ export interface SensitiveInfoOperationXacppEvent extends SensitiveInfoOperationEvent {
56
+ type: "sensitive_info_operation";
57
+ }
58
+ /** SubActivity waiting for command. */
59
+ export interface WaitingCommandXacppEvent {
60
+ type: "waiting_command";
61
+ }
62
+ /** SubActivity started. */
63
+ export interface ActivityStartXacppEvent extends ActivityStartEvent {
64
+ type: "activity_start";
65
+ }
66
+ /** SubActivity completed. */
67
+ export interface ActivityDoneXacppEvent {
68
+ type: "activity_done";
69
+ activityId: string;
70
+ }
71
+ /** SubActivity aborted. */
72
+ export interface ActivityAbortedXacppEvent {
73
+ type: "activity_aborted";
74
+ activityId: string;
75
+ reason: string;
76
+ }
77
+ /** Tool call started. */
78
+ export interface ToolUseXacppEvent extends ToolUseEvent {
79
+ type: "tool_use";
80
+ }
81
+ /** Tool call completed. */
82
+ export interface ToolResultXacppEvent extends ToolResultEvent {
83
+ type: "tool_result";
84
+ }
85
+ /** Security alert. */
86
+ export interface SecurityAlertXacppEvent extends SecurityAlertEvent {
87
+ type: "security_alert";
88
+ }
89
+ /** File upload event. */
90
+ export type UploadXacppEvent = UploadEvent & {
91
+ type: "upload";
92
+ };
93
+ /** ReAct loop single iteration completed. */
94
+ export interface PairCompleteXacppEvent {
95
+ type: "pair_complete";
96
+ contextWindow: number;
97
+ tokenUsage: TokenUsage;
98
+ }
99
+ /** The sole terminal signal for an invoke. */
100
+ export interface CompleteXacppEvent {
101
+ type: "complete";
102
+ assistantReply: ContentPart[];
103
+ }
104
+ /** ACPP protocol event union type. */
105
+ export type XacppEvent = ContentDeltaXacppEvent | ContentPartXacppEvent | ThinkXacppEvent | InfoXacppEvent | WarnXacppEvent | ErrorXacppEvent | ActionRequestXacppEvent | NotifyXacppEvent | QuestionXacppEvent | SensitiveInfoOperationXacppEvent | WaitingCommandXacppEvent | ActivityStartXacppEvent | ActivityDoneXacppEvent | ActivityAbortedXacppEvent | ToolUseXacppEvent | ToolResultXacppEvent | SecurityAlertXacppEvent | UploadXacppEvent | PairCompleteXacppEvent | CompleteXacppEvent;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * XACPP Handler type definitions.
3
+ *
4
+ * This module centralizes all handler-related types:
5
+ *
6
+ * - {@link XacppSessionHandler}: logical session handler (processes Command / Event)
7
+ * - {@link EstablishHandler}: peer Establish request handler
8
+ */
9
+ import type { XacppTransport } from "./transport";
10
+ import type { XacppCommand } from "./commands";
11
+ import type { XacppEvent } from "./events";
12
+ import type { XacppResponse } from "./message";
13
+ /** XACPP Session Handler interface.
14
+ *
15
+ * Each logical session holds one implementation, processing Commands and Events from the peer.
16
+ */
17
+ export interface XacppSessionHandler {
18
+ /** Handle Command. */
19
+ onCommand(command: XacppCommand): Promise<XacppResponse>;
20
+ /** Handle Event. */
21
+ onEvent(event: XacppEvent): Promise<XacppResponse>;
22
+ }
23
+ /** Peer Establish request handler — serve main function.
24
+ *
25
+ * Called by the responder when receiving an Establish command from the peer.
26
+ * The developer performs credential validation, creates and holds a Session (for subsequent proactive sends),
27
+ * creates a SessionHandler and returns it. Returning reject denies the handshake.
28
+ */
29
+ export interface EstablishHandler {
30
+ /**
31
+ * Handle Establish request.
32
+ *
33
+ * `transport` is passed in by Peer, for use inside `onEstablish` to create `XacppSession`.
34
+ * Returns `{ sessionId, handler }`: sessionId identifies this session,
35
+ * handler processes inbound Command/Event for this session.
36
+ */
37
+ onEstablish(transport: XacppTransport, credentials: string | null): Promise<{
38
+ sessionId: string;
39
+ handler: XacppSessionHandler;
40
+ }>;
41
+ }
@@ -0,0 +1,10 @@
1
+ export type { XacppCommand } from "./commands";
2
+ export * from "./events";
3
+ export { XacppError } from "./message";
4
+ export type { XacppRequest, XacppResponse, XacppEnvelope } from "./message";
5
+ export { XacppPeer, PeerState } from "./peer";
6
+ export { XacppSession } from "./session";
7
+ export { SocketTransport } from "./socket-transport";
8
+ export { StdioTransport } from "./stdio-transport";
9
+ export type { XacppTransport, RequestHandler } from "./transport";
10
+ export type { XacppSessionHandler, EstablishHandler } from "./handler";
@@ -0,0 +1,467 @@
1
+ import * as __rspack_external_node_net_0373943e from "node:net";
2
+ import * as __rspack_external_node_readline_91c31510 from "node:readline";
3
+ class XacppError extends Error {
4
+ code;
5
+ constructor(code, message){
6
+ super(message);
7
+ this.name = "XacppError";
8
+ this.code = code;
9
+ }
10
+ static notConnected() {
11
+ return new XacppError("not_connected", "not connected");
12
+ }
13
+ static alreadyConnected() {
14
+ return new XacppError("already_connected", "already connected");
15
+ }
16
+ static closed() {
17
+ return new XacppError("closed", "connection closed");
18
+ }
19
+ static noHandler() {
20
+ return new XacppError("no_handler", "no handler registered");
21
+ }
22
+ static internal(message) {
23
+ return new XacppError("internal_error", `internal error: ${message}`);
24
+ }
25
+ static application(code, message) {
26
+ return new XacppError(code, message);
27
+ }
28
+ static invalidRequest(message) {
29
+ return new XacppError("invalid_request", `invalid request: ${message}`);
30
+ }
31
+ static establishReject(reason) {
32
+ return new XacppError("establish_rejected", `establish rejected: ${reason}`);
33
+ }
34
+ }
35
+ class XacppSession {
36
+ transport;
37
+ _sessionId;
38
+ _credentials;
39
+ constructor(transport, sessionId, credentials){
40
+ this.transport = transport;
41
+ this._sessionId = sessionId;
42
+ this._credentials = credentials;
43
+ }
44
+ get sessionId() {
45
+ return this._sessionId;
46
+ }
47
+ get credentials() {
48
+ return this._credentials;
49
+ }
50
+ async requestCommand(command) {
51
+ return this.transport.send(this._sessionId, {
52
+ kind: "command",
53
+ payload: command
54
+ });
55
+ }
56
+ async requestEvent(event) {
57
+ return this.transport.send(this._sessionId, {
58
+ kind: "event",
59
+ payload: event
60
+ });
61
+ }
62
+ }
63
+ var peer_PeerState = /*#__PURE__*/ function(PeerState) {
64
+ PeerState["Disconnected"] = "disconnected";
65
+ PeerState["Connected"] = "connected";
66
+ return PeerState;
67
+ }({});
68
+ class XacppPeer {
69
+ transport;
70
+ _state = "disconnected";
71
+ sessions = new Map();
72
+ establishHandler;
73
+ constructor(transport, establishHandler){
74
+ this.transport = transport;
75
+ this.establishHandler = establishHandler;
76
+ }
77
+ get state() {
78
+ return this._state;
79
+ }
80
+ async connect() {
81
+ const sessions = this.sessions;
82
+ const establishHandler = this.establishHandler;
83
+ const transport = this.transport;
84
+ transport.onRequest((sessionId, payload)=>Promise.resolve().then(async ()=>{
85
+ if (null === sessionId) {
86
+ if ("command" === payload.kind && "object" == typeof payload.payload && "establish" in payload.payload) {
87
+ const credentials = payload.payload.establish.credentials;
88
+ const result = await establishHandler.onEstablish(transport, credentials);
89
+ sessions.set(result.sessionId, result.handler);
90
+ return {
91
+ kind: "established",
92
+ sessionId: result.sessionId
93
+ };
94
+ }
95
+ throw XacppError.invalidRequest("missing session_id");
96
+ }
97
+ const handler = sessions.get(sessionId);
98
+ if (!handler) throw XacppError.internal(`unknown session: ${sessionId}`);
99
+ if ("command" === payload.kind) return handler.onCommand(payload.payload);
100
+ return handler.onEvent(payload.payload);
101
+ }));
102
+ await this.transport.connect();
103
+ if ("disconnected" === this._state) this._state = "connected";
104
+ }
105
+ async establish(credentials, handler) {
106
+ const response = await this.transport.send(null, {
107
+ kind: "command",
108
+ payload: {
109
+ establish: {
110
+ credentials
111
+ }
112
+ }
113
+ });
114
+ if ("established" === response.kind) {
115
+ this.sessions.set(response.sessionId, handler);
116
+ return new XacppSession(this.transport, response.sessionId, response.credentials ?? null);
117
+ }
118
+ if ("establish_reject" === response.kind) throw XacppError.establishReject(response.reason);
119
+ if ("error" === response.kind) throw XacppError.application(response.code, response.message);
120
+ throw XacppError.internal(`unexpected response to establish: ${JSON.stringify(response)}`);
121
+ }
122
+ async disconnect() {
123
+ await this.transport.disconnect();
124
+ this._state = "disconnected";
125
+ this.sessions.clear();
126
+ }
127
+ async requestCommand(sessionId, command) {
128
+ return this.transport.send(sessionId, {
129
+ kind: "command",
130
+ payload: command
131
+ });
132
+ }
133
+ async requestEvent(sessionId, event) {
134
+ return this.transport.send(sessionId, {
135
+ kind: "event",
136
+ payload: event
137
+ });
138
+ }
139
+ }
140
+ class SocketTransport {
141
+ socket = null;
142
+ handler = null;
143
+ pending = new Map();
144
+ nextId = 1;
145
+ _connected = false;
146
+ _exhausted = false;
147
+ writeQueue = Promise.resolve();
148
+ inflight = new Set();
149
+ port;
150
+ host;
151
+ rl = null;
152
+ static connectTo(port, host) {
153
+ const t = new SocketTransport();
154
+ t.port = port;
155
+ t.host = host ?? "127.0.0.1";
156
+ return t;
157
+ }
158
+ constructor(socket){
159
+ if (socket) this.socket = socket;
160
+ }
161
+ async connect() {
162
+ if (this._exhausted || this._connected) throw XacppError.alreadyConnected();
163
+ if (!this.socket) {
164
+ if (void 0 === this.port) throw XacppError.alreadyConnected();
165
+ this.socket = new __rspack_external_node_net_0373943e.Socket();
166
+ await new Promise((resolve, reject)=>{
167
+ const sock = this.socket;
168
+ const onError = (err)=>{
169
+ cleanup();
170
+ reject(new Error(`connect failed: ${err.message}`));
171
+ };
172
+ const onConnect = ()=>{
173
+ cleanup();
174
+ resolve();
175
+ };
176
+ const cleanup = ()=>{
177
+ sock.removeListener("error", onError);
178
+ sock.removeListener("connect", onConnect);
179
+ };
180
+ sock.once("error", onError);
181
+ sock.once("connect", onConnect);
182
+ sock.connect(this.port, this.host, ()=>{});
183
+ });
184
+ }
185
+ const sock = this.socket;
186
+ this.rl = __rspack_external_node_readline_91c31510.createInterface({
187
+ input: sock
188
+ });
189
+ this.rl.on("line", (line)=>this.onFrame(line));
190
+ this.rl.on("close", ()=>{
191
+ console.info("[xacpp:socket] accept loop exited");
192
+ this.cleanup();
193
+ });
194
+ this._connected = true;
195
+ console.debug("[xacpp:socket] connected");
196
+ }
197
+ async disconnect() {
198
+ this._exhausted = true;
199
+ this._connected = false;
200
+ for (const controller of this.inflight)controller.abort();
201
+ this.inflight.clear();
202
+ if (this.rl) {
203
+ this.rl.close();
204
+ this.rl = null;
205
+ }
206
+ if (this.socket) {
207
+ this.socket.destroy();
208
+ this.socket = null;
209
+ }
210
+ this.writeQueue = Promise.resolve();
211
+ this.rejectAllPending();
212
+ console.debug("[xacpp:socket] disconnected");
213
+ }
214
+ async send(sessionId, payload) {
215
+ if (!this._connected || !this.socket) throw XacppError.notConnected();
216
+ const id = `r${this.nextId++}`;
217
+ return new Promise((resolve, reject)=>{
218
+ this.pending.set(id, {
219
+ resolve,
220
+ reject
221
+ });
222
+ const envelope = {
223
+ type: "request",
224
+ id,
225
+ ...null != sessionId ? {
226
+ session_id: sessionId
227
+ } : {},
228
+ payload
229
+ };
230
+ this.writeEnvelope(envelope).catch(()=>{
231
+ this.pending.delete(id);
232
+ reject(XacppError.closed());
233
+ });
234
+ });
235
+ }
236
+ onRequest(handler) {
237
+ if (this._connected) throw XacppError.alreadyConnected();
238
+ this.handler = handler;
239
+ }
240
+ async onFrame(line) {
241
+ let envelope;
242
+ try {
243
+ envelope = JSON.parse(line);
244
+ } catch {
245
+ console.warn("[xacpp:socket] failed to parse frame: %s", line);
246
+ return;
247
+ }
248
+ if ("request" === envelope.type) this.dispatchRequest(envelope);
249
+ else if ("response" === envelope.type) {
250
+ const pending = this.pending.get(envelope.id);
251
+ if (pending) {
252
+ this.pending.delete(envelope.id);
253
+ pending.resolve(envelope.payload);
254
+ } else console.warn("[xacpp:socket] received response for unknown request %s", envelope.id);
255
+ }
256
+ }
257
+ dispatchRequest(envelope) {
258
+ if (!this.handler) return void this.writeEnvelope({
259
+ type: "response",
260
+ id: envelope.id,
261
+ ...null != envelope.session_id ? {
262
+ session_id: envelope.session_id
263
+ } : {},
264
+ payload: {
265
+ kind: "error",
266
+ code: "no_handler",
267
+ message: "no handler registered"
268
+ }
269
+ }).catch(()=>{});
270
+ const controller = new AbortController();
271
+ this.inflight.add(controller);
272
+ const sessionId = envelope.session_id ?? null;
273
+ const handler = this.handler;
274
+ handler(sessionId, envelope.payload).then((responsePayload)=>{
275
+ if (controller.signal.aborted) return;
276
+ return this.writeEnvelope({
277
+ type: "response",
278
+ id: envelope.id,
279
+ ...null != envelope.session_id ? {
280
+ session_id: envelope.session_id
281
+ } : {},
282
+ payload: responsePayload
283
+ });
284
+ }).catch((e)=>{
285
+ if (controller.signal.aborted) return;
286
+ const err = e instanceof XacppError ? e : XacppError.internal(e instanceof Error ? e.message : String(e));
287
+ console.error("[xacpp:socket] handler error for request %s: %s", envelope.id, err.message);
288
+ return this.writeEnvelope({
289
+ type: "response",
290
+ id: envelope.id,
291
+ ...null != envelope.session_id ? {
292
+ session_id: envelope.session_id
293
+ } : {},
294
+ payload: {
295
+ kind: "error",
296
+ code: err.code,
297
+ message: err.message
298
+ }
299
+ });
300
+ }).finally(()=>{
301
+ this.inflight.delete(controller);
302
+ });
303
+ }
304
+ writeEnvelope(envelope) {
305
+ if (!this.socket) return Promise.reject(XacppError.closed());
306
+ const json = JSON.stringify(envelope) + "\n";
307
+ const sock = this.socket;
308
+ let resolveOp;
309
+ let rejectOp;
310
+ const opPromise = new Promise((resolve, reject)=>{
311
+ resolveOp = resolve;
312
+ rejectOp = reject;
313
+ });
314
+ this.writeQueue = this.writeQueue.then(()=>new Promise((chainResolve)=>{
315
+ sock.write(json, (err)=>{
316
+ if (err) rejectOp(XacppError.closed());
317
+ else resolveOp();
318
+ chainResolve();
319
+ });
320
+ }), ()=>{});
321
+ return opPromise;
322
+ }
323
+ rejectAllPending() {
324
+ const err = XacppError.closed();
325
+ for (const [, p] of this.pending)p.reject(err);
326
+ this.pending.clear();
327
+ }
328
+ cleanup() {
329
+ this._connected = false;
330
+ this.rejectAllPending();
331
+ }
332
+ }
333
+ class StdioTransport {
334
+ writer;
335
+ reader;
336
+ rl = null;
337
+ _connected = false;
338
+ _exhausted = false;
339
+ requestHandler = null;
340
+ pending = new Map();
341
+ nextId = 1;
342
+ constructor(writer, reader){
343
+ this.writer = writer;
344
+ this.reader = reader;
345
+ }
346
+ genId() {
347
+ return `r${this.nextId++}`;
348
+ }
349
+ async connect() {
350
+ if (this._exhausted) throw XacppError.alreadyConnected();
351
+ if (this._connected) throw XacppError.alreadyConnected();
352
+ if (!this.writer || !this.reader) throw XacppError.alreadyConnected();
353
+ this.rl = __rspack_external_node_readline_91c31510.createInterface({
354
+ input: this.reader
355
+ });
356
+ this.rl.on("line", (line)=>{
357
+ this.onFrame(line);
358
+ });
359
+ this.rl.on("close", ()=>{
360
+ console.info("[xacpp:stdio] accept loop exited");
361
+ this.cleanup();
362
+ });
363
+ this._connected = true;
364
+ console.debug("[xacpp:stdio] connected");
365
+ }
366
+ async disconnect() {
367
+ if (this.rl) {
368
+ this.rl.close();
369
+ this.rl = null;
370
+ }
371
+ if (this.writer) {
372
+ this.writer.end();
373
+ this.writer = null;
374
+ }
375
+ this.reader = null;
376
+ this.cleanup();
377
+ this._exhausted = true;
378
+ console.debug("[xacpp:stdio] disconnected");
379
+ }
380
+ async send(sessionId, payload) {
381
+ if (!this._connected || !this.writer) throw XacppError.notConnected();
382
+ const id = this.genId();
383
+ return new Promise((resolve, reject)=>{
384
+ this.pending.set(id, {
385
+ resolve,
386
+ reject
387
+ });
388
+ const envelope = {
389
+ type: "request",
390
+ id,
391
+ ...null != sessionId ? {
392
+ session_id: sessionId
393
+ } : {},
394
+ payload
395
+ };
396
+ const json = JSON.stringify(envelope) + "\n";
397
+ this.writer.write(json, (err)=>{
398
+ if (err) {
399
+ this.pending.delete(id);
400
+ reject(XacppError.closed());
401
+ }
402
+ });
403
+ });
404
+ }
405
+ onRequest(handler) {
406
+ if (this._connected) throw XacppError.alreadyConnected();
407
+ this.requestHandler = handler;
408
+ }
409
+ async onFrame(line) {
410
+ let envelope;
411
+ try {
412
+ envelope = JSON.parse(line);
413
+ } catch {
414
+ console.warn("[xacpp:stdio] failed to parse frame: %s", line);
415
+ return;
416
+ }
417
+ if ("request" === envelope.type) await this.handleRequest(envelope.id, envelope.session_id ?? null, envelope.payload);
418
+ else if ("response" === envelope.type) this.handleResponse(envelope.id, envelope.payload);
419
+ }
420
+ async handleRequest(id, sessionId, payload) {
421
+ let responsePayload;
422
+ try {
423
+ if (!this.requestHandler) throw XacppError.noHandler();
424
+ responsePayload = await this.requestHandler(sessionId, payload);
425
+ } catch (e) {
426
+ const err = e instanceof XacppError ? e : XacppError.internal(e instanceof Error ? e.message : String(e));
427
+ console.error("[xacpp:stdio] handler error for request %s: %s", id, err.message);
428
+ responsePayload = {
429
+ kind: "error",
430
+ code: err.code,
431
+ message: err.message
432
+ };
433
+ }
434
+ const response = {
435
+ type: "response",
436
+ id,
437
+ ...null != sessionId ? {
438
+ session_id: sessionId
439
+ } : {},
440
+ payload: responsePayload
441
+ };
442
+ const ok = this.writeEnvelope(response);
443
+ if (!ok) console.warn("[xacpp:stdio] failed to send response for request %s", id);
444
+ }
445
+ handleResponse(id, payload) {
446
+ const pending = this.pending.get(id);
447
+ if (pending) {
448
+ this.pending.delete(id);
449
+ pending.resolve(payload);
450
+ } else console.warn("[xacpp:stdio] received response for unknown request %s", id);
451
+ }
452
+ writeEnvelope(envelope) {
453
+ if (!this.writer) return false;
454
+ const json = JSON.stringify(envelope) + "\n";
455
+ return this.writer.write(json);
456
+ }
457
+ cleanup() {
458
+ this._connected = false;
459
+ const err = XacppError.closed();
460
+ for (const [id, pending] of this.pending){
461
+ console.warn("[xacpp:stdio] rejecting pending request %s: %s", id, err.message);
462
+ pending.reject(err);
463
+ }
464
+ this.pending.clear();
465
+ }
466
+ }
467
+ export { SocketTransport, StdioTransport, XacppError, XacppPeer, XacppSession, peer_PeerState as PeerState };