@agent-e/server 1.6.10 → 1.6.12

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/cli.js CHANGED
@@ -28,6 +28,7 @@ var http = __toESM(require("http"));
28
28
  var import_core3 = require("@agent-e/core");
29
29
 
30
30
  // src/routes.ts
31
+ var import_node_crypto = require("crypto");
31
32
  var import_core = require("@agent-e/core");
32
33
 
33
34
  // src/dashboard.ts
@@ -974,8 +975,17 @@ function setSecurityHeaders(res) {
974
975
  }
975
976
  function setCorsHeaders(res, allowedOrigin, requestOrigin) {
976
977
  setSecurityHeaders(res);
977
- const origin = allowedOrigin === "*" ? "*" : requestOrigin === allowedOrigin ? allowedOrigin : allowedOrigin;
978
- res.setHeader("Access-Control-Allow-Origin", origin);
978
+ let origin;
979
+ if (allowedOrigin === "*") {
980
+ origin = "*";
981
+ } else if (requestOrigin === void 0) {
982
+ origin = allowedOrigin;
983
+ } else {
984
+ origin = requestOrigin.toLowerCase() === allowedOrigin.toLowerCase() ? requestOrigin : "";
985
+ }
986
+ if (origin) {
987
+ res.setHeader("Access-Control-Allow-Origin", origin);
988
+ }
979
989
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
980
990
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
981
991
  }
