@roxy-agent/agents 0.1.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/LICENSE +21 -0
- package/README.md +306 -0
- package/dist/approvals.js +143 -0
- package/dist/approvals.js.map +1 -0
- package/dist/classifier.js +436 -0
- package/dist/classifier.js.map +1 -0
- package/dist/dashboard/client.js +2057 -0
- package/dist/dashboard/client.js.map +1 -0
- package/dist/dashboard/html.js +57 -0
- package/dist/dashboard/html.js.map +1 -0
- package/dist/dashboard/icons.js +18 -0
- package/dist/dashboard/icons.js.map +1 -0
- package/dist/dashboard/server.js +423 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/dashboard/styles.js +1685 -0
- package/dist/dashboard/styles.js.map +1 -0
- package/dist/dashboard.js +2 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/db.js +526 -0
- package/dist/db.js.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/license.js +257 -0
- package/dist/license.js.map +1 -0
- package/dist/logger.js +44 -0
- package/dist/logger.js.map +1 -0
- package/dist/ml/bash-classifier.js +121 -0
- package/dist/ml/bash-classifier.js.map +1 -0
- package/dist/ml/embedder.js +79 -0
- package/dist/ml/embedder.js.map +1 -0
- package/dist/ml/prototypes.js +707 -0
- package/dist/ml/prototypes.js.map +1 -0
- package/dist/policies.js +289 -0
- package/dist/policies.js.map +1 -0
- package/dist/slack.js +149 -0
- package/dist/slack.js.map +1 -0
- package/dist/tools/bash.js +134 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/conversation.js +36 -0
- package/dist/tools/conversation.js.map +1 -0
- package/dist/tools/filesystem.js +243 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/introspect.js +187 -0
- package/dist/tools/introspect.js.map +1 -0
- package/dist/tools/network.js +152 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/policies.js +107 -0
- package/dist/tools/policies.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/dashboard/styles.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,qDAAqD;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAipDtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// Resolve the data directory. Order of precedence:
|
|
8
|
+
// 1. AGENT_PROXY_DATA_DIR env override
|
|
9
|
+
// 2. ~/.agent-proxy/ (default — works whether the server was npm-installed,
|
|
10
|
+
// run via `npx`, or cloned from source)
|
|
11
|
+
// 3. <repo>/data/ if we detect we're running from a source checkout and
|
|
12
|
+
// the repo-local data dir already exists (back-compat for existing dev
|
|
13
|
+
// installs).
|
|
14
|
+
function resolveDataDir() {
|
|
15
|
+
const env = process.env.AGENT_PROXY_DATA_DIR;
|
|
16
|
+
if (env && env.trim())
|
|
17
|
+
return path.resolve(env.trim());
|
|
18
|
+
const home = os.homedir();
|
|
19
|
+
const userDir = path.join(home, ".agent-proxy");
|
|
20
|
+
// Back-compat: if a developer is running from a source checkout that
|
|
21
|
+
// already has <repo>/data/audit.db, keep using it so we don't orphan
|
|
22
|
+
// their existing audit history.
|
|
23
|
+
const repoLocal = path.resolve(__dirname, "..", "data");
|
|
24
|
+
const repoLocalDb = path.join(repoLocal, "audit.db");
|
|
25
|
+
if (fs.existsSync(repoLocalDb) &&
|
|
26
|
+
!fs.existsSync(path.join(userDir, "audit.db"))) {
|
|
27
|
+
return repoLocal;
|
|
28
|
+
}
|
|
29
|
+
return userDir;
|
|
30
|
+
}
|
|
31
|
+
const DATA_DIR = resolveDataDir();
|
|
32
|
+
const DB_PATH = path.join(DATA_DIR, "audit.db");
|
|
33
|
+
if (!fs.existsSync(DATA_DIR))
|
|
34
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
35
|
+
export const db = new Database(DB_PATH);
|
|
36
|
+
// WAL mode keeps the dashboard responsive while the MCP server writes events.
|
|
37
|
+
db.pragma("journal_mode = WAL");
|
|
38
|
+
db.pragma("synchronous = NORMAL");
|
|
39
|
+
export function initDb() {
|
|
40
|
+
db.exec(`
|
|
41
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
42
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
+
timestamp TEXT NOT NULL,
|
|
44
|
+
session_id TEXT NOT NULL,
|
|
45
|
+
tool TEXT NOT NULL,
|
|
46
|
+
action_type TEXT NOT NULL,
|
|
47
|
+
payload TEXT NOT NULL,
|
|
48
|
+
risk_level TEXT NOT NULL CHECK(risk_level IN ('low', 'medium', 'high')),
|
|
49
|
+
decision TEXT NOT NULL CHECK(decision IN ('allowed', 'denied', 'flagged', 'pending_approval')),
|
|
50
|
+
result TEXT,
|
|
51
|
+
duration_ms INTEGER,
|
|
52
|
+
error TEXT,
|
|
53
|
+
reason TEXT
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_timestamp ON events(timestamp);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_session ON events(session_id);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_risk ON events(risk_level);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_decision ON events(decision);
|
|
60
|
+
|
|
61
|
+
CREATE TABLE IF NOT EXISTS usage (
|
|
62
|
+
period TEXT PRIMARY KEY,
|
|
63
|
+
used INTEGER NOT NULL DEFAULT 0,
|
|
64
|
+
last_event TEXT,
|
|
65
|
+
synced_at TEXT
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE TABLE IF NOT EXISTS builtin_rule_overrides (
|
|
69
|
+
id TEXT PRIMARY KEY,
|
|
70
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
71
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS approvals (
|
|
75
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
|
+
event_id INTEGER,
|
|
77
|
+
tool TEXT NOT NULL,
|
|
78
|
+
summary TEXT NOT NULL,
|
|
79
|
+
reason TEXT NOT NULL,
|
|
80
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
81
|
+
requested_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
82
|
+
decided_at TEXT,
|
|
83
|
+
decided_by TEXT,
|
|
84
|
+
slack_ts TEXT,
|
|
85
|
+
payload TEXT,
|
|
86
|
+
session_id TEXT
|
|
87
|
+
);
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status);
|
|
89
|
+
|
|
90
|
+
CREATE TABLE IF NOT EXISTS app_settings (
|
|
91
|
+
key TEXT PRIMARY KEY,
|
|
92
|
+
value TEXT NOT NULL,
|
|
93
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
94
|
+
);
|
|
95
|
+
`);
|
|
96
|
+
// Soft-migration: relax the events.decision CHECK constraint so existing
|
|
97
|
+
// databases accept the new 'pending_approval' value. SQLite stores CHECK
|
|
98
|
+
// constraints inline, so we patch the schema string in sqlite_master. This
|
|
99
|
+
// requires temporarily disabling better-sqlite3's "defensive" mode.
|
|
100
|
+
const evRow = db
|
|
101
|
+
.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='events'`)
|
|
102
|
+
.get();
|
|
103
|
+
if (evRow && !evRow.sql.includes("pending_approval")) {
|
|
104
|
+
try {
|
|
105
|
+
db.unsafeMode(true);
|
|
106
|
+
db.pragma("writable_schema = ON");
|
|
107
|
+
db.prepare(`UPDATE sqlite_master SET sql = ? WHERE type='table' AND name='events'`).run(evRow.sql.replace("decision IN ('allowed', 'denied', 'flagged')", "decision IN ('allowed', 'denied', 'flagged', 'pending_approval')"));
|
|
108
|
+
// Force every connection to re-read the schema by bumping the cookie.
|
|
109
|
+
const v = db.pragma("schema_version", { simple: true });
|
|
110
|
+
db.pragma(`schema_version = ${v + 1}`);
|
|
111
|
+
db.pragma("writable_schema = OFF");
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
db.unsafeMode(false);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Lightweight migration: older databases may not yet have the `reason`
|
|
118
|
+
// column, so add it on the fly.
|
|
119
|
+
const cols = db.prepare(`PRAGMA table_info(events)`).all();
|
|
120
|
+
if (!cols.some((c) => c.name === "reason")) {
|
|
121
|
+
db.exec(`ALTER TABLE events ADD COLUMN reason TEXT`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Usage / billing
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
export function getUsage(period) {
|
|
128
|
+
const row = db
|
|
129
|
+
.prepare(`SELECT used FROM usage WHERE period = ?`)
|
|
130
|
+
.get(period);
|
|
131
|
+
return row?.used ?? 0;
|
|
132
|
+
}
|
|
133
|
+
export function incrementUsage(period) {
|
|
134
|
+
db.prepare(`INSERT INTO usage (period, used, last_event)
|
|
135
|
+
VALUES (?, 1, datetime('now'))
|
|
136
|
+
ON CONFLICT(period) DO UPDATE SET
|
|
137
|
+
used = used + 1,
|
|
138
|
+
last_event = datetime('now')`).run(period);
|
|
139
|
+
return getUsage(period);
|
|
140
|
+
}
|
|
141
|
+
export function setUsageSyncedAt(period, ts) {
|
|
142
|
+
db.prepare(`INSERT INTO usage (period, used, synced_at)
|
|
143
|
+
VALUES (?, 0, ?)
|
|
144
|
+
ON CONFLICT(period) DO UPDATE SET synced_at = excluded.synced_at`).run(period, ts);
|
|
145
|
+
}
|
|
146
|
+
export function getRecentUsage(limit = 6) {
|
|
147
|
+
return db
|
|
148
|
+
.prepare(`SELECT * FROM usage ORDER BY period DESC LIMIT ?`)
|
|
149
|
+
.all(limit);
|
|
150
|
+
}
|
|
151
|
+
export function getBuiltinRuleOverrides() {
|
|
152
|
+
const rows = db
|
|
153
|
+
.prepare(`SELECT id, enabled FROM builtin_rule_overrides`)
|
|
154
|
+
.all();
|
|
155
|
+
const out = new Map();
|
|
156
|
+
for (const r of rows)
|
|
157
|
+
out.set(r.id, !!r.enabled);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
export function setBuiltinRuleOverride(id, enabled) {
|
|
161
|
+
db.prepare(`INSERT INTO builtin_rule_overrides (id, enabled, updated_at)
|
|
162
|
+
VALUES (?, ?, datetime('now'))
|
|
163
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
164
|
+
enabled = excluded.enabled,
|
|
165
|
+
updated_at = datetime('now')`).run(id, enabled ? 1 : 0);
|
|
166
|
+
}
|
|
167
|
+
export function createApprovalRow(input) {
|
|
168
|
+
const r = db
|
|
169
|
+
.prepare(`INSERT INTO approvals (event_id, tool, summary, reason, payload, session_id)
|
|
170
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
171
|
+
.run(input.event_id, input.tool, input.summary.slice(0, 500), input.reason, input.payload === undefined ? null : JSON.stringify(input.payload), input.session_id ?? null);
|
|
172
|
+
return Number(r.lastInsertRowid);
|
|
173
|
+
}
|
|
174
|
+
export function setApprovalStatus(id, status, by) {
|
|
175
|
+
const r = db
|
|
176
|
+
.prepare(`UPDATE approvals SET status = ?, decided_at = datetime('now'), decided_by = ?
|
|
177
|
+
WHERE id = ? AND status = 'pending'`)
|
|
178
|
+
.run(status, by, id);
|
|
179
|
+
return r.changes > 0;
|
|
180
|
+
}
|
|
181
|
+
export function setApprovalSlackTs(id, ts) {
|
|
182
|
+
db.prepare(`UPDATE approvals SET slack_ts = ? WHERE id = ?`).run(ts, id);
|
|
183
|
+
}
|
|
184
|
+
export function getApproval(id) {
|
|
185
|
+
return db.prepare(`SELECT * FROM approvals WHERE id = ?`).get(id);
|
|
186
|
+
}
|
|
187
|
+
export function listApprovals(opts) {
|
|
188
|
+
const limit = opts?.limit ?? 100;
|
|
189
|
+
if (opts?.status) {
|
|
190
|
+
return db
|
|
191
|
+
.prepare(`SELECT * FROM approvals WHERE status = ? ORDER BY id DESC LIMIT ?`)
|
|
192
|
+
.all(opts.status, limit);
|
|
193
|
+
}
|
|
194
|
+
return db
|
|
195
|
+
.prepare(`SELECT * FROM approvals ORDER BY id DESC LIMIT ?`)
|
|
196
|
+
.all(limit);
|
|
197
|
+
}
|
|
198
|
+
export function countPendingApprovals() {
|
|
199
|
+
const row = db
|
|
200
|
+
.prepare(`SELECT COUNT(*) AS n FROM approvals WHERE status = 'pending'`)
|
|
201
|
+
.get();
|
|
202
|
+
return row.n;
|
|
203
|
+
}
|
|
204
|
+
// Mark any approvals left over from a previous process run as 'timeout' since
|
|
205
|
+
// the awaiting promise can't be rehydrated across restarts.
|
|
206
|
+
export function expireOrphanApprovals() {
|
|
207
|
+
const r = db
|
|
208
|
+
.prepare(`UPDATE approvals SET status = 'timeout', decided_at = datetime('now'),
|
|
209
|
+
decided_by = COALESCE(decided_by, 'process restart')
|
|
210
|
+
WHERE status = 'pending'`)
|
|
211
|
+
.run();
|
|
212
|
+
return r.changes;
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// Update an event row's decision/reason after the fact (used when an HITL
|
|
216
|
+
// approval resolves: pending_approval → allowed/denied so aggregation queries
|
|
217
|
+
// stay consistent).
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
export function updateEventDecision(id, decision, reason) {
|
|
220
|
+
db.prepare(`UPDATE events SET decision = ?, reason = COALESCE(?, reason) WHERE id = ?`).run(decision, reason, id);
|
|
221
|
+
}
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// App settings (small key/value store for things like Slack webhook URL).
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
export function getAppSetting(key) {
|
|
226
|
+
const row = db
|
|
227
|
+
.prepare(`SELECT value FROM app_settings WHERE key = ?`)
|
|
228
|
+
.get(key);
|
|
229
|
+
return row?.value ?? null;
|
|
230
|
+
}
|
|
231
|
+
export function setAppSetting(key, value) {
|
|
232
|
+
if (value == null || value === "") {
|
|
233
|
+
db.prepare(`DELETE FROM app_settings WHERE key = ?`).run(key);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
db.prepare(`INSERT INTO app_settings (key, value, updated_at)
|
|
237
|
+
VALUES (?, ?, datetime('now'))
|
|
238
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')`).run(key, value);
|
|
239
|
+
}
|
|
240
|
+
export function getAllAppSettings() {
|
|
241
|
+
const rows = db
|
|
242
|
+
.prepare(`SELECT key, value FROM app_settings`)
|
|
243
|
+
.all();
|
|
244
|
+
const out = {};
|
|
245
|
+
for (const r of rows)
|
|
246
|
+
out[r.key] = r.value;
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
let _insert = null;
|
|
250
|
+
let _updateResult = null;
|
|
251
|
+
function insertStmt() {
|
|
252
|
+
if (_insert)
|
|
253
|
+
return _insert;
|
|
254
|
+
_insert = db.prepare(`
|
|
255
|
+
INSERT INTO events
|
|
256
|
+
(timestamp, session_id, tool, action_type, payload, risk_level, decision, result, duration_ms, error, reason)
|
|
257
|
+
VALUES
|
|
258
|
+
(datetime('now'), @session_id, @tool, @action_type, @payload, @risk_level, @decision, @result, @duration_ms, @error, @reason)
|
|
259
|
+
`);
|
|
260
|
+
return _insert;
|
|
261
|
+
}
|
|
262
|
+
function updateResultStmt() {
|
|
263
|
+
if (_updateResult)
|
|
264
|
+
return _updateResult;
|
|
265
|
+
_updateResult = db.prepare(`
|
|
266
|
+
UPDATE events
|
|
267
|
+
SET result = ?, duration_ms = ?, error = ?
|
|
268
|
+
WHERE id = ?
|
|
269
|
+
`);
|
|
270
|
+
return _updateResult;
|
|
271
|
+
}
|
|
272
|
+
export function logEvent(event) {
|
|
273
|
+
const result = insertStmt().run({
|
|
274
|
+
session_id: event.session_id,
|
|
275
|
+
tool: event.tool,
|
|
276
|
+
action_type: event.action_type,
|
|
277
|
+
payload: JSON.stringify(event.payload),
|
|
278
|
+
risk_level: event.risk_level,
|
|
279
|
+
decision: event.decision,
|
|
280
|
+
result: event.result ?? null,
|
|
281
|
+
duration_ms: event.duration_ms ?? null,
|
|
282
|
+
error: event.error ?? null,
|
|
283
|
+
reason: event.reason ?? null,
|
|
284
|
+
});
|
|
285
|
+
return Number(result.lastInsertRowid);
|
|
286
|
+
}
|
|
287
|
+
export function updateEventResult(id, result, duration_ms, error) {
|
|
288
|
+
updateResultStmt().run(truncate(result, 100_000), duration_ms, error ?? null, id);
|
|
289
|
+
}
|
|
290
|
+
function truncate(s, max) {
|
|
291
|
+
if (s.length <= max)
|
|
292
|
+
return s;
|
|
293
|
+
return s.slice(0, max) + `… [truncated, ${s.length - max} more chars]`;
|
|
294
|
+
}
|
|
295
|
+
export function getRecentEvents(limit = 100) {
|
|
296
|
+
return db
|
|
297
|
+
.prepare(`SELECT * FROM events ORDER BY id DESC LIMIT ?`)
|
|
298
|
+
.all(limit);
|
|
299
|
+
}
|
|
300
|
+
export function getEventsSince(sinceId, limit = 500) {
|
|
301
|
+
return db
|
|
302
|
+
.prepare(`SELECT * FROM events WHERE id > ? ORDER BY id ASC LIMIT ?`)
|
|
303
|
+
.all(sinceId, limit);
|
|
304
|
+
}
|
|
305
|
+
export function getEvent(id) {
|
|
306
|
+
return db.prepare(`SELECT * FROM events WHERE id = ?`).get(id);
|
|
307
|
+
}
|
|
308
|
+
export function getSessionEvents(session_id) {
|
|
309
|
+
return db
|
|
310
|
+
.prepare(`SELECT * FROM events WHERE session_id = ? ORDER BY id ASC`)
|
|
311
|
+
.all(session_id);
|
|
312
|
+
}
|
|
313
|
+
export function getStats() {
|
|
314
|
+
return db
|
|
315
|
+
.prepare(`
|
|
316
|
+
SELECT
|
|
317
|
+
COUNT(*) as total,
|
|
318
|
+
COALESCE(SUM(CASE WHEN risk_level = 'high' THEN 1 ELSE 0 END), 0) as high_risk,
|
|
319
|
+
COALESCE(SUM(CASE WHEN risk_level = 'medium' THEN 1 ELSE 0 END), 0) as medium_risk,
|
|
320
|
+
COALESCE(SUM(CASE WHEN risk_level = 'low' THEN 1 ELSE 0 END), 0) as low_risk,
|
|
321
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) as denied,
|
|
322
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) as flagged,
|
|
323
|
+
COALESCE(SUM(CASE WHEN tool = 'bash' THEN 1 ELSE 0 END), 0) as bash_calls,
|
|
324
|
+
COALESCE(SUM(CASE WHEN tool = 'filesystem' THEN 1 ELSE 0 END), 0) as file_calls,
|
|
325
|
+
COALESCE(SUM(CASE WHEN tool = 'network' THEN 1 ELSE 0 END), 0) as network_calls,
|
|
326
|
+
COALESCE(SUM(CASE WHEN error IS NOT NULL AND error <> '' THEN 1 ELSE 0 END), 0) as errors,
|
|
327
|
+
COUNT(DISTINCT session_id) as sessions
|
|
328
|
+
FROM events
|
|
329
|
+
`)
|
|
330
|
+
.get();
|
|
331
|
+
}
|
|
332
|
+
export function getDbPath() {
|
|
333
|
+
return DB_PATH;
|
|
334
|
+
}
|
|
335
|
+
function strftimeFmt(g) {
|
|
336
|
+
if (g === "minute")
|
|
337
|
+
return "%Y-%m-%d %H:%M";
|
|
338
|
+
if (g === "day")
|
|
339
|
+
return "%Y-%m-%d";
|
|
340
|
+
return "%Y-%m-%d %H:00";
|
|
341
|
+
}
|
|
342
|
+
// Returns one row per bucket in the requested window, zero-filled when a
|
|
343
|
+
// concrete window is given, sorted oldest→newest. Pass `hours = null` for
|
|
344
|
+
// "all time" (no zero-fill — only buckets that actually have data).
|
|
345
|
+
export function getActivityAggregate(hours = 24, granularity = "hour") {
|
|
346
|
+
const fmt = strftimeFmt(granularity);
|
|
347
|
+
const filterClause = hours == null ? "" : "WHERE timestamp >= ?";
|
|
348
|
+
const params = hours == null
|
|
349
|
+
? []
|
|
350
|
+
: [
|
|
351
|
+
new Date(Date.now() - hours * 60 * 60 * 1000)
|
|
352
|
+
.toISOString()
|
|
353
|
+
.slice(0, 19)
|
|
354
|
+
.replace("T", " "),
|
|
355
|
+
];
|
|
356
|
+
const rows = db
|
|
357
|
+
.prepare(`
|
|
358
|
+
SELECT
|
|
359
|
+
strftime('${fmt}', timestamp) AS hour,
|
|
360
|
+
COUNT(*) AS total,
|
|
361
|
+
COALESCE(SUM(CASE WHEN decision = 'allowed' THEN 1 ELSE 0 END), 0) AS allowed,
|
|
362
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) AS flagged,
|
|
363
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) AS denied
|
|
364
|
+
FROM events
|
|
365
|
+
${filterClause}
|
|
366
|
+
GROUP BY hour
|
|
367
|
+
ORDER BY hour ASC
|
|
368
|
+
`)
|
|
369
|
+
.all(...params);
|
|
370
|
+
// No concrete window → return raw buckets (sparse).
|
|
371
|
+
if (hours == null)
|
|
372
|
+
return rows;
|
|
373
|
+
// Zero-fill so charts have a continuous x-axis.
|
|
374
|
+
const byKey = new Map(rows.map((r) => [r.hour, r]));
|
|
375
|
+
const out = [];
|
|
376
|
+
const now = new Date();
|
|
377
|
+
if (granularity === "day") {
|
|
378
|
+
now.setUTCHours(0, 0, 0, 0);
|
|
379
|
+
const days = Math.max(1, Math.ceil(hours / 24));
|
|
380
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
381
|
+
const d = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
|
|
382
|
+
const key = d.toISOString().slice(0, 10);
|
|
383
|
+
out.push(byKey.get(key) ?? { hour: key, total: 0, allowed: 0, flagged: 0, denied: 0 });
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else if (granularity === "minute") {
|
|
387
|
+
now.setUTCSeconds(0, 0);
|
|
388
|
+
const mins = Math.max(1, Math.ceil(hours * 60));
|
|
389
|
+
for (let i = mins - 1; i >= 0; i--) {
|
|
390
|
+
const d = new Date(now.getTime() - i * 60 * 1000);
|
|
391
|
+
const key = d.toISOString().slice(0, 16).replace("T", " ");
|
|
392
|
+
out.push(byKey.get(key) ?? { hour: key, total: 0, allowed: 0, flagged: 0, denied: 0 });
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
now.setUTCMinutes(0, 0, 0);
|
|
397
|
+
const buckets = Math.max(1, Math.ceil(hours));
|
|
398
|
+
for (let i = buckets - 1; i >= 0; i--) {
|
|
399
|
+
const d = new Date(now.getTime() - i * 60 * 60 * 1000);
|
|
400
|
+
const key = d.toISOString().slice(0, 13).replace("T", " ") + ":00";
|
|
401
|
+
out.push(byKey.get(key) ?? { hour: key, total: 0, allowed: 0, flagged: 0, denied: 0 });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
// Backwards-compat alias used elsewhere.
|
|
407
|
+
export function getHourlyAggregate(hours = 24) {
|
|
408
|
+
return getActivityAggregate(hours, "hour");
|
|
409
|
+
}
|
|
410
|
+
// Frequency table of recent commands/paths/urls grouped by their canonical
|
|
411
|
+
// summary. Used by the Insights "top denied / flagged" cards.
|
|
412
|
+
export function getTopActions(decision = "any", limit = 8, windowHours = 24 * 7) {
|
|
413
|
+
const decisionFilter = decision === "any" ? "1=1" : `decision = '${decision}'`;
|
|
414
|
+
const params = [];
|
|
415
|
+
let timeClause = "";
|
|
416
|
+
if (windowHours != null) {
|
|
417
|
+
timeClause = "timestamp >= ? AND ";
|
|
418
|
+
params.push(new Date(Date.now() - windowHours * 60 * 60 * 1000)
|
|
419
|
+
.toISOString()
|
|
420
|
+
.slice(0, 19)
|
|
421
|
+
.replace("T", " "));
|
|
422
|
+
}
|
|
423
|
+
params.push(limit);
|
|
424
|
+
const rows = db
|
|
425
|
+
.prepare(`
|
|
426
|
+
SELECT
|
|
427
|
+
tool,
|
|
428
|
+
decision,
|
|
429
|
+
risk_level,
|
|
430
|
+
COALESCE(json_extract(payload, '$.command'),
|
|
431
|
+
json_extract(payload, '$.path'),
|
|
432
|
+
json_extract(payload, '$.url'),
|
|
433
|
+
substr(payload, 1, 80)) AS summary,
|
|
434
|
+
COUNT(*) AS count
|
|
435
|
+
FROM events
|
|
436
|
+
WHERE ${timeClause}${decisionFilter}
|
|
437
|
+
GROUP BY summary, tool, decision, risk_level
|
|
438
|
+
ORDER BY count DESC, MAX(id) DESC
|
|
439
|
+
LIMIT ?
|
|
440
|
+
`)
|
|
441
|
+
.all(...params);
|
|
442
|
+
return rows;
|
|
443
|
+
}
|
|
444
|
+
export function getRecentSessions(limit = 10) {
|
|
445
|
+
return db
|
|
446
|
+
.prepare(`
|
|
447
|
+
SELECT
|
|
448
|
+
session_id,
|
|
449
|
+
MAX(timestamp) AS last_event,
|
|
450
|
+
COUNT(*) AS events,
|
|
451
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) AS flagged,
|
|
452
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) AS denied,
|
|
453
|
+
GROUP_CONCAT(DISTINCT tool) AS tools
|
|
454
|
+
FROM events
|
|
455
|
+
GROUP BY session_id
|
|
456
|
+
ORDER BY MAX(id) DESC
|
|
457
|
+
LIMIT ?
|
|
458
|
+
`)
|
|
459
|
+
.all(limit);
|
|
460
|
+
}
|
|
461
|
+
export function getToolBreakdown(windowHours = 24 * 7) {
|
|
462
|
+
const params = [];
|
|
463
|
+
let where = "";
|
|
464
|
+
if (windowHours != null) {
|
|
465
|
+
where = "WHERE timestamp >= ?";
|
|
466
|
+
params.push(new Date(Date.now() - windowHours * 60 * 60 * 1000)
|
|
467
|
+
.toISOString()
|
|
468
|
+
.slice(0, 19)
|
|
469
|
+
.replace("T", " "));
|
|
470
|
+
}
|
|
471
|
+
return db
|
|
472
|
+
.prepare(`
|
|
473
|
+
SELECT
|
|
474
|
+
tool,
|
|
475
|
+
COUNT(*) AS count,
|
|
476
|
+
COALESCE(SUM(CASE WHEN decision = 'allowed' THEN 1 ELSE 0 END), 0) AS allowed,
|
|
477
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) AS flagged,
|
|
478
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) AS denied
|
|
479
|
+
FROM events
|
|
480
|
+
${where}
|
|
481
|
+
GROUP BY tool
|
|
482
|
+
ORDER BY count DESC
|
|
483
|
+
`)
|
|
484
|
+
.all(...params);
|
|
485
|
+
}
|
|
486
|
+
// Stats over an arbitrary trailing window. `hours = null` returns all-time.
|
|
487
|
+
export function getRangedStats(hours = 24) {
|
|
488
|
+
const params = [];
|
|
489
|
+
let where = "";
|
|
490
|
+
if (hours != null) {
|
|
491
|
+
where = "WHERE timestamp >= ?";
|
|
492
|
+
params.push(new Date(Date.now() - hours * 60 * 60 * 1000)
|
|
493
|
+
.toISOString()
|
|
494
|
+
.slice(0, 19)
|
|
495
|
+
.replace("T", " "));
|
|
496
|
+
}
|
|
497
|
+
return db
|
|
498
|
+
.prepare(`
|
|
499
|
+
SELECT
|
|
500
|
+
COUNT(*) AS total,
|
|
501
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) AS flagged,
|
|
502
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) AS denied,
|
|
503
|
+
COUNT(DISTINCT session_id) AS sessions
|
|
504
|
+
FROM events
|
|
505
|
+
${where}
|
|
506
|
+
`)
|
|
507
|
+
.get(...params);
|
|
508
|
+
}
|
|
509
|
+
// "Today" stats (since UTC midnight) used by the Overview hero KPIs.
|
|
510
|
+
export function getTodayStats() {
|
|
511
|
+
const since = new Date();
|
|
512
|
+
since.setUTCHours(0, 0, 0, 0);
|
|
513
|
+
const sinceStr = since.toISOString().slice(0, 19).replace("T", " ");
|
|
514
|
+
return db
|
|
515
|
+
.prepare(`
|
|
516
|
+
SELECT
|
|
517
|
+
COUNT(*) AS total,
|
|
518
|
+
COALESCE(SUM(CASE WHEN decision = 'flagged' THEN 1 ELSE 0 END), 0) AS flagged,
|
|
519
|
+
COALESCE(SUM(CASE WHEN decision = 'denied' THEN 1 ELSE 0 END), 0) AS denied,
|
|
520
|
+
COUNT(DISTINCT session_id) AS sessions
|
|
521
|
+
FROM events
|
|
522
|
+
WHERE timestamp >= ?
|
|
523
|
+
`)
|
|
524
|
+
.get(sinceStr);
|
|
525
|
+
}
|
|
526
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { initDb } from "./db.js";
|
|
6
|
+
import { startDashboard } from "./dashboard.js";
|
|
7
|
+
import { prepareBashML } from "./ml/bash-classifier.js";
|
|
8
|
+
import { initPoliciesTable, ensureEmbeddings } from "./policies.js";
|
|
9
|
+
import { initApprovals } from "./approvals.js";
|
|
10
|
+
import { bashToolDefinition, executeBash } from "./tools/bash.js";
|
|
11
|
+
import { readFileToolDefinition, writeFileToolDefinition, deleteFileToolDefinition, listDirectoryToolDefinition, readFile, writeFile, deleteFile, listDirectory, } from "./tools/filesystem.js";
|
|
12
|
+
import { networkToolDefinition, fetchUrl } from "./tools/network.js";
|
|
13
|
+
import { classifyToolDefinition, classify, recentEventsToolDefinition, recentEvents, proxyStatsToolDefinition, proxyStats, } from "./tools/introspect.js";
|
|
14
|
+
import { addPolicyToolDefinition, addPolicy, listPoliciesToolDefinition, listPoliciesTool, deletePolicyToolDefinition, deletePolicyTool, updatePolicyToolDefinition, updatePolicyTool, } from "./tools/policies.js";
|
|
15
|
+
import { ensureLicense, checkQuota, chargeUsage, syncWithCloud, } from "./license.js";
|
|
16
|
+
// One session ID per server run (one per agent session). The agent or
|
|
17
|
+
// orchestrator can override it via AGENT_PROXY_SESSION_ID for traceability.
|
|
18
|
+
const SESSION_ID = process.env.AGENT_PROXY_SESSION_ID ?? randomUUID();
|
|
19
|
+
const DASHBOARD_PORT = Number(process.env.AGENT_PROXY_PORT) || 4242;
|
|
20
|
+
const DASHBOARD_DISABLED = process.env.AGENT_PROXY_DISABLE_DASHBOARD === "1";
|
|
21
|
+
initDb();
|
|
22
|
+
initPoliciesTable();
|
|
23
|
+
initApprovals();
|
|
24
|
+
const LICENSE = ensureLicense();
|
|
25
|
+
if (!DASHBOARD_DISABLED)
|
|
26
|
+
startDashboard(DASHBOARD_PORT);
|
|
27
|
+
process.stderr.write(`[agent-proxy] license user=${LICENSE.user_id} plan=${LICENSE.plan} quota=${LICENSE.quota}\n`);
|
|
28
|
+
// Background cloud sync — best-effort, non-fatal. Pulls fresh quota from the
|
|
29
|
+
// remote API every 5 min so paid upgrades take effect without a restart.
|
|
30
|
+
if (LICENSE.jwt) {
|
|
31
|
+
syncWithCloud().catch(() => { });
|
|
32
|
+
setInterval(() => {
|
|
33
|
+
syncWithCloud().catch(() => { });
|
|
34
|
+
}, 5 * 60 * 1000);
|
|
35
|
+
}
|
|
36
|
+
process.stderr.write(`[agent-proxy] session=${SESSION_ID} pid=${process.pid}\n`);
|
|
37
|
+
// Kick off ML embedder + prototype embedding in the background. We don't
|
|
38
|
+
// await: bash calls that arrive before the model is ready transparently fall
|
|
39
|
+
// back to the rule-based classifier. Set AGENT_PROXY_ML=0 to skip entirely.
|
|
40
|
+
if (process.env.AGENT_PROXY_ML !== "0") {
|
|
41
|
+
prepareBashML()
|
|
42
|
+
.then(() => ensureEmbeddings())
|
|
43
|
+
.catch((err) => {
|
|
44
|
+
process.stderr.write(`[agent-proxy] ML prep failed: ${err.message}\n`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const server = new McpServer({
|
|
48
|
+
name: "agent-proxy",
|
|
49
|
+
version: "0.1.0",
|
|
50
|
+
});
|
|
51
|
+
function asText(value) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Quota gate — runs before any billable tool. Returns the agent a structured
|
|
57
|
+
// "blocked" object (mirroring how policy/classifier blocks already look) when
|
|
58
|
+
// the current month's free quota is exhausted, and bumps the counter on
|
|
59
|
+
// successful execution.
|
|
60
|
+
async function billable(toolName, fn, actionHint) {
|
|
61
|
+
const block = checkQuota(toolName, actionHint);
|
|
62
|
+
if (block)
|
|
63
|
+
return block;
|
|
64
|
+
const result = await fn();
|
|
65
|
+
chargeUsage(toolName, actionHint);
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
server.tool(bashToolDefinition.name, bashToolDefinition.description, bashToolDefinition.schema.shape, async (args) => asText(await billable("bash", () => executeBash(args, SESSION_ID))));
|
|
69
|
+
server.tool(readFileToolDefinition.name, readFileToolDefinition.description, readFileToolDefinition.schema.shape, async (args) => asText(await readFile(args, SESSION_ID)));
|
|
70
|
+
server.tool(writeFileToolDefinition.name, writeFileToolDefinition.description, writeFileToolDefinition.schema.shape, async (args) => asText(await billable("write_file", () => writeFile({ ...args, append: args.append ?? false }, SESSION_ID))));
|
|
71
|
+
server.tool(deleteFileToolDefinition.name, deleteFileToolDefinition.description, deleteFileToolDefinition.schema.shape, async (args) => asText(await billable("delete_file", () => deleteFile(args, SESSION_ID))));
|
|
72
|
+
server.tool(listDirectoryToolDefinition.name, listDirectoryToolDefinition.description, listDirectoryToolDefinition.schema.shape, async (args) => asText(await listDirectory(args, SESSION_ID)));
|
|
73
|
+
server.tool(networkToolDefinition.name, networkToolDefinition.description, networkToolDefinition.schema.shape, async (args) => asText(await billable("network", () => fetchUrl({ ...args, method: args.method ?? "GET" }, SESSION_ID))));
|
|
74
|
+
// Introspection tools (read-only — no audit entry generated).
|
|
75
|
+
server.tool(classifyToolDefinition.name, classifyToolDefinition.description, classifyToolDefinition.schema.shape, async (args) => asText(await classify(args)));
|
|
76
|
+
server.tool(recentEventsToolDefinition.name, recentEventsToolDefinition.description, recentEventsToolDefinition.schema.shape, async (args) => asText(recentEvents(args, SESSION_ID)));
|
|
77
|
+
server.tool(proxyStatsToolDefinition.name, proxyStatsToolDefinition.description, proxyStatsToolDefinition.schema.shape, async () => asText(proxyStats(SESSION_ID, DASHBOARD_PORT)));
|
|
78
|
+
// Policy management tools — persist guardrails across sessions.
|
|
79
|
+
server.tool(addPolicyToolDefinition.name, addPolicyToolDefinition.description, addPolicyToolDefinition.schema.shape, async (args) => asText(await addPolicy(args)));
|
|
80
|
+
server.tool(listPoliciesToolDefinition.name, listPoliciesToolDefinition.description, listPoliciesToolDefinition.schema.shape, async (args) => asText(await listPoliciesTool(args)));
|
|
81
|
+
server.tool(updatePolicyToolDefinition.name, updatePolicyToolDefinition.description, updatePolicyToolDefinition.schema.shape, async (args) => asText(await updatePolicyTool(args)));
|
|
82
|
+
server.tool(deletePolicyToolDefinition.name, deletePolicyToolDefinition.description, deletePolicyToolDefinition.schema.shape, async (args) => asText(deletePolicyTool(args)));
|
|
83
|
+
const transport = new StdioServerTransport();
|
|
84
|
+
process.on("SIGINT", () => {
|
|
85
|
+
process.stderr.write("[agent-proxy] SIGINT — shutting down\n");
|
|
86
|
+
process.exit(0);
|
|
87
|
+
});
|
|
88
|
+
process.on("SIGTERM", () => {
|
|
89
|
+
process.stderr.write("[agent-proxy] SIGTERM — shutting down\n");
|
|
90
|
+
process.exit(0);
|
|
91
|
+
});
|
|
92
|
+
await server.connect(transport);
|
|
93
|
+
process.stderr.write("[agent-proxy] MCP server ready on stdio\n");
|
|
94
|
+
//# sourceMappingURL=index.js.map
|