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,516 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ PeerState: ()=>peer_PeerState,
28
+ SocketTransport: ()=>SocketTransport,
29
+ StdioTransport: ()=>StdioTransport,
30
+ XacppError: ()=>XacppError,
31
+ XacppPeer: ()=>XacppPeer,
32
+ XacppSession: ()=>XacppSession
33
+ });
34
+ class XacppError extends Error {
35
+ code;
36
+ constructor(code, message){
37
+ super(message);
38
+ this.name = "XacppError";
39
+ this.code = code;
40
+ }
41
+ static notConnected() {
42
+ return new XacppError("not_connected", "not connected");
43
+ }
44
+ static alreadyConnected() {
45
+ return new XacppError("already_connected", "already connected");
46
+ }
47
+ static closed() {
48
+ return new XacppError("closed", "connection closed");
49
+ }
50
+ static noHandler() {
51
+ return new XacppError("no_handler", "no handler registered");
52
+ }
53
+ static internal(message) {
54
+ return new XacppError("internal_error", `internal error: ${message}`);
55
+ }
56
+ static application(code, message) {
57
+ return new XacppError(code, message);
58
+ }
59
+ static invalidRequest(message) {
60
+ return new XacppError("invalid_request", `invalid request: ${message}`);
61
+ }
62
+ static establishReject(reason) {
63
+ return new XacppError("establish_rejected", `establish rejected: ${reason}`);
64
+ }
65
+ }
66
+ class XacppSession {
67
+ transport;
68
+ _sessionId;
69
+ _credentials;
70
+ constructor(transport, sessionId, credentials){
71
+ this.transport = transport;
72
+ this._sessionId = sessionId;
73
+ this._credentials = credentials;
74
+ }
75
+ get sessionId() {
76
+ return this._sessionId;
77
+ }
78
+ get credentials() {
79
+ return this._credentials;
80
+ }
81
+ async requestCommand(command) {
82
+ return this.transport.send(this._sessionId, {
83
+ kind: "command",
84
+ payload: command
85
+ });
86
+ }
87
+ async requestEvent(event) {
88
+ return this.transport.send(this._sessionId, {
89
+ kind: "event",
90
+ payload: event
91
+ });
92
+ }
93
+ }
94
+ var peer_PeerState = /*#__PURE__*/ function(PeerState) {
95
+ PeerState["Disconnected"] = "disconnected";
96
+ PeerState["Connected"] = "connected";
97
+ return PeerState;
98
+ }({});
99
+ class XacppPeer {
100
+ transport;
101
+ _state = "disconnected";
102
+ sessions = new Map();
103
+ establishHandler;
104
+ constructor(transport, establishHandler){
105
+ this.transport = transport;
106
+ this.establishHandler = establishHandler;
107
+ }
108
+ get state() {
109
+ return this._state;
110
+ }
111
+ async connect() {
112
+ const sessions = this.sessions;
113
+ const establishHandler = this.establishHandler;
114
+ const transport = this.transport;
115
+ transport.onRequest((sessionId, payload)=>Promise.resolve().then(async ()=>{
116
+ if (null === sessionId) {
117
+ if ("command" === payload.kind && "object" == typeof payload.payload && "establish" in payload.payload) {
118
+ const credentials = payload.payload.establish.credentials;
119
+ const result = await establishHandler.onEstablish(transport, credentials);
120
+ sessions.set(result.sessionId, result.handler);
121
+ return {
122
+ kind: "established",
123
+ sessionId: result.sessionId
124
+ };
125
+ }
126
+ throw XacppError.invalidRequest("missing session_id");
127
+ }
128
+ const handler = sessions.get(sessionId);
129
+ if (!handler) throw XacppError.internal(`unknown session: ${sessionId}`);
130
+ if ("command" === payload.kind) return handler.onCommand(payload.payload);
131
+ return handler.onEvent(payload.payload);
132
+ }));
133
+ await this.transport.connect();
134
+ if ("disconnected" === this._state) this._state = "connected";
135
+ }
136
+ async establish(credentials, handler) {
137
+ const response = await this.transport.send(null, {
138
+ kind: "command",
139
+ payload: {
140
+ establish: {
141
+ credentials
142
+ }
143
+ }
144
+ });
145
+ if ("established" === response.kind) {
146
+ this.sessions.set(response.sessionId, handler);
147
+ return new XacppSession(this.transport, response.sessionId, response.credentials ?? null);
148
+ }
149
+ if ("establish_reject" === response.kind) throw XacppError.establishReject(response.reason);
150
+ if ("error" === response.kind) throw XacppError.application(response.code, response.message);
151
+ throw XacppError.internal(`unexpected response to establish: ${JSON.stringify(response)}`);
152
+ }
153
+ async disconnect() {
154
+ await this.transport.disconnect();
155
+ this._state = "disconnected";
156
+ this.sessions.clear();
157
+ }
158
+ async requestCommand(sessionId, command) {
159
+ return this.transport.send(sessionId, {
160
+ kind: "command",
161
+ payload: command
162
+ });
163
+ }
164
+ async requestEvent(sessionId, event) {
165
+ return this.transport.send(sessionId, {
166
+ kind: "event",
167
+ payload: event
168
+ });
169
+ }
170
+ }
171
+ const external_node_net_namespaceObject = require("node:net");
172
+ const external_node_readline_namespaceObject = require("node:readline");
173
+ class SocketTransport {
174
+ socket = null;
175
+ handler = null;
176
+ pending = new Map();
177
+ nextId = 1;
178
+ _connected = false;
179
+ _exhausted = false;
180
+ writeQueue = Promise.resolve();
181
+ inflight = new Set();
182
+ port;
183
+ host;
184
+ rl = null;
185
+ static connectTo(port, host) {
186
+ const t = new SocketTransport();
187
+ t.port = port;
188
+ t.host = host ?? "127.0.0.1";
189
+ return t;
190
+ }
191
+ constructor(socket){
192
+ if (socket) this.socket = socket;
193
+ }
194
+ async connect() {
195
+ if (this._exhausted || this._connected) throw XacppError.alreadyConnected();
196
+ if (!this.socket) {
197
+ if (void 0 === this.port) throw XacppError.alreadyConnected();
198
+ this.socket = new external_node_net_namespaceObject.Socket();
199
+ await new Promise((resolve, reject)=>{
200
+ const sock = this.socket;
201
+ const onError = (err)=>{
202
+ cleanup();
203
+ reject(new Error(`connect failed: ${err.message}`));
204
+ };
205
+ const onConnect = ()=>{
206
+ cleanup();
207
+ resolve();
208
+ };
209
+ const cleanup = ()=>{
210
+ sock.removeListener("error", onError);
211
+ sock.removeListener("connect", onConnect);
212
+ };
213
+ sock.once("error", onError);
214
+ sock.once("connect", onConnect);
215
+ sock.connect(this.port, this.host, ()=>{});
216
+ });
217
+ }
218
+ const sock = this.socket;
219
+ this.rl = external_node_readline_namespaceObject.createInterface({
220
+ input: sock
221
+ });
222
+ this.rl.on("line", (line)=>this.onFrame(line));
223
+ this.rl.on("close", ()=>{
224
+ console.info("[xacpp:socket] accept loop exited");
225
+ this.cleanup();
226
+ });
227
+ this._connected = true;
228
+ console.debug("[xacpp:socket] connected");
229
+ }
230
+ async disconnect() {
231
+ this._exhausted = true;
232
+ this._connected = false;
233
+ for (const controller of this.inflight)controller.abort();
234
+ this.inflight.clear();
235
+ if (this.rl) {
236
+ this.rl.close();
237
+ this.rl = null;
238
+ }
239
+ if (this.socket) {
240
+ this.socket.destroy();
241
+ this.socket = null;
242
+ }
243
+ this.writeQueue = Promise.resolve();
244
+ this.rejectAllPending();
245
+ console.debug("[xacpp:socket] disconnected");
246
+ }
247
+ async send(sessionId, payload) {
248
+ if (!this._connected || !this.socket) throw XacppError.notConnected();
249
+ const id = `r${this.nextId++}`;
250
+ return new Promise((resolve, reject)=>{
251
+ this.pending.set(id, {
252
+ resolve,
253
+ reject
254
+ });
255
+ const envelope = {
256
+ type: "request",
257
+ id,
258
+ ...null != sessionId ? {
259
+ session_id: sessionId
260
+ } : {},
261
+ payload
262
+ };
263
+ this.writeEnvelope(envelope).catch(()=>{
264
+ this.pending.delete(id);
265
+ reject(XacppError.closed());
266
+ });
267
+ });
268
+ }
269
+ onRequest(handler) {
270
+ if (this._connected) throw XacppError.alreadyConnected();
271
+ this.handler = handler;
272
+ }
273
+ async onFrame(line) {
274
+ let envelope;
275
+ try {
276
+ envelope = JSON.parse(line);
277
+ } catch {
278
+ console.warn("[xacpp:socket] failed to parse frame: %s", line);
279
+ return;
280
+ }
281
+ if ("request" === envelope.type) this.dispatchRequest(envelope);
282
+ else if ("response" === envelope.type) {
283
+ const pending = this.pending.get(envelope.id);
284
+ if (pending) {
285
+ this.pending.delete(envelope.id);
286
+ pending.resolve(envelope.payload);
287
+ } else console.warn("[xacpp:socket] received response for unknown request %s", envelope.id);
288
+ }
289
+ }
290
+ dispatchRequest(envelope) {
291
+ if (!this.handler) return void this.writeEnvelope({
292
+ type: "response",
293
+ id: envelope.id,
294
+ ...null != envelope.session_id ? {
295
+ session_id: envelope.session_id
296
+ } : {},
297
+ payload: {
298
+ kind: "error",
299
+ code: "no_handler",
300
+ message: "no handler registered"
301
+ }
302
+ }).catch(()=>{});
303
+ const controller = new AbortController();
304
+ this.inflight.add(controller);
305
+ const sessionId = envelope.session_id ?? null;
306
+ const handler = this.handler;
307
+ handler(sessionId, envelope.payload).then((responsePayload)=>{
308
+ if (controller.signal.aborted) return;
309
+ return this.writeEnvelope({
310
+ type: "response",
311
+ id: envelope.id,
312
+ ...null != envelope.session_id ? {
313
+ session_id: envelope.session_id
314
+ } : {},
315
+ payload: responsePayload
316
+ });
317
+ }).catch((e)=>{
318
+ if (controller.signal.aborted) return;
319
+ const err = e instanceof XacppError ? e : XacppError.internal(e instanceof Error ? e.message : String(e));
320
+ console.error("[xacpp:socket] handler error for request %s: %s", envelope.id, err.message);
321
+ return this.writeEnvelope({
322
+ type: "response",
323
+ id: envelope.id,
324
+ ...null != envelope.session_id ? {
325
+ session_id: envelope.session_id
326
+ } : {},
327
+ payload: {
328
+ kind: "error",
329
+ code: err.code,
330
+ message: err.message
331
+ }
332
+ });
333
+ }).finally(()=>{
334
+ this.inflight.delete(controller);
335
+ });
336
+ }
337
+ writeEnvelope(envelope) {
338
+ if (!this.socket) return Promise.reject(XacppError.closed());
339
+ const json = JSON.stringify(envelope) + "\n";
340
+ const sock = this.socket;
341
+ let resolveOp;
342
+ let rejectOp;
343
+ const opPromise = new Promise((resolve, reject)=>{
344
+ resolveOp = resolve;
345
+ rejectOp = reject;
346
+ });
347
+ this.writeQueue = this.writeQueue.then(()=>new Promise((chainResolve)=>{
348
+ sock.write(json, (err)=>{
349
+ if (err) rejectOp(XacppError.closed());
350
+ else resolveOp();
351
+ chainResolve();
352
+ });
353
+ }), ()=>{});
354
+ return opPromise;
355
+ }
356
+ rejectAllPending() {
357
+ const err = XacppError.closed();
358
+ for (const [, p] of this.pending)p.reject(err);
359
+ this.pending.clear();
360
+ }
361
+ cleanup() {
362
+ this._connected = false;
363
+ this.rejectAllPending();
364
+ }
365
+ }
366
+ class StdioTransport {
367
+ writer;
368
+ reader;
369
+ rl = null;
370
+ _connected = false;
371
+ _exhausted = false;
372
+ requestHandler = null;
373
+ pending = new Map();
374
+ nextId = 1;
375
+ constructor(writer, reader){
376
+ this.writer = writer;
377
+ this.reader = reader;
378
+ }
379
+ genId() {
380
+ return `r${this.nextId++}`;
381
+ }
382
+ async connect() {
383
+ if (this._exhausted) throw XacppError.alreadyConnected();
384
+ if (this._connected) throw XacppError.alreadyConnected();
385
+ if (!this.writer || !this.reader) throw XacppError.alreadyConnected();
386
+ this.rl = external_node_readline_namespaceObject.createInterface({
387
+ input: this.reader
388
+ });
389
+ this.rl.on("line", (line)=>{
390
+ this.onFrame(line);
391
+ });
392
+ this.rl.on("close", ()=>{
393
+ console.info("[xacpp:stdio] accept loop exited");
394
+ this.cleanup();
395
+ });
396
+ this._connected = true;
397
+ console.debug("[xacpp:stdio] connected");
398
+ }
399
+ async disconnect() {
400
+ if (this.rl) {
401
+ this.rl.close();
402
+ this.rl = null;
403
+ }
404
+ if (this.writer) {
405
+ this.writer.end();
406
+ this.writer = null;
407
+ }
408
+ this.reader = null;
409
+ this.cleanup();
410
+ this._exhausted = true;
411
+ console.debug("[xacpp:stdio] disconnected");
412
+ }
413
+ async send(sessionId, payload) {
414
+ if (!this._connected || !this.writer) throw XacppError.notConnected();
415
+ const id = this.genId();
416
+ return new Promise((resolve, reject)=>{
417
+ this.pending.set(id, {
418
+ resolve,
419
+ reject
420
+ });
421
+ const envelope = {
422
+ type: "request",
423
+ id,
424
+ ...null != sessionId ? {
425
+ session_id: sessionId
426
+ } : {},
427
+ payload
428
+ };
429
+ const json = JSON.stringify(envelope) + "\n";
430
+ this.writer.write(json, (err)=>{
431
+ if (err) {
432
+ this.pending.delete(id);
433
+ reject(XacppError.closed());
434
+ }
435
+ });
436
+ });
437
+ }
438
+ onRequest(handler) {
439
+ if (this._connected) throw XacppError.alreadyConnected();
440
+ this.requestHandler = handler;
441
+ }
442
+ async onFrame(line) {
443
+ let envelope;
444
+ try {
445
+ envelope = JSON.parse(line);
446
+ } catch {
447
+ console.warn("[xacpp:stdio] failed to parse frame: %s", line);
448
+ return;
449
+ }
450
+ if ("request" === envelope.type) await this.handleRequest(envelope.id, envelope.session_id ?? null, envelope.payload);
451
+ else if ("response" === envelope.type) this.handleResponse(envelope.id, envelope.payload);
452
+ }
453
+ async handleRequest(id, sessionId, payload) {
454
+ let responsePayload;
455
+ try {
456
+ if (!this.requestHandler) throw XacppError.noHandler();
457
+ responsePayload = await this.requestHandler(sessionId, payload);
458
+ } catch (e) {
459
+ const err = e instanceof XacppError ? e : XacppError.internal(e instanceof Error ? e.message : String(e));
460
+ console.error("[xacpp:stdio] handler error for request %s: %s", id, err.message);
461
+ responsePayload = {
462
+ kind: "error",
463
+ code: err.code,
464
+ message: err.message
465
+ };
466
+ }
467
+ const response = {
468
+ type: "response",
469
+ id,
470
+ ...null != sessionId ? {
471
+ session_id: sessionId
472
+ } : {},
473
+ payload: responsePayload
474
+ };
475
+ const ok = this.writeEnvelope(response);
476
+ if (!ok) console.warn("[xacpp:stdio] failed to send response for request %s", id);
477
+ }
478
+ handleResponse(id, payload) {
479
+ const pending = this.pending.get(id);
480
+ if (pending) {
481
+ this.pending.delete(id);
482
+ pending.resolve(payload);
483
+ } else console.warn("[xacpp:stdio] received response for unknown request %s", id);
484
+ }
485
+ writeEnvelope(envelope) {
486
+ if (!this.writer) return false;
487
+ const json = JSON.stringify(envelope) + "\n";
488
+ return this.writer.write(json);
489
+ }
490
+ cleanup() {
491
+ this._connected = false;
492
+ const err = XacppError.closed();
493
+ for (const [id, pending] of this.pending){
494
+ console.warn("[xacpp:stdio] rejecting pending request %s: %s", id, err.message);
495
+ pending.reject(err);
496
+ }
497
+ this.pending.clear();
498
+ }
499
+ }
500
+ exports.PeerState = __webpack_exports__.PeerState;
501
+ exports.SocketTransport = __webpack_exports__.SocketTransport;
502
+ exports.StdioTransport = __webpack_exports__.StdioTransport;
503
+ exports.XacppError = __webpack_exports__.XacppError;
504
+ exports.XacppPeer = __webpack_exports__.XacppPeer;
505
+ exports.XacppSession = __webpack_exports__.XacppSession;
506
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
507
+ "PeerState",
508
+ "SocketTransport",
509
+ "StdioTransport",
510
+ "XacppError",
511
+ "XacppPeer",
512
+ "XacppSession"
513
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
514
+ Object.defineProperty(exports, '__esModule', {
515
+ value: true
516
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * XACPP protocol command types.
3
+ *
4
+ * Commands are transmitted via transport, driving the interaction flow between the initiator and the peer.
5
+ *
6
+ * Establish replaces the legacy Paring/Authenticate, unifying handshake and session establishment.
7
+ */
8
+ /** XACPP protocol command. */
9
+ export type XacppCommand =
10
+ /** Establish logical session. */
11
+ {
12
+ establish: {
13
+ credentials: string | null;
14
+ };
15
+ }
16
+ /** Create a new Activity session. */
17
+ | "new_activity"
18
+ /** Invoke an existing Activity to perform an operation. */
19
+ | "invoke_activity"
20
+ /** Compact Activity (reclaim resources / generate snapshot summary). */
21
+ | "compact_activity"
22
+ /** Cancel Activity. */
23
+ | "cancel_activity";
@@ -0,0 +1,40 @@
1
+ /** 多模态内容基础类型。 */
2
+ /** 文件引用(协议级简化版)。 */
3
+ export interface FileRef {
4
+ remoteUrl: string;
5
+ localUri: string;
6
+ mimeType: string;
7
+ sizeBytes: number;
8
+ }
9
+ export interface TextPart {
10
+ type: "text";
11
+ text: string;
12
+ partId?: string;
13
+ }
14
+ export interface ImagePart {
15
+ type: "image";
16
+ source: FileRef;
17
+ detail?: string;
18
+ width?: number;
19
+ height?: number;
20
+ partId?: string;
21
+ }
22
+ export interface AudioPart {
23
+ type: "audio";
24
+ source: FileRef;
25
+ sampleRate?: number;
26
+ channels?: number;
27
+ durationMs?: number;
28
+ partId?: string;
29
+ }
30
+ export interface VideoPart {
31
+ type: "video";
32
+ source: FileRef;
33
+ durationMs?: number;
34
+ fps?: number;
35
+ width?: number;
36
+ height?: number;
37
+ partId?: string;
38
+ }
39
+ /** 统一多模态内容分片。 */
40
+ export type ContentPart = TextPart | ImagePart | AudioPart | VideoPart;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ACPP event types.
3
+ *
4
+ * Standardized event stream between the initiator and the peer.
5
+ */
6
+ export * from "./content";
7
+ export * from "./interaction";
8
+ export * from "./payload";
9
+ export * from "./upload";
10
+ export type { XacppEvent } from "./xacpp_event";
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 交互事件载荷(请求-响应模式)。
3
+ *
4
+ * 协议层不持有通道,通过 requestId 进行请求-响应关联,
5
+ * 响应方通过 transport 发送对应的 Response 消息。
6
+ */
7
+ import type { AlertLevel } from "./payload";
8
+ /** 工具调用授权响应。 */
9
+ export type ActionResponse = {
10
+ type: "approve";
11
+ } | {
12
+ type: "approve_always";
13
+ } | {
14
+ type: "reject";
15
+ reason: string;
16
+ };
17
+ /** 工具调用授权请求事件载荷。 */
18
+ export interface ActionRequestEvent {
19
+ requestId: string;
20
+ toolName: string;
21
+ arguments: string;
22
+ actionId: string;
23
+ description: string;
24
+ alert: AlertLevel;
25
+ }
26
+ /** 用户通知事件载荷(单向推送,不阻塞等待回复)。 */
27
+ export interface NotifyEvent {
28
+ requestId: string;
29
+ message: string;
30
+ }
31
+ /** 用户提问响应。 */
32
+ export type QuestionResponse = {
33
+ type: "answer";
34
+ content: string;
35
+ } | {
36
+ type: "skip";
37
+ reason?: string;
38
+ };
39
+ /** 用户提问事件载荷。 */
40
+ export interface QuestionEvent {
41
+ requestId: string;
42
+ question: string;
43
+ options: string[];
44
+ }
45
+ /** 敏感信息类型。 */
46
+ export type SensitiveInfoType = "secret" | "env_var";
47
+ /** 敏感信息条目(脱敏展示)。 */
48
+ export interface SensitiveInfoItem {
49
+ id?: string;
50
+ key: string;
51
+ displayText: string;
52
+ hint: string;
53
+ siType: SensitiveInfoType;
54
+ }
55
+ /** 敏感信息操作类型。 */
56
+ export type SensitiveInfoOperation = {
57
+ type: "collect";
58
+ items: SensitiveInfoItem[];
59
+ } | {
60
+ type: "delete";
61
+ items: SensitiveInfoItem[];
62
+ };
63
+ /** 单个敏感信息的操作结果。 */
64
+ export type SensitiveInfoResult = {
65
+ type: "provided";
66
+ key: string;
67
+ value: string;
68
+ } | {
69
+ type: "collect_skipped";
70
+ key: string;
71
+ reason?: string;
72
+ } | {
73
+ type: "deleted";
74
+ id: string;
75
+ } | {
76
+ type: "delete_rejected";
77
+ id: string;
78
+ reason?: string;
79
+ };
80
+ /** 敏感信息操作响应。 */
81
+ export interface SensitiveInfoOperationResponse {
82
+ results: SensitiveInfoResult[];
83
+ }
84
+ /** 敏感信息操作请求事件载荷。 */
85
+ export interface SensitiveInfoOperationEvent {
86
+ requestId: string;
87
+ operation: SensitiveInfoOperation;
88
+ }