@@ -992,7 +1002,10 @@ function sanitizeJson(obj) {
992
1002
  function checkAuth(req, apiKey) {
993
1003
  if (!apiKey) return true;
994
1004
  const header = req.headers["authorization"];
995
- return header === `Bearer ${apiKey}`;
1005
+ if (typeof header !== "string") return false;
1006
+ const expected = `Bearer ${apiKey}`;
1007
+ if (header.length !== expected.length) return false;
1008
+ return (0, import_node_crypto.timingSafeEqual)(Buffer.from(header), Buffer.from(expected));
996
1009
  }
997
1010
  function json(res, status, data, origin, reqOrigin) {
998
1011
  setCorsHeaders(res, origin, reqOrigin);
@@ -1024,8 +1037,10 @@ function createRouteHandler(server2) {
1024
1037
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
1025
1038
  const path = url.pathname;
1026
1039
  const method = req.method?.toUpperCase() ?? "GET";
1040
+ const reqOrigin = req.headers["origin"];
1041
+ const respond = (status, data) => json(res, status, data, cors, reqOrigin);
1027
1042
  if (method === "OPTIONS") {
1028
- setCorsHeaders(res, cors);
1043
+ setCorsHeaders(res, cors, reqOrigin);
1029
1044
  res.writeHead(204);
1030
1045
  res.end();
1031
1046
  return;
@@ -1033,7 +1048,7 @@ function createRouteHandler(server2) {
1033
1048
  try {
1034
1049
  if (path === "/tick" && method === "POST") {
1035
1050
  if (!checkAuth(req, apiKey)) {
1036
- json(res, 401, { error: "Unauthorized" }, cors);
1051
+ respond(401, { error: "Unauthorized" });
1037
1052
  return;
1038
1053
  }
1039
1054
  const body = await readBody(req);
@@ -1041,11 +1056,11 @@ function createRouteHandler(server2) {
1041
1056
  try {
1042
1057
  parsed = sanitizeJson(JSON.parse(body));
1043
1058
  } catch {
1044
- json(res, 400, { error: "Invalid JSON" }, cors);
1059
+ respond(400, { error: "Invalid JSON" });
1045
1060
  return;
1046
1061
  }
1047
1062
  if (!parsed || typeof parsed !== "object") {
1048
- json(res, 400, { error: "Body must be a JSON object" }, cors);
1063
+ respond(400, { error: "Body must be a JSON object" });
1049
1064
  return;
1050
1065
  }
1051
1066
  const payload = parsed;
@@ -1053,10 +1068,10 @@ function createRouteHandler(server2) {
1053
1068
  const events = payload["events"];
1054
1069
  const validation = server2.validateState ? (0, import_core.validateEconomyState)(state) : null;
1055
1070
  if (validation && !validation.valid) {
1056
- json(res, 400, {
1071
+ respond(400, {
1057
1072
  error: "invalid_state",
1058
1073
  validationErrors: validation.errors
1059
- }, cors);
1074
+ });
1060
1075
  return;
1061
1076
  }
1062
1077
  const result = await server2.processTick(
@@ -1064,7 +1079,7 @@ function createRouteHandler(server2) {
1064
1079
  Array.isArray(events) ? events : void 0
1065
1080
  );
1066
1081
  const warnings = validation?.warnings ?? [];
1067
- json(res, 200, {
1082
+ respond(200, {
1068
1083
  adjustments: result.adjustments,
1069
1084
  alerts: result.alerts.map((a) => ({
1070
1085
  principleId: a.principle.id,
@@ -1076,18 +1091,18 @@ function createRouteHandler(server2) {
1076
1091
  health: result.health,
1077
1092
  tick: result.tick,
1078
1093
  ...warnings.length > 0 ? { validationWarnings: warnings } : {}
1079
- }, cors);
1094
+ });
1080
1095
  return;
1081
1096
  }
1082
1097
  if (path === "/health" && method === "GET") {
1083
1098
  const agentE = server2.getAgentE();
1084
- json(res, 200, {
1099
+ respond(200, {
1085
1100
  health: agentE.getHealth(),
1086
1101
  tick: agentE.metrics.latest()?.tick ?? 0,
1087
1102
  mode: agentE.getMode(),
1088
1103
  activePlans: agentE.getActivePlans().length,
1089
1104
  uptime: server2.getUptime()
1090
- }, cors);
1105
+ });
1091
1106
  return;
1092
1107
  }
1093
1108
  if (path === "/decisions" && method === "GET") {
@@ -1099,19 +1114,19 @@ function createRouteHandler(server2) {
1099
1114
  if (sinceParam) {
1100
1115
  const since = parseInt(sinceParam, 10);
1101
1116
  if (Number.isNaN(since)) {
1102
- json(res, 400, { error: 'Invalid "since" parameter \u2014 must be a number' }, cors);
1117
+ respond(400, { error: 'Invalid "since" parameter \u2014 must be a number' });
1103
1118
  return;
1104
1119
  }
1105
1120
  decisions = agentE.getDecisions({ since });
1106
1121
  } else {
1107
1122
  decisions = agentE.log.latest(limit);
1108
1123
  }
1109
- json(res, 200, { decisions }, cors);
1124
+ respond(200, { decisions });
1110
1125
  return;
1111
1126
  }
1112
1127
  if (path === "/config" && method === "POST") {
1113
1128
  if (!checkAuth(req, apiKey)) {
1114
- json(res, 401, { error: "Unauthorized" }, cors);
1129
+ respond(401, { error: "Unauthorized" });
1115
1130
  return;
1116
1131
  }
1117
1132
  const body = await readBody(req);
@@ -1119,7 +1134,7 @@ function createRouteHandler(server2) {
1119
1134
  try {
1120
1135
  parsed = sanitizeJson(JSON.parse(body));
1121
1136
  } catch {
1122
- json(res, 400, { error: "Invalid JSON" }, cors);
1137
+ respond(400, { error: "Invalid JSON" });
1123
1138
  return;
1124
1139
  }
1125
1140
  const config = parsed;
@@ -1139,11 +1154,11 @@ function createRouteHandler(server2) {
1139
1154
  if (c && typeof c === "object" && typeof c["param"] === "string" && typeof c["min"] === "number" && typeof c["max"] === "number") {
1140
1155
  const constraint = c;
1141
1156
  if (!Number.isFinite(constraint.min) || !Number.isFinite(constraint.max)) {
1142
- json(res, 400, { error: "Constraint bounds must be finite numbers" }, cors);
1157
+ respond(400, { error: "Constraint bounds must be finite numbers" });
1143
1158
  return;
1144
1159
  }
1145
1160
  if (constraint.min > constraint.max) {
1146
- json(res, 400, { error: "Constraint min cannot exceed max" }, cors);
1161
+ respond(400, { error: "Constraint min cannot exceed max" });
1147
1162
  return;
1148
1163
  }
1149
1164
  validated.push(constraint);
@@ -1156,12 +1171,12 @@ function createRouteHandler(server2) {
1156
1171
  if (config["mode"] === "autonomous" || config["mode"] === "advisor") {
1157
1172
  server2.setMode(config["mode"]);
1158
1173
  }
1159
- json(res, 200, { ok: true }, cors);
1174
+ respond(200, { ok: true });
1160
1175
  return;
1161
1176
  }
1162
1177
  if (path === "/principles" && method === "GET") {
1163
1178
  const principles = server2.getAgentE().getPrinciples();
1164
- json(res, 200, {
1179
+ respond(200, {
1165
1180
  count: principles.length,
1166
1181
  principles: principles.map((p) => ({
1167
1182
  id: p.id,
@@ -1169,12 +1184,12 @@ function createRouteHandler(server2) {
1169
1184
  category: p.category,
1170
1185
  description: p.description
1171
1186
  }))
1172
- }, cors);
1187
+ });
1173
1188
  return;
1174
1189
  }
1175
1190
  if (path === "/diagnose" && method === "POST") {
1176
1191
  if (!checkAuth(req, apiKey)) {
1177
- json(res, 401, { error: "Unauthorized" }, cors);
1192
+ respond(401, { error: "Unauthorized" });
1178
1193
  return;
1179
1194
  }
1180
1195
  const body = await readBody(req);
@@ -1182,7 +1197,7 @@ function createRouteHandler(server2) {
1182
1197
  try {
1183
1198
  parsed = sanitizeJson(JSON.parse(body));
1184
1199
  } catch {
1185
- json(res, 400, { error: "Invalid JSON" }, cors);
1200
+ respond(400, { error: "Invalid JSON" });
1186
1201
  return;
1187
1202
  }
1188
1203
  const payload = parsed;
@@ -1190,12 +1205,12 @@ function createRouteHandler(server2) {
1190
1205
  if (server2.validateState) {
1191
1206
  const validation = (0, import_core.validateEconomyState)(state);
1192
1207
  if (!validation.valid) {
1193
- json(res, 400, { error: "invalid_state", validationErrors: validation.errors }, cors);
1208
+ respond(400, { error: "invalid_state", validationErrors: validation.errors });
1194
1209
  return;
1195
1210
  }
1196
1211
  }
1197
1212
  const result = server2.diagnoseOnly(state);
1198
- json(res, 200, {
1213
+ respond(200, {
1199
1214
  health: result.health,
1200
1215
  diagnoses: result.diagnoses.map((d) => ({
1201
1216
  principleId: d.principle.id,
@@ -1204,11 +1219,11 @@ function createRouteHandler(server2) {
1204
1219
  evidence: d.violation.evidence,
1205
1220
  suggestedAction: d.violation.suggestedAction
1206
1221
  }))
1207
- }, cors);
1222
+ });
1208
1223
  return;
1209
1224
  }
1210
1225
  if (path === "/" && method === "GET" && server2.serveDashboard) {
1211
- setCorsHeaders(res, cors);
1226
+ setCorsHeaders(res, cors, reqOrigin);
1212
1227
  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:");
1213
1228
  res.setHeader("Cache-Control", "public, max-age=60");
1214
1229
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -1219,7 +1234,7 @@ function createRouteHandler(server2) {
1219
1234
  const agentE = server2.getAgentE();
1220
1235
  const latest = agentE.store.latest();
1221
1236
  const history = agentE.store.recentHistory(100);
1222
- json(res, 200, { latest, history }, cors);
1237
+ respond(200, { latest, history });
1223
1238
  return;
1224
1239
  }
1225
1240
  if (path === "/metrics/personas" && method === "GET") {
@@ -1227,12 +1242,12 @@ function createRouteHandler(server2) {
1227
1242
  const latest = agentE.store.latest();
1228
1243
  const dist = latest.personaDistribution || {};
1229
1244
  const total = Object.values(dist).reduce((s, v) => s + v, 0);
1230
- json(res, 200, { distribution: dist, total }, cors);
1245
+ respond(200, { distribution: dist, total });
1231
1246
  return;
1232
1247
  }
1233
1248
  if (path === "/approve" && method === "POST") {
1234
1249
  if (!checkAuth(req, apiKey)) {
1235
- json(res, 401, { error: "Unauthorized" }, cors);
1250
+ respond(401, { error: "Unauthorized" });
1236
1251
  return;
1237
1252
  }
1238
1253
  const body = await readBody(req);
@@ -1240,42 +1255,42 @@ function createRouteHandler(server2) {
1240
1255
  try {
1241
1256
  parsed = sanitizeJson(JSON.parse(body));
1242
1257
  } catch {
1243
- json(res, 400, { error: "Invalid JSON" }, cors);
1258
+ respond(400, { error: "Invalid JSON" });
1244
1259
  return;
1245
1260
  }
1246
1261
  const payload = parsed;
1247
1262
  const decisionId = payload["decisionId"];
1248
1263
  if (!decisionId) {
1249
- json(res, 400, { error: "missing_decision_id" }, cors);
1264
+ respond(400, { error: "missing_decision_id" });
1250
1265
  return;
1251
1266
  }
1252
1267
  const agentE = server2.getAgentE();
1253
1268
  if (agentE.getMode() !== "advisor") {
1254
- json(res, 400, { error: "not_in_advisor_mode" }, cors);
1269
+ respond(400, { error: "not_in_advisor_mode" });
1255
1270
  return;
1256
1271
  }
1257
1272
  const entry = agentE.log.getById(decisionId);
1258
1273
  if (!entry) {
1259
- json(res, 404, { error: "decision_not_found" }, cors);
1274
+ respond(404, { error: "decision_not_found" });
1260
1275
  return;
1261
1276
  }
1262
1277
  if (entry.result !== "skipped_override") {
1263
- json(res, 409, { error: "decision_not_pending", currentResult: entry.result }, cors);
1278
+ respond(409, { error: "decision_not_pending", currentResult: entry.result });
1264
1279
  return;
1265
1280
  }
1266
1281
  await agentE.apply(entry.plan);
1267
1282
  agentE.log.updateResult(decisionId, "applied");
1268
1283
  server2.broadcast({ type: "advisor_action", action: "approved", decisionId });
1269
- json(res, 200, {
1284
+ respond(200, {
1270
1285
  ok: true,
1271
1286
  parameter: entry.plan.parameter,
1272
1287
  value: entry.plan.targetValue
1273
- }, cors);
1288
+ });
1274
1289
  return;
1275
1290
  }
1276
1291
  if (path === "/reject" && method === "POST") {
1277
1292
  if (!checkAuth(req, apiKey)) {
1278
- json(res, 401, { error: "Unauthorized" }, cors);
1293
+ respond(401, { error: "Unauthorized" });
1279
1294
  return;
1280
1295
  }
1281
1296
  const body = await readBody(req);
@@ -1283,49 +1298,49 @@ function createRouteHandler(server2) {
1283
1298
  try {
1284
1299
  parsed = sanitizeJson(JSON.parse(body));
1285
1300
  } catch {
1286
- json(res, 400, { error: "Invalid JSON" }, cors);
1301
+ respond(400, { error: "Invalid JSON" });
1287
1302
  return;
1288
1303
  }
1289
1304
  const payload = parsed;
1290
1305
  const decisionId = payload["decisionId"];
1291
1306
  const reason = payload["reason"] || void 0;
1292
1307
  if (!decisionId) {
1293
- json(res, 400, { error: "missing_decision_id" }, cors);
1308
+ respond(400, { error: "missing_decision_id" });
1294
1309
  return;
1295
1310
  }
1296
1311
  const agentE = server2.getAgentE();
1297
1312
  if (agentE.getMode() !== "advisor") {
1298
- json(res, 400, { error: "not_in_advisor_mode" }, cors);
1313
+ respond(400, { error: "not_in_advisor_mode" });
1299
1314
  return;
1300
1315
  }
1301
1316
  const entry = agentE.log.getById(decisionId);
1302
1317
  if (!entry) {
1303
- json(res, 404, { error: "decision_not_found" }, cors);
1318
+ respond(404, { error: "decision_not_found" });
1304
1319
  return;
1305
1320
  }
1306
1321
  if (entry.result !== "skipped_override") {
1307
- json(res, 409, { error: "decision_not_pending", currentResult: entry.result }, cors);
1322
+ respond(409, { error: "decision_not_pending", currentResult: entry.result });
1308
1323
  return;
1309
1324
  }
1310
1325
  agentE.log.updateResult(decisionId, "rejected", reason);
1311
1326
  server2.broadcast({ type: "advisor_action", action: "rejected", decisionId, reason });
1312
- json(res, 200, { ok: true, decisionId }, cors);
1327
+ respond(200, { ok: true, decisionId });
1313
1328
  return;
1314
1329
  }
1315
1330
  if (path === "/pending" && method === "GET") {
1316
1331
  const agentE = server2.getAgentE();
1317
1332
  const pending = agentE.log.query({ result: "skipped_override" });
1318
- json(res, 200, {
1333
+ respond(200, {
1319
1334
  mode: agentE.getMode(),
1320
1335
  pending,
1321
1336
  count: pending.length
1322
- }, cors);
1337
+ });
1323
1338
  return;
1324
1339
  }
1325
- json(res, 404, { error: "Not found" }, cors);
1340
+ respond(404, { error: "Not found" });
1326
1341
  } catch (err) {
1327
1342
  console.error("[AgentE Server] Unhandled route error:", err);
1328
- json(res, 500, { error: "Internal server error" }, cors);
1343
+ respond(500, { error: "Internal server error" });
1329
1344
  }
1330
1345
  };
1331
1346
  }
@@ -1371,6 +1386,13 @@ function createWebSocketHandler(httpServer, server2) {
1371
1386
  ws.close(1013, "Server at capacity");
1372
1387
  return;
1373
1388
  }
1389
+ const wsOrigin = req.headers["origin"];
1390
+ if (wsOrigin && server2.corsOrigin !== "*") {
1391
+ if (wsOrigin.toLowerCase() !== server2.corsOrigin.toLowerCase()) {
1392
+ ws.close(1008, "Origin not allowed");
1393
+ return;
1394
+ }
1395
+ }
1374
1396
  if (server2.apiKey) {
1375
1397
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
1376
1398
  const token = url.searchParams.get("token") ?? req.headers["authorization"]?.replace("Bearer ", "");
@@ -1682,7 +1704,7 @@ var AgentEServer = class {
1682
1704
 
1683
1705
  // src/cli.ts
1684
1706
  var port = parseInt(process.env["AGENTE_PORT"] ?? "3100", 10);
1685
- var host = process.env["AGENTE_HOST"] ?? "0.0.0.0";
1707
+ var host = process.env["AGENTE_HOST"] ?? "127.0.0.1";
1686
1708
  var mode = process.env["AGENTE_MODE"] === "advisor" ? "advisor" : "autonomous";
1687
1709
  var server = new AgentEServer({
1688
1710
  port,