@foldrun/core 1.4.1 → 1.4.2

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.
@@ -36,7 +36,9 @@ import { repoDir } from "./gitrepo.js";
36
36
  import { entriesNoFollow } from "./paths.js";
37
37
  import { filterIgnored, findingFingerprint, ruleForWhere, scanFiles } from "./scan.js";
38
38
  /** Directories a deploy never reads out of a source tree. */
39
- const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results"]);
39
+ // `.cache` is what a run's tools leave in an agent's folder (HOME is that
40
+ // folder): logs and font caches, never authored.
41
+ const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results", ".cache"]);
40
42
  /** Files that are never part of a workspace, whatever directory they sit in. */
41
43
  const NOT_SOURCE_FILE = new Set([".DS_Store", "secrets.json"]);
42
44
  const IN_WORKSPACE_DIR = new RegExp(`^(${WORKSPACE_DIRS.join("|")})/`);
@@ -59,6 +59,10 @@ const DENY_BACK_GIT_RE = /(^|\/)\.git(\/|$)/;
59
59
  const DENY_BACK_SECRET_FILES = /(^|\/)\.secret-files\//;
60
60
  // And per-agent knowledge, at any depth under agents/<name>/.
61
61
  const DENY_BACK_RE = /^agents\/[^/]+\/knowledge\//;
62
+ // A run's caches are not workspace content either: HOME is the agent's own
63
+ // folder, so a tool that ignores XDG_CACHE_HOME (set by the driver) still
64
+ // writes ~/.cache or ~/.npm there. Never copied back.
65
+ const DENY_BACK_CACHE = /^agents\/[^/]+\/\.(?:cache|npm)(?:\/|$)/;
62
66
  // A dependency tree is not workspace content. Nothing authored lives in
63
67
  // node_modules, it is enormous, and a runtime linked into a tool's directory
64
68
  // so ESM can resolve it would otherwise be copied back file by file.
@@ -80,6 +84,8 @@ export function allowedBack(rel) {
80
84
  return false;
81
85
  if (DENY_BACK_NODE_MODULES.test(norm))
82
86
  return false;
87
+ if (DENY_BACK_CACHE.test(norm))
88
+ return false;
83
89
  return true;
84
90
  }
85
91
  /**
@@ -433,6 +439,11 @@ try {
433
439
  // @file secrets crossed as content; materialise them to 0600 paths inside
434
440
  // the container (a host path from the other side would not exist here).
435
441
  const env = materializeFileSecrets(agentDir, { ...process.env, HOME: agentDir }).env;
442
+ // Caches go to the sandbox user's own home, not to HOME: the Claude CLI's
443
+ // logs, fontconfig, Mesa and gstreamer all follow XDG_CACHE_HOME, and under
444
+ // agents/<name>/.cache they were copied back after every step — 3,855 files
445
+ // across 179 agent folders on the box by 17 Oct 2026, read by nothing.
446
+ env.XDG_CACHE_HOME = "/home/agent/.cache";
436
447
 
437
448
  // The declared runtime, built in here — pip and npm have the network, which
438
449
  // the host side may not. It lands in .foldrun/runner/.runtimes, which the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldrun/core",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Agents are just folders. The format, the runner, the checks.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
package/src/deploy.ts CHANGED
@@ -49,7 +49,9 @@ import { entriesNoFollow } from "./paths.ts";
49
49
  import { filterIgnored, findingFingerprint, ruleForWhere, scanFiles, type ScanFinding, type ScanOptions } from "./scan.ts";
50
50
 
51
51
  /** Directories a deploy never reads out of a source tree. */
52
- const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results"]);
52
+ // `.cache` is what a run's tools leave in an agent's folder (HOME is that
53
+ // folder): logs and font caches, never authored.
54
+ const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results", ".cache"]);
53
55
 
54
56
  /** Files that are never part of a workspace, whatever directory they sit in. */
55
57
  const NOT_SOURCE_FILE = new Set([".DS_Store", "secrets.json"]);
@@ -192,6 +192,10 @@ const DENY_BACK_GIT_RE = /(^|\/)\.git(\/|$)/;
192
192
  const DENY_BACK_SECRET_FILES = /(^|\/)\.secret-files\//;
193
193
  // And per-agent knowledge, at any depth under agents/<name>/.
194
194
  const DENY_BACK_RE = /^agents\/[^/]+\/knowledge\//;
195
+ // A run's caches are not workspace content either: HOME is the agent's own
196
+ // folder, so a tool that ignores XDG_CACHE_HOME (set by the driver) still
197
+ // writes ~/.cache or ~/.npm there. Never copied back.
198
+ const DENY_BACK_CACHE = /^agents\/[^/]+\/\.(?:cache|npm)(?:\/|$)/;
195
199
  // A dependency tree is not workspace content. Nothing authored lives in
196
200
  // node_modules, it is enormous, and a runtime linked into a tool's directory
197
201
  // so ESM can resolve it would otherwise be copied back file by file.
@@ -207,6 +211,7 @@ export function allowedBack(rel: string): boolean {
207
211
  if (DENY_BACK_GIT_RE.test(norm)) return false;
208
212
  if (DENY_BACK_SECRET_FILES.test(norm)) return false;
209
213
  if (DENY_BACK_NODE_MODULES.test(norm)) return false;
214
+ if (DENY_BACK_CACHE.test(norm)) return false;
210
215
  return true;
211
216
  }
212
217
 
@@ -564,6 +569,11 @@ try {
564
569
  // @file secrets crossed as content; materialise them to 0600 paths inside
565
570
  // the container (a host path from the other side would not exist here).
566
571
  const env = materializeFileSecrets(agentDir, { ...process.env, HOME: agentDir }).env;
572
+ // Caches go to the sandbox user's own home, not to HOME: the Claude CLI's
573
+ // logs, fontconfig, Mesa and gstreamer all follow XDG_CACHE_HOME, and under
574
+ // agents/<name>/.cache they were copied back after every step — 3,855 files
575
+ // across 179 agent folders on the box by 17 Oct 2026, read by nothing.
576
+ env.XDG_CACHE_HOME = "/home/agent/.cache";
567
577
 
568
578
  // The declared runtime, built in here — pip and npm have the network, which
569
579
  // the host side may not. It lands in .foldrun/runner/.runtimes, which the