@foldrun/core 2.13.0 → 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -425,6 +425,11 @@ export declare function dockerMemory(value: string): string;
425
425
  * than the engine has. Null when the figure is not a number, so the flag is
426
426
  * left off rather than failing the step on an install's typo. */
427
427
  export declare function dockerCpus(cpus: string, available?: number): string | null;
428
+ /** The cores a step's sandbox actually holds, for its record (the bill and
429
+ * the compute in use): the asked-for figure, except on the docker
430
+ * executor, which lowers --cpus to what the engine has (dockerCpus). Until
431
+ * 26 Oct 2026 the record said heavy's 4 on a two-core machine that gave 2. */
432
+ export declare function heldCores(cpus: string, isolation: string | undefined, available?: number): number;
428
433
  export interface RunInContainerArgs {
429
434
  workspaceRoot: string;
430
435
  libraryRoot: string;
@@ -1300,6 +1300,17 @@ export function dockerCpus(cpus, available = engineCpus()) {
1300
1300
  return null;
1301
1301
  return String(Math.min(n, available));
1302
1302
  }
1303
+ /** The cores a step's sandbox actually holds, for its record (the bill and
1304
+ * the compute in use): the asked-for figure, except on the docker
1305
+ * executor, which lowers --cpus to what the engine has (dockerCpus). Until
1306
+ * 26 Oct 2026 the record said heavy's 4 on a two-core machine that gave 2. */
1307
+ export function heldCores(cpus, isolation, available) {
1308
+ const asked = Number(cpus) || 2;
1309
+ if (isolation !== "container")
1310
+ return asked;
1311
+ const given = Number(available === undefined ? dockerCpus(cpus) : dockerCpus(cpus, available));
1312
+ return Number.isFinite(given) && given > 0 ? given : asked;
1313
+ }
1303
1314
  /**
1304
1315
  * What crosses into the container as its environment, and how.
1305
1316
  *
@@ -16,7 +16,7 @@ import { cascadeLimits, toolOwners } from "./limits.js";
16
16
  import { resolveAgentPath } from "./confine.js";
17
17
  import { browserPodLine, podLossDecision, RERAN_ON_FULL } from "./browser-pod.js";
18
18
  import { eventUrl } from "./webhook.js";
19
- import { runStepInContainer, resolveResources, memoryGiB, killRunSandboxes } from "./run-container.js";
19
+ import { runStepInContainer, resolveResources, memoryGiB, heldCores, killRunSandboxes } from "./run-container.js";
20
20
  import { readResources, hasOverride } from "./resources.js";
21
21
  import { hostSafeEnv, platformApiUrl } from "./host-env.js";
22
22
  import { resolveModelCredential, credentialLine, accountModelBlock, isClaudeLoginToken, isModelEnvName, DECLARED_ENV_PREFIX } from "./model-credential.js";
@@ -2129,7 +2129,7 @@ delegateJob) {
2129
2129
  const limits = resolveResources(size, asked.value, { atLeastClass: !!step.sizeUp });
2130
2130
  // What the sandbox holds while it exists — `step.holding`, what the
2131
2131
  // account's compute in use sums (Settings, `foldrun usage compute`).
2132
- const held = { cpus: Number(limits.cpus) || 2, memGiB: memoryGiB(limits.memory) };
2132
+ const held = { cpus: heldCores(limits.cpus, process.env.FOLDRUN_RUN_ISOLATION), memGiB: memoryGiB(limits.memory) };
2133
2133
  // oauth2 secrets become live access tokens here — the one async moment
2134
2134
  // in secret resolution, at the last host-side point before anything is
2135
2135
  // injected or substituted. The refresh recipes never leave this process:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldrun/core",
3
- "version": "2.13.0",
3
+ "version": "2.13.1",
4
4
  "description": "Agents are just folders. The format, the runner, the checks.",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",
@@ -1473,6 +1473,17 @@ export function dockerCpus(cpus: string, available: number = engineCpus()): stri
1473
1473
  return String(Math.min(n, available));
1474
1474
  }
1475
1475
 
1476
+ /** The cores a step's sandbox actually holds, for its record (the bill and
1477
+ * the compute in use): the asked-for figure, except on the docker
1478
+ * executor, which lowers --cpus to what the engine has (dockerCpus). Until
1479
+ * 26 Oct 2026 the record said heavy's 4 on a two-core machine that gave 2. */
1480
+ export function heldCores(cpus: string, isolation: string | undefined, available?: number): number {
1481
+ const asked = Number(cpus) || 2;
1482
+ if (isolation !== "container") return asked;
1483
+ const given = Number(available === undefined ? dockerCpus(cpus) : dockerCpus(cpus, available));
1484
+ return Number.isFinite(given) && given > 0 ? given : asked;
1485
+ }
1486
+
1476
1487
  export interface RunInContainerArgs {
1477
1488
  workspaceRoot: string;
1478
1489
  libraryRoot: string;
package/src/runner.ts CHANGED
@@ -19,7 +19,7 @@ import { cascadeLimits, toolOwners } from "./limits.ts";
19
19
  import { resolveAgentPath } from "./confine.ts";
20
20
  import { browserPodLine, podLossDecision, RERAN_ON_FULL } from "./browser-pod.ts";
21
21
  import { eventUrl } from "./webhook.ts";
22
- import { runStepInContainer, resolveResources, memoryGiB, killRunSandboxes, type StepTiming } from "./run-container.ts";
22
+ import { runStepInContainer, resolveResources, memoryGiB, heldCores, killRunSandboxes, type StepTiming } from "./run-container.ts";
23
23
  import { readResources, hasOverride } from "./resources.ts";
24
24
  import { hostSafeEnv, platformApiUrl } from "./host-env.ts";
25
25
  import { resolveModelCredential, credentialLine, accountModelBlock, isClaudeLoginToken, isModelEnvName, DECLARED_ENV_PREFIX } from "./model-credential.ts";
@@ -2322,7 +2322,7 @@ async function runStep(
2322
2322
  const limits = resolveResources(size, asked.value, { atLeastClass: !!step.sizeUp });
2323
2323
  // What the sandbox holds while it exists — `step.holding`, what the
2324
2324
  // account's compute in use sums (Settings, `foldrun usage compute`).
2325
- const held = { cpus: Number(limits.cpus) || 2, memGiB: memoryGiB(limits.memory) };
2325
+ const held = { cpus: heldCores(limits.cpus, process.env.FOLDRUN_RUN_ISOLATION), memGiB: memoryGiB(limits.memory) };
2326
2326
 
2327
2327
  // oauth2 secrets become live access tokens here — the one async moment
2328
2328
  // in secret resolution, at the last host-side point before anything is