@wrongstack/acp 0.298.3 → 0.300.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/dist/agent.js CHANGED
@@ -933,10 +933,16 @@ var ACPProtocolHandler = class {
933
933
  }
934
934
  };
935
935
  let result;
936
+ const pendingNotifications = [];
937
+ const emit = (update) => {
938
+ const p2 = this.sendNotification({ sessionId, update });
939
+ pendingNotifications.push(p2.catch(() => {
940
+ }));
941
+ };
936
942
  try {
937
943
  result = await this.runTurn(
938
944
  { sessionId, prompt: p.prompt, signal: turnSignal.signal },
939
- (update) => this.sendNotification({ sessionId, update }),
945
+ emit,
940
946
  api
941
947
  );
942
948
  } catch (err) {
@@ -945,6 +951,7 @@ var ACPProtocolHandler = class {
945
951
  await this.sendError(id, code, message, data);
946
952
  return false;
947
953
  }
954
+ await Promise.all(pendingNotifications);
948
955
  session.abort.signal.removeEventListener("abort", onCancel);
949
956
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
950
957
  await this.persist(session);
@@ -1439,6 +1446,7 @@ var WsBridgeTransport = class {
1439
1446
  };
1440
1447
 
1441
1448
  // src/agent/wrongstack-acp-agent.ts
1449
+ import { timingSafeEqual } from "node:crypto";
1442
1450
  import { createServer } from "node:http";
1443
1451
  import { isIP } from "node:net";
1444
1452
  import { fileURLToPath } from "node:url";
@@ -1506,10 +1514,10 @@ var WrongStackACPServer = class {
1506
1514
  this.httpServer = createServer(async (req, res) => {
1507
1515
  if (authToken) {
1508
1516
  const url = new URL(requestPath(req.url), `http://${host}:${port}`);
1509
- const queryToken = url.searchParams.get("token");
1510
1517
  const bearerToken = headerValue(req.headers.authorization)?.replace(/^Bearer\s+/i, "");
1511
- const supplied = queryToken ?? bearerToken ?? "";
1512
- if (supplied !== authToken) {
1518
+ const queryToken = url.searchParams.get("token");
1519
+ const queryOk = queryToken !== null && isLoopbackPeer(req) && timingSafeTokenEqual(queryToken, authToken);
1520
+ if (!queryOk && !timingSafeTokenEqual(bearerToken ?? "", authToken)) {
1513
1521
  res.writeHead(401, { "Content-Type": "application/json" });
1514
1522
  res.end(JSON.stringify({ error: { code: -32001, message: "Unauthorized" } }));
1515
1523
  return;
@@ -1623,6 +1631,17 @@ var WrongStackACPServer = class {
1623
1631
  var defaultEchoRunTurn = async (_input, _emit) => {
1624
1632
  return { stopReason: "end_turn" };
1625
1633
  };
1634
+ function timingSafeTokenEqual(supplied, expected) {
1635
+ if (!supplied || !expected) return false;
1636
+ const a = Buffer.from(supplied);
1637
+ const b = Buffer.from(expected);
1638
+ if (a.length !== b.length) return false;
1639
+ return timingSafeEqual(a, b);
1640
+ }
1641
+ function isLoopbackPeer(req) {
1642
+ const address = req.socket.remoteAddress?.replace(/^::ffff:/i, "");
1643
+ return address !== void 0 && isLoopbackHost(address);
1644
+ }
1626
1645
  function headerValue(value) {
1627
1646
  return Array.isArray(value) ? value[0] : value;
1628
1647
  }
package/dist/index.js CHANGED
@@ -652,10 +652,16 @@ var ACPProtocolHandler = class {
652
652
  }
653
653
  };
654
654
  let result;
655
+ const pendingNotifications = [];
656
+ const emit = (update) => {
657
+ const p2 = this.sendNotification({ sessionId, update });
658
+ pendingNotifications.push(p2.catch(() => {
659
+ }));
660
+ };
655
661
  try {
656
662
  result = await this.runTurn(
657
663
  { sessionId, prompt: p.prompt, signal: turnSignal.signal },
658
- (update) => this.sendNotification({ sessionId, update }),
664
+ emit,
659
665
  api
660
666
  );
661
667
  } catch (err) {
@@ -664,6 +670,7 @@ var ACPProtocolHandler = class {
664
670
  await this.sendError(id, code, message, data);
665
671
  return false;
666
672
  }
673
+ await Promise.all(pendingNotifications);
667
674
  session.abort.signal.removeEventListener("abort", onCancel);
668
675
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
669
676
  await this.persist(session);
@@ -1377,6 +1384,7 @@ function toolToPriority(tool) {
1377
1384
  }
1378
1385
 
1379
1386
  // src/agent/wrongstack-acp-agent.ts
1387
+ import { timingSafeEqual } from "node:crypto";
1380
1388
  import { createServer } from "node:http";
1381
1389
  import { isIP } from "node:net";
1382
1390
  import { fileURLToPath } from "node:url";
@@ -1444,10 +1452,10 @@ var WrongStackACPServer = class {
1444
1452
  this.httpServer = createServer(async (req, res) => {
1445
1453
  if (authToken) {
1446
1454
  const url = new URL(requestPath(req.url), `http://${host}:${port}`);
1447
- const queryToken = url.searchParams.get("token");
1448
1455
  const bearerToken = headerValue(req.headers.authorization)?.replace(/^Bearer\s+/i, "");
1449
- const supplied = queryToken ?? bearerToken ?? "";
1450
- if (supplied !== authToken) {
1456
+ const queryToken = url.searchParams.get("token");
1457
+ const queryOk = queryToken !== null && isLoopbackPeer(req) && timingSafeTokenEqual(queryToken, authToken);
1458
+ if (!queryOk && !timingSafeTokenEqual(bearerToken ?? "", authToken)) {
1451
1459
  res.writeHead(401, { "Content-Type": "application/json" });
1452
1460
  res.end(JSON.stringify({ error: { code: -32001, message: "Unauthorized" } }));
1453
1461
  return;
@@ -1561,6 +1569,17 @@ var WrongStackACPServer = class {
1561
1569
  var defaultEchoRunTurn = async (_input, _emit) => {
1562
1570
  return { stopReason: "end_turn" };
1563
1571
  };
1572
+ function timingSafeTokenEqual(supplied, expected) {
1573
+ if (!supplied || !expected) return false;
1574
+ const a = Buffer.from(supplied);
1575
+ const b = Buffer.from(expected);
1576
+ if (a.length !== b.length) return false;
1577
+ return timingSafeEqual(a, b);
1578
+ }
1579
+ function isLoopbackPeer(req) {
1580
+ const address = req.socket.remoteAddress?.replace(/^::ffff:/i, "");
1581
+ return address !== void 0 && isLoopbackHost(address);
1582
+ }
1564
1583
  function headerValue(value) {
1565
1584
  return Array.isArray(value) ? value[0] : value;
1566
1585
  }
@@ -1,4 +1,5 @@
1
1
  // src/agent/wrongstack-acp-agent.ts
2
+ import { timingSafeEqual } from "node:crypto";
2
3
  import { createServer } from "node:http";
3
4
  import { isIP } from "node:net";
4
5
  import { fileURLToPath } from "node:url";
@@ -653,10 +654,16 @@ var ACPProtocolHandler = class {
653
654
  }
654
655
  };
655
656
  let result;
657
+ const pendingNotifications = [];
658
+ const emit = (update) => {
659
+ const p2 = this.sendNotification({ sessionId, update });
660
+ pendingNotifications.push(p2.catch(() => {
661
+ }));
662
+ };
656
663
  try {
657
664
  result = await this.runTurn(
658
665
  { sessionId, prompt: p.prompt, signal: turnSignal.signal },
659
- (update) => this.sendNotification({ sessionId, update }),
666
+ emit,
660
667
  api
661
668
  );
662
669
  } catch (err) {
@@ -665,6 +672,7 @@ var ACPProtocolHandler = class {
665
672
  await this.sendError(id, code, message, data);
666
673
  return false;
667
674
  }
675
+ await Promise.all(pendingNotifications);
668
676
  session.abort.signal.removeEventListener("abort", onCancel);
669
677
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
670
678
  await this.persist(session);
@@ -1084,10 +1092,10 @@ var WrongStackACPServer = class {
1084
1092
  this.httpServer = createServer(async (req, res) => {
1085
1093
  if (authToken) {
1086
1094
  const url = new URL(requestPath(req.url), `http://${host}:${port}`);
1087
- const queryToken = url.searchParams.get("token");
1088
1095
  const bearerToken = headerValue(req.headers.authorization)?.replace(/^Bearer\s+/i, "");
1089
- const supplied = queryToken ?? bearerToken ?? "";
1090
- if (supplied !== authToken) {
1096
+ const queryToken = url.searchParams.get("token");
1097
+ const queryOk = queryToken !== null && isLoopbackPeer(req) && timingSafeTokenEqual(queryToken, authToken);
1098
+ if (!queryOk && !timingSafeTokenEqual(bearerToken ?? "", authToken)) {
1091
1099
  res.writeHead(401, { "Content-Type": "application/json" });
1092
1100
  res.end(JSON.stringify({ error: { code: -32001, message: "Unauthorized" } }));
1093
1101
  return;
@@ -1201,6 +1209,17 @@ var WrongStackACPServer = class {
1201
1209
  var defaultEchoRunTurn = async (_input, _emit) => {
1202
1210
  return { stopReason: "end_turn" };
1203
1211
  };
1212
+ function timingSafeTokenEqual(supplied, expected) {
1213
+ if (!supplied || !expected) return false;
1214
+ const a = Buffer.from(supplied);
1215
+ const b = Buffer.from(expected);
1216
+ if (a.length !== b.length) return false;
1217
+ return timingSafeEqual(a, b);
1218
+ }
1219
+ function isLoopbackPeer(req) {
1220
+ const address = req.socket.remoteAddress?.replace(/^::ffff:/i, "");
1221
+ return address !== void 0 && isLoopbackHost(address);
1222
+ }
1204
1223
  function headerValue(value) {
1205
1224
  return Array.isArray(value) ? value[0] : value;
1206
1225
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/acp",
3
- "version": "0.298.3",
3
+ "version": "0.300.0",
4
4
  "license": "MIT",
5
5
  "description": "ACP (Agent Client Protocol) integration for WrongStack — client + agent support",
6
6
  "keywords": [
@@ -52,7 +52,7 @@
52
52
  ],
53
53
  "dependencies": {
54
54
  "@agentclientprotocol/sdk": "^1.3.0",
55
- "@wrongstack/core": "0.298.3"
55
+ "@wrongstack/core": "0.300.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/node": "^26.1.2",