@wrongstack/acp 0.293.0 → 0.295.1

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.
Files changed (63) hide show
  1. package/README.md +22 -2
  2. package/dist/agent/protocol-contract.d.ts +210 -0
  3. package/dist/agent/protocol-contract.d.ts.map +1 -0
  4. package/dist/agent/protocol-handler.d.ts +15 -189
  5. package/dist/agent/protocol-handler.d.ts.map +1 -1
  6. package/dist/agent/server-agent-turn.d.ts +89 -1
  7. package/dist/agent/server-agent-turn.d.ts.map +1 -1
  8. package/dist/agent/session-store.d.ts.map +1 -1
  9. package/dist/agent/stdio-transport.d.ts +30 -1
  10. package/dist/agent/stdio-transport.d.ts.map +1 -1
  11. package/dist/agent/tools-registry.d.ts +1 -1
  12. package/dist/agent/tools-registry.d.ts.map +1 -1
  13. package/dist/agent/wrongstack-acp-agent.d.ts +37 -0
  14. package/dist/agent/wrongstack-acp-agent.d.ts.map +1 -1
  15. package/dist/agent.js +189 -32
  16. package/dist/agent.js.map +4 -4
  17. package/dist/client/acp-session.d.ts +13 -1
  18. package/dist/client/acp-session.d.ts.map +1 -1
  19. package/dist/client/file-server.d.ts +19 -0
  20. package/dist/client/file-server.d.ts.map +1 -1
  21. package/dist/client/index.d.ts +11 -9
  22. package/dist/client/index.d.ts.map +1 -1
  23. package/dist/client/terminal-server.d.ts +5 -0
  24. package/dist/client/terminal-server.d.ts.map +1 -1
  25. package/dist/client/tool-translator.d.ts +1 -1
  26. package/dist/client/tool-translator.d.ts.map +1 -1
  27. package/dist/client/trust-boundary-permission.d.ts +31 -0
  28. package/dist/client/trust-boundary-permission.d.ts.map +1 -0
  29. package/dist/client/websocket-transport.d.ts +6 -0
  30. package/dist/client/websocket-transport.d.ts.map +1 -1
  31. package/dist/client.js +459 -243
  32. package/dist/client.js.map +4 -4
  33. package/dist/index.d.ts +29 -29
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2116 -1802
  36. package/dist/index.js.map +4 -4
  37. package/dist/integration/acp-bench.d.ts +32 -0
  38. package/dist/integration/acp-bench.d.ts.map +1 -1
  39. package/dist/integration/acp-subagent-runner.d.ts +3 -3
  40. package/dist/integration/acp-subagent-runner.d.ts.map +1 -1
  41. package/dist/integration/ensemble-runner.d.ts +22 -1
  42. package/dist/integration/ensemble-runner.d.ts.map +1 -1
  43. package/dist/legacy.d.ts +8 -0
  44. package/dist/legacy.d.ts.map +1 -0
  45. package/dist/legacy.js +6 -0
  46. package/dist/legacy.js.map +7 -0
  47. package/dist/registry/acp-registry-fetch.d.ts +1 -1
  48. package/dist/registry/acp-registry-fetch.d.ts.map +1 -1
  49. package/dist/registry/ensemble-registry.d.ts +22 -0
  50. package/dist/registry/ensemble-registry.d.ts.map +1 -1
  51. package/dist/sdk.d.ts +10 -8
  52. package/dist/sdk.d.ts.map +1 -1
  53. package/dist/sdk.js +22 -0
  54. package/dist/sdk.js.map +3 -3
  55. package/dist/v1.d.ts +3 -0
  56. package/dist/v1.d.ts.map +1 -0
  57. package/dist/v1.js +12 -0
  58. package/dist/v1.js.map +7 -0
  59. package/dist/version.d.ts +10 -0
  60. package/dist/version.d.ts.map +1 -0
  61. package/dist/wrongstack-acp-agent.js +121 -24
  62. package/dist/wrongstack-acp-agent.js.map +4 -4
  63. package/package.json +10 -2
