averecion-lite 1.3.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.
Files changed (50) hide show
  1. package/README.md +161 -0
  2. package/dashboard/dash.css +1085 -0
  3. package/dashboard/dash.js +898 -0
  4. package/dashboard/index.html +312 -0
  5. package/dashboard/landing.html +360 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +409 -0
  9. package/dist/hooks.d.ts +25 -0
  10. package/dist/hooks.d.ts.map +1 -0
  11. package/dist/hooks.js +68 -0
  12. package/dist/index.d.ts +34 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +64 -0
  15. package/dist/injectionGuard.d.ts +9 -0
  16. package/dist/injectionGuard.d.ts.map +1 -0
  17. package/dist/injectionGuard.js +16 -0
  18. package/dist/log-watcher.d.ts +26 -0
  19. package/dist/log-watcher.d.ts.map +1 -0
  20. package/dist/log-watcher.js +397 -0
  21. package/dist/metrics.d.ts +53 -0
  22. package/dist/metrics.d.ts.map +1 -0
  23. package/dist/metrics.js +58 -0
  24. package/dist/policy.d.ts +11 -0
  25. package/dist/policy.d.ts.map +1 -0
  26. package/dist/policy.js +60 -0
  27. package/dist/server.d.ts +3 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +226 -0
  30. package/dist/src/capability-manifest.d.ts +16 -0
  31. package/dist/src/capability-manifest.d.ts.map +1 -0
  32. package/dist/src/capability-manifest.js +228 -0
  33. package/dist/src/http-proxy.d.ts +4 -0
  34. package/dist/src/http-proxy.d.ts.map +1 -0
  35. package/dist/src/http-proxy.js +266 -0
  36. package/dist/src/risk-engine.d.ts +43 -0
  37. package/dist/src/risk-engine.d.ts.map +1 -0
  38. package/dist/src/risk-engine.js +258 -0
  39. package/dist/src/shell-wrapper.d.ts +3 -0
  40. package/dist/src/shell-wrapper.d.ts.map +1 -0
  41. package/dist/src/shell-wrapper.js +264 -0
  42. package/dist/storage.d.ts +28 -0
  43. package/dist/storage.d.ts.map +1 -0
  44. package/dist/storage.js +144 -0
  45. package/examples/INTEGRATION.md +162 -0
  46. package/examples/claude-desktop-agent.json +32 -0
  47. package/examples/clawdbot-agent.json +44 -0
  48. package/examples/custom-agent.json +20 -0
  49. package/lite-policy.json +5 -0
  50. package/package.json +56 -0
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ const child_process_1 = require("child_process");
41
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
42
+ const CONFIG_FILE = path.join(CLAWGUARD_DIR, "config.json");
43
+ const LOG_DIR = path.join(CLAWGUARD_DIR, "logs");
44
+ const PENDING_DIR = path.join(CLAWGUARD_DIR, "pending");
45
+ const POLICY_FILE = path.join(CLAWGUARD_DIR, "policy.json");
46
+ const DEFAULT_POLICY = [
47
+ { pattern: "rm\\s+(-rf?|--recursive|--force)\\s+[\\/~]", decision: "block", reason: "Recursive delete from root or home", riskScore: 100 },
48
+ { pattern: "rm\\s+-[rf]{2}\\s+", decision: "block", reason: "Force recursive delete", riskScore: 100 },
49
+ { pattern: "mkfs\\.", decision: "block", reason: "Filesystem formatting", riskScore: 100 },
50
+ { pattern: "dd\\s+if=.*of=\\/dev", decision: "block", reason: "Direct disk write", riskScore: 100 },
51
+ { pattern: ">\\s*\\/dev\\/sd[a-z]", decision: "block", reason: "Direct device write", riskScore: 100 },
52
+ { pattern: "chmod\\s+777\\s+\\/", decision: "block", reason: "Dangerous permissions on root", riskScore: 90 },
53
+ { pattern: "curl.*\\|\\s*(ba)?sh", decision: "block", reason: "Pipe to shell execution", riskScore: 95 },
54
+ { pattern: "wget.*\\|\\s*(ba)?sh", decision: "block", reason: "Pipe to shell execution", riskScore: 95 },
55
+ { pattern: ":\\(\\)\\{.*\\}:", decision: "block", reason: "Fork bomb pattern", riskScore: 100 },
56
+ { pattern: "sudo\\s+rm", decision: "review", reason: "Privileged delete operation", riskScore: 80 },
57
+ { pattern: "sudo\\s+chmod", decision: "review", reason: "Privileged permission change", riskScore: 70 },
58
+ { pattern: "sudo\\s+chown", decision: "review", reason: "Privileged ownership change", riskScore: 70 },
59
+ { pattern: "npm\\s+install\\s+-g", decision: "review", reason: "Global package installation", riskScore: 50 },
60
+ { pattern: "pip\\s+install", decision: "review", reason: "Python package installation", riskScore: 40 },
61
+ { pattern: "ssh\\s+", decision: "review", reason: "Remote connection", riskScore: 60 },
62
+ { pattern: "scp\\s+", decision: "review", reason: "Remote file transfer", riskScore: 60 },
63
+ { pattern: "rsync\\s+", decision: "review", reason: "Remote sync operation", riskScore: 50 },
64
+ { pattern: "git\\s+push\\s+.*--force", decision: "review", reason: "Force push to remote", riskScore: 70 },
65
+ { pattern: "docker\\s+run", decision: "review", reason: "Container execution", riskScore: 50 },
66
+ { pattern: "systemctl\\s+(start|stop|restart|enable|disable)", decision: "review", reason: "Service management", riskScore: 60 },
67
+ ];
68
+ function ensureDir(dir) {
69
+ if (!fs.existsSync(dir)) {
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ }
72
+ }
73
+ function loadConfig() {
74
+ ensureDir(CLAWGUARD_DIR);
75
+ try {
76
+ if (fs.existsSync(CONFIG_FILE)) {
77
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
78
+ return {
79
+ enabled: config.enabled ?? true,
80
+ protectionLevel: config.protectionLevel ?? "balanced",
81
+ realShell: config.realShell ?? process.env.CLAWGUARD_REAL_SHELL ?? "/bin/bash"
82
+ };
83
+ }
84
+ }
85
+ catch { }
86
+ return {
87
+ enabled: true,
88
+ protectionLevel: "balanced",
89
+ realShell: process.env.CLAWGUARD_REAL_SHELL ?? "/bin/bash"
90
+ };
91
+ }
92
+ function loadPolicy() {
93
+ try {
94
+ if (fs.existsSync(POLICY_FILE)) {
95
+ return JSON.parse(fs.readFileSync(POLICY_FILE, "utf-8"));
96
+ }
97
+ }
98
+ catch { }
99
+ return DEFAULT_POLICY;
100
+ }
101
+ function logAction(command, allowed, reason, riskScore) {
102
+ ensureDir(LOG_DIR);
103
+ const logEntry = {
104
+ ts: new Date().toISOString(),
105
+ type: "shell",
106
+ command,
107
+ allowed,
108
+ reason,
109
+ riskScore,
110
+ pid: process.pid,
111
+ ppid: process.ppid
112
+ };
113
+ const logFile = path.join(LOG_DIR, `${new Date().toISOString().split("T")[0]}.jsonl`);
114
+ fs.appendFileSync(logFile, JSON.stringify(logEntry) + "\n");
115
+ }
116
+ function assessCommand(command) {
117
+ const policy = loadPolicy();
118
+ for (const rule of policy) {
119
+ try {
120
+ const regex = new RegExp(rule.pattern, "i");
121
+ if (regex.test(command)) {
122
+ return {
123
+ decision: rule.decision,
124
+ reason: rule.reason,
125
+ riskScore: rule.riskScore
126
+ };
127
+ }
128
+ }
129
+ catch { }
130
+ }
131
+ return { decision: "allow", reason: "No policy match", riskScore: 0 };
132
+ }
133
+ function generateApprovalId() {
134
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
135
+ }
136
+ function createPendingApproval(command, reason, riskScore) {
137
+ ensureDir(PENDING_DIR);
138
+ const id = generateApprovalId();
139
+ const approval = {
140
+ id,
141
+ type: "shell",
142
+ command,
143
+ reason,
144
+ riskScore,
145
+ createdAt: new Date().toISOString(),
146
+ status: "pending"
147
+ };
148
+ fs.writeFileSync(path.join(PENDING_DIR, `${id}.json`), JSON.stringify(approval, null, 2));
149
+ return id;
150
+ }
151
+ function checkApprovalStatus(id) {
152
+ const filePath = path.join(PENDING_DIR, `${id}.json`);
153
+ try {
154
+ if (fs.existsSync(filePath)) {
155
+ const approval = JSON.parse(fs.readFileSync(filePath, "utf-8"));
156
+ return approval.status;
157
+ }
158
+ }
159
+ catch { }
160
+ return "pending";
161
+ }
162
+ async function waitForApproval(id, command, timeoutMs = 30000) {
163
+ console.error(`\x1b[33m🛡️ Clawguard: Command requires approval\x1b[0m`);
164
+ console.error(` Command: ${command.substring(0, 100)}${command.length > 100 ? "..." : ""}`);
165
+ console.error(` Approve at: http://localhost:4321/clawguard`);
166
+ console.error(` Or run: clawguard approve ${id}`);
167
+ const startTime = Date.now();
168
+ const pollInterval = 500;
169
+ while (Date.now() - startTime < timeoutMs) {
170
+ const status = checkApprovalStatus(id);
171
+ if (status === "approved") {
172
+ console.error(`\x1b[32m🛡️ Command approved\x1b[0m`);
173
+ return true;
174
+ }
175
+ if (status === "denied") {
176
+ console.error(`\x1b[31m🛡️ Command denied\x1b[0m`);
177
+ return false;
178
+ }
179
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
180
+ }
181
+ console.error(`\x1b[31m🛡️ Approval timed out - command blocked\x1b[0m`);
182
+ return false;
183
+ }
184
+ async function executeCommand(command, config) {
185
+ return new Promise((resolve) => {
186
+ const options = {
187
+ shell: config.realShell,
188
+ stdio: "inherit",
189
+ env: {
190
+ ...process.env,
191
+ SHELL: config.realShell
192
+ }
193
+ };
194
+ const child = (0, child_process_1.spawn)(command, [], options);
195
+ child.on("close", (code) => {
196
+ resolve(code ?? 0);
197
+ });
198
+ child.on("error", (err) => {
199
+ console.error(`Error: ${err.message}`);
200
+ resolve(1);
201
+ });
202
+ });
203
+ }
204
+ async function main() {
205
+ const config = loadConfig();
206
+ const args = process.argv.slice(2);
207
+ if (args.length === 0) {
208
+ const child = (0, child_process_1.spawn)(config.realShell, [], {
209
+ stdio: "inherit",
210
+ env: { ...process.env, SHELL: config.realShell }
211
+ });
212
+ child.on("close", (code) => process.exit(code ?? 0));
213
+ return;
214
+ }
215
+ let command = "";
216
+ if (args[0] === "-c" && args[1]) {
217
+ command = args[1];
218
+ }
219
+ else {
220
+ command = args.join(" ");
221
+ }
222
+ if (!config.enabled) {
223
+ const exitCode = await executeCommand(command, config);
224
+ process.exit(exitCode);
225
+ return;
226
+ }
227
+ const assessment = assessCommand(command);
228
+ if (assessment.decision === "allow") {
229
+ logAction(command, true, assessment.reason, assessment.riskScore);
230
+ const exitCode = await executeCommand(command, config);
231
+ process.exit(exitCode);
232
+ return;
233
+ }
234
+ if (assessment.decision === "block") {
235
+ logAction(command, false, assessment.reason, assessment.riskScore);
236
+ console.error(`\x1b[31m🛡️ Clawguard: Command blocked\x1b[0m`);
237
+ console.error(` Reason: ${assessment.reason}`);
238
+ console.error(` Risk Score: ${assessment.riskScore}/100`);
239
+ process.exit(1);
240
+ return;
241
+ }
242
+ if (assessment.decision === "review") {
243
+ if (config.protectionLevel === "relaxed") {
244
+ logAction(command, true, "Relaxed mode - auto-approved", assessment.riskScore);
245
+ const exitCode = await executeCommand(command, config);
246
+ process.exit(exitCode);
247
+ return;
248
+ }
249
+ const approvalId = createPendingApproval(command, assessment.reason, assessment.riskScore);
250
+ const approved = await waitForApproval(approvalId, command);
251
+ logAction(command, approved, approved ? "Manual approval" : "Denied/timeout", assessment.riskScore);
252
+ if (approved) {
253
+ const exitCode = await executeCommand(command, config);
254
+ process.exit(exitCode);
255
+ }
256
+ else {
257
+ process.exit(1);
258
+ }
259
+ }
260
+ }
261
+ main().catch((err) => {
262
+ console.error(`Clawguard error: ${err.message}`);
263
+ process.exit(1);
264
+ });
@@ -0,0 +1,28 @@
1
+ export interface ActionEvent {
2
+ ts: string;
3
+ tool: string;
4
+ decision: "approved" | "blocked" | "manual";
5
+ reason: string;
6
+ egress: string[];
7
+ inputTokens?: number;
8
+ outputTokens?: number;
9
+ estimatedUSD?: number;
10
+ }
11
+ export declare function appendEvent(event: ActionEvent): void;
12
+ export declare function getEvents(hoursBack?: number): ActionEvent[];
13
+ export declare function getLastEvents(count?: number): ActionEvent[];
14
+ export declare function getConfig(): {
15
+ enabled: boolean;
16
+ showMode: boolean;
17
+ showModeActionsRemaining: number;
18
+ protectionLevel: string;
19
+ consented: boolean;
20
+ } | null;
21
+ export declare function getPendingApprovals(): {
22
+ id: string;
23
+ tool: string;
24
+ reason: string;
25
+ createdAt: string;
26
+ }[];
27
+ export declare function resolveApproval(id: string, approved: boolean): boolean;
28
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../storage.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2CD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,QAW7C;AAED,wBAAgB,SAAS,CAAC,SAAS,SAAK,GAAG,WAAW,EAAE,CAGvD;AAED,wBAAgB,aAAa,CAAC,KAAK,SAAK,GAAG,WAAW,EAAE,CAEvD;AAED,wBAAgB,SAAS,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,wBAAwB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAOzJ;AAED,wBAAgB,mBAAmB,IAAI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,CAgBvG;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAYtE"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.appendEvent = appendEvent;
37
+ exports.getEvents = getEvents;
38
+ exports.getLastEvents = getLastEvents;
39
+ exports.getConfig = getConfig;
40
+ exports.getPendingApprovals = getPendingApprovals;
41
+ exports.resolveApproval = resolveApproval;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
45
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
46
+ const LOGS_DIR = path.join(CLAWGUARD_DIR, "logs");
47
+ const CONFIG_FILE = path.join(CLAWGUARD_DIR, "config.json");
48
+ const PENDING_DIR = path.join(CLAWGUARD_DIR, "pending");
49
+ function ensureDir() {
50
+ if (!fs.existsSync(CLAWGUARD_DIR))
51
+ fs.mkdirSync(CLAWGUARD_DIR, { recursive: true });
52
+ if (!fs.existsSync(LOGS_DIR))
53
+ fs.mkdirSync(LOGS_DIR, { recursive: true });
54
+ }
55
+ function loadLogsFromJsonl() {
56
+ ensureDir();
57
+ const events = [];
58
+ try {
59
+ const files = fs.readdirSync(LOGS_DIR).filter(f => f.endsWith(".jsonl")).sort();
60
+ for (const file of files) {
61
+ const content = fs.readFileSync(path.join(LOGS_DIR, file), "utf-8");
62
+ for (const line of content.trim().split("\n")) {
63
+ if (!line)
64
+ continue;
65
+ try {
66
+ const entry = JSON.parse(line);
67
+ if (entry.phase === "after")
68
+ continue;
69
+ events.push({
70
+ ts: entry.ts,
71
+ tool: entry.tool,
72
+ decision: entry.allowed === false ? "blocked" : (entry.reason === "manualApproval" ? "manual" : "approved"),
73
+ reason: entry.reason || "",
74
+ egress: [],
75
+ inputTokens: entry.inputTokens,
76
+ outputTokens: entry.outputTokens,
77
+ estimatedUSD: entry.estimatedUSD
78
+ });
79
+ }
80
+ catch { }
81
+ }
82
+ }
83
+ }
84
+ catch { }
85
+ return events;
86
+ }
87
+ function appendEvent(event) {
88
+ ensureDir();
89
+ const logFile = path.join(LOGS_DIR, `${new Date().toISOString().split("T")[0]}.jsonl`);
90
+ const logEntry = {
91
+ ts: event.ts,
92
+ tool: event.tool,
93
+ allowed: event.decision !== "blocked",
94
+ reason: event.reason,
95
+ egress: event.egress
96
+ };
97
+ fs.appendFileSync(logFile, JSON.stringify(logEntry) + "\n");
98
+ }
99
+ function getEvents(hoursBack = 24) {
100
+ const cutoff = new Date(Date.now() - hoursBack * 3600000).toISOString();
101
+ return loadLogsFromJsonl().filter(e => e.ts >= cutoff);
102
+ }
103
+ function getLastEvents(count = 10) {
104
+ return loadLogsFromJsonl().slice(-count);
105
+ }
106
+ function getConfig() {
107
+ try {
108
+ if (fs.existsSync(CONFIG_FILE)) {
109
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
110
+ }
111
+ }
112
+ catch { }
113
+ return null;
114
+ }
115
+ function getPendingApprovals() {
116
+ if (!fs.existsSync(PENDING_DIR))
117
+ return [];
118
+ const approvals = [];
119
+ const files = fs.readdirSync(PENDING_DIR).filter(f => f.endsWith(".json"));
120
+ for (const file of files) {
121
+ try {
122
+ const data = JSON.parse(fs.readFileSync(path.join(PENDING_DIR, file), "utf-8"));
123
+ if (data.status === "pending") {
124
+ approvals.push({ id: data.id, tool: data.tool, reason: data.reason, createdAt: data.createdAt });
125
+ }
126
+ }
127
+ catch { }
128
+ }
129
+ return approvals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
130
+ }
131
+ function resolveApproval(id, approved) {
132
+ const filePath = path.join(PENDING_DIR, `${id}.json`);
133
+ try {
134
+ if (fs.existsSync(filePath)) {
135
+ const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
136
+ data.status = approved ? "approved" : "denied";
137
+ data.resolvedAt = new Date().toISOString();
138
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
139
+ return true;
140
+ }
141
+ }
142
+ catch { }
143
+ return false;
144
+ }
@@ -0,0 +1,162 @@
1
+ # Clawguard Integration Examples
2
+
3
+ Clawguard is agent-agnostic - it works with any AI agent framework by intercepting actions at the execution boundary (shell commands, HTTP requests, file operations) rather than hooking into specific agent internals.
4
+
5
+ ## Installation Methods
6
+
7
+ ### 1. Shell Wrapper (Recommended)
8
+
9
+ The shell wrapper intercepts all terminal commands before execution:
10
+
11
+ ```bash
12
+ # Install the shell wrapper
13
+ clawguard install-shell
14
+
15
+ # For any agent, set the SHELL environment variable:
16
+ SHELL=~/.local/bin/clawguard-sh your-agent-command
17
+ ```
18
+
19
+ ### 2. HTTP Proxy
20
+
21
+ Monitor and control outbound API calls:
22
+
23
+ ```bash
24
+ # Start the HTTP proxy (runs on port 4322)
25
+ clawguard start
26
+
27
+ # Configure your agent to use the proxy:
28
+ HTTP_PROXY=http://localhost:4322 your-agent-command
29
+ HTTPS_PROXY=http://localhost:4322 your-agent-command
30
+ ```
31
+
32
+ ### 3. Direct API Integration
33
+
34
+ For programmatic integration, use the governance API:
35
+
36
+ ```javascript
37
+ // Check if an action should be allowed
38
+ const response = await fetch('http://localhost:4321/api/assess-action', {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'X-Lite-Secret': process.env.CLAWGUARD_SECRET
43
+ },
44
+ body: JSON.stringify({
45
+ type: 'shell',
46
+ command: 'rm -rf /tmp/cache',
47
+ agentId: 'my-agent'
48
+ })
49
+ });
50
+
51
+ const { decision, riskScore, reason } = await response.json();
52
+ // decision: 'allow' | 'block' | 'require_approval'
53
+ ```
54
+
55
+ ## Agent Manifest Registration
56
+
57
+ Register your agent's capabilities for static risk assessment:
58
+
59
+ ```bash
60
+ # Create a manifest file (see examples/*.json)
61
+ clawguard agent register ./my-agent-manifest.json
62
+ ```
63
+
64
+ Example manifest:
65
+ ```json
66
+ {
67
+ "id": "my-agent",
68
+ "name": "My Custom Agent",
69
+ "version": "1.0.0",
70
+ "framework": "custom",
71
+ "capabilities": [
72
+ {
73
+ "name": "web_search",
74
+ "type": "http",
75
+ "description": "Search the web",
76
+ "riskWeight": 25
77
+ },
78
+ {
79
+ "name": "file_read",
80
+ "type": "filesystem",
81
+ "description": "Read local files",
82
+ "riskWeight": 20
83
+ }
84
+ ]
85
+ }
86
+ ```
87
+
88
+ ## Framework-Specific Examples
89
+
90
+ ### ClawdBot
91
+
92
+ ```bash
93
+ # Register ClawdBot with Clawguard
94
+ clawguard agent register ./examples/clawdbot-agent.json
95
+
96
+ # Run ClawdBot through the shell wrapper
97
+ SHELL=~/.local/bin/clawguard-sh clawdbot run
98
+ ```
99
+
100
+ ### Claude Desktop (MCP)
101
+
102
+ ```bash
103
+ # Register Claude Desktop
104
+ clawguard agent register ./examples/claude-desktop-agent.json
105
+
106
+ # Claude Desktop uses MCP tools - intercept at shell level
107
+ SHELL=~/.local/bin/clawguard-sh claude-desktop
108
+ ```
109
+
110
+ ### LangChain
111
+
112
+ ```python
113
+ # For LangChain, wrap tool execution with governance checks
114
+ import requests
115
+
116
+ def governed_tool_call(tool_name, **kwargs):
117
+ # Check with Clawguard first
118
+ response = requests.post('http://localhost:4321/api/assess-action', json={
119
+ 'type': 'tool',
120
+ 'tool': tool_name,
121
+ 'agentId': 'langchain-agent'
122
+ }, headers={'X-Lite-Secret': os.environ['CLAWGUARD_SECRET']})
123
+
124
+ result = response.json()
125
+ if result['decision'] == 'block':
126
+ raise PermissionError(f"Action blocked: {result['reason']}")
127
+
128
+ # Execute the tool
129
+ return original_tool_call(tool_name, **kwargs)
130
+ ```
131
+
132
+ ### AutoGPT
133
+
134
+ ```bash
135
+ # Run AutoGPT with shell interception
136
+ SHELL=~/.local/bin/clawguard-sh \
137
+ HTTP_PROXY=http://localhost:4322 \
138
+ autogpt run
139
+ ```
140
+
141
+ ## CLI Commands
142
+
143
+ ```bash
144
+ clawguard start # Start the dashboard server
145
+ clawguard agents # List registered agents
146
+ clawguard agent register <manifest.json> # Register an agent
147
+ clawguard pending # Show pending approvals
148
+ clawguard approve <id> # Approve a pending action
149
+ clawguard deny <id> # Deny a pending action
150
+ clawguard install-shell # Install the shell wrapper
151
+ ```
152
+
153
+ ## Dashboard
154
+
155
+ Access the visual dashboard at `http://localhost:4321/clawguard`
156
+
157
+ Features:
158
+ - View registered agents with risk scores
159
+ - Real-time activity monitoring
160
+ - Pending approval workflow
161
+ - Protection level configuration
162
+ - Capability breakdown for each agent
@@ -0,0 +1,32 @@
1
+ {
2
+ "id": "claude-desktop",
3
+ "name": "Claude Desktop",
4
+ "version": "1.0.0",
5
+ "framework": "claude-desktop",
6
+ "capabilities": [
7
+ {
8
+ "name": "computer",
9
+ "type": "shell",
10
+ "description": "Computer use - full system access",
11
+ "riskWeight": 95
12
+ },
13
+ {
14
+ "name": "bash",
15
+ "type": "shell",
16
+ "description": "Bash command execution",
17
+ "riskWeight": 80
18
+ },
19
+ {
20
+ "name": "text_editor",
21
+ "type": "filesystem",
22
+ "description": "Text file editing",
23
+ "riskWeight": 50
24
+ },
25
+ {
26
+ "name": "browser",
27
+ "type": "network",
28
+ "description": "Web browsing capability",
29
+ "riskWeight": 40
30
+ }
31
+ ]
32
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "clawdbot-main",
3
+ "name": "ClawdBot Main Agent",
4
+ "version": "2026.1.24",
5
+ "framework": "clawdbot",
6
+ "capabilities": [
7
+ {
8
+ "name": "exec",
9
+ "type": "shell",
10
+ "description": "Execute shell commands",
11
+ "riskWeight": 80
12
+ },
13
+ {
14
+ "name": "read",
15
+ "type": "filesystem",
16
+ "description": "Read files from disk",
17
+ "riskWeight": 20
18
+ },
19
+ {
20
+ "name": "write",
21
+ "type": "filesystem",
22
+ "description": "Write files to disk",
23
+ "riskWeight": 50
24
+ },
25
+ {
26
+ "name": "process",
27
+ "type": "process",
28
+ "description": "Process management (list, kill)",
29
+ "riskWeight": 60
30
+ },
31
+ {
32
+ "name": "http",
33
+ "type": "http",
34
+ "description": "Make HTTP requests",
35
+ "riskWeight": 30
36
+ },
37
+ {
38
+ "name": "memory",
39
+ "type": "custom",
40
+ "description": "Long-term memory storage",
41
+ "riskWeight": 20
42
+ }
43
+ ]
44
+ }