agent-dag 1.24.0 → 1.25.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.
@@ -938,6 +938,20 @@ async function serveStatic(req, res, url) {
938
938
  }
939
939
  }
940
940
 
941
+ /** Collect a request body as a string, capped so a bad client can't fill memory. */
942
+ function readBody(req, limit = 64_000) {
943
+ return new Promise((resolve, reject) => {
944
+ let body = "";
945
+ req.setEncoding("utf8");
946
+ req.on("data", c => {
947
+ body += c;
948
+ if (body.length > limit) { req.destroy(); reject(new Error("body too large")); }
949
+ });
950
+ req.on("end", () => resolve(body));
951
+ req.on("error", reject);
952
+ });
953
+ }
954
+
941
955
  function handleEventIngest(req, res) {
942
956
  let body = "";
943
957
  req.setEncoding("utf8");
@@ -1035,6 +1049,31 @@ async function handleCcusage(req, res) {
1035
1049
  send(res, 200, data);
1036
1050
  }
1037
1051
 
1052
+ async function handleClaudeAccounts(req, res) {
1053
+ const { fetchClaudeAccounts } = await import(
1054
+ pathToFileURL(join(PKG_ROOT, "src/server/claude-accounts.mjs")).href
1055
+ );
1056
+ const url = new URL(req.url, "http://localhost");
1057
+ const force = url.searchParams.get("refresh") === "1";
1058
+ send(res, 200, await fetchClaudeAccounts({ force }));
1059
+ }
1060
+
1061
+ async function handleClaudeAccountSwitch(req, res) {
1062
+ const { switchClaudeAccount, invalidateClaudeAccountsCache } = await import(
1063
+ pathToFileURL(join(PKG_ROOT, "src/server/claude-accounts.mjs")).href
1064
+ );
1065
+ const body = await readBody(req).catch(() => null);
1066
+ let parsed = null;
1067
+ try { parsed = JSON.parse(body ?? ""); } catch { /* handled below */ }
1068
+ if (!parsed || typeof parsed !== "object") return send(res, 400, { ok: false, reason: "bad_request" });
1069
+
1070
+ const result = await switchClaudeAccount(parsed.account);
1071
+ // The active account just moved; the next poll should see it immediately
1072
+ // rather than serving the pre-switch roster for another few seconds.
1073
+ invalidateClaudeAccountsCache();
1074
+ send(res, result.ok ? 200 : 400, result);
1075
+ }
1076
+
1038
1077
  function handleHealth(_req, res) {
1039
1078
  send(res, 200, {
1040
1079
  ok: true,
@@ -1115,6 +1154,8 @@ export async function startServer({ port = 4317, host = "127.0.0.1", persist = n
1115
1154
  if (req.method === "GET" && url.pathname === "/api/codex-usage") return guard(handleCodexUsage(req, res), res);
1116
1155
  if (req.method === "GET" && url.pathname === "/api/codex-quota") return guard(handleCodexQuota(req, res), res);
1117
1156
  if (req.method === "GET" && url.pathname === "/api/ccusage") return guard(handleCcusage(req, res), res);
1157
+ if (req.method === "GET" && url.pathname === "/api/claude-accounts") return guard(handleClaudeAccounts(req, res), res);
1158
+ if (req.method === "POST" && url.pathname === "/api/claude-accounts/switch") return guard(handleClaudeAccountSwitch(req, res), res);
1118
1159
 
1119
1160
  if (req.method === "GET" && url.pathname === "/api/events") {
1120
1161
  const since = Number(url.searchParams.get("since") ?? 0);