@wrongstack/acp 1.0.26 → 1.0.27

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
@@ -1691,6 +1691,16 @@ import { treeKill } from "@wrongstack/core/utils/tree-kill";
1691
1691
  var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
1692
1692
  var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
1693
1693
  var DEFAULT_MAX_QUEUED_CHARS = 32 * 1024 * 1024;
1694
+ function takeLines(pending, chunk) {
1695
+ const lines = [];
1696
+ let start = 0;
1697
+ for (let nl = chunk.indexOf("\n"); nl !== -1; nl = chunk.indexOf("\n", start)) {
1698
+ lines.push(pending + chunk.slice(start, nl));
1699
+ pending = "";
1700
+ start = nl + 1;
1701
+ }
1702
+ return { lines, pending: pending + chunk.slice(start) };
1703
+ }
1694
1704
  function positiveLimit(value, fallback) {
1695
1705
  return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
1696
1706
  }
@@ -1778,9 +1788,8 @@ var StdioTransport = class {
1778
1788
  this.claimHandlers.clear();
1779
1789
  }
1780
1790
  onData(chunk) {
1781
- this.buffer += chunk;
1782
- const lines = this.buffer.split("\n");
1783
- this.buffer = lines.pop() ?? "";
1791
+ const { lines, pending } = takeLines(this.buffer, chunk);
1792
+ this.buffer = pending;
1784
1793
  if (this.buffer.length > this.maxFrameChars) {
1785
1794
  this.stderr.write(
1786
1795
  `[wstack-acp frame error] pending frame exceeds ${this.maxFrameChars} characters
package/dist/client.js CHANGED
@@ -11,6 +11,16 @@ import {
11
11
  var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
12
12
  var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
13
13
  var DEFAULT_MAX_QUEUED_CHARS = 32 * 1024 * 1024;
14
+ function takeLines(pending, chunk) {
15
+ const lines = [];
16
+ let start = 0;
17
+ for (let nl = chunk.indexOf("\n"); nl !== -1; nl = chunk.indexOf("\n", start)) {
18
+ lines.push(pending + chunk.slice(start, nl));
19
+ pending = "";
20
+ start = nl + 1;
21
+ }
22
+ return { lines, pending: pending + chunk.slice(start) };
23
+ }
14
24
  function positiveLimit(value, fallback) {
15
25
  return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
16
26
  }
@@ -178,9 +188,8 @@ var ClientTransport = class {
178
188
  this.child = null;
179
189
  }
180
190
  onChildData(chunk) {
181
- this.buffer += chunk;
182
- const lines = this.buffer.split("\n");
183
- this.buffer = lines.pop() ?? "";
191
+ const { lines, pending } = takeLines(this.buffer, chunk);
192
+ this.buffer = pending;
184
193
  if (this.buffer.length > this.maxFrameChars) {
185
194
  writeErr(`[acp-child pending frame exceeds ${this.maxFrameChars} characters]
186
195
  `);
@@ -1263,11 +1272,30 @@ function makePermissionPolicy(decide) {
1263
1272
  // src/client/terminal-server.ts
1264
1273
  import { spawn } from "node:child_process";
1265
1274
  import { randomBytes as randomBytes2 } from "node:crypto";
1266
- import { realpathSync as realpathSync2 } from "node:fs";
1275
+ import { accessSync, realpathSync as realpathSync2 } from "node:fs";
1267
1276
  import * as path2 from "node:path";
1268
1277
  import { buildChildEnv } from "@wrongstack/core/utils";
1269
1278
  import { treeKill as treeKill2 } from "@wrongstack/core/utils/tree-kill";
1270
1279
  var EMPTY_BUFFER = Buffer.alloc(0);
1280
+ function win32BatchTarget(command) {
1281
+ if (/\.(?:cmd|bat)$/i.test(command)) return command;
1282
+ if (/[\\/]/.test(command) || path2.extname(command)) return void 0;
1283
+ const exts = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").toLowerCase().split(";");
1284
+ for (const dir of (process.env["PATH"] ?? "").split(path2.delimiter)) {
1285
+ if (!dir) continue;
1286
+ for (const ext of exts) {
1287
+ if (!ext) continue;
1288
+ const full = path2.join(dir, `${command}${ext}`);
1289
+ try {
1290
+ accessSync(full);
1291
+ } catch {
1292
+ continue;
1293
+ }
1294
+ return ext === ".cmd" || ext === ".bat" ? full : void 0;
1295
+ }
1296
+ }
1297
+ return void 0;
1298
+ }
1271
1299
  var DEBUG_DISPOSE = typeof process !== "undefined" && !!process.env?.WRONGSTACK_DEBUG && process.env.WRONGSTACK_DEBUG !== "0" && process.env.WRONGSTACK_DEBUG !== "false";
1272
1300
  var TerminalServer = class {
1273
1301
  terminals = /* @__PURE__ */ new Map();
@@ -1318,11 +1346,14 @@ var TerminalServer = class {
1318
1346
  Math.max(1, this.clampFiniteInt(params.outputByteLimit, this.outputByteLimit)),
1319
1347
  this.maxOutputByteLimit
1320
1348
  );
1321
- const proc = spawn(params.command, params.args ?? [], {
1349
+ const batch = process.platform === "win32" ? win32BatchTarget(params.command) : void 0;
1350
+ const shim = batch ? buildWin32CmdShimInvocation(batch, params.args ?? []) : void 0;
1351
+ const proc = spawn(shim?.command ?? params.command, shim?.args ?? params.args ?? [], {
1322
1352
  cwd,
1323
1353
  env: this.buildEnv(params.env),
1324
1354
  stdio: ["ignore", "pipe", "pipe"],
1325
- windowsHide: true
1355
+ windowsHide: true,
1356
+ ...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
1326
1357
  // shell: false on purpose. The terminal server is invoked with
1327
1358
  // the agent's explicit argv; turning on shell-mode would make
1328
1359
  // the command a single shell-parsed string, which breaks
package/dist/index.js CHANGED
@@ -991,6 +991,16 @@ import {
991
991
  var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
992
992
  var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
993
993
  var DEFAULT_MAX_QUEUED_CHARS = 32 * 1024 * 1024;
994
+ function takeLines(pending, chunk) {
995
+ const lines = [];
996
+ let start = 0;
997
+ for (let nl = chunk.indexOf("\n"); nl !== -1; nl = chunk.indexOf("\n", start)) {
998
+ lines.push(pending + chunk.slice(start, nl));
999
+ pending = "";
1000
+ start = nl + 1;
1001
+ }
1002
+ return { lines, pending: pending + chunk.slice(start) };
1003
+ }
994
1004
  function positiveLimit(value, fallback) {
995
1005
  return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
996
1006
  }
@@ -1078,9 +1088,8 @@ var StdioTransport = class {
1078
1088
  this.claimHandlers.clear();
1079
1089
  }
1080
1090
  onData(chunk) {
1081
- this.buffer += chunk;
1082
- const lines = this.buffer.split("\n");
1083
- this.buffer = lines.pop() ?? "";
1091
+ const { lines, pending } = takeLines(this.buffer, chunk);
1092
+ this.buffer = pending;
1084
1093
  if (this.buffer.length > this.maxFrameChars) {
1085
1094
  this.stderr.write(
1086
1095
  `[wstack-acp frame error] pending frame exceeds ${this.maxFrameChars} characters
@@ -1320,9 +1329,8 @@ var ClientTransport = class {
1320
1329
  this.child = null;
1321
1330
  }
1322
1331
  onChildData(chunk) {
1323
- this.buffer += chunk;
1324
- const lines = this.buffer.split("\n");
1325
- this.buffer = lines.pop() ?? "";
1332
+ const { lines, pending } = takeLines(this.buffer, chunk);
1333
+ this.buffer = pending;
1326
1334
  if (this.buffer.length > this.maxFrameChars) {
1327
1335
  writeErr(`[acp-child pending frame exceeds ${this.maxFrameChars} characters]
1328
1336
  `);
@@ -2786,11 +2794,30 @@ function makePermissionPolicy(decide) {
2786
2794
  // src/client/terminal-server.ts
2787
2795
  import { spawn } from "node:child_process";
2788
2796
  import { randomBytes as randomBytes2 } from "node:crypto";
2789
- import { realpathSync as realpathSync2 } from "node:fs";
2797
+ import { accessSync, realpathSync as realpathSync2 } from "node:fs";
2790
2798
  import * as path3 from "node:path";
2791
2799
  import { buildChildEnv } from "@wrongstack/core/utils";
2792
2800
  import { treeKill as treeKill2 } from "@wrongstack/core/utils/tree-kill";
2793
2801
  var EMPTY_BUFFER = Buffer.alloc(0);
2802
+ function win32BatchTarget(command) {
2803
+ if (/\.(?:cmd|bat)$/i.test(command)) return command;
2804
+ if (/[\\/]/.test(command) || path3.extname(command)) return void 0;
2805
+ const exts = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").toLowerCase().split(";");
2806
+ for (const dir of (process.env["PATH"] ?? "").split(path3.delimiter)) {
2807
+ if (!dir) continue;
2808
+ for (const ext of exts) {
2809
+ if (!ext) continue;
2810
+ const full = path3.join(dir, `${command}${ext}`);
2811
+ try {
2812
+ accessSync(full);
2813
+ } catch {
2814
+ continue;
2815
+ }
2816
+ return ext === ".cmd" || ext === ".bat" ? full : void 0;
2817
+ }
2818
+ }
2819
+ return void 0;
2820
+ }
2794
2821
  var DEBUG_DISPOSE = typeof process !== "undefined" && !!process.env?.WRONGSTACK_DEBUG && process.env.WRONGSTACK_DEBUG !== "0" && process.env.WRONGSTACK_DEBUG !== "false";
2795
2822
  var TerminalServer = class {
2796
2823
  terminals = /* @__PURE__ */ new Map();
@@ -2841,11 +2868,14 @@ var TerminalServer = class {
2841
2868
  Math.max(1, this.clampFiniteInt(params.outputByteLimit, this.outputByteLimit)),
2842
2869
  this.maxOutputByteLimit
2843
2870
  );
2844
- const proc = spawn(params.command, params.args ?? [], {
2871
+ const batch = process.platform === "win32" ? win32BatchTarget(params.command) : void 0;
2872
+ const shim = batch ? buildWin32CmdShimInvocation(batch, params.args ?? []) : void 0;
2873
+ const proc = spawn(shim?.command ?? params.command, shim?.args ?? params.args ?? [], {
2845
2874
  cwd,
2846
2875
  env: this.buildEnv(params.env),
2847
2876
  stdio: ["ignore", "pipe", "pipe"],
2848
- windowsHide: true
2877
+ windowsHide: true,
2878
+ ...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
2849
2879
  // shell: false on purpose. The terminal server is invoked with
2850
2880
  // the agent's explicit argv; turning on shell-mode would make
2851
2881
  // the command a single shell-parsed string, which breaks
@@ -988,6 +988,16 @@ import { treeKill } from "@wrongstack/core/utils/tree-kill";
988
988
  var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
989
989
  var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
990
990
  var DEFAULT_MAX_QUEUED_CHARS = 32 * 1024 * 1024;
991
+ function takeLines(pending, chunk) {
992
+ const lines = [];
993
+ let start = 0;
994
+ for (let nl = chunk.indexOf("\n"); nl !== -1; nl = chunk.indexOf("\n", start)) {
995
+ lines.push(pending + chunk.slice(start, nl));
996
+ pending = "";
997
+ start = nl + 1;
998
+ }
999
+ return { lines, pending: pending + chunk.slice(start) };
1000
+ }
991
1001
  function positiveLimit(value, fallback) {
992
1002
  return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
993
1003
  }
@@ -1075,9 +1085,8 @@ var StdioTransport = class {
1075
1085
  this.claimHandlers.clear();
1076
1086
  }
1077
1087
  onData(chunk) {
1078
- this.buffer += chunk;
1079
- const lines = this.buffer.split("\n");
1080
- this.buffer = lines.pop() ?? "";
1088
+ const { lines, pending } = takeLines(this.buffer, chunk);
1089
+ this.buffer = pending;
1081
1090
  if (this.buffer.length > this.maxFrameChars) {
1082
1091
  this.stderr.write(
1083
1092
  `[wstack-acp frame error] pending frame exceeds ${this.maxFrameChars} characters
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/acp",
3
- "version": "1.0.26",
3
+ "version": "1.0.27",
4
4
  "license": "MIT",
5
5
  "description": "ACP (Agent Client Protocol) integration for WrongStack — client + agent support",
6
6
  "keywords": [
@@ -52,8 +52,8 @@
52
52
  ],
53
53
  "dependencies": {
54
54
  "@agentclientprotocol/sdk": "^1.4.0",
55
- "@wrongstack/core": "1.0.26",
56
- "@wrongstack/primitives": "1.0.26"
55
+ "@wrongstack/core": "1.0.27",
56
+ "@wrongstack/primitives": "1.0.27"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "^26.5.1",