@standardagents/code 0.13.7 → 0.13.8

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/index.js CHANGED
@@ -13,7 +13,7 @@ import * as transcript_delivery_star from '@standardagents/code-network/transcri
13
13
  import * as approvals_star from '@standardagents/code-network/approvals';
14
14
  import net from 'net';
15
15
  import { setImmediate } from 'timers';
16
- import fs11 from 'fs';
16
+ import fs12 from 'fs';
17
17
  import { permissionKey, Bridge as Bridge$1 } from '@standardagents/code-network/bridge';
18
18
  import readline from 'readline';
19
19
  import * as types_star from '@standardagents/code-network/types';
@@ -103,10 +103,10 @@ var AccountUserStream = class {
103
103
  options.uniqueConnectionId
104
104
  );
105
105
  }
106
- start() {
106
+ async start() {
107
107
  if (this.started) return;
108
108
  this.started = true;
109
- this.hub.start();
109
+ await this.hub.start();
110
110
  }
111
111
  onEvent(listener) {
112
112
  this.eventListeners.add(listener);
@@ -119,7 +119,7 @@ var AccountUserStream = class {
119
119
  /** Wait for a live socket. The timeout is local and performs no network work. */
120
120
  waitUntilConnected(timeoutMs = 15e3) {
121
121
  if (this.connected) return Promise.resolve();
122
- this.start();
122
+ void this.start();
123
123
  return new Promise((resolve, reject) => {
124
124
  let timer;
125
125
  const remove = this.onConnection((state) => {
@@ -217,6 +217,7 @@ function riskCeiling(state) {
217
217
  function decide(state, tool, risk, hasPermissionRequest) {
218
218
  const effectiveRisk = typeof risk === "number" ? Math.min(5, Math.max(1, risk)) : hasPermissionRequest ? 3 : 1;
219
219
  if (state.alwaysAllow.has(tool)) return "allow";
220
+ if (hasPermissionRequest) return "ask";
220
221
  return effectiveRisk <= riskCeiling(state) ? "allow" : "ask";
221
222
  }
222
223
  var CATASTROPHIC_PATTERNS = [
@@ -420,7 +421,7 @@ var ToolLedger = class {
420
421
  if (this.loaded) return;
421
422
  this.loaded = true;
422
423
  try {
423
- const raw = fs11.readFileSync(this.file, "utf8");
424
+ const raw = fs12.readFileSync(this.file, "utf8");
424
425
  const parsed = JSON.parse(raw);
425
426
  for (const [id, entry] of Object.entries(parsed)) {
426
427
  if (entry && typeof entry.ok === "boolean") this.entries.set(id, entry);
@@ -452,13 +453,13 @@ var ToolLedger = class {
452
453
  }
453
454
  persist() {
454
455
  try {
455
- fs11.mkdirSync(ledgerDir(), { recursive: true });
456
+ fs12.mkdirSync(ledgerDir(), { recursive: true });
456
457
  const out = {};
457
458
  for (const [id, entry] of this.entries) {
458
459
  const size = entry.result ? Buffer.byteLength(entry.result) : 0;
459
460
  out[id] = size > MAX_RESULT_BYTES ? { ...entry, result: void 0 } : entry;
460
461
  }
461
- fs11.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
462
+ fs12.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
462
463
  } catch {
463
464
  }
464
465
  }
@@ -1546,6 +1547,46 @@ var WordMill = class {
1546
1547
  // src/types.ts
1547
1548
  var types_exports = {};
1548
1549
  __reExport(types_exports, types_star);
1550
+
1551
+ // src/subprocess-env.ts
1552
+ var INHERITED_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
1553
+ "APPDATA",
1554
+ "COMSPEC",
1555
+ "HOME",
1556
+ "LANG",
1557
+ "LC_ALL",
1558
+ "LC_CTYPE",
1559
+ "LOCALAPPDATA",
1560
+ "LOGNAME",
1561
+ "PATH",
1562
+ "PATHEXT",
1563
+ "PROGRAMDATA",
1564
+ "SHELL",
1565
+ "SYSTEMROOT",
1566
+ "TEMP",
1567
+ "TERM",
1568
+ "TMP",
1569
+ "TMPDIR",
1570
+ "USER",
1571
+ "USERPROFILE",
1572
+ "WINDIR"
1573
+ ]);
1574
+ function inheritedSubprocessEnv(ambient = process.env) {
1575
+ const child = { ...ambient };
1576
+ delete child.NODE_TLS_REJECT_UNAUTHORIZED;
1577
+ return child;
1578
+ }
1579
+ function restrictedSubprocessEnv(explicit = {}, ambient = process.env) {
1580
+ const inherited = {};
1581
+ for (const [name, value] of Object.entries(ambient)) {
1582
+ if (value !== void 0 && INHERITED_ENV_ALLOWLIST.has(name.toUpperCase())) {
1583
+ inherited[name] = value;
1584
+ }
1585
+ }
1586
+ return { ...inherited, ...explicit };
1587
+ }
1588
+
1589
+ // src/clipboard.ts
1549
1590
  var FILE_MIMES = {
1550
1591
  ".png": "image/png",
1551
1592
  ".jpg": "image/jpeg",
@@ -1556,7 +1597,11 @@ var FILE_MIMES = {
1556
1597
  var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
1557
1598
  function run(cmd, args, maxBuffer = MAX_IMAGE_BYTES * 2) {
1558
1599
  return new Promise((resolve) => {
1559
- execFile(cmd, args, { encoding: "buffer", maxBuffer }, (err, stdout) => {
1600
+ execFile(cmd, args, {
1601
+ encoding: "buffer",
1602
+ maxBuffer,
1603
+ env: inheritedSubprocessEnv()
1604
+ }, (err, stdout) => {
1560
1605
  resolve({ ok: !err, stdout: stdout ?? Buffer.alloc(0) });
1561
1606
  });
1562
1607
  });
@@ -1565,9 +1610,9 @@ function fromFile(filePath) {
1565
1610
  const mime = FILE_MIMES[path9.extname(filePath).toLowerCase()];
1566
1611
  if (!mime) return null;
1567
1612
  try {
1568
- const stat = fs11.statSync(filePath);
1613
+ const stat = fs12.statSync(filePath);
1569
1614
  if (!stat.isFile() || stat.size === 0 || stat.size > MAX_IMAGE_BYTES) return null;
1570
- return { data: fs11.readFileSync(filePath).toString("base64"), mime };
1615
+ return { data: fs12.readFileSync(filePath).toString("base64"), mime };
1571
1616
  } catch {
1572
1617
  return null;
1573
1618
  }
@@ -1585,7 +1630,7 @@ async function readDarwin() {
1585
1630
  if (png.ok) {
1586
1631
  const img = fromFile(tmp);
1587
1632
  try {
1588
- fs11.unlinkSync(tmp);
1633
+ fs12.unlinkSync(tmp);
1589
1634
  } catch {
1590
1635
  }
1591
1636
  if (img) return img;
@@ -1619,7 +1664,7 @@ async function readWindows() {
1619
1664
  await run("powershell", ["-NoProfile", "-STA", "-Command", ps]);
1620
1665
  const img = fromFile(tmp);
1621
1666
  try {
1622
- fs11.unlinkSync(tmp);
1667
+ fs12.unlinkSync(tmp);
1623
1668
  } catch {
1624
1669
  }
1625
1670
  return img;
@@ -3816,6 +3861,18 @@ __reExport(shared_messaging_exports, shared_messaging_star);
3816
3861
  var history_exports = {};
3817
3862
  __reExport(history_exports, history_star);
3818
3863
  var LOG_DIR = path9.join(os6.homedir(), ".standardagents", "process-logs");
3864
+ function openPrivateProcessLog(logPath) {
3865
+ const directory = path9.dirname(logPath);
3866
+ fs12.mkdirSync(directory, { recursive: true, mode: 448 });
3867
+ fs12.chmodSync(directory, 448);
3868
+ const descriptor = fs12.openSync(
3869
+ logPath,
3870
+ fs12.constants.O_WRONLY | fs12.constants.O_CREAT | fs12.constants.O_APPEND,
3871
+ 384
3872
+ );
3873
+ fs12.fchmodSync(descriptor, 384);
3874
+ return descriptor;
3875
+ }
3819
3876
  function isAlive(pid) {
3820
3877
  try {
3821
3878
  process.kill(pid, 0);
@@ -3834,7 +3891,7 @@ function configFile() {
3834
3891
  }
3835
3892
  function loadMcpConfig() {
3836
3893
  try {
3837
- const raw = fs11.readFileSync(configFile(), "utf8");
3894
+ const raw = fs12.readFileSync(configFile(), "utf8");
3838
3895
  const parsed = JSON.parse(raw);
3839
3896
  if (!parsed.servers || typeof parsed.servers !== "object") parsed.servers = {};
3840
3897
  return parsed;
@@ -3865,8 +3922,8 @@ function setMcpServerEnabled(name, enabled) {
3865
3922
  }
3866
3923
  function write(cfg) {
3867
3924
  const file2 = configFile();
3868
- fs11.mkdirSync(path9.dirname(file2), { recursive: true });
3869
- fs11.writeFileSync(file2, JSON.stringify(cfg, null, 2), { mode: 384 });
3925
+ fs12.mkdirSync(path9.dirname(file2), { recursive: true });
3926
+ fs12.writeFileSync(file2, JSON.stringify(cfg, null, 2), { mode: 384 });
3870
3927
  }
3871
3928
  function parseServerSpec(spec) {
3872
3929
  const trimmed = spec.trim();
@@ -3937,7 +3994,11 @@ function openUrl(url) {
3937
3994
  const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
3938
3995
  const args = platform === "win32" ? ["/c", "start", "", url] : [url];
3939
3996
  try {
3940
- const child = spawn(cmd, args, { stdio: "ignore", detached: true });
3997
+ const child = spawn(cmd, args, {
3998
+ stdio: "ignore",
3999
+ detached: true,
4000
+ env: inheritedSubprocessEnv()
4001
+ });
3941
4002
  child.unref();
3942
4003
  } catch {
3943
4004
  }
@@ -3949,11 +4010,11 @@ __reExport(recorder_exports, recorder_star);
3949
4010
  __reExport(recorder_exports, recorder_node_star);
3950
4011
  function readVersion() {
3951
4012
  try {
3952
- const pkg = JSON.parse(fs11.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
4013
+ const pkg = JSON.parse(fs12.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
3953
4014
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
3954
4015
  } catch {
3955
4016
  }
3956
- return "0.13.7" ;
4017
+ return "0.13.8" ;
3957
4018
  }
3958
4019
  function isLocalHost(host) {
3959
4020
  return host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local") || host.endsWith(".localhost") || /^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
@@ -3979,7 +4040,7 @@ var dir = () => path9.join(os6.homedir(), ".standardagents");
3979
4040
  var file = () => path9.join(dir(), "machine.json");
3980
4041
  function loadMachineIdentity() {
3981
4042
  try {
3982
- const parsed = JSON.parse(fs11.readFileSync(file(), "utf8"));
4043
+ const parsed = JSON.parse(fs12.readFileSync(file(), "utf8"));
3983
4044
  if (typeof parsed.machine_id === "string" && parsed.machine_id.length > 0) {
3984
4045
  return { machine_id: parsed.machine_id, created_at: parsed.created_at ?? Date.now() };
3985
4046
  }
@@ -3993,8 +4054,8 @@ function loadMachineIdentity() {
3993
4054
  return identity;
3994
4055
  }
3995
4056
  function saveMachineIdentity(identity) {
3996
- fs11.mkdirSync(dir(), { recursive: true });
3997
- fs11.writeFileSync(file(), JSON.stringify(identity, null, 2), { mode: 384 });
4057
+ fs12.mkdirSync(dir(), { recursive: true });
4058
+ fs12.writeFileSync(file(), JSON.stringify(identity, null, 2), { mode: 384 });
3998
4059
  }
3999
4060
  function daemonClientId(identity) {
4000
4061
  return `daemon:${identity.machine_id}`;
@@ -4325,7 +4386,8 @@ function projectRepository(projectDir) {
4325
4386
  const url = execFileSync("git", ["-C", projectDir, "remote", "get-url", "origin"], {
4326
4387
  encoding: "utf8",
4327
4388
  timeout: 3e3,
4328
- stdio: ["ignore", "pipe", "ignore"]
4389
+ stdio: ["ignore", "pipe", "ignore"],
4390
+ env: inheritedSubprocessEnv()
4329
4391
  }).trim();
4330
4392
  return url || null;
4331
4393
  } catch {
@@ -4504,7 +4566,7 @@ function markers(dirPath) {
4504
4566
  for (const marker of PROJECT_MARKERS) {
4505
4567
  let hit = false;
4506
4568
  try {
4507
- hit = fs11.existsSync(path9.join(dirPath, marker));
4569
+ hit = fs12.existsSync(path9.join(dirPath, marker));
4508
4570
  } catch {
4509
4571
  hit = false;
4510
4572
  }
@@ -4526,11 +4588,11 @@ function browseDirectory(input3, opts = {}) {
4526
4588
  };
4527
4589
  let dirents;
4528
4590
  try {
4529
- const stat = fs11.statSync(abs);
4591
+ const stat = fs12.statSync(abs);
4530
4592
  if (!stat.isDirectory()) {
4531
4593
  return { ...base, entries: [], truncated: false, error: "Not a directory" };
4532
4594
  }
4533
- dirents = fs11.readdirSync(abs, { withFileTypes: true });
4595
+ dirents = fs12.readdirSync(abs, { withFileTypes: true });
4534
4596
  } catch (err) {
4535
4597
  const code = err?.code;
4536
4598
  const message = code === "EACCES" || code === "EPERM" ? "Permission denied" : code === "ENOENT" ? "Folder not found" : "Could not read this folder";
@@ -4545,7 +4607,7 @@ function browseDirectory(input3, opts = {}) {
4545
4607
  let isDir = d.isDirectory();
4546
4608
  if (d.isSymbolicLink()) {
4547
4609
  try {
4548
- isDir = fs11.statSync(path9.join(abs, name)).isDirectory();
4610
+ isDir = fs12.statSync(path9.join(abs, name)).isDirectory();
4549
4611
  } catch {
4550
4612
  isDir = false;
4551
4613
  }
@@ -4576,7 +4638,7 @@ function mkdirDirectory(parentInput, name, opts = {}) {
4576
4638
  return { ...listParent(), error: "Invalid folder name." };
4577
4639
  }
4578
4640
  try {
4579
- fs11.mkdirSync(target, { recursive: false });
4641
+ fs12.mkdirSync(target, { recursive: false });
4580
4642
  } catch (err) {
4581
4643
  const code = err?.code;
4582
4644
  const message = code === "EEXIST" ? "A folder with that name already exists." : code === "EACCES" || code === "EPERM" ? "Permission denied." : code === "ENOENT" ? "The parent folder no longer exists." : "Could not create the folder.";
@@ -4791,7 +4853,10 @@ function probe(cmd) {
4791
4853
  return new Promise((resolve) => {
4792
4854
  let child;
4793
4855
  try {
4794
- child = spawn(cmd, ["--version"], { stdio: "ignore" });
4856
+ child = spawn(cmd, ["--version"], {
4857
+ stdio: "ignore",
4858
+ env: inheritedSubprocessEnv()
4859
+ });
4795
4860
  } catch {
4796
4861
  resolve(false);
4797
4862
  return;
@@ -4827,7 +4892,7 @@ function download(url, dest, redirects = 5) {
4827
4892
  reject(new Error(`HTTP ${status} for ${url}`));
4828
4893
  return;
4829
4894
  }
4830
- const out = fs11.createWriteStream(dest);
4895
+ const out = fs12.createWriteStream(dest);
4831
4896
  res.pipe(out);
4832
4897
  out.on("finish", () => out.close(() => resolve()));
4833
4898
  out.on("error", reject);
@@ -4838,7 +4903,7 @@ function download(url, dest, redirects = 5) {
4838
4903
  async function sha256File(file2) {
4839
4904
  const hash = crypto.createHash("sha256");
4840
4905
  await new Promise((resolve, reject) => {
4841
- const stream = fs11.createReadStream(file2);
4906
+ const stream = fs12.createReadStream(file2);
4842
4907
  stream.on("data", (chunk) => hash.update(chunk));
4843
4908
  stream.on("end", () => resolve());
4844
4909
  stream.on("error", reject);
@@ -4849,7 +4914,11 @@ function runOk(cmd, args, cwd) {
4849
4914
  return new Promise((resolve) => {
4850
4915
  let child;
4851
4916
  try {
4852
- child = spawn(cmd, args, { cwd, stdio: "ignore" });
4917
+ child = spawn(cmd, args, {
4918
+ cwd,
4919
+ stdio: "ignore",
4920
+ env: inheritedSubprocessEnv()
4921
+ });
4853
4922
  } catch {
4854
4923
  resolve(false);
4855
4924
  return;
@@ -4876,7 +4945,7 @@ async function provision(target) {
4876
4945
  let extracted = null;
4877
4946
  for (const entry of entries) {
4878
4947
  const candidate = entry.isDirectory() ? path9.join(work, entry.name, binName) : entry.name === binName ? path9.join(work, entry.name) : null;
4879
- if (candidate && fs11.existsSync(candidate)) {
4948
+ if (candidate && fs12.existsSync(candidate)) {
4880
4949
  extracted = candidate;
4881
4950
  break;
4882
4951
  }
@@ -4901,7 +4970,7 @@ function resolveRg(log) {
4901
4970
  const override = process.env.STANDARDCODE_RG_PATH;
4902
4971
  if (override && await probe(override)) return override;
4903
4972
  if (await probe("rg")) return "rg";
4904
- if (fs11.existsSync(RG_BIN) && await probe(RG_BIN)) return RG_BIN;
4973
+ if (fs12.existsSync(RG_BIN) && await probe(RG_BIN)) return RG_BIN;
4905
4974
  const target = RG_TARGETS[`${process.platform}-${process.arch}`];
4906
4975
  if (!target) return null;
4907
4976
  try {
@@ -4960,16 +5029,36 @@ var HostTools = class {
4960
5029
  mcp;
4961
5030
  onMcpCatalogChange;
4962
5031
  api;
4963
- /** Resolve a user/model-supplied path against the project directory. */
5032
+ /** Resolve a user/model-supplied path against the project directory.
5033
+ * A leading `~` expands to the host home directory — without this, a
5034
+ * model-supplied `~/Desktop/x` silently lands at `<project>/~/Desktop/x`.
5035
+ * Outside-project containment checks run on the resolved result, so an
5036
+ * expanded home path still requires a fresh human decision. */
4964
5037
  resolve(p) {
4965
5038
  if (!p || p === ".") return this.projectDir;
5039
+ if (p === "~" || p.startsWith("~/")) {
5040
+ p = path9.join(os6.homedir(), p.slice(1));
5041
+ }
4966
5042
  return path9.resolve(this.projectDir, p);
4967
5043
  }
4968
- /** True when the resolved path escapes the project directory. */
5044
+ /** Resolve symlinks in an existing target or its nearest existing ancestor. */
5045
+ realPathForContainment(target) {
5046
+ const missing = [];
5047
+ let existing = path9.resolve(target);
5048
+ while (!fs12.existsSync(existing)) {
5049
+ const parent = path9.dirname(existing);
5050
+ if (parent === existing) return path9.resolve(target);
5051
+ missing.unshift(path9.basename(existing));
5052
+ existing = parent;
5053
+ }
5054
+ return path9.join(fs12.realpathSync.native(existing), ...missing);
5055
+ }
5056
+ /** True when the resolved path escapes the real project directory. */
4969
5057
  isOutsideProject(p) {
4970
- const abs = this.resolve(p);
4971
- const rel = path9.relative(this.projectDir, abs);
4972
- return rel.startsWith("..") || path9.isAbsolute(rel);
5058
+ const project = this.realPathForContainment(this.projectDir);
5059
+ const candidate = this.realPathForContainment(this.resolve(p));
5060
+ const rel = path9.relative(project, candidate);
5061
+ return rel === ".." || rel.startsWith(`..${path9.sep}`) || path9.isAbsolute(rel);
4973
5062
  }
4974
5063
  async execute(tool, args) {
4975
5064
  try {
@@ -5065,7 +5154,7 @@ var HostTools = class {
5065
5154
  const file2 = this.resolve(String(args.path || ""));
5066
5155
  const content = String(args.content ?? "");
5067
5156
  await fsp2.mkdir(path9.dirname(file2), { recursive: true });
5068
- const existed = fs11.existsSync(file2);
5157
+ const existed = fs12.existsSync(file2);
5069
5158
  await fsp2.writeFile(file2, content, "utf8");
5070
5159
  return {
5071
5160
  ok: true,
@@ -5107,7 +5196,7 @@ var HostTools = class {
5107
5196
  if (!bytes) return { ok: false, error: `Could not download ${source} from the thread filesystem.` };
5108
5197
  const dest = this.resolve(destArg);
5109
5198
  await fsp2.mkdir(path9.dirname(dest), { recursive: true });
5110
- const existed = fs11.existsSync(dest);
5199
+ const existed = fs12.existsSync(dest);
5111
5200
  await fsp2.writeFile(dest, bytes);
5112
5201
  return {
5113
5202
  ok: true,
@@ -5184,7 +5273,7 @@ var HostTools = class {
5184
5273
  return await new Promise((resolvePromise) => {
5185
5274
  const child = spawn(cmd, argv, {
5186
5275
  cwd: this.projectDir,
5187
- env: { ...process.env, SKILL_DIR: skillDir },
5276
+ env: restrictedSubprocessEnv({ SKILL_DIR: skillDir }),
5188
5277
  stdio: ["ignore", "pipe", "pipe"]
5189
5278
  });
5190
5279
  let out = "";
@@ -5237,30 +5326,34 @@ ${truncated}`
5237
5326
  const command = String(args.command || "");
5238
5327
  if (!command.trim()) return { ok: false, error: "command is required" };
5239
5328
  const cwd = args.cwd ? this.resolve(String(args.cwd)) : this.projectDir;
5240
- if (!fs11.existsSync(cwd)) {
5329
+ if (!fs12.existsSync(cwd)) {
5241
5330
  return { ok: false, error: `cwd does not exist: ${cwd}` };
5242
5331
  }
5243
5332
  const id = crypto.randomUUID().slice(0, 8);
5244
5333
  const logPath = path9.join(LOG_DIR, `${id}.log`);
5245
5334
  let out;
5246
5335
  try {
5247
- await fsp2.mkdir(LOG_DIR, { recursive: true });
5248
- out = fs11.openSync(logPath, "a");
5336
+ out = openPrivateProcessLog(logPath);
5249
5337
  } catch (err) {
5250
5338
  return { ok: false, error: `Could not open log file: ${err instanceof Error ? err.message : String(err)}` };
5251
5339
  }
5252
5340
  let child;
5253
5341
  try {
5254
- child = spawn("bash", ["-lc", command], { cwd, detached: true, stdio: ["ignore", out, out] });
5342
+ child = spawn("bash", ["-lc", command], {
5343
+ cwd,
5344
+ detached: true,
5345
+ stdio: ["ignore", out, out],
5346
+ env: inheritedSubprocessEnv()
5347
+ });
5255
5348
  } catch (err) {
5256
- fs11.closeSync(out);
5349
+ fs12.closeSync(out);
5257
5350
  return { ok: false, error: `Failed to start: ${err instanceof Error ? err.message : String(err)}` };
5258
5351
  }
5259
5352
  let spawnError = null;
5260
5353
  child.on("error", (err) => {
5261
5354
  spawnError = err;
5262
5355
  });
5263
- fs11.closeSync(out);
5356
+ fs12.closeSync(out);
5264
5357
  const pid = child.pid;
5265
5358
  let earlyExit;
5266
5359
  const onEarlyExit = (code) => {
@@ -5466,7 +5559,11 @@ ${tail2}` : " No output was captured.")
5466
5559
  const MAX_OUTPUT = 256 * 1024;
5467
5560
  let child;
5468
5561
  try {
5469
- child = spawn(cmd, args, { cwd, detached: true });
5562
+ child = spawn(cmd, args, {
5563
+ cwd,
5564
+ detached: true,
5565
+ env: inheritedSubprocessEnv()
5566
+ });
5470
5567
  } catch {
5471
5568
  resolve({ stdout: "", stderr: "", code: 127, timedOut: false });
5472
5569
  return;
@@ -5566,7 +5663,7 @@ var McpClient = class {
5566
5663
  async connect(defaultCwd) {
5567
5664
  const child = spawn(this.config.command, this.config.args, {
5568
5665
  cwd: this.config.cwd || defaultCwd,
5569
- env: { ...process.env, ...this.config.env || {} },
5666
+ env: restrictedSubprocessEnv(this.config.env),
5570
5667
  stdio: ["pipe", "pipe", "pipe"]
5571
5668
  });
5572
5669
  this.child = child;
@@ -6030,7 +6127,7 @@ var DaemonUserStream = class {
6030
6127
  if (hooks.onConnection) this.stream.onConnection(hooks.onConnection);
6031
6128
  }
6032
6129
  start() {
6033
- this.stream.start();
6130
+ return this.stream.start();
6034
6131
  }
6035
6132
  close() {
6036
6133
  this.stream.close();
@@ -6073,7 +6170,7 @@ function cachePath() {
6073
6170
  }
6074
6171
  function readCache() {
6075
6172
  try {
6076
- const raw = fs11.readFileSync(cachePath(), "utf-8");
6173
+ const raw = fs12.readFileSync(cachePath(), "utf-8");
6077
6174
  return JSON.parse(raw);
6078
6175
  } catch {
6079
6176
  return null;
@@ -6082,14 +6179,14 @@ function readCache() {
6082
6179
  function writeCache(latest) {
6083
6180
  try {
6084
6181
  const dir2 = cacheDir();
6085
- if (!fs11.existsSync(dir2)) fs11.mkdirSync(dir2, { recursive: true });
6086
- fs11.writeFileSync(cachePath(), JSON.stringify({ latest, timestamp: Date.now() }));
6182
+ if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
6183
+ fs12.writeFileSync(cachePath(), JSON.stringify({ latest, timestamp: Date.now() }));
6087
6184
  } catch {
6088
6185
  }
6089
6186
  }
6090
6187
  function readAutoUpdateState(dir2 = cacheDir()) {
6091
6188
  try {
6092
- const raw = fs11.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
6189
+ const raw = fs12.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
6093
6190
  const state = JSON.parse(raw);
6094
6191
  return typeof state?.version === "string" ? state : null;
6095
6192
  } catch {
@@ -6098,14 +6195,14 @@ function readAutoUpdateState(dir2 = cacheDir()) {
6098
6195
  }
6099
6196
  function writeAutoUpdateState(state, dir2 = cacheDir()) {
6100
6197
  try {
6101
- if (!fs11.existsSync(dir2)) fs11.mkdirSync(dir2, { recursive: true });
6102
- fs11.writeFileSync(path9.join(dir2, STATE_FILE), JSON.stringify(state));
6198
+ if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
6199
+ fs12.writeFileSync(path9.join(dir2, STATE_FILE), JSON.stringify(state));
6103
6200
  } catch {
6104
6201
  }
6105
6202
  }
6106
6203
  function clearAutoUpdateState(dir2 = cacheDir()) {
6107
6204
  try {
6108
- fs11.unlinkSync(path9.join(dir2, STATE_FILE));
6205
+ fs12.unlinkSync(path9.join(dir2, STATE_FILE));
6109
6206
  } catch {
6110
6207
  }
6111
6208
  }
@@ -6152,7 +6249,11 @@ function startBackgroundUpdate(latest, pm, dir2 = cacheDir()) {
6152
6249
  const { cmd, args } = updateCommand(pm);
6153
6250
  const script = `const cp=require('child_process');const fs=require('fs');const r=cp.spawnSync(${JSON.stringify(cmd)},${JSON.stringify(args)},{shell:process.platform==='win32',encoding:'utf8'});const out=((r.stdout||'')+(r.stderr||'')).slice(-2000);fs.writeFileSync(${JSON.stringify(stateFile)},JSON.stringify({version:${JSON.stringify(latest)},startedAt:${startedAt},exitCode:r.status==null?-1:r.status,finishedAt:Date.now(),output:out}));`;
6154
6251
  try {
6155
- const child = spawn(process.execPath, ["-e", script], { detached: true, stdio: "ignore" });
6252
+ const child = spawn(process.execPath, ["-e", script], {
6253
+ detached: true,
6254
+ stdio: "ignore",
6255
+ env: inheritedSubprocessEnv()
6256
+ });
6156
6257
  child.unref();
6157
6258
  return true;
6158
6259
  } catch {
@@ -6224,7 +6325,8 @@ function runUpdate(pm) {
6224
6325
  const { cmd, args } = updateCommand(pm);
6225
6326
  const child = spawn(cmd, args, {
6226
6327
  shell: process.platform === "win32",
6227
- stdio: ["ignore", "pipe", "pipe"]
6328
+ stdio: ["ignore", "pipe", "pipe"],
6329
+ env: inheritedSubprocessEnv()
6228
6330
  });
6229
6331
  let out = "";
6230
6332
  child.stdout?.on("data", (d) => out += d);
@@ -6240,22 +6342,30 @@ var UPDATE_CHECK_MS = 6 * 60 * 6e4;
6240
6342
  var MAX_WORKERS = 30;
6241
6343
  var BRIDGE_ATTACH_GRACE_MS = 15e3;
6242
6344
  var BRIDGE_IDLE_MS = 2e3;
6345
+ var LIVE_FRAME_APPROVAL_TIMEOUT_MS = 45e3;
6243
6346
  var LOG_MAX_BYTES = 1e6;
6244
6347
  var LOG_FILE = path9.join(os6.homedir(), ".standardagents", "daemon.log");
6245
- function daemonLog(line) {
6348
+ function appendPrivateLog(file2, line, maxBytes) {
6246
6349
  try {
6247
- fs11.mkdirSync(path9.dirname(LOG_FILE), { recursive: true });
6350
+ const directory = path9.dirname(file2);
6351
+ fs12.mkdirSync(directory, { recursive: true, mode: 448 });
6352
+ fs12.chmodSync(directory, 448);
6248
6353
  try {
6249
- if (fs11.statSync(LOG_FILE).size > LOG_MAX_BYTES) {
6250
- fs11.renameSync(LOG_FILE, `${LOG_FILE}.old`);
6354
+ fs12.chmodSync(file2, 384);
6355
+ if (fs12.statSync(file2).size > maxBytes) {
6356
+ fs12.renameSync(file2, `${file2}.old`);
6251
6357
  }
6252
6358
  } catch {
6253
6359
  }
6254
- fs11.appendFileSync(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
6255
- `);
6360
+ fs12.appendFileSync(file2, line, { mode: 384 });
6361
+ fs12.chmodSync(file2, 384);
6256
6362
  } catch {
6257
6363
  }
6258
6364
  }
6365
+ function daemonLog(line) {
6366
+ appendPrivateLog(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
6367
+ `, LOG_MAX_BYTES);
6368
+ }
6259
6369
  function pathFromTags(tags) {
6260
6370
  const tag = tags.find((t) => t.startsWith("path:"));
6261
6371
  if (!tag) return null;
@@ -6320,7 +6430,8 @@ var ThreadWorker = class {
6320
6430
  const permKey = permissionKey(req);
6321
6431
  const fresh = decide(this.perm, permKey, effectiveRisk, !!req.requestPermission);
6322
6432
  if (fresh === "allow") return { choice: "allow" };
6323
- if (!req.toolCallId) {
6433
+ const relayId = req.toolCallId ?? req.id;
6434
+ if (!relayId) {
6324
6435
  return { choice: "deny", reason: "No one is available to approve this right now." };
6325
6436
  }
6326
6437
  daemonLog(`[${threadId.slice(0, 8)}] relaying approval: ${summary} (risk ${effectiveRisk})`);
@@ -6331,7 +6442,7 @@ var ThreadWorker = class {
6331
6442
  api,
6332
6443
  threadId,
6333
6444
  {
6334
- tool_call_id: req.toolCallId,
6445
+ tool_call_id: relayId,
6335
6446
  tool: req.tool,
6336
6447
  summary,
6337
6448
  permission: req.requestPermission,
@@ -6339,7 +6450,15 @@ var ThreadWorker = class {
6339
6450
  machine: machineName,
6340
6451
  requested_at: Date.now()
6341
6452
  },
6342
- { subscribe: (wake) => approvalWakes.subscribe(threadId, wake) }
6453
+ {
6454
+ subscribe: (wake) => approvalWakes.subscribe(threadId, wake),
6455
+ // A live frame is answered over the socket and the server fails
6456
+ // the call on its own frame timeout — bound the human wait so a
6457
+ // late "allow" can never execute a side effect into a frame the
6458
+ // server already gave up on. Durable calls park server-side and
6459
+ // keep the long default.
6460
+ timeoutMs: req.toolCallId ? void 0 : LIVE_FRAME_APPROVAL_TIMEOUT_MS
6461
+ }
6343
6462
  );
6344
6463
  if (!response) {
6345
6464
  return { choice: "deny", reason: "The approval request timed out with no one to approve it." };
@@ -6514,7 +6633,7 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
6514
6633
  daemonLog(`detached ${oldest.threadId.slice(0, 8)} (worker cap)`);
6515
6634
  }
6516
6635
  try {
6517
- fs11.mkdirSync(projectDir, { recursive: true });
6636
+ fs12.mkdirSync(projectDir, { recursive: true });
6518
6637
  } catch (e) {
6519
6638
  daemonLog(`cannot prepare project dir ${projectDir}: ${e instanceof Error ? e.message : String(e)}`);
6520
6639
  return;
@@ -6817,7 +6936,7 @@ function resolveDaemonCommand(extraArgs = []) {
6817
6936
  let tsx = null;
6818
6937
  for (let i = 0; i < 6 && dir2 !== path9.dirname(dir2); i++) {
6819
6938
  const candidate = path9.join(dir2, "node_modules", "tsx", "dist", "cli.mjs");
6820
- if (fs11.existsSync(candidate)) {
6939
+ if (fs12.existsSync(candidate)) {
6821
6940
  tsx = candidate;
6822
6941
  break;
6823
6942
  }
@@ -6847,7 +6966,10 @@ function servicePath() {
6847
6966
  return [.../* @__PURE__ */ new Set([...current, ...parts])].join(":");
6848
6967
  }
6849
6968
  function run2(cmd, args) {
6850
- const res = spawnSync(cmd, args, { encoding: "utf8" });
6969
+ const res = spawnSync(cmd, args, {
6970
+ encoding: "utf8",
6971
+ env: inheritedSubprocessEnv()
6972
+ });
6851
6973
  const output4 = `${res.stdout ?? ""}${res.stderr ?? ""}`.trim();
6852
6974
  return { ok: res.status === 0, output: output4 };
6853
6975
  }
@@ -6865,8 +6987,8 @@ function installService(command, endpoint) {
6865
6987
  }
6866
6988
  function installLaunchd(command, endpoint) {
6867
6989
  const logDir = path9.join(os6.homedir(), ".standardagents");
6868
- fs11.mkdirSync(logDir, { recursive: true });
6869
- fs11.mkdirSync(path9.dirname(plistPath()), { recursive: true });
6990
+ fs12.mkdirSync(logDir, { recursive: true });
6991
+ fs12.mkdirSync(path9.dirname(plistPath()), { recursive: true });
6870
6992
  const envEntries = [
6871
6993
  ` <key>PATH</key><string>${xmlEscape(servicePath())}</string>`,
6872
6994
  ...endpoint ? [` <key>STANDARD_CODE_DAEMON_ENDPOINT</key><string>${xmlEscape(endpoint)}</string>`] : []
@@ -6892,7 +7014,7 @@ ${envEntries}
6892
7014
  </dict>
6893
7015
  </plist>
6894
7016
  `;
6895
- fs11.writeFileSync(plistPath(), plist);
7017
+ fs12.writeFileSync(plistPath(), plist);
6896
7018
  const uid = typeof process.getuid === "function" ? process.getuid() : 501;
6897
7019
  run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
6898
7020
  const boot = run2("launchctl", ["bootstrap", `gui/${uid}`, plistPath()]);
@@ -6909,7 +7031,7 @@ ${envEntries}
6909
7031
  return { ok: true, detail: `LaunchAgent installed (${plistPath()})` };
6910
7032
  }
6911
7033
  function installSystemd(command, endpoint) {
6912
- fs11.mkdirSync(path9.dirname(unitPath()), { recursive: true });
7034
+ fs12.mkdirSync(path9.dirname(unitPath()), { recursive: true });
6913
7035
  const unit = `[Unit]
6914
7036
  Description=Standard Code daemon (headless coding-agent execution client)
6915
7037
  After=network-online.target
@@ -6924,7 +7046,7 @@ ${endpoint ? `Environment=STANDARD_CODE_DAEMON_ENDPOINT=${endpoint}
6924
7046
  [Install]
6925
7047
  WantedBy=default.target
6926
7048
  `;
6927
- fs11.writeFileSync(unitPath(), unit);
7049
+ fs12.writeFileSync(unitPath(), unit);
6928
7050
  const reload = run2("systemctl", ["--user", "daemon-reload"]);
6929
7051
  if (!reload.ok) {
6930
7052
  return {
@@ -6948,7 +7070,7 @@ function uninstallService() {
6948
7070
  const uid = typeof process.getuid === "function" ? process.getuid() : 501;
6949
7071
  run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
6950
7072
  try {
6951
- fs11.unlinkSync(plistPath());
7073
+ fs12.unlinkSync(plistPath());
6952
7074
  } catch {
6953
7075
  }
6954
7076
  return { ok: true, detail: "LaunchAgent removed" };
@@ -6956,7 +7078,7 @@ function uninstallService() {
6956
7078
  if (process.platform === "linux") {
6957
7079
  run2("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
6958
7080
  try {
6959
- fs11.unlinkSync(unitPath());
7081
+ fs12.unlinkSync(unitPath());
6960
7082
  } catch {
6961
7083
  }
6962
7084
  run2("systemctl", ["--user", "daemon-reload"]);
@@ -6966,7 +7088,7 @@ function uninstallService() {
6966
7088
  }
6967
7089
  function serviceStatus() {
6968
7090
  if (process.platform === "darwin") {
6969
- const installed = fs11.existsSync(plistPath());
7091
+ const installed = fs12.existsSync(plistPath());
6970
7092
  const list = run2("launchctl", ["list", SERVICE_LABEL]);
6971
7093
  const pidMatch = list.output.match(/"PID"\s*=\s*(\d+)/);
6972
7094
  return {
@@ -6976,7 +7098,7 @@ function serviceStatus() {
6976
7098
  };
6977
7099
  }
6978
7100
  if (process.platform === "linux") {
6979
- const installed = fs11.existsSync(unitPath());
7101
+ const installed = fs12.existsSync(unitPath());
6980
7102
  const active = run2("systemctl", ["--user", "is-active", SYSTEMD_UNIT]);
6981
7103
  return {
6982
7104
  installed,
@@ -7199,7 +7321,7 @@ async function projectCommand(action, target) {
7199
7321
  process.exit(1);
7200
7322
  }
7201
7323
  const dir2 = path9.resolve(target);
7202
- if (action === "add" && !fs11.existsSync(dir2)) {
7324
+ if (action === "add" && !fs12.existsSync(dir2)) {
7203
7325
  stdout.write(`${c3.red}\u2717${c3.reset} ${dir2} does not exist on this machine.
7204
7326
  `);
7205
7327
  process.exit(1);
@@ -7268,15 +7390,15 @@ var DIR = path9.join(os6.homedir(), ".standardagents");
7268
7390
  var FILE = path9.join(DIR, "prefs.json");
7269
7391
  function loadPrefs(file2 = FILE) {
7270
7392
  try {
7271
- return JSON.parse(fs11.readFileSync(file2, "utf8"));
7393
+ return JSON.parse(fs12.readFileSync(file2, "utf8"));
7272
7394
  } catch {
7273
7395
  return {};
7274
7396
  }
7275
7397
  }
7276
7398
  function savePrefs(update, file2 = FILE) {
7277
7399
  const merged = { ...loadPrefs(file2), ...update };
7278
- fs11.mkdirSync(path9.dirname(file2), { recursive: true });
7279
- fs11.writeFileSync(file2, JSON.stringify(merged, null, 2));
7400
+ fs12.mkdirSync(path9.dirname(file2), { recursive: true });
7401
+ fs12.writeFileSync(file2, JSON.stringify(merged, null, 2));
7280
7402
  }
7281
7403
  function shouldOfferDaemonInstall(facts) {
7282
7404
  if (facts.optedOutEnv) return false;