averecion-lite 1.7.0 → 1.8.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/dashboard/dash.css +53 -0
- package/dashboard/dash.js +60 -5
- package/dashboard/index.html +15 -0
- package/package.json +1 -1
package/dashboard/dash.css
CHANGED
|
@@ -1390,6 +1390,59 @@ body {
|
|
|
1390
1390
|
color: var(--text-primary);
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
|
+
/* Activity Filters */
|
|
1394
|
+
.activity-filters {
|
|
1395
|
+
display: flex;
|
|
1396
|
+
gap: 0.5rem;
|
|
1397
|
+
margin-bottom: 0.75rem;
|
|
1398
|
+
flex-wrap: wrap;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.filter-btn {
|
|
1402
|
+
display: flex;
|
|
1403
|
+
align-items: center;
|
|
1404
|
+
gap: 0.4rem;
|
|
1405
|
+
background: var(--bg-card);
|
|
1406
|
+
border: 1px solid var(--border);
|
|
1407
|
+
color: var(--text-secondary);
|
|
1408
|
+
padding: 0.4rem 0.75rem;
|
|
1409
|
+
border-radius: 20px;
|
|
1410
|
+
font-size: 0.8rem;
|
|
1411
|
+
cursor: pointer;
|
|
1412
|
+
transition: all 0.2s;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
.filter-btn:hover {
|
|
1416
|
+
border-color: var(--text-secondary);
|
|
1417
|
+
color: var(--text-primary);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
.filter-btn.active {
|
|
1421
|
+
background: rgba(139, 92, 246, 0.15);
|
|
1422
|
+
border-color: var(--accent);
|
|
1423
|
+
color: var(--accent);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
.filter-dot {
|
|
1427
|
+
width: 8px;
|
|
1428
|
+
height: 8px;
|
|
1429
|
+
border-radius: 50%;
|
|
1430
|
+
display: inline-block;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
.filter-dot.safe { background: var(--success); }
|
|
1434
|
+
.filter-dot.flagged { background: var(--warning); }
|
|
1435
|
+
.filter-dot.attack { background: var(--danger); }
|
|
1436
|
+
.filter-dot.reviewed { background: var(--accent); }
|
|
1437
|
+
|
|
1438
|
+
.activity-filter-empty {
|
|
1439
|
+
color: var(--text-muted);
|
|
1440
|
+
font-size: 0.85rem;
|
|
1441
|
+
text-align: center;
|
|
1442
|
+
padding: 1.5rem 1rem;
|
|
1443
|
+
font-style: italic;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1393
1446
|
@keyframes slideInLeft {
|
|
1394
1447
|
from { opacity: 0; transform: translateX(-20px); }
|
|
1395
1448
|
to { opacity: 1; transform: translateX(0); }
|
package/dashboard/dash.js
CHANGED
|
@@ -245,6 +245,7 @@
|
|
|
245
245
|
const eventId = event.id || `${event.ts}-${index}`;
|
|
246
246
|
const showFeedback = event.decision === "blocked" || friendly.isAttack;
|
|
247
247
|
const alreadyFeedback = feedback[eventId];
|
|
248
|
+
const category = friendly.isAttack ? "attack" : friendly.class === "blocked" ? "flagged" : friendly.class === "manual" ? "reviewed" : "safe";
|
|
248
249
|
|
|
249
250
|
const feedbackHtml = showFeedback ? (alreadyFeedback ?
|
|
250
251
|
`<div class="activity-feedback"><span class="feedback-thanks">Thanks for your feedback!</span></div>` :
|
|
@@ -257,7 +258,7 @@
|
|
|
257
258
|
|
|
258
259
|
if (hasContext) {
|
|
259
260
|
return `
|
|
260
|
-
<div class="activity-item has-context" data-event-id="${eventId}">
|
|
261
|
+
<div class="activity-item has-context" data-category="${category}" data-event-id="${eventId}">
|
|
261
262
|
<div class="activity-header">
|
|
262
263
|
<div class="activity-icon ${friendly.class}">${friendly.icon}</div>
|
|
263
264
|
<div class="activity-content">
|
|
@@ -274,7 +275,7 @@
|
|
|
274
275
|
`;
|
|
275
276
|
}
|
|
276
277
|
return `
|
|
277
|
-
<div class="activity-item" data-event-id="${eventId}">
|
|
278
|
+
<div class="activity-item" data-category="${category}" data-event-id="${eventId}">
|
|
278
279
|
<div class="activity-icon ${friendly.class}">${friendly.icon}</div>
|
|
279
280
|
<div class="activity-content">
|
|
280
281
|
<div class="activity-text">${friendly.text}</div>
|
|
@@ -283,6 +284,7 @@
|
|
|
283
284
|
</div>
|
|
284
285
|
`;
|
|
285
286
|
}).join("");
|
|
287
|
+
applyActivityFilter();
|
|
286
288
|
|
|
287
289
|
// Attach feedback handlers for initial load
|
|
288
290
|
activityList.querySelectorAll(".feedback-btn").forEach(btn => {
|
|
@@ -756,11 +758,13 @@
|
|
|
756
758
|
let className = "approved";
|
|
757
759
|
let text = `Tool executed: ${data.tool}`;
|
|
758
760
|
let context = null;
|
|
761
|
+
let category = "safe";
|
|
759
762
|
|
|
760
763
|
if (isBlocked || isDanger) {
|
|
761
764
|
icon = "⚠️";
|
|
762
765
|
className = "blocked";
|
|
763
766
|
text = `Dangerous action: ${data.tool}`;
|
|
767
|
+
category = "flagged";
|
|
764
768
|
context = {
|
|
765
769
|
title: isDanger ? data.analysis.danger.reason : "Dangerous Action Detected",
|
|
766
770
|
desc: "This action was flagged as potentially dangerous."
|
|
@@ -771,13 +775,13 @@
|
|
|
771
775
|
icon = "🛡️";
|
|
772
776
|
className = "blocked attack";
|
|
773
777
|
text = `Caught attack in ${data.tool}`;
|
|
778
|
+
category = "attack";
|
|
774
779
|
context = {
|
|
775
780
|
title: "Prompt Injection Detected!",
|
|
776
781
|
desc: data.analysis.injection.reason
|
|
777
782
|
};
|
|
778
783
|
}
|
|
779
784
|
|
|
780
|
-
// Send browser notification for critical events
|
|
781
785
|
if (isInjection) {
|
|
782
786
|
showNotification("🛡️ Prompt Injection Detected!", `Attack attempt caught in ${data.tool}`, true);
|
|
783
787
|
} else if (isDanger) {
|
|
@@ -795,7 +799,7 @@
|
|
|
795
799
|
` : "";
|
|
796
800
|
|
|
797
801
|
const itemHtml = context ? `
|
|
798
|
-
<div class="activity-item has-context" data-new="true" data-event-id="${eventId}">
|
|
802
|
+
<div class="activity-item has-context" data-new="true" data-category="${category}" data-event-id="${eventId}">
|
|
799
803
|
<div class="activity-header">
|
|
800
804
|
<div class="activity-icon ${className}">${icon}</div>
|
|
801
805
|
<div class="activity-content">
|
|
@@ -810,7 +814,7 @@
|
|
|
810
814
|
${feedbackHtml}
|
|
811
815
|
</div>
|
|
812
816
|
` : `
|
|
813
|
-
<div class="activity-item" data-new="true" data-event-id="${eventId}">
|
|
817
|
+
<div class="activity-item" data-new="true" data-category="${category}" data-event-id="${eventId}">
|
|
814
818
|
<div class="activity-icon ${className}">${icon}</div>
|
|
815
819
|
<div class="activity-content">
|
|
816
820
|
<div class="activity-text">${text}</div>
|
|
@@ -820,6 +824,7 @@
|
|
|
820
824
|
`;
|
|
821
825
|
|
|
822
826
|
activityList.insertAdjacentHTML("afterbegin", itemHtml);
|
|
827
|
+
applyActivityFilter();
|
|
823
828
|
|
|
824
829
|
// Attach feedback button handlers
|
|
825
830
|
const newItemEl = activityList.querySelector(`[data-event-id="${eventId}"]`);
|
|
@@ -1269,4 +1274,54 @@
|
|
|
1269
1274
|
console.error("Failed to load archives:", err);
|
|
1270
1275
|
}
|
|
1271
1276
|
}
|
|
1277
|
+
|
|
1278
|
+
let activeFilter = "all";
|
|
1279
|
+
|
|
1280
|
+
function initActivityFilters() {
|
|
1281
|
+
const filterBar = document.getElementById("activity-filters");
|
|
1282
|
+
if (!filterBar) return;
|
|
1283
|
+
|
|
1284
|
+
filterBar.querySelectorAll(".filter-btn").forEach(btn => {
|
|
1285
|
+
btn.addEventListener("click", () => {
|
|
1286
|
+
filterBar.querySelectorAll(".filter-btn").forEach(b => b.classList.remove("active"));
|
|
1287
|
+
btn.classList.add("active");
|
|
1288
|
+
activeFilter = btn.dataset.filter;
|
|
1289
|
+
applyActivityFilter();
|
|
1290
|
+
});
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function applyActivityFilter() {
|
|
1295
|
+
const activityList = document.getElementById("activity-list");
|
|
1296
|
+
if (!activityList) return;
|
|
1297
|
+
|
|
1298
|
+
const items = activityList.querySelectorAll(".activity-item");
|
|
1299
|
+
let visibleCount = 0;
|
|
1300
|
+
|
|
1301
|
+
items.forEach(item => {
|
|
1302
|
+
const cat = item.dataset.category;
|
|
1303
|
+
if (activeFilter === "all" || cat === activeFilter) {
|
|
1304
|
+
item.style.display = "";
|
|
1305
|
+
visibleCount++;
|
|
1306
|
+
} else {
|
|
1307
|
+
item.style.display = "none";
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
let emptyMsg = activityList.querySelector(".activity-filter-empty");
|
|
1312
|
+
if (visibleCount === 0 && items.length > 0) {
|
|
1313
|
+
if (!emptyMsg) {
|
|
1314
|
+
emptyMsg = document.createElement("div");
|
|
1315
|
+
emptyMsg.className = "activity-filter-empty";
|
|
1316
|
+
activityList.appendChild(emptyMsg);
|
|
1317
|
+
}
|
|
1318
|
+
const labels = { safe: "safe", flagged: "flagged", attack: "attack", reviewed: "reviewed" };
|
|
1319
|
+
emptyMsg.textContent = `No ${labels[activeFilter] || ""} activity to show`;
|
|
1320
|
+
emptyMsg.style.display = "";
|
|
1321
|
+
} else if (emptyMsg) {
|
|
1322
|
+
emptyMsg.style.display = "none";
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
initActivityFilters();
|
|
1272
1327
|
})();
|
package/dashboard/index.html
CHANGED
|
@@ -212,6 +212,21 @@
|
|
|
212
212
|
|
|
213
213
|
<section class="activity-section">
|
|
214
214
|
<h2>Recent Activity</h2>
|
|
215
|
+
<div class="activity-filters" id="activity-filters" data-testid="activity-filters">
|
|
216
|
+
<button class="filter-btn active" data-filter="all" data-testid="filter-all">All</button>
|
|
217
|
+
<button class="filter-btn" data-filter="safe" data-testid="filter-safe">
|
|
218
|
+
<span class="filter-dot safe"></span> Safe
|
|
219
|
+
</button>
|
|
220
|
+
<button class="filter-btn" data-filter="flagged" data-testid="filter-flagged">
|
|
221
|
+
<span class="filter-dot flagged"></span> Flagged
|
|
222
|
+
</button>
|
|
223
|
+
<button class="filter-btn" data-filter="attack" data-testid="filter-attack">
|
|
224
|
+
<span class="filter-dot attack"></span> Attacks
|
|
225
|
+
</button>
|
|
226
|
+
<button class="filter-btn" data-filter="reviewed" data-testid="filter-reviewed">
|
|
227
|
+
<span class="filter-dot reviewed"></span> Reviewed
|
|
228
|
+
</button>
|
|
229
|
+
</div>
|
|
215
230
|
<div class="activity-list" id="activity-list" data-testid="list-activity">
|
|
216
231
|
<div class="activity-empty">
|
|
217
232
|
<p>🦞 Your bot hasn't done anything yet. When it does, you'll see it here!</p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "averecion-lite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Real-time AI agent monitoring - watches logs, detects dangerous commands and prompt injection attempts",
|
|
5
5
|
"author": "Averecion <hello@averecion.com>",
|
|
6
6
|
"homepage": "https://github.com/averecion/clawguard#readme",
|