@agentproto/driver-agent-cli 2.5.1 → 2.6.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.
@@ -2,9 +2,9 @@ import { z } from 'zod';
2
2
  import { Writable, Readable } from 'stream';
3
3
  import { createAcpClient } from '@agentproto/acp/client';
4
4
  import { spawn, execFile } from 'child_process';
5
- import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync, mkdtempSync } from 'fs';
5
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync, realpathSync, mkdtempSync } from 'fs';
6
6
  import { createInterface } from 'readline';
7
- import { join, delimiter, dirname, basename } from 'path';
7
+ import { join, resolve, delimiter, dirname, basename } from 'path';
8
8
  import { tmpdir, homedir } from 'os';
9
9
  import { loadAdapterSpawnSandboxConfig, resolveCommandSandbox } from '@agentproto/command-sandbox';
10
10
  import { randomUUID, createHash } from 'crypto';
@@ -701,18 +701,34 @@ function isAlive(pid) {
701
701
  }
702
702
  }
703
703
  function listProcesses() {
704
- return new Promise((resolve) => {
704
+ return new Promise((resolve2) => {
705
705
  execFile("ps", ["-axo", "pid=,ppid="], { maxBuffer: 32 * 1024 * 1024 }, (err, stdout) => {
706
- if (err) return resolve([]);
706
+ if (err) return resolve2([]);
707
707
  const out = [];
708
708
  for (const line of stdout.split("\n")) {
709
709
  const m = line.match(/^\s*(\d+)\s+(\d+)\s*$/);
710
710
  if (m) out.push({ pid: Number(m[1]), ppid: Number(m[2]) });
711
711
  }
712
- resolve(out);
712
+ resolve2(out);
713
713
  });
714
714
  });
715
715
  }
716
+ function isWindowsBatchFile(exe, deps) {
717
+ if ((process.platform) !== "win32") return false;
718
+ return /\.(?:bat|cmd)$/i.test(exe);
719
+ }
720
+ function windowsBatchShellOption(exe, deps) {
721
+ if (isWindowsBatchFile(exe)) return { shell: true };
722
+ return {};
723
+ }
724
+ function resolveWindowsBatchSpawn(bin, args, deps) {
725
+ if ((process.platform) !== "win32") return void 0;
726
+ if (!isWindowsBatchFile(bin)) return void 0;
727
+ const stem = basename(bin).replace(/\.(?:bat|cmd)$/i, "");
728
+ if (stem !== "npx" && stem !== "npm") return void 0;
729
+ join(dirname(bin), "node_modules", "npm", "bin", `${stem}-cli.js`);
730
+ return void 0;
731
+ }
716
732
  function defaultToolchainWritePaths() {
717
733
  const home = homedir();
718
734
  return [
@@ -743,8 +759,13 @@ function defaultToolchainReadPaths() {
743
759
  }
744
760
  async function wrapAgentCliSpawn(bin, args, opts) {
745
761
  const cfg = await loadAdapterSpawnSandboxConfig(opts.cwd);
746
- const mode = opts.mode ?? cfg.mode;
762
+ const mode = opts.zones ? opts.mode ?? "workspace" : opts.mode ?? cfg.mode;
747
763
  if (mode === void 0) return [bin, args];
764
+ if (mode === "off" && opts.zones) {
765
+ throw new Error(
766
+ `agent-cli '${opts.label}': filesystem zones (an app boundary) cannot be combined with commandSandbox "off" \u2014 the zones are only enforceable through the OS sandbox. Refusing to spawn.`
767
+ );
768
+ }
748
769
  if (mode === "off") {
749
770
  console.error(
750
771
  `[agent-cli] \u26A0 spawning '${opts.label}' UNCONFINED \u2014 no OS-level sandbox is active (commandSandbox mode is "off").`
@@ -757,18 +778,20 @@ async function wrapAgentCliSpawn(bin, args, opts) {
757
778
  `agent-cli '${opts.label}': commandSandbox mode="${mode}" is configured but no sandbox backend is available on ${process.platform} (macOS needs sandbox-exec, Linux needs bwrap installed). Refusing to spawn unconfined \u2014 pass commandSandbox: "off" to explicitly accept unconfined execution, or install the missing backend.`
758
779
  );
759
780
  }
781
+ const fileCfg = opts.zones ? void 0 : cfg;
760
782
  const policy = {
761
783
  workspace: opts.cwd,
762
784
  extraReadPaths: [
763
785
  ...defaultToolchainReadPaths(),
764
- ...cfg.extraReadPaths,
786
+ ...fileCfg?.extraReadPaths ?? [],
765
787
  ...opts.extraReadPaths ?? []
766
788
  ],
767
789
  extraWritePaths: [
768
790
  ...defaultToolchainWritePaths(),
769
- ...cfg.extraWritePaths,
791
+ ...fileCfg?.extraWritePaths ?? [],
770
792
  ...opts.extraWritePaths ?? []
771
793
  ],
794
+ ...opts.zones ? { zones: opts.zones } : {},
772
795
  network: mode === "strict" || cfg.network === "deny" ? "deny" : "allow"
773
796
  };
774
797
  const wrapped = backend.wrap([bin, ...args], policy);
@@ -777,12 +800,12 @@ async function wrapAgentCliSpawn(bin, args, opts) {
777
800
 
778
801
  // src/protocol/print-arm.ts
779
802
  function printModelMismatch(requested, reported) {
780
- const basename2 = (id) => {
803
+ const basename3 = (id) => {
781
804
  const noSuffix = id.split("@")[0] ?? id;
782
805
  const segs = noSuffix.split("/");
783
806
  return (segs[segs.length - 1] ?? noSuffix).trim().toLowerCase();
784
807
  };
785
- return basename2(requested) !== basename2(reported);
808
+ return basename3(requested) !== basename3(reported);
786
809
  }
787
810
  var DEFAULT_OUTPUT = ["--output-format", "stream-json"];
788
811
  var DEFAULT_PRE_PROMPT = ["--no-interactive"];
@@ -822,20 +845,26 @@ function createPrintSession(opts) {
822
845
  cwd: opts.cwd,
823
846
  ...opts.extraWritePaths ? { extraWritePaths: opts.extraWritePaths } : {},
824
847
  ...opts.extraReadPaths ? { extraReadPaths: opts.extraReadPaths } : {},
848
+ ...opts.fsZones ? { zones: opts.fsZones } : {},
825
849
  label: "print-arm"
826
850
  });
827
851
  const child = spawn(execBin, execArgs, {
828
852
  cwd: opts.cwd,
829
853
  env: opts.env,
830
- stdio: ["ignore", "pipe", "pipe"]
854
+ stdio: ["ignore", "pipe", "pipe"],
855
+ // Win32: only reached for a `.cmd`/`.bat` bin that
856
+ // `resolveWindowsBatchSpawn` couldn't rewrite to its node entry
857
+ // (see `win32-spawn.ts` — Node refuses direct batch spawning,
858
+ // CVE-2024-27980, the recap-10 `spawn EINVAL`). POSIX: `{}`.
859
+ ...windowsBatchShellOption(execBin)
831
860
  });
832
861
  activeChild = child;
833
862
  let spawnFailure;
834
- await new Promise((resolve) => {
835
- child.once("spawn", () => resolve());
863
+ await new Promise((resolve2) => {
864
+ child.once("spawn", () => resolve2());
836
865
  child.once("error", (err) => {
837
866
  spawnFailure = err;
838
- resolve();
867
+ resolve2();
839
868
  });
840
869
  });
841
870
  if (spawnFailure) {
@@ -1454,16 +1483,16 @@ var EventQueue = class {
1454
1483
  `print-arm: event backlog exceeded ${QUEUE_HIGH_WATER_MARK} buffered events \u2014 downstream consumer is not keeping up. The child's stdout is still being drained (no ENOBUFS), but memory will grow until the consumer catches up.`
1455
1484
  );
1456
1485
  }
1457
- const resolve = this.resolveNext;
1486
+ const resolve2 = this.resolveNext;
1458
1487
  this.resolveNext = null;
1459
- resolve?.();
1488
+ resolve2?.();
1460
1489
  }
1461
1490
  /** Signal that no further events will be pushed. */
1462
1491
  end() {
1463
1492
  this.ended = true;
1464
- const resolve = this.resolveNext;
1493
+ const resolve2 = this.resolveNext;
1465
1494
  this.resolveNext = null;
1466
- resolve?.();
1495
+ resolve2?.();
1467
1496
  }
1468
1497
  async *[Symbol.asyncIterator]() {
1469
1498
  for (; ; ) {
@@ -1473,8 +1502,8 @@ var EventQueue = class {
1473
1502
  continue;
1474
1503
  }
1475
1504
  if (this.ended) return;
1476
- await new Promise((resolve) => {
1477
- this.resolveNext = resolve;
1505
+ await new Promise((resolve2) => {
1506
+ this.resolveNext = resolve2;
1478
1507
  });
1479
1508
  }
1480
1509
  }
@@ -1493,9 +1522,9 @@ function mapMastraFinishReason(raw) {
1493
1522
  }
1494
1523
  }
1495
1524
  function waitForExit(child) {
1496
- return new Promise((resolve) => {
1497
- child.once("exit", (code) => resolve(code));
1498
- child.once("error", () => resolve(null));
1525
+ return new Promise((resolve2) => {
1526
+ child.once("exit", (code) => resolve2(code));
1527
+ child.once("error", () => resolve2(null));
1499
1528
  });
1500
1529
  }
1501
1530
 
@@ -1744,6 +1773,42 @@ function interpolateEnv(env, value) {
1744
1773
  }
1745
1774
  return out;
1746
1775
  }
1776
+ function agentCliSupportsHostContextIsolation(adapterId) {
1777
+ return adapterId === "claude-code";
1778
+ }
1779
+ function escapeGlob(p) {
1780
+ return p.replace(/[\\*?[\]{}()!+@]/g, "\\$&");
1781
+ }
1782
+ function ancestors(dir) {
1783
+ const out = [];
1784
+ let cur = dirname(dir);
1785
+ for (; ; ) {
1786
+ out.push(cur);
1787
+ const parent = dirname(cur);
1788
+ if (parent === cur) return out;
1789
+ cur = parent;
1790
+ }
1791
+ }
1792
+ function hostContextExcludes(cwd) {
1793
+ const abs = resolve(cwd);
1794
+ let real = abs;
1795
+ try {
1796
+ real = realpathSync(abs);
1797
+ } catch {
1798
+ }
1799
+ const dirs = /* @__PURE__ */ new Set([...ancestors(abs), ...ancestors(real)]);
1800
+ const out = [];
1801
+ for (const d of dirs) {
1802
+ const base = d === "/" ? "" : escapeGlob(d);
1803
+ out.push(
1804
+ `${base}/CLAUDE.md`,
1805
+ `${base}/CLAUDE.local.md`,
1806
+ `${base}/.claude/CLAUDE.md`,
1807
+ `${base}/.claude/rules/**`
1808
+ );
1809
+ }
1810
+ return out;
1811
+ }
1747
1812
  function createArmSessionControls(arm, definition) {
1748
1813
  const modelApply = definition.models?.apply ?? "config";
1749
1814
  return {
@@ -1998,6 +2063,9 @@ function createAgentCliRuntime(definition) {
1998
2063
  }
1999
2064
  const spawnBin = npxFast?.bin ?? resolvedBin;
2000
2065
  const spawnArgs = npxFast?.args ?? composed.binArgs;
2066
+ const batchRewrite = resolveWindowsBatchSpawn(spawnBin);
2067
+ const finalBin = batchRewrite?.bin ?? spawnBin;
2068
+ const finalArgs = batchRewrite?.args ?? spawnArgs;
2001
2069
  if (opts?.additionalReadPaths?.length) {
2002
2070
  env.AGENTPROTO_ADDITIONAL_READ_PATHS = JSON.stringify(opts.additionalReadPaths);
2003
2071
  }
@@ -2033,8 +2101,16 @@ function createAgentCliRuntime(definition) {
2033
2101
  const isolatedSettings = {
2034
2102
  attribution: { commit: "", pr: "", sessionUrl: false }
2035
2103
  };
2036
- if (permissionMode) {
2037
- isolatedSettings.permissions = { defaultMode: permissionMode };
2104
+ const isolatedPermissions = {};
2105
+ if (permissionMode) isolatedPermissions.defaultMode = permissionMode;
2106
+ if (opts?.fsZones?.writable.length) {
2107
+ isolatedPermissions.additionalDirectories = opts.fsZones.writable;
2108
+ }
2109
+ if (Object.keys(isolatedPermissions).length > 0) {
2110
+ isolatedSettings.permissions = isolatedPermissions;
2111
+ }
2112
+ if (opts?.isolateHostContext) {
2113
+ isolatedSettings.claudeMdExcludes = hostContextExcludes(cwd);
2038
2114
  }
2039
2115
  writeFileSync(
2040
2116
  join(claudeConfigDir, "settings.json"),
@@ -2045,14 +2121,15 @@ function createAgentCliRuntime(definition) {
2045
2121
  if (definition.protocol === "print") {
2046
2122
  const printModel = config?.options?.model;
2047
2123
  return createPrintSession({
2048
- bin: spawnBin,
2049
- baseArgs: spawnArgs,
2124
+ bin: finalBin,
2125
+ baseArgs: finalArgs,
2050
2126
  cwd,
2051
2127
  env,
2052
2128
  ...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {},
2053
2129
  ...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
2054
2130
  printConfig: definition.print,
2055
2131
  commandSandbox: opts?.commandSandbox,
2132
+ ...opts?.fsZones ? { fsZones: opts.fsZones } : {},
2056
2133
  ...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
2057
2134
  // Exact-file read grant — see the ACP arm's wrapAgentCliSpawn call.
2058
2135
  ...opts?.additionalReadPaths?.length ? { extraReadPaths: opts.additionalReadPaths } : {},
@@ -2063,11 +2140,12 @@ function createAgentCliRuntime(definition) {
2063
2140
  const stderrBuf = [];
2064
2141
  if (definition.protocol !== "proprietary") {
2065
2142
  const [execBin, execArgs] = await wrapAgentCliSpawn(
2066
- spawnBin,
2067
- spawnArgs,
2143
+ finalBin,
2144
+ finalArgs,
2068
2145
  {
2069
2146
  mode: opts?.commandSandbox,
2070
2147
  cwd,
2148
+ ...opts?.fsZones ? { zones: opts.fsZones } : {},
2071
2149
  ...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
2072
2150
  // Exact-file read grant (see additionalReadPaths above):
2073
2151
  // READ-only exceptions to the confinement boundary, never writes.
@@ -2079,15 +2157,20 @@ function createAgentCliRuntime(definition) {
2079
2157
  cwd,
2080
2158
  env,
2081
2159
  stdio: ["pipe", "pipe", "pipe"],
2082
- signal: opts?.signal
2160
+ signal: opts?.signal,
2161
+ // Win32: a `.cmd`/`.bat` bin that `resolveWindowsBatchSpawn`
2162
+ // couldn't rewrite to its node entry needs the shell — Node
2163
+ // refuses to spawn batch files directly (CVE-2024-27980, the
2164
+ // recap-10 `spawn EINVAL`). POSIX: `{}` — unchanged.
2165
+ ...windowsBatchShellOption(execBin)
2083
2166
  });
2084
2167
  child = spawned;
2085
2168
  let spawnFailure;
2086
- await new Promise((resolve) => {
2087
- spawned.once("spawn", () => resolve());
2169
+ await new Promise((resolve2) => {
2170
+ spawned.once("spawn", () => resolve2());
2088
2171
  spawned.once("error", (err) => {
2089
2172
  spawnFailure = err;
2090
- resolve();
2173
+ resolve2();
2091
2174
  });
2092
2175
  });
2093
2176
  if (spawnFailure) {
@@ -2296,6 +2379,6 @@ function derivedModelRefusalError(definition, requested, reason) {
2296
2379
  );
2297
2380
  }
2298
2381
 
2299
- export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createJcodeMapperState, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, isModelSwitchAcknowledgement, mapJcodeEvent, mapMastraEvent, parseModelSwitchCommand, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
2300
- //# sourceMappingURL=chunk-ES4VLTGZ.mjs.map
2301
- //# sourceMappingURL=chunk-ES4VLTGZ.mjs.map
2382
+ export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, agentCliSupportsHostContextIsolation, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createJcodeMapperState, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, hostContextExcludes, inferLegacyModeKind, isLegacyExtractedModeId, isModelSwitchAcknowledgement, mapJcodeEvent, mapMastraEvent, parseModelSwitchCommand, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
2383
+ //# sourceMappingURL=chunk-EZROBN7Q.mjs.map
2384
+ //# sourceMappingURL=chunk-EZROBN7Q.mjs.map