@honor-claw/yoyo 1.2.1-beta.3 → 1.2.1-beta.5
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/references/express-logistics-search.md +15 -15
- package/src/cloud-channel/admin-client-manager.ts +5 -1
- package/src/cloud-channel/client.ts +1 -1
- package/src/gateway-client/protocol-client.ts +1 -0
- package/src/gateway-client/types/client.ts +1 -0
- package/src/modules/configs/config-manager.ts +4 -11
- package/src/modules/configs/identity-persist.ts +5 -0
- package/src/modules/device/gateway-auth.ts +25 -0
- package/src/modules/device/identity.ts +8 -0
- package/src/modules/device/index.ts +1 -0
- package/src/modules/device/registry.ts +35 -1
- package/src/services/connection/impl.ts +11 -3
- package/src/utils/hash.ts +9 -0
package/package.json
CHANGED
|
@@ -66,7 +66,7 @@ express_logistics_query
|
|
|
66
66
|
### 示例 1: 通用物流查询(未提供单号)
|
|
67
67
|
**用户输入**: "查一下我的快递"
|
|
68
68
|
|
|
69
|
-
**工具**: "
|
|
69
|
+
**工具**: "express_logistics_query"
|
|
70
70
|
|
|
71
71
|
**JSON 参数**:
|
|
72
72
|
```json
|
|
@@ -75,12 +75,12 @@ express_logistics_query
|
|
|
75
75
|
|
|
76
76
|
**Windows (Cmd) 执行命令**:
|
|
77
77
|
```bash
|
|
78
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command
|
|
78
|
+
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"express_logistics_query\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{}}"'
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
**Linux (Bash) 执行命令**:
|
|
82
82
|
```bash
|
|
83
|
-
openclaw nodes invoke --node <ID> --command
|
|
83
|
+
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"express_logistics_query","appPkg":"com.hihonor.magicvoice","arguments":{}}'
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
---
|
|
@@ -88,7 +88,7 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
88
88
|
### 示例 2: 签收状态核实(未提供单号)
|
|
89
89
|
**用户输入**: "我的快递签收了吗"
|
|
90
90
|
|
|
91
|
-
**工具**: "
|
|
91
|
+
**工具**: "express_logistics_query"
|
|
92
92
|
|
|
93
93
|
**JSON 参数**:
|
|
94
94
|
```json
|
|
@@ -97,12 +97,12 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
97
97
|
|
|
98
98
|
**Windows (Cmd) 执行命令**:
|
|
99
99
|
```bash
|
|
100
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command
|
|
100
|
+
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"express_logistics_query\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{}}"'
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
**Linux (Bash) 执行命令**:
|
|
104
104
|
```bash
|
|
105
|
-
openclaw nodes invoke --node <ID> --command
|
|
105
|
+
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"express_logistics_query","appPkg":"com.hihonor.magicvoice","arguments":{}}'
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
---
|
|
@@ -110,7 +110,7 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
110
110
|
### 示例 3: 指定运单号查询
|
|
111
111
|
**用户输入**: "看看快递单号为123456789的快递"
|
|
112
112
|
|
|
113
|
-
**工具**: "
|
|
113
|
+
**工具**: "express_logistics_query"
|
|
114
114
|
|
|
115
115
|
**JSON 参数**:
|
|
116
116
|
```json
|
|
@@ -119,12 +119,12 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
119
119
|
|
|
120
120
|
**Windows (Cmd) 执行命令**:
|
|
121
121
|
```bash
|
|
122
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command
|
|
122
|
+
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"express_logistics_query\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{}}"'
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
**Linux (Bash) 执行命令**:
|
|
126
126
|
```bash
|
|
127
|
-
openclaw nodes invoke --node <ID> --command
|
|
127
|
+
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"express_logistics_query","appPkg":"com.hihonor.magicvoice","arguments":{}}'
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
---
|
|
@@ -132,7 +132,7 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
132
132
|
### 示例 4: 指定快递公司与单号查询
|
|
133
133
|
**用户输入**: "帮我查一下顺丰快递单号987654321现在到哪了"
|
|
134
134
|
|
|
135
|
-
**工具**: "
|
|
135
|
+
**工具**: "express_logistics_query"
|
|
136
136
|
|
|
137
137
|
**JSON 参数**:
|
|
138
138
|
```json
|
|
@@ -141,12 +141,12 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
141
141
|
|
|
142
142
|
**Windows (Cmd) 执行命令**:
|
|
143
143
|
```bash
|
|
144
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command
|
|
144
|
+
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"express_logistics_query\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{}}"'
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
**Linux (Bash) 执行命令**:
|
|
148
148
|
```bash
|
|
149
|
-
openclaw nodes invoke --node <ID> --command
|
|
149
|
+
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"express_logistics_query","appPkg":"com.hihonor.magicvoice","arguments":{}}'
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
---
|
|
@@ -154,7 +154,7 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
154
154
|
### 示例 5: 到件/签收意图识别
|
|
155
155
|
**用户输入**: "查询我的包裹到了吗"
|
|
156
156
|
|
|
157
|
-
**工具**: "
|
|
157
|
+
**工具**: "express_logistics_query"
|
|
158
158
|
|
|
159
159
|
**JSON 参数**:
|
|
160
160
|
```json
|
|
@@ -163,10 +163,10 @@ openclaw nodes invoke --node <ID> --command express-logistics-query --params '{}
|
|
|
163
163
|
|
|
164
164
|
**Windows (Cmd) 执行命令**:
|
|
165
165
|
```bash
|
|
166
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command
|
|
166
|
+
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"express_logistics_query\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{}}"'
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
**Linux (Bash) 执行命令**:
|
|
170
170
|
```bash
|
|
171
|
-
openclaw nodes invoke --node <ID> --command
|
|
171
|
+
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"express_logistics_query","appPkg":"com.hihonor.magicvoice","arguments":{}}'
|
|
172
172
|
```
|
|
@@ -29,9 +29,13 @@ export class AdminClientManager {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const gatewayAuthConfig = getConfigManager().getGatewayAuthConfig();
|
|
33
|
+
const token = typeof gatewayAuthConfig?.token === "string" ? gatewayAuthConfig.token : "";
|
|
34
|
+
const password =
|
|
35
|
+
typeof gatewayAuthConfig?.password === "string" ? gatewayAuthConfig.password : "";
|
|
33
36
|
this.client = new AdminGatewayClient({
|
|
34
37
|
token,
|
|
38
|
+
password,
|
|
35
39
|
onAuthenticated: () => {
|
|
36
40
|
useClawLogger().info("[yoyoclaw-channel] admin gateway client authenticated");
|
|
37
41
|
this.ready = true;
|
|
@@ -196,7 +196,7 @@ export class ClawCloudSocketClient {
|
|
|
196
196
|
useClawLogger().debug?.(
|
|
197
197
|
`[yoyoclaw-channel] received cloud message from session ${message.wsOutputEvent?.sourceDeviceId}, deviceId ${
|
|
198
198
|
message.wsOutputEvent?.sourceDeviceInfo?.deviceId || "nil"
|
|
199
|
-
}, ${dataText.slice(0,
|
|
199
|
+
}, ${dataText.slice(0, 3000)}`,
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
if (message.code === "YOYO_CLAW_100000") {
|
|
@@ -101,22 +101,15 @@ export class ConfigManager {
|
|
|
101
101
|
return undefined;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (authConfig.token) {
|
|
107
|
-
result.token = authConfig.token;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (authConfig.password) {
|
|
111
|
-
result.password = authConfig.password;
|
|
112
|
-
}
|
|
104
|
+
const token = authConfig.token ?? "";
|
|
105
|
+
const password = authConfig.password ?? "";
|
|
113
106
|
|
|
114
107
|
// 如果没有任何认证信息,返回 undefined
|
|
115
|
-
if (
|
|
108
|
+
if (!token && !password) {
|
|
116
109
|
return undefined;
|
|
117
110
|
}
|
|
118
111
|
|
|
119
|
-
return
|
|
112
|
+
return { token, password };
|
|
120
113
|
} catch (error) {
|
|
121
114
|
console.error(`[claw-configs] Failed to read gateway auth config: ${error}`);
|
|
122
115
|
return undefined;
|
|
@@ -24,6 +24,7 @@ export interface PersistedIdentity {
|
|
|
24
24
|
publicKeyPem?: string;
|
|
25
25
|
privateKeyPem?: string;
|
|
26
26
|
createdAtMs?: number;
|
|
27
|
+
gatewayAuthMd5?: string;
|
|
27
28
|
version: IdentityVersion;
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -130,6 +131,10 @@ export async function updatePersistedIdentity(
|
|
|
130
131
|
updatedConfig.version = identity.version;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
if ("gatewayAuthMd5" in identity) {
|
|
135
|
+
updatedConfig.gatewayAuthMd5 = identity.gatewayAuthMd5;
|
|
136
|
+
}
|
|
137
|
+
|
|
133
138
|
// 写入配置
|
|
134
139
|
const configPath = getConfigPath();
|
|
135
140
|
await safeWriteFile({
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { md5 } from "../../utils/hash.js";
|
|
2
|
+
import { GatewayAuthConfig } from "../configs/types.js";
|
|
3
|
+
|
|
4
|
+
function normalizeSecretValue(value: unknown): string {
|
|
5
|
+
if (typeof value === "string") {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
if (value == null) {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
return JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createGatewayAuthMd5(gatewayAuthConfig: GatewayAuthConfig | undefined): string {
|
|
15
|
+
return md5(
|
|
16
|
+
JSON.stringify({
|
|
17
|
+
token: normalizeSecretValue(gatewayAuthConfig?.token),
|
|
18
|
+
password: normalizeSecretValue(gatewayAuthConfig?.password),
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isSameGatewayAuthMd5(persist: string | undefined, right: string): boolean {
|
|
24
|
+
return (persist ?? "") === right;
|
|
25
|
+
}
|
|
@@ -114,6 +114,14 @@ export async function loadOrCreateDeviceIdentity(): Promise<DeviceIdentity> {
|
|
|
114
114
|
return identity;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* 只读取已持久化的 Gateway 认证 MD5
|
|
119
|
+
*/
|
|
120
|
+
export async function loadPersistedGatewayAuthMd5(): Promise<string | undefined> {
|
|
121
|
+
const persisted = await getPersistedIdentity();
|
|
122
|
+
return persisted?.gatewayAuthMd5;
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
/**
|
|
118
126
|
* Sign a payload using device private key
|
|
119
127
|
* @param privateKeyPem - Private key in PEM format
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { createClawCloudClient } from "../../apis/claw-cloud.js";
|
|
2
2
|
import { isOKResponse } from "../../apis/index.js";
|
|
3
3
|
import type { DeviceInfo, HonorUserInfo } from "../../types.js";
|
|
4
|
-
import {
|
|
4
|
+
import { formatHashForLog } from "../../utils/hash.js";
|
|
5
|
+
import { useClawLogger } from "../../utils/logger.js";
|
|
6
|
+
import { getConfigManager, updatePersistedIdentity } from "../configs/index.js";
|
|
7
|
+
import { createGatewayAuthMd5, isSameGatewayAuthMd5 } from "./gateway-auth.js";
|
|
8
|
+
import { loadPersistedGatewayAuthMd5 } from "./identity.js";
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* 注册设备到 Claw Cloud
|
|
@@ -25,3 +29,33 @@ export async function registerDevice(deviceInfo: DeviceInfo, userInfo: HonorUser
|
|
|
25
29
|
throw new Error(`注册失败:${response.data?.cnMessage}`);
|
|
26
30
|
}
|
|
27
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gateway 认证信息发生变化时重新注册设备
|
|
35
|
+
*/
|
|
36
|
+
export async function registerDeviceIfGatewayAuthChanged(
|
|
37
|
+
deviceInfo: DeviceInfo,
|
|
38
|
+
userInfo: HonorUserInfo,
|
|
39
|
+
) {
|
|
40
|
+
const configManager = getConfigManager();
|
|
41
|
+
const gatewayAuthConfig = configManager.getGatewayAuthConfig();
|
|
42
|
+
const gatewayAuthMd5 = createGatewayAuthMd5(gatewayAuthConfig);
|
|
43
|
+
const persistedGatewayAuthMd5 = await loadPersistedGatewayAuthMd5();
|
|
44
|
+
const logger = useClawLogger();
|
|
45
|
+
|
|
46
|
+
logger.info(
|
|
47
|
+
`[yoyoclaw-registry] checking gateway auth md5: current=${formatHashForLog(
|
|
48
|
+
gatewayAuthMd5,
|
|
49
|
+
)}, persisted=${formatHashForLog(persistedGatewayAuthMd5)}`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (isSameGatewayAuthMd5(persistedGatewayAuthMd5, gatewayAuthMd5)) {
|
|
53
|
+
logger.info("[yoyoclaw-registry] gateway auth unchanged, skipping device registration");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
logger.info("[yoyoclaw-registry] gateway auth changed, registering device");
|
|
58
|
+
await registerDevice(deviceInfo, userInfo);
|
|
59
|
+
await updatePersistedIdentity({ gatewayAuthMd5 });
|
|
60
|
+
logger.info("[yoyoclaw-registry] gateway auth md5 persisted after device registration");
|
|
61
|
+
}
|
|
@@ -2,7 +2,11 @@ import { OpenClawPluginApi, OpenClawPluginService } from "openclaw/plugin-sdk";
|
|
|
2
2
|
import { ClawChannel } from "../../cloud-channel/channel.js";
|
|
3
3
|
import { loadToken, clearToken } from "../../honor-auth/token-manager.js";
|
|
4
4
|
import { getConfigManager } from "../../modules/configs/config-manager.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getDeviceInfo,
|
|
7
|
+
registerDevice,
|
|
8
|
+
registerDeviceIfGatewayAuthChanged,
|
|
9
|
+
} from "../../modules/device/index.js";
|
|
6
10
|
import { DeviceInfo, HonorUserInfo } from "../../types.js";
|
|
7
11
|
import { useClawLogger } from "../../utils/logger.js";
|
|
8
12
|
import { StatusTracker, StatusEventType } from "./status-tracker/index.js";
|
|
@@ -79,9 +83,13 @@ export const createClawConnectionService = (api: OpenClawPluginApi) =>
|
|
|
79
83
|
* 创建channel
|
|
80
84
|
*/
|
|
81
85
|
async function createChannel(deviceInfo: DeviceInfo, userInfo: HonorUserInfo): Promise<void> {
|
|
82
|
-
clawConnection.status = "connecting";
|
|
83
86
|
useClawLogger().info(`[yoyoclaw-conn] creating new channel for device: ${deviceInfo.deviceId}`);
|
|
84
87
|
|
|
88
|
+
await registerDeviceIfGatewayAuthChanged(deviceInfo, userInfo);
|
|
89
|
+
|
|
90
|
+
const previousStatus = clawConnection.status;
|
|
91
|
+
clawConnection.status = "connecting";
|
|
92
|
+
|
|
85
93
|
// 通知状态跟踪器:连接状态变更
|
|
86
94
|
if (statusTracker) {
|
|
87
95
|
await statusTracker.handleEvent({
|
|
@@ -89,7 +97,7 @@ async function createChannel(deviceInfo: DeviceInfo, userInfo: HonorUserInfo): P
|
|
|
89
97
|
timestamp: Date.now(),
|
|
90
98
|
data: {
|
|
91
99
|
status: "connecting",
|
|
92
|
-
previousStatus
|
|
100
|
+
previousStatus,
|
|
93
101
|
},
|
|
94
102
|
});
|
|
95
103
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export function md5(value: string): string {
|
|
4
|
+
return crypto.createHash("md5").update(value).digest("hex");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function formatHashForLog(value: string | undefined): string {
|
|
8
|
+
return value ? `${value.slice(0, 8)}...` : "none";
|
|
9
|
+
}
|