cclawd 2026.3.27 → 2026.3.28
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/.buildstamp +1 -1
- package/dist/build-info.json +3 -3
- package/dist/extensions/cclawd-guard/dashboard-launcher.js +1 -1
- package/dist/extensions/cclawd-guard/index.js +55 -376
- package/dist/extensions/discord/node_modules/.package-lock.json +3 -3
- package/dist/extensions/feishu/node_modules/.package-lock.json +7 -7
- package/dist/extensions/feishu/node_modules/qs/CHANGELOG.md +6 -0
- package/dist/extensions/feishu/node_modules/qs/dist/qs.js +16 -16
- package/dist/extensions/feishu/node_modules/qs/lib/parse.js +2 -2
- package/dist/extensions/feishu/node_modules/qs/package.json +3 -3
- package/dist/extensions/feishu/node_modules/qs/test/parse.js +86 -0
- package/dist/extensions/feishu/node_modules/qs/test/stringify.js +9 -0
- package/dist/extensions/feishu/node_modules/qs/test/utils.js +31 -3
- package/dist/extensions/feishu/node_modules/side-channel-list/CHANGELOG.md +25 -4
- package/dist/extensions/feishu/node_modules/side-channel-list/index.js +1 -3
- package/dist/extensions/feishu/node_modules/side-channel-list/package.json +8 -8
- package/dist/extensions/feishu/node_modules/side-channel-list/test/index.js +50 -0
- package/dist/extensions/slack/node_modules/.package-lock.json +10 -10
- package/dist/extensions/slack/node_modules/axios/CHANGELOG.md +1 -1
- package/dist/extensions/slack/node_modules/axios/README.md +90 -17
- package/dist/extensions/slack/node_modules/axios/dist/axios.js +47 -7
- package/dist/extensions/slack/node_modules/axios/dist/axios.js.map +1 -1
- package/dist/extensions/slack/node_modules/axios/dist/axios.min.js +3 -3
- package/dist/extensions/slack/node_modules/axios/dist/axios.min.js.map +1 -1
- package/dist/extensions/slack/node_modules/axios/dist/browser/axios.cjs +56 -8
- package/dist/extensions/slack/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/dist/extensions/slack/node_modules/axios/dist/esm/axios.js +56 -8
- package/dist/extensions/slack/node_modules/axios/dist/esm/axios.js.map +1 -1
- package/dist/extensions/slack/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/dist/extensions/slack/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/dist/extensions/slack/node_modules/axios/dist/node/axios.cjs +123 -9
- package/dist/extensions/slack/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/dist/extensions/slack/node_modules/axios/lib/adapters/http.js +4 -2
- package/dist/extensions/slack/node_modules/axios/lib/core/Axios.js +19 -3
- package/dist/extensions/slack/node_modules/axios/lib/core/AxiosHeaders.js +35 -3
- package/dist/extensions/slack/node_modules/axios/lib/env/data.js +1 -1
- package/dist/extensions/slack/node_modules/axios/lib/helpers/shouldBypassProxy.js +106 -0
- package/dist/extensions/slack/node_modules/axios/package.json +4 -1
- package/dist/extensions/slack/node_modules/qs/CHANGELOG.md +6 -0
- package/dist/extensions/slack/node_modules/qs/dist/qs.js +16 -16
- package/dist/extensions/slack/node_modules/qs/lib/parse.js +2 -2
- package/dist/extensions/slack/node_modules/qs/package.json +3 -3
- package/dist/extensions/slack/node_modules/qs/test/parse.js +86 -0
- package/dist/extensions/slack/node_modules/qs/test/stringify.js +9 -0
- package/dist/extensions/slack/node_modules/qs/test/utils.js +31 -3
- package/dist/extensions/slack/node_modules/side-channel-list/CHANGELOG.md +25 -4
- package/dist/extensions/slack/node_modules/side-channel-list/index.js +1 -3
- package/dist/extensions/slack/node_modules/side-channel-list/package.json +8 -8
- package/dist/extensions/slack/node_modules/side-channel-list/test/index.js +50 -0
- package/dist/{gateway-manager-D_f5cQVk.js → gateway-manager-D66ezIC1.js} +2 -6
- package/package.json +1 -1
package/dist/.buildstamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"builtAt":
|
|
1
|
+
{"builtAt":1775727523888,"head":"eb993539ed3bdef773db4ffc7adb3e6399a0f57d"}
|
package/dist/build-info.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as openclawHome } from "../../env-CcGPS0ln.js";
|
|
2
|
-
import {
|
|
2
|
+
import { c as loadJsonSync, i as setDashboardPort } from "../../gateway-manager-D66ezIC1.js";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as openclawHome, n as envApiKey, t as defaultCoreUrl } from "../../env-CcGPS0ln.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as startGateway, c as loadJsonSync, i as setDashboardPort, l as loadTextSafe, n as enableGateway, o as stopGateway, r as getGatewayStatus, s as loadJsonSafe, t as disableGateway, u as loadTextSync } from "../../gateway-manager-D66ezIC1.js";
|
|
3
3
|
import fs, { existsSync, mkdirSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import os, { networkInterfaces } from "node:os";
|
|
@@ -379,6 +379,33 @@ function sanitizeContent(content) {
|
|
|
379
379
|
};
|
|
380
380
|
}
|
|
381
381
|
//#endregion
|
|
382
|
+
//#region extensions/cclawd-guard/agent/machine-id.ts
|
|
383
|
+
let cachedMachineInfo = null;
|
|
384
|
+
/**
|
|
385
|
+
* Build a stable per-device ID from hostname + first non-internal MAC.
|
|
386
|
+
* Hashing avoids sending raw MAC addresses.
|
|
387
|
+
*/
|
|
388
|
+
function getMachineInfo() {
|
|
389
|
+
if (cachedMachineInfo) return cachedMachineInfo;
|
|
390
|
+
const machineName = os.hostname();
|
|
391
|
+
const interfaces = networkInterfaces();
|
|
392
|
+
let mac = "";
|
|
393
|
+
for (const iface of Object.values(interfaces)) {
|
|
394
|
+
if (!iface) continue;
|
|
395
|
+
for (const info of iface) if (!info.internal && info.mac && info.mac !== "00:00:00:00:00:00") {
|
|
396
|
+
mac = info.mac;
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
if (mac) break;
|
|
400
|
+
}
|
|
401
|
+
const input = `${machineName}:${mac || "unknown"}`;
|
|
402
|
+
cachedMachineInfo = {
|
|
403
|
+
machineId: createHash("sha256").update(input).digest("hex").slice(0, 16),
|
|
404
|
+
machineName
|
|
405
|
+
};
|
|
406
|
+
return cachedMachineInfo;
|
|
407
|
+
}
|
|
408
|
+
//#endregion
|
|
382
409
|
//#region extensions/cclawd-guard/agent/behavior-detector.ts
|
|
383
410
|
/**
|
|
384
411
|
* Behavioral anomaly detector — runs at before_tool_call.
|
|
@@ -389,28 +416,9 @@ function sanitizeContent(content) {
|
|
|
389
416
|
* 3. Core does all classification, signal computation, and risk decisions
|
|
390
417
|
* 4. Fail-open: if Core is unavailable, allow execution
|
|
391
418
|
*/
|
|
392
|
-
const FILE_READ_TOOLS = new Set([
|
|
393
|
-
"Read",
|
|
394
|
-
"read_file",
|
|
395
|
-
"read",
|
|
396
|
-
"cat",
|
|
397
|
-
"head",
|
|
398
|
-
"tail",
|
|
399
|
-
"view",
|
|
400
|
-
"get_file_contents",
|
|
401
|
-
"open_file"
|
|
402
|
-
]);
|
|
403
|
-
const WEB_FETCH_TOOLS = new Set([
|
|
404
|
-
"WebFetch",
|
|
405
|
-
"web_fetch",
|
|
406
|
-
"fetch",
|
|
407
|
-
"http_request",
|
|
408
|
-
"get_url",
|
|
409
|
-
"browser_navigate",
|
|
410
|
-
"navigate"
|
|
411
|
-
]);
|
|
412
419
|
/** Module-level secret detection callback (set by BehaviorDetector) */
|
|
413
420
|
let secretDetectionCallback = null;
|
|
421
|
+
const machineInfo$1 = getMachineInfo();
|
|
414
422
|
function sanitizeParams(params) {
|
|
415
423
|
const result = {};
|
|
416
424
|
const allRedactions = {};
|
|
@@ -495,7 +503,9 @@ var BehaviorDetector = class {
|
|
|
495
503
|
},
|
|
496
504
|
meta: {
|
|
497
505
|
pluginVersion: this.config.pluginVersion,
|
|
498
|
-
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
506
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
507
|
+
machineId: machineInfo$1.machineId,
|
|
508
|
+
machineName: machineInfo$1.machineName
|
|
499
509
|
}
|
|
500
510
|
};
|
|
501
511
|
const verdict = await this.callAssessApi(req);
|
|
@@ -537,6 +547,7 @@ var BehaviorDetector = class {
|
|
|
537
547
|
*/
|
|
538
548
|
async scanContent(sessionKey, toolName, content) {
|
|
539
549
|
if (!this.coreCredentials) return null;
|
|
550
|
+
const state = this.getOrCreate(sessionKey);
|
|
540
551
|
const maxSize = 100 * 1024;
|
|
541
552
|
const truncatedContent = content.length > maxSize ? content.slice(0, maxSize) : content;
|
|
542
553
|
const controller = new AbortController();
|
|
@@ -551,7 +562,15 @@ var BehaviorDetector = class {
|
|
|
551
562
|
body: JSON.stringify({
|
|
552
563
|
content: truncatedContent,
|
|
553
564
|
toolName,
|
|
554
|
-
sessionKey
|
|
565
|
+
sessionKey,
|
|
566
|
+
runId: state.runId,
|
|
567
|
+
userIntent: state.userIntent,
|
|
568
|
+
meta: {
|
|
569
|
+
machineId: machineInfo$1.machineId,
|
|
570
|
+
machineName: machineInfo$1.machineName,
|
|
571
|
+
pluginVersion: this.config.pluginVersion,
|
|
572
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
573
|
+
}
|
|
555
574
|
}),
|
|
556
575
|
signal: controller.signal
|
|
557
576
|
});
|
|
@@ -663,7 +682,8 @@ const BATCH_FLUSH_INTERVAL_MS = 100;
|
|
|
663
682
|
/** Maximum events per batch */
|
|
664
683
|
const MAX_BATCH_SIZE = 50;
|
|
665
684
|
/** Timeout for Core API calls */
|
|
666
|
-
const API_TIMEOUT_MS$
|
|
685
|
+
const API_TIMEOUT_MS$1 = 3e3;
|
|
686
|
+
const machineInfo = getMachineInfo();
|
|
667
687
|
var EventReporter = class {
|
|
668
688
|
constructor(config, log) {
|
|
669
689
|
this.credentials = null;
|
|
@@ -675,7 +695,7 @@ var EventReporter = class {
|
|
|
675
695
|
this.config = {
|
|
676
696
|
coreUrl: config.coreUrl,
|
|
677
697
|
pluginVersion: config.pluginVersion,
|
|
678
|
-
timeoutMs: config.timeoutMs ?? API_TIMEOUT_MS$
|
|
698
|
+
timeoutMs: config.timeoutMs ?? API_TIMEOUT_MS$1,
|
|
679
699
|
enableBatching: config.enableBatching ?? true
|
|
680
700
|
};
|
|
681
701
|
this.log = log;
|
|
@@ -726,7 +746,9 @@ var EventReporter = class {
|
|
|
726
746
|
events: [event],
|
|
727
747
|
meta: {
|
|
728
748
|
pluginVersion: this.config.pluginVersion,
|
|
729
|
-
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
749
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
750
|
+
machineId: machineInfo.machineId,
|
|
751
|
+
machineName: machineInfo.machineName
|
|
730
752
|
}
|
|
731
753
|
};
|
|
732
754
|
const controller = new AbortController();
|
|
@@ -830,7 +852,9 @@ var EventReporter = class {
|
|
|
830
852
|
events,
|
|
831
853
|
meta: {
|
|
832
854
|
pluginVersion: this.config.pluginVersion,
|
|
833
|
-
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
855
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
856
|
+
machineId: machineInfo.machineId,
|
|
857
|
+
machineName: machineInfo.machineName
|
|
834
858
|
}
|
|
835
859
|
};
|
|
836
860
|
const controller = new AbortController();
|
|
@@ -897,285 +921,6 @@ var EventReporter = class {
|
|
|
897
921
|
}
|
|
898
922
|
};
|
|
899
923
|
//#endregion
|
|
900
|
-
//#region extensions/cclawd-guard/agent/business-reporter.ts
|
|
901
|
-
/**
|
|
902
|
-
* BusinessReporter - Reports telemetry data to Core's Business Dashboard.
|
|
903
|
-
*
|
|
904
|
-
* Only active when the agent's account is on the "business" plan.
|
|
905
|
-
* Accumulates events and agentic hours locally, then flushes to Core
|
|
906
|
-
* every 60 seconds via POST /api/v1/business/telemetry.
|
|
907
|
-
*/
|
|
908
|
-
function debugLog$1(msg) {
|
|
909
|
-
try {
|
|
910
|
-
const logPath = path.join(openclawHome, "logs", "cclawd-guard-debug.log");
|
|
911
|
-
fs.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [BusinessReporter] ${msg}\n`);
|
|
912
|
-
} catch {}
|
|
913
|
-
}
|
|
914
|
-
/** Flush interval in ms (60 seconds) */
|
|
915
|
-
const FLUSH_INTERVAL_MS = 6e4;
|
|
916
|
-
/** Maximum events to buffer before forced flush */
|
|
917
|
-
const MAX_BUFFERED_EVENTS = 500;
|
|
918
|
-
/** Timeout for Core API calls */
|
|
919
|
-
const API_TIMEOUT_MS$1 = 5e3;
|
|
920
|
-
var BusinessReporter = class {
|
|
921
|
-
constructor(config, log) {
|
|
922
|
-
this.enabled = false;
|
|
923
|
-
this.credentials = null;
|
|
924
|
-
this.ownerName = "";
|
|
925
|
-
this.agentName = "";
|
|
926
|
-
this.provider = "";
|
|
927
|
-
this.model = "";
|
|
928
|
-
this.pendingEvents = [];
|
|
929
|
-
this.hoursAccum = this.emptyAccum();
|
|
930
|
-
this.scanAccum = [];
|
|
931
|
-
this.gatewayAccum = this.emptyGatewayAccum();
|
|
932
|
-
this.secretAccum = this.emptySecretAccum();
|
|
933
|
-
this.flushInterval = null;
|
|
934
|
-
this.flushing = false;
|
|
935
|
-
this.config = config;
|
|
936
|
-
this.log = log;
|
|
937
|
-
this.machineName = os.hostname();
|
|
938
|
-
this.machineId = generateMachineId();
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Initialize the reporter. Only enables if the account plan is "business".
|
|
942
|
-
* Call this after fetching the account info from Core.
|
|
943
|
-
*/
|
|
944
|
-
initialize(plan) {
|
|
945
|
-
if (plan !== "business") {
|
|
946
|
-
this.log.debug?.(`BusinessReporter: plan is "${plan}", not enabling`);
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
this.enabled = true;
|
|
950
|
-
this.startPeriodicFlush();
|
|
951
|
-
this.log.info(`BusinessReporter: enabled for business plan (machine: ${this.machineName})`);
|
|
952
|
-
}
|
|
953
|
-
/** Set Core credentials */
|
|
954
|
-
setCredentials(credentials) {
|
|
955
|
-
this.credentials = credentials;
|
|
956
|
-
}
|
|
957
|
-
/** Update agent profile info (called when profile changes) */
|
|
958
|
-
setProfile(profile) {
|
|
959
|
-
if (profile.ownerName !== void 0) this.ownerName = profile.ownerName;
|
|
960
|
-
if (profile.agentName !== void 0) this.agentName = profile.agentName;
|
|
961
|
-
if (profile.provider !== void 0) this.provider = profile.provider;
|
|
962
|
-
if (profile.model !== void 0) this.model = profile.model;
|
|
963
|
-
}
|
|
964
|
-
/** Whether the reporter is active */
|
|
965
|
-
isEnabled() {
|
|
966
|
-
return this.enabled;
|
|
967
|
-
}
|
|
968
|
-
/** Stop the reporter and flush remaining data */
|
|
969
|
-
async stop() {
|
|
970
|
-
if (this.flushInterval) {
|
|
971
|
-
clearInterval(this.flushInterval);
|
|
972
|
-
this.flushInterval = null;
|
|
973
|
-
}
|
|
974
|
-
if (this.enabled) await this.flush();
|
|
975
|
-
this.enabled = false;
|
|
976
|
-
}
|
|
977
|
-
/** Record a tool call */
|
|
978
|
-
recordToolCall(toolName, category, durationMs, blocked) {
|
|
979
|
-
if (!this.enabled) return;
|
|
980
|
-
this.pendingEvents.push({
|
|
981
|
-
type: blocked ? "block" : "tool_call",
|
|
982
|
-
toolName,
|
|
983
|
-
category,
|
|
984
|
-
durationMs,
|
|
985
|
-
blocked
|
|
986
|
-
});
|
|
987
|
-
this.hoursAccum.toolCallDurationMs += durationMs;
|
|
988
|
-
this.hoursAccum.toolCallCount += 1;
|
|
989
|
-
this.hoursAccum.totalDurationMs += durationMs;
|
|
990
|
-
if (blocked) this.hoursAccum.blockCount += 1;
|
|
991
|
-
this.maybeFlush();
|
|
992
|
-
}
|
|
993
|
-
/** Record an LLM call */
|
|
994
|
-
recordLlmCall(durationMs, model) {
|
|
995
|
-
if (!this.enabled) return;
|
|
996
|
-
if (model) this.model = model;
|
|
997
|
-
this.hoursAccum.llmDurationMs += durationMs;
|
|
998
|
-
this.hoursAccum.llmCallCount += 1;
|
|
999
|
-
this.hoursAccum.totalDurationMs += durationMs;
|
|
1000
|
-
}
|
|
1001
|
-
/** Record a detection event */
|
|
1002
|
-
recordDetection(riskLevel, blocked, summary) {
|
|
1003
|
-
if (!this.enabled) return;
|
|
1004
|
-
this.pendingEvents.push({
|
|
1005
|
-
type: "detection",
|
|
1006
|
-
riskLevel,
|
|
1007
|
-
blocked,
|
|
1008
|
-
summary
|
|
1009
|
-
});
|
|
1010
|
-
if (riskLevel !== "no_risk" && riskLevel !== "low") this.hoursAccum.riskEventCount += 1;
|
|
1011
|
-
if (blocked) this.hoursAccum.blockCount += 1;
|
|
1012
|
-
this.maybeFlush();
|
|
1013
|
-
}
|
|
1014
|
-
/** Record a session start/end */
|
|
1015
|
-
recordSession(type, durationMs) {
|
|
1016
|
-
if (!this.enabled) return;
|
|
1017
|
-
this.pendingEvents.push({
|
|
1018
|
-
type: type === "start" ? "session_start" : "session_end",
|
|
1019
|
-
durationMs
|
|
1020
|
-
});
|
|
1021
|
-
if (type === "start") this.hoursAccum.sessionCount += 1;
|
|
1022
|
-
if (durationMs) this.hoursAccum.totalDurationMs += durationMs;
|
|
1023
|
-
}
|
|
1024
|
-
/** Record a scan result (static or dynamic) */
|
|
1025
|
-
recordScanResult(scanType, categories, risky) {
|
|
1026
|
-
if (!this.enabled) return;
|
|
1027
|
-
let accum = this.scanAccum.find((s) => s.scanType === scanType);
|
|
1028
|
-
if (!accum) {
|
|
1029
|
-
accum = {
|
|
1030
|
-
scanType,
|
|
1031
|
-
totalScans: 0,
|
|
1032
|
-
riskyScans: 0,
|
|
1033
|
-
categoryCounts: {}
|
|
1034
|
-
};
|
|
1035
|
-
this.scanAccum.push(accum);
|
|
1036
|
-
}
|
|
1037
|
-
accum.totalScans += 1;
|
|
1038
|
-
if (risky) accum.riskyScans += 1;
|
|
1039
|
-
for (const cat of categories) accum.categoryCounts[cat] = (accum.categoryCounts[cat] ?? 0) + 1;
|
|
1040
|
-
}
|
|
1041
|
-
/** Record gateway sanitization activity */
|
|
1042
|
-
recordGatewayActivity(redactionCount, typeCounts) {
|
|
1043
|
-
if (!this.enabled) return;
|
|
1044
|
-
this.gatewayAccum.totalRequests += 1;
|
|
1045
|
-
this.gatewayAccum.totalRedactions += redactionCount;
|
|
1046
|
-
for (const [k, v] of Object.entries(typeCounts)) this.gatewayAccum.typeCounts[k] = (this.gatewayAccum.typeCounts[k] ?? 0) + v;
|
|
1047
|
-
}
|
|
1048
|
-
/** Record secret detection */
|
|
1049
|
-
recordSecretDetection(typeCounts) {
|
|
1050
|
-
if (!this.enabled) return;
|
|
1051
|
-
const total = Object.values(typeCounts).reduce((a, b) => a + b, 0);
|
|
1052
|
-
this.secretAccum.totalDetections += total;
|
|
1053
|
-
for (const [k, v] of Object.entries(typeCounts)) this.secretAccum.typeCounts[k] = (this.secretAccum.typeCounts[k] ?? 0) + v;
|
|
1054
|
-
}
|
|
1055
|
-
startPeriodicFlush() {
|
|
1056
|
-
if (this.flushInterval) return;
|
|
1057
|
-
this.flushInterval = setInterval(() => {
|
|
1058
|
-
this.flush().catch((err) => {
|
|
1059
|
-
this.log.debug?.(`BusinessReporter: flush error: ${err}`);
|
|
1060
|
-
});
|
|
1061
|
-
}, FLUSH_INTERVAL_MS);
|
|
1062
|
-
this.flushInterval.unref();
|
|
1063
|
-
}
|
|
1064
|
-
maybeFlush() {
|
|
1065
|
-
if (this.pendingEvents.length >= MAX_BUFFERED_EVENTS) this.flush().catch((err) => {
|
|
1066
|
-
this.log.debug?.(`BusinessReporter: forced flush error: ${err}`);
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1069
|
-
async flush() {
|
|
1070
|
-
if (this.flushing || !this.enabled || !this.credentials) return;
|
|
1071
|
-
const hasEvents = this.pendingEvents.length > 0;
|
|
1072
|
-
const hasHours = this.hoursAccum.totalDurationMs > 0 || this.hoursAccum.toolCallCount > 0 || this.hoursAccum.llmCallCount > 0 || this.hoursAccum.sessionCount > 0;
|
|
1073
|
-
const hasScans = this.scanAccum.length > 0;
|
|
1074
|
-
const hasGateway = this.gatewayAccum.totalRequests > 0;
|
|
1075
|
-
const hasSecrets = this.secretAccum.totalDetections > 0;
|
|
1076
|
-
if (!hasEvents && !hasHours && !hasScans && !hasGateway && !hasSecrets) return;
|
|
1077
|
-
this.flushing = true;
|
|
1078
|
-
const events = this.pendingEvents.splice(0);
|
|
1079
|
-
const hours = { ...this.hoursAccum };
|
|
1080
|
-
this.hoursAccum = this.emptyAccum();
|
|
1081
|
-
const scans = this.scanAccum.splice(0);
|
|
1082
|
-
const gateway = { ...this.gatewayAccum };
|
|
1083
|
-
this.gatewayAccum = this.emptyGatewayAccum();
|
|
1084
|
-
const secrets = { ...this.secretAccum };
|
|
1085
|
-
this.secretAccum = this.emptySecretAccum();
|
|
1086
|
-
const controller = new AbortController();
|
|
1087
|
-
const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS$1);
|
|
1088
|
-
try {
|
|
1089
|
-
const body = {
|
|
1090
|
-
agentId: this.credentials.agentId,
|
|
1091
|
-
ownerName: this.ownerName || void 0,
|
|
1092
|
-
machineName: this.machineName,
|
|
1093
|
-
machineId: this.machineId,
|
|
1094
|
-
agentName: this.agentName || void 0,
|
|
1095
|
-
provider: this.provider || void 0,
|
|
1096
|
-
model: this.model || void 0,
|
|
1097
|
-
events: events.length > 0 ? events : void 0,
|
|
1098
|
-
agenticHours: hasHours ? hours : void 0,
|
|
1099
|
-
heartbeat: true,
|
|
1100
|
-
scanSummary: scans.length > 0 ? scans : void 0,
|
|
1101
|
-
gatewaySummary: hasGateway ? gateway : void 0,
|
|
1102
|
-
secretSummary: hasSecrets ? secrets : void 0
|
|
1103
|
-
};
|
|
1104
|
-
debugLog$1(`flush: POSTing to ${this.config.coreUrl}/api/v1/business/telemetry events=${events.length} hours=${JSON.stringify(hours)}`);
|
|
1105
|
-
const response = await fetch(`${this.config.coreUrl}/api/v1/business/telemetry`, {
|
|
1106
|
-
method: "POST",
|
|
1107
|
-
headers: {
|
|
1108
|
-
"Content-Type": "application/json",
|
|
1109
|
-
Authorization: `Bearer ${this.credentials.apiKey}`
|
|
1110
|
-
},
|
|
1111
|
-
body: JSON.stringify(body),
|
|
1112
|
-
signal: controller.signal
|
|
1113
|
-
});
|
|
1114
|
-
if (!response.ok) {
|
|
1115
|
-
debugLog$1(`flush: POST failed with ${response.status}`);
|
|
1116
|
-
this.log.debug?.(`BusinessReporter: telemetry request failed with ${response.status}`);
|
|
1117
|
-
this.pendingEvents.unshift(...events);
|
|
1118
|
-
if (this.pendingEvents.length > MAX_BUFFERED_EVENTS) this.pendingEvents.length = MAX_BUFFERED_EVENTS;
|
|
1119
|
-
} else {
|
|
1120
|
-
debugLog$1(`flush: POST success`);
|
|
1121
|
-
this.log.debug?.(`BusinessReporter: flushed ${events.length} events`);
|
|
1122
|
-
}
|
|
1123
|
-
} catch (err) {
|
|
1124
|
-
debugLog$1(`flush: POST error: ${err}`);
|
|
1125
|
-
if (err.name !== "AbortError") this.log.debug?.(`BusinessReporter: telemetry error: ${err}`);
|
|
1126
|
-
this.pendingEvents.unshift(...events);
|
|
1127
|
-
if (this.pendingEvents.length > MAX_BUFFERED_EVENTS) this.pendingEvents.length = MAX_BUFFERED_EVENTS;
|
|
1128
|
-
} finally {
|
|
1129
|
-
clearTimeout(timer);
|
|
1130
|
-
this.flushing = false;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
emptyAccum() {
|
|
1134
|
-
return {
|
|
1135
|
-
toolCallDurationMs: 0,
|
|
1136
|
-
llmDurationMs: 0,
|
|
1137
|
-
totalDurationMs: 0,
|
|
1138
|
-
toolCallCount: 0,
|
|
1139
|
-
llmCallCount: 0,
|
|
1140
|
-
sessionCount: 0,
|
|
1141
|
-
blockCount: 0,
|
|
1142
|
-
riskEventCount: 0
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
emptyGatewayAccum() {
|
|
1146
|
-
return {
|
|
1147
|
-
totalRequests: 0,
|
|
1148
|
-
totalRedactions: 0,
|
|
1149
|
-
typeCounts: {}
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
emptySecretAccum() {
|
|
1153
|
-
return {
|
|
1154
|
-
totalDetections: 0,
|
|
1155
|
-
typeCounts: {}
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
};
|
|
1159
|
-
/**
|
|
1160
|
-
* Generate a stable machine ID from hostname + first MAC address.
|
|
1161
|
-
* This identifies a specific machine across restarts.
|
|
1162
|
-
*/
|
|
1163
|
-
function generateMachineId() {
|
|
1164
|
-
const hostname = os.hostname();
|
|
1165
|
-
const interfaces = networkInterfaces();
|
|
1166
|
-
let mac = "";
|
|
1167
|
-
for (const iface of Object.values(interfaces)) {
|
|
1168
|
-
if (!iface) continue;
|
|
1169
|
-
for (const info of iface) if (!info.internal && info.mac && info.mac !== "00:00:00:00:00:00") {
|
|
1170
|
-
mac = info.mac;
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
if (mac) break;
|
|
1174
|
-
}
|
|
1175
|
-
const input = `${hostname}:${mac || "unknown"}`;
|
|
1176
|
-
return createHash("sha256").update(input).digest("hex").slice(0, 16);
|
|
1177
|
-
}
|
|
1178
|
-
//#endregion
|
|
1179
924
|
//#region extensions/cclawd-guard/agent/config-sync.ts
|
|
1180
925
|
/** Poll interval in ms (5 minutes) */
|
|
1181
926
|
const POLL_INTERVAL_MS = 5 * 6e4;
|
|
@@ -1638,26 +1383,6 @@ function debugLog(msg) {
|
|
|
1638
1383
|
fs.appendFileSync(DEBUG_LOG_PATH, `[${ts}] ${msg}\n`);
|
|
1639
1384
|
} catch {}
|
|
1640
1385
|
}
|
|
1641
|
-
/** Infer tool category from tool name for business reporting */
|
|
1642
|
-
function inferToolCategory(toolName) {
|
|
1643
|
-
const name = toolName.toLowerCase();
|
|
1644
|
-
if (FILE_READ_TOOLS.has(toolName) || FILE_READ_TOOLS.has(name)) return "file_read";
|
|
1645
|
-
if (WEB_FETCH_TOOLS.has(toolName) || WEB_FETCH_TOOLS.has(name)) return "web_fetch";
|
|
1646
|
-
if ([
|
|
1647
|
-
"bash",
|
|
1648
|
-
"shell",
|
|
1649
|
-
"run_command",
|
|
1650
|
-
"execute"
|
|
1651
|
-
].some((t) => name.includes(t))) return "shell";
|
|
1652
|
-
if ([
|
|
1653
|
-
"write",
|
|
1654
|
-
"edit",
|
|
1655
|
-
"create_file",
|
|
1656
|
-
"delete"
|
|
1657
|
-
].some((t) => name.includes(t))) return "file_write";
|
|
1658
|
-
if (name.includes("agent") || name.includes("subagent")) return "agent";
|
|
1659
|
-
return "other";
|
|
1660
|
-
}
|
|
1661
1386
|
/**
|
|
1662
1387
|
* Replace all injection matches in `text` with `__REDACTED_BY_CCLAWD_GUARD_DUE_TO_{riskType}__`.
|
|
1663
1388
|
*/
|
|
@@ -1733,7 +1458,6 @@ function createLogger(baseLogger) {
|
|
|
1733
1458
|
let globalCoreCredentials = null;
|
|
1734
1459
|
let globalBehaviorDetector = null;
|
|
1735
1460
|
let globalEventReporter = null;
|
|
1736
|
-
let globalBusinessReporter = null;
|
|
1737
1461
|
let globalConfigSync = null;
|
|
1738
1462
|
let globalDashboardClient = null;
|
|
1739
1463
|
let globalFileWatcher = null;
|
|
@@ -1969,30 +1693,6 @@ const openClawGuardPlugin = {
|
|
|
1969
1693
|
log.debug?.(`Account plan is "${plan}", business features not enabled`);
|
|
1970
1694
|
return;
|
|
1971
1695
|
}
|
|
1972
|
-
if (!globalBusinessReporter) {
|
|
1973
|
-
globalBusinessReporter = new BusinessReporter({
|
|
1974
|
-
coreUrl,
|
|
1975
|
-
pluginVersion: PLUGIN_VERSION
|
|
1976
|
-
}, log);
|
|
1977
|
-
globalBusinessReporter.setCredentials(globalCoreCredentials);
|
|
1978
|
-
const profile = readAgentProfile();
|
|
1979
|
-
globalBusinessReporter.setProfile({
|
|
1980
|
-
ownerName: profile.ownerName,
|
|
1981
|
-
agentName: config.agentName,
|
|
1982
|
-
provider: profile.provider,
|
|
1983
|
-
model: profile.model
|
|
1984
|
-
});
|
|
1985
|
-
globalBusinessReporter.initialize(plan);
|
|
1986
|
-
debugLog(`BusinessReporter initialized, enabled=${globalBusinessReporter.isEnabled()}`);
|
|
1987
|
-
if (globalBusinessReporter.isEnabled()) {
|
|
1988
|
-
setGatewayActivityCallback((redactionCount, typeCounts) => {
|
|
1989
|
-
globalBusinessReporter?.recordGatewayActivity(redactionCount, typeCounts);
|
|
1990
|
-
});
|
|
1991
|
-
globalBehaviorDetector?.setOnSecretDetected((typeCounts) => {
|
|
1992
|
-
globalBusinessReporter?.recordSecretDetection(typeCounts);
|
|
1993
|
-
});
|
|
1994
|
-
}
|
|
1995
|
-
}
|
|
1996
1696
|
if (!globalConfigSync) {
|
|
1997
1697
|
globalConfigSync = new ConfigSync({
|
|
1998
1698
|
coreUrl,
|
|
@@ -2057,7 +1757,6 @@ const openClawGuardPlugin = {
|
|
|
2057
1757
|
sessionId: event.sessionId ?? sessionKey,
|
|
2058
1758
|
durationMs: event.durationMs
|
|
2059
1759
|
});
|
|
2060
|
-
globalBusinessReporter?.recordSession("end", event.durationMs);
|
|
2061
1760
|
globalBehaviorDetector?.clearSession(sessionKey);
|
|
2062
1761
|
globalEventReporter?.clearSession(sessionKey);
|
|
2063
1762
|
});
|
|
@@ -2091,7 +1790,6 @@ const openClawGuardPlugin = {
|
|
|
2091
1790
|
log.debug?.(`Dashboard: report failed (before ${event.toolName}) — ${err}`);
|
|
2092
1791
|
});
|
|
2093
1792
|
if (blocked) {
|
|
2094
|
-
globalBusinessReporter?.recordToolCall(event.toolName, inferToolCategory(event.toolName), 0, true);
|
|
2095
1793
|
globalDashboardClient?.recordToolCallDuration(0, true);
|
|
2096
1794
|
return {
|
|
2097
1795
|
block: true,
|
|
@@ -2150,8 +1848,6 @@ const openClawGuardPlugin = {
|
|
|
2150
1848
|
const scanResult = await globalBehaviorDetector.scanContent(ctx.sessionKey ?? "", event.toolName, resultText);
|
|
2151
1849
|
if (scanResult?.detected) {
|
|
2152
1850
|
log.warn(`Core: injection detected in "${event.toolName}" result: ${scanResult.summary}`);
|
|
2153
|
-
globalBusinessReporter?.recordDetection(scanResult.detected ? "high" : "no_risk", false, scanResult.summary);
|
|
2154
|
-
globalBusinessReporter?.recordScanResult("dynamic", scanResult.categories ?? [], true);
|
|
2155
1851
|
globalDashboardClient?.recordRiskEvent();
|
|
2156
1852
|
}
|
|
2157
1853
|
if (scanResult && globalDashboardClient) {
|
|
@@ -2194,8 +1890,7 @@ const openClawGuardPlugin = {
|
|
|
2194
1890
|
}).catch((err) => {
|
|
2195
1891
|
log.debug?.(`Dashboard: report failed (after ${event.toolName}) — ${err}`);
|
|
2196
1892
|
});
|
|
2197
|
-
debugLog(`after_tool_call: tool=${event.toolName} durationMs=${event.durationMs} dashboardClient=${!!globalDashboardClient}
|
|
2198
|
-
globalBusinessReporter?.recordToolCall(event.toolName, inferToolCategory(event.toolName), event.durationMs ?? 0, false);
|
|
1893
|
+
debugLog(`after_tool_call: tool=${event.toolName} durationMs=${event.durationMs} dashboardClient=${!!globalDashboardClient}`);
|
|
2199
1894
|
globalDashboardClient?.recordToolCallDuration(event.durationMs ?? 0);
|
|
2200
1895
|
});
|
|
2201
1896
|
const apiAny = api;
|
|
@@ -2220,8 +1915,7 @@ const openClawGuardPlugin = {
|
|
|
2220
1915
|
sessionId,
|
|
2221
1916
|
isNew: event?.isNew ?? true
|
|
2222
1917
|
});
|
|
2223
|
-
debugLog(`session_start: sessionKey=${sessionKey} dashboardClient=${!!globalDashboardClient}
|
|
2224
|
-
globalBusinessReporter?.recordSession("start");
|
|
1918
|
+
debugLog(`session_start: sessionKey=${sessionKey} dashboardClient=${!!globalDashboardClient}`);
|
|
2225
1919
|
globalDashboardClient?.recordSessionStart();
|
|
2226
1920
|
});
|
|
2227
1921
|
apiAny.on("before_model_resolve", async (event, ctx) => {
|
|
@@ -2269,11 +1963,8 @@ const openClawGuardPlugin = {
|
|
|
2269
1963
|
latencyMs: llmDuration,
|
|
2270
1964
|
stopReason: event?.stopReason ?? event?.stop_reason
|
|
2271
1965
|
});
|
|
2272
|
-
debugLog(`llm_output: model=${event?.model} latencyMs=${event?.latencyMs} durationMs=${event?.durationMs} computed=${llmDuration} dashboardClient=${!!globalDashboardClient}
|
|
2273
|
-
if (llmDuration > 0)
|
|
2274
|
-
globalBusinessReporter?.recordLlmCall(llmDuration, event?.model);
|
|
2275
|
-
globalDashboardClient?.recordLlmDuration(llmDuration);
|
|
2276
|
-
}
|
|
1966
|
+
debugLog(`llm_output: model=${event?.model} latencyMs=${event?.latencyMs} durationMs=${event?.durationMs} computed=${llmDuration} dashboardClient=${!!globalDashboardClient}`);
|
|
1967
|
+
if (llmDuration > 0) globalDashboardClient?.recordLlmDuration(llmDuration);
|
|
2277
1968
|
});
|
|
2278
1969
|
api.on("message_sending", async (event, ctx) => {
|
|
2279
1970
|
const sessionKey = ctx.sessionKey ?? "";
|
|
@@ -2791,10 +2482,6 @@ const openClawGuardPlugin = {
|
|
|
2791
2482
|
log.warn(`Failed to report detection to dashboard: ${err}`);
|
|
2792
2483
|
});
|
|
2793
2484
|
} else if (!globalDashboardClient) log.warn("Dashboard client not initialized - scan results not reported to dashboard");
|
|
2794
|
-
if (globalBusinessReporter && batchResult.results) for (const fileResult of batchResult.results) {
|
|
2795
|
-
const categories = fileResult.findings?.map((f) => f.scanner) ?? [];
|
|
2796
|
-
globalBusinessReporter.recordScanResult("static", categories, fileResult.riskLevel !== "safe");
|
|
2797
|
-
}
|
|
2798
2485
|
}
|
|
2799
2486
|
const result = {
|
|
2800
2487
|
filesScanned: totalFilesScanned,
|
|
@@ -2896,10 +2583,6 @@ const openClawGuardPlugin = {
|
|
|
2896
2583
|
const riskCount = result.results.filter((r) => r.riskLevel !== "safe").length;
|
|
2897
2584
|
if (riskCount > 0) log.info(`Auto-scan found ${riskCount} file(s) with security risks`);
|
|
2898
2585
|
}
|
|
2899
|
-
if (globalBusinessReporter && result.results) for (const fileResult of result.results) {
|
|
2900
|
-
const categories = fileResult.findings?.map((f) => f.scanner) ?? [];
|
|
2901
|
-
globalBusinessReporter.recordScanResult("static", categories, fileResult.riskLevel !== "safe");
|
|
2902
|
-
}
|
|
2903
2586
|
} catch (err) {
|
|
2904
2587
|
log.debug?.(`Auto-scan failed: ${err}`);
|
|
2905
2588
|
}
|
|
@@ -3028,10 +2711,6 @@ const openClawGuardPlugin = {
|
|
|
3028
2711
|
await globalEventReporter.stop();
|
|
3029
2712
|
globalEventReporter = null;
|
|
3030
2713
|
}
|
|
3031
|
-
if (globalBusinessReporter) {
|
|
3032
|
-
await globalBusinessReporter.stop();
|
|
3033
|
-
globalBusinessReporter = null;
|
|
3034
|
-
}
|
|
3035
2714
|
if (globalConfigSync) {
|
|
3036
2715
|
globalConfigSync.stop();
|
|
3037
2716
|
globalConfigSync = null;
|
|
@@ -90,9 +90,9 @@
|
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
92
|
"node_modules/@napi-rs/wasm-runtime": {
|
|
93
|
-
"version": "1.1.
|
|
94
|
-
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.
|
|
95
|
-
"integrity": "sha512-
|
|
93
|
+
"version": "1.1.3",
|
|
94
|
+
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz",
|
|
95
|
+
"integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==",
|
|
96
96
|
"ideallyInert": true,
|
|
97
97
|
"license": "MIT",
|
|
98
98
|
"optional": true,
|
|
@@ -497,9 +497,9 @@
|
|
|
497
497
|
"license": "MIT"
|
|
498
498
|
},
|
|
499
499
|
"node_modules/qs": {
|
|
500
|
-
"version": "6.15.
|
|
501
|
-
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.
|
|
502
|
-
"integrity": "sha512-
|
|
500
|
+
"version": "6.15.1",
|
|
501
|
+
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
|
|
502
|
+
"integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
|
|
503
503
|
"license": "BSD-3-Clause",
|
|
504
504
|
"dependencies": {
|
|
505
505
|
"side-channel": "^1.1.0"
|
|
@@ -531,13 +531,13 @@
|
|
|
531
531
|
}
|
|
532
532
|
},
|
|
533
533
|
"node_modules/side-channel-list": {
|
|
534
|
-
"version": "1.0.
|
|
535
|
-
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.
|
|
536
|
-
"integrity": "sha512-
|
|
534
|
+
"version": "1.0.1",
|
|
535
|
+
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
|
|
536
|
+
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
|
|
537
537
|
"license": "MIT",
|
|
538
538
|
"dependencies": {
|
|
539
539
|
"es-errors": "^1.3.0",
|
|
540
|
-
"object-inspect": "^1.13.
|
|
540
|
+
"object-inspect": "^1.13.4"
|
|
541
541
|
},
|
|
542
542
|
"engines": {
|
|
543
543
|
"node": ">= 0.4"
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## **6.15.1**
|
|
2
|
+
- [Fix] `parse`: `parameterLimit: Infinity` with `throwOnLimitExceeded: true` silently drops all parameters
|
|
3
|
+
- [Deps] update `@ljharb/eslint-config`
|
|
4
|
+
- [Dev Deps] update `@ljharb/eslint-config`, `iconv-lite`
|
|
5
|
+
- [Tests] increase coverage
|
|
6
|
+
|
|
1
7
|
## **6.15.0**
|
|
2
8
|
- [New] `parse`: add `strictMerge` option to wrap object/primitive conflicts in an array (#425, #122)
|
|
3
9
|
- [Fix] `duplicates` option should not apply to bracket notation keys (#514)
|