@senpi/runtime 1.1.0-dev.runtime-phase-2.20260512102629 → 1.1.0-dev.runtime-phase-2.20260513122539
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/cli/senpi-commands.d.ts.map +1 -1
- package/dist/cli/senpi-commands.js +93 -0
- package/dist/cli/senpi-commands.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -1
- package/dist/skills-manager/bootstrap.d.ts +26 -0
- package/dist/skills-manager/bootstrap.d.ts.map +1 -0
- package/dist/skills-manager/bootstrap.js +68 -0
- package/dist/skills-manager/bootstrap.js.map +1 -0
- package/dist/skills-manager/constants.d.ts +12 -0
- package/dist/skills-manager/constants.d.ts.map +1 -0
- package/dist/skills-manager/constants.js +15 -0
- package/dist/skills-manager/constants.js.map +1 -0
- package/dist/skills-manager/coordinator.d.ts +209 -0
- package/dist/skills-manager/coordinator.d.ts.map +1 -0
- package/dist/skills-manager/coordinator.js +757 -0
- package/dist/skills-manager/coordinator.js.map +1 -0
- package/dist/skills-manager/fetcher.d.ts +28 -0
- package/dist/skills-manager/fetcher.d.ts.map +1 -0
- package/dist/skills-manager/fetcher.js +92 -0
- package/dist/skills-manager/fetcher.js.map +1 -0
- package/dist/skills-manager/index.d.ts +5 -0
- package/dist/skills-manager/index.d.ts.map +1 -0
- package/dist/skills-manager/index.js +4 -0
- package/dist/skills-manager/index.js.map +1 -0
- package/dist/skills-manager/state-store.d.ts +34 -0
- package/dist/skills-manager/state-store.d.ts.map +1 -0
- package/dist/skills-manager/state-store.js +103 -0
- package/dist/skills-manager/state-store.js.map +1 -0
- package/dist/skills-manager/types.d.ts +127 -0
- package/dist/skills-manager/types.d.ts.map +1 -0
- package/dist/skills-manager/types.js +2 -0
- package/dist/skills-manager/types.js.map +1 -0
- package/dist/skills-manager/utils.d.ts +46 -0
- package/dist/skills-manager/utils.d.ts.map +1 -0
- package/dist/skills-manager/utils.js +87 -0
- package/dist/skills-manager/utils.js.map +1 -0
- package/dist/skills-manager/version-manager.d.ts +61 -0
- package/dist/skills-manager/version-manager.d.ts.map +1 -0
- package/dist/skills-manager/version-manager.js +142 -0
- package/dist/skills-manager/version-manager.js.map +1 -0
- package/dist/skills-manager/writer.d.ts +28 -0
- package/dist/skills-manager/writer.d.ts.map +1 -0
- package/dist/skills-manager/writer.js +101 -0
- package/dist/skills-manager/writer.js.map +1 -0
- package/openclaw.plugin.json +29 -0
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/skills-manager/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAQpD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB,CAAC,uBAAuB,CAAC,CAAC;AAEnF;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAAqC;IAErC,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE,CAAC;IACxB,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;QAClC,SAAS,EAAE,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACtE,CAAC,CAAC,GAAG,CAAC,SAAS;YACf,CAAC,CAAC,kBAAkB;QACtB,mBAAmB,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC;QAC7E,4DAA4D;QAC5D,sEAAsE;QACtE,uEAAuE;QACvE,6BAA6B;QAC7B,oEAAoE;QACpE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAC/B,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YACjE,CAAC,CAAC,CAAC,GAAG,sBAAsB,CAAC;KAChC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,+BAA+B;IAC7C,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO;QACL,IAAI;QACJ,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,IAAI;QACnB,kBAAkB,EAAE,IAAI;QACxB,wBAAwB,EAAE,IAAI;QAC9B,mBAAmB,EAAE,CAAC;QACtB,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,IAAI;KACxB,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,MAAM,CAAC,KAAc,EAAE,QAAiB;IAC/C,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc,EAAE,QAAgB;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAChF,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW;IAChD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version detection for Senpi skills.
|
|
3
|
+
*
|
|
4
|
+
* Reads the installed SKILL.md version from disk and the remote version from
|
|
5
|
+
* raw.githubusercontent.com, then uses the existing semver helpers from
|
|
6
|
+
* src/runtime/auto-update/policy.ts to classify the delta.
|
|
7
|
+
*/
|
|
8
|
+
import type { LoggerLike, SkillVersionInfo } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Normalise a version string before passing it to parseSemver / classifyUpdate.
|
|
11
|
+
*
|
|
12
|
+
* Accepts two-part versions used in production skills (e.g. "1.0", "v2.3")
|
|
13
|
+
* and expands them to the full three-part form ("1.0.0", "v2.3.0") that
|
|
14
|
+
* parseSemver requires. All other strings are returned unchanged.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeVersion(v: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Extract the `version` value from a SKILL.md YAML frontmatter block.
|
|
19
|
+
*
|
|
20
|
+
* Handles both nested form:
|
|
21
|
+
* metadata:
|
|
22
|
+
* version: 1.2.3
|
|
23
|
+
* and flat form:
|
|
24
|
+
* version: "1.2.3"
|
|
25
|
+
*
|
|
26
|
+
* Returns null when the frontmatter block is absent or the field is missing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseSkillMdVersion(content: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Read the installed version for a skill from its local SKILL.md.
|
|
31
|
+
* Returns null when the file is absent or the version field is missing.
|
|
32
|
+
* Logs a warning for unexpected errors (anything other than ENOENT).
|
|
33
|
+
*/
|
|
34
|
+
export declare function readLocalVersion(skillsDir: string, skillName: string, logger?: LoggerLike): Promise<string | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Fetch the remote SKILL.md for a skill and return its version.
|
|
37
|
+
*
|
|
38
|
+
* Returns null when the skill does not exist in the remote repo (HTTP 404) —
|
|
39
|
+
* that's a legitimate state ("skill removed or not yet published"), not an
|
|
40
|
+
* error, so it should not pollute failure counters.
|
|
41
|
+
*
|
|
42
|
+
* Throws on transient/operational failures (network errors, timeouts, 5xx
|
|
43
|
+
* responses, body-parse failures) so the caller's failure-recording path can
|
|
44
|
+
* fire.
|
|
45
|
+
*
|
|
46
|
+
* @param fetchImpl Injectable for unit testing — defaults to global `fetch`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function fetchRemoteVersion(skillName: string, rawBaseUrl?: string, fetchImpl?: typeof fetch): Promise<string | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Compare the local and remote versions for a skill and return a classified diff.
|
|
51
|
+
*
|
|
52
|
+
* Special cases:
|
|
53
|
+
* - Local version is null (skill predates versioning) + valid remote → "minor"
|
|
54
|
+
* so the update is auto-applied without manual major-version approval.
|
|
55
|
+
* - Local version exists but is not valid semver (e.g. "latest") → "unknown",
|
|
56
|
+
* skip safely.
|
|
57
|
+
* - Remote version is absent or unparseable → "unknown", caller should log and
|
|
58
|
+
* skip.
|
|
59
|
+
*/
|
|
60
|
+
export declare function checkSkillVersion(skillsDir: string, skillName: string, rawBaseUrl?: string, fetchImpl?: typeof fetch, logger?: LoggerLike): Promise<SkillVersionInfo>;
|
|
61
|
+
//# sourceMappingURL=version-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-manager.d.ts","sourceRoot":"","sources":["../../src/skills-manager/version-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGhF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAA4B,EACxC,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BxB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAA4B,EACxC,SAAS,GAAE,OAAO,KAAa,EAC/B,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,gBAAgB,CAAC,CAyC3B"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version detection for Senpi skills.
|
|
3
|
+
*
|
|
4
|
+
* Reads the installed SKILL.md version from disk and the remote version from
|
|
5
|
+
* raw.githubusercontent.com, then uses the existing semver helpers from
|
|
6
|
+
* src/runtime/auto-update/policy.ts to classify the delta.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { classifyUpdate, parseSemver } from "../runtime/auto-update/policy.js";
|
|
11
|
+
import { SKILLS_RAW_BASE_URL } from "./constants.js";
|
|
12
|
+
import { formatErr } from "./utils.js";
|
|
13
|
+
/**
|
|
14
|
+
* Normalise a version string before passing it to parseSemver / classifyUpdate.
|
|
15
|
+
*
|
|
16
|
+
* Accepts two-part versions used in production skills (e.g. "1.0", "v2.3")
|
|
17
|
+
* and expands them to the full three-part form ("1.0.0", "v2.3.0") that
|
|
18
|
+
* parseSemver requires. All other strings are returned unchanged.
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeVersion(v) {
|
|
21
|
+
return /^v?\d+\.\d+$/.test(v.trim()) ? `${v.trim()}.0` : v;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extract the `version` value from a SKILL.md YAML frontmatter block.
|
|
25
|
+
*
|
|
26
|
+
* Handles both nested form:
|
|
27
|
+
* metadata:
|
|
28
|
+
* version: 1.2.3
|
|
29
|
+
* and flat form:
|
|
30
|
+
* version: "1.2.3"
|
|
31
|
+
*
|
|
32
|
+
* Returns null when the frontmatter block is absent or the field is missing.
|
|
33
|
+
*/
|
|
34
|
+
export function parseSkillMdVersion(content) {
|
|
35
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content.trim());
|
|
36
|
+
if (!match)
|
|
37
|
+
return null;
|
|
38
|
+
const frontmatter = match[1];
|
|
39
|
+
const versionMatch = /(?:^|\n)[ \t]*version:[ \t]*["']?([^\s"'\r\n]+)["']?/i.exec(frontmatter);
|
|
40
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read the installed version for a skill from its local SKILL.md.
|
|
44
|
+
* Returns null when the file is absent or the version field is missing.
|
|
45
|
+
* Logs a warning for unexpected errors (anything other than ENOENT).
|
|
46
|
+
*/
|
|
47
|
+
export async function readLocalVersion(skillsDir, skillName, logger) {
|
|
48
|
+
const filePath = join(skillsDir, skillName, "SKILL.md");
|
|
49
|
+
try {
|
|
50
|
+
const content = await readFile(filePath, "utf8");
|
|
51
|
+
return parseSkillMdVersion(content);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (err.code !== "ENOENT") {
|
|
55
|
+
logger?.warn(`[senpi-skills-manager] failed to read SKILL.md for "${skillName}" | path=${filePath} err=${formatErr(err)}`);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Fetch the remote SKILL.md for a skill and return its version.
|
|
62
|
+
*
|
|
63
|
+
* Returns null when the skill does not exist in the remote repo (HTTP 404) —
|
|
64
|
+
* that's a legitimate state ("skill removed or not yet published"), not an
|
|
65
|
+
* error, so it should not pollute failure counters.
|
|
66
|
+
*
|
|
67
|
+
* Throws on transient/operational failures (network errors, timeouts, 5xx
|
|
68
|
+
* responses, body-parse failures) so the caller's failure-recording path can
|
|
69
|
+
* fire.
|
|
70
|
+
*
|
|
71
|
+
* @param fetchImpl Injectable for unit testing — defaults to global `fetch`.
|
|
72
|
+
*/
|
|
73
|
+
export async function fetchRemoteVersion(skillName, rawBaseUrl = SKILLS_RAW_BASE_URL, fetchImpl = fetch) {
|
|
74
|
+
const url = `${rawBaseUrl}/${encodeURIComponent(skillName)}/SKILL.md`;
|
|
75
|
+
let res;
|
|
76
|
+
try {
|
|
77
|
+
res = await fetchImpl(url, { signal: AbortSignal.timeout(15_000) });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
throw new Error(`Network error fetching remote SKILL.md for "${skillName}": ${formatErr(err)}`);
|
|
81
|
+
}
|
|
82
|
+
// 404 = skill is not in the remote repo. Treated as "no remote version"
|
|
83
|
+
// rather than a failure so the caller can skip cleanly without escalating.
|
|
84
|
+
if (res.status === 404) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (!res.ok) {
|
|
88
|
+
throw new Error(`Failed to fetch remote SKILL.md for "${skillName}": HTTP ${res.status} ${res.statusText}`);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const text = await res.text();
|
|
92
|
+
return parseSkillMdVersion(text);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
throw new Error(`Failed to read response body for "${skillName}": ${formatErr(err)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Compare the local and remote versions for a skill and return a classified diff.
|
|
100
|
+
*
|
|
101
|
+
* Special cases:
|
|
102
|
+
* - Local version is null (skill predates versioning) + valid remote → "minor"
|
|
103
|
+
* so the update is auto-applied without manual major-version approval.
|
|
104
|
+
* - Local version exists but is not valid semver (e.g. "latest") → "unknown",
|
|
105
|
+
* skip safely.
|
|
106
|
+
* - Remote version is absent or unparseable → "unknown", caller should log and
|
|
107
|
+
* skip.
|
|
108
|
+
*/
|
|
109
|
+
export async function checkSkillVersion(skillsDir, skillName, rawBaseUrl = SKILLS_RAW_BASE_URL, fetchImpl = fetch, logger) {
|
|
110
|
+
// Log the specific fetch failure for traceability, then re-throw so the
|
|
111
|
+
// coordinator records it as a check failure (consecutiveFailures,
|
|
112
|
+
// lastFailureReason). 404 is intentionally returned as null inside
|
|
113
|
+
// fetchRemoteVersion and never reaches this catch.
|
|
114
|
+
const remoteVersionPromise = fetchRemoteVersion(skillName, rawBaseUrl, fetchImpl).catch((err) => {
|
|
115
|
+
logger?.warn(`[senpi-skills-manager] failed to fetch remote version for "${skillName}" | err=${formatErr(err)}`);
|
|
116
|
+
throw err;
|
|
117
|
+
});
|
|
118
|
+
const [localVersion, remoteVersion] = await Promise.all([
|
|
119
|
+
readLocalVersion(skillsDir, skillName, logger),
|
|
120
|
+
remoteVersionPromise,
|
|
121
|
+
]);
|
|
122
|
+
const normalizedRemote = normalizeVersion(remoteVersion ?? "");
|
|
123
|
+
if (!remoteVersion || !parseSemver(normalizedRemote)) {
|
|
124
|
+
return { localVersion, remoteVersion, updateKind: "unknown" };
|
|
125
|
+
}
|
|
126
|
+
// Skill has never had a version in SKILL.md (null) — predates the versioning
|
|
127
|
+
// system or was installed before the field was added. Treat as a minor update
|
|
128
|
+
// so it is auto-applied without requiring a manual major-version approval.
|
|
129
|
+
if (localVersion === null) {
|
|
130
|
+
return { localVersion, remoteVersion, updateKind: "minor" };
|
|
131
|
+
}
|
|
132
|
+
const normalizedLocal = normalizeVersion(localVersion);
|
|
133
|
+
// Local version string exists but is not valid semver even after normalisation
|
|
134
|
+
// (e.g. "latest", "nightly"). We cannot safely compare, so skip.
|
|
135
|
+
if (!parseSemver(normalizedLocal)) {
|
|
136
|
+
return { localVersion, remoteVersion, updateKind: "unknown" };
|
|
137
|
+
}
|
|
138
|
+
// classifyUpdate returns AutoUpdateKind which is a strict subset of SkillUpdateKind
|
|
139
|
+
const updateKind = classifyUpdate(normalizedLocal, normalizedRemote);
|
|
140
|
+
return { localVersion, remoteVersion, updateKind };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=version-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-manager.js","sourceRoot":"","sources":["../../src/skills-manager/version-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs a skill from a cloned repo directory into the target skills
|
|
3
|
+
* directory using a crash-safe swap flow.
|
|
4
|
+
*/
|
|
5
|
+
import type { LoggerLike } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Copy a skill's subdirectory from `cloneDir` into `skillsDir/<skillName>/`,
|
|
8
|
+
* replacing the existing copy via a crash-safe swap.
|
|
9
|
+
*
|
|
10
|
+
* Strategy:
|
|
11
|
+
* 1. Validate source directory exists in the clone.
|
|
12
|
+
* 2. Write to a `.tmp-<skillName>` staging path inside `skillsDir`.
|
|
13
|
+
* 3. Move existing target to a hidden backup path (if present).
|
|
14
|
+
* 4. Move staging → target (atomic on same fs).
|
|
15
|
+
* 5. Delete the backup only after the new target is in place.
|
|
16
|
+
*
|
|
17
|
+
* This avoids destroying the previous skill copy before the new one is ready.
|
|
18
|
+
* There is still a brief window where `targetPath` may be absent, but the old
|
|
19
|
+
* content remains recoverable from the backup path until install succeeds.
|
|
20
|
+
*
|
|
21
|
+
* The `.tmp-` prefix hides the staging directory from skill discovery, which
|
|
22
|
+
* only reads immediate subdirectories of `skillsDir`.
|
|
23
|
+
*
|
|
24
|
+
* @throws When the skill subdirectory is absent in the clone.
|
|
25
|
+
* @throws When the staging copy fails.
|
|
26
|
+
*/
|
|
27
|
+
export declare function installSkill(cloneDir: string, skillName: string, skillsDir: string, logger?: LoggerLike): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/skills-manager/writer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CA6Ff"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installs a skill from a cloned repo directory into the target skills
|
|
3
|
+
* directory using a crash-safe swap flow.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs/promises";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { ALLOWED_SKILLS } from "./constants.js";
|
|
9
|
+
import { formatErr } from "./utils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Copy a skill's subdirectory from `cloneDir` into `skillsDir/<skillName>/`,
|
|
12
|
+
* replacing the existing copy via a crash-safe swap.
|
|
13
|
+
*
|
|
14
|
+
* Strategy:
|
|
15
|
+
* 1. Validate source directory exists in the clone.
|
|
16
|
+
* 2. Write to a `.tmp-<skillName>` staging path inside `skillsDir`.
|
|
17
|
+
* 3. Move existing target to a hidden backup path (if present).
|
|
18
|
+
* 4. Move staging → target (atomic on same fs).
|
|
19
|
+
* 5. Delete the backup only after the new target is in place.
|
|
20
|
+
*
|
|
21
|
+
* This avoids destroying the previous skill copy before the new one is ready.
|
|
22
|
+
* There is still a brief window where `targetPath` may be absent, but the old
|
|
23
|
+
* content remains recoverable from the backup path until install succeeds.
|
|
24
|
+
*
|
|
25
|
+
* The `.tmp-` prefix hides the staging directory from skill discovery, which
|
|
26
|
+
* only reads immediate subdirectories of `skillsDir`.
|
|
27
|
+
*
|
|
28
|
+
* @throws When the skill subdirectory is absent in the clone.
|
|
29
|
+
* @throws When the staging copy fails.
|
|
30
|
+
*/
|
|
31
|
+
export async function installSkill(cloneDir, skillName, skillsDir, logger) {
|
|
32
|
+
if (!ALLOWED_SKILLS.includes(skillName)) {
|
|
33
|
+
throw new Error(`Skill "${skillName}" is not in the allowed skills list: ${ALLOWED_SKILLS.join(", ")}`);
|
|
34
|
+
}
|
|
35
|
+
const sourcePath = join(cloneDir, skillName);
|
|
36
|
+
const targetPath = join(skillsDir, skillName);
|
|
37
|
+
const stagingPath = join(skillsDir, `.tmp-${skillName}`);
|
|
38
|
+
const backupPath = join(skillsDir, `.bak-${skillName}-${randomUUID()}`);
|
|
39
|
+
logger?.info(`[senpi-skills-manager] installing skill | skill=${skillName} from=${sourcePath} to=${targetPath}`);
|
|
40
|
+
// Validate source exists and is a directory
|
|
41
|
+
try {
|
|
42
|
+
const info = await fs.stat(sourcePath);
|
|
43
|
+
if (!info.isDirectory()) {
|
|
44
|
+
throw new Error(`Expected a directory at "${sourcePath}" for skill "${skillName}" but found a file`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
if (err.code === "ENOENT") {
|
|
49
|
+
throw new Error(`Skill "${skillName}" not found in cloned repo at "${sourcePath}"`);
|
|
50
|
+
}
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
// Ensure skillsDir exists
|
|
54
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
55
|
+
// Remove any leftover staging dir from a previous failed install
|
|
56
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
57
|
+
logger?.info(`[senpi-skills-manager] cleared leftover staging dir | path=${stagingPath}`);
|
|
58
|
+
// Copy source → staging
|
|
59
|
+
logger?.info(`[senpi-skills-manager] copying skill to staging | from=${sourcePath} to=${stagingPath}`);
|
|
60
|
+
await fs.cp(sourcePath, stagingPath, { recursive: true });
|
|
61
|
+
// Move current target out of the way first so old data is recoverable on failure.
|
|
62
|
+
let movedTargetToBackup = false;
|
|
63
|
+
try {
|
|
64
|
+
await fs.rename(targetPath, backupPath);
|
|
65
|
+
movedTargetToBackup = true;
|
|
66
|
+
logger?.info(`[senpi-skills-manager] backed up existing install | from=${targetPath} to=${backupPath}`);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err.code !== "ENOENT") {
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
logger?.info(`[senpi-skills-manager] no existing install to back up | skill=${skillName}`);
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
logger?.info(`[senpi-skills-manager] swapping staging to target | from=${stagingPath} to=${targetPath}`);
|
|
76
|
+
await fs.rename(stagingPath, targetPath);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
logger?.warn(`[senpi-skills-manager] swap failed, rolling back | skill=${skillName} err=${formatErr(err)}`);
|
|
80
|
+
// Remove any partial target before restoring old contents.
|
|
81
|
+
await fs.rm(targetPath, { recursive: true, force: true });
|
|
82
|
+
if (movedTargetToBackup) {
|
|
83
|
+
await fs.rename(backupPath, targetPath).catch((restoreErr) => {
|
|
84
|
+
logger?.warn(`[senpi-skills-manager] failed to restore backup after swap failure | skill=${skillName} backup=${backupPath} err=${formatErr(restoreErr)}`);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
// On successful rename this path no longer exists; rm is still safe with force=true.
|
|
91
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
// Backup cleanup is best-effort once the new target is in place.
|
|
94
|
+
if (movedTargetToBackup) {
|
|
95
|
+
await fs.rm(backupPath, { recursive: true, force: true }).catch((err) => {
|
|
96
|
+
logger?.warn(`[senpi-skills-manager] failed to remove backup dir | path=${backupPath} err=${formatErr(err)}`);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
logger?.info(`[senpi-skills-manager] skill installed successfully | skill=${skillName} path=${targetPath}`);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/skills-manager/writer.ts"],"names":[],"mappings":"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"}
|
package/openclaw.plugin.json
CHANGED
|
@@ -71,6 +71,35 @@
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
+
"skillsManager": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"description": "Skills manager configuration. Polls the senpi-skills repo for updates to declared skills and applies patch/minor updates automatically (major updates are notify-only). Omit this block to use defaults.",
|
|
78
|
+
"default": {
|
|
79
|
+
"enabled": true,
|
|
80
|
+
"skills": ["senpi-trading-runtime"],
|
|
81
|
+
"pollIntervalMinutes": 60
|
|
82
|
+
},
|
|
83
|
+
"properties": {
|
|
84
|
+
"enabled": {
|
|
85
|
+
"type": "boolean",
|
|
86
|
+
"description": "Enable or disable the skills manager (default: true)"
|
|
87
|
+
},
|
|
88
|
+
"skillsDir": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"description": "Directory where managed skills are installed (default: /data/.openclaw/skills, override via SENPI_SKILLS_DIR env)"
|
|
91
|
+
},
|
|
92
|
+
"pollIntervalMinutes": {
|
|
93
|
+
"type": "number",
|
|
94
|
+
"description": "Minutes between version checks (default: 60, range: 1-1440)"
|
|
95
|
+
},
|
|
96
|
+
"skills": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"items": { "type": "string" },
|
|
99
|
+
"description": "Explicit skill names to manage. Omitting the field falls back to the canonical default [\"senpi-trading-runtime\"]; passing an explicit empty array [] switches to discovery mode (scan subdirs under skillsDir)."
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
74
103
|
"api": {
|
|
75
104
|
"type": "object",
|
|
76
105
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@senpi/runtime",
|
|
3
|
-
"version": "1.1.0-dev.runtime-phase-2.
|
|
3
|
+
"version": "1.1.0-dev.runtime-phase-2.20260513122539",
|
|
4
4
|
"description": "Senpi runtime plugin for OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35
35
|
"@sinclair/typebox": "^0.34.0",
|
|
36
|
+
"async-retry": "^1.3.3",
|
|
36
37
|
"dd-trace": "^5.99.1",
|
|
37
38
|
"dotenv": "^16.4.5",
|
|
38
39
|
"fastify": "^5.8.5",
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
"openclaw": ">=2026.2.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
48
|
+
"@types/async-retry": "^1.4.9",
|
|
47
49
|
"@types/node": "^22.0.0",
|
|
48
50
|
"tsx": "^4.21.0",
|
|
49
51
|
"typescript": "^5.7.0",
|