@honor-claw/yoyo 1.4.0-beta.7 → 1.4.0-beta.9
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/modules/device-toolset/archive.mjs +35 -24
- package/dist/modules/device-toolset/processor.mjs +33 -33
- package/dist/modules/device-toolset/skill-inject.mjs +31 -33
- package/dist/modules/device-toolset/skill-refresh-marker.mjs +26 -28
- package/dist/utils/error.mjs +7 -1
- package/dist/utils/fs-safe.mjs +105 -107
- package/dist/utils/version.mjs +1 -1
- package/package.json +1 -1
- package/skills/yoyo-control/SKILL.md +1 -6
- package/skills/yoyo-control/configs/sub-skills.json +8 -1
- package/skills/yoyo-control/references/gui-task-create.md +0 -222
- package/skills/yoyo-control/references/gui-task-pause.md +0 -188
- package/skills/yoyo-control/references/gui-task-terminate.md +0 -192
|
@@ -1,39 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import r from "
|
|
1
|
+
import { hasNodeErrorCode as e } from "../../utils/error.mjs";
|
|
2
|
+
import { safeWriteFile as t } from "../../utils/fs-safe.mjs";
|
|
3
|
+
import { INVALID_TOOL_FILENAME_CHAR_PATTERN as n, TOOL_ARCHIVE_DIR as r } from "./consts.mjs";
|
|
4
|
+
import i from "node:path";
|
|
5
|
+
import a from "node:fs/promises";
|
|
4
6
|
//#region src/modules/device-toolset/archive.ts
|
|
5
|
-
async function
|
|
6
|
-
let
|
|
7
|
-
for (let
|
|
8
|
-
let
|
|
9
|
-
if (!
|
|
10
|
-
|
|
7
|
+
async function o(e, n) {
|
|
8
|
+
let a = 0, o = 0, u = await c(e);
|
|
9
|
+
for (let s of n) {
|
|
10
|
+
let n = l(s.name);
|
|
11
|
+
if (!n) {
|
|
12
|
+
o += 1;
|
|
11
13
|
continue;
|
|
12
14
|
}
|
|
13
|
-
await
|
|
14
|
-
rootDir:
|
|
15
|
-
relativePath:
|
|
16
|
-
data: JSON.stringify(
|
|
15
|
+
await t({
|
|
16
|
+
rootDir: e,
|
|
17
|
+
relativePath: i.join(r, n),
|
|
18
|
+
data: JSON.stringify(s, null, 2),
|
|
17
19
|
encoding: "utf8",
|
|
18
20
|
mkdir: !0
|
|
19
|
-
}),
|
|
21
|
+
}), a += 1;
|
|
20
22
|
}
|
|
21
23
|
return {
|
|
22
|
-
archiveDir:
|
|
23
|
-
writtenCount:
|
|
24
|
-
skippedCount:
|
|
24
|
+
archiveDir: s(e),
|
|
25
|
+
writtenCount: a,
|
|
26
|
+
skippedCount: o,
|
|
27
|
+
createdArchiveDir: !u && a > 0
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
|
-
function
|
|
28
|
-
return
|
|
30
|
+
function s(e) {
|
|
31
|
+
return i.join(e, r);
|
|
32
|
+
}
|
|
33
|
+
async function c(t) {
|
|
34
|
+
try {
|
|
35
|
+
return (await a.stat(s(t))).isDirectory();
|
|
36
|
+
} catch (t) {
|
|
37
|
+
if (e(t, "ENOENT", "ENOTDIR")) return !1;
|
|
38
|
+
throw t;
|
|
39
|
+
}
|
|
29
40
|
}
|
|
30
|
-
function
|
|
31
|
-
let
|
|
32
|
-
if (!(!
|
|
41
|
+
function l(e) {
|
|
42
|
+
let t = e.trim();
|
|
43
|
+
if (!(!t || n.test(t) || u(t))) return `${t}.json`;
|
|
33
44
|
}
|
|
34
|
-
function
|
|
45
|
+
function u(e) {
|
|
35
46
|
for (let t of e) if (t.codePointAt(0) < 32) return !0;
|
|
36
47
|
return !1;
|
|
37
48
|
}
|
|
38
49
|
//#endregion
|
|
39
|
-
export {
|
|
50
|
+
export { o as refreshToolArchive, s as resolveToolArchiveDir };
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
import { useClawLogger as e } from "../../utils/logger.mjs";
|
|
2
2
|
import { resolveEffectiveHomeDir as t, resolveExtensionRoot as n } from "../../utils/home-dir.mjs";
|
|
3
|
-
import { clearYoyoControlSkillReadMarker as r } from "./skill-refresh-marker.mjs";
|
|
4
|
-
import { refreshToolArchive as
|
|
5
|
-
import { ensureMcpToolsMapping as
|
|
6
|
-
import { mergeDeviceToolSetCache as
|
|
7
|
-
import { refreshYoyoControlSkill as
|
|
8
|
-
import { ensureDeviceToolSetArtifacts as
|
|
9
|
-
import { computeDeviceToolSetMd5 as
|
|
10
|
-
import { assertDeviceToolSetPayload as
|
|
3
|
+
import { clearYoyoControlSkillReadMarker as r, markYoyoControlSkillRead as i } from "./skill-refresh-marker.mjs";
|
|
4
|
+
import { refreshToolArchive as a } from "./archive.mjs";
|
|
5
|
+
import { ensureMcpToolsMapping as o, resolveMcpToolsTargetDir as s } from "./link.mjs";
|
|
6
|
+
import { mergeDeviceToolSetCache as c } from "./persist.mjs";
|
|
7
|
+
import { refreshYoyoControlSkill as l } from "./skill-inject.mjs";
|
|
8
|
+
import { ensureDeviceToolSetArtifacts as u } from "./artifacts.mjs";
|
|
9
|
+
import { computeDeviceToolSetMd5 as d, getDeviceToolSetChangeState as f, writeToolSetMd5Entry as p } from "./md5-index.mjs";
|
|
10
|
+
import { assertDeviceToolSetPayload as m, normalizeDeviceToolSet as h } from "./normalize.mjs";
|
|
11
11
|
//#region src/modules/device-toolset/processor.ts
|
|
12
|
-
var
|
|
13
|
-
async function
|
|
14
|
-
let
|
|
15
|
-
if (!
|
|
16
|
-
let
|
|
17
|
-
e().info(`[yoyoclaw-device-toolset] process start, nodeId: ${
|
|
18
|
-
let
|
|
19
|
-
if (e().debug?.(`[yoyoclaw-device-toolset] computed md5, nodeId: ${
|
|
20
|
-
let t = await
|
|
21
|
-
return e().info(`[yoyoclaw-device-toolset] unchanged, skip refresh, nodeId: ${
|
|
12
|
+
var g = n();
|
|
13
|
+
async function _(n) {
|
|
14
|
+
let _ = m(n), v = t();
|
|
15
|
+
if (!v) throw Error("Unable to resolve home directory for DeviceToolSet persistence");
|
|
16
|
+
let y = h(_);
|
|
17
|
+
e().info(`[yoyoclaw-device-toolset] process start, nodeId: ${y.nodeId}, tools: ${y.tools.length}, skipped: ${y.skippedCount}`);
|
|
18
|
+
let b = d(y.tools);
|
|
19
|
+
if (e().debug?.(`[yoyoclaw-device-toolset] computed md5, nodeId: ${y.nodeId}, md5: ${b}`), !(await f(v, y.nodeId, b)).changed) {
|
|
20
|
+
let t = await u(v, g);
|
|
21
|
+
return e().info(`[yoyoclaw-device-toolset] unchanged, skip refresh, nodeId: ${y.nodeId}, artifactsRestored: ${t.restored}`), {
|
|
22
22
|
changed: !1,
|
|
23
|
-
nodeId:
|
|
24
|
-
skippedCount:
|
|
23
|
+
nodeId: y.nodeId,
|
|
24
|
+
skippedCount: y.skippedCount
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
let
|
|
28
|
-
e().info(`[yoyoclaw-device-toolset] cache merged, nodeId: ${
|
|
29
|
-
let
|
|
30
|
-
e().info(`[yoyoclaw-device-toolset] archive refreshed, nodeId: ${
|
|
31
|
-
let
|
|
32
|
-
e().info(`[yoyoclaw-device-toolset] skill refreshed, nodeId: ${
|
|
33
|
-
let
|
|
34
|
-
return e().info(`[yoyoclaw-device-toolset] mapping ready, nodeId: ${
|
|
27
|
+
let x = await c(v, y.nodeId, y.tools);
|
|
28
|
+
e().info(`[yoyoclaw-device-toolset] cache merged, nodeId: ${y.nodeId}, supportedNodes: ${x.nodeCount}, tools: ${x.toolCount}`);
|
|
29
|
+
let S = x.cache.tools, C = await a(v, y.tools);
|
|
30
|
+
e().info(`[yoyoclaw-device-toolset] archive refreshed, nodeId: ${y.nodeId}, written: ${C.writtenCount}, skipped: ${C.skippedCount}, createdArchiveDir: ${C.createdArchiveDir}`);
|
|
31
|
+
let w = await l(g, S);
|
|
32
|
+
e().info(`[yoyoclaw-device-toolset] skill refreshed, nodeId: ${y.nodeId}, rows: ${w.rowCount}, updated: ${w.updated}`), C.createdArchiveDir ? await i(g, "clean_install") : w.updated && await r(g, y.nodeId);
|
|
33
|
+
let T = await o(C.archiveDir, s(g));
|
|
34
|
+
return e().info(`[yoyoclaw-device-toolset] mapping ready, nodeId: ${y.nodeId}, mode: ${T.mode}`), await p(v, y.nodeId, b, Date.now()), e().info(`[yoyoclaw-device-toolset] process complete, nodeId: ${y.nodeId}`), {
|
|
35
35
|
changed: !0,
|
|
36
|
-
nodeId:
|
|
37
|
-
nodeCount:
|
|
38
|
-
toolCount:
|
|
39
|
-
skippedCount:
|
|
36
|
+
nodeId: y.nodeId,
|
|
37
|
+
nodeCount: x.nodeCount,
|
|
38
|
+
toolCount: x.toolCount,
|
|
39
|
+
skippedCount: y.skippedCount
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
43
|
-
export {
|
|
43
|
+
export { _ as processDeviceToolSet };
|
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import a from "
|
|
3
|
-
import o from "node:
|
|
1
|
+
import { hasNodeErrorCode as e } from "../../utils/error.mjs";
|
|
2
|
+
import { MCP_TOOLS_END_MARKER as t, MCP_TOOLS_PLACEHOLDER as n, MCP_TOOLS_START_MARKER as r, YOYO_CONTROL_SKILL_RELATIVE_PATH as i, YOYO_CONTROL_SUB_SKILLS_RELATIVE_PATH as a } from "./consts.mjs";
|
|
3
|
+
import o from "node:path";
|
|
4
|
+
import s from "node:fs/promises";
|
|
4
5
|
//#region src/modules/device-toolset/skill-inject.ts
|
|
5
|
-
async function
|
|
6
|
-
let n =
|
|
7
|
-
return
|
|
6
|
+
async function c(e, t) {
|
|
7
|
+
let n = o.join(e, i), r = await s.readFile(n, "utf8"), a = u(t, await l(e)), c = p(r, d(a));
|
|
8
|
+
return c !== r && await s.writeFile(n, c, "utf8"), {
|
|
8
9
|
skillPath: n,
|
|
9
|
-
rowCount:
|
|
10
|
-
updated:
|
|
10
|
+
rowCount: f(a).length,
|
|
11
|
+
updated: c !== r
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
async function
|
|
14
|
-
let
|
|
14
|
+
async function l(t) {
|
|
15
|
+
let n = o.join(t, a), r;
|
|
15
16
|
try {
|
|
16
|
-
|
|
17
|
-
} catch (
|
|
18
|
-
if (
|
|
19
|
-
throw
|
|
17
|
+
r = await s.readFile(n, "utf8");
|
|
18
|
+
} catch (t) {
|
|
19
|
+
if (e(t, "ENOENT")) return /* @__PURE__ */ new Set();
|
|
20
|
+
throw t;
|
|
20
21
|
}
|
|
21
|
-
let
|
|
22
|
-
if (!Array.isArray(
|
|
23
|
-
return new Set(
|
|
22
|
+
let i = JSON.parse(r);
|
|
23
|
+
if (!Array.isArray(i) || i.some((e) => typeof e != "string")) throw Error("sub-skills config must be a JSON array of tool names");
|
|
24
|
+
return new Set(i.map((e) => e.trim()).filter(Boolean));
|
|
24
25
|
}
|
|
25
|
-
function
|
|
26
|
+
function u(e, t) {
|
|
26
27
|
return t.size === 0 ? e : Object.fromEntries(Object.entries(e).filter(([e, n]) => !t.has(e) && !t.has(n.name)));
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
+
function d(e) {
|
|
29
30
|
return [
|
|
30
|
-
|
|
31
|
-
...
|
|
32
|
-
|
|
31
|
+
r,
|
|
32
|
+
...f(e).map((e) => `| ${m(e.name)} | ${m(e.description)} | ${m(e.nodeId)} |`),
|
|
33
|
+
t
|
|
33
34
|
].join("\n");
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
+
function f(e) {
|
|
36
37
|
return Object.values(e).flatMap((e) => e.supportedNodeIds.map((t) => ({
|
|
37
38
|
name: e.name,
|
|
38
39
|
description: e.description,
|
|
@@ -42,20 +43,17 @@ function d(e) {
|
|
|
42
43
|
return n === 0 ? e.nodeId.localeCompare(t.nodeId) : n;
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
|
-
function
|
|
46
|
-
let a = RegExp(`${
|
|
47
|
-
if (a.test(
|
|
48
|
-
if (
|
|
46
|
+
function p(e, i) {
|
|
47
|
+
let a = RegExp(`${h(r)}[\\s\\S]*?${h(t)}`);
|
|
48
|
+
if (a.test(e)) return e.replace(a, i);
|
|
49
|
+
if (e.includes("{{full-mcp-tool-list}}")) return e.replace(n, i);
|
|
49
50
|
throw Error("Unable to find MCP tools placeholder or generated block in yoyo-control skill");
|
|
50
51
|
}
|
|
51
|
-
function p(e) {
|
|
52
|
-
return e.replaceAll("|", "\\|").replace(/\r?\n/g, " ");
|
|
53
|
-
}
|
|
54
52
|
function m(e) {
|
|
55
|
-
return e.replace(/
|
|
53
|
+
return e.replaceAll("|", "\\|").replace(/\r?\n/g, " ");
|
|
56
54
|
}
|
|
57
55
|
function h(e) {
|
|
58
|
-
return e
|
|
56
|
+
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
59
57
|
}
|
|
60
58
|
//#endregion
|
|
61
|
-
export {
|
|
59
|
+
export { c as refreshYoyoControlSkill };
|
|
@@ -1,44 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import n from "
|
|
4
|
-
import r from "node:
|
|
1
|
+
import { hasNodeErrorCode as e } from "../../utils/error.mjs";
|
|
2
|
+
import { useClawLogger as t } from "../../utils/logger.mjs";
|
|
3
|
+
import { YOYO_CONTROL_SKILL_READ_MARKER_RELATIVE_PATH as n } from "./consts.mjs";
|
|
4
|
+
import r from "node:path";
|
|
5
|
+
import i from "node:fs/promises";
|
|
5
6
|
//#region src/modules/device-toolset/skill-refresh-marker.ts
|
|
6
|
-
var
|
|
7
|
-
function
|
|
8
|
-
return typeof e == "string" &&
|
|
7
|
+
var a = /(?:^|[\\/])skills[\\/]yoyo-control[\\/]SKILL\.md$/i, o, s = "## Mandatory yoyo_phone_control skill refresh\n\nThis is a one-shot instruction for the same user message that contains this notice.\n\nThe yoyo_phone_control skill may have changed after your cached context was built. Your next tool call MUST read exactly skills/yoyo-control/SKILL.md, even if the current user message does not involve phone control.\n\n1. Until that read succeeds, DO NOT read skills/yoyo-control/references/*, read skills/yoyo-control/mcptools/*, run openclaw commands, or invoke any phone-control action.\n2. Ignore all previously cached yoyo_phone_control instructions, tool tables, reference paths, command formats, and parameter schemas. They are stale even if they look relevant.\n3. After reading SKILL.md, use only the freshly read workflow to decide whether any yoyo_phone_control follow-up is needed. If the user message is unrelated to phone control, continue answering normally without performing phone-control actions.\n\nThis instruction expires as soon as you either successfully read skills/yoyo-control/SKILL.md or finish responding to that same user message. If you see this notice only in conversation history, and it is not included in the latest user message you are answering, ignore it and do not re-read SKILL.md because of this old notice.\n\nThinking or saying that you should re-read the skill is not enough while this one-shot instruction is active; the first tool call after the active notice must be the SKILL.md read.";
|
|
8
|
+
function c(e) {
|
|
9
|
+
return typeof e == "string" && a.test(e);
|
|
9
10
|
}
|
|
10
|
-
async function
|
|
11
|
-
if (
|
|
12
|
-
try {
|
|
13
|
-
await
|
|
14
|
-
} catch (
|
|
15
|
-
if (
|
|
16
|
-
else throw
|
|
11
|
+
async function l(n) {
|
|
12
|
+
if (o === !0) return t().debug?.(`[yoyoclaw-skill-refresh] skill marker state resolved from memory, exists: ${o}`), !1;
|
|
13
|
+
if (o === void 0) try {
|
|
14
|
+
return await i.access(f(n)), o = !0, t().debug?.("[yoyoclaw-skill-refresh] skill marker state resolved from file, exists: true"), !1;
|
|
15
|
+
} catch (n) {
|
|
16
|
+
if (e(n, "ENOENT")) o = !1, t().debug?.("[yoyoclaw-skill-refresh] skill marker state resolved from file, exists: false");
|
|
17
|
+
else throw n;
|
|
17
18
|
}
|
|
18
|
-
return !
|
|
19
|
+
return t().debug?.("[yoyoclaw-skill-refresh] skill marker missing; refresh prompt required"), !0;
|
|
19
20
|
}
|
|
20
|
-
async function
|
|
21
|
-
let
|
|
21
|
+
async function u(e, t) {
|
|
22
|
+
let n = f(e), a = {
|
|
22
23
|
updateTime: Date.now(),
|
|
23
24
|
triggerReason: t
|
|
24
25
|
};
|
|
25
|
-
await
|
|
26
|
+
await i.mkdir(r.dirname(n), { recursive: !0 }), await i.writeFile(n, JSON.stringify(a, null, 2), "utf8"), o = !0;
|
|
26
27
|
}
|
|
27
|
-
async function
|
|
28
|
+
async function d(e, n) {
|
|
28
29
|
try {
|
|
29
|
-
await
|
|
30
|
-
} catch (
|
|
31
|
-
|
|
30
|
+
await i.rm(f(e), { force: !0 }), o = !1, t().info(`[yoyoclaw-skill-refresh] skill read marker cleared${p(n)}`);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
t().warn(`[yoyoclaw-skill-refresh] failed to clear skill read marker${p(n)}, error: ${String(e)}`);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
function d(e) {
|
|
35
|
-
return n.join(e, t);
|
|
36
|
-
}
|
|
37
35
|
function f(e) {
|
|
38
|
-
return e
|
|
36
|
+
return r.join(e, n);
|
|
39
37
|
}
|
|
40
38
|
function p(e) {
|
|
41
|
-
return e
|
|
39
|
+
return e ? `, nodeId: ${e}` : "";
|
|
42
40
|
}
|
|
43
41
|
//#endregion
|
|
44
|
-
export {
|
|
42
|
+
export { s as YOYO_CONTROL_SKILL_REFRESH_PROMPT, d as clearYoyoControlSkillReadMarker, c as isYoyoControlSkillReadPath, u as markYoyoControlSkillRead, l as shouldRefreshYoyoControlSkillPrompt };
|
package/dist/utils/error.mjs
CHANGED
|
@@ -3,5 +3,11 @@ function e(e, t) {
|
|
|
3
3
|
let n = e instanceof Error ? e.message : String(e);
|
|
4
4
|
return Error(`${t}: ${n}`, { cause: e });
|
|
5
5
|
}
|
|
6
|
+
function t(e) {
|
|
7
|
+
return e instanceof Error && "code" in e;
|
|
8
|
+
}
|
|
9
|
+
function n(e, ...n) {
|
|
10
|
+
return t(e) && typeof e.code == "string" && n.includes(e.code);
|
|
11
|
+
}
|
|
6
12
|
//#endregion
|
|
7
|
-
export { e as wrapError };
|
|
13
|
+
export { n as hasNodeErrorCode, t as isNodeError, e as wrapError };
|