@agentdock/sdk 0.0.1

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.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # @agentdock/sdk
2
+
3
+ > 客户端 SDK — Socket.IO 连接管理 + 类型安全 RPC + 离线队列。
4
+
5
+ ## 概述
6
+
7
+ sdk 包为 Web 前端和其他客户端提供与 AgentDock server 的连接能力:
8
+
9
+ - **自动重连**:断线后指数退避重连,连接状态实时可观测
10
+ - **RPC 封装**:类型安全的远程调用,Promise 风格
11
+ - **离线队列**:断线期间的 RPC 调用自动入队,重连后按序 flush
12
+ - **事件流**:订阅 CoreUpdate 实时推送
13
+
14
+ ## 在架构中的位置
15
+
16
+ ```
17
+ wire → crypto → sdk → web
18
+ ```
19
+
20
+ 依赖 wire(协议定义)和 crypto(加密),被 web 包使用。
21
+
22
+ ## 模块结构
23
+
24
+ ```
25
+ src/
26
+ ├── client.ts # AgentdockClient — 连接管理 + 事件订阅 + 状态监听
27
+ ├── rpc.ts # RpcClient — 类型安全 RPC + 离线队列 + flush
28
+ └── index.ts # Barrel exports
29
+ ```
30
+
31
+ ## API 参考
32
+
33
+ ### createClient (client.ts)
34
+
35
+ ```typescript
36
+ import { createClient } from '@agentdock/sdk';
37
+ import type { AgentdockClient, ClientConfig } from '@agentdock/sdk';
38
+
39
+ const client: AgentdockClient = createClient({
40
+ serverUrl: 'https://api.agentdock.dev',
41
+ token: 'user-auth-token',
42
+ clientType: 'web', // 'web' | 'daemon' | 'cli'
43
+ autoConnect: true, // 默认 true
44
+ });
45
+
46
+ // 连接状态监听
47
+ const unsub = client.onStatus((status: ConnectionStatus) => {
48
+ // 'connected' | 'connecting' | 'disconnected' | 'error'
49
+ console.log('Connection:', status);
50
+ });
51
+
52
+ // 订阅实时更新
53
+ const unsub2 = client.onUpdate((update: CoreUpdate) => {
54
+ // 处理增量更新(会话事件、消息等)
55
+ });
56
+
57
+ // 手动连接/断开
58
+ client.connect();
59
+ client.disconnect(); // 清理所有事件监听器(L16 教训)
60
+ ```
61
+
62
+ ### createRpcClient (rpc.ts)
63
+
64
+ ```typescript
65
+ import { createRpcClient } from '@agentdock/sdk';
66
+ import type { RpcClient, RpcTransport } from '@agentdock/sdk';
67
+
68
+ const rpc: RpcClient = createRpcClient(transport);
69
+
70
+ // 调用 RPC 方法(在线时立即发送,离线时入队)
71
+ const result: RpcResult = await rpc.call('method-name', params);
72
+
73
+ // 离线队列在重连时自动 flush(带互斥锁防竞态,L19 教训)
74
+ ```
75
+
76
+ ### 类型定义
77
+
78
+ ```typescript
79
+ type ConnectionStatus = 'connected' | 'connecting' | 'disconnected' | 'error';
80
+ type ClientType = 'web' | 'daemon' | 'cli';
81
+ type Unsubscribe = () => void;
82
+ type StatusListener = (status: ConnectionStatus) => void;
83
+ type UpdateListener = (update: CoreUpdate) => void;
84
+ ```
85
+
86
+ ## 开发
87
+
88
+ ```bash
89
+ # 运行测试(42 tests)
90
+ pnpm --filter @agentdock/sdk test
91
+
92
+ # 覆盖率(目标 90%+)
93
+ pnpm --filter @agentdock/sdk test:coverage
94
+ ```
95
+
96
+ ## 设计决策
97
+
98
+ - **Socket.IO 而非原生 WebSocket**:自动重连、命名空间、房间、二进制支持
99
+ - **RPC + 离线队列**:离线期间操作不丢失,重连后补发
100
+ - **flush 互斥锁**:防止两次 reconnect 触发竞态(L19 教训)
101
+ - **disconnect 清理**:所有 `on()` 注册都有对应 `off()` 清理(L16 教训)
@@ -0,0 +1,61 @@
1
+ /**
2
+ * AgentDock SDK client — Socket.IO connection management.
3
+ *
4
+ * Provides a uniform interface for connecting to the AgentDock server
5
+ * with auto-reconnection, status tracking, and event handling.
6
+ */
7
+ import { type Socket } from 'socket.io-client';
8
+ /** Connection status for the client. */
9
+ export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
10
+ /** Client scope type for auth. */
11
+ export type ClientType = 'user-scoped' | 'session-scoped' | 'machine-scoped';
12
+ /** Status change listener. */
13
+ export type StatusListener = (status: ConnectionStatus) => void;
14
+ /** Update data listener. */
15
+ export type UpdateListener = (data: unknown) => void;
16
+ /** Unsubscribe function returned by event registration. */
17
+ export type Unsubscribe = () => void;
18
+ /** Socket factory — returns a Socket-like object. Used for DI in tests. */
19
+ export type SocketFactory = (endpoint: string, opts: Record<string, unknown>) => Socket;
20
+ /** Client configuration. */
21
+ export interface ClientConfig {
22
+ /** Server endpoint URL. */
23
+ readonly endpoint: string;
24
+ /** Authentication token. */
25
+ readonly token: string;
26
+ /** Socket.IO path (default: '/v1/updates'). */
27
+ readonly path?: string;
28
+ /** Client scope type (default: 'user-scoped'). */
29
+ readonly clientType?: ClientType;
30
+ /** Session ID (required for session-scoped). */
31
+ readonly sessionId?: string;
32
+ /** Machine ID (required for machine-scoped). */
33
+ readonly machineId?: string;
34
+ /** Reconnection delay in ms (default: 1000). */
35
+ readonly reconnectionDelay?: number;
36
+ /** Max reconnection delay in ms (default: 5000). */
37
+ readonly reconnectionDelayMax?: number;
38
+ /** Internal: socket factory for testing. */
39
+ readonly _socketFactory?: SocketFactory;
40
+ }
41
+ /** AgentDock client interface. */
42
+ export interface AgentdockClient {
43
+ /** Connect to the server. */
44
+ connect(): void;
45
+ /** Disconnect from the server. */
46
+ disconnect(): void;
47
+ /** Get the current connection status. */
48
+ getStatus(): ConnectionStatus;
49
+ /** Listen for status changes. Returns unsubscribe function. */
50
+ onStatusChange(listener: StatusListener): Unsubscribe;
51
+ /** Listen for server update events. Returns unsubscribe function. */
52
+ onUpdate(listener: UpdateListener): Unsubscribe;
53
+ /** Emit an event with acknowledgement (RPC-style). */
54
+ emitWithAck<T>(event: string, data: unknown): Promise<T>;
55
+ /** Subscribe to a raw socket event. Returns unsubscribe function. */
56
+ on(event: string, handler: (...args: unknown[]) => void): Unsubscribe;
57
+ /** Emit a raw socket event (fire-and-forget). */
58
+ emit(event: string, ...args: unknown[]): void;
59
+ }
60
+ export declare function createClient(config: ClientConfig): AgentdockClient;
61
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAKnD,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAErF,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAE7E,8BAA8B;AAC9B,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE,4BAA4B;AAC5B,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;AAErD,2DAA2D;AAC3D,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;AAExF,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IAC3B,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,gDAAgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,oDAAoD;IACpD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,4CAA4C;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC;CACzC;AAED,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,OAAO,IAAI,IAAI,CAAC;IAChB,kCAAkC;IAClC,UAAU,IAAI,IAAI,CAAC;IACnB,yCAAyC;IACzC,SAAS,IAAI,gBAAgB,CAAC;IAC9B,+DAA+D;IAC/D,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,WAAW,CAAC;IACtD,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,WAAW,CAAC;IAChD,sDAAsD;IACtD,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzD,qEAAqE;IACrE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,WAAW,CAAC;IACtE,iDAAiD;IACjD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC/C;AAYD,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAiJlE"}
package/dist/client.js ADDED
@@ -0,0 +1,145 @@
1
+ /**
2
+ * AgentDock SDK client — Socket.IO connection management.
3
+ *
4
+ * Provides a uniform interface for connecting to the AgentDock server
5
+ * with auto-reconnection, status tracking, and event handling.
6
+ */
7
+ import { io } from 'socket.io-client';
8
+ import createDebug from 'debug';
9
+ // ── Factory ─────────────────────────────────────────────────────────
10
+ /**
11
+ * Create an AgentDock client instance.
12
+ *
13
+ * @param config - Client configuration.
14
+ * @returns An AgentdockClient ready to be connected.
15
+ */
16
+ const log = createDebug('agentdock:sdk:client');
17
+ export function createClient(config) {
18
+ let status = 'disconnected';
19
+ let socket = null;
20
+ const statusListeners = new Set();
21
+ const updateListeners = new Set();
22
+ const createSocket = config._socketFactory ?? io;
23
+ // Buffer for event listeners registered before connect()
24
+ const pendingListeners = [];
25
+ function setStatus(newStatus) {
26
+ status = newStatus;
27
+ for (const listener of statusListeners) {
28
+ listener(newStatus);
29
+ }
30
+ }
31
+ function emitUpdate(data) {
32
+ for (const listener of updateListeners) {
33
+ listener(data);
34
+ }
35
+ }
36
+ function buildAuth() {
37
+ const auth = {
38
+ token: config.token,
39
+ clientType: config.clientType ?? 'user-scoped',
40
+ };
41
+ if (config.sessionId) {
42
+ auth['sessionId'] = config.sessionId;
43
+ }
44
+ if (config.machineId) {
45
+ auth['machineId'] = config.machineId;
46
+ }
47
+ return auth;
48
+ }
49
+ return {
50
+ connect() {
51
+ if (socket)
52
+ return;
53
+ setStatus('connecting');
54
+ socket = createSocket(config.endpoint, {
55
+ path: config.path ?? '/v1/updates',
56
+ auth: buildAuth(),
57
+ transports: ['websocket', 'polling'],
58
+ reconnection: true,
59
+ reconnectionDelay: config.reconnectionDelay ?? 1000,
60
+ reconnectionDelayMax: config.reconnectionDelayMax ?? 5000,
61
+ reconnectionAttempts: Infinity,
62
+ autoConnect: false,
63
+ });
64
+ socket.on('connect', () => {
65
+ log('connected to %s', config.endpoint);
66
+ setStatus('connected');
67
+ });
68
+ socket.on('disconnect', (reason) => {
69
+ log('disconnected: %s', reason);
70
+ setStatus('disconnected');
71
+ });
72
+ socket.on('connect_error', (err) => {
73
+ log('connect_error: %s', err instanceof Error ? err.message : err);
74
+ setStatus('error');
75
+ });
76
+ socket.on('update', (data) => {
77
+ emitUpdate(data);
78
+ });
79
+ socket.on('ephemeral', (data) => {
80
+ emitUpdate(data);
81
+ });
82
+ // Replay any event listeners registered before connect()
83
+ for (const { event, handler } of pendingListeners) {
84
+ socket.on(event, handler);
85
+ }
86
+ pendingListeners.length = 0;
87
+ // Connect after all listeners are registered (avoids race with autoConnect)
88
+ socket.connect();
89
+ },
90
+ disconnect() {
91
+ if (socket) {
92
+ // Clean up all event listeners before disconnecting (L16)
93
+ socket.removeAllListeners();
94
+ socket.disconnect();
95
+ socket = null;
96
+ setStatus('disconnected');
97
+ }
98
+ },
99
+ getStatus() {
100
+ return status;
101
+ },
102
+ onStatusChange(listener) {
103
+ statusListeners.add(listener);
104
+ return () => {
105
+ statusListeners.delete(listener);
106
+ };
107
+ },
108
+ onUpdate(listener) {
109
+ updateListeners.add(listener);
110
+ return () => {
111
+ updateListeners.delete(listener);
112
+ };
113
+ },
114
+ async emitWithAck(event, data) {
115
+ if (!socket || !socket.connected) {
116
+ throw new Error('Not connected');
117
+ }
118
+ return socket.emitWithAck(event, data);
119
+ },
120
+ on(event, handler) {
121
+ if (socket) {
122
+ socket.on(event, handler);
123
+ }
124
+ else {
125
+ pendingListeners.push({ event, handler });
126
+ }
127
+ return () => {
128
+ if (socket) {
129
+ socket.off(event, handler);
130
+ }
131
+ else {
132
+ const idx = pendingListeners.findIndex((p) => p.event === event && p.handler === handler);
133
+ if (idx !== -1)
134
+ pendingListeners.splice(idx, 1);
135
+ }
136
+ };
137
+ },
138
+ emit(event, ...args) {
139
+ if (socket?.connected) {
140
+ socket.emit(event, ...args);
141
+ }
142
+ },
143
+ };
144
+ }
145
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { createClient } from './client.js';
2
+ export type { AgentdockClient, ClientConfig, ClientType, ConnectionStatus, StatusListener, UpdateListener, Unsubscribe, } from './client.js';
3
+ export { createRpcClient } from './rpc.js';
4
+ export type { RpcClient, RpcTransport, RpcResult } from './rpc.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @agentdock/sdk — Client SDK for AgentDock
2
+ export { createClient } from './client.js';
3
+ export { createRpcClient } from './rpc.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
package/dist/rpc.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * RPC client — typed method calls over Socket.IO with offline queue.
3
+ *
4
+ * When disconnected, calls are queued and automatically flushed
5
+ * when the transport reconnects.
6
+ */
7
+ /** RPC call result. */
8
+ export interface RpcResult<T = unknown> {
9
+ readonly ok: boolean;
10
+ readonly result?: T;
11
+ readonly error?: string;
12
+ }
13
+ /** Transport abstraction for RPC calls. */
14
+ export interface RpcTransport {
15
+ /** Emit an event and wait for acknowledgement. */
16
+ emitWithAck<T>(event: string, data: unknown): Promise<T>;
17
+ /** Whether the transport is currently connected. */
18
+ isConnected(): boolean;
19
+ }
20
+ /** RPC client interface. */
21
+ export interface RpcClient {
22
+ /** Call an RPC method. Queues if disconnected. */
23
+ call<T = unknown>(method: string, params: unknown): Promise<RpcResult<T>>;
24
+ /** Get the number of queued (offline) calls. */
25
+ getQueueSize(): number;
26
+ /** Flush queued calls (call after reconnection). */
27
+ flush(): Promise<void>;
28
+ }
29
+ /**
30
+ * Create an RPC client.
31
+ *
32
+ * @param transport - Transport layer for sending RPC calls.
33
+ * @returns An RpcClient instance.
34
+ */
35
+ export declare function createRpcClient(transport: RpcTransport): RpcClient;
36
+ //# sourceMappingURL=rpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,uBAAuB;AACvB,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzD,oDAAoD;IACpD,WAAW,IAAI,OAAO,CAAC;CACxB;AAUD,4BAA4B;AAC5B,MAAM,WAAW,SAAS;IACxB,kDAAkD;IAClD,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,gDAAgD;IAChD,YAAY,IAAI,MAAM,CAAC;IACvB,oDAAoD;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,CAyDlE"}
package/dist/rpc.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * RPC client — typed method calls over Socket.IO with offline queue.
3
+ *
4
+ * When disconnected, calls are queued and automatically flushed
5
+ * when the transport reconnects.
6
+ */
7
+ import createDebug from 'debug';
8
+ const log = createDebug('agentdock:sdk:rpc');
9
+ // ── Factory ─────────────────────────────────────────────────────────
10
+ /**
11
+ * Create an RPC client.
12
+ *
13
+ * @param transport - Transport layer for sending RPC calls.
14
+ * @returns An RpcClient instance.
15
+ */
16
+ export function createRpcClient(transport) {
17
+ const queue = [];
18
+ let isFlushing = false;
19
+ async function executeCall(method, params) {
20
+ return transport.emitWithAck('rpc-call', {
21
+ method,
22
+ params,
23
+ });
24
+ }
25
+ return {
26
+ call(method, params) {
27
+ if (transport.isConnected()) {
28
+ log('call %s', method);
29
+ return executeCall(method, params);
30
+ }
31
+ log('queued %s (offline, queue=%d)', method, queue.length + 1);
32
+ return new Promise((resolve, reject) => {
33
+ queue.push({
34
+ method,
35
+ params,
36
+ resolve: resolve,
37
+ reject,
38
+ });
39
+ });
40
+ },
41
+ getQueueSize() {
42
+ return queue.length;
43
+ },
44
+ async flush() {
45
+ if (!transport.isConnected())
46
+ return;
47
+ if (isFlushing)
48
+ return;
49
+ isFlushing = true;
50
+ log('flushing %d queued calls', queue.length);
51
+ try {
52
+ while (queue.length > 0) {
53
+ const item = queue.shift();
54
+ if (!item)
55
+ break;
56
+ try {
57
+ const result = await executeCall(item.method, item.params);
58
+ item.resolve(result);
59
+ }
60
+ catch (err) {
61
+ log('flush failed for %s: %s', item.method, err);
62
+ item.reject(err instanceof Error ? err : new Error(String(err)));
63
+ }
64
+ }
65
+ }
66
+ finally {
67
+ isFlushing = false;
68
+ }
69
+ },
70
+ };
71
+ }
72
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,WAAW,MAAM,OAAO,CAAC;AAEhC,MAAM,GAAG,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC;AAmC7C,uEAAuE;AAEvE;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,SAAuB;IACrD,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,KAAK,UAAU,WAAW,CAAI,MAAc,EAAE,MAAe;QAC3D,OAAO,SAAS,CAAC,WAAW,CAAe,UAAU,EAAE;YACrD,MAAM;YACN,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,IAAI,CAAc,MAAc,EAAE,MAAe;YAC/C,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC5B,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBACvB,OAAO,WAAW,CAAI,MAAM,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;YAED,GAAG,CAAC,+BAA+B,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACnD,KAAK,CAAC,IAAI,CAAC;oBACT,MAAM;oBACN,MAAM;oBACN,OAAO,EAAE,OAAmC;oBAC5C,MAAM;iBACP,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,YAAY;YACV,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;QAED,KAAK,CAAC,KAAK;YACT,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;gBAAE,OAAO;YACrC,IAAI,UAAU;gBAAE,OAAO;YACvB,UAAU,GAAG,IAAI,CAAC;YAClB,GAAG,CAAC,0BAA0B,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAE9C,IAAI,CAAC;gBACH,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC3B,IAAI,CAAC,IAAI;wBAAE,MAAM;oBAEjB,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC3D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACvB,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,GAAG,CAAC,yBAAyB,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;wBACjD,IAAI,CAAC,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,UAAU,GAAG,KAAK,CAAC;YACrB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@agentdock/sdk",
3
+ "version": "0.0.1",
4
+ "description": "Client SDK for AgentDock — Socket.IO, RPC, offline queue",
5
+ "license": "UNLICENSED",
6
+ "author": "kevin8536945",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public",
21
+ "registry": "https://registry.npmjs.org"
22
+ },
23
+ "dependencies": {
24
+ "debug": "^4.4.3",
25
+ "socket.io-client": "^4.8.3",
26
+ "@agentdock/crypto": "0.0.1",
27
+ "@agentdock/wire": "0.0.1"
28
+ },
29
+ "devDependencies": {
30
+ "@types/debug": "^4.1.12",
31
+ "@vitest/coverage-v8": "^3.0.0",
32
+ "typescript": "^5.7.0",
33
+ "vitest": "^3.0.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "test": "vitest run",
38
+ "test:coverage": "vitest run --coverage",
39
+ "lint": "eslint src/ && tsc --noEmit",
40
+ "typecheck": "tsc --noEmit"
41
+ }
42
+ }