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,266 @@
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.createProxyServer = createProxyServer;
37
+ exports.getProxyEnvVars = getProxyEnvVars;
38
+ const http = __importStar(require("http"));
39
+ const https = __importStar(require("https"));
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const os = __importStar(require("os"));
43
+ const url = __importStar(require("url"));
44
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
45
+ const CONFIG_FILE = path.join(CLAWGUARD_DIR, "config.json");
46
+ const LOG_DIR = path.join(CLAWGUARD_DIR, "logs");
47
+ const PENDING_DIR = path.join(CLAWGUARD_DIR, "pending");
48
+ const DEFAULT_URL_POLICY = [
49
+ { pattern: "api\\.stripe\\.com", decision: "review", reason: "Payment API", riskScore: 80 },
50
+ { pattern: "api\\.paypal\\.com", decision: "review", reason: "Payment API", riskScore: 80 },
51
+ { pattern: "api\\.braintree", decision: "review", reason: "Payment API", riskScore: 80 },
52
+ { pattern: "plaid\\.com", decision: "review", reason: "Financial API", riskScore: 75 },
53
+ { pattern: "api\\.twilio\\.com", decision: "review", reason: "SMS/Communication API", riskScore: 60 },
54
+ { pattern: "api\\.sendgrid\\.com", decision: "review", reason: "Email API", riskScore: 50 },
55
+ { pattern: "smtp\\.", decision: "review", reason: "Email SMTP", riskScore: 50 },
56
+ { pattern: "api\\.github\\.com.*repos.*delete", decision: "review", reason: "GitHub repo deletion", riskScore: 90 },
57
+ { pattern: "api\\.github\\.com.*settings", decision: "review", reason: "GitHub settings change", riskScore: 70 },
58
+ { pattern: "console\\.aws\\.amazon\\.com", decision: "review", reason: "AWS Console", riskScore: 85 },
59
+ { pattern: "api\\.openai\\.com", decision: "allow", reason: "AI API", riskScore: 30 },
60
+ { pattern: "api\\.anthropic\\.com", decision: "allow", reason: "AI API", riskScore: 30 },
61
+ { pattern: "api\\.google\\.com", decision: "allow", reason: "Google API", riskScore: 25 },
62
+ { pattern: "localhost|127\\.0\\.0\\.1", decision: "allow", reason: "Local service", riskScore: 10 },
63
+ ];
64
+ function ensureDir(dir) {
65
+ if (!fs.existsSync(dir)) {
66
+ fs.mkdirSync(dir, { recursive: true });
67
+ }
68
+ }
69
+ function loadConfig() {
70
+ ensureDir(CLAWGUARD_DIR);
71
+ try {
72
+ if (fs.existsSync(CONFIG_FILE)) {
73
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
74
+ return {
75
+ enabled: config.enabled ?? true,
76
+ protectionLevel: config.protectionLevel ?? "balanced",
77
+ port: config.proxyPort ?? 4322,
78
+ allowedDomains: config.allowedDomains,
79
+ blockedDomains: config.blockedDomains
80
+ };
81
+ }
82
+ }
83
+ catch { }
84
+ return {
85
+ enabled: true,
86
+ protectionLevel: "balanced",
87
+ port: 4322
88
+ };
89
+ }
90
+ function logRequest(method, targetUrl, allowed, reason, riskScore) {
91
+ ensureDir(LOG_DIR);
92
+ const logEntry = {
93
+ ts: new Date().toISOString(),
94
+ type: "http",
95
+ method,
96
+ url: targetUrl,
97
+ allowed,
98
+ reason,
99
+ riskScore
100
+ };
101
+ const logFile = path.join(LOG_DIR, `${new Date().toISOString().split("T")[0]}.jsonl`);
102
+ fs.appendFileSync(logFile, JSON.stringify(logEntry) + "\n");
103
+ }
104
+ function assessUrl(targetUrl) {
105
+ const config = loadConfig();
106
+ if (config.blockedDomains) {
107
+ for (const domain of config.blockedDomains) {
108
+ if (targetUrl.includes(domain)) {
109
+ return { decision: "block", reason: `Domain in blocklist: ${domain}`, riskScore: 100 };
110
+ }
111
+ }
112
+ }
113
+ if (config.allowedDomains && config.allowedDomains.length > 0) {
114
+ const isAllowed = config.allowedDomains.some(domain => targetUrl.includes(domain));
115
+ if (!isAllowed) {
116
+ return { decision: "block", reason: "Domain not in allowlist", riskScore: 80 };
117
+ }
118
+ }
119
+ for (const rule of DEFAULT_URL_POLICY) {
120
+ try {
121
+ const regex = new RegExp(rule.pattern, "i");
122
+ if (regex.test(targetUrl)) {
123
+ return {
124
+ decision: rule.decision,
125
+ reason: rule.reason,
126
+ riskScore: rule.riskScore
127
+ };
128
+ }
129
+ }
130
+ catch { }
131
+ }
132
+ return { decision: "allow", reason: "No policy match", riskScore: 20 };
133
+ }
134
+ function generateApprovalId() {
135
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
136
+ }
137
+ function createPendingApproval(method, targetUrl, reason, riskScore) {
138
+ ensureDir(PENDING_DIR);
139
+ const id = generateApprovalId();
140
+ const approval = {
141
+ id,
142
+ type: "http",
143
+ method,
144
+ url: targetUrl,
145
+ reason,
146
+ riskScore,
147
+ createdAt: new Date().toISOString(),
148
+ status: "pending"
149
+ };
150
+ fs.writeFileSync(path.join(PENDING_DIR, `${id}.json`), JSON.stringify(approval, null, 2));
151
+ return id;
152
+ }
153
+ function checkApprovalStatus(id) {
154
+ const filePath = path.join(PENDING_DIR, `${id}.json`);
155
+ try {
156
+ if (fs.existsSync(filePath)) {
157
+ const approval = JSON.parse(fs.readFileSync(filePath, "utf-8"));
158
+ return approval.status;
159
+ }
160
+ }
161
+ catch { }
162
+ return "pending";
163
+ }
164
+ async function waitForApproval(id, timeoutMs = 30000) {
165
+ const startTime = Date.now();
166
+ const pollInterval = 500;
167
+ while (Date.now() - startTime < timeoutMs) {
168
+ const status = checkApprovalStatus(id);
169
+ if (status === "approved")
170
+ return true;
171
+ if (status === "denied")
172
+ return false;
173
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
174
+ }
175
+ return false;
176
+ }
177
+ function proxyRequest(clientReq, clientRes, targetUrl) {
178
+ const parsedUrl = new url.URL(targetUrl);
179
+ const isHttps = parsedUrl.protocol === "https:";
180
+ const options = {
181
+ hostname: parsedUrl.hostname,
182
+ port: parsedUrl.port || (isHttps ? 443 : 80),
183
+ path: parsedUrl.pathname + parsedUrl.search,
184
+ method: clientReq.method,
185
+ headers: {
186
+ ...clientReq.headers,
187
+ host: parsedUrl.host
188
+ }
189
+ };
190
+ const proxyReq = (isHttps ? https : http).request(options, (proxyRes) => {
191
+ clientRes.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
192
+ proxyRes.pipe(clientRes);
193
+ });
194
+ proxyReq.on("error", (err) => {
195
+ console.error(`Proxy error: ${err.message}`);
196
+ clientRes.writeHead(502);
197
+ clientRes.end(`Proxy Error: ${err.message}`);
198
+ });
199
+ clientReq.pipe(proxyReq);
200
+ }
201
+ function createProxyServer(port) {
202
+ const config = loadConfig();
203
+ const proxyPort = port ?? config.port;
204
+ const server = http.createServer(async (req, res) => {
205
+ const targetUrl = req.url || "";
206
+ const method = req.method || "GET";
207
+ if (!config.enabled) {
208
+ proxyRequest(req, res, targetUrl);
209
+ return;
210
+ }
211
+ const assessment = assessUrl(targetUrl);
212
+ if (assessment.decision === "allow") {
213
+ logRequest(method, targetUrl, true, assessment.reason, assessment.riskScore);
214
+ proxyRequest(req, res, targetUrl);
215
+ return;
216
+ }
217
+ if (assessment.decision === "block") {
218
+ logRequest(method, targetUrl, false, assessment.reason, assessment.riskScore);
219
+ res.writeHead(403, { "Content-Type": "application/json" });
220
+ res.end(JSON.stringify({
221
+ error: "Blocked by Clawguard",
222
+ reason: assessment.reason,
223
+ riskScore: assessment.riskScore
224
+ }));
225
+ return;
226
+ }
227
+ if (assessment.decision === "review") {
228
+ if (config.protectionLevel === "relaxed") {
229
+ logRequest(method, targetUrl, true, "Relaxed mode - auto-approved", assessment.riskScore);
230
+ proxyRequest(req, res, targetUrl);
231
+ return;
232
+ }
233
+ const approvalId = createPendingApproval(method, targetUrl, assessment.reason, assessment.riskScore);
234
+ console.log(`🛡️ HTTP request requires approval: ${method} ${targetUrl.substring(0, 60)}...`);
235
+ console.log(` Approve at: http://localhost:4321/clawguard`);
236
+ const approved = await waitForApproval(approvalId);
237
+ logRequest(method, targetUrl, approved, approved ? "Manual approval" : "Denied/timeout", assessment.riskScore);
238
+ if (approved) {
239
+ proxyRequest(req, res, targetUrl);
240
+ }
241
+ else {
242
+ res.writeHead(403, { "Content-Type": "application/json" });
243
+ res.end(JSON.stringify({
244
+ error: "Request denied or timed out",
245
+ reason: assessment.reason
246
+ }));
247
+ }
248
+ }
249
+ });
250
+ server.listen(proxyPort, () => {
251
+ console.log(`🛡️ Clawguard HTTP proxy listening on port ${proxyPort}`);
252
+ console.log(` Set HTTP_PROXY=http://localhost:${proxyPort} to enable`);
253
+ });
254
+ return server;
255
+ }
256
+ function getProxyEnvVars(port) {
257
+ const config = loadConfig();
258
+ const proxyPort = port ?? config.port;
259
+ const proxyUrl = `http://localhost:${proxyPort}`;
260
+ return {
261
+ HTTP_PROXY: proxyUrl,
262
+ HTTPS_PROXY: proxyUrl,
263
+ http_proxy: proxyUrl,
264
+ https_proxy: proxyUrl
265
+ };
266
+ }
@@ -0,0 +1,43 @@
1
+ export interface AgentCapability {
2
+ name: string;
3
+ type: "shell" | "http" | "filesystem" | "process" | "network" | "code" | "custom";
4
+ description?: string;
5
+ permissions?: string[];
6
+ riskWeight: number;
7
+ }
8
+ export interface AgentManifest {
9
+ id: string;
10
+ name: string;
11
+ version?: string;
12
+ framework?: string;
13
+ capabilities: AgentCapability[];
14
+ registeredAt: string;
15
+ lastSeen?: string;
16
+ }
17
+ export interface RiskAssessment {
18
+ overallScore: number;
19
+ riskLevel: "low" | "medium" | "high" | "critical";
20
+ breakdown: {
21
+ capability: string;
22
+ score: number;
23
+ reason: string;
24
+ }[];
25
+ recommendations: string[];
26
+ }
27
+ export declare function registerAgent(manifest: Omit<AgentManifest, "registeredAt">): AgentManifest;
28
+ export declare function getAgent(id: string): AgentManifest | null;
29
+ export declare function listAgents(): AgentManifest[];
30
+ export declare function updateAgentLastSeen(id: string): void;
31
+ export declare function assessAgentRisk(manifest: AgentManifest): RiskAssessment;
32
+ export declare function assessActionRisk(action: {
33
+ type: string;
34
+ tool?: string;
35
+ command?: string;
36
+ url?: string;
37
+ path?: string;
38
+ }, agentId?: string): {
39
+ score: number;
40
+ level: "low" | "medium" | "high" | "critical";
41
+ reason: string;
42
+ };
43
+ //# sourceMappingURL=risk-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-engine.d.ts","sourceRoot":"","sources":["../../src/risk-engine.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAClD,SAAS,EAAE;QACT,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,EAAE,CAAC;IACJ,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAmCD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,GAAG,aAAa,CAa1F;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAQzD;AAED,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAe5C;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAOpD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,GAAG,cAAc,CA6DvE;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACtF,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAuFlF"}
@@ -0,0 +1,258 @@
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.registerAgent = registerAgent;
37
+ exports.getAgent = getAgent;
38
+ exports.listAgents = listAgents;
39
+ exports.updateAgentLastSeen = updateAgentLastSeen;
40
+ exports.assessAgentRisk = assessAgentRisk;
41
+ exports.assessActionRisk = assessActionRisk;
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 AGENTS_DIR = path.join(CLAWGUARD_DIR, "agents");
47
+ const CAPABILITY_RISK_WEIGHTS = {
48
+ "shell.execute": 80,
49
+ "shell.sudo": 100,
50
+ "filesystem.read": 20,
51
+ "filesystem.write": 50,
52
+ "filesystem.delete": 70,
53
+ "filesystem.chmod": 60,
54
+ "network.http": 30,
55
+ "network.https": 25,
56
+ "network.tcp": 50,
57
+ "network.udp": 50,
58
+ "process.spawn": 60,
59
+ "process.kill": 70,
60
+ "database.read": 30,
61
+ "database.write": 50,
62
+ "database.admin": 80,
63
+ "secrets.read": 90,
64
+ "secrets.write": 95,
65
+ "email.send": 40,
66
+ "sms.send": 50,
67
+ "payment.charge": 90,
68
+ "code.execute": 85,
69
+ "browser.navigate": 40,
70
+ "browser.screenshot": 30,
71
+ "mcp.callTool": 50,
72
+ };
73
+ function ensureDir(dir) {
74
+ if (!fs.existsSync(dir)) {
75
+ fs.mkdirSync(dir, { recursive: true });
76
+ }
77
+ }
78
+ function registerAgent(manifest) {
79
+ ensureDir(AGENTS_DIR);
80
+ const fullManifest = {
81
+ ...manifest,
82
+ registeredAt: new Date().toISOString(),
83
+ lastSeen: new Date().toISOString()
84
+ };
85
+ const filePath = path.join(AGENTS_DIR, `${manifest.id}.json`);
86
+ fs.writeFileSync(filePath, JSON.stringify(fullManifest, null, 2));
87
+ return fullManifest;
88
+ }
89
+ function getAgent(id) {
90
+ const filePath = path.join(AGENTS_DIR, `${id}.json`);
91
+ try {
92
+ if (fs.existsSync(filePath)) {
93
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
94
+ }
95
+ }
96
+ catch { }
97
+ return null;
98
+ }
99
+ function listAgents() {
100
+ ensureDir(AGENTS_DIR);
101
+ const agents = [];
102
+ try {
103
+ const files = fs.readdirSync(AGENTS_DIR).filter(f => f.endsWith(".json"));
104
+ for (const file of files) {
105
+ try {
106
+ const content = fs.readFileSync(path.join(AGENTS_DIR, file), "utf-8");
107
+ agents.push(JSON.parse(content));
108
+ }
109
+ catch { }
110
+ }
111
+ }
112
+ catch { }
113
+ return agents;
114
+ }
115
+ function updateAgentLastSeen(id) {
116
+ const agent = getAgent(id);
117
+ if (agent) {
118
+ agent.lastSeen = new Date().toISOString();
119
+ const filePath = path.join(AGENTS_DIR, `${id}.json`);
120
+ fs.writeFileSync(filePath, JSON.stringify(agent, null, 2));
121
+ }
122
+ }
123
+ function assessAgentRisk(manifest) {
124
+ const breakdown = [];
125
+ let totalScore = 0;
126
+ let maxPossibleScore = 0;
127
+ for (const capability of manifest.capabilities) {
128
+ const capabilityKey = `${capability.type}.${capability.name}`;
129
+ const weight = CAPABILITY_RISK_WEIGHTS[capabilityKey] ??
130
+ CAPABILITY_RISK_WEIGHTS[capability.type] ??
131
+ capability.riskWeight ?? 50;
132
+ breakdown.push({
133
+ capability: capability.name,
134
+ score: weight,
135
+ reason: capability.description ?? `${capability.type} capability`
136
+ });
137
+ totalScore += weight;
138
+ maxPossibleScore += 100;
139
+ }
140
+ const normalizedScore = maxPossibleScore > 0
141
+ ? Math.round((totalScore / maxPossibleScore) * 100)
142
+ : 0;
143
+ let riskLevel;
144
+ if (normalizedScore >= 80) {
145
+ riskLevel = "critical";
146
+ }
147
+ else if (normalizedScore >= 60) {
148
+ riskLevel = "high";
149
+ }
150
+ else if (normalizedScore >= 40) {
151
+ riskLevel = "medium";
152
+ }
153
+ else {
154
+ riskLevel = "low";
155
+ }
156
+ const recommendations = [];
157
+ const hasShellExecute = manifest.capabilities.some(c => c.type === "shell");
158
+ const hasSecrets = manifest.capabilities.some(c => c.name.includes("secret") || c.name.includes("credential"));
159
+ const hasPayment = manifest.capabilities.some(c => c.name.includes("payment") || c.name.includes("charge"));
160
+ if (hasShellExecute) {
161
+ recommendations.push("Consider restricting shell access to specific commands only");
162
+ }
163
+ if (hasSecrets) {
164
+ recommendations.push("Enable strict mode for secret access operations");
165
+ }
166
+ if (hasPayment) {
167
+ recommendations.push("Require manual approval for all payment operations");
168
+ }
169
+ if (riskLevel === "critical") {
170
+ recommendations.push("This agent has critical risk level - review all capabilities carefully");
171
+ }
172
+ return {
173
+ overallScore: normalizedScore,
174
+ riskLevel,
175
+ breakdown: breakdown.sort((a, b) => b.score - a.score),
176
+ recommendations
177
+ };
178
+ }
179
+ function assessActionRisk(action, agentId) {
180
+ let score = 0;
181
+ let reason = "Unknown action";
182
+ if (action.type === "shell" && action.command) {
183
+ const dangerousPatterns = [
184
+ { pattern: /rm\s+(-rf|--force)/i, score: 90, reason: "Force delete command" },
185
+ { pattern: /sudo/i, score: 70, reason: "Privileged command" },
186
+ { pattern: /curl.*\|\s*sh/i, score: 95, reason: "Remote code execution" },
187
+ { pattern: /chmod\s+777/i, score: 60, reason: "Permissive file permissions" },
188
+ { pattern: /ssh|scp|rsync/i, score: 50, reason: "Remote access" },
189
+ { pattern: /docker|podman/i, score: 50, reason: "Container operation" },
190
+ { pattern: /npm|pip|gem|cargo/i, score: 40, reason: "Package management" },
191
+ { pattern: /git\s+push/i, score: 40, reason: "Code push" },
192
+ ];
193
+ for (const { pattern, score: s, reason: r } of dangerousPatterns) {
194
+ if (pattern.test(action.command)) {
195
+ if (s > score) {
196
+ score = s;
197
+ reason = r;
198
+ }
199
+ }
200
+ }
201
+ if (score === 0) {
202
+ score = 20;
203
+ reason = "Standard shell command";
204
+ }
205
+ }
206
+ if (action.type === "http" && action.url) {
207
+ const sensitivePatterns = [
208
+ { pattern: /api\.stripe\.com/i, score: 80, reason: "Payment API" },
209
+ { pattern: /api\.openai\.com/i, score: 50, reason: "AI API call" },
210
+ { pattern: /github\.com.*api/i, score: 40, reason: "GitHub API" },
211
+ { pattern: /localhost|127\.0\.0\.1/i, score: 30, reason: "Local service" },
212
+ ];
213
+ for (const { pattern, score: s, reason: r } of sensitivePatterns) {
214
+ if (pattern.test(action.url)) {
215
+ score = s;
216
+ reason = r;
217
+ break;
218
+ }
219
+ }
220
+ if (score === 0) {
221
+ score = 25;
222
+ reason = "HTTP request";
223
+ }
224
+ }
225
+ if (action.type === "filesystem" && action.path) {
226
+ const sensitivePatterns = [
227
+ { pattern: /\.(env|pem|key|crt|ssh)/i, score: 90, reason: "Sensitive file access" },
228
+ { pattern: /\/etc\/(passwd|shadow|sudoers)/i, score: 95, reason: "System file access" },
229
+ { pattern: /~\/\.(bash|zsh|ssh|gnupg)/i, score: 80, reason: "User config access" },
230
+ { pattern: /node_modules|vendor|packages/i, score: 20, reason: "Dependency access" },
231
+ ];
232
+ for (const { pattern, score: s, reason: r } of sensitivePatterns) {
233
+ if (pattern.test(action.path)) {
234
+ score = s;
235
+ reason = r;
236
+ break;
237
+ }
238
+ }
239
+ if (score === 0) {
240
+ score = 15;
241
+ reason = "File access";
242
+ }
243
+ }
244
+ let level;
245
+ if (score >= 80) {
246
+ level = "critical";
247
+ }
248
+ else if (score >= 60) {
249
+ level = "high";
250
+ }
251
+ else if (score >= 40) {
252
+ level = "medium";
253
+ }
254
+ else {
255
+ level = "low";
256
+ }
257
+ return { score, level, reason };
258
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=shell-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-wrapper.d.ts","sourceRoot":"","sources":["../../src/shell-wrapper.ts"],"names":[],"mappings":""}