@standardagents/code 0.13.6 → 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
@@ -5,6 +5,7 @@ import readline3 from 'readline/promises';
5
5
  import { stdout, stdin } from 'process';
6
6
  import * as api_star from '@standardagents/code-network/api';
7
7
  import * as stream_star from '@standardagents/code-network/stream';
8
+ import * as snapshot_epoch_star from '@standardagents/code-network/snapshot-epoch';
8
9
  import * as hub_star from '@standardagents/code-network/hub';
9
10
  import * as subagent_streams_star from '@standardagents/code-network/subagent-streams';
10
11
  import * as session_state_star from '@standardagents/code-network/session-state';
@@ -12,7 +13,7 @@ import * as transcript_delivery_star from '@standardagents/code-network/transcri
12
13
  import * as approvals_star from '@standardagents/code-network/approvals';
13
14
  import net from 'net';
14
15
  import { setImmediate } from 'timers';
15
- import fs11 from 'fs';
16
+ import fs12 from 'fs';
16
17
  import { permissionKey, Bridge as Bridge$1 } from '@standardagents/code-network/bridge';
17
18
  import readline from 'readline';
18
19
  import * as types_star from '@standardagents/code-network/types';
@@ -71,6 +72,10 @@ var themeGray = isLightTheme ? "\x1B[38;5;244m" : "\x1B[90m";
71
72
  var stream_exports = {};
72
73
  __reExport(stream_exports, stream_star);
73
74
 
75
+ // src/snapshot-epoch.ts
76
+ var snapshot_epoch_exports = {};
77
+ __reExport(snapshot_epoch_exports, snapshot_epoch_star);
78
+
74
79
  // src/hub.ts
75
80
  var hub_exports = {};
76
81
  __reExport(hub_exports, hub_star);
@@ -98,10 +103,10 @@ var AccountUserStream = class {
98
103
  options.uniqueConnectionId
99
104
  );
100
105
  }
