@cfio/cohort-sync 0.34.4 → 0.34.6
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/index.js +78 -20
- package/dist/openclaw.plugin.json +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2826,7 +2826,7 @@ async function markAllUnreachable(cfg, logger) {
|
|
|
2826
2826
|
}
|
|
2827
2827
|
logger.info("cohort-sync: all agents marked unreachable");
|
|
2828
2828
|
}
|
|
2829
|
-
var MAX_SKILL_BYTES =
|
|
2829
|
+
var MAX_SKILL_BYTES = 256 * 1024;
|
|
2830
2830
|
var MAX_SYNC_SKILLS = 500;
|
|
2831
2831
|
function parseSkillFrontmatter(text) {
|
|
2832
2832
|
if (!text) return null;
|
|
@@ -2853,7 +2853,8 @@ function parseSkillFrontmatter(text) {
|
|
|
2853
2853
|
if (!closed) return null;
|
|
2854
2854
|
const name = fields.name;
|
|
2855
2855
|
if (!name) return null;
|
|
2856
|
-
|
|
2856
|
+
const description = fields.description ?? "";
|
|
2857
|
+
return { name, description, triggers: extractSkillTriggers(description || text) };
|
|
2857
2858
|
}
|
|
2858
2859
|
function stripScalar(value) {
|
|
2859
2860
|
const v2 = value.trim();
|
|
@@ -2862,7 +2863,12 @@ function stripScalar(value) {
|
|
|
2862
2863
|
}
|
|
2863
2864
|
return v2;
|
|
2864
2865
|
}
|
|
2865
|
-
function
|
|
2866
|
+
function extractSkillTriggers(text) {
|
|
2867
|
+
const match = text.match(/\btriggers?\s+on\s*:\s*([^.\n]+)/i) ?? text.match(/\btriggers?\s*:\s*([^.\n]+)/i);
|
|
2868
|
+
if (!match?.[1]) return [];
|
|
2869
|
+
return match[1].split(/[,;]| or | and /i).map((trigger) => trigger.trim()).filter((trigger) => trigger.length > 0).slice(0, 50);
|
|
2870
|
+
}
|
|
2871
|
+
function enumerateSkills(skillsDir2, source = "hermes") {
|
|
2866
2872
|
const byName = /* @__PURE__ */ new Map();
|
|
2867
2873
|
const visit = (dir) => {
|
|
2868
2874
|
let entries;
|
|
@@ -2893,15 +2899,45 @@ function enumerateSkills(skillsDir, source = "hermes") {
|
|
|
2893
2899
|
const parsed = parseSkillFrontmatter(text);
|
|
2894
2900
|
if (!parsed) continue;
|
|
2895
2901
|
if (byName.has(parsed.name)) continue;
|
|
2896
|
-
byName.set(parsed.name, {
|
|
2902
|
+
byName.set(parsed.name, {
|
|
2903
|
+
name: parsed.name,
|
|
2904
|
+
description: parsed.description,
|
|
2905
|
+
source,
|
|
2906
|
+
triggers: parsed.triggers,
|
|
2907
|
+
body: text,
|
|
2908
|
+
location: path.relative(skillsDir2, full)
|
|
2909
|
+
});
|
|
2897
2910
|
}
|
|
2898
2911
|
};
|
|
2899
|
-
visit(
|
|
2912
|
+
visit(skillsDir2);
|
|
2900
2913
|
return [...byName.values()];
|
|
2901
2914
|
}
|
|
2902
|
-
function
|
|
2915
|
+
function writeSkillBody(skillsDir2, location, body) {
|
|
2916
|
+
if (!skillsDir2) {
|
|
2917
|
+
throw new Error("skillsDir is required for skill writeback");
|
|
2918
|
+
}
|
|
2919
|
+
if (!location || path.isAbsolute(location) || location.split(/[\\/]+/).includes("..")) {
|
|
2920
|
+
throw new Error("Invalid skill location");
|
|
2921
|
+
}
|
|
2922
|
+
if (path.basename(location) !== "SKILL.md") {
|
|
2923
|
+
throw new Error("Skill location must end with SKILL.md");
|
|
2924
|
+
}
|
|
2925
|
+
if (body.length > MAX_SKILL_BYTES) {
|
|
2926
|
+
throw new Error(`Skill body exceeds maximum length of ${MAX_SKILL_BYTES} characters`);
|
|
2927
|
+
}
|
|
2928
|
+
const root = path.resolve(skillsDir2);
|
|
2929
|
+
const target = path.resolve(root, location);
|
|
2930
|
+
const relative = path.relative(root, target);
|
|
2931
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
2932
|
+
throw new Error("Skill location escapes skills directory");
|
|
2933
|
+
}
|
|
2934
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
2935
|
+
fs.writeFileSync(target, body, "utf8");
|
|
2936
|
+
return target;
|
|
2937
|
+
}
|
|
2938
|
+
function skillsDirExists(skillsDir2) {
|
|
2903
2939
|
try {
|
|
2904
|
-
return fs.statSync(
|
|
2940
|
+
return fs.statSync(skillsDir2).isDirectory();
|
|
2905
2941
|
} catch {
|
|
2906
2942
|
return false;
|
|
2907
2943
|
}
|
|
@@ -2913,7 +2949,7 @@ async function syncSkills(agentName, skills, cfg, logger) {
|
|
|
2913
2949
|
}
|
|
2914
2950
|
await v1Post(cfg.apiUrl, cfg.apiKey, "/api/v1/skills/sync", { agentName, skills: capped });
|
|
2915
2951
|
}
|
|
2916
|
-
async function fullSync(agentName, model, cfg, logger, openClawAgents,
|
|
2952
|
+
async function fullSync(agentName, model, cfg, logger, openClawAgents, skillsDir2) {
|
|
2917
2953
|
logger.info("cohort-sync: full sync starting");
|
|
2918
2954
|
if (openClawAgents && openClawAgents.length > 0) {
|
|
2919
2955
|
try {
|
|
@@ -2924,14 +2960,14 @@ async function fullSync(agentName, model, cfg, logger, openClawAgents, skillsDir
|
|
|
2924
2960
|
} else {
|
|
2925
2961
|
await syncAgentStatus(agentName, "working", model, cfg, logger);
|
|
2926
2962
|
}
|
|
2927
|
-
if (
|
|
2963
|
+
if (skillsDir2) {
|
|
2928
2964
|
try {
|
|
2929
|
-
if (!skillsDirExists(
|
|
2930
|
-
logger.info(`cohort-sync: skill sync skipped (skills dir missing or unreadable: ${
|
|
2965
|
+
if (!skillsDirExists(skillsDir2)) {
|
|
2966
|
+
logger.info(`cohort-sync: skill sync skipped (skills dir missing or unreadable: ${skillsDir2})`);
|
|
2931
2967
|
} else {
|
|
2932
|
-
const skills = enumerateSkills(
|
|
2968
|
+
const skills = enumerateSkills(skillsDir2, "openclaw");
|
|
2933
2969
|
await syncSkills(agentName, skills, cfg, logger);
|
|
2934
|
-
logger.info(`cohort-sync: synced ${skills.length} skill(s) from ${
|
|
2970
|
+
logger.info(`cohort-sync: synced ${skills.length} skill(s) from ${skillsDir2}`);
|
|
2935
2971
|
}
|
|
2936
2972
|
} catch (err) {
|
|
2937
2973
|
logger.warn(`cohort-sync: skill sync failed (non-fatal): ${String(err)}`);
|
|
@@ -11892,6 +11928,27 @@ async function executeCommand(cmd, gwClient, cfg, resolveAgentName, logger, cron
|
|
|
11892
11928
|
});
|
|
11893
11929
|
return;
|
|
11894
11930
|
}
|
|
11931
|
+
if (cmd.type === "skillWrite") {
|
|
11932
|
+
const skillsDir2 = injection?.skillsDir;
|
|
11933
|
+
const agentName = cmd.payload?.agentId;
|
|
11934
|
+
const location = cmd.payload?.location;
|
|
11935
|
+
const body = cmd.payload?.skillBody;
|
|
11936
|
+
if (!skillsDir2) {
|
|
11937
|
+
throw new Error("skillsDir is required for skillWrite");
|
|
11938
|
+
}
|
|
11939
|
+
if (!agentName) {
|
|
11940
|
+
throw new Error("agentId is required for skillWrite");
|
|
11941
|
+
}
|
|
11942
|
+
if (!location) {
|
|
11943
|
+
throw new Error("location is required for skillWrite");
|
|
11944
|
+
}
|
|
11945
|
+
if (typeof body !== "string") {
|
|
11946
|
+
throw new Error("skillBody is required for skillWrite");
|
|
11947
|
+
}
|
|
11948
|
+
writeSkillBody(skillsDir2, location, body);
|
|
11949
|
+
await syncSkills(agentName, enumerateSkills(skillsDir2, "openclaw"), cfg, logger);
|
|
11950
|
+
return;
|
|
11951
|
+
}
|
|
11895
11952
|
if (cmd.type.startsWith("cron")) {
|
|
11896
11953
|
if (!gwClient || !gwClient.isAlive()) {
|
|
11897
11954
|
logger.warn(`cohort-sync: no gateway client, cannot execute ${cmd.type}`);
|
|
@@ -14266,7 +14323,7 @@ function dumpEvent(event) {
|
|
|
14266
14323
|
function positiveNumber(value) {
|
|
14267
14324
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
14268
14325
|
}
|
|
14269
|
-
var PLUGIN_VERSION = true ? "0.34.
|
|
14326
|
+
var PLUGIN_VERSION = true ? "0.34.6" : "unknown";
|
|
14270
14327
|
var PRESENCE_PING_INTERVAL_MS = 12e4;
|
|
14271
14328
|
function resolveGatewayToken(api) {
|
|
14272
14329
|
const token2 = api.config?.gateway?.auth?.token;
|
|
@@ -14444,7 +14501,7 @@ async function handleGatewayStart(event, state) {
|
|
|
14444
14501
|
if (!state) {
|
|
14445
14502
|
return;
|
|
14446
14503
|
}
|
|
14447
|
-
const { cfg, tracker, logger, config, api } = state;
|
|
14504
|
+
const { cfg, tracker, logger, config, api, skillsDir: skillsDir2 } = state;
|
|
14448
14505
|
try {
|
|
14449
14506
|
const latestVersion = await checkForUpdate(PLUGIN_VERSION, logger);
|
|
14450
14507
|
if (latestVersion) {
|
|
@@ -14471,14 +14528,13 @@ async function handleGatewayStart(event, state) {
|
|
|
14471
14528
|
model: state.resolveModel(a.id),
|
|
14472
14529
|
identity: resolveIdentity(a.identity, a.workspace)
|
|
14473
14530
|
}));
|
|
14474
|
-
const skillsDir = api.config?.skills?.dir ?? path3.join(os2.homedir(), ".openclaw", "skills");
|
|
14475
14531
|
await fullSync(
|
|
14476
14532
|
state.resolveAgentName("main"),
|
|
14477
14533
|
state.resolveModel("main"),
|
|
14478
14534
|
cfg,
|
|
14479
14535
|
logger,
|
|
14480
14536
|
agentList,
|
|
14481
|
-
|
|
14537
|
+
skillsDir2
|
|
14482
14538
|
);
|
|
14483
14539
|
} catch (err) {
|
|
14484
14540
|
logger.error(`cohort-sync: gateway_start sync failed: ${String(err)}`);
|
|
@@ -14512,7 +14568,7 @@ async function handleGatewayStart(event, state) {
|
|
|
14512
14568
|
state.resolveAgentName,
|
|
14513
14569
|
state.persistentGwClient,
|
|
14514
14570
|
state.cronTimestampTracker,
|
|
14515
|
-
{ port: state.gatewayPort, hooksToken }
|
|
14571
|
+
{ port: state.gatewayPort, hooksToken, skillsDir: skillsDir2 }
|
|
14516
14572
|
);
|
|
14517
14573
|
state.commandUnsubscriber = unsub;
|
|
14518
14574
|
} catch (err) {
|
|
@@ -14860,7 +14916,7 @@ function registerHookHandlers(api, logger, getState) {
|
|
|
14860
14916
|
state.resolveAgentName,
|
|
14861
14917
|
state.persistentGwClient,
|
|
14862
14918
|
state.cronTimestampTracker,
|
|
14863
|
-
{ port: state.gatewayPort, hooksToken: state.gatewayToken }
|
|
14919
|
+
{ port: state.gatewayPort, hooksToken: state.gatewayToken, skillsDir }
|
|
14864
14920
|
);
|
|
14865
14921
|
state.commandUnsubscriber = unsub;
|
|
14866
14922
|
} catch (err) {
|
|
@@ -15173,6 +15229,7 @@ function initializeHookState(api, cfg) {
|
|
|
15173
15229
|
const gatewayPort = api.config?.gateway?.port ?? null;
|
|
15174
15230
|
const gatewayToken = resolveGatewayToken(api);
|
|
15175
15231
|
const hooksToken = resolveHooksToken(api);
|
|
15232
|
+
const skillsDir2 = api.config?.skills?.dir ?? path3.join(os2.homedir(), ".openclaw", "skills");
|
|
15176
15233
|
const cronTimestampTracker = new CronTimestampTracker();
|
|
15177
15234
|
const cronRunStarts = /* @__PURE__ */ new Map();
|
|
15178
15235
|
let persistentGwClient = null;
|
|
@@ -15188,7 +15245,7 @@ function initializeHookState(api, cfg) {
|
|
|
15188
15245
|
resolveAgentName,
|
|
15189
15246
|
persistentGwClient,
|
|
15190
15247
|
cronTimestampTracker,
|
|
15191
|
-
{ port: gatewayPort, hooksToken }
|
|
15248
|
+
{ port: gatewayPort, hooksToken, skillsDir: skillsDir2 }
|
|
15192
15249
|
);
|
|
15193
15250
|
setToolRuntime({
|
|
15194
15251
|
apiKey: cfg.apiKey,
|
|
@@ -15233,6 +15290,7 @@ function initializeHookState(api, cfg) {
|
|
|
15233
15290
|
getModelContextLimit: getModelContextLimit2,
|
|
15234
15291
|
activityBatch,
|
|
15235
15292
|
cronStorePath,
|
|
15293
|
+
skillsDir: skillsDir2,
|
|
15236
15294
|
stateFilePath,
|
|
15237
15295
|
gatewayPort,
|
|
15238
15296
|
gatewayToken,
|
package/dist/package.json
CHANGED
package/package.json
CHANGED