@gendigital/sage-openclaw 0.13.0 → 0.14.0
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.cjs +183 -74
- package/dist/index.cjs.map +4 -4
- package/dist/mcp-server.cjs +385 -90
- package/dist/mcp-server.cjs.map +4 -4
- package/dist/model-download-worker.cjs +1 -1
- package/dist/model-download-worker.cjs.map +2 -2
- package/dist/skill-upload-worker.cjs +129 -42
- package/dist/skill-upload-worker.cjs.map +4 -4
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/resources/skills/security-awareness/SKILL.md +2 -2
|
@@ -35,6 +35,9 @@ __export(skill_upload_worker_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(skill_upload_worker_exports);
|
|
36
36
|
var import_node_path8 = require("node:path");
|
|
37
37
|
|
|
38
|
+
// ../core/src/audit-log.ts
|
|
39
|
+
var import_node_crypto2 = require("node:crypto");
|
|
40
|
+
|
|
38
41
|
// ../core/src/config.ts
|
|
39
42
|
var import_node_path2 = require("node:path");
|
|
40
43
|
|
|
@@ -4457,6 +4460,46 @@ var CONTENT_FIELD_LIMITS = Object.freeze({
|
|
|
4457
4460
|
package_registry: 128
|
|
4458
4461
|
});
|
|
4459
4462
|
|
|
4463
|
+
// ../core/src/detection-names.ts
|
|
4464
|
+
var REPORTING_ENGINE_SHORTHANDS = {
|
|
4465
|
+
package: "sgpk",
|
|
4466
|
+
amsi: "sgam",
|
|
4467
|
+
heuristics: "sghe",
|
|
4468
|
+
ml: "sgml",
|
|
4469
|
+
skill: "skan"
|
|
4470
|
+
};
|
|
4471
|
+
var REPORTING_DETECTION_SUFFIX = "sage";
|
|
4472
|
+
function formatReportingDetectionName(canonicalName, engine, optionalData = "") {
|
|
4473
|
+
const engineMetadata = optionalData ? `${REPORTING_ENGINE_SHORTHANDS[engine]}:${optionalData}` : REPORTING_ENGINE_SHORTHANDS[engine];
|
|
4474
|
+
return `${canonicalName}|${engineMetadata}|${REPORTING_DETECTION_SUFFIX}`;
|
|
4475
|
+
}
|
|
4476
|
+
var SKILL_DETECTION_NAMES = {
|
|
4477
|
+
HIGH: "Other:SageSuspiciousSkill-A [Susp]",
|
|
4478
|
+
CRITICAL: "Other:SageMaliciousSkill-A [Trj]"
|
|
4479
|
+
};
|
|
4480
|
+
function skillDetectionName(verdict) {
|
|
4481
|
+
return SKILL_DETECTION_NAMES[verdict.toUpperCase()];
|
|
4482
|
+
}
|
|
4483
|
+
function isSkillId(value) {
|
|
4484
|
+
return /^[0-9a-f]{64}$/i.test(value);
|
|
4485
|
+
}
|
|
4486
|
+
function skillReportingDetectionName(verdict, skillId) {
|
|
4487
|
+
const canonicalName = skillDetectionName(verdict);
|
|
4488
|
+
return canonicalName && isSkillId(skillId) ? formatReportingDetectionName(canonicalName, "skill", skillId.toLowerCase()) : void 0;
|
|
4489
|
+
}
|
|
4490
|
+
function buildSkillCheckSignal(skillId, analyzerVerdict, jobId) {
|
|
4491
|
+
const normalizedSkillId = skillId.toLowerCase();
|
|
4492
|
+
const normalizedVerdict = analyzerVerdict.toUpperCase();
|
|
4493
|
+
const detectionName = skillReportingDetectionName(normalizedVerdict, normalizedSkillId);
|
|
4494
|
+
if (!detectionName) return void 0;
|
|
4495
|
+
return {
|
|
4496
|
+
detection_name: detectionName,
|
|
4497
|
+
skill_id: normalizedSkillId,
|
|
4498
|
+
...jobId ? { job_id: jobId } : {},
|
|
4499
|
+
analyzer_verdict: normalizedVerdict
|
|
4500
|
+
};
|
|
4501
|
+
}
|
|
4502
|
+
|
|
4460
4503
|
// ../core/src/jsonl-log-writer.ts
|
|
4461
4504
|
var import_promises2 = require("node:fs/promises");
|
|
4462
4505
|
var import_node_path3 = require("node:path");
|
|
@@ -4516,19 +4559,30 @@ async function appendEntry(config, entry) {
|
|
|
4516
4559
|
const stamped = { ...entry, schema_version: AUDIT_LOG_SCHEMA_VERSION };
|
|
4517
4560
|
await appendJsonlEntry(config, stamped);
|
|
4518
4561
|
}
|
|
4519
|
-
async function logSkillVerdict(config, skillId, status, verdict, summary) {
|
|
4520
|
-
if (!config.enabled) return;
|
|
4562
|
+
async function logSkillVerdict(config, skillId, status, verdict, summary, context = {}) {
|
|
4563
|
+
if (!config.enabled) return false;
|
|
4521
4564
|
const entry = {
|
|
4522
4565
|
type: "skill_verdict",
|
|
4566
|
+
entry_id: context.entryId ?? (0, import_node_crypto2.randomUUID)(),
|
|
4523
4567
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4524
4568
|
skill_id: skillId,
|
|
4525
4569
|
status
|
|
4526
4570
|
};
|
|
4571
|
+
if (context.jobId !== void 0) entry.job_id = context.jobId;
|
|
4572
|
+
if (context.agentRuntime !== void 0) entry.agent_runtime = context.agentRuntime;
|
|
4527
4573
|
if (verdict !== void 0) entry.verdict = verdict;
|
|
4528
4574
|
if (summary !== void 0) entry.summary = summary.slice(0, MAX_SUMMARY_LEN);
|
|
4575
|
+
const skillSignal = status === "analyzed" && verdict !== void 0 ? buildSkillCheckSignal(skillId, verdict, context.jobId) : void 0;
|
|
4576
|
+
if (skillSignal) {
|
|
4577
|
+
entry.signals = {
|
|
4578
|
+
skill_checks: [skillSignal]
|
|
4579
|
+
};
|
|
4580
|
+
}
|
|
4529
4581
|
try {
|
|
4530
4582
|
await appendEntry(config, entry);
|
|
4583
|
+
return true;
|
|
4531
4584
|
} catch {
|
|
4585
|
+
return false;
|
|
4532
4586
|
}
|
|
4533
4587
|
}
|
|
4534
4588
|
|
|
@@ -4537,7 +4591,7 @@ var import_node_path4 = require("node:path");
|
|
|
4537
4591
|
var import_node_url = require("node:url");
|
|
4538
4592
|
var import_meta = {};
|
|
4539
4593
|
function resolveVersion() {
|
|
4540
|
-
if (true) return "0.
|
|
4594
|
+
if (true) return "0.14.0";
|
|
4541
4595
|
try {
|
|
4542
4596
|
const pkgPath = (0, import_node_path4.join)((0, import_node_path4.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
|
|
4543
4597
|
const pkg = JSON.parse(getFileContentSync(pkgPath));
|
|
@@ -4914,7 +4968,7 @@ function mergeSources(existing, incoming) {
|
|
|
4914
4968
|
function defaultCachePath2() {
|
|
4915
4969
|
return (0, import_node_path7.join)(resolvePath(SAGE_DIR), "skill_verdict_cache.json");
|
|
4916
4970
|
}
|
|
4917
|
-
async function
|
|
4971
|
+
async function loadSkillVerdictCacheInternal(cachePath, ttlMs, logger, pruneOnLoad) {
|
|
4918
4972
|
let raw;
|
|
4919
4973
|
try {
|
|
4920
4974
|
raw = await getFileContent(cachePath);
|
|
@@ -4936,6 +4990,8 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
|
|
|
4936
4990
|
continue;
|
|
4937
4991
|
}
|
|
4938
4992
|
entries[skillId] = {
|
|
4993
|
+
entryId: typeof entry.entry_id === "string" ? entry.entry_id : void 0,
|
|
4994
|
+
jobId: typeof entry.job_id === "string" ? entry.job_id : void 0,
|
|
4939
4995
|
verdict: typeof entry.verdict === "string" ? entry.verdict : void 0,
|
|
4940
4996
|
summary: typeof entry.summary === "string" ? entry.summary : void 0,
|
|
4941
4997
|
skillName: typeof entry.skill_name === "string" ? entry.skill_name : void 0,
|
|
@@ -4944,7 +5000,7 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
|
|
|
4944
5000
|
};
|
|
4945
5001
|
}
|
|
4946
5002
|
const cache = { entries };
|
|
4947
|
-
if (pruned > 0) {
|
|
5003
|
+
if (pruneOnLoad && pruned > 0) {
|
|
4948
5004
|
logger.debug(`Pruned ${pruned} stale verdict(s) from cache`, { cachePath });
|
|
4949
5005
|
await saveSkillVerdictCache(cache, cachePath, logger);
|
|
4950
5006
|
}
|
|
@@ -4954,6 +5010,9 @@ async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DE
|
|
|
4954
5010
|
return { entries: {} };
|
|
4955
5011
|
}
|
|
4956
5012
|
}
|
|
5013
|
+
async function loadSkillVerdictCache(cachePath = defaultCachePath2(), ttlMs = DEFAULT_VERDICT_TTL_MS, logger = nullLogger) {
|
|
5014
|
+
return loadSkillVerdictCacheInternal(cachePath, ttlMs, logger, true);
|
|
5015
|
+
}
|
|
4957
5016
|
async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), logger = nullLogger) {
|
|
4958
5017
|
try {
|
|
4959
5018
|
const data = {
|
|
@@ -4962,6 +5021,8 @@ async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), log
|
|
|
4962
5021
|
Object.entries(cache.entries).map(([skillId, v]) => [
|
|
4963
5022
|
skillId,
|
|
4964
5023
|
{
|
|
5024
|
+
entry_id: v.entryId,
|
|
5025
|
+
job_id: v.jobId,
|
|
4965
5026
|
verdict: v.verdict,
|
|
4966
5027
|
summary: v.summary,
|
|
4967
5028
|
skill_name: v.skillName,
|
|
@@ -4975,8 +5036,10 @@ async function saveSkillVerdictCache(cache, cachePath = defaultCachePath2(), log
|
|
|
4975
5036
|
)
|
|
4976
5037
|
};
|
|
4977
5038
|
await atomicWriteJson(cachePath, data);
|
|
5039
|
+
return true;
|
|
4978
5040
|
} catch (e) {
|
|
4979
5041
|
logger.warn(`Failed to save verdict cache to ${cachePath}`, { error: String(e) });
|
|
5042
|
+
return false;
|
|
4980
5043
|
}
|
|
4981
5044
|
}
|
|
4982
5045
|
function putVerdict(cache, skillId, verdict) {
|
|
@@ -4988,6 +5051,33 @@ function putVerdict(cache, skillId, verdict) {
|
|
|
4988
5051
|
};
|
|
4989
5052
|
}
|
|
4990
5053
|
|
|
5054
|
+
// ../core/src/skill-verdict-record.ts
|
|
5055
|
+
var import_node_crypto3 = require("node:crypto");
|
|
5056
|
+
function recordAnalyzedSkillVerdict(cache, skillId, result, origin) {
|
|
5057
|
+
const entryId = (0, import_node_crypto3.randomUUID)();
|
|
5058
|
+
putVerdict(cache, skillId, {
|
|
5059
|
+
entryId,
|
|
5060
|
+
jobId: result.jobId,
|
|
5061
|
+
verdict: result.verdict,
|
|
5062
|
+
summary: result.summary,
|
|
5063
|
+
skillName: origin.skillName,
|
|
5064
|
+
sources: [{ agentRuntime: origin.agentRuntime, containerKey: origin.containerKey }]
|
|
5065
|
+
});
|
|
5066
|
+
const { loggingConfig } = origin;
|
|
5067
|
+
return {
|
|
5068
|
+
entryId,
|
|
5069
|
+
writeAuditEntry: async () => {
|
|
5070
|
+
if (!loggingConfig) return;
|
|
5071
|
+
await logSkillVerdict(loggingConfig, skillId, "analyzed", result.verdict, result.summary, {
|
|
5072
|
+
entryId,
|
|
5073
|
+
jobId: result.jobId,
|
|
5074
|
+
agentRuntime: origin.agentRuntime
|
|
5075
|
+
});
|
|
5076
|
+
}
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5079
|
+
var SKILL_ENTRY_ID_NAMESPACE = Buffer.from("75bba79a376142a7bacbf95d791126d3", "hex");
|
|
5080
|
+
|
|
4991
5081
|
// ../../node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
|
|
4992
5082
|
var import_module = require("module");
|
|
4993
5083
|
var require2 = (0, import_module.createRequire)("/");
|
|
@@ -5519,14 +5609,18 @@ async function runSkillUploadWorker(args = {}) {
|
|
|
5519
5609
|
error: String(outcome.error)
|
|
5520
5610
|
});
|
|
5521
5611
|
if (loggingConfig) {
|
|
5522
|
-
logSkillVerdict(loggingConfig, skillId, "error"
|
|
5612
|
+
logSkillVerdict(loggingConfig, skillId, "error", void 0, void 0, {
|
|
5613
|
+
agentRuntime: skill.agentRuntime ?? args.agentRuntime
|
|
5614
|
+
}).catch(() => {
|
|
5523
5615
|
});
|
|
5524
5616
|
}
|
|
5525
5617
|
} else if (outcome.tag === "no_verdict") {
|
|
5526
5618
|
retained += 1;
|
|
5527
5619
|
logger.debug("Skill analysis returned no verdict; leaving pending", { skillId });
|
|
5528
5620
|
if (loggingConfig) {
|
|
5529
|
-
logSkillVerdict(loggingConfig, skillId, "no_verdict"
|
|
5621
|
+
logSkillVerdict(loggingConfig, skillId, "no_verdict", void 0, void 0, {
|
|
5622
|
+
agentRuntime: skill.agentRuntime ?? args.agentRuntime
|
|
5623
|
+
}).catch(() => {
|
|
5530
5624
|
});
|
|
5531
5625
|
}
|
|
5532
5626
|
} else if (outcome.tag === "ok") {
|
|
@@ -5534,55 +5628,48 @@ async function runSkillUploadWorker(args = {}) {
|
|
|
5534
5628
|
} else if (outcome.tag === "too_large" || outcome.tag === "empty") {
|
|
5535
5629
|
terminal.push(skillId);
|
|
5536
5630
|
if (loggingConfig) {
|
|
5537
|
-
logSkillVerdict(loggingConfig, skillId, outcome.tag
|
|
5631
|
+
logSkillVerdict(loggingConfig, skillId, outcome.tag, void 0, void 0, {
|
|
5632
|
+
agentRuntime: skill.agentRuntime ?? args.agentRuntime
|
|
5633
|
+
}).catch(() => {
|
|
5538
5634
|
});
|
|
5539
5635
|
}
|
|
5540
5636
|
}
|
|
5541
5637
|
}
|
|
5542
5638
|
if (successes.length === 0 && terminal.length === 0) continue;
|
|
5543
5639
|
const cache = await loadSkillVerdictCache(args.verdictCachePath, args.verdictTtlMs, logger);
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
verdict: result.verdict,
|
|
5547
|
-
summary: result.summary,
|
|
5640
|
+
const recorded = successes.map(
|
|
5641
|
+
({ skill, result }) => recordAnalyzedSkillVerdict(cache, skill.skillId, result, {
|
|
5548
5642
|
skillName: (0, import_node_path8.basename)(skill.folder),
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
]
|
|
5555
|
-
});
|
|
5556
|
-
}
|
|
5643
|
+
agentRuntime: skill.agentRuntime ?? args.agentRuntime,
|
|
5644
|
+
containerKey: skill.containerKey,
|
|
5645
|
+
loggingConfig
|
|
5646
|
+
})
|
|
5647
|
+
);
|
|
5557
5648
|
for (const skillId of terminal) {
|
|
5558
5649
|
putVerdict(cache, skillId, {});
|
|
5559
5650
|
}
|
|
5560
|
-
await saveSkillVerdictCache(cache, args.verdictCachePath, logger);
|
|
5651
|
+
const cacheSaved = await saveSkillVerdictCache(cache, args.verdictCachePath, logger);
|
|
5561
5652
|
const fresh = await loadPendingMarker(args.pendingPath, logger);
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
logSkillVerdict(
|
|
5577
|
-
loggingConfig,
|
|
5578
|
-
skill.skillId,
|
|
5579
|
-
"analyzed",
|
|
5580
|
-
result.verdict,
|
|
5581
|
-
result.summary
|
|
5582
|
-
).catch(() => {
|
|
5653
|
+
if (cacheSaved) {
|
|
5654
|
+
for (const { skill } of successes) {
|
|
5655
|
+
removePending(fresh, skill.skillId);
|
|
5656
|
+
}
|
|
5657
|
+
for (const skillId of terminal) {
|
|
5658
|
+
removePending(fresh, skillId);
|
|
5659
|
+
}
|
|
5660
|
+
analyzed += successes.length;
|
|
5661
|
+
await Promise.all(recorded.map((entry) => entry.writeAuditEntry().catch(() => {
|
|
5662
|
+
})));
|
|
5663
|
+
for (const { skill, result } of successes) {
|
|
5664
|
+
logger.debug("Skill analyzed and cached", {
|
|
5665
|
+
skillId: skill.skillId,
|
|
5666
|
+
risk: result.verdict
|
|
5583
5667
|
});
|
|
5584
5668
|
}
|
|
5669
|
+
} else {
|
|
5670
|
+
retained += successes.length + terminal.length;
|
|
5585
5671
|
}
|
|
5672
|
+
await savePendingMarker(fresh, args.pendingPath, logger);
|
|
5586
5673
|
}
|
|
5587
5674
|
return { analyzed, retained };
|
|
5588
5675
|
}
|