101
- start() {
106
+ async start() {
102
107
  if (this.started) return;
103
108
  this.started = true;
104
- this.hub.start();
109
+ await this.hub.start();
105
110
  }
106
111
  onEvent(listener) {
107
112
  this.eventListeners.add(listener);
@@ -114,7 +119,7 @@ var AccountUserStream = class {
114
119
  /** Wait for a live socket. The timeout is local and performs no network work. */
115
120
  waitUntilConnected(timeoutMs = 15e3) {
116
121
  if (this.connected) return Promise.resolve();
117
- this.start();
122
+ void this.start();
118
123
  return new Promise((resolve, reject) => {
119
124
  let timer;
120
125
  const remove = this.onConnection((state) => {
@@ -212,6 +217,7 @@ function riskCeiling(state) {
212
217
  function decide(state, tool, risk, hasPermissionRequest) {
213
218
  const effectiveRisk = typeof risk === "number" ? Math.min(5, Math.max(1, risk)) : hasPermissionRequest ? 3 : 1;
214
219
  if (state.alwaysAllow.has(tool)) return "allow";
220
+ if (hasPermissionRequest) return "ask";
215
221
  return effectiveRisk <= riskCeiling(state) ? "allow" : "ask";
216
222
  }
217
223
  var CATASTROPHIC_PATTERNS = [
@@ -415,7 +421,7 @@ var ToolLedger = class {
415
421
  if (this.loaded) return;
416
422
  this.loaded = true;
417
423
  try {
418
- const raw = fs11.readFileSync(this.file, "utf8");
424
+ const raw = fs12.readFileSync(this.file, "utf8");
419
425
  const parsed = JSON.parse(raw);
420
426
  for (const [id, entry] of Object.entries(parsed)) {
421
427
  if (entry && typeof entry.ok === "boolean") this.entries.set(id, entry);
@@ -447,13 +453,13 @@ var ToolLedger = class {
447
453
  }
448
454
  persist() {
449
455
  try {
450
- fs11.mkdirSync(ledgerDir(), { recursive: true });
456
+ fs12.mkdirSync(ledgerDir(), { recursive: true });
451
457
  const out = {};
452
458
  for (const [id, entry] of this.entries) {
453
459
  const size = entry.result ? Buffer.byteLength(entry.result) : 0;
454
460
  out[id] = size > MAX_RESULT_BYTES ? { ...entry, result: void 0 } : entry;
455
461
  }
456
- fs11.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
462
+ fs12.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
457
463
  } catch {
458
464
  }
459
465
  }
@@ -1541,6 +1547,46 @@ var WordMill = class {
1541
1547
  // src/types.ts
1542
1548
  var types_exports = {};
1543
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
1544
1590
  var FILE_MIMES = {
1545
1591
  ".png": "image/png",
1546
1592
  ".jpg": "image/jpeg",
@@ -1551,7 +1597,11 @@ var FILE_MIMES = {
1551
1597
  var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
1552
1598
  function run(cmd, args, maxBuffer = MAX_IMAGE_BYTES * 2) {
1553
1599
  return new Promise((resolve) => {
1554
- execFile(cmd, args, { encoding: "buffer", maxBuffer }, (err, stdout) => {
1600
+ execFile(cmd, args, {
1601
+ encoding: "buffer",
1602
+ maxBuffer,
1603
+ env: inheritedSubprocessEnv()
1604
+ }, (err, stdout) => {
1555
1605
  resolve({ ok: !err, stdout: stdout ?? Buffer.alloc(0) });
1556
1606
  });
1557
1607
  });
@@ -1560,9 +1610,9 @@ function fromFile(filePath) {
1560
1610
  const mime = FILE_MIMES[path9.extname(filePath).toLowerCase()];
1561
1611
  if (!mime) return null;
1562
1612
  try {
1563
- const stat = fs11.statSync(filePath);
1613
+ const stat = fs12.statSync(filePath);
1564
1614
  if (!stat.isFile() || stat.size === 0 || stat.size > MAX_IMAGE_BYTES) return null;
1565
- return { data: fs11.readFileSync(filePath).toString("base64"), mime };
1615
+ return { data: fs12.readFileSync(filePath).toString("base64"), mime };
1566
1616
  } catch {
1567
1617
  return null;
1568
1618
  }
@@ -1580,7 +1630,7 @@ async function readDarwin() {
1580
1630
  if (png.ok) {
1581
1631
  const img = fromFile(tmp);
1582
1632
  try {
1583
- fs11.unlinkSync(tmp);
1633
+ fs12.unlinkSync(tmp);
1584
1634
  } catch {
1585
1635
  }
1586
1636
  if (img) return img;
@@ -1614,7 +1664,7 @@ async function readWindows() {
1614
1664
  await run("powershell", ["-NoProfile", "-STA", "-Command", ps]);
1615
1665
  const img = fromFile(tmp);
1616
1666
  try {
1617
- fs11.unlinkSync(tmp);
1667
+ fs12.unlinkSync(tmp);
1618
1668
  } catch {
1619
1669
  }
1620
1670
  return img;
@@ -3811,6 +3861,18 @@ __reExport(shared_messaging_exports, shared_messaging_star);
3811
3861
  var history_exports = {};
3812
3862
  __reExport(history_exports, history_star);
3813
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
+ }
3814
3876
  function isAlive(pid) {
3815
3877
  try {
3816
3878
  process.kill(pid, 0);
@@ -3829,7 +3891,7 @@ function configFile() {
3829
3891
  }
3830
3892
  function loadMcpConfig() {
3831
3893
  try {
3832
- const raw = fs11.readFileSync(configFile(), "utf8");
3894
+ const raw = fs12.readFileSync(configFile(), "utf8");
3833
3895
  const parsed = JSON.parse(raw);
3834
3896
  if (!parsed.servers || typeof parsed.servers !== "object") parsed.servers = {};
3835
3897
  return parsed;
@@ -3860,8 +3922,8 @@ function setMcpServerEnabled(name, enabled) {
3860
3922
  }
3861
3923
  function write(cfg) {
3862
3924
  const file2 = configFile();
3863
- fs11.mkdirSync(path9.dirname(file2), { recursive: true });
3864
- 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 });
3865
3927
  }
3866
3928
  function parseServerSpec(spec) {
3867
3929
  const trimmed = spec.trim();
@@ -3932,7 +3994,11 @@ function openUrl(url) {
3932
3994
  const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
3933
3995
  const args = platform === "win32" ? ["/c", "start", "", url] : [url];
3934
3996
  try {
3935
- 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
+ });
3936
4002
  child.unref();
3937
4003
  } catch {
3938
4004
  }
@@ -3944,11 +4010,11 @@ __reExport(recorder_exports, recorder_star);
3944
4010
  __reExport(recorder_exports, recorder_node_star);
3945
4011
  function readVersion() {
3946
4012
  try {
3947
- 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"));
3948
4014
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
3949
4015
  } catch {
3950
4016
  }
3951
- return "0.13.6" ;
4017
+ return "0.13.8" ;
3952
4018
  }
3953
4019
  function isLocalHost(host) {
3954
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);
@@ -3974,7 +4040,7 @@ var dir = () => path9.join(os6.homedir(), ".standardagents");
3974
4040
  var file = () => path9.join(dir(), "machine.json");
3975
4041
  function loadMachineIdentity() {
3976
4042
  try {
3977
- const parsed = JSON.parse(fs11.readFileSync(file(), "utf8"));
4043
+ const parsed = JSON.parse(fs12.readFileSync(file(), "utf8"));
3978
4044
  if (typeof parsed.machine_id === "string" && parsed.machine_id.length > 0) {
3979
4045
  return { machine_id: parsed.machine_id, created_at: parsed.created_at ?? Date.now() };
3980
4046
  }
@@ -3988,8 +4054,8 @@ function loadMachineIdentity() {
3988
4054
  return identity;
3989
4055
  }
3990
4056
  function saveMachineIdentity(identity) {
3991
- fs11.mkdirSync(dir(), { recursive: true });
3992
- 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 });
3993
4059
  }
3994
4060
  function daemonClientId(identity) {
3995
4061
  return `daemon:${identity.machine_id}`;
@@ -4320,7 +4386,8 @@ function projectRepository(projectDir) {
4320
4386
  const url = execFileSync("git", ["-C", projectDir, "remote", "get-url", "origin"], {
4321
4387
  encoding: "utf8",
4322
4388
  timeout: 3e3,
4323
- stdio: ["ignore", "pipe", "ignore"]
4389
+ stdio: ["ignore", "pipe", "ignore"],
4390
+ env: inheritedSubprocessEnv()
4324
4391
  }).trim();
4325
4392
  return url || null;
4326
4393
  } catch {
@@ -4499,7 +4566,7 @@ function markers(dirPath) {
4499
4566
  for (const marker of PROJECT_MARKERS) {
4500
4567
  let hit = false;
4501
4568
  try {
4502
- hit = fs11.existsSync(path9.join(dirPath, marker));
4569
+ hit = fs12.existsSync(path9.join(dirPath, marker));
4503
4570
  } catch {
4504
4571
  hit = false;
4505
4572
  }
@@ -4521,11 +4588,11 @@ function browseDirectory(input3, opts = {}) {
4521
4588
  };
4522
4589
  let dirents;
4523
4590
  try {
4524
- const stat = fs11.statSync(abs);
4591
+ const stat = fs12.statSync(abs);
4525
4592
  if (!stat.isDirectory()) {
4526
4593
  return { ...base, entries: [], truncated: false, error: "Not a directory" };
4527
4594
  }
4528
- dirents = fs11.readdirSync(abs, { withFileTypes: true });
4595
+ dirents = fs12.readdirSync(abs, { withFileTypes: true });
4529
4596
  } catch (err) {
4530
4597
  const code = err?.code;
4531
4598
  const message = code === "EACCES" || code === "EPERM" ? "Permission denied" : code === "ENOENT" ? "Folder not found" : "Could not read this folder";
@@ -4540,7 +4607,7 @@ function browseDirectory(input3, opts = {}) {
4540
4607
  let isDir = d.isDirectory();
4541
4608
  if (d.isSymbolicLink()) {
4542
4609
  try {
4543
- isDir = fs11.statSync(path9.join(abs, name)).isDirectory();
4610
+ isDir = fs12.statSync(path9.join(abs, name)).isDirectory();
4544
4611
  } catch {
4545
4612
  isDir = false;
4546
4613
  }
@@ -4571,7 +4638,7 @@ function mkdirDirectory(parentInput, name, opts = {}) {
4571
4638
  return { ...listParent(), error: "Invalid folder name." };
4572
4639
  }
4573
4640
  try {
4574
- fs11.mkdirSync(target, { recursive: false });
4641
+ fs12.mkdirSync(target, { recursive: false });
4575
4642
  } catch (err) {
4576
4643
  const code = err?.code;
4577
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.";
@@ -4786,7 +4853,10 @@ function probe(cmd) {
4786
4853
  return new Promise((resolve) => {
4787
4854
  let child;
4788
4855
  try {
4789
- child = spawn(cmd, ["--version"], { stdio: "ignore" });
4856
+ child = spawn(cmd, ["--version"], {
4857
+ stdio: "ignore",
4858
+ env: inheritedSubprocessEnv()
4859
+ });
4790
4860
  } catch {
4791
4861
  resolve(false);
4792
4862
  return;
@@ -4822,7 +4892,7 @@ function download(url, dest, redirects = 5) {
4822
4892
  reject(new Error(`HTTP ${status} for ${url}`));
4823
4893
  return;
4824
4894
  }
4825
- const out = fs11.createWriteStream(dest);
4895
+ const out = fs12.createWriteStream(dest);
4826
4896
  res.pipe(out);
4827
4897
  out.on("finish", () => out.close(() => resolve()));
4828
4898
  out.on("error", reject);
@@ -4833,7 +4903,7 @@ function download(url, dest, redirects = 5) {
4833
4903
  async function sha256File(file2) {
4834
4904
  const hash = crypto.createHash("sha256");
4835
4905
  await new Promise((resolve, reject) => {
4836
- const stream = fs11.createReadStream(file2);
4906
+ const stream = fs12.createReadStream(file2);
4837
4907
  stream.on("data", (chunk) => hash.update(chunk));
4838
4908
  stream.on("end", () => resolve());
4839
4909
  stream.on("error", reject);
@@ -4844,7 +4914,11 @@ function runOk(cmd, args, cwd) {
4844
4914
  return new Promise((resolve) => {
4845
4915
  let child;
4846
4916
  try {
4847
- child = spawn(cmd, args, { cwd, stdio: "ignore" });
4917
+ child = spawn(cmd, args, {
4918
+ cwd,
4919
+ stdio: "ignore",
4920
+ env: inheritedSubprocessEnv()
4921
+ });
4848
4922
  } catch {
4849
4923
  resolve(false);
4850
4924
  return;
@@ -4871,7 +4945,7 @@ async function provision(target) {
4871
4945
  let extracted = null;
4872
4946
  for (const entry of entries) {
4873
4947
  const candidate = entry.isDirectory() ? path9.join(work, entry.name, binName) : entry.name === binName ? path9.join(work, entry.name) : null;
4874
- if (candidate && fs11.existsSync(candidate)) {
4948
+ if (candidate && fs12.existsSync(candidate)) {
4875
4949
  extracted = candidate;
4876
4950
  break;
4877
4951
  }
@@ -4896,7 +4970,7 @@ function resolveRg(log) {
4896
4970
  const override = process.env.STANDARDCODE_RG_PATH;
4897
4971
  if (override && await probe(override)) return override;
4898
4972
  if (await probe("rg")) return "rg";
4899
- 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;
4900
4974
  const target = RG_TARGETS[`${process.platform}-${process.arch}`];
4901
4975
  if (!target) return null;
4902
4976
  try {
@@ -4955,16 +5029,36 @@ var HostTools = class {
4955
5029
  mcp;
4956
5030
  onMcpCatalogChange;
4957
5031
  api;
4958
- /** 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. */
4959
5037
  resolve(p) {
4960
5038
  if (!p || p === ".") return this.projectDir;
5039
+ if (p === "~" || p.startsWith("~/")) {
5040
+ p = path9.join(os6.homedir(), p.slice(1));
5041
+ }
4961
5042
  return path9.resolve(this.projectDir, p);
4962
5043
  }
4963
- /** 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. */
4964
5057
  isOutsideProject(p) {
4965
- const abs = this.resolve(p);
4966
- const rel = path9.relative(this.projectDir, abs);
4967
- 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);
4968
5062
  }
4969
5063
  async execute(tool, args) {
4970
5064
  try {
@@ -5060,7 +5154,7 @@ var HostTools = class {
5060
5154
  const file2 = this.resolve(String(args.path || ""));
5061
5155
  const content = String(args.content ?? "");
5062
5156
  await fsp2.mkdir(path9.dirname(file2), { recursive: true });
5063
- const existed = fs11.existsSync(file2);
5157
+ const existed = fs12.existsSync(file2);
5064
5158
  await fsp2.writeFile(file2, content, "utf8");
5065
5159
  return {
5066
5160
  ok: true,
@@ -5102,7 +5196,7 @@ var HostTools = class {
5102
5196
  if (!bytes) return { ok: false, error: `Could not download ${source} from the thread filesystem.` };
5103
5197
  const dest = this.resolve(destArg);
5104
5198
  await fsp2.mkdir(path9.dirname(dest), { recursive: true });
5105
- const existed = fs11.existsSync(dest);
5199
+ const existed = fs12.existsSync(dest);
5106
5200
  await fsp2.writeFile(dest, bytes);
5107
5201
  return {
5108
5202
  ok: true,
@@ -5179,7 +5273,7 @@ var HostTools = class {
5179
5273
  return await new Promise((resolvePromise) => {
5180
5274
  const child = spawn(cmd, argv, {
5181
5275
  cwd: this.projectDir,
5182
- env: { ...process.env, SKILL_DIR: skillDir },
5276
+ env: restrictedSubprocessEnv({ SKILL_DIR: skillDir }),
5183
5277
  stdio: ["ignore", "pipe", "pipe"]
5184
5278
  });
5185
5279
  let out = "";
@@ -5232,30 +5326,34 @@ ${truncated}`
5232
5326
  const command = String(args.command || "");
5233
5327
  if (!command.trim()) return { ok: false, error: "command is required" };
5234
5328
  const cwd = args.cwd ? this.resolve(String(args.cwd)) : this.projectDir;
5235
- if (!fs11.existsSync(cwd)) {
5329
+ if (!fs12.existsSync(cwd)) {
5236
5330
  return { ok: false, error: `cwd does not exist: ${cwd}` };
5237
5331
  }
5238
5332
  const id = crypto.randomUUID().slice(0, 8);
5239
5333
  const logPath = path9.join(LOG_DIR, `${id}.log`);
5240
5334
  let out;
5241
5335
  try {
5242
- await fsp2.mkdir(LOG_DIR, { recursive: true });
5243
- out = fs11.openSync(logPath, "a");
5336
+ out = openPrivateProcessLog(logPath);
5244
5337
  } catch (err) {
5245
5338
  return { ok: false, error: `Could not open log file: ${err instanceof Error ? err.message : String(err)}` };
5246
5339
  }
5247
5340
  let child;
5248
5341
  try {
5249
- 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
+ });
5250
5348
  } catch (err) {
5251
- fs11.closeSync(out);
5349
+ fs12.closeSync(out);
5252
5350
  return { ok: false, error: `Failed to start: ${err instanceof Error ? err.message : String(err)}` };
5253
5351
  }
5254
5352
  let spawnError = null;
5255
5353
  child.on("error", (err) => {
5256
5354
  spawnError = err;
5257
5355
  });
5258
- fs11.closeSync(out);
5356
+ fs12.closeSync(out);
5259
5357
  const pid = child.pid;
5260
5358
  let earlyExit;
5261
5359
  const onEarlyExit = (code) => {
@@ -5461,7 +5559,11 @@ ${tail2}` : " No output was captured.")
5461
5559
  const MAX_OUTPUT = 256 * 1024;
5462
5560
  let child;
5463
5561
  try {
5464
- child = spawn(cmd, args, { cwd, detached: true });
5562
+ child = spawn(cmd, args, {
5563
+ cwd,
5564
+ detached: true,
5565
+ env: inheritedSubprocessEnv()
5566
+ });
5465
5567
  } catch {
5466
5568
  resolve({ stdout: "", stderr: "", code: 127, timedOut: false });
5467
5569
  return;
@@ -5561,7 +5663,7 @@ var McpClient = class {
5561
5663
  async connect(defaultCwd) {
5562
5664
  const child = spawn(this.config.command, this.config.args, {
5563
5665
  cwd: this.config.cwd || defaultCwd,
5564
- env: { ...process.env, ...this.config.env || {} },
5666
+ env: restrictedSubprocessEnv(this.config.env),
5565
5667
  stdio: ["pipe", "pipe", "pipe"]
5566
5668
  });
5567
5669
  this.child = child;
@@ -6025,7 +6127,7 @@ var DaemonUserStream = class {
6025
6127
  if (hooks.onConnection) this.stream.onConnection(hooks.onConnection);
6026
6128
  }
6027
6129
  start() {
6028
- this.stream.start();
6130
+ return this.stream.start();
6029
6131
  }
6030
6132
  close() {
6031
6133
  this.stream.close();
@@ -6068,7 +6170,7 @@ function cachePath() {
6068
6170
  }
6069
6171
  function readCache() {
6070
6172
  try {
6071
- const raw = fs11.readFileSync(cachePath(), "utf-8");
6173
+ const raw = fs12.readFileSync(cachePath(), "utf-8");
6072
6174
  return JSON.parse(raw);
6073
6175
  } catch {
6074
6176
  return null;
@@ -6077,14 +6179,14 @@ function readCache() {
6077
6179
  function writeCache(latest) {
6078
6180
  try {
6079
6181
  const dir2 = cacheDir();
6080
- if (!fs11.existsSync(dir2)) fs11.mkdirSync(dir2, { recursive: true });
6081
- 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() }));
6082
6184
  } catch {
6083
6185
  }
6084
6186
  }
6085
6187
  function readAutoUpdateState(dir2 = cacheDir()) {
6086
6188
  try {
6087
- const raw = fs11.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
6189
+ const raw = fs12.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
6088
6190
  const state = JSON.parse(raw);
6089
6191
  return typeof state?.version === "string" ? state : null;
6090
6192
  } catch {
@@ -6093,14 +6195,14 @@ function readAutoUpdateState(dir2 = cacheDir()) {
6093
6195
  }
6094
6196
  function writeAutoUpdateState(state, dir2 = cacheDir()) {
6095
6197
  try {
6096
- if (!fs11.existsSync(dir2)) fs11.mkdirSync(dir2, { recursive: true });
6097
- 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));
6098
6200
  } catch {
6099
6201
  }
6100
6202
  }
6101
6203
  function clearAutoUpdateState(dir2 = cacheDir()) {
6102
6204
  try {
6103
- fs11.unlinkSync(path9.join(dir2, STATE_FILE));
6205
+ fs12.unlinkSync(path9.join(dir2, STATE_FILE));
6104
6206
  } catch {
6105
6207
  }
6106
6208
  }
@@ -6147,7 +6249,11 @@ function startBackgroundUpdate(latest, pm, dir2 = cacheDir()) {
6147
6249
  const { cmd, args } = updateCommand(pm);
6148
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}));`;
6149
6251
  try {
6150
- 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
+ });
6151
6257
  child.unref();
6152
6258
  return true;
6153
6259
  } catch {
@@ -6219,7 +6325,8 @@ function runUpdate(pm) {
6219
6325
  const { cmd, args } = updateCommand(pm);
6220
6326
  const child = spawn(cmd, args, {
6221
6327
  shell: process.platform === "win32",
6222
- stdio: ["ignore", "pipe", "pipe"]
6328
+ stdio: ["ignore", "pipe", "pipe"],
6329
+ env: inheritedSubprocessEnv()
6223
6330
  });
6224
6331
  let out = "";
6225
6332
  child.stdout?.on("data", (d) => out += d);
@@ -6235,22 +6342,30 @@ var UPDATE_CHECK_MS = 6 * 60 * 6e4;
6235
6342
  var MAX_WORKERS = 30;
6236
6343
  var BRIDGE_ATTACH_GRACE_MS = 15e3;
6237
6344
  var BRIDGE_IDLE_MS = 2e3;
6345
+ var LIVE_FRAME_APPROVAL_TIMEOUT_MS = 45e3;
6238
6346
  var LOG_MAX_BYTES = 1e6;
6239
6347
  var LOG_FILE = path9.join(os6.homedir(), ".standardagents", "daemon.log");
6240
- function daemonLog(line) {
6348
+ function appendPrivateLog(file2, line, maxBytes) {
6241
6349
  try {
6242
- 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);
6243
6353
  try {
6244
- if (fs11.statSync(LOG_FILE).size > LOG_MAX_BYTES) {
6245
- 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`);
6246
6357
  }
6247
6358
  } catch {
6248
6359
  }
6249
- fs11.appendFileSync(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
6250
- `);
6360
+ fs12.appendFileSync(file2, line, { mode: 384 });
6361
+ fs12.chmodSync(file2, 384);
6251
6362
  } catch {
6252
6363
  }
6253
6364
  }
6365
+ function daemonLog(line) {
6366
+ appendPrivateLog(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
6367
+ `, LOG_MAX_BYTES);
6368
+ }
6254
6369
  function pathFromTags(tags) {
6255
6370
  const tag = tags.find((t) => t.startsWith("path:"));
6256
6371
  if (!tag) return null;
@@ -6315,7 +6430,8 @@ var ThreadWorker = class {
6315
6430
  const permKey = permissionKey(req);
6316
6431
  const fresh = decide(this.perm, permKey, effectiveRisk, !!req.requestPermission);
6317
6432
  if (fresh === "allow") return { choice: "allow" };
6318
- if (!req.toolCallId) {
6433
+ const relayId = req.toolCallId ?? req.id;
6434
+ if (!relayId) {
6319
6435
  return { choice: "deny", reason: "No one is available to approve this right now." };
6320
6436
  }
6321
6437
  daemonLog(`[${threadId.slice(0, 8)}] relaying approval: ${summary} (risk ${effectiveRisk})`);
@@ -6326,7 +6442,7 @@ var ThreadWorker = class {
6326
6442
  api,
6327
6443
  threadId,
6328
6444
  {
6329
- tool_call_id: req.toolCallId,
6445
+ tool_call_id: relayId,
6330
6446
  tool: req.tool,
6331
6447
  summary,
6332
6448
  permission: req.requestPermission,
@@ -6334,7 +6450,15 @@ var ThreadWorker = class {
6334
6450
  machine: machineName,
6335
6451
  requested_at: Date.now()
6336
6452
  },
6337
- { 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
+ }
6338
6462
  );
6339
6463
  if (!response) {
6340
6464
  return { choice: "deny", reason: "The approval request timed out with no one to approve it." };
@@ -6509,7 +6633,7 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
6509
6633
  daemonLog(`detached ${oldest.threadId.slice(0, 8)} (worker cap)`);
6510
6634
  }
6511
6635
  try {
6512
- fs11.mkdirSync(projectDir, { recursive: true });
6636
+ fs12.mkdirSync(projectDir, { recursive: true });
6513
6637
  } catch (e) {
6514
6638
  daemonLog(`cannot prepare project dir ${projectDir}: ${e instanceof Error ? e.message : String(e)}`);
6515
6639
  return;
@@ -6812,7 +6936,7 @@ function resolveDaemonCommand(extraArgs = []) {
6812
6936
  let tsx = null;
6813
6937
  for (let i = 0; i < 6 && dir2 !== path9.dirname(dir2); i++) {
6814
6938
  const candidate = path9.join(dir2, "node_modules", "tsx", "dist", "cli.mjs");
6815
- if (fs11.existsSync(candidate)) {
6939
+ if (fs12.existsSync(candidate)) {
6816
6940
  tsx = candidate;
6817
6941
  break;
6818
6942
  }
@@ -6842,7 +6966,10 @@ function servicePath() {
6842
6966
  return [.../* @__PURE__ */ new Set([...current, ...parts])].join(":");
6843
6967
  }
6844
6968
  function run2(cmd, args) {
6845
- const res = spawnSync(cmd, args, { encoding: "utf8" });
6969
+ const res = spawnSync(cmd, args, {
6970
+ encoding: "utf8",
6971
+ env: inheritedSubprocessEnv()
6972
+ });
6846
6973
  const output4 = `${res.stdout ?? ""}${res.stderr ?? ""}`.trim();
6847
6974
  return { ok: res.status === 0, output: output4 };
6848
6975
  }
@@ -6860,8 +6987,8 @@ function installService(command, endpoint) {
6860
6987
  }
6861
6988
  function installLaunchd(command, endpoint) {
6862
6989
  const logDir = path9.join(os6.homedir(), ".standardagents");
6863
- fs11.mkdirSync(logDir, { recursive: true });
6864
- fs11.mkdirSync(path9.dirname(plistPath()), { recursive: true });
6990
+ fs12.mkdirSync(logDir, { recursive: true });
6991
+ fs12.mkdirSync(path9.dirname(plistPath()), { recursive: true });
6865
6992
  const envEntries = [
6866
6993
  ` <key>PATH</key><string>${xmlEscape(servicePath())}</string>`,
6867
6994
  ...endpoint ? [` <key>STANDARD_CODE_DAEMON_ENDPOINT</key><string>${xmlEscape(endpoint)}</string>`] : []
@@ -6887,7 +7014,7 @@ ${envEntries}
6887
7014
  </dict>
6888
7015
  </plist>
6889
7016
  `;
6890
- fs11.writeFileSync(plistPath(), plist);
7017
+ fs12.writeFileSync(plistPath(), plist);
6891
7018
  const uid = typeof process.getuid === "function" ? process.getuid() : 501;
6892
7019
  run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
6893
7020
  const boot = run2("launchctl", ["bootstrap", `gui/${uid}`, plistPath()]);
@@ -6904,7 +7031,7 @@ ${envEntries}
6904
7031
  return { ok: true, detail: `LaunchAgent installed (${plistPath()})` };
6905
7032
  }
6906
7033
  function installSystemd(command, endpoint) {
6907
- fs11.mkdirSync(path9.dirname(unitPath()), { recursive: true });
7034
+ fs12.mkdirSync(path9.dirname(unitPath()), { recursive: true });
6908
7035
  const unit = `[Unit]
6909
7036
  Description=Standard Code daemon (headless coding-agent execution client)
6910
7037
  After=network-online.target
@@ -6919,7 +7046,7 @@ ${endpoint ? `Environment=STANDARD_CODE_DAEMON_ENDPOINT=${endpoint}
6919
7046
  [Install]
6920
7047
  WantedBy=default.target
6921
7048
  `;
6922
- fs11.writeFileSync(unitPath(), unit);
7049
+ fs12.writeFileSync(unitPath(), unit);
6923
7050
  const reload = run2("systemctl", ["--user", "daemon-reload"]);
6924
7051
  if (!reload.ok) {
6925
7052
  return {
@@ -6943,7 +7070,7 @@ function uninstallService() {
6943
7070
  const uid = typeof process.getuid === "function" ? process.getuid() : 501;
6944
7071
  run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
6945
7072
  try {
6946
- fs11.unlinkSync(plistPath());
7073
+ fs12.unlinkSync(plistPath());
6947
7074
  } catch {
6948
7075
  }
6949
7076
  return { ok: true, detail: "LaunchAgent removed" };
@@ -6951,7 +7078,7 @@ function uninstallService() {
6951
7078
  if (process.platform === "linux") {
6952
7079
  run2("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
6953
7080
  try {
6954
- fs11.unlinkSync(unitPath());
7081
+ fs12.unlinkSync(unitPath());
6955
7082
  } catch {
6956
7083
  }
6957
7084
  run2("systemctl", ["--user", "daemon-reload"]);
@@ -6961,7 +7088,7 @@ function uninstallService() {
6961
7088
  }
6962
7089
  function serviceStatus() {
6963
7090
  if (process.platform === "darwin") {
6964
- const installed = fs11.existsSync(plistPath());
7091
+ const installed = fs12.existsSync(plistPath());
6965
7092
  const list = run2("launchctl", ["list", SERVICE_LABEL]);
6966
7093
  const pidMatch = list.output.match(/"PID"\s*=\s*(\d+)/);
6967
7094
  return {
@@ -6971,7 +7098,7 @@ function serviceStatus() {
6971
7098
  };
6972
7099
  }
6973
7100
  if (process.platform === "linux") {
6974
- const installed = fs11.existsSync(unitPath());
7101
+ const installed = fs12.existsSync(unitPath());
6975
7102
  const active = run2("systemctl", ["--user", "is-active", SYSTEMD_UNIT]);
6976
7103
  return {
6977
7104
  installed,
@@ -7194,7 +7321,7 @@ async function projectCommand(action, target) {
7194
7321
  process.exit(1);
7195
7322
  }
7196
7323
  const dir2 = path9.resolve(target);
7197
- if (action === "add" && !fs11.existsSync(dir2)) {
7324
+ if (action === "add" && !fs12.existsSync(dir2)) {
7198
7325
  stdout.write(`${c3.red}\u2717${c3.reset} ${dir2} does not exist on this machine.
7199
7326
  `);
7200
7327
  process.exit(1);
@@ -7263,15 +7390,15 @@ var DIR = path9.join(os6.homedir(), ".standardagents");
7263
7390
  var FILE = path9.join(DIR, "prefs.json");
7264
7391
  function loadPrefs(file2 = FILE) {
7265
7392
  try {
7266
- return JSON.parse(fs11.readFileSync(file2, "utf8"));
7393
+ return JSON.parse(fs12.readFileSync(file2, "utf8"));
7267
7394
  } catch {
7268
7395
  return {};
7269
7396
  }
7270
7397
  }
7271
7398
  function savePrefs(update, file2 = FILE) {
7272
7399
  const merged = { ...loadPrefs(file2), ...update };
7273
- fs11.mkdirSync(path9.dirname(file2), { recursive: true });
7274
- 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));
7275
7402
  }
7276
7403
  function shouldOfferDaemonInstall(facts) {
7277
7404
  if (facts.optedOutEnv) return false;
@@ -8446,10 +8573,14 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
8446
8573
  let reconcileSharedMessaging = async () => {
8447
8574
  };
8448
8575
  let applySharedMessagingEvent = () => false;
8449
- let refreshSessionProjection = async () => {
8450
- };
8451
8576
  let scheduleProjectionRefresh = () => {
8452
8577
  };
8578
+ let connectionEpoch = 0;
8579
+ let projectionSnapshot = null;
8580
+ const sharedMessagingSnapshot = new snapshot_epoch_exports.EpochSnapshot(
8581
+ () => reconcileSharedMessaging(true),
8582
+ () => connectionEpoch
8583
+ );
8453
8584
  const shownIds = /* @__PURE__ */ new Set();
8454
8585
  const toolActivity = new ToolActivityFeed();
8455
8586
  const pendingSent = /* @__PURE__ */ new Map();
@@ -8467,9 +8598,10 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
8467
8598
  tui.setStep(label, liveOut);
8468
8599
  };
8469
8600
  const stream = new stream_exports.MessageStream(api, threadId, {
8470
- onOpen: () => {
8471
- void reconcileSharedMessaging(true);
8472
- void refreshSessionProjection();
8601
+ onOpen: (epoch) => {
8602
+ connectionEpoch = epoch;
8603
+ void sharedMessagingSnapshot.reconcile(epoch);
8604
+ void projectionSnapshot?.reconcile(epoch);
8473
8605
  },
8474
8606
  // Live streaming preview: answer text and (opt-in) internal reasoning feed
8475
8607
  // the TUI's ephemeral preview; the committed message still renders from
@@ -8502,7 +8634,7 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
8502
8634
  void relayApprovals().catch(() => {
8503
8635
  });
8504
8636
  } else if (eventType === shared_messaging_exports.SHARED_MESSAGING_EVENT) {
8505
- if (!applySharedMessagingEvent(data)) void reconcileSharedMessaging(true);
8637
+ if (!applySharedMessagingEvent(data)) void sharedMessagingSnapshot.refresh();
8506
8638
  }
8507
8639
  },
8508
8640
  // A failed turn whose message is the lease service's at-limit denial → offer
@@ -8676,7 +8808,7 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
8676
8808
  applySharedMessaging({ version: 1, pending: sharedMessaging.pending, draft: event.draft }, true);
8677
8809
  return true;
8678
8810
  };
8679
- const onTerminalResume = () => void reconcileSharedMessaging(true);
8811
+ const onTerminalResume = () => void sharedMessagingSnapshot.refresh();
8680
8812
  process.on("SIGCONT", onTerminalResume);
8681
8813
  const applySharedMutation = (promise) => promise.then((snapshot) => {
8682
8814
  applySharedMessaging(snapshot, false);
@@ -8995,7 +9127,7 @@ ${c5.gray}Close another session (its slot frees within ~90s), then resend your m
8995
9127
  ]);
8996
9128
  const history = await (0, history_exports.loadHistory)(api, threadId, historySeedThreadId);
8997
9129
  tui.setHistory(history);
8998
- await reconcileSharedMessaging(true);
9130
+ await sharedMessagingSnapshot.refresh();
8999
9131
  let latestDraftPayload = null;
9000
9132
  let draftDirty = false;
9001
9133
  let draftInFlight = false;
@@ -9235,11 +9367,7 @@ ${c5.dim}runs on ${request.machine || runnerName}${c5.reset}`,
9235
9367
  stalledNoticeShown = false;
9236
9368
  }
9237
9369
  } catch {
9238
- try {
9239
- msgs = await api.getMessages(threadId, 60);
9240
- } catch {
9241
- return;
9242
- }
9370
+ msgs = await api.getMessages(threadId, 60);
9243
9371
  }
9244
9372
  const sorted = [...msgs].sort((a, b) => (a.created_at ?? 0) - (b.created_at ?? 0));
9245
9373
  for (const m of sorted) toolActivity.index(m);
@@ -9335,17 +9463,19 @@ ${c5.dim}runs on ${request.machine || runnerName}${c5.reset}`,
9335
9463
  } catch {
9336
9464
  }
9337
9465
  };
9338
- refreshSessionProjection = () => reconcileProjection().catch(() => {
9339
- });
9466
+ projectionSnapshot = new snapshot_epoch_exports.EpochSnapshot(
9467
+ reconcileProjection,
9468
+ () => connectionEpoch
9469
+ );
9340
9470
  let projectionDebounce = null;
9341
9471
  scheduleProjectionRefresh = () => {
9342
9472
  if (projectionDebounce) return;
9343
9473
  projectionDebounce = setTimeout(() => {
9344
9474
  projectionDebounce = null;
9345
- void refreshSessionProjection();
9475
+ void projectionSnapshot?.refresh();
9346
9476
  }, 250);
9347
9477
  };
9348
- await refreshSessionProjection();
9478
+ await projectionSnapshot.reconcile(connectionEpoch);
9349
9479
  await sessionEnded;
9350
9480
  if (projectionDebounce) clearTimeout(projectionDebounce);
9351
9481
  process.off("SIGCONT", onTerminalResume);