@agentproto/driver-agent-cli 2.8.0 → 2.10.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.
@@ -2,7 +2,7 @@ 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, realpathSync, mkdtempSync } from 'fs';
5
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync, realpathSync, mkdtempSync, lstatSync, unlinkSync, symlinkSync } from 'fs';
6
6
  import { createInterface } from 'readline';
7
7
  import { join, isAbsolute, resolve, delimiter, dirname, basename } from 'path';
8
8
  import { tmpdir, homedir } from 'os';
@@ -392,6 +392,15 @@ var agentCliFrontmatterSchema = z.object({
392
392
  routeSelection: z.enum(["free", "derived-from-model"]).optional(),
393
393
  authEnforce: z.enum(["always", "when-configured"]).optional(),
394
394
  sandbox: z.union([z.string(), z.record(z.string(), z.unknown())]),
395
+ stateHome: z.object({
396
+ env: z.string().regex(/^[A-Z][A-Z0-9_]*$/),
397
+ defaultDir: z.string().min(1).refine((d) => !d.startsWith("/") && !d.split("/").includes(".."), {
398
+ message: "defaultDir must be relative to $HOME and stay inside it"
399
+ }),
400
+ share: z.array(z.string().regex(/^[^/]+$/)).optional(),
401
+ seed: z.record(z.string().regex(/^[^/]+$/).refine((n) => n !== "." && n !== "..", { message: "seed names a file of the home" }), z.string()).optional()
402
+ }).strict().optional(),
403
+ credentialDataHome: z.object({ env: z.string().regex(/^[A-Z][A-Z0-9_]*$/) }).strict().optional(),
395
404
  runner: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
396
405
  protocol: z.enum(["acp", "mcp", "proprietary", "print"]),
397
406
  acp: z.string().optional(),
@@ -720,15 +729,15 @@ function isAlive(pid) {
720
729
  }
721
730
  }
722
731
  function listProcesses() {
723
- return new Promise((resolve2) => {
732
+ return new Promise((resolve3) => {
724
733
  execFile("ps", ["-axo", "pid=,ppid="], { maxBuffer: 32 * 1024 * 1024 }, (err, stdout) => {
725
- if (err) return resolve2([]);
734
+ if (err) return resolve3([]);
726
735
  const out = [];
727
736
  for (const line of stdout.split("\n")) {
728
737
  const m = line.match(/^\s*(\d+)\s+(\d+)\s*$/);
729
738
  if (m) out.push({ pid: Number(m[1]), ppid: Number(m[2]) });
730
739
  }
731
- resolve2(out);
740
+ resolve3(out);
732
741
  });
733
742
  });
734
743
  }
@@ -777,9 +786,17 @@ function defaultToolchainReadPaths() {
777
786
  // macOS Keychain DB — git/gh credential retrieval (read-only; see doc above)
778
787
  ];
779
788
  }
789
+ function effectiveSpawnSandboxMode(opts, configured) {
790
+ return opts.zones ? opts.mode ?? "workspace" : opts.mode ?? configured;
791
+ }
792
+ async function willConfineAgentCliSpawn(opts) {
793
+ const cfg = await loadAdapterSpawnSandboxConfig(opts.cwd);
794
+ const mode = effectiveSpawnSandboxMode(opts, cfg.mode);
795
+ return mode !== void 0 && mode !== "off";
796
+ }
780
797
  async function wrapAgentCliSpawn(bin, args, opts) {
781
798
  const cfg = await loadAdapterSpawnSandboxConfig(opts.cwd);
782
- const mode = opts.zones ? opts.mode ?? "workspace" : opts.mode ?? cfg.mode;
799
+ const mode = effectiveSpawnSandboxMode(opts, cfg.mode);
783
800
  if (mode === void 0) return [bin, args];
784
801
  if (mode === "off" && opts.zones) {
785
802
  throw new Error(
@@ -880,11 +897,11 @@ function createPrintSession(opts) {
880
897
  });
881
898
  activeChild = child;
882
899
  let spawnFailure;
883
- await new Promise((resolve2) => {
884
- child.once("spawn", () => resolve2());
900
+ await new Promise((resolve3) => {
901
+ child.once("spawn", () => resolve3());
885
902
  child.once("error", (err) => {
886
903
  spawnFailure = err;
887
- resolve2();
904
+ resolve3();
888
905
  });
889
906
  });
890
907
  if (spawnFailure) {
@@ -1503,16 +1520,16 @@ var EventQueue = class {
1503
1520
  `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.`
1504
1521
  );
1505
1522
  }
1506
- const resolve2 = this.resolveNext;
1523
+ const resolve3 = this.resolveNext;
1507
1524
  this.resolveNext = null;
1508
- resolve2?.();
1525
+ resolve3?.();
1509
1526
  }
1510
1527
  /** Signal that no further events will be pushed. */
1511
1528
  end() {
1512
1529
  this.ended = true;
1513
- const resolve2 = this.resolveNext;
1530
+ const resolve3 = this.resolveNext;
1514
1531
  this.resolveNext = null;
1515
- resolve2?.();
1532
+ resolve3?.();
1516
1533
  }
1517
1534
  async *[Symbol.asyncIterator]() {
1518
1535
  for (; ; ) {
@@ -1522,8 +1539,8 @@ var EventQueue = class {
1522
1539
  continue;
1523
1540
  }
1524
1541
  if (this.ended) return;
1525
- await new Promise((resolve2) => {
1526
- this.resolveNext = resolve2;
1542
+ await new Promise((resolve3) => {
1543
+ this.resolveNext = resolve3;
1527
1544
  });
1528
1545
  }
1529
1546
  }
@@ -1542,9 +1559,9 @@ function mapMastraFinishReason(raw) {
1542
1559
  }
1543
1560
  }
1544
1561
  function waitForExit(child) {
1545
- return new Promise((resolve2) => {
1546
- child.once("exit", (code) => resolve2(code));
1547
- child.once("error", () => resolve2(null));
1562
+ return new Promise((resolve3) => {
1563
+ child.once("exit", (code) => resolve3(code));
1564
+ child.once("error", () => resolve3(null));
1548
1565
  });
1549
1566
  }
1550
1567
  async function createProprietaryProtocolArm(options) {
@@ -1792,6 +1809,49 @@ function interpolateEnv(env, value) {
1792
1809
  }
1793
1810
  return out;
1794
1811
  }
1812
+ function realStateHome(stateHome, env) {
1813
+ const fromEnv = env[stateHome.env];
1814
+ if (fromEnv && isAbsolute(fromEnv)) return fromEnv;
1815
+ return resolve(homedir(), stateHome.defaultDir);
1816
+ }
1817
+ function prepareIsolatedStateHome(stateHome, opts) {
1818
+ const real = realStateHome(stateHome, opts.env);
1819
+ let dir;
1820
+ if (opts.configDir) {
1821
+ dir = opts.configDir;
1822
+ mkdirSync(dir, { recursive: true });
1823
+ } else {
1824
+ dir = mkdtempSync(join(tmpdir(), `agentproto-${stateHome.env.toLowerCase()}-`));
1825
+ }
1826
+ const writePaths = [dir];
1827
+ for (const name of stateHome.share ?? []) {
1828
+ const target = join(real, name);
1829
+ const link = join(dir, name);
1830
+ try {
1831
+ lstatSync(link);
1832
+ unlinkSync(link);
1833
+ } catch {
1834
+ }
1835
+ if (!existsSync(target)) continue;
1836
+ symlinkSync(target, link);
1837
+ writePaths.push(realpathSync(target));
1838
+ }
1839
+ for (const [name, content] of Object.entries(stateHome.seed ?? {})) {
1840
+ const file = join(dir, name);
1841
+ try {
1842
+ unlinkSync(file);
1843
+ } catch {
1844
+ }
1845
+ writeFileSync(file, content);
1846
+ }
1847
+ return { dir, writePaths };
1848
+ }
1849
+ var CREDENTIAL_DATA_SUBDIR = "auth-data";
1850
+ function isolatedCredentialDataHome(configDir) {
1851
+ const dir = configDir ? join(configDir, CREDENTIAL_DATA_SUBDIR) : mkdtempSync(join(tmpdir(), "agentproto-data-"));
1852
+ mkdirSync(dir, { recursive: true });
1853
+ return dir;
1854
+ }
1795
1855
  function agentCliSupportsHostContextIsolation(adapterId) {
1796
1856
  return adapterId === "claude-code";
1797
1857
  }
@@ -1981,8 +2041,8 @@ async function* promptTurn(arm, turnId, message, stderrTurnError) {
1981
2041
  return;
1982
2042
  }
1983
2043
  const nextEvent = iterator.next();
1984
- const stderrArrived = new Promise((resolve2) => {
1985
- wake = resolve2;
2044
+ const stderrArrived = new Promise((resolve3) => {
2045
+ wake = resolve3;
1986
2046
  });
1987
2047
  const winner = await Promise.race([
1988
2048
  nextEvent.then((result) => ({ source: "event", result })),
@@ -2111,6 +2171,26 @@ function ensureExecDirOnPath(env, execPath = process.execPath) {
2111
2171
  if (parts.includes(execDir)) return;
2112
2172
  env.PATH = [...parts, execDir].join(delimiter);
2113
2173
  }
2174
+ function isPlainObject(v) {
2175
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2176
+ }
2177
+ function deepMergeJson(base, over) {
2178
+ const out = { ...base };
2179
+ for (const [k, v] of Object.entries(over)) {
2180
+ const prev = out[k];
2181
+ out[k] = isPlainObject(prev) && isPlainObject(v) ? deepMergeJson(prev, v) : v;
2182
+ }
2183
+ return out;
2184
+ }
2185
+ function mergeJsonEnvValue(base, over) {
2186
+ try {
2187
+ const a = JSON.parse(base);
2188
+ const b = JSON.parse(over);
2189
+ if (isPlainObject(a) && isPlainObject(b)) return JSON.stringify(deepMergeJson(a, b));
2190
+ } catch {
2191
+ }
2192
+ return over;
2193
+ }
2114
2194
  function createAgentCliRuntime(definition) {
2115
2195
  return {
2116
2196
  definition,
@@ -2128,6 +2208,7 @@ function createAgentCliRuntime(definition) {
2128
2208
  };
2129
2209
  for (const k of composed.envUnset) delete env[k];
2130
2210
  const authSpec = opts?.auth;
2211
+ let credentialDataDir;
2131
2212
  const hasGatewayAuthToken = "ANTHROPIC_AUTH_TOKEN" in composed.env;
2132
2213
  const hasGatewayBaseUrl = "ANTHROPIC_BASE_URL" in composed.env;
2133
2214
  const resolverCoupledGateway = authSpec?.baseUrl !== void 0;
@@ -2147,6 +2228,15 @@ function createAgentCliRuntime(definition) {
2147
2228
  throw new RuntimeConfigError("missing_auth_credential", "opts.auth.credential", message);
2148
2229
  }
2149
2230
  env[authSpec.setEnv] = authSpec.credential;
2231
+ if (authSpec.extraEnv) {
2232
+ for (const [key, value] of Object.entries(authSpec.extraEnv)) {
2233
+ env[key] = key in composed.env ? mergeJsonEnvValue(composed.env[key], value) : value;
2234
+ }
2235
+ }
2236
+ if (definition.credentialDataHome && authSpec.isolateDataHome !== false) {
2237
+ credentialDataDir = isolatedCredentialDataHome(opts?.configDir);
2238
+ env[definition.credentialDataHome.env] = credentialDataDir;
2239
+ }
2150
2240
  }
2151
2241
  }
2152
2242
  Object.assign(env, opts?.env ?? {});
@@ -2212,6 +2302,16 @@ function createAgentCliRuntime(definition) {
2212
2302
  );
2213
2303
  env.CLAUDE_CONFIG_DIR = claudeConfigDir;
2214
2304
  }
2305
+ const extraWritePaths = claudeConfigDir ? [claudeConfigDir] : [];
2306
+ if (credentialDataDir) extraWritePaths.push(credentialDataDir);
2307
+ if (definition.stateHome && definition.protocol !== "proprietary" && await willConfineAgentCliSpawn({ mode: opts?.commandSandbox, cwd, zones: opts?.fsZones })) {
2308
+ const isolated = prepareIsolatedStateHome(definition.stateHome, {
2309
+ ...opts?.configDir ? { configDir: opts.configDir } : {},
2310
+ env
2311
+ });
2312
+ env[definition.stateHome.env] = isolated.dir;
2313
+ extraWritePaths.push(...isolated.writePaths);
2314
+ }
2215
2315
  if (definition.protocol === "print") {
2216
2316
  const printModel = config?.options?.model;
2217
2317
  return createPrintSession({
@@ -2224,7 +2324,7 @@ function createAgentCliRuntime(definition) {
2224
2324
  printConfig: definition.print,
2225
2325
  commandSandbox: opts?.commandSandbox,
2226
2326
  ...opts?.fsZones ? { fsZones: opts.fsZones } : {},
2227
- ...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
2327
+ ...extraWritePaths.length ? { extraWritePaths } : {},
2228
2328
  // Exact-file read grant — see the ACP arm's wrapAgentCliSpawn call.
2229
2329
  ...opts?.additionalReadPaths?.length ? { extraReadPaths: opts.additionalReadPaths } : {},
2230
2330
  ...definition.routeSelection === "derived-from-model" && printModel ? { expectedModel: String(printModel) } : {}
@@ -2241,7 +2341,7 @@ function createAgentCliRuntime(definition) {
2241
2341
  mode: opts?.commandSandbox,
2242
2342
  cwd,
2243
2343
  ...opts?.fsZones ? { zones: opts.fsZones } : {},
2244
- ...claudeConfigDir ? { extraWritePaths: [claudeConfigDir] } : {},
2344
+ ...extraWritePaths.length ? { extraWritePaths } : {},
2245
2345
  // Exact-file read grant (see additionalReadPaths above):
2246
2346
  // READ-only exceptions to the confinement boundary, never writes.
2247
2347
  ...opts?.additionalReadPaths?.length ? { extraReadPaths: opts.additionalReadPaths } : {},
@@ -2261,11 +2361,11 @@ function createAgentCliRuntime(definition) {
2261
2361
  });
2262
2362
  child = spawned;
2263
2363
  let spawnFailure;
2264
- await new Promise((resolve2) => {
2265
- spawned.once("spawn", () => resolve2());
2364
+ await new Promise((resolve3) => {
2365
+ spawned.once("spawn", () => resolve3());
2266
2366
  spawned.once("error", (err) => {
2267
2367
  spawnFailure = err;
2268
- resolve2();
2368
+ resolve3();
2269
2369
  });
2270
2370
  });
2271
2371
  if (spawnFailure) {
@@ -2486,6 +2586,6 @@ function derivedModelRefusalError(definition, requested, reason) {
2486
2586
  );
2487
2587
  }
2488
2588
 
2489
- 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 };
2490
- //# sourceMappingURL=chunk-E45SX7GU.mjs.map
2491
- //# sourceMappingURL=chunk-E45SX7GU.mjs.map
2589
+ export { CREDENTIAL_DATA_SUBDIR, 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 };
2590
+ //# sourceMappingURL=chunk-K5PKRW2Q.mjs.map
2591
+ //# sourceMappingURL=chunk-K5PKRW2Q.mjs.map