@@ -1,16 +1,33 @@
1
1
  // src/agent/wrongstack-acp-agent.ts
2
- import { fileURLToPath } from "node:url";
3
2
  import { createServer } from "node:http";
4
- import { writeErr as writeErr2 } from "@wrongstack/core";
3
+ import { fileURLToPath } from "node:url";
4
+ import { writeErr as writeErr2 } from "@wrongstack/core/utils";
5
5
 
6
6
  // src/types/acp-v1.ts
7
7
  var ACP_PROTOCOL_VERSION = 1;
8
8
 
9
- // src/agent/protocol-handler.ts
9
+ // src/version.ts
10
+ import { createRequire } from "node:module";
11
+ var require2 = createRequire(import.meta.url);
12
+ function readPackageVersion(load = () => require2("../package.json")) {
13
+ try {
14
+ const packageJson = load();
15
+ if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
16
+ return packageJson.version;
17
+ }
18
+ } catch {
19
+ }
20
+ return "dev";
21
+ }
22
+ var ACP_PACKAGE_VERSION = readPackageVersion();
23
+
24
+ // src/agent/protocol-contract.ts
10
25
  function toWire(msg) {
11
26
  return msg;
12
27
  }
13
- var WRONGSTACK_VERSION = "0.274.1";
28
+ var WRONGSTACK_VERSION = ACP_PACKAGE_VERSION;
29
+
30
+ // src/agent/protocol-handler.ts
14
31
  var WRONGSTACK_AUTH_METHODS = [
15
32
  {
16
33
  id: "wrongstack-auth",
@@ -21,6 +38,7 @@ var WRONGSTACK_AUTH_METHODS = [
21
38
  }
22
39
  ];
23
40
  var DEFAULT_MODE_ID = "code";
41
+ var DEFAULT_MAX_SESSIONS = 64;
24
42
  var DEFAULT_MODES = [
25
43
  {
26
44
  id: DEFAULT_MODE_ID,
@@ -38,6 +56,8 @@ var ACPProtocolHandler = class {
38
56
  agentName;
39
57
  replayFor;
40
58
  seedFor;
59
+ disposeFor;
60
+ maxSessions;
41
61
  store;
42
62
  initialized = false;
43
63
  clientCapabilities = {};
@@ -58,6 +78,8 @@ var ACPProtocolHandler = class {
58
78
  this.agentName = opts.agentName ?? "wrongstack";
59
79
  this.replayFor = opts.replayFor;
60
80
  this.seedFor = opts.seedFor;
81
+ this.disposeFor = opts.disposeFor;
82
+ this.maxSessions = Number.isFinite(opts.maxSessions) && opts.maxSessions > 0 ? Math.floor(opts.maxSessions) : DEFAULT_MAX_SESSIONS;
61
83
  this.store = opts.store;
62
84
  if (typeof this.transport.onMessage === "function") {
63
85
  this.transport.onMessage((m) => this.maybeResolvePending(m));
@@ -115,8 +137,9 @@ var ACPProtocolHandler = class {
115
137
  }
116
138
  /** Abort all active turns and drop session state. */
117
139
  close() {
118
- for (const [, session] of this.sessions) {
140
+ for (const [sessionId, session] of this.sessions) {
119
141
  session.abort.abort();
142
+ this.disposeSession(sessionId);
120
143
  }
121
144
  this.sessions.clear();
122
145
  for (const [, p] of this.pendingOut) {
@@ -125,6 +148,12 @@ var ACPProtocolHandler = class {
125
148
  }
126
149
  this.pendingOut.clear();
127
150
  }
151
+ disposeSession(sessionId) {
152
+ try {
153
+ this.disposeFor?.(sessionId);
154
+ } catch {
155
+ }
156
+ }
128
157
  // ────────────────────────────────────────────────────────────────────
129
158
  // Requests
130
159
  // ────────────────────────────────────────────────────────────────────
@@ -244,6 +273,10 @@ var ACPProtocolHandler = class {
244
273
  return false;
245
274
  }
246
275
  async handleSessionNew(id, params) {
276
+ if (this.sessions.size >= this.maxSessions) {
277
+ await this.sendError(id, -32e3, `active session limit reached (${this.maxSessions})`);
278
+ return false;
279
+ }
247
280
  const p = params ?? {};
248
281
  const cwd = typeof p.cwd === "string" ? p.cwd : this.defaultCwd;
249
282
  const sessionId = `sess_${this.allocId()}`;
@@ -294,6 +327,10 @@ var ACPProtocolHandler = class {
294
327
  if (!existing && sessionId && this.store) {
295
328
  const persisted = await this.store.load(sessionId);
296
329
  if (persisted) {
330
+ if (this.sessions.size >= this.maxSessions) {
331
+ await this.sendError(id, -32e3, `active session limit reached (${this.maxSessions})`);
332
+ return false;
333
+ }
297
334
  const restored = {
298
335
  id: sessionId,
299
336
  cwd: persisted.cwd ?? loadCwd ?? this.defaultCwd,
@@ -324,7 +361,7 @@ var ACPProtocolHandler = class {
324
361
  }
325
362
  if (existing) {
326
363
  existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
327
- const replay = sessionId ? this.replayFor?.(sessionId) : void 0;
364
+ const replay = this.replayFor?.(sessionId);
328
365
  if (replay) {
329
366
  for (const update of replay) {
330
367
  await this.sendNotification({ sessionId, update });
@@ -389,7 +426,8 @@ var ACPProtocolHandler = class {
389
426
  return false;
390
427
  }
391
428
  session.abort.abort();
392
- if (sessionId) this.sessions.delete(sessionId);
429
+ this.sessions.delete(sessionId);
430
+ this.disposeSession(sessionId);
393
431
  await this.transport.send(toWire({
394
432
  jsonrpc: "2.0",
395
433
  id,
@@ -411,6 +449,7 @@ var ACPProtocolHandler = class {
411
449
  const session = this.sessions.get(sessionId);
412
450
  session.abort.abort();
413
451
  this.sessions.delete(sessionId);
452
+ this.disposeSession(sessionId);
414
453
  await this.transport.send(toWire({
415
454
  jsonrpc: "2.0",
416
455
  id,
@@ -426,6 +465,10 @@ var ACPProtocolHandler = class {
426
465
  await this.sendError(id, -32e3, `session not found: ${sourceId}`);
427
466
  return false;
428
467
  }
468
+ if (this.sessions.size >= this.maxSessions) {
469
+ await this.sendError(id, -32e3, `active session limit reached (${this.maxSessions})`);
470
+ return false;
471
+ }
429
472
  const now = (/* @__PURE__ */ new Date()).toISOString();
430
473
  const sessionId = `sess_${this.allocId()}`;
431
474
  const forked = {
@@ -692,7 +735,13 @@ function errorToJsonRpc(err) {
692
735
  }
693
736
 
694
737
  // src/agent/stdio-transport.ts
695
- import { expectDefined, writeErr } from "@wrongstack/core";
738
+ import { expectDefined, writeErr } from "@wrongstack/core/utils";
739
+ import { treeKill } from "@wrongstack/core/utils/tree-kill";
740
+ var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
741
+ var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
742
+ function positiveLimit(value, fallback) {
743
+ return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
744
+ }
696
745
  var StdioTransport = class {
697
746
  stdin = process.stdin;
698
747
  stdout = process.stdout;
@@ -702,7 +751,11 @@ var StdioTransport = class {
702
751
  closed = false;
703
752
  resolveRead = null;
704
753
  messageQueue = [];
705
- constructor() {
754
+ maxFrameChars;
755
+ maxQueuedMessages;
756
+ constructor(opts = {}) {
757
+ this.maxFrameChars = positiveLimit(opts.maxFrameChars, DEFAULT_MAX_FRAME_CHARS);
758
+ this.maxQueuedMessages = positiveLimit(opts.maxQueuedMessages, DEFAULT_MAX_QUEUED_MESSAGES);
706
759
  this.stdin.resume();
707
760
  this.stdin.setEncoding("utf8");
708
761
  this.stdin.on("data", (chunk) => this.onData(chunk));
@@ -723,7 +776,8 @@ var StdioTransport = class {
723
776
  this.stdout.write(chunk, "utf8");
724
777
  }
725
778
  read() {
726
- if (this.messageQueue.length > 0) return Promise.resolve(expectDefined(this.messageQueue.shift()));
779
+ if (this.messageQueue.length > 0)
780
+ return Promise.resolve(expectDefined(this.messageQueue.shift()));
727
781
  if (this.closed) return Promise.resolve(null);
728
782
  return new Promise((resolve) => {
729
783
  this.resolveRead = resolve;
@@ -738,13 +792,34 @@ var StdioTransport = class {
738
792
  this.stdin.pause();
739
793
  this.resolveRead?.(null);
740
794
  this.resolveRead = null;
795
+ this.buffer = "";
796
+ this.messageQueue.length = 0;
797
+ this.handlers.clear();
741
798
  }
742
799
  onData(chunk) {
743
800
  this.buffer += chunk;
744
801
  const lines = this.buffer.split("\n");
745
802
  this.buffer = lines.pop() ?? "";
803
+ if (this.buffer.length > this.maxFrameChars) {
804
+ this.stderr.write(
805
+ `[wstack-acp frame error] pending frame exceeds ${this.maxFrameChars} characters
806
+ `,
807
+ "utf8"
808
+ );
809
+ this.close();
810
+ return;
811
+ }
746
812
  for (const raw of lines) {
747
813
  if (!raw.trim()) continue;
814
+ if (raw.length > this.maxFrameChars) {
815
+ this.stderr.write(
816
+ `[wstack-acp frame error] frame exceeds ${this.maxFrameChars} characters
817
+ `,
818
+ "utf8"
819
+ );
820
+ this.close();
821
+ return;
822
+ }
748
823
  try {
749
824
  this.dispatch(JSON.parse(raw));
750
825
  } catch (err) {
@@ -759,6 +834,15 @@ var StdioTransport = class {
759
834
  this.resolveRead = null;
760
835
  resolve(msg);
761
836
  } else {
837
+ if (this.messageQueue.length >= this.maxQueuedMessages) {
838
+ this.stderr.write(
839
+ `[wstack-acp queue error] pending message queue exceeds ${this.maxQueuedMessages} entries
840
+ `,
841
+ "utf8"
842
+ );
843
+ this.close();
844
+ return;
845
+ }
762
846
  this.messageQueue.push(msg);
763
847
  }
764
848
  for (const handler of this.handlers) {
@@ -771,9 +855,7 @@ var StdioTransport = class {
771
855
  }
772
856
  }
773
857
  handleClose() {
774
- this.closed = true;
775
- this.resolveRead?.(null);
776
- this.resolveRead = null;
858
+ this.close();
777
859
  }
778
860
  failAll(err) {
779
861
  this.stderr.write(`[wstack-acp stdin error] ${err.message}
@@ -801,6 +883,7 @@ var WrongStackACPServer = class {
801
883
  agentName: opts.agentName,
802
884
  ...opts.replayFor ? { replayFor: opts.replayFor } : {},
803
885
  ...opts.seedFor ? { seedFor: opts.seedFor } : {},
886
+ ...opts.disposeFor ? { disposeFor: opts.disposeFor } : {},
804
887
  ...opts.store ? { store: opts.store } : {}
805
888
  });
806
889
  }
@@ -822,13 +905,17 @@ var WrongStackACPServer = class {
822
905
  this.transport.sendStartupMarker();
823
906
  }
824
907
  this.running = true;
825
- while (this.running) {
826
- const msg = await this.transport.read();
827
- if (!msg) break;
828
- const terminal = await this.handler.handleMessage(msg);
829
- if (terminal) break;
908
+ try {
909
+ while (this.running) {
910
+ const msg = await this.transport.read();
911
+ if (!msg) break;
912
+ const terminal = await this.handler.handleMessage(msg);
913
+ if (terminal) break;
914
+ }
915
+ } finally {
916
+ this.handler.close();
917
+ this.transport.close();
830
918
  }
831
- this.transport.close();
832
919
  }
833
920
  async startHttp(port) {
834
921
  const host = this.options.host ?? "127.0.0.1";
@@ -837,10 +924,9 @@ var WrongStackACPServer = class {
837
924
  let httpChain = Promise.resolve();
838
925
  this.httpServer = createServer(async (req, res) => {
839
926
  if (authToken) {
840
- const url = new URL(req.url ?? "/", `http://${host}:${port}`);
927
+ const url = new URL(requestPath(req.url), `http://${host}:${port}`);
841
928
  const queryToken = url.searchParams.get("token");
842
- const authHeader = req.headers["authorization"];
843
- const bearerToken = Array.isArray(authHeader) ? authHeader[0]?.replace(/^Bearer\s+/i, "") : authHeader?.replace(/^Bearer\s+/i, "");
929
+ const bearerToken = headerValue(req.headers.authorization)?.replace(/^Bearer\s+/i, "");
844
930
  const supplied = queryToken ?? bearerToken ?? "";
845
931
  if (supplied !== authToken) {
846
932
  res.writeHead(401, { "Content-Type": "application/json" });
@@ -849,7 +935,7 @@ var WrongStackACPServer = class {
849
935
  }
850
936
  }
851
937
  const selfOrigin = `http://${host}:${port}`;
852
- const reqOrigin = Array.isArray(req.headers.origin) ? req.headers.origin[0] : req.headers.origin;
938
+ const reqOrigin = headerValue(req.headers.origin);
853
939
  if (reqOrigin && reqOrigin !== selfOrigin) {
854
940
  res.writeHead(403);
855
941
  res.end(JSON.stringify({ error: "cross-origin request forbidden" }));
@@ -929,6 +1015,8 @@ var WrongStackACPServer = class {
929
1015
  try {
930
1016
  await requestPromise;
931
1017
  } catch {
1018
+ res.writeHead(500, { "Content-Type": "application/json" });
1019
+ res.end(JSON.stringify({ error: { code: -32603, message: "Internal error" } }));
932
1020
  }
933
1021
  });
934
1022
  return new Promise((resolve) => {
@@ -943,6 +1031,7 @@ var WrongStackACPServer = class {
943
1031
  /** Stop the server. */
944
1032
  stop() {
945
1033
  this.running = false;
1034
+ this.handler.close();
946
1035
  this.transport.close();
947
1036
  if (this.httpServer) {
948
1037
  this.httpServer.close();
@@ -953,6 +1042,13 @@ var WrongStackACPServer = class {
953
1042
  var defaultEchoRunTurn = async (_input, _emit) => {
954
1043
  return { stopReason: "end_turn" };
955
1044
  };
1045
+ function headerValue(value) {
1046
+ return Array.isArray(value) ? value[0] : value;
1047
+ }
1048
+ function requestPath(value) {
1049
+ return value ?? "/";
1050
+ }
1051
+ var wrongStackACPServerCoverage = { defaultEchoRunTurn, headerValue, requestPath };
956
1052
  async function main() {
957
1053
  const server = new WrongStackACPServer();
958
1054
  await server.start();
@@ -966,6 +1062,7 @@ if (isEntrypoint) {
966
1062
  });
967
1063
  }
968
1064
  export {
969
- WrongStackACPServer
1065
+ WrongStackACPServer,
1066
+ wrongStackACPServerCoverage
970
1067
  };
971
1068
  //# sourceMappingURL=wrongstack-acp-agent.js.map