@honor-claw/yoyo 1.4.0-beta.4 → 1.4.1-alpha.2
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/dist/apis/claw-cloud.mjs +36 -32
- package/dist/cloud-channel/message-handler.mjs +21 -20
- package/dist/modules/configs/identity-persist.mjs +1 -1
- package/dist/modules/device/identity.mjs +3 -6
- package/dist/modules/device/index.mjs +1 -1
- package/dist/modules/device/registry.mjs +29 -18
- package/dist/modules/device-toolset/ack.mjs +54 -0
- package/dist/modules/device-toolset/archive.mjs +4 -9
- package/dist/modules/device-toolset/index.mjs +1 -0
- package/dist/modules/device-toolset/normalize.mjs +3 -4
- package/dist/modules/device-toolset/persist.mjs +0 -7
- package/dist/modules/device-toolset/processor.mjs +7 -7
- package/dist/services/connection/impl.mjs +1 -1
- package/dist/utils/version.mjs +14 -4
- package/package.json +2 -3
- package/skills/yoyo-update/SKILL.md +166 -0
package/dist/apis/claw-cloud.mjs
CHANGED
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { getYoyoPluginVersionCode as e } from "../utils/version.mjs";
|
|
2
|
+
import { uuid as t } from "../utils/id.mjs";
|
|
3
|
+
import { isOKResponse as n } from "./helpers.mjs";
|
|
4
|
+
import { takeApiHost as r } from "./hosts.mjs";
|
|
5
|
+
import { HttpClient as i } from "./http-client.mjs";
|
|
5
6
|
//#region src/apis/claw-cloud.ts
|
|
6
|
-
var
|
|
7
|
+
var a = class {
|
|
7
8
|
httpClient;
|
|
8
9
|
constructor(e, t) {
|
|
9
|
-
this.httpClient = new
|
|
10
|
+
this.httpClient = new i(e, t);
|
|
10
11
|
}
|
|
11
|
-
async registerDevice(
|
|
12
|
-
let
|
|
13
|
-
"x-trace-id":
|
|
14
|
-
"x-jwt-token":
|
|
15
|
-
"x-device-id":
|
|
16
|
-
},
|
|
12
|
+
async registerDevice(n, r, i) {
|
|
13
|
+
let a = {
|
|
14
|
+
"x-trace-id": t(),
|
|
15
|
+
"x-jwt-token": r.token,
|
|
16
|
+
"x-device-id": n.deviceId
|
|
17
|
+
}, o = {
|
|
17
18
|
businessTag: "YOYO_CLAW",
|
|
18
19
|
role: "yoyoclaw",
|
|
19
20
|
deviceInfo: {
|
|
20
|
-
...
|
|
21
|
-
manufacture:
|
|
22
|
-
brand:
|
|
23
|
-
bizExtInfo:
|
|
21
|
+
...n,
|
|
22
|
+
manufacture: n.manufacture,
|
|
23
|
+
brand: n.brand,
|
|
24
|
+
bizExtInfo: {
|
|
25
|
+
...i,
|
|
26
|
+
pluginVersionCode: e()
|
|
27
|
+
}
|
|
24
28
|
}
|
|
25
29
|
};
|
|
26
30
|
return this.httpClient.post("/v1/device/registry", {
|
|
27
|
-
headers:
|
|
28
|
-
body:
|
|
31
|
+
headers: a,
|
|
32
|
+
body: o
|
|
29
33
|
});
|
|
30
34
|
}
|
|
31
|
-
async logoutDevice(
|
|
35
|
+
async logoutDevice(e, n) {
|
|
32
36
|
let r = {
|
|
33
|
-
"x-trace-id":
|
|
37
|
+
"x-trace-id": t(),
|
|
34
38
|
"x-jwt-token": n.token,
|
|
35
|
-
"x-device-id":
|
|
39
|
+
"x-device-id": e.deviceId
|
|
36
40
|
}, i = {
|
|
37
41
|
businessTag: "YOYO_CLAW",
|
|
38
42
|
deviceInfo: {
|
|
39
|
-
...
|
|
40
|
-
manufacture:
|
|
41
|
-
brand:
|
|
43
|
+
...e,
|
|
44
|
+
manufacture: e.manufacture,
|
|
45
|
+
brand: e.brand
|
|
42
46
|
}
|
|
43
47
|
};
|
|
44
48
|
return this.httpClient.post("/v1/user/logout", {
|
|
@@ -46,10 +50,10 @@ var i = class {
|
|
|
46
50
|
body: i
|
|
47
51
|
});
|
|
48
52
|
}
|
|
49
|
-
async exchangeToken(
|
|
50
|
-
let i =
|
|
53
|
+
async exchangeToken(e, r) {
|
|
54
|
+
let i = t(), a = {
|
|
51
55
|
"Content-Type": "application/json",
|
|
52
|
-
"x-device-id":
|
|
56
|
+
"x-device-id": e.deviceId,
|
|
53
57
|
"x-trace-id": i
|
|
54
58
|
}, o = {};
|
|
55
59
|
"userId" in r ? a["x-agw-userId"] = r.userId : o = {
|
|
@@ -62,13 +66,13 @@ var i = class {
|
|
|
62
66
|
headers: a,
|
|
63
67
|
timeout: 15e3
|
|
64
68
|
});
|
|
65
|
-
if (
|
|
69
|
+
if (n(s) && s.data.data) return s.data.data;
|
|
66
70
|
throw Error(`failed to get token: ${JSON.stringify(s.data)}, traceId: ${i}`);
|
|
67
71
|
}
|
|
68
72
|
};
|
|
69
|
-
function
|
|
70
|
-
let e =
|
|
71
|
-
return new
|
|
73
|
+
function o() {
|
|
74
|
+
let e = r();
|
|
75
|
+
return new a(`https://${e.clawCloud}/aicloud/yoyo-claw-service`, e.grayTag ? { defaultHeaders: { "x-gray": e.grayTag } } : void 0);
|
|
72
76
|
}
|
|
73
77
|
//#endregion
|
|
74
|
-
export {
|
|
78
|
+
export { a as ClawCloudClient, o as createClawCloudClient };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useClawLogger as e } from "../utils/logger.mjs";
|
|
2
2
|
import { StatusEventType as t } from "../services/connection/status-tracker/events.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { createDeviceToolSetUpdateAck as n } from "../modules/device-toolset/ack.mjs";
|
|
4
4
|
import "../modules/device-toolset/index.mjs";
|
|
5
5
|
//#region src/cloud-channel/message-handler.ts
|
|
6
6
|
var r = { style: "SOUL.md" }, i = "[yoyoclaw-channel]", a = class {
|
|
@@ -167,7 +167,7 @@ var r = { style: "SOUL.md" }, i = "[yoyoclaw-channel]", a = class {
|
|
|
167
167
|
this.sendMessage("deviceControl", t, n, "", void 0, o), e().info(`${i} auto pair is completed, requestId: ${r}`);
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
|
-
|
|
170
|
+
this.sendMessage("userMessage", t, n, r) || (e().error(`${i} failed to send message, cloud socket closed, session ${t}, device ${s}`), this.sessionManager.closeNodeGatewayClient(t));
|
|
171
171
|
} catch (t) {
|
|
172
172
|
e().error(`${i} failed to handle gateway message: ${String(t)}`);
|
|
173
173
|
}
|
|
@@ -206,10 +206,10 @@ var r = { style: "SOUL.md" }, i = "[yoyoclaw-channel]", a = class {
|
|
|
206
206
|
e().info(`${i} ${o ? "update" : "fetch"} context '${u}' processed (no reply)`);
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
|
-
d.ok ? (e().info(`${i} ${o ? "update" : "fetch"} context successfully`), this.sendContextResponse(a, n, r, s, {
|
|
209
|
+
d.ok ? (e().info(`${i} ${o ? "update" : "fetch"} context successfully`), this.sendContextResponse(a, n, r, s, d.responsePayload ?? {
|
|
210
210
|
ok: !0,
|
|
211
211
|
...d.data
|
|
212
|
-
})) : (e().error(`${i} failed to ${o ? "update" : "fetch"} context: ${d.error}`), this.sendContextResponse(a, n, r, s, {
|
|
212
|
+
})) : (e().error(`${i} failed to ${o ? "update" : "fetch"} context: ${d.error}`), this.sendContextResponse(a, n, r, s, d.responsePayload ?? {
|
|
213
213
|
ok: !1,
|
|
214
214
|
error: d.error,
|
|
215
215
|
...d?.data,
|
|
@@ -220,20 +220,20 @@ var r = { style: "SOUL.md" }, i = "[yoyoclaw-channel]", a = class {
|
|
|
220
220
|
e().error(`${i} error ${o ? "updating" : "fetching"} context '${u}': ${c}`), this.replyContextError(a, n, r, s, c);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
|
-
sendMessage(
|
|
224
|
-
let
|
|
225
|
-
msgType:
|
|
223
|
+
sendMessage(t, n, r, a, o, s) {
|
|
224
|
+
let c = {
|
|
225
|
+
msgType: t,
|
|
226
226
|
sourceRole: "yoyoclaw",
|
|
227
227
|
sourceDeviceId: this.config.deviceInfo.deviceId,
|
|
228
|
-
traceInfo:
|
|
228
|
+
traceInfo: r,
|
|
229
229
|
targetRole: "node",
|
|
230
|
-
targetDeviceId:
|
|
230
|
+
targetDeviceId: n,
|
|
231
231
|
port: this.config.deviceInfo.port,
|
|
232
|
-
data: typeof
|
|
233
|
-
contexts:
|
|
234
|
-
bizExtInfo:
|
|
232
|
+
data: typeof a == "string" ? a : JSON.stringify(a),
|
|
233
|
+
contexts: o,
|
|
234
|
+
bizExtInfo: s
|
|
235
235
|
};
|
|
236
|
-
return this.config.onReply(
|
|
236
|
+
return e().debug?.(`${i} sending message to cloud, msgType: ${c.msgType}, targetDeviceId: ${c.targetDeviceId}, data: ${JSON.stringify(c).slice(0, 3e3)}`), this.config.onReply(c, n);
|
|
237
237
|
}
|
|
238
238
|
validateContext(e) {
|
|
239
239
|
return e?.header?.name ? {
|
|
@@ -367,13 +367,14 @@ var r = { style: "SOUL.md" }, i = "[yoyoclaw-channel]", a = class {
|
|
|
367
367
|
return !e || t !== "DeviceToolSet" && t !== "UniversalToolSet";
|
|
368
368
|
}
|
|
369
369
|
async updateDeviceToolSetContext(e, t, r) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
ok:
|
|
376
|
-
error:
|
|
370
|
+
let i = await n({
|
|
371
|
+
namespace: r?.header.namespace,
|
|
372
|
+
payload: t
|
|
373
|
+
});
|
|
374
|
+
return {
|
|
375
|
+
ok: i.ok,
|
|
376
|
+
error: i.error,
|
|
377
|
+
responsePayload: i.payload
|
|
377
378
|
};
|
|
378
379
|
}
|
|
379
380
|
};
|
|
@@ -36,7 +36,7 @@ async function f(t) {
|
|
|
36
36
|
...o,
|
|
37
37
|
version: o?.version || a.NEW
|
|
38
38
|
};
|
|
39
|
-
return t.legacyDeviceId && (s.legacyDeviceId = t.legacyDeviceId), t.deviceId && (s.deviceId = t.deviceId, s.publicKeyPem = t.publicKeyPem, s.privateKeyPem = t.privateKeyPem, s.createdAtMs = t.createdAtMs), t.version && (s.version = t.version), "gatewayAuthMd5" in t && (s.gatewayAuthMd5 = t.gatewayAuthMd5), await n({
|
|
39
|
+
return t.legacyDeviceId && (s.legacyDeviceId = t.legacyDeviceId), t.deviceId && (s.deviceId = t.deviceId, s.publicKeyPem = t.publicKeyPem, s.privateKeyPem = t.privateKeyPem, s.createdAtMs = t.createdAtMs), t.version && (s.version = t.version), "gatewayAuthMd5" in t && (s.gatewayAuthMd5 = t.gatewayAuthMd5), "pluginVersionCode" in t && (s.pluginVersionCode = t.pluginVersionCode), await n({
|
|
40
40
|
rootDir: i,
|
|
41
41
|
relativePath: l(),
|
|
42
42
|
data: JSON.stringify(s, null, 2),
|
|
@@ -49,15 +49,12 @@ async function c() {
|
|
|
49
49
|
let r = await s();
|
|
50
50
|
return await t(r), r;
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
return (await e())?.gatewayAuthMd5;
|
|
54
|
-
}
|
|
55
|
-
function u(e, t) {
|
|
52
|
+
function l(e, t) {
|
|
56
53
|
let r = n.createPrivateKey(e);
|
|
57
54
|
return i(n.sign(null, Buffer.from(t, "utf8"), r));
|
|
58
55
|
}
|
|
59
|
-
function
|
|
56
|
+
function u(e) {
|
|
60
57
|
return i(a(e));
|
|
61
58
|
}
|
|
62
59
|
//#endregion
|
|
63
|
-
export { c as loadOrCreateDeviceIdentity,
|
|
60
|
+
export { c as loadOrCreateDeviceIdentity, u as publicKeyRawBase64UrlFromPem, l as signDevicePayload };
|
|
@@ -1,26 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { getYoyoPluginVersionCode as e } from "../../utils/version.mjs";
|
|
2
|
+
import { useClawLogger as t } from "../../utils/logger.mjs";
|
|
3
|
+
import { getConfigManager as n } from "../configs/config-manager.mjs";
|
|
4
|
+
import { isOKResponse as r } from "../../apis/helpers.mjs";
|
|
5
|
+
import { createClawCloudClient as i } from "../../apis/claw-cloud.mjs";
|
|
6
|
+
import { getPersistedIdentity as a, updatePersistedIdentity as o } from "../configs/identity-persist.mjs";
|
|
6
7
|
import "../configs/index.mjs";
|
|
7
8
|
import "../../apis/index.mjs";
|
|
8
|
-
import { formatHashForLog as
|
|
9
|
-
import { createGatewayAuthMd5 as
|
|
10
|
-
import { loadPersistedGatewayAuthMd5 as c } from "./identity.mjs";
|
|
9
|
+
import { formatHashForLog as s } from "../../utils/hash.mjs";
|
|
10
|
+
import { createGatewayAuthMd5 as c, isSameGatewayAuthMd5 as l } from "./gateway-auth.mjs";
|
|
11
11
|
//#region src/modules/device/registry.ts
|
|
12
|
-
async function
|
|
13
|
-
if (!
|
|
14
|
-
let
|
|
15
|
-
if (!
|
|
12
|
+
async function u(t, a) {
|
|
13
|
+
if (!t || !a) throw Error("设备信息或用户信息缺失");
|
|
14
|
+
let o = n().getGatewayAuthConfig(), s = c(o), l = e(), u = await i().registerDevice(t, a, o);
|
|
15
|
+
if (!r(u)) throw Error(`注册失败:${u.data?.cnMessage}`);
|
|
16
|
+
await f(s, l);
|
|
16
17
|
}
|
|
17
|
-
async function
|
|
18
|
-
let
|
|
19
|
-
if (
|
|
20
|
-
|
|
18
|
+
async function d(r, i) {
|
|
19
|
+
let o = c(n().getGatewayAuthConfig()), d = e(), f = await a(), p = f?.gatewayAuthMd5, m = f?.pluginVersionCode, h = t();
|
|
20
|
+
if (h.info(`[yoyoclaw-registry] checking registration state: gatewayAuth current=${s(o)}, persisted=${s(p)}; pluginVersionCode current=${d}, persisted=${m ?? "none"}`), l(p, o) && m === d) {
|
|
21
|
+
h.info("[yoyoclaw-registry] registration state unchanged, skipping device registration");
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
h.info("[yoyoclaw-registry] registration state changed, registering device"), await u(r, i), h.info(`[yoyoclaw-registry] device registration succeeded, pluginVersionCode=${d}`);
|
|
25
|
+
}
|
|
26
|
+
async function f(e, n) {
|
|
27
|
+
try {
|
|
28
|
+
await o({
|
|
29
|
+
gatewayAuthMd5: e,
|
|
30
|
+
pluginVersionCode: n
|
|
31
|
+
}), t().info("[yoyoclaw-registry] registration state persisted after device registration");
|
|
32
|
+
} catch (e) {
|
|
33
|
+
t().warn(`[yoyoclaw-registry] failed to persist registration state: ${String(e)}`);
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
//#endregion
|
|
26
|
-
export {
|
|
37
|
+
export { u as registerDevice, d as registerDeviceIfRegistrationStateChanged };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { processDeviceToolSet as e } from "./processor.mjs";
|
|
2
|
+
//#region src/modules/device-toolset/ack.ts
|
|
3
|
+
var t = "200", n = "500", r = "DeviceToolSet payload missing nodeId";
|
|
4
|
+
async function i(t) {
|
|
5
|
+
let n = a(t.payload);
|
|
6
|
+
if (t.namespace !== "yoyoclaw") {
|
|
7
|
+
let e = `Unsupported DeviceToolSet namespace: ${t.namespace ?? "unknown"}`;
|
|
8
|
+
return {
|
|
9
|
+
ok: !1,
|
|
10
|
+
error: e,
|
|
11
|
+
payload: s(n, e)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (!n) return {
|
|
15
|
+
ok: !1,
|
|
16
|
+
error: r,
|
|
17
|
+
payload: s("", r)
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
return {
|
|
21
|
+
ok: !0,
|
|
22
|
+
payload: o(await e(t.payload))
|
|
23
|
+
};
|
|
24
|
+
} catch (e) {
|
|
25
|
+
let t = e instanceof Error ? e.message : String(e);
|
|
26
|
+
return {
|
|
27
|
+
ok: !1,
|
|
28
|
+
error: t,
|
|
29
|
+
payload: s(n, t)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function a(e) {
|
|
34
|
+
let t = e?.nodeId;
|
|
35
|
+
return typeof t == "string" && t.trim() ? t : "";
|
|
36
|
+
}
|
|
37
|
+
function o(e) {
|
|
38
|
+
return {
|
|
39
|
+
nodeId: e.nodeId,
|
|
40
|
+
errorCode: t,
|
|
41
|
+
changed: e.changed,
|
|
42
|
+
rawCount: e.rawCount,
|
|
43
|
+
validCount: e.validCount
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function s(e, t) {
|
|
47
|
+
return {
|
|
48
|
+
nodeId: e,
|
|
49
|
+
errorCode: n,
|
|
50
|
+
errorMessage: t
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { i as createDeviceToolSetUpdateAck };
|
|
@@ -3,25 +3,20 @@ import { INVALID_TOOL_FILENAME_CHAR_PATTERN as t, TOOL_ARCHIVE_DIR as n } from "
|
|
|
3
3
|
import r from "node:path";
|
|
4
4
|
//#region src/modules/device-toolset/archive.ts
|
|
5
5
|
async function i(t, i) {
|
|
6
|
-
let s = 0
|
|
6
|
+
let s = 0;
|
|
7
7
|
for (let a of i) {
|
|
8
8
|
let i = o(a.name);
|
|
9
|
-
|
|
10
|
-
c += 1;
|
|
11
|
-
continue;
|
|
12
|
-
}
|
|
13
|
-
await e({
|
|
9
|
+
i && (await e({
|
|
14
10
|
rootDir: t,
|
|
15
11
|
relativePath: r.join(n, i),
|
|
16
12
|
data: JSON.stringify(a, null, 2),
|
|
17
13
|
encoding: "utf8",
|
|
18
14
|
mkdir: !0
|
|
19
|
-
}), s += 1;
|
|
15
|
+
}), s += 1);
|
|
20
16
|
}
|
|
21
17
|
return {
|
|
22
18
|
archiveDir: a(t),
|
|
23
|
-
writtenCount: s
|
|
24
|
-
skippedCount: c
|
|
19
|
+
writtenCount: s
|
|
25
20
|
};
|
|
26
21
|
}
|
|
27
22
|
function a(e) {
|
|
@@ -10,15 +10,14 @@ function t(t) {
|
|
|
10
10
|
return t;
|
|
11
11
|
}
|
|
12
12
|
function n(e) {
|
|
13
|
-
let t = e.nodeId, n = /* @__PURE__ */ new Map()
|
|
13
|
+
let t = e.nodeId, n = /* @__PURE__ */ new Map();
|
|
14
14
|
for (let t of e.toolSet) {
|
|
15
15
|
let e = r(t);
|
|
16
|
-
e
|
|
16
|
+
e && n.set(e.name, e);
|
|
17
17
|
}
|
|
18
18
|
return {
|
|
19
19
|
nodeId: t,
|
|
20
|
-
tools: Array.from(n.values())
|
|
21
|
-
skippedCount: i
|
|
20
|
+
tools: Array.from(n.values())
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
23
|
function r(t) {
|
|
@@ -36,8 +36,6 @@ async function s(e, t, r) {
|
|
|
36
36
|
mkdir: !0
|
|
37
37
|
}), {
|
|
38
38
|
changed: !0,
|
|
39
|
-
nodeCount: d(a.tools),
|
|
40
|
-
toolCount: Object.keys(a.tools).length,
|
|
41
39
|
cache: a
|
|
42
40
|
};
|
|
43
41
|
}
|
|
@@ -72,10 +70,5 @@ function l(e, t) {
|
|
|
72
70
|
function u(e, t) {
|
|
73
71
|
return [...new Set([...e, t])];
|
|
74
72
|
}
|
|
75
|
-
function d(e) {
|
|
76
|
-
let t = /* @__PURE__ */ new Set();
|
|
77
|
-
for (let n of Object.values(e)) for (let e of n.supportedNodeIds) t.add(e);
|
|
78
|
-
return t.size;
|
|
79
|
-
}
|
|
80
73
|
//#endregion
|
|
81
74
|
export { o as loadDeviceToolSetCache, s as mergeDeviceToolSetCache };
|
|
@@ -14,29 +14,29 @@ async function g(n) {
|
|
|
14
14
|
let g = p(n), _ = t();
|
|
15
15
|
if (!_) throw Error("Unable to resolve home directory for DeviceToolSet persistence");
|
|
16
16
|
let v = m(g);
|
|
17
|
-
e().info(`[yoyoclaw-device-toolset] process start, nodeId: ${v.nodeId},
|
|
17
|
+
e().info(`[yoyoclaw-device-toolset] process start, nodeId: ${v.nodeId}, raw: ${g.toolSet.length}, valid: ${v.tools.length}`);
|
|
18
18
|
let y = u(v.tools);
|
|
19
19
|
if (e().debug?.(`[yoyoclaw-device-toolset] computed md5, nodeId: ${v.nodeId}, md5: ${y}`), !(await d(_, v.nodeId, y)).changed) {
|
|
20
20
|
let t = await l(_, h);
|
|
21
21
|
return e().info(`[yoyoclaw-device-toolset] unchanged, skip refresh, nodeId: ${v.nodeId}, artifactsRestored: ${t.restored}`), {
|
|
22
22
|
changed: !1,
|
|
23
23
|
nodeId: v.nodeId,
|
|
24
|
-
|
|
24
|
+
rawCount: g.toolSet.length,
|
|
25
|
+
validCount: v.tools.length
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
let b = await s(_, v.nodeId, v.tools);
|
|
28
|
-
e().info(`[yoyoclaw-device-toolset] cache merged, nodeId: ${v.nodeId},
|
|
29
|
+
e().info(`[yoyoclaw-device-toolset] cache merged, nodeId: ${v.nodeId}, processed: ${v.tools.length}`);
|
|
29
30
|
let x = b.cache.tools, S = await i(_, v.tools);
|
|
30
|
-
e().info(`[yoyoclaw-device-toolset] archive refreshed, nodeId: ${v.nodeId}, written: ${S.writtenCount}
|
|
31
|
+
e().info(`[yoyoclaw-device-toolset] archive refreshed, nodeId: ${v.nodeId}, written: ${S.writtenCount}`);
|
|
31
32
|
let C = await c(h, x);
|
|
32
33
|
e().info(`[yoyoclaw-device-toolset] skill refreshed, nodeId: ${v.nodeId}, rows: ${C.rowCount}, updated: ${C.updated}`), C.updated && await r(h, v.nodeId);
|
|
33
34
|
let w = await a(S.archiveDir, o(h));
|
|
34
35
|
return e().info(`[yoyoclaw-device-toolset] mapping ready, nodeId: ${v.nodeId}, mode: ${w.mode}`), await f(_, v.nodeId, y, Date.now()), e().info(`[yoyoclaw-device-toolset] process complete, nodeId: ${v.nodeId}`), {
|
|
35
36
|
changed: !0,
|
|
36
37
|
nodeId: v.nodeId,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
skippedCount: v.skippedCount
|
|
38
|
+
rawCount: g.toolSet.length,
|
|
39
|
+
validCount: v.tools.length
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useClawLogger as e } from "../../utils/logger.mjs";
|
|
2
2
|
import { getConfigManager as t } from "../../modules/configs/config-manager.mjs";
|
|
3
|
-
import { registerDevice as n,
|
|
3
|
+
import { registerDevice as n, registerDeviceIfRegistrationStateChanged as r } from "../../modules/device/registry.mjs";
|
|
4
4
|
import { getDeviceInfo as i } from "../../modules/device/device-info.mjs";
|
|
5
5
|
import "../../modules/device/index.mjs";
|
|
6
6
|
import { clearToken as a, loadToken as o } from "../../honor-auth/token-manager.mjs";
|
package/dist/utils/version.mjs
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
//#region src/utils/version.ts
|
|
2
|
-
var e = null;
|
|
3
|
-
function
|
|
4
|
-
return e === null && (e = "1.4.
|
|
2
|
+
var e = null, t = null;
|
|
3
|
+
function n() {
|
|
4
|
+
return e === null && (e = "1.4.1-alpha.2".includes("beta") || "1.4.1-alpha.2".includes("alpha")), !!e;
|
|
5
|
+
}
|
|
6
|
+
function r(e) {
|
|
7
|
+
if (!e) return 0;
|
|
8
|
+
let t = Number.parseInt(e, 10);
|
|
9
|
+
return Number.isFinite(t) && t >= 0 ? t : 0;
|
|
10
|
+
}
|
|
11
|
+
function i() {
|
|
12
|
+
if (t !== null) return t;
|
|
13
|
+
let [e, n, i] = "1.4.1-alpha.2".split("-", 1)[0].split("."), a = r(e), o = r(n), s = r(i);
|
|
14
|
+
return t = a * 1e6 + o * 1e3 + s, t;
|
|
5
15
|
}
|
|
6
16
|
//#endregion
|
|
7
|
-
export {
|
|
17
|
+
export { i as getYoyoPluginVersionCode, n as isBetaVersion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honor-claw/yoyo",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1-alpha.2",
|
|
4
4
|
"description": "OpenClaw Honor Yoyo connection plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
|
14
14
|
"skills",
|
|
15
|
-
"openclaw.plugin.json"
|
|
16
|
-
"src/agent/**/*.md"
|
|
15
|
+
"openclaw.plugin.json"
|
|
17
16
|
],
|
|
18
17
|
"type": "module",
|
|
19
18
|
"exports": {
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yoyo-update
|
|
3
|
+
description: >
|
|
4
|
+
更新 YOYO 插件到最新版本。当用户要求更新、升级 yoyo 插件,或检查 yoyo 插件版本更新时触发。
|
|
5
|
+
metadata: { "openclaw": { "emoji": "🔄", "always": true } }
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# YOYO 插件更新
|
|
9
|
+
|
|
10
|
+
按照以下 5 步工作流完成 YOYO 插件的版本更新。
|
|
11
|
+
|
|
12
|
+
## 全局规则
|
|
13
|
+
|
|
14
|
+
- [MANDATORY] **严禁在技能流程内重启网关** — 不得执行 `openclaw gateway stop/start/restart` 或任何网关重启操作
|
|
15
|
+
- [MANDATORY] **严禁卸载插件** — 不得执行 `openclaw plugins uninstall`,否则用户配置将丢失
|
|
16
|
+
- [MANDATORY] 出错时仅汇总错误并给出建议,不得尝试自动修复(尤其是不得通过卸载重装来解决问题)
|
|
17
|
+
- [MANDATORY] 所有面向用户的输出必须使用中文
|
|
18
|
+
- 所有命令在 Windows (bash) 和 Unix (bash) 环境下格式一致,无需区分平台
|
|
19
|
+
|
|
20
|
+
## 步骤 1:预检查
|
|
21
|
+
|
|
22
|
+
执行以下命令获取当前插件信息:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
openclaw plugins info yoyo
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**输出字段说明**:
|
|
29
|
+
|
|
30
|
+
| 字段 | 说明 | 示例 |
|
|
31
|
+
| -------------- | ---------------------------- | -------------------------------- |
|
|
32
|
+
| `Status` | 插件加载状态 | `loaded` / `error` / `not found` |
|
|
33
|
+
| `Version` | 当前已安装版本 | `1.3.0-beta.8` |
|
|
34
|
+
| `Spec` | 安装来源标识,含包名和渠道 | `@honor-claw/yoyo@beta` |
|
|
35
|
+
| `Install path` | 插件安装路径 | `~/.openclaw/extensions/yoyo` |
|
|
36
|
+
|
|
37
|
+
**处理规则**:
|
|
38
|
+
|
|
39
|
+
- 若插件未找到(输出为空或提示未安装)→ 告知用户"未检测到 YOYO 插件,请先安装"并停止
|
|
40
|
+
- 若状态非 `loaded`(如 `error`)→ 告知用户插件状态异常并展示具体信息,停止流程
|
|
41
|
+
- 若命令本身执行失败 → 告知用户"无法获取插件信息,请确认 OpenClaw 网关正在运行"并停止
|
|
42
|
+
- 成功获取信息 → 提取 `Version` 和 `Spec` 字段值,进入步骤 2
|
|
43
|
+
|
|
44
|
+
## 步骤 2:检查最新版本
|
|
45
|
+
|
|
46
|
+
### 2.1 确定当前发布渠道
|
|
47
|
+
|
|
48
|
+
根据步骤 1 中 `Spec` 字段判断当前发布渠道:
|
|
49
|
+
|
|
50
|
+
- `Spec` 包含 `@alpha` 后缀 → 渠道为 `alpha`
|
|
51
|
+
- `Spec` 包含 `@beta` 后缀 → 渠道为 `beta`
|
|
52
|
+
- `Spec` 无预发布后缀 → 渠道为 `latest`
|
|
53
|
+
|
|
54
|
+
### 2.2 查询最新版本
|
|
55
|
+
|
|
56
|
+
执行以下命令获取所有发布渠道的最新版本:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm view @honor-claw/yoyo dist-tags --json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
从 JSON 输出中提取对应渠道的版本号。示例输出:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"latest": "1.2.0",
|
|
67
|
+
"beta": "1.3.0-beta.8",
|
|
68
|
+
"alpha": "1.4.0-alpha.3"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
若 `npm view` 命令失败,回退使用以下命令获取 `latest` 版本:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm view @honor-claw/yoyo version
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2.3 版本对比
|
|
79
|
+
|
|
80
|
+
将目标版本(对应渠道最新版)与步骤 1 获取的当前版本进行对比:
|
|
81
|
+
|
|
82
|
+
- **版本相同** → 告知用户"当前已是最新版本(v{version}),无需更新"并停止流程
|
|
83
|
+
- **版本不同** → 记录当前版本和目标版本,进入步骤 3
|
|
84
|
+
|
|
85
|
+
## 步骤 3:展示版本差异
|
|
86
|
+
|
|
87
|
+
向用户展示更新摘要后直接进入步骤 4:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
🔄 YOYO 插件更新可用
|
|
91
|
+
|
|
92
|
+
当前版本:v{当前版本}
|
|
93
|
+
目标版本:v{目标版本}
|
|
94
|
+
发布渠道:{渠道名}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 步骤 4:执行更新
|
|
98
|
+
|
|
99
|
+
### 4.1 执行更新命令
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
openclaw plugins update yoyo
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
注意:该命令可能需要较长时间执行(下载和安装),请使用足够的超时时间。
|
|
106
|
+
|
|
107
|
+
### 4.2 监控更新进度
|
|
108
|
+
|
|
109
|
+
实时监控命令输出,根据不同阶段向用户报告进度:
|
|
110
|
+
|
|
111
|
+
| 输出关键词 | 向用户报告 | 内部处理 |
|
|
112
|
+
| -------------------------------------- | ----------------- | ------------------------------ |
|
|
113
|
+
| `Downloading @honor-claw/yoyo@` | "正在下载插件..." | — |
|
|
114
|
+
| `Extracting` | 不输出 | 静默跟踪 |
|
|
115
|
+
| `Installing to` | "正在更新插件..." | — |
|
|
116
|
+
| `Installing plugin dependencies` | 不输出 | 静默跟踪 |
|
|
117
|
+
| `Updated yoyo:` | 不输出 | 捕获成功版本信息 |
|
|
118
|
+
| `Config overwrite:` / `Config backup:` | 不输出 | 记录配置备份路径 |
|
|
119
|
+
| `Restart the gateway to load plugins` | 不输出 | 更新成功的确认信号,进入步骤 5 |
|
|
120
|
+
|
|
121
|
+
### 4.3 错误处理
|
|
122
|
+
|
|
123
|
+
若命令执行过程中出现错误(非零退出码或输出中包含错误信息):
|
|
124
|
+
|
|
125
|
+
- 记录完整错误输出
|
|
126
|
+
- 不尝试重试或替代方案
|
|
127
|
+
- 直接进入步骤 5 的失败处理流程
|
|
128
|
+
|
|
129
|
+
## 步骤 5:更新后处理
|
|
130
|
+
|
|
131
|
+
### 更新成功
|
|
132
|
+
|
|
133
|
+
向用户报告:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
✅ 插件更新完成
|
|
137
|
+
|
|
138
|
+
更新版本:v{旧版本} → v{新版本}
|
|
139
|
+
|
|
140
|
+
插件更新完成,重启网关后生效。是否立即重启?
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**[MANDATORY] 不得在此步骤中执行网关重启操作。** 仅向用户提问,由用户在下一轮对话中自行决定是否重启。
|
|
144
|
+
|
|
145
|
+
### 更新失败
|
|
146
|
+
|
|
147
|
+
向用户报告失败摘要:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
❌ 插件更新失败
|
|
151
|
+
|
|
152
|
+
失败原因:{简要描述错误}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
并给出以下建议(根据实际错误类型选择):
|
|
156
|
+
|
|
157
|
+
- 网络错误(如 `ECONNREFUSED`、`ETIMEDOUT`)→ "请检查网络连接后重试"
|
|
158
|
+
- 权限错误(如 `EACCES`、`EPERM`)→ "请检查 OpenClaw 安装目录的读写权限"
|
|
159
|
+
- 版本冲突 / 依赖冲突 → "请将以下错误信息反馈给开发团队"
|
|
160
|
+
- 其他未预期错误 → "请将错误信息反馈给开发团队,或稍后重试"
|
|
161
|
+
|
|
162
|
+
**[MANDATORY] 不得尝试以下操作**:
|
|
163
|
+
- 卸载后重装插件(配置会丢失)
|
|
164
|
+
- 手动删除插件目录
|
|
165
|
+
- 修改插件配置文件来绕过错误
|
|
166
|
+
- 重启网关
|