@wrongstack/acp 0.276.4 → 0.277.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.
package/dist/sdk.js CHANGED
@@ -11,6 +11,32 @@ import { createServer } from 'http';
11
11
  import { SubagentBudget } from '@wrongstack/core/coordination';
12
12
 
13
13
  // src/sdk.ts
14
+
15
+ // src/win32-cmd.ts
16
+ var WIN32_CMD_META = /[&|<>"\r\n\0]/;
17
+ function buildWin32CmdShimInvocation(command, args = []) {
18
+ assertSafeWin32CmdArgs([command, ...args]);
19
+ const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
20
+ return {
21
+ command: process.env["COMSPEC"] ?? "cmd.exe",
22
+ args: ["/d", "/c", line],
23
+ windowsVerbatimArguments: true
24
+ };
25
+ }
26
+ function assertSafeWin32CmdArgs(args) {
27
+ for (const arg of args) {
28
+ if (typeof arg === "string" && WIN32_CMD_META.test(arg)) {
29
+ throw new Error(
30
+ 'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
31
+ );
32
+ }
33
+ }
34
+ }
35
+ function quoteWin32CmdArg(arg) {
36
+ return `"${arg}"`;
37
+ }
38
+
39
+ // src/agent/stdio-transport.ts
14
40
  var StdioTransport = class {
15
41
  stdin = process.stdin;
16
42
  stdout = process.stdout;
@@ -129,19 +155,14 @@ var ClientTransport = class {
129
155
  const isPkgLauncher = this.opts.command === "npx" || this.opts.command === "uvx";
130
156
  const spawnCwd = isPkgLauncher ? os.homedir() : this.opts.cwd;
131
157
  try {
132
- this.child = spawn2(this.opts.command, this.opts.args ?? [], {
158
+ const childArgs = this.opts.args ?? [];
159
+ const shim = process.platform === "win32" ? buildWin32CmdShimInvocation(this.opts.command, childArgs) : null;
160
+ this.child = spawn2(shim?.command ?? this.opts.command, shim?.args ?? childArgs, {
133
161
  env: { ...buildChildEnv(), ...this.opts.env },
134
162
  cwd: spawnCwd,
135
163
  stdio: ["pipe", "pipe", "pipe"],
136
164
  windowsHide: true,
137
- // On Windows, most ACP-supporting tools (claude, gemini, codex,
138
- // qwen, copilot) are installed as `.cmd` shims under
139
- // AppData\Roaming\npm\. Node's spawn won't find them via
140
- // `shell: false` because the .cmd extension is not in the
141
- // default PATHEXT lookup. The argv here is always from our
142
- // own static catalog or from a hardcoded spec, never from
143
- // user input, so shell-expansion is bounded.
144
- shell: process.platform === "win32"
165
+ ...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
145
166
  });
146
167
  } catch (err) {
147
168
  clearTimeout(timeout);