@honor-claw/yoyo 1.2.0-beta.8 → 1.2.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/package.json +1 -1
- package/skills/yoyo-control/SKILL.md +46 -44
- package/skills/yoyo-control/references/alarm-create.md +37 -0
- package/skills/yoyo-control/references/app-uninstall.md +3 -25
- package/skills/yoyo-control/references/audio-record.md +14 -28
- package/skills/yoyo-control/references/autoscreen-onnotice.md +7 -27
- package/skills/yoyo-control/references/battery.md +11 -42
- package/skills/yoyo-control/references/brightness.md +1 -26
- package/skills/yoyo-control/references/camera.md +1 -26
- package/skills/yoyo-control/references/dark-mode.md +7 -22
- package/skills/yoyo-control/references/device-operation.md +16 -28
- package/skills/yoyo-control/references/eyecomfort.md +19 -24
- package/skills/yoyo-control/references/location-service.md +6 -26
- package/skills/yoyo-control/references/nfc.md +1 -21
- package/skills/yoyo-control/references/schedule-delete.md +1 -1
- package/skills/yoyo-control/references/status-bar-show.md +14 -28
- package/skills/yoyo-control/references/usb-shared-network.md +7 -22
- package/src/cloud-channel/client.ts +1 -22
- package/src/cloud-channel/message-handler.ts +11 -17
- package/src/cloud-channel/types.ts +16 -1
- package/src/commands/logout/impl.ts +0 -1
- package/src/honor-auth/cloud.ts +18 -24
- package/src/modules/device/providers/windows.ts +34 -3
|
@@ -7,7 +7,6 @@ description: >
|
|
|
7
7
|
# Usb Shared Network USB共享网络
|
|
8
8
|
|
|
9
9
|
## Tool Command
|
|
10
|
-
|
|
11
10
|
```bash
|
|
12
11
|
usb-shared-network
|
|
13
12
|
```
|
|
@@ -15,7 +14,6 @@ usb-shared-network
|
|
|
15
14
|
## 集成工作流
|
|
16
15
|
|
|
17
16
|
### Step 1: 意图解析与参数组装
|
|
18
|
-
|
|
19
17
|
```
|
|
20
18
|
┌─────────────────────────────────────────────────────────────┐
|
|
21
19
|
│ 意图识别与参数提取 │
|
|
@@ -43,18 +41,21 @@ usb-shared-network
|
|
|
43
41
|
```
|
|
44
42
|
|
|
45
43
|
### Step 2: 执行调用
|
|
46
|
-
|
|
47
44
|
- 根据操作系统选择对应的命令格式
|
|
48
45
|
- Windows: Cmd 格式(双引号需转义)
|
|
49
46
|
- Linux: Bash 格式(单引号包裹)
|
|
50
47
|
|
|
51
48
|
## 参数定义
|
|
52
|
-
|
|
53
49
|
```json
|
|
54
50
|
{
|
|
55
51
|
"actionType": {
|
|
56
52
|
"type": "string",
|
|
57
|
-
"enum": [
|
|
53
|
+
"enum": [
|
|
54
|
+
"设置",
|
|
55
|
+
"查询",
|
|
56
|
+
"打开",
|
|
57
|
+
"关闭"
|
|
58
|
+
],
|
|
58
59
|
"description": "必填参数,USB 共享网络相关操作的动作类型,用于明确本次指令的主要行为。当涉及调整 USB 共享网络配置时使用设置;当获取当前 USB 共享网络状态时使用查询;当启用 USB 共享网络功能时使用打开;当停用 USB 共享网络功能时使用关闭。"
|
|
59
60
|
},
|
|
60
61
|
"app": {
|
|
@@ -65,7 +66,6 @@ usb-shared-network
|
|
|
65
66
|
```
|
|
66
67
|
|
|
67
68
|
### 参数注意事项
|
|
68
|
-
|
|
69
69
|
1. 必填参数:`actionType`是必填参数,其取值必须满足枚举值范围,必须是`"设置"`、`"查询"`、`"打开"`、`"关闭"`之一。
|
|
70
70
|
2. 同义词/间接表述映射: "开启/打开/启用"统一识别为`actionType`的`打开`;"停用/禁用/关闭"统一识别为`关闭`;"设置/设定/调整/配置/进入设置页面"统一识别为`设置`;"查看/查询/了解状态"统一识别为`查询`。
|
|
71
71
|
3. 默认值或缺省行为: 未指定`app`时视为对系统全局设置进行操作;`actionType`为必填,无明确语义时需追问用户。
|
|
@@ -81,7 +81,6 @@ usb-shared-network
|
|
|
81
81
|
**工具**: "usb-shared-network"
|
|
82
82
|
|
|
83
83
|
**JSON 参数**:
|
|
84
|
-
|
|
85
84
|
```json
|
|
86
85
|
{
|
|
87
86
|
"actionType": "打开"
|
|
@@ -89,13 +88,11 @@ usb-shared-network
|
|
|
89
88
|
```
|
|
90
89
|
|
|
91
90
|
**Windows (Cmd) 执行命令**:
|
|
92
|
-
|
|
93
91
|
```bash
|
|
94
92
|
cmd /c 'openclaw nodes invoke --node <ID> --command usb-shared-network --params "{\"actionType\":\"打开\"}"'
|
|
95
93
|
```
|
|
96
94
|
|
|
97
95
|
**Linux (Bash) 执行命令**:
|
|
98
|
-
|
|
99
96
|
```bash
|
|
100
97
|
openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actionType":"打开"}'
|
|
101
98
|
```
|
|
@@ -109,7 +106,6 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
109
106
|
**工具**: "usb-shared-network"
|
|
110
107
|
|
|
111
108
|
**JSON 参数**:
|
|
112
|
-
|
|
113
109
|
```json
|
|
114
110
|
{
|
|
115
111
|
"actionType": "关闭"
|
|
@@ -117,13 +113,11 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
117
113
|
```
|
|
118
114
|
|
|
119
115
|
**Windows (Cmd) 执行命令**:
|
|
120
|
-
|
|
121
116
|
```bash
|
|
122
117
|
cmd /c 'openclaw nodes invoke --node <ID> --command usb-shared-network --params "{\"actionType\":\"关闭\"}"'
|
|
123
118
|
```
|
|
124
119
|
|
|
125
120
|
**Linux (Bash) 执行命令**:
|
|
126
|
-
|
|
127
121
|
```bash
|
|
128
122
|
openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actionType":"关闭"}'
|
|
129
123
|
```
|
|
@@ -137,7 +131,6 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
137
131
|
**工具**: "usb-shared-network"
|
|
138
132
|
|
|
139
133
|
**JSON 参数**:
|
|
140
|
-
|
|
141
134
|
```json
|
|
142
135
|
{
|
|
143
136
|
"actionType": "设置"
|
|
@@ -145,13 +138,11 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
145
138
|
```
|
|
146
139
|
|
|
147
140
|
**Windows (Cmd) 执行命令**:
|
|
148
|
-
|
|
149
141
|
```bash
|
|
150
142
|
cmd /c 'openclaw nodes invoke --node <ID> --command usb-shared-network --params "{\"actionType\":\"设置\"}"'
|
|
151
143
|
```
|
|
152
144
|
|
|
153
145
|
**Linux (Bash) 执行命令**:
|
|
154
|
-
|
|
155
146
|
```bash
|
|
156
147
|
openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actionType":"设置"}'
|
|
157
148
|
```
|
|
@@ -165,7 +156,6 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
165
156
|
**工具**: "usb-shared-network"
|
|
166
157
|
|
|
167
158
|
**JSON 参数**:
|
|
168
|
-
|
|
169
159
|
```json
|
|
170
160
|
{
|
|
171
161
|
"actionType": "打开"
|
|
@@ -173,13 +163,11 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
173
163
|
```
|
|
174
164
|
|
|
175
165
|
**Windows (Cmd) 执行命令**:
|
|
176
|
-
|
|
177
166
|
```bash
|
|
178
167
|
cmd /c 'openclaw nodes invoke --node <ID> --command usb-shared-network --params "{\"actionType\":\"打开\"}"'
|
|
179
168
|
```
|
|
180
169
|
|
|
181
170
|
**Linux (Bash) 执行命令**:
|
|
182
|
-
|
|
183
171
|
```bash
|
|
184
172
|
openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actionType":"打开"}'
|
|
185
173
|
```
|
|
@@ -193,7 +181,6 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
193
181
|
**工具**: "usb-shared-network"
|
|
194
182
|
|
|
195
183
|
**JSON 参数**:
|
|
196
|
-
|
|
197
184
|
```json
|
|
198
185
|
{
|
|
199
186
|
"actionType": "设置"
|
|
@@ -201,13 +188,11 @@ openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actio
|
|
|
201
188
|
```
|
|
202
189
|
|
|
203
190
|
**Windows (Cmd) 执行命令**:
|
|
204
|
-
|
|
205
191
|
```bash
|
|
206
192
|
cmd /c 'openclaw nodes invoke --node <ID> --command usb-shared-network --params "{\"actionType\":\"设置\"}"'
|
|
207
193
|
```
|
|
208
194
|
|
|
209
195
|
**Linux (Bash) 执行命令**:
|
|
210
|
-
|
|
211
196
|
```bash
|
|
212
197
|
openclaw nodes invoke --node <ID> --command usb-shared-network --params '{"actionType":"设置"}'
|
|
213
|
-
```
|
|
198
|
+
```
|
|
@@ -26,7 +26,6 @@ export class ClawCloudSocketClient {
|
|
|
26
26
|
private retryTimer: NodeJS.Timeout | null = null;
|
|
27
27
|
private isManualClose = false;
|
|
28
28
|
private isRetryPaused = false; // 重试状态
|
|
29
|
-
private hasRetried = false;
|
|
30
29
|
// ping/pong 配置
|
|
31
30
|
private pingTimer: NodeJS.Timeout | null = null;
|
|
32
31
|
// 当前连接上下文
|
|
@@ -76,7 +75,6 @@ export class ClawCloudSocketClient {
|
|
|
76
75
|
this.isManualClose = false;
|
|
77
76
|
this.retryCount = 0;
|
|
78
77
|
this.isRetryPaused = false;
|
|
79
|
-
this.hasRetried = false;
|
|
80
78
|
|
|
81
79
|
this.startPingTimer();
|
|
82
80
|
|
|
@@ -257,25 +255,7 @@ export class ClawCloudSocketClient {
|
|
|
257
255
|
|
|
258
256
|
this.clearRetryTimer();
|
|
259
257
|
|
|
260
|
-
//
|
|
261
|
-
if (!this.hasRetried) {
|
|
262
|
-
this.hasRetried = true;
|
|
263
|
-
useClawLogger().info(`[claw-cloud-socket] first retry, reconnecting immediately`);
|
|
264
|
-
|
|
265
|
-
this.options.onStatusEvent?.({
|
|
266
|
-
type: StatusEventType.CLOUD_SOCKET_RETRY,
|
|
267
|
-
timestamp: Date.now(),
|
|
268
|
-
data: {
|
|
269
|
-
retryCount: this.retryCount,
|
|
270
|
-
delay: 0,
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
this.connect(true);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// 后续重试使用指数退避: 1s → 2s → 4s,封顶4s无限重试
|
|
258
|
+
// 使用指数退避重试: 1s → 2s → 4s,封顶4s无限重试
|
|
279
259
|
const delay = this.calculateRetryDelay();
|
|
280
260
|
this.retryCount = Math.min(this.retryCount + 1, RETRY_COUNT_CAP);
|
|
281
261
|
|
|
@@ -365,7 +345,6 @@ export class ClawCloudSocketClient {
|
|
|
365
345
|
|
|
366
346
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
367
347
|
this.retryCount = 0;
|
|
368
|
-
this.hasRetried = false;
|
|
369
348
|
this.connect(true);
|
|
370
349
|
}
|
|
371
350
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type DeviceSessionInfo,
|
|
9
9
|
type YOYOClawServiceContext,
|
|
10
10
|
type StatusEvent,
|
|
11
|
+
type RawGatewayMessage,
|
|
11
12
|
StatusEventType,
|
|
12
13
|
} from "./types.js";
|
|
13
14
|
|
|
@@ -358,7 +359,7 @@ export class MessageHandler {
|
|
|
358
359
|
const targetDeviceId = sessionInfo.sourceInfo.sourceDeviceId;
|
|
359
360
|
|
|
360
361
|
// 收到NOT_PAIRED错误时,自动获取待配对设备并审批
|
|
361
|
-
let rawData:
|
|
362
|
+
let rawData: RawGatewayMessage;
|
|
362
363
|
try {
|
|
363
364
|
rawData = JSON.parse(data);
|
|
364
365
|
} catch {
|
|
@@ -367,18 +368,16 @@ export class MessageHandler {
|
|
|
367
368
|
}
|
|
368
369
|
|
|
369
370
|
if (!rawData.ok && rawData.error?.code === "NOT_PAIRED") {
|
|
370
|
-
const requestId = rawData.error?.details?.requestId;
|
|
371
|
+
const requestId = rawData.error?.details?.requestId as string | undefined;
|
|
371
372
|
if (!requestId) {
|
|
372
373
|
useClawLogger().warn(`${LOG_PREFIX} NOT_PAIRED without requestId, ignoring...`);
|
|
373
374
|
return;
|
|
374
375
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
376
|
+
await this.handleAutoPair(requestId);
|
|
377
|
+
const bizExtInfo = { id: rawData.id, type: "reconnect-required" };
|
|
378
|
+
this.sendMessage("deviceControl", targetDeviceId, traceInfo, "", undefined, bizExtInfo);
|
|
379
|
+
useClawLogger().info(`${LOG_PREFIX} auto pair is completed, requestId: ${requestId}`);
|
|
380
|
+
return;
|
|
382
381
|
}
|
|
383
382
|
|
|
384
383
|
useClawLogger().debug?.(
|
|
@@ -398,7 +397,7 @@ export class MessageHandler {
|
|
|
398
397
|
}
|
|
399
398
|
};
|
|
400
399
|
|
|
401
|
-
private async handleAutoPair(requestId: string)
|
|
400
|
+
private async handleAutoPair(requestId: string) {
|
|
402
401
|
const adminClient = this.adminClientManager.getClient();
|
|
403
402
|
if (!adminClient) {
|
|
404
403
|
useClawLogger().warn(`${LOG_PREFIX} admin client not available for auto pair`);
|
|
@@ -407,16 +406,11 @@ export class MessageHandler {
|
|
|
407
406
|
|
|
408
407
|
try {
|
|
409
408
|
useClawLogger().info(`${LOG_PREFIX} auto pair approve, requestId: ${requestId}`);
|
|
410
|
-
|
|
411
|
-
if (!res.ok) {
|
|
412
|
-
throw new Error(JSON.stringify(res.error));
|
|
413
|
-
}
|
|
414
|
-
return true;
|
|
409
|
+
await adminClient.devicePairApprove(requestId);
|
|
415
410
|
} catch (error) {
|
|
416
411
|
useClawLogger().error(
|
|
417
|
-
`${LOG_PREFIX} auto pair approve failed, requestId: ${requestId}, error: ${String(error)}
|
|
412
|
+
`${LOG_PREFIX} auto pair approve failed, requestId: ${requestId}, error: ${String(error)}, ignore...`,
|
|
418
413
|
);
|
|
419
|
-
return false;
|
|
420
414
|
}
|
|
421
415
|
}
|
|
422
416
|
|
|
@@ -42,7 +42,7 @@ export interface YOYOClawServiceEvent {
|
|
|
42
42
|
/**
|
|
43
43
|
* 业务扩展信息
|
|
44
44
|
*/
|
|
45
|
-
bizExtInfo?: Record<string,
|
|
45
|
+
bizExtInfo?: Record<string, unknown>;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -126,3 +126,18 @@ export interface DeviceSessionInfo {
|
|
|
126
126
|
timestamp: number;
|
|
127
127
|
sourceInfo: ClawSocketSourceInfo;
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 通用网关原始消息结构
|
|
132
|
+
* 用于 JSON.parse 后的数据结构,允许任意扩展字段
|
|
133
|
+
*/
|
|
134
|
+
export interface RawGatewayMessage {
|
|
135
|
+
ok?: boolean;
|
|
136
|
+
id?: string;
|
|
137
|
+
error?: {
|
|
138
|
+
code?: string;
|
|
139
|
+
message?: string;
|
|
140
|
+
details?: Record<string, unknown>;
|
|
141
|
+
};
|
|
142
|
+
[key: string]: unknown;
|
|
143
|
+
}
|
|
@@ -25,7 +25,6 @@ export function registerLogoutCommand(api: OpenClawPluginApi, command: Command)
|
|
|
25
25
|
} catch (error) {
|
|
26
26
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
27
27
|
console.error("❌ Logout failed:", errorMessage);
|
|
28
|
-
throw error;
|
|
29
28
|
}
|
|
30
29
|
});
|
|
31
30
|
|
package/src/honor-auth/cloud.ts
CHANGED
|
@@ -3,41 +3,35 @@ import { isOKResponse } from "../apis/index.js";
|
|
|
3
3
|
import { getConfigManager } from "../modules/configs/index.js";
|
|
4
4
|
import { getDeviceInfo } from "../modules/device/device-info.js";
|
|
5
5
|
import type { HonorUserInfo } from "../types.js";
|
|
6
|
-
import { wrapError } from "../utils/error.js";
|
|
7
6
|
import { clearToken } from "./token-manager.js";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* 执行登出流程
|
|
11
10
|
*/
|
|
12
11
|
export async function performLogout(): Promise<void> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const userConfig = configManager.getUserConfig();
|
|
12
|
+
const configManager = getConfigManager();
|
|
13
|
+
const userConfig = configManager.getUserConfig();
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 获取设备信息
|
|
23
|
-
const deviceInfo = await getDeviceInfo();
|
|
15
|
+
if (!userConfig?.token) {
|
|
16
|
+
throw new Error("⚠️ Not logged in");
|
|
17
|
+
}
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
// 获取设备信息
|
|
20
|
+
const deviceInfo = await getDeviceInfo();
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
};
|
|
22
|
+
// 调用登出接口
|
|
23
|
+
const client = createClawCloudClient();
|
|
31
24
|
|
|
32
|
-
|
|
25
|
+
const userInfo: HonorUserInfo = {
|
|
26
|
+
token: userConfig.token,
|
|
27
|
+
};
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
throw new Error(`Logout failed: ${response.data?.cnMessage || "Unknown error"}`);
|
|
36
|
-
}
|
|
29
|
+
const response = await client.logoutDevice(deviceInfo, userInfo);
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
} catch (error) {
|
|
41
|
-
throw wrapError(error, "failed to logout");
|
|
31
|
+
if (!isOKResponse(response)) {
|
|
32
|
+
throw new Error(response.data?.cnMessage || "Unknown error");
|
|
42
33
|
}
|
|
34
|
+
|
|
35
|
+
// 清除Token
|
|
36
|
+
await clearToken();
|
|
43
37
|
}
|
|
@@ -40,6 +40,31 @@ function getRegistryStringValueAsync(
|
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* 异步检查注册表键是否存在
|
|
45
|
+
* 使用 winreg 的 values() 方法,键不存在时会报错
|
|
46
|
+
*/
|
|
47
|
+
function registryKeyExistsAsync(hive: number, keyPath: string): Promise<boolean> {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
try {
|
|
50
|
+
const regKey = new Registry({
|
|
51
|
+
hive,
|
|
52
|
+
key: keyPath,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
regKey.values((err: Error | null) => {
|
|
56
|
+
if (err) {
|
|
57
|
+
resolve(false);
|
|
58
|
+
} else {
|
|
59
|
+
resolve(true);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
} catch {
|
|
63
|
+
resolve(false);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
export class WindowsDeviceInfoProvider implements DeviceInfoProvider {
|
|
44
69
|
private cache: DeviceInfoCache = {
|
|
45
70
|
deviceId: "",
|
|
@@ -111,11 +136,17 @@ export class WindowsDeviceInfoProvider implements DeviceInfoProvider {
|
|
|
111
136
|
systemManufacturer2,
|
|
112
137
|
];
|
|
113
138
|
|
|
114
|
-
const manufacturer = manufacturerSources.find((m) => m && m.
|
|
115
|
-
if (manufacturer
|
|
139
|
+
const manufacturer = manufacturerSources.find((m) => m && m.toLowerCase().includes("honor"));
|
|
140
|
+
if (manufacturer) {
|
|
116
141
|
this.cache.deviceBrand = "HONOR";
|
|
117
142
|
} else {
|
|
118
|
-
|
|
143
|
+
// 最后兜底:检查 HKLM:\SOFTWARE\HONOR 注册表键是否存在
|
|
144
|
+
const honorKeyExists = await registryKeyExistsAsync(Registry.HKLM, "\\SOFTWARE\\HONOR");
|
|
145
|
+
if (honorKeyExists) {
|
|
146
|
+
this.cache.deviceBrand = "HONOR";
|
|
147
|
+
} else {
|
|
148
|
+
this.cache.deviceBrand = "";
|
|
149
|
+
}
|
|
119
150
|
}
|
|
120
151
|
} catch {
|
|
121
152
|
// 初始化失败,使用默认值
|