phoneclaw-connector 1.0.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.
package/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # PhoneClaw Skill 使用指南
2
+
3
+ ## 概述
4
+
5
+ PhoneClaw Skill 是一个 OpenClaw 插件,用于将你的 OpenClaw Gateway 与 PhoneClaw iOS App 连接。安装后,Skill 会自动建立与中继服务器的连接,使你可以从手机远程控制你的 AI Agent。
6
+
7
+ ## 快速开始
8
+
9
+ ### 前置条件
10
+
11
+ - OpenClaw Gateway 已安装并运行
12
+ - Node.js >= 18.0.0
13
+ - 可以访问中继服务器(默认 `wss://relay.phoneclaw.com`)
14
+
15
+ ### 安装
16
+
17
+ ```bash
18
+ # 1. 克隆或下载 Skill 代码
19
+ git clone https://github.com/your-org/phoneclaw-skill.git
20
+ cd phoneclaw-skill
21
+
22
+ # 2. 安装依赖
23
+ npm install
24
+
25
+ # 3. 构建
26
+ npm run build
27
+
28
+ # 4. 安装到 OpenClaw
29
+ openclaw skills install ./dist
30
+ ```
31
+
32
+ ### 配置
33
+
34
+ 编辑 `config.json` 文件:
35
+
36
+ ```json
37
+ {
38
+ "relayServer": "wss://relay.phoneclaw.com",
39
+ "autoConnect": true,
40
+ "heartbeatInterval": 30000,
41
+ "reconnectAttempts": 5,
42
+ "reconnectDelay": 5000,
43
+ "gatewayUrl": "ws://127.0.0.1:18789",
44
+ "gatewayToken": ""
45
+ }
46
+ ```
47
+
48
+ | 配置项 | 说明 | 默认值 |
49
+ |--------|------|--------|
50
+ | `relayServer` | 中继服务器地址 | `wss://relay.phoneclaw.com` |
51
+ | `autoConnect` | 是否自动连接 | `true` |
52
+ | `heartbeatInterval` | 心跳间隔(毫秒) | `30000` |
53
+ | `reconnectAttempts` | 最大重连次数 | `5` |
54
+ | `reconnectDelay` | 重连基础延迟(毫秒) | `5000` |
55
+ | `gatewayUrl` | OpenClaw Gateway 地址 | `ws://127.0.0.1:18789` |
56
+ | `gatewayToken` | Gateway 认证 Token(可选) | `""` |
57
+
58
+ ### 启动
59
+
60
+ ```bash
61
+ # 启动 Skill
62
+ npm start
63
+
64
+ # 或使用 openclaw 命令
65
+ openclaw skills enable phoneclaw-connector
66
+ openclaw skills start phoneclaw-connector
67
+ ```
68
+
69
+ ## 使用方式
70
+
71
+ ### 生成配对码
72
+
73
+ ```bash
74
+ # 生成 6 位配对码和二维码
75
+ npm run pair
76
+
77
+ # 输出示例:
78
+ # === PhoneClaw Pairing Code ===
79
+ # Code: 123456
80
+ # Expires: 2024-01-01 12:00:00
81
+ #
82
+ # QR Code:
83
+ # ██████████████████████████████
84
+ # ...
85
+ # ==============================
86
+ ```
87
+
88
+ ### 查看状态
89
+
90
+ ```bash
91
+ # 查看连接状态
92
+ npm run status
93
+
94
+ # 输出示例:
95
+ # === PhoneClaw Skill Status ===
96
+ # Device ID: abc123def456
97
+ # Gateway: Connected
98
+ # Relay: Connected
99
+ # Active Sessions: 2
100
+ # ===============================
101
+ ```
102
+
103
+ ### 日常使用
104
+
105
+ 1. **启动 Skill**:运行 `npm start`
106
+ 2. **打开 PhoneClaw App**:在 iPhone 上打开 App
107
+ 3. **扫码配对**:扫描 Skill 终端显示的二维码,或手动输入配对码
108
+ 4. **开始聊天**:配对成功后即可从手机发送消息
109
+
110
+ ## 命令参考
111
+
112
+ | 命令 | 说明 |
113
+ |------|------|
114
+ | `npm start` | 启动 Skill(守护进程模式) |
115
+ | `npm run pair` | 生成配对码和二维码 |
116
+ | `npm run status` | 查看连接状态 |
117
+ | `npm run build` | 构建 TypeScript 代码 |
118
+ | `npm run dev` | 开发模式(带热重载) |
119
+
120
+ ## 故障排查
121
+
122
+ ### 无法连接到中继服务器
123
+
124
+ ```bash
125
+ # 检查网络连接
126
+ ping relay.phoneclaw.com
127
+
128
+ # 检查防火墙设置
129
+ # 确保出站 WebSocket 连接(端口 443)未被阻止
130
+ ```
131
+
132
+ ### 无法连接到 Gateway
133
+
134
+ ```bash
135
+ # 检查 Gateway 是否运行
136
+ openclaw gateway status
137
+
138
+ # 检查 Gateway 地址和端口
139
+ # 默认: ws://127.0.0.1:18789
140
+
141
+ # 检查 Token 是否正确
142
+ # 如果配置了 gatewayToken,确保与 Gateway 配置一致
143
+ ```
144
+
145
+ ### 配对失败
146
+
147
+ ```bash
148
+ # 检查配对码是否过期(10 分钟有效)
149
+ # 重新生成配对码: npm run pair
150
+
151
+ # 检查设备是否在线
152
+ npm run status
153
+
154
+ # 确保 Skill 已连接到中继服务器
155
+ ```
156
+
157
+ ### 消息发送失败
158
+
159
+ ```bash
160
+ # 检查 Gateway 连接状态
161
+ npm run status
162
+
163
+ # 检查中继服务器连接状态
164
+ npm run status
165
+
166
+ # 查看日志输出
167
+ # Skill 会在终端输出详细的连接和消息日志
168
+ ```
169
+
170
+ ## 高级配置
171
+
172
+ ### 自定义中继服务器
173
+
174
+ 如果你部署了自己的中继服务器,修改 `config.json`:
175
+
176
+ ```json
177
+ {
178
+ "relayServer": "wss://your-relay-server.com"
179
+ }
180
+ ```
181
+
182
+ ### 自定义 Gateway 地址
183
+
184
+ 如果 Gateway 运行在非默认地址或远程服务器:
185
+
186
+ ```json
187
+ {
188
+ "gatewayUrl": "ws://your-gateway-server.com:18789",
189
+ "gatewayToken": "your-gateway-token"
190
+ }
191
+ ```
192
+
193
+ ### 日志级别
194
+
195
+ Skill 默认输出 INFO 级别日志。要启用调试日志:
196
+
197
+ ```bash
198
+ # 设置环境变量
199
+ DEBUG=phoneclaw:* npm start
200
+ ```
201
+
202
+ ## 安全注意事项
203
+
204
+ - **设备密钥**:`device.json` 文件包含设备认证密钥,请妥善保管
205
+ - **配对码**:配对码 10 分钟有效,使用后自动失效
206
+ - **网络连接**:确保中继服务器使用 WSS(WebSocket Secure)加密连接
207
+ - **Token 保护**:如果配置了 `gatewayToken`,不要将其提交到版本控制系统
208
+
209
+ ## 更新
210
+
211
+ ```bash
212
+ # 拉取最新代码
213
+ git pull
214
+
215
+ # 重新安装依赖
216
+ npm install
217
+
218
+ # 重新构建
219
+ npm run build
220
+
221
+ # 重启 Skill
222
+ npm start
223
+ ```
224
+
225
+ ## 技术支持
226
+
227
+ - 文档:[PhoneClaw 技术方案](../requirements/technical-solution.md)
228
+ - 问题反馈:wzzvictory_tjsd@163.com
package/SKILL.md ADDED
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: phone-claw-skill
3
+ description: Connect PhoneClaw iOS app to this OpenClaw Gateway via relay server. Enables remote control from mobile device. Auto-activates when user wants to pair their phone or send messages through PhoneClaw app.
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ bins: ["node"]
8
+ env: ["HOME"]
9
+ ---
10
+
11
+ # PhoneClaw Relay Connector
12
+
13
+ This skill establishes and maintains a WebSocket connection between this OpenClaw Gateway and the PhoneClaw iOS app through a relay server. Once connected, users can interact with this AI agent from their iPhone.
14
+
15
+ ## When to Use
16
+
17
+ - User wants to connect their iPhone to this OpenClaw instance
18
+ - User mentions PhoneClaw, mobile connection, or phone pairing
19
+ - User wants to generate a pairing code for their phone
20
+ - User wants to check connection status with PhoneClaw app
21
+
22
+ ## How It Works
23
+
24
+ ### Architecture
25
+
26
+ ```
27
+ PhoneClaw iOS App <--WSS--> Relay Server <--WSS--> PhoneClaw Skill <--WebSocket--> OpenClaw Gateway
28
+ ```
29
+
30
+ The skill runs as a background process that:
31
+ 1. Connects to the relay server via WebSocket
32
+ 2. Listens for incoming messages from the PhoneClaw app
33
+ 3. Forwards messages to the OpenClaw Gateway
34
+ 4. Streams AI responses back to the phone
35
+
36
+ ### Quick Start
37
+
38
+ #### 1. Install Dependencies
39
+
40
+ ```bash
41
+ cd ~/.openclaw/workspace/skills/phoneclaw-relay
42
+ npm install
43
+ ```
44
+
45
+ #### 2. Configure
46
+
47
+ Edit `config.json`:
48
+
49
+ ```json
50
+ {
51
+ "relayServer": "wss://relay.phoneclaw.com",
52
+ "autoConnect": true,
53
+ "heartbeatInterval": 30000,
54
+ "gatewayUrl": "ws://127.0.0.1:18789",
55
+ "gatewayToken": ""
56
+ }
57
+ ```
58
+
59
+ | Field | Description | Default |
60
+ |-------|-------------|---------|
61
+ | `relayServer` | Relay server WebSocket URL | `wss://relay.phoneclaw.com` |
62
+ | `autoConnect` | Auto-connect on startup | `true` |
63
+ | `heartbeatInterval` | Heartbeat interval (ms) | `30000` |
64
+ | `gatewayUrl` | OpenClaw Gateway URL | `ws://127.0.0.1:18789` |
65
+ | `gatewayToken` | Gateway auth token (optional) | `""` |
66
+
67
+ #### 3. Start the Connector
68
+
69
+ ```bash
70
+ npm start
71
+ ```
72
+
73
+ The skill will:
74
+ - Generate a unique device ID (stored in `device.json`)
75
+ - Connect to the relay server
76
+ - Wait for phone pairing
77
+
78
+ #### 4. Pair Your Phone
79
+
80
+ Generate a pairing code:
81
+
82
+ ```bash
83
+ npm run pair
84
+ ```
85
+
86
+ Output example:
87
+ ```
88
+ === PhoneClaw Pairing Code ===
89
+ Code: 123456
90
+ Expires: 2024-01-01 12:00:00
91
+
92
+ QR Code:
93
+ ██████████████████████████████
94
+ ...
95
+ ==============================
96
+ ```
97
+
98
+ Open the PhoneClaw app on your iPhone and:
99
+ 1. Tap "Add Device"
100
+ 2. Scan the QR code or enter the 6-digit code
101
+ 3. Wait for pairing confirmation
102
+
103
+ #### 5. Check Status
104
+
105
+ ```bash
106
+ npm run status
107
+ ```
108
+
109
+ Output example:
110
+ ```
111
+ === PhoneClaw Skill Status ===
112
+ Device ID: abc123def456
113
+ Gateway: Connected
114
+ Relay: Connected
115
+ Active Sessions: 2
116
+ ===============================
117
+ ```
118
+
119
+ ## Commands
120
+
121
+ | Command | Description |
122
+ |---------|-------------|
123
+ | `npm start` | Start the connector (daemon mode) |
124
+ | `npm run pair` | Generate pairing code and QR code |
125
+ | `npm run status` | Show connection status |
126
+ | `npm run build` | Build TypeScript code |
127
+ | `npm run dev` | Development mode with hot reload |
128
+
129
+ ## Message Flow
130
+
131
+ ### Phone Sends Message
132
+
133
+ 1. User types message in PhoneClaw app
134
+ 2. App sends to relay server: `{ type: "message", deviceId, sessionId, content }`
135
+ 3. Relay forwards to this skill: `{ type: "forward_message", sessionId, content }`
136
+ 4. Skill forwards to OpenClaw Gateway
137
+ 5. Gateway processes with AI model
138
+ 6. Skill receives streaming response
139
+ 7. Skill forwards chunks to relay: `{ type: "stream_chunk", sessionId, chunk }`
140
+ 8. Relay forwards to PhoneClaw app
141
+ 9. App displays response in real-time
142
+
143
+ ### Session Management
144
+
145
+ - Each conversation has a unique `sessionId`
146
+ - Sessions are tracked in memory
147
+ - User can rename, export, or delete sessions from the app
148
+ - Session history is stored on the device (not on relay server)
149
+
150
+ ## Troubleshooting
151
+
152
+ ### Cannot Connect to Relay Server
153
+
154
+ ```bash
155
+ # Check network
156
+ ping relay.phoneclaw.com
157
+
158
+ # Check firewall (ensure outbound WebSocket on port 443 is allowed)
159
+ ```
160
+
161
+ ### Cannot Connect to Gateway
162
+
163
+ ```bash
164
+ # Check Gateway is running
165
+ openclaw gateway status
166
+
167
+ # Check Gateway URL and port (default: ws://127.0.0.1:18789)
168
+
169
+ # Check token matches Gateway config
170
+ ```
171
+
172
+ ### Pairing Fails
173
+
174
+ - Pairing codes expire after 10 minutes
175
+ - Generate a new code: `npm run pair`
176
+ - Ensure skill is connected to relay server: `npm run status`
177
+
178
+ ### Messages Not Sending
179
+
180
+ - Check both Gateway and Relay connections: `npm run status`
181
+ - Review terminal logs for error messages
182
+ - Restart the connector: `npm start`
183
+
184
+ ## Security Notes
185
+
186
+ - **Device Key**: `device.json` contains authentication credentials - keep it secure
187
+ - **Pairing Code**: Valid for 10 minutes, single-use only
188
+ - **Encryption**: All connections use WSS (WebSocket Secure) with TLS 1.3
189
+ - **Token Protection**: Never commit `gatewayToken` to version control
190
+
191
+ ## Update
192
+
193
+ ```bash
194
+ git pull
195
+ npm install
196
+ npm run build
197
+ npm start
198
+ ```
199
+
200
+ ## Support
201
+
202
+ - Technical documentation: See `requirements/technical-solution.md` in project root
203
+ - Issues: Report at GitHub repository
@@ -0,0 +1,29 @@
1
+ export interface StoredDeviceToken {
2
+ /** Gateway-issued device token, opaque string. */
3
+ token: string;
4
+ /** Role the token was issued for, e.g. 'operator'. */
5
+ role: string;
6
+ /** Scopes granted together with the token. */
7
+ scopes: string[];
8
+ /** Device id this token is bound to. */
9
+ deviceId: string;
10
+ /** ISO timestamp when this token was persisted. */
11
+ updatedAt: string;
12
+ }
13
+ /**
14
+ * Persists the OpenClaw Gateway-issued device token for a given role so that
15
+ * subsequent skill launches can reuse it without going through the full
16
+ * device identity pairing flow again.
17
+ */
18
+ export declare class DeviceAuthStore {
19
+ private storePath;
20
+ private cache;
21
+ constructor(configDir?: string);
22
+ /** Load token for a given role+deviceId. Returns null if not stored. */
23
+ loadToken(role: string, deviceId: string): Promise<StoredDeviceToken | null>;
24
+ /** Persist a new device token to disk and update in-memory cache. */
25
+ saveToken(token: StoredDeviceToken): Promise<void>;
26
+ /** Remove the persisted device token (e.g. after auth failure / reset). */
27
+ clearToken(): Promise<void>;
28
+ }
29
+ //# sourceMappingURL=device-auth-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-auth-store.d.ts","sourceRoot":"","sources":["../src/device-auth-store.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;CACnB;AAoBD;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAkC;gBAEnC,SAAS,CAAC,EAAE,MAAM;IAM9B,wEAAwE;IAClE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IA6BlF,qEAAqE;IAC/D,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD,2EAA2E;IACrE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAQlC"}
@@ -0,0 +1,75 @@
1
+ import { promises as fs } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ const AUTH_FILE = 'device-auth.json';
4
+ function isValidToken(value) {
5
+ if (!value || typeof value !== 'object')
6
+ return false;
7
+ const v = value;
8
+ return (typeof v.token === 'string' &&
9
+ v.token.length > 0 &&
10
+ typeof v.role === 'string' &&
11
+ v.role.length > 0 &&
12
+ Array.isArray(v.scopes) &&
13
+ v.scopes.every((s) => typeof s === 'string') &&
14
+ typeof v.deviceId === 'string' &&
15
+ v.deviceId.length > 0 &&
16
+ typeof v.updatedAt === 'string');
17
+ }
18
+ /**
19
+ * Persists the OpenClaw Gateway-issued device token for a given role so that
20
+ * subsequent skill launches can reuse it without going through the full
21
+ * device identity pairing flow again.
22
+ */
23
+ export class DeviceAuthStore {
24
+ storePath;
25
+ cache = null;
26
+ constructor(configDir) {
27
+ this.storePath = configDir
28
+ ? join(configDir, AUTH_FILE)
29
+ : join(process.cwd(), AUTH_FILE);
30
+ }
31
+ /** Load token for a given role+deviceId. Returns null if not stored. */
32
+ async loadToken(role, deviceId) {
33
+ if (this.cache &&
34
+ this.cache.role === role &&
35
+ this.cache.deviceId === deviceId) {
36
+ return this.cache;
37
+ }
38
+ try {
39
+ const data = await fs.readFile(this.storePath, 'utf-8');
40
+ const parsed = JSON.parse(data);
41
+ if (isValidToken(parsed) &&
42
+ parsed.role === role &&
43
+ parsed.deviceId === deviceId) {
44
+ this.cache = parsed;
45
+ return parsed;
46
+ }
47
+ console.warn('[DeviceAuth] Existing auth file is invalid or mismatched; ignoring.');
48
+ }
49
+ catch {
50
+ // file does not exist or is unreadable — first launch or wiped
51
+ }
52
+ return null;
53
+ }
54
+ /** Persist a new device token to disk and update in-memory cache. */
55
+ async saveToken(token) {
56
+ await fs.mkdir(dirname(this.storePath), { recursive: true });
57
+ const payload = { ...token, updatedAt: new Date().toISOString() };
58
+ await fs.writeFile(this.storePath, JSON.stringify(payload, null, 2), {
59
+ mode: 0o600,
60
+ });
61
+ this.cache = payload;
62
+ console.log(`[DeviceAuth] Saved device token for role=${token.role} deviceId=${token.deviceId}`);
63
+ }
64
+ /** Remove the persisted device token (e.g. after auth failure / reset). */
65
+ async clearToken() {
66
+ this.cache = null;
67
+ try {
68
+ await fs.unlink(this.storePath);
69
+ }
70
+ catch {
71
+ // file does not exist — fine
72
+ }
73
+ }
74
+ }
75
+ //# sourceMappingURL=device-auth-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-auth-store.js","sourceRoot":"","sources":["../src/device-auth-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export interface DeviceIdentity {
2
+ /** SHA-256 of raw public key bytes, base64url-encoded (no padding). */
3
+ deviceId: string;
4
+ /** Raw 32-byte Ed25519 public key, base64url-encoded (no padding). */
5
+ publicKey: string;
6
+ /** PKCS#8 PEM private key (32-byte Ed25519 seed wrapped). */
7
+ privateKey: string;
8
+ /** SPKI PEM public key. */
9
+ publicKeyPem: string;
10
+ /** ISO timestamp when identity was generated. */
11
+ createdAt: string;
12
+ }
13
+ declare function base64UrlEncode(buf: Buffer): string;
14
+ declare function deriveDeviceIdFromPublicKeyPem(publicKeyPem: string): string;
15
+ declare function publicKeyRawBase64UrlFromPem(publicKeyPem: string): string;
16
+ /**
17
+ * Manages the skill's persistent Ed25519 device identity used for OpenClaw
18
+ * Gateway pairing. The identity is stored next to the skill source so that
19
+ * re-launches keep the same deviceId and can be auto-approved as a paired
20
+ * node.
21
+ */
22
+ export declare class DeviceIdentityStore {
23
+ private identityPath;
24
+ private identity;
25
+ constructor(configDir?: string);
26
+ /**
27
+ * Load existing identity or generate a new one. Persists to disk on first
28
+ * creation. Subsequent calls return the in-memory cached identity.
29
+ */
30
+ getOrCreate(): Promise<DeviceIdentity>;
31
+ /** Verify the persisted publicKey (base64url raw) actually matches the PEM. */
32
+ private matchesPublicKey;
33
+ private persist;
34
+ /**
35
+ * Sign a payload string with the identity's Ed25519 private key. Returns
36
+ * base64url-encoded raw signature (no padding).
37
+ */
38
+ signPayload(payload: string, identity: DeviceIdentity): string;
39
+ }
40
+ export { base64UrlEncode, publicKeyRawBase64UrlFromPem, deriveDeviceIdFromPublicKeyPem };
41
+ //# sourceMappingURL=device-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-identity.d.ts","sourceRoot":"","sources":["../src/device-identity.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,iBAAS,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM5C;AAED,iBAAS,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAgBpE;AAED,iBAAS,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAclE;AA4BD;;;;;GAKG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAA+B;gBAEnC,SAAS,CAAC,EAAE,MAAM;IAM9B;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC;IAuB5C,+EAA+E;IAC/E,OAAO,CAAC,gBAAgB;YASV,OAAO;IAOrB;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM;CAK/D;AAED,OAAO,EAAE,eAAe,EAAE,4BAA4B,EAAE,8BAA8B,EAAE,CAAC"}