@honor-claw/yoyo 2026.6.9-beta.2 → 2026.6.9-beta.20
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 +0 -19
- package/dist/capabilities/admin/impl.mjs +44 -24
- package/dist/capabilities/admin/manager.mjs +21 -19
- package/dist/capabilities/node/directory.mjs +10 -0
- package/dist/capabilities/node/index.mjs +1 -0
- package/dist/capabilities/node/invoke.mjs +27 -22
- package/dist/capabilities/node/list.mjs +22 -12
- package/dist/capabilities/routing/index.mjs +1 -0
- package/dist/capabilities/routing/restart.mjs +17 -0
- package/dist/channel/directory.mjs +5 -8
- package/dist/channel/messaging.mjs +15 -15
- package/dist/{commands → cli}/debug/clean-tools.mjs +1 -1
- package/dist/{commands → cli}/debug/impl.mjs +1 -1
- package/dist/{commands → cli}/env/impl.mjs +1 -1
- package/dist/{commands → cli}/index.mjs +6 -7
- package/dist/{commands → cli}/login/impl.mjs +2 -2
- package/dist/cli/logout/impl.mjs +29 -0
- package/dist/cloud-channel/authorization/refresh-manager.mjs +4 -4
- package/dist/cloud-channel/dispatcher/impl.mjs +13 -19
- package/dist/cloud-channel/handlers/context/handler.mjs +74 -73
- package/dist/cloud-channel/transport/cloud-socket.mjs +43 -69
- package/dist/command/diagnose.mjs +9 -0
- package/dist/command/doctor.mjs +9 -0
- package/dist/command/help.mjs +30 -0
- package/dist/command/index.mjs +33 -0
- package/dist/command/parser.mjs +19 -0
- package/dist/command/status.mjs +9 -0
- package/dist/core/hooks/gateway-lifecycle.mjs +9 -11
- package/dist/core/hooks/tool-trace.mjs +24 -18
- package/dist/core/prompt/builder.mjs +8 -13
- package/dist/diagnose/chat-id-resolver.mjs +42 -0
- package/dist/diagnose/collector.mjs +29 -0
- package/dist/diagnose/collectors/account.mjs +32 -0
- package/dist/diagnose/collectors/configuration.mjs +17 -0
- package/dist/diagnose/collectors/connection.mjs +7 -0
- package/dist/diagnose/collectors/environment.mjs +18 -0
- package/dist/diagnose/connection/tracker.mjs +59 -0
- package/dist/diagnose/index.mjs +7 -0
- package/dist/diagnose/report/diagnose.mjs +72 -0
- package/dist/diagnose/report/doctor/device-check.mjs +72 -0
- package/dist/diagnose/report/doctor/impl.mjs +95 -0
- package/dist/diagnose/report/doctor/index.mjs +1 -0
- package/dist/diagnose/report/formatter.mjs +30 -0
- package/dist/diagnose/report/index.mjs +5 -0
- package/dist/diagnose/report/status.mjs +55 -0
- package/dist/diagnose/report/trace.mjs +116 -0
- package/dist/gateway/client/admin.mjs +3 -0
- package/dist/gateway/client/node.mjs +5 -23
- package/dist/gateway/client/protocol.mjs +4 -4
- package/dist/gateway/session/manager.mjs +58 -76
- package/dist/honor-auth/browser/flow.mjs +1 -1
- package/dist/honor-auth/browser/result-page.mjs +125 -75
- package/dist/honor-auth/login/impl.mjs +24 -23
- package/dist/honor-auth/logout.mjs +6 -6
- package/dist/honor-auth/vault/impl.mjs +39 -21
- package/dist/honor-auth/vault/token-expiry.mjs +1 -1
- package/dist/index.mjs +11 -10
- package/dist/messaging/dispatchers/command/impl.mjs +10 -15
- package/dist/messaging/dispatchers/stream/controller.mjs +51 -32
- package/dist/messaging/dispatchers/stream/error.mjs +47 -25
- package/dist/messaging/dispatchers/stream/hooks.mjs +9 -9
- package/dist/messaging/dispatchers/stream/index.mjs +1 -0
- package/dist/messaging/dispatchers/stream/session.mjs +70 -68
- package/dist/messaging/dispatchers/stream/tool/sanitize.mjs +1 -20
- package/dist/messaging/guard/constants.mjs +10 -0
- package/dist/messaging/guard/content.mjs +31 -0
- package/dist/messaging/guard/index.mjs +2 -0
- package/dist/messaging/guard/reasoning.mjs +21 -0
- package/dist/messaging/guard/snapshot.mjs +6 -0
- package/dist/messaging/guard/state.mjs +9 -0
- package/dist/messaging/guard/tokens.mjs +28 -0
- package/dist/messaging/inbound/agent.mjs +22 -20
- package/dist/messaging/inbound/command.mjs +26 -23
- package/dist/messaging/inbound/context.mjs +27 -21
- package/dist/messaging/inbound/dispatch.mjs +33 -30
- package/dist/messaging/inbound/interrupt.mjs +1 -1
- package/dist/messaging/inbound/new-session.mjs +1 -1
- package/dist/messaging/index.mjs +1 -1
- package/dist/messaging/send/text.mjs +22 -13
- package/dist/messaging/target/address.mjs +24 -13
- package/dist/messaging/target/index.mjs +1 -1
- package/dist/messaging/target/outbound.mjs +9 -9
- package/dist/messaging/trace/fingerprint.mjs +19 -0
- package/dist/messaging/trace/index.mjs +5 -0
- package/dist/messaging/trace/lifecycle.mjs +49 -0
- package/dist/messaging/trace/query.mjs +25 -0
- package/dist/messaging/trace/storage.mjs +59 -0
- package/dist/messaging/trace/tool-context.mjs +30 -0
- package/dist/messaging/trace/tool.mjs +112 -0
- package/dist/modules/configs/channel.mjs +12 -3
- package/dist/modules/configs/plugin-init.mjs +36 -44
- package/dist/modules/configs/plugin.mjs +4 -7
- package/dist/modules/configs/provider.mjs +58 -58
- package/dist/modules/device/helpers.mjs +1 -3
- package/dist/modules/secure-token/crypto-utils.mjs +1 -1
- package/dist/modules/secure-token/token-record.mjs +5 -1
- package/dist/modules/secure-token/token-vault.mjs +1 -1
- package/dist/provisioning/toolset/ack.mjs +20 -19
- package/dist/provisioning/toolset/archive.mjs +1 -2
- package/dist/provisioning/toolset/consts.mjs +2 -2
- package/dist/provisioning/toolset/copy.mjs +31 -0
- package/dist/provisioning/toolset/link.mjs +35 -35
- package/dist/provisioning/toolset/normalize.mjs +8 -10
- package/dist/provisioning/toolset/skill-refresh-marker.mjs +1 -1
- package/dist/tools/index.mjs +5 -5
- package/dist/tools/nodes-status/mapper.mjs +10 -14
- package/dist/tools/nodes-status/tool.mjs +1 -6
- package/dist/tools/plugin-restart/tool.mjs +44 -0
- package/dist/types.mjs +6 -0
- package/dist/utils/home-dir.mjs +18 -20
- package/dist/utils/normalize.mjs +6 -0
- package/dist/utils/object.mjs +8 -0
- package/dist/utils/version.mjs +23 -15
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/yoyo-phone-control/SKILL.md +5 -14
- package/skills/yoyo-phone-control/configs/sub-skills.json +1 -15
- package/skills/yoyo-phone-control/mcptools/airplane_mode.json +67 -0
- package/skills/yoyo-phone-control/mcptools/autoscreen_onnotice.json +63 -0
- package/skills/yoyo-phone-control/mcptools/battery.json +66 -0
- package/skills/yoyo-phone-control/mcptools/bluetooth.json +78 -0
- package/skills/yoyo-phone-control/mcptools/brightness.json +150 -0
- package/skills/yoyo-phone-control/mcptools/call.json +107 -0
- package/skills/yoyo-phone-control/mcptools/camera.json +146 -0
- package/skills/yoyo-phone-control/mcptools/cancel_countdown_timer.json +71 -0
- package/skills/yoyo-phone-control/mcptools/capture_screenshot.json +69 -0
- package/skills/yoyo-phone-control/mcptools/check_alarm.json +90 -0
- package/skills/yoyo-phone-control/mcptools/check_countdown_timer.json +55 -0
- package/skills/yoyo-phone-control/mcptools/check_schedule.json +76 -0
- package/skills/yoyo-phone-control/mcptools/check_todo.json +72 -0
- package/skills/yoyo-phone-control/mcptools/clean_dirty.json +61 -0
- package/skills/yoyo-phone-control/mcptools/close_alarm.json +91 -0
- package/skills/yoyo-phone-control/mcptools/close_app.json +90 -0
- package/skills/yoyo-phone-control/mcptools/close_countdown_timer.json +70 -0
- package/skills/yoyo-phone-control/mcptools/create_alarm.json +93 -0
- package/skills/yoyo-phone-control/mcptools/create_countdown_timer.json +77 -0
- package/skills/yoyo-phone-control/mcptools/create_schedule.json +86 -0
- package/skills/yoyo-phone-control/mcptools/create_todo.json +73 -0
- package/skills/yoyo-phone-control/mcptools/dark_mode.json +63 -0
- package/skills/yoyo-phone-control/mcptools/delete_alarm.json +99 -0
- package/skills/yoyo-phone-control/mcptools/delete_schedule.json +107 -0
- package/skills/yoyo-phone-control/mcptools/delete_todo.json +35 -0
- package/skills/yoyo-phone-control/mcptools/desktop.json +240 -0
- package/skills/yoyo-phone-control/mcptools/device_operation.json +122 -0
- package/skills/yoyo-phone-control/mcptools/express_logistics_query.json +51 -0
- package/skills/yoyo-phone-control/mcptools/eyecomfort.json +76 -0
- package/skills/yoyo-phone-control/mcptools/flashlight.json +65 -0
- package/skills/yoyo-phone-control/mcptools/get_user_location.json +62 -0
- package/skills/yoyo-phone-control/mcptools/gui_task_pause.json +67 -0
- package/skills/yoyo-phone-control/mcptools/hotspot.json +66 -0
- package/skills/yoyo-phone-control/mcptools/hover_button.json +71 -0
- package/skills/yoyo-phone-control/mcptools/local_user_file_search.json +120 -0
- package/skills/yoyo-phone-control/mcptools/location_service.json +79 -0
- package/skills/yoyo-phone-control/mcptools/mobile_data.json +78 -0
- package/skills/yoyo-phone-control/mcptools/modify_schedule.json +107 -0
- package/skills/yoyo-phone-control/mcptools/modify_todo.json +35 -0
- package/skills/yoyo-phone-control/mcptools/musicFeedbackAction.json +46 -0
- package/skills/yoyo-phone-control/mcptools/nfc.json +68 -0
- package/skills/yoyo-phone-control/mcptools/no_disturb.json +59 -0
- package/skills/yoyo-phone-control/mcptools/onehanded_mode.json +84 -0
- package/skills/yoyo-phone-control/mcptools/open_alarm.json +91 -0
- package/skills/yoyo-phone-control/mcptools/open_app.json +92 -0
- package/skills/yoyo-phone-control/mcptools/open_countdown_timer.json +43 -0
- package/skills/yoyo-phone-control/mcptools/open_payment_code.json +83 -0
- package/skills/yoyo-phone-control/mcptools/open_transport_code.json +53 -0
- package/skills/yoyo-phone-control/mcptools/operateMusic.json +76 -0
- package/skills/yoyo-phone-control/mcptools/operateRhythm.json +59 -0
- package/skills/yoyo-phone-control/mcptools/operateVideo.json +64 -0
- package/skills/yoyo-phone-control/mcptools/pause_countdown_timer.json +71 -0
- package/skills/yoyo-phone-control/mcptools/playMusic.json +125 -0
- package/skills/yoyo-phone-control/mcptools/playNews.json +35 -0
- package/skills/yoyo-phone-control/mcptools/playVideo.json +109 -0
- package/skills/yoyo-phone-control/mcptools/play_record.json +56 -0
- package/skills/yoyo-phone-control/mcptools/quiet_mode.json +67 -0
- package/skills/yoyo-phone-control/mcptools/recognitionMusic.json +54 -0
- package/skills/yoyo-phone-control/mcptools/record.json +88 -0
- package/skills/yoyo-phone-control/mcptools/redial_recall.json +88 -0
- package/skills/yoyo-phone-control/mcptools/restart_countdown_timer.json +71 -0
- package/skills/yoyo-phone-control/mcptools/resume_countdown_timer.json +71 -0
- package/skills/yoyo-phone-control/mcptools/ringing_mode.json +63 -0
- package/skills/yoyo-phone-control/mcptools/scan_code.json +51 -0
- package/skills/yoyo-phone-control/mcptools/screen_recorder.json +76 -0
- package/skills/yoyo-phone-control/mcptools/search_contact.json +59 -0
- package/skills/yoyo-phone-control/mcptools/search_message.json +59 -0
- package/skills/yoyo-phone-control/mcptools/search_record.json +72 -0
- package/skills/yoyo-phone-control/mcptools/send_message.json +103 -0
- package/skills/yoyo-phone-control/mcptools/setMusicPlayMode.json +56 -0
- package/skills/yoyo-phone-control/mcptools/status_bar_show.json +91 -0
- package/skills/yoyo-phone-control/mcptools/switchMusic.json +66 -0
- package/skills/yoyo-phone-control/mcptools/uninstall_app.json +88 -0
- package/skills/yoyo-phone-control/mcptools/usb_shared_network.json +62 -0
- package/skills/yoyo-phone-control/mcptools/vibration_mode.json +86 -0
- package/skills/yoyo-phone-control/mcptools/volume.json +103 -0
- package/skills/yoyo-phone-control/mcptools/wlan.json +105 -0
- package/skills/yoyo-phone-control/references/gui-task-create.md +11 -3
- package/skills/yoyo-phone-control/references/{local_user_data_qa.md → local-user-data-qa.md} +33 -49
- package/skills/yoyo-phone-control/references/{local_user_file_search.md → local-user-file-search.md} +27 -27
- package/skills/yoyo-phone-control/references/task-result-query.md +1 -1
- package/skills/yoyo-update/SKILL.md +55 -11
- package/dist/capabilities/cloud-invoke/index.mjs +0 -1
- package/dist/capabilities/cloud-invoke/invoke.mjs +0 -43
- package/dist/commands/logout/impl.mjs +0 -18
- package/dist/commands/status/index.mjs +0 -64
- package/dist/core/prompt/cloud-tool.mjs +0 -7
- package/dist/messaging/dispatchers/stream/tool/index.mjs +0 -4
- package/dist/messaging/dispatchers/stream/tool/trace-store.mjs +0 -120
- package/dist/modules/status/channel.mjs +0 -1
- package/dist/modules/status/events.mjs +0 -6
- package/dist/modules/status/global.mjs +0 -32
- package/dist/modules/status/index.mjs +0 -6
- package/dist/modules/status/storage.mjs +0 -52
- package/dist/modules/status/tracker.mjs +0 -155
- package/dist/modules/status/types.mjs +0 -36
- package/dist/provisioning/toolset/copy-fallback.mjs +0 -42
- package/dist/tools/cloud-invoke/tool.mjs +0 -48
- package/dist/utils/array.mjs +0 -6
- package/skills/yoyo-phone-control/references/alarm-create.md +0 -356
- package/skills/yoyo-phone-control/references/alarm-delete.md +0 -301
- package/skills/yoyo-phone-control/references/alarm-disable.md +0 -309
- package/skills/yoyo-phone-control/references/alarm-enable.md +0 -309
- package/skills/yoyo-phone-control/references/alarm-query.md +0 -411
- package/skills/yoyo-phone-control/references/alarm-update.md +0 -386
- package/skills/yoyo-phone-control/references/file-upload.md +0 -283
- package/skills/yoyo-phone-control/references/local-search.md +0 -221
- package/skills/yoyo-phone-control/references/schedule-create.md +0 -483
- package/skills/yoyo-phone-control/references/schedule-delete.md +0 -507
- package/skills/yoyo-phone-control/references/schedule-search.md +0 -591
- package/skills/yoyo-phone-control/references/schedule-update.md +0 -556
- package/skills/yoyo-smart-home/SKILL.md +0 -78
- package/skills/yoyo-smart-home/mcptools/device_control.json +0 -136
- package/skills/yoyo-smart-home/mcptools/device_query.json +0 -114
- package/skills/yoyo-smart-home/mcptools/skill_exit.json +0 -6
- /package/dist/{commands → cli}/debug/index.mjs +0 -0
- /package/dist/{commands → cli}/env/index.mjs +0 -0
- /package/dist/{commands → cli}/login/index.mjs +0 -0
- /package/dist/{commands → cli}/logout/index.mjs +0 -0
- /package/dist/tools/{cloud-invoke → plugin-restart}/index.mjs +0 -0
package/dist/apis/claw-cloud.mjs
CHANGED
|
@@ -69,25 +69,6 @@ var o = class {
|
|
|
69
69
|
timeout: r?.timeoutMs ?? 3e4
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
async invokeCloudTool(e, n, r) {
|
|
73
|
-
let i = {
|
|
74
|
-
"x-trace-id": t(),
|
|
75
|
-
"x-jwt-token": n.token
|
|
76
|
-
}, a = {
|
|
77
|
-
pluginService: { serviceId: r.serviceId },
|
|
78
|
-
pluginParams: r.pluginParams,
|
|
79
|
-
device: {
|
|
80
|
-
deviceId: e.deviceId,
|
|
81
|
-
role: "yoyoclaw",
|
|
82
|
-
port: e.port
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
return this.httpClient.post("/icsplugin/execute", {
|
|
86
|
-
headers: i,
|
|
87
|
-
body: a,
|
|
88
|
-
timeout: r?.timeoutMs ?? 3e4
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
72
|
async exchangeToken(e, r) {
|
|
92
73
|
let i = t(), o = {
|
|
93
74
|
"Content-Type": "application/json",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { toErrorMessage as e } from "../../utils/error.mjs";
|
|
2
|
+
import { clawLogger as t } from "../../utils/claw-logger.mjs";
|
|
3
|
+
import { AdminClientManager as n } from "./manager.mjs";
|
|
3
4
|
//#region src/capabilities/admin/impl.ts
|
|
4
|
-
var
|
|
5
|
-
manager = new
|
|
5
|
+
var r = t("capabilities"), i = null, a = class {
|
|
6
|
+
manager = new n();
|
|
6
7
|
constructor() {
|
|
7
8
|
this.manager.init();
|
|
8
9
|
}
|
|
@@ -17,15 +18,15 @@ var n = e("capabilities"), r = null, i = class {
|
|
|
17
18
|
}
|
|
18
19
|
async pairApprove(e) {
|
|
19
20
|
let t = this.manager.getClient();
|
|
20
|
-
if (!t) return
|
|
21
|
+
if (!t) return r.warn("admin client not available for auto pair"), !1;
|
|
21
22
|
try {
|
|
22
|
-
let
|
|
23
|
-
return
|
|
23
|
+
let n = await t.devicePairApprove(e);
|
|
24
|
+
return n.ok ? (r.info("auto pair approve completed", { ok: !0 }), !0) : (r.warn("auto pair approve rejected", {
|
|
24
25
|
ok: !1,
|
|
25
|
-
errorCode:
|
|
26
|
+
errorCode: n.error?.code
|
|
26
27
|
}), !1);
|
|
27
28
|
} catch (t) {
|
|
28
|
-
return
|
|
29
|
+
return r.error("auto pair approve failed, ignore...", t, { requestId: e }), !1;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
async setAgentFile(e, t, n) {
|
|
@@ -63,37 +64,56 @@ var n = e("capabilities"), r = null, i = class {
|
|
|
63
64
|
};
|
|
64
65
|
}
|
|
65
66
|
async getModelList() {
|
|
66
|
-
let
|
|
67
|
-
if (!
|
|
67
|
+
let t = this.manager.getClient();
|
|
68
|
+
if (!t) return {
|
|
68
69
|
ok: !1,
|
|
69
70
|
error: "Admin gateway client not ready"
|
|
70
71
|
};
|
|
71
72
|
try {
|
|
72
73
|
return {
|
|
73
74
|
ok: !0,
|
|
74
|
-
data: { models: (await
|
|
75
|
+
data: { models: (await t.getModelList())?.models ?? [] }
|
|
75
76
|
};
|
|
76
|
-
} catch (
|
|
77
|
-
let
|
|
78
|
-
return
|
|
77
|
+
} catch (t) {
|
|
78
|
+
let n = e(t);
|
|
79
|
+
return r.error("fetchModelsList failed", t), {
|
|
79
80
|
ok: !1,
|
|
80
|
-
error: `fetchModelsList error: ${
|
|
81
|
+
error: `fetchModelsList error: ${n}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async restart(t) {
|
|
86
|
+
let n = this.manager.getClient();
|
|
87
|
+
if (!n) return {
|
|
88
|
+
ok: !1,
|
|
89
|
+
error: "Admin gateway client not ready"
|
|
90
|
+
};
|
|
91
|
+
try {
|
|
92
|
+
return await n.restartGateway(t), r.info("plugin restart command dispatched via admin RPC", { reason: t }), {
|
|
93
|
+
ok: !0,
|
|
94
|
+
data: { dispatched: !0 }
|
|
95
|
+
};
|
|
96
|
+
} catch (t) {
|
|
97
|
+
let n = e(t);
|
|
98
|
+
return r.error("gateway restart RPC failed", t), {
|
|
99
|
+
ok: !1,
|
|
100
|
+
error: `gateway restart failed: ${n}`
|
|
81
101
|
};
|
|
82
102
|
}
|
|
83
103
|
}
|
|
84
104
|
};
|
|
85
|
-
function a() {
|
|
86
|
-
return r === null && (r = new i()), r;
|
|
87
|
-
}
|
|
88
105
|
function o() {
|
|
89
|
-
return a();
|
|
106
|
+
return i === null && (i = new a()), i;
|
|
90
107
|
}
|
|
91
108
|
function s() {
|
|
92
|
-
|
|
93
|
-
return n.info("admin gateway connection started", { ready: e }), e;
|
|
109
|
+
return o();
|
|
94
110
|
}
|
|
95
111
|
function c() {
|
|
96
|
-
|
|
112
|
+
let e = o().ensureConnected();
|
|
113
|
+
return r.info("admin gateway connection started", { ready: e }), e;
|
|
114
|
+
}
|
|
115
|
+
function l() {
|
|
116
|
+
o().destroy(), r.info("admin gateway connection stopped");
|
|
97
117
|
}
|
|
98
118
|
//#endregion
|
|
99
|
-
export {
|
|
119
|
+
export { c as startAdminConnection, l as stopAdminConnection, s as useAdminCapability };
|
|
@@ -1,48 +1,50 @@
|
|
|
1
1
|
import { clawLogger as e } from "../../utils/claw-logger.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { markAdminAuthenticated as t, markAdminAuthenticating as n, markAdminClosed as r, markAdminError as i, markAdminReconnecting as a } from "../../diagnose/connection/tracker.mjs";
|
|
3
|
+
import { getGatewayAuthConfig as o } from "../../modules/configs/gateway.mjs";
|
|
3
4
|
import "../../modules/configs/index.mjs";
|
|
4
|
-
import
|
|
5
|
-
import { StatusEventTypeE as r } from "../../modules/status/events.mjs";
|
|
6
|
-
import { emitStatusEvent as i } from "../../modules/status/global.mjs";
|
|
5
|
+
import s from "../../gateway/client/admin.mjs";
|
|
7
6
|
//#region src/capabilities/admin/manager.ts
|
|
8
|
-
var
|
|
7
|
+
var c = e("capabilities"), l = class {
|
|
9
8
|
client = null;
|
|
10
9
|
ready = !1;
|
|
11
10
|
pendingReadyRequests = /* @__PURE__ */ new Map();
|
|
12
11
|
requestIdCounter = 0;
|
|
13
12
|
init() {
|
|
14
13
|
if (this.client !== null) return;
|
|
15
|
-
let e =
|
|
16
|
-
this.client = new
|
|
17
|
-
token:
|
|
18
|
-
password:
|
|
14
|
+
let e = o(), l = typeof e?.token == "string" ? e.token : "", u = typeof e?.password == "string" ? e.password : "";
|
|
15
|
+
n(), this.client = new s({
|
|
16
|
+
token: l,
|
|
17
|
+
password: u,
|
|
19
18
|
onAuthenticated: () => {
|
|
20
|
-
|
|
19
|
+
c.info("admin gateway client authenticated"), t(), this.ready = !0, this.resolveAllPending(!0);
|
|
21
20
|
},
|
|
22
21
|
onClose: (e) => {
|
|
23
|
-
|
|
22
|
+
c.info("admin gateway client closed", { reason: e }), r(e), this.ready = !1;
|
|
23
|
+
},
|
|
24
|
+
onReconnecting: (e, t) => {
|
|
25
|
+
c.info("admin gateway client reconnecting", {
|
|
26
|
+
reason: e,
|
|
27
|
+
retryCount: t
|
|
28
|
+
}), a(e, t), this.ready = !1;
|
|
24
29
|
},
|
|
25
30
|
onReconnectFailed: () => {
|
|
26
|
-
|
|
27
|
-
type: r.ADMIN_CLIENT_RECONNECT_FAILED,
|
|
28
|
-
data: {}
|
|
29
|
-
});
|
|
31
|
+
c.error("admin gateway client reconnect failed"), i("网关管理通道连接重试超限");
|
|
30
32
|
}
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
destroy() {
|
|
34
|
-
this.client &&= (this.client.stop(), null), this.ready = !1, this.cancelAllPending(),
|
|
36
|
+
this.client &&= (this.client.stop(), null), this.ready = !1, this.cancelAllPending(), c.info("admin client destroyed");
|
|
35
37
|
}
|
|
36
38
|
getClient() {
|
|
37
39
|
return this.ready && this.client?.isAuthenticated() ? this.client : null;
|
|
38
40
|
}
|
|
39
41
|
ensureConnected() {
|
|
40
|
-
return this.client === null && (
|
|
42
|
+
return this.client === null && (c.info("admin gateway client is null, initializing"), this.init()), this.ready || (c.info("admin gateway client not ready, connecting"), this.client?.connect()), this.client !== null && this.ready;
|
|
41
43
|
}
|
|
42
44
|
waitForReady(e = 5e3) {
|
|
43
45
|
return this.client !== null && this.ready ? Promise.resolve(!0) : new Promise((t) => {
|
|
44
46
|
let n = `req_${++this.requestIdCounter}`, r = setTimeout(() => {
|
|
45
|
-
this.pendingReadyRequests.delete(n), this.pendingReadyRequests.size === 0 &&
|
|
47
|
+
this.pendingReadyRequests.delete(n), this.pendingReadyRequests.size === 0 && c.warn("admin gateway client waitForReady timeout, all requests rejected"), t(!1);
|
|
46
48
|
}, e);
|
|
47
49
|
this.pendingReadyRequests.set(n, {
|
|
48
50
|
resolve: t,
|
|
@@ -60,4 +62,4 @@ var a = e("capabilities"), o = class {
|
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
//#endregion
|
|
63
|
-
export {
|
|
65
|
+
export { l as AdminClientManager };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { listNodeDevices as e } from "./list.mjs";
|
|
2
|
+
//#region src/capabilities/node/directory.ts
|
|
3
|
+
async function t() {
|
|
4
|
+
return (await e()).devices;
|
|
5
|
+
}
|
|
6
|
+
async function n(t) {
|
|
7
|
+
return (await e({ deviceIdList: [t] })).devices.find((e) => e.deviceId === t);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { n as getDeviceWithStatus, t as listDevicesWithStatus };
|
|
@@ -2,10 +2,12 @@ import { clawLogger as e } from "../../utils/claw-logger.mjs";
|
|
|
2
2
|
import { buildEndpoint as t } from "../../cloud-channel/protocol/target.mjs";
|
|
3
3
|
import { resolveEnabledYoyoAccountId as n } from "../../modules/configs/channel.mjs";
|
|
4
4
|
import { ClawClient as r } from "../../connection/registry.mjs";
|
|
5
|
+
import { getToolCallContext as i } from "../../messaging/trace/tool-context.mjs";
|
|
6
|
+
import "../../messaging/trace/index.mjs";
|
|
5
7
|
//#region src/capabilities/node/invoke.ts
|
|
6
|
-
var
|
|
7
|
-
async function
|
|
8
|
-
let i = {
|
|
8
|
+
var a = e("capabilities");
|
|
9
|
+
async function o(e) {
|
|
10
|
+
let a = i(e.toolCallId) ?? void 0, o = {
|
|
9
11
|
to: t("node", e.nodeId),
|
|
10
12
|
msgType: "nodeInvokeRequest",
|
|
11
13
|
data: { node: {
|
|
@@ -13,28 +15,31 @@ async function a(e) {
|
|
|
13
15
|
nodeId: e.nodeId,
|
|
14
16
|
name: e.name,
|
|
15
17
|
...e.params ? { params: { arguments: JSON.stringify(e.params) } } : {}
|
|
16
|
-
} }
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
} },
|
|
19
|
+
...a ? { traceInfo: a } : {}
|
|
20
|
+
}, c = n();
|
|
21
|
+
return r.forAccount(c).request(o, {
|
|
19
22
|
timeoutMs: e.timeoutMs,
|
|
20
|
-
matchResult:
|
|
23
|
+
matchResult: s(e.toolCallId)
|
|
21
24
|
});
|
|
22
25
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
matched: !
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
function s(e) {
|
|
27
|
+
return (t) => {
|
|
28
|
+
if (t.payload.msgType !== "nodeInvokeResult") return { matched: !1 };
|
|
29
|
+
let n = t.data?.node;
|
|
30
|
+
return !n || n.toolCallId !== e ? { matched: !1 } : typeof n.runStatus != "number" || !n.nodeId ? (a.warn("nodeInvokeResult missing required fields", { node: n }), {
|
|
31
|
+
matched: !0,
|
|
32
|
+
error: "missing required fields in invoke result"
|
|
33
|
+
}) : {
|
|
34
|
+
matched: !0,
|
|
35
|
+
result: {
|
|
36
|
+
nodeId: n.nodeId,
|
|
37
|
+
toolCallId: e,
|
|
38
|
+
runStatus: n.runStatus,
|
|
39
|
+
result: n.result
|
|
40
|
+
}
|
|
41
|
+
};
|
|
37
42
|
};
|
|
38
43
|
}
|
|
39
44
|
//#endregion
|
|
40
|
-
export {
|
|
45
|
+
export { o as invokeNodeTool };
|
|
@@ -8,32 +8,42 @@ import "../../modules/device/index.mjs";
|
|
|
8
8
|
import "../../honor-auth/vault/index.mjs";
|
|
9
9
|
import "../../apis/index.mjs";
|
|
10
10
|
import { ToolError as o } from "../../tools/error.mjs";
|
|
11
|
+
import { DeviceStatus as s } from "../../types.mjs";
|
|
11
12
|
//#region src/capabilities/node/list.ts
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
var c = t("capabilities");
|
|
14
|
+
function l(e) {
|
|
15
|
+
return {
|
|
16
|
+
deviceId: e.deviceId,
|
|
17
|
+
...e.deviceName ? { deviceName: e.deviceName } : {},
|
|
18
|
+
deviceType: e.deviceType ?? "unknown",
|
|
19
|
+
deviceModel: e.deviceModel ?? "",
|
|
20
|
+
online: e.status === s.Online
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function u(t) {
|
|
24
|
+
let s = await n.fromUser().current();
|
|
25
|
+
if (!s?.token || !s.userId) throw c.error("node device list skipped: no current user"), new o("unauthorized", "missing current user token");
|
|
26
|
+
let u;
|
|
17
27
|
try {
|
|
18
|
-
|
|
28
|
+
u = await a();
|
|
19
29
|
} catch (e) {
|
|
20
|
-
throw
|
|
30
|
+
throw c.error("node device list failed to get device info", e), new o("device_info", "failed to get device info", { cause: e });
|
|
21
31
|
}
|
|
22
32
|
try {
|
|
23
|
-
let e = await i().getDeviceList(
|
|
33
|
+
let e = await i().getDeviceList(u, s, { deviceIdList: t?.deviceIdList });
|
|
24
34
|
if (!r(e)) {
|
|
25
35
|
let t = e.data?.code, n = e.data?.cnMessage;
|
|
26
|
-
throw
|
|
36
|
+
throw c.error("node device list response not ok", null, {
|
|
27
37
|
status: e.status,
|
|
28
38
|
code: t,
|
|
29
39
|
cnMessage: n
|
|
30
40
|
}), new o("api_failed", `code=${t} message=${n}`);
|
|
31
41
|
}
|
|
32
42
|
let n = e.data.data?.deviceList;
|
|
33
|
-
return { devices: Array.isArray(n) ? n : [] };
|
|
43
|
+
return { devices: Array.isArray(n) ? n.map(l) : [] };
|
|
34
44
|
} catch (t) {
|
|
35
|
-
throw t instanceof o ? t : (
|
|
45
|
+
throw t instanceof o ? t : (c.error("node device list failed", t), new o("network_error", e(t), { cause: t }));
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
//#endregion
|
|
39
|
-
export {
|
|
49
|
+
export { u as listNodeDevices };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { clawLogger as e } from "../../utils/claw-logger.mjs";
|
|
2
|
+
import { useAdminCapability as t } from "../admin/impl.mjs";
|
|
3
|
+
import "../admin/index.mjs";
|
|
4
|
+
//#region src/capabilities/routing/restart.ts
|
|
5
|
+
var n = e("routing");
|
|
6
|
+
async function r(e) {
|
|
7
|
+
let r = await t().restart(e);
|
|
8
|
+
return n.info("plugin restart command dispatched", {
|
|
9
|
+
ok: r.ok,
|
|
10
|
+
reason: e
|
|
11
|
+
}), r.ok ? { ok: !0 } : {
|
|
12
|
+
ok: !1,
|
|
13
|
+
error: r.error
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { r as restartGateway };
|
|
@@ -3,13 +3,13 @@ import "../capabilities/node/index.mjs";
|
|
|
3
3
|
//#region src/channel/directory.ts
|
|
4
4
|
async function t(t) {
|
|
5
5
|
try {
|
|
6
|
-
return
|
|
6
|
+
return r((await e()).devices.map((e) => n(e)), t);
|
|
7
7
|
} catch {
|
|
8
8
|
return [];
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
function n(e) {
|
|
12
|
-
let t = e.deviceId
|
|
12
|
+
let t = e.deviceId, n = e.deviceName || t;
|
|
13
13
|
return {
|
|
14
14
|
kind: "user",
|
|
15
15
|
id: `device:${t}`,
|
|
@@ -18,10 +18,7 @@ function n(e) {
|
|
|
18
18
|
raw: { deviceId: t }
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
function r(e) {
|
|
22
|
-
return typeof e.deviceId == "string" && e.deviceId.trim().length > 0;
|
|
23
|
-
}
|
|
24
|
-
function i(e, t) {
|
|
21
|
+
function r(e, t) {
|
|
25
22
|
let n = t.query?.trim().toLowerCase(), r = n ? e.filter((e) => [
|
|
26
23
|
e.id,
|
|
27
24
|
e.name,
|
|
@@ -29,10 +26,10 @@ function i(e, t) {
|
|
|
29
26
|
].filter((e) => typeof e == "string").some((e) => e.toLowerCase().includes(n))) : e;
|
|
30
27
|
return typeof t.limit == "number" && t.limit >= 0 ? r.slice(0, t.limit) : r;
|
|
31
28
|
}
|
|
32
|
-
var
|
|
29
|
+
var i = {
|
|
33
30
|
self: async () => null,
|
|
34
31
|
listPeers: async (e) => t(e),
|
|
35
32
|
listGroups: async () => []
|
|
36
33
|
};
|
|
37
34
|
//#endregion
|
|
38
|
-
export {
|
|
35
|
+
export { i as yoyoDirectory };
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { YOYO_CHANNEL_ID as e } from "../consts.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { buildChatId as t, looksLikeChatId as n } from "../messaging/target/chat-id.mjs";
|
|
3
|
+
import { buildChatTo as r, buildFrom as i, readChatIdFromTo as a, readDeviceIdFromTo as o } from "../messaging/target/address.mjs";
|
|
4
4
|
import { resolveOutboundTarget as s } from "../messaging/target/outbound.mjs";
|
|
5
5
|
import { buildChannelOutboundSessionRoute as c, stripChannelTargetPrefix as l } from "openclaw/plugin-sdk/channel-core";
|
|
6
6
|
//#region src/channel/messaging.ts
|
|
7
7
|
function u(t) {
|
|
8
8
|
let n = l(t, e).trim();
|
|
9
|
-
return d(
|
|
9
|
+
return d(n) ? n : void 0;
|
|
10
10
|
}
|
|
11
|
-
function d(e
|
|
12
|
-
let
|
|
13
|
-
if (
|
|
14
|
-
let
|
|
15
|
-
return
|
|
11
|
+
function d(e) {
|
|
12
|
+
let t = a(e);
|
|
13
|
+
if (t !== void 0) return t.length > 0 && n(t);
|
|
14
|
+
let r = o(e);
|
|
15
|
+
return r !== void 0 && r.length > 0;
|
|
16
16
|
}
|
|
17
|
-
async function f(
|
|
18
|
-
let s = await a
|
|
17
|
+
async function f(n, a, o) {
|
|
18
|
+
let s = await t(a, o);
|
|
19
19
|
return c({
|
|
20
|
-
cfg:
|
|
21
|
-
agentId:
|
|
20
|
+
cfg: n.cfg,
|
|
21
|
+
agentId: n.agentId,
|
|
22
22
|
channel: e,
|
|
23
|
-
accountId:
|
|
23
|
+
accountId: a,
|
|
24
24
|
peer: {
|
|
25
25
|
kind: "direct",
|
|
26
26
|
id: s
|
|
27
27
|
},
|
|
28
28
|
chatType: "direct",
|
|
29
|
-
from:
|
|
30
|
-
to:
|
|
29
|
+
from: i(s),
|
|
30
|
+
to: r(s)
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
async function p(e) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toErrorMessage as e } from "../../utils/error.mjs";
|
|
2
2
|
import { cleanDeviceToolSetArtifacts as t } from "../../provisioning/toolset/cleanup.mjs";
|
|
3
3
|
import "../../provisioning/toolset/index.mjs";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/cli/debug/clean-tools.ts
|
|
5
5
|
function n(n) {
|
|
6
6
|
n.command("clean-tools").description("Wipe cached device toolset data (tools archive, device-toolsets.json, toolset-md5.json) and restore SKILL.md placeholder").action(async () => {
|
|
7
7
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { withCommandRuntime as e } from "../../core/runtime.mjs";
|
|
2
2
|
import { getEnvAndGray as t, resetEnv as n, updateEnv as r, updateGrayTag as i } from "../../modules/configs/plugin.mjs";
|
|
3
3
|
import "../../modules/configs/index.mjs";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/cli/env/impl.ts
|
|
5
5
|
var a = {
|
|
6
6
|
env: "environment variable",
|
|
7
7
|
manual: "manual config"
|
|
@@ -7,13 +7,12 @@ import { registerLoginCommand as r } from "./login/impl.mjs";
|
|
|
7
7
|
import "./login/index.mjs";
|
|
8
8
|
import { registerLogoutCommand as i } from "./logout/impl.mjs";
|
|
9
9
|
import "./logout/index.mjs";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
r(o, c), a(o, c), i(o, c), t(o, c), e() && n(o, c);
|
|
10
|
+
//#region src/cli/index.ts
|
|
11
|
+
function a(a) {
|
|
12
|
+
a.registerCli((o) => {
|
|
13
|
+
let s = o.program.command("honor").description("Commands for Honor yoyoclaw");
|
|
14
|
+
r(a, s), i(a, s), e() && (n(a, s), t(a, s));
|
|
16
15
|
}, { commands: ["honor"] });
|
|
17
16
|
}
|
|
18
17
|
//#endregion
|
|
19
|
-
export {
|
|
18
|
+
export { a as registerCliCommands };
|
|
@@ -5,10 +5,10 @@ import { patchYoyoChannelConfig as i, resolveEnabledYoyoAccountId as a, setAllYo
|
|
|
5
5
|
import "../../modules/configs/index.mjs";
|
|
6
6
|
import { performLogin as c } from "../../honor-auth/login/impl.mjs";
|
|
7
7
|
import "../../honor-auth/index.mjs";
|
|
8
|
-
//#region src/
|
|
8
|
+
//#region src/cli/login/impl.ts
|
|
9
9
|
var l = t("login-cli");
|
|
10
10
|
function u(t, u) {
|
|
11
|
-
u.command("login").description("login to
|
|
11
|
+
u.command("login").description("login to Honor and register devices").option("-u, --uid <userId>", "login with a specific user ID").option("--token <token>", "login with a specific token").action(async (u) => e(t.runtime, async () => {
|
|
12
12
|
let { token: e } = u;
|
|
13
13
|
l.debug("login CLI command called");
|
|
14
14
|
let t = a(), d = await c({ token: e });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { withCommandRuntime as e } from "../../core/runtime.mjs";
|
|
2
|
+
import { toErrorMessage as t } from "../../utils/error.mjs";
|
|
3
|
+
import { clawLogger as n } from "../../utils/claw-logger.mjs";
|
|
4
|
+
import { loadConfig as r, saveConfig as i } from "../../modules/configs/config-store.mjs";
|
|
5
|
+
import { removeYoyoChannelAccount as a, resolveEnabledYoyoAccountId as o } from "../../modules/configs/channel.mjs";
|
|
6
|
+
import "../../modules/configs/index.mjs";
|
|
7
|
+
import { performLogout as s } from "../../honor-auth/logout.mjs";
|
|
8
|
+
//#region src/cli/logout/impl.ts
|
|
9
|
+
var c = n("logout-cli");
|
|
10
|
+
function l(n, l) {
|
|
11
|
+
l.command("logout").description("Logout and clear user configuration").action(async () => e(n.runtime, async () => {
|
|
12
|
+
c.info("logout CLI command called");
|
|
13
|
+
let e = o();
|
|
14
|
+
try {
|
|
15
|
+
await s(e);
|
|
16
|
+
try {
|
|
17
|
+
await i(a(r(), e));
|
|
18
|
+
} catch (t) {
|
|
19
|
+
c.error("failed to remove channel account after logout", t, { userId: e });
|
|
20
|
+
}
|
|
21
|
+
console.log("✅ Logout successful, gateway will automatically stop the account connection");
|
|
22
|
+
} catch (e) {
|
|
23
|
+
let n = t(e);
|
|
24
|
+
console.error("🚫 Logout failed:", n);
|
|
25
|
+
}
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { l as registerLogoutCommand };
|
|
@@ -34,14 +34,14 @@ var r = e("cloud-auth"), i = class {
|
|
|
34
34
|
}
|
|
35
35
|
async applyNewToken(e) {
|
|
36
36
|
let t = e?.accessToken;
|
|
37
|
-
if (typeof t != "string" ||
|
|
37
|
+
if (typeof t != "string" || t.length === 0) return r.warn("updateAuthorization missing valid access token"), !1;
|
|
38
38
|
try {
|
|
39
|
-
let n = Date.now(), i =
|
|
40
|
-
accessToken:
|
|
39
|
+
let n = Date.now(), i = await this.account.update({
|
|
40
|
+
accessToken: t,
|
|
41
41
|
expire: e?.expire,
|
|
42
42
|
grantedAt: n
|
|
43
43
|
});
|
|
44
|
-
return r.info("cached new token to vault", { accountKey:
|
|
44
|
+
return r.info("cached new token to vault", { accountKey: i.userId }), !0;
|
|
45
45
|
} catch (e) {
|
|
46
46
|
return r.error("failed to cache new token", e), !1;
|
|
47
47
|
}
|
|
@@ -21,13 +21,10 @@ function s(e) {
|
|
|
21
21
|
send: u,
|
|
22
22
|
async request(e, t) {
|
|
23
23
|
let { matchResult: r, timeoutMs: i } = t, s = n();
|
|
24
|
-
if (!await u(
|
|
25
|
-
...e,
|
|
26
|
-
traceInfo: { traceId: s }
|
|
27
|
-
})) throw Error("send failed");
|
|
24
|
+
if (!await u(e)) throw Error("send failed");
|
|
28
25
|
return new Promise((e, t) => {
|
|
29
26
|
let n = setTimeout(() => {
|
|
30
|
-
l.has(s) && (l.delete(s), o.warn("request timeout", {
|
|
27
|
+
l.has(s) && (l.delete(s), o.warn("request timeout", { requestId: s }), t(/* @__PURE__ */ Error("request timeout")));
|
|
31
28
|
}, a(i));
|
|
32
29
|
l.set(s, {
|
|
33
30
|
timeout: n,
|
|
@@ -38,25 +35,22 @@ function s(e) {
|
|
|
38
35
|
});
|
|
39
36
|
},
|
|
40
37
|
consume(e) {
|
|
41
|
-
let t
|
|
42
|
-
|
|
43
|
-
let n = l.get(t);
|
|
44
|
-
if (n) {
|
|
38
|
+
for (let [t, n] of l) {
|
|
39
|
+
let r;
|
|
45
40
|
try {
|
|
46
|
-
|
|
47
|
-
if (r.matched) {
|
|
48
|
-
if (l.delete(t), clearTimeout(n.timeout), "error" in r) {
|
|
49
|
-
n.reject(r.error);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
n.resolve(r.result);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
41
|
+
r = n.matchResult(e);
|
|
55
42
|
} catch (e) {
|
|
56
43
|
o.error("match request result failed", e);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (r?.matched) {
|
|
47
|
+
if (l.delete(t), clearTimeout(n.timeout), "error" in r) {
|
|
48
|
+
n.reject(r.error);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
n.resolve(r.result);
|
|
57
52
|
return;
|
|
58
53
|
}
|
|
59
|
-
o.warn("response shape not matched, keep pending", { traceId: t });
|
|
60
54
|
}
|
|
61
55
|
},
|
|
62
56
|
destroy() {
|