@agent-e/server 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AgentEServer-DT6ETPR6.mjs +7 -0
- package/dist/{chunk-OALXQFKY.mjs → chunk-53EPMEWX.mjs} +55 -31
- package/dist/chunk-53EPMEWX.mjs.map +1 -0
- package/dist/cli.js +54 -30
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.js +55 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
- package/dist/AgentEServer-H3FWDCYM.mjs +0 -7
- package/dist/chunk-OALXQFKY.mjs.map +0 -1
- /package/dist/{AgentEServer-H3FWDCYM.mjs.map → AgentEServer-DT6ETPR6.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -569,6 +569,7 @@ function getDashboardHtml() {
|
|
|
569
569
|
const $app = document.getElementById('app');
|
|
570
570
|
|
|
571
571
|
// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
572
|
+
function esc(s) { return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,'''); }
|
|
572
573
|
function pad(n, w) { return String(n).padStart(w || 4, ' '); }
|
|
573
574
|
function fmt(n) { return typeof n === 'number' ? n.toFixed(3) : '\u2014'; }
|
|
574
575
|
function pct(n) { return typeof n === 'number' ? (n * 100).toFixed(0) + '%' : '\u2014'; }
|
|
@@ -674,15 +675,15 @@ function getDashboardHtml() {
|
|
|
674
675
|
let advisorBtns = '';
|
|
675
676
|
if (isAdvisor && d.result === 'skipped_override') {
|
|
676
677
|
advisorBtns = '<span class="advisor-actions">'
|
|
677
|
-
+ '<button class="advisor-btn approve" onclick="window._approve(\\'' + d.id + '\\')">[Approve]</button>'
|
|
678
|
-
+ '<button class="advisor-btn reject" onclick="window._reject(\\'' + d.id + '\\')">[Reject]</button>'
|
|
678
|
+
+ '<button class="advisor-btn approve" onclick="window._approve(\\'' + esc(d.id) + '\\')">[Approve]</button>'
|
|
679
|
+
+ '<button class="advisor-btn reject" onclick="window._reject(\\'' + esc(d.id) + '\\')">[Reject]</button>'
|
|
679
680
|
+ '</span>';
|
|
680
681
|
}
|
|
681
682
|
|
|
682
683
|
return '<span class="t-tick">[Tick ' + pad(d.tick) + ']</span> '
|
|
683
684
|
+ resultIcon
|
|
684
|
-
+ '<span class="t-principle">[' + (principle.id || '?') + '] ' + (principle.name || '') + ':</span> '
|
|
685
|
-
+ '<span class="t-param">' + (plan.parameter || '\u2014') + ' </span>'
|
|
685
|
+
+ '<span class="t-principle">[' + esc(principle.id || '?') + '] ' + esc(principle.name || '') + ':</span> '
|
|
686
|
+
+ '<span class="t-param">' + esc(plan.parameter || '\u2014') + ' </span>'
|
|
686
687
|
+ '<span class="t-old">' + fmt(plan.currentValue) + '</span>'
|
|
687
688
|
+ '<span class="t-arrow"> \\u2192 </span>'
|
|
688
689
|
+ '<span class="t-new">' + fmt(plan.targetValue) + '</span>'
|
|
@@ -706,8 +707,8 @@ function getDashboardHtml() {
|
|
|
706
707
|
return '<div class="alert-card">'
|
|
707
708
|
+ '<span class="alert-severity ' + sc + '">' + sev + '/10</span>'
|
|
708
709
|
+ '<div class="alert-body">'
|
|
709
|
-
+ '<div class="alert-principle">[' + pid + '] ' + name + '</div>'
|
|
710
|
-
+ '<div class="alert-reason">' + reason + '</div>'
|
|
710
|
+
+ '<div class="alert-principle">[' + esc(pid) + '] ' + esc(name) + '</div>'
|
|
711
|
+
+ '<div class="alert-reason">' + esc(reason) + '</div>'
|
|
711
712
|
+ '</div></div>';
|
|
712
713
|
}).join('');
|
|
713
714
|
}
|
|
@@ -735,10 +736,10 @@ function getDashboardHtml() {
|
|
|
735
736
|
$violationsBody.innerHTML = sorted.map(function(v) {
|
|
736
737
|
return '<tr>'
|
|
737
738
|
+ '<td>' + v.tick + '</td>'
|
|
738
|
-
+ '<td style="color:var(--text-primary);font-family:var(--font-sans)">' + v.principle + '</td>'
|
|
739
|
+
+ '<td style="color:var(--text-primary);font-family:var(--font-sans)">' + esc(v.principle) + '</td>'
|
|
739
740
|
+ '<td><span class="alert-severity ' + sevClass(v.severity) + '">' + v.severity + '</span></td>'
|
|
740
|
-
+ '<td>' + v.parameter + '</td>'
|
|
741
|
-
+ '<td>' + v.result + '</td>'
|
|
741
|
+
+ '<td>' + esc(v.parameter) + '</td>'
|
|
742
|
+
+ '<td>' + esc(v.result) + '</td>'
|
|
742
743
|
+ '</tr>';
|
|
743
744
|
}).join('');
|
|
744
745
|
}
|
|
@@ -764,7 +765,7 @@ function getDashboardHtml() {
|
|
|
764
765
|
$personaBars.innerHTML = entries.map(function(e) {
|
|
765
766
|
const pctVal = total > 0 ? (e[1] / total * 100) : 0;
|
|
766
767
|
return '<div class="persona-row">'
|
|
767
|
-
+ '<div class="persona-label">' + e[0] + '</div>'
|
|
768
|
+
+ '<div class="persona-label">' + esc(e[0]) + '</div>'
|
|
768
769
|
+ '<div class="persona-bar-track"><div class="persona-bar-fill" style="width:' + pctVal + '%"></div></div>'
|
|
769
770
|
+ '<div class="persona-pct">' + pctVal.toFixed(0) + '%</div>'
|
|
770
771
|
+ '</div>';
|
|
@@ -777,12 +778,10 @@ function getDashboardHtml() {
|
|
|
777
778
|
$registryList.innerHTML = '<div class="empty-state">No parameters registered</div>';
|
|
778
779
|
return;
|
|
779
780
|
}
|
|
780
|
-
// Show unique parameters from principles
|
|
781
|
-
const params = new Set();
|
|
782
781
|
$registryList.innerHTML = principles.slice(0, 30).map(function(p) {
|
|
783
782
|
return '<div class="registry-item">'
|
|
784
|
-
+ '<span class="registry-key">[' + p.id + ']</span>'
|
|
785
|
-
+ '<span class="registry-val">' + p.name + '</span>'
|
|
783
|
+
+ '<span class="registry-key">[' + esc(p.id) + ']</span>'
|
|
784
|
+
+ '<span class="registry-val">' + esc(p.name) + '</span>'
|
|
786
785
|
+ '</div>';
|
|
787
786
|
}).join('');
|
|
788
787
|
}
|
|
@@ -973,7 +972,13 @@ var init_dashboard = __esm({
|
|
|
973
972
|
});
|
|
974
973
|
|
|
975
974
|
// src/routes.ts
|
|
975
|
+
function setSecurityHeaders(res) {
|
|
976
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
977
|
+
res.setHeader("X-Frame-Options", "DENY");
|
|
978
|
+
res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
979
|
+
}
|
|
976
980
|
function setCorsHeaders(res, origin) {
|
|
981
|
+
setSecurityHeaders(res);
|
|
977
982
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
978
983
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
979
984
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
@@ -1029,21 +1034,19 @@ function createRouteHandler(server) {
|
|
|
1029
1034
|
const payload = parsed;
|
|
1030
1035
|
const state = payload["state"] ?? parsed;
|
|
1031
1036
|
const events = payload["events"];
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
return;
|
|
1040
|
-
}
|
|
1037
|
+
const validation = server.validateState ? (0, import_core.validateEconomyState)(state) : null;
|
|
1038
|
+
if (validation && !validation.valid) {
|
|
1039
|
+
json(res, 400, {
|
|
1040
|
+
error: "invalid_state",
|
|
1041
|
+
validationErrors: validation.errors
|
|
1042
|
+
}, cors);
|
|
1043
|
+
return;
|
|
1041
1044
|
}
|
|
1042
1045
|
const result = await server.processTick(
|
|
1043
1046
|
state,
|
|
1044
1047
|
Array.isArray(events) ? events : void 0
|
|
1045
1048
|
);
|
|
1046
|
-
const warnings =
|
|
1049
|
+
const warnings = validation?.warnings ?? [];
|
|
1047
1050
|
json(res, 200, {
|
|
1048
1051
|
adjustments: result.adjustments,
|
|
1049
1052
|
alerts: result.alerts.map((a) => ({
|
|
@@ -1071,12 +1074,18 @@ function createRouteHandler(server) {
|
|
|
1071
1074
|
return;
|
|
1072
1075
|
}
|
|
1073
1076
|
if (path === "/decisions" && method === "GET") {
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1077
|
+
const rawLimit = parseInt(url.searchParams.get("limit") ?? "100", 10);
|
|
1078
|
+
const limit = Math.min(Math.max(isNaN(rawLimit) ? 100 : rawLimit, 1), 1e3);
|
|
1079
|
+
const sinceParam = url.searchParams.get("since");
|
|
1076
1080
|
const agentE = server.getAgentE();
|
|
1077
1081
|
let decisions;
|
|
1078
|
-
if (
|
|
1079
|
-
|
|
1082
|
+
if (sinceParam) {
|
|
1083
|
+
const since = parseInt(sinceParam, 10);
|
|
1084
|
+
if (isNaN(since)) {
|
|
1085
|
+
json(res, 400, { error: 'Invalid "since" parameter \u2014 must be a number' }, cors);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
decisions = agentE.getDecisions({ since });
|
|
1080
1089
|
} else {
|
|
1081
1090
|
decisions = agentE.log.latest(limit);
|
|
1082
1091
|
}
|
|
@@ -1107,6 +1116,14 @@ function createRouteHandler(server) {
|
|
|
1107
1116
|
for (const c of config["constrain"]) {
|
|
1108
1117
|
if (c && typeof c === "object" && typeof c["param"] === "string" && typeof c["min"] === "number" && typeof c["max"] === "number") {
|
|
1109
1118
|
const constraint = c;
|
|
1119
|
+
if (!isFinite(constraint.min) || !isFinite(constraint.max)) {
|
|
1120
|
+
json(res, 400, { error: "Constraint bounds must be finite numbers" }, cors);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
if (constraint.min > constraint.max) {
|
|
1124
|
+
json(res, 400, { error: "Constraint min cannot exceed max" }, cors);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1110
1127
|
server.constrain(constraint.param, { min: constraint.min, max: constraint.max });
|
|
1111
1128
|
}
|
|
1112
1129
|
}
|
|
@@ -1163,6 +1180,7 @@ function createRouteHandler(server) {
|
|
|
1163
1180
|
}
|
|
1164
1181
|
if (path === "/" && method === "GET" && server.serveDashboard) {
|
|
1165
1182
|
setCorsHeaders(res, cors);
|
|
1183
|
+
res.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self' ws: wss:; img-src 'self' data:");
|
|
1166
1184
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1167
1185
|
res.end(getDashboardHtml());
|
|
1168
1186
|
return;
|
|
@@ -1290,7 +1308,7 @@ function send(ws, data) {
|
|
|
1290
1308
|
}
|
|
1291
1309
|
}
|
|
1292
1310
|
function createWebSocketHandler(httpServer, server) {
|
|
1293
|
-
const wss = new import_ws.WebSocketServer({ server: httpServer });
|
|
1311
|
+
const wss = new import_ws.WebSocketServer({ server: httpServer, maxPayload: MAX_WS_PAYLOAD });
|
|
1294
1312
|
const aliveMap = /* @__PURE__ */ new WeakMap();
|
|
1295
1313
|
const heartbeatInterval = setInterval(() => {
|
|
1296
1314
|
for (const ws of wss.clients) {
|
|
@@ -1305,6 +1323,10 @@ function createWebSocketHandler(httpServer, server) {
|
|
|
1305
1323
|
}
|
|
1306
1324
|
}, 3e4);
|
|
1307
1325
|
wss.on("connection", (ws) => {
|
|
1326
|
+
if (wss.clients.size > MAX_WS_CONNECTIONS) {
|
|
1327
|
+
ws.close(1013, "Server at capacity");
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1308
1330
|
console.log("[AgentE Server] Client connected");
|
|
1309
1331
|
aliveMap.set(ws, true);
|
|
1310
1332
|
ws.on("pong", () => {
|
|
@@ -1426,12 +1448,14 @@ function createWebSocketHandler(httpServer, server) {
|
|
|
1426
1448
|
broadcast
|
|
1427
1449
|
};
|
|
1428
1450
|
}
|
|
1429
|
-
var import_ws, import_core2;
|
|
1451
|
+
var import_ws, import_core2, MAX_WS_PAYLOAD, MAX_WS_CONNECTIONS;
|
|
1430
1452
|
var init_websocket = __esm({
|
|
1431
1453
|
"src/websocket.ts"() {
|
|
1432
1454
|
"use strict";
|
|
1433
1455
|
import_ws = require("ws");
|
|
1434
1456
|
import_core2 = require("@agent-e/core");
|
|
1457
|
+
MAX_WS_PAYLOAD = 1048576;
|
|
1458
|
+
MAX_WS_CONNECTIONS = 100;
|
|
1435
1459
|
}
|
|
1436
1460
|
});
|
|
1437
1461
|
|
|
@@ -1458,7 +1482,7 @@ var init_AgentEServer = __esm({
|
|
|
1458
1482
|
this.port = config.port ?? 3100;
|
|
1459
1483
|
this.host = config.host ?? "0.0.0.0";
|
|
1460
1484
|
this.validateState = config.validateState ?? true;
|
|
1461
|
-
this.corsOrigin = config.corsOrigin ?? "
|
|
1485
|
+
this.corsOrigin = config.corsOrigin ?? "http://localhost:3100";
|
|
1462
1486
|
this.serveDashboard = config.serveDashboard ?? true;
|
|
1463
1487
|
const adapter = {
|
|
1464
1488
|
getState: () => {
|