@moinulmoin/eden 0.6.0 → 0.7.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.
package/README.md CHANGED
@@ -12,15 +12,15 @@ If you already have an Eve project, start with `eden deploy`.
12
12
  Use any one of these package managers:
13
13
 
14
14
  ```sh
15
- npm install --global @moinulmoin/eden@0.6.0
15
+ npm install --global @moinulmoin/eden@0.7.1
16
16
  ```
17
17
 
18
18
  ```sh
19
- pnpm add --global @moinulmoin/eden@0.6.0
19
+ pnpm add --global @moinulmoin/eden@0.7.1
20
20
  ```
21
21
 
22
22
  ```sh
23
- bun add --global @moinulmoin/eden@0.6.0
23
+ bun add --global @moinulmoin/eden@0.7.1
24
24
  ```
25
25
 
26
26
  Then confirm the CLI is available:
@@ -126,12 +126,16 @@ Run `eden <command> --help` for command-specific options.
126
126
 
127
127
  - Deploy does not replace the Eve project's providers, databases, Workflow
128
128
  World, authentication, schedules, channels, or sandbox.
129
- - Container disk and memory are wiped when the Container sleeps. Durable
130
- state needs a project-configured, Cloudflare-reachable Workflow World such
131
- as Postgres (for example `@workflow/world-postgres`).
132
- - Schedules do not fire while the Container sleeps.
133
- - This release uses one logical Container instance (`basic`, 1 GiB) and does
134
- not promise horizontal scaling or custom domains.
129
+ - Container files survive sleep via snapshots, and image updates now carry
130
+ Eve's sandbox sessions — every conversation's files — across the image
131
+ change through the Durable Object's storage (capped at 1 GiB compressed).
132
+ The rest of `/workspace` still resets to the new image. Durable Workflow
133
+ state across updates needs a project-configured
134
+ World, such as Postgres or `@moinulmoin/eden-world-cloudflare`.
135
+ - Standard 5-field cron schedules wake the Container; unsupported cron forms
136
+ only run while it is awake.
137
+ - This release uses one logical Container instance (`standard-1`, 1/2 vCPU,
138
+ 4 GiB) and does not promise horizontal scaling or custom domains.
135
139
  - Bun is an installer only; Node remains the runtime.
136
140
 
137
141
  ## Documentation
@@ -7,8 +7,8 @@ import { createServer, } from "node:net";
7
7
  import { execFile, spawn, } from "node:child_process";
8
8
  import { fileURLToPath, } from "node:url";
9
9
  import { promisify, } from "node:util";
10
- import { EveCliError, } from "./eve.js";
11
- import { buildEveProjectSnapshot, createDockerEveProjectBuilder, revalidateEveProjectCandidateInputs, EvePackagingError, } from "./eve-packaging.js";
10
+ import { EveCliError, EVE_NAME_PATTERN, } from "./eve.js";
11
+ import { buildEveProjectSnapshot, createDockerEveProjectBuilder, revalidateEveProjectCandidateInputs, EvePackagingError, IMAGE_ID_PATTERN, } from "./eve-packaging.js";
12
12
  import { buildEveRuntimeImage, discardEveRuntimeImage, revalidateEveRuntimeCandidate, validateEveHostRequirements, } from "./eve-runtime-image.js";
13
13
  import { EveRuntimeConfigError, prepareEveRuntimeInjection, redactEveRuntimeOutput, } from "./eve-runtime-config.js";
14
14
  import { createEveHostConfig, generateEveHostWorkerSource, parseEveScheduleCron, resolveStableWorkersDevOrigin, } from "@moinulmoin/eden-runtime-cloudflare";
@@ -64,6 +64,8 @@ function mapPackagingCheck(value) {
64
64
  return "VAL-SEC-003";
65
65
  case "DOCKER_PLATFORM_BLOCKED":
66
66
  return "VAL-BUILD-005";
67
+ case "EVE_SANDBOX_RESUME_PATCH":
68
+ return value.id;
67
69
  default:
68
70
  return `EVE-${value.id}`;
69
71
  }
@@ -521,7 +523,7 @@ async function readWorkersDevSubdomain(accountId) {
521
523
  ? result.subdomain
522
524
  : undefined;
523
525
  return typeof subdomain === "string" &&
524
- /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(subdomain)
526
+ EVE_NAME_PATTERN.test(subdomain)
525
527
  ? subdomain
526
528
  : undefined;
527
529
  }
@@ -537,34 +539,34 @@ async function readWorkersDevSubdomain(accountId) {
537
539
  export function exactTargetContainerEntries(value, name) {
538
540
  return exactContainerEntries(value, boundedResourceName(name, "container"));
539
541
  }
540
- async function defaultCloudflareRead(request) {
541
- const account = await readWranglerJson(["whoami", "--json"]);
542
+ async function readExactTargetInventory(workerName, containerApp) {
542
543
  const containers = await readWranglerJson([
543
- "containers",
544
- "list",
545
- "--json",
546
- "--per-page",
547
- "100",
544
+ "containers", "list", "--json", "--per-page", "100",
548
545
  ]);
549
546
  const deployments = await readWranglerJson([
550
- "deployments",
551
- "list",
552
- "--name",
553
- request.name,
554
- "--json",
547
+ "deployments", "list", "--name", workerName, "--json",
555
548
  ]);
549
+ return {
550
+ containers,
551
+ deployments,
552
+ containerEntries: exactContainerEntries(containers.value, containerApp),
553
+ deploymentEntries: exactDeploymentEntries(deployments.value),
554
+ };
555
+ }
556
+ async function defaultCloudflareRead(request) {
557
+ const account = await readWranglerJson(["whoami", "--json"]);
558
+ const { containers, deployments, containerEntries, deploymentEntries: listedDeployments } = await readExactTargetInventory(request.name, boundedResourceName(request.name, "container"));
556
559
  const accountId = authenticatedAccountId(account.value);
557
560
  const accountAccess = account.failed || accountId === undefined
558
561
  ? "unavailable"
559
562
  : "available";
560
- const containerEntries = exactTargetContainerEntries(containers.value, request.name);
561
563
  const containerAccess = containers.failed || containerEntries === undefined
562
564
  ? "unavailable"
563
565
  : "available";
564
566
  const deploymentEntries = deployments.failed &&
565
567
  /(?:does not exist|not found)/iu.test(deployments.stderr ?? "")
566
568
  ? []
567
- : exactDeploymentEntries(deployments.value);
569
+ : listedDeployments;
568
570
  const workersDevSubdomain = await readWorkersDevSubdomain(accountId);
569
571
  if (accountAccess === "unavailable" ||
570
572
  containerAccess === "unavailable" ||
@@ -1008,7 +1010,11 @@ async function writeEveDeploymentArtifacts(candidate, hostConfig, workerSource)
1008
1010
  });
1009
1011
  return { workerSourcePath, wranglerConfigPath };
1010
1012
  }
1011
- function runWranglerWithInput(args, cwd, input) {
1013
+ /** Deadline for bounded Wrangler reads, secret writes, pushes, and deletions. */
1014
+ const WRANGLER_OPERATION_TIMEOUT_MS = 120_000;
1015
+ /** Deadline for `wrangler deploy`, whose Container image preparation alone can approach two minutes. */
1016
+ const WRANGLER_PUBLICATION_TIMEOUT_MS = 600_000;
1017
+ function runWranglerWithInput(args, cwd, input, timeoutMs = WRANGLER_OPERATION_TIMEOUT_MS) {
1012
1018
  return new Promise((resolveResult) => {
1013
1019
  const child = spawn(process.execPath, [wranglerEntrypoint, ...args], {
1014
1020
  cwd,
@@ -1035,7 +1041,7 @@ function runWranglerWithInput(args, cwd, input) {
1035
1041
  stdout,
1036
1042
  stderr: "The bounded Wrangler operation timed out.",
1037
1043
  });
1038
- }, 120_000);
1044
+ }, timeoutMs);
1039
1045
  child.stdout.on("data", (chunk) => {
1040
1046
  stdout += chunk.toString();
1041
1047
  });
@@ -1154,7 +1160,7 @@ function defaultPublicationRunner() {
1154
1160
  "--env",
1155
1161
  request.identity.environment,
1156
1162
  "--strict",
1157
- ], dirname(request.wranglerConfigPath));
1163
+ ], dirname(request.wranglerConfigPath), undefined, WRANGLER_PUBLICATION_TIMEOUT_MS);
1158
1164
  if (result.exitCode !== 0) {
1159
1165
  return {
1160
1166
  status: "indeterminate",
@@ -1162,22 +1168,7 @@ function defaultPublicationRunner() {
1162
1168
  ownershipEvidenceRetained: true,
1163
1169
  };
1164
1170
  }
1165
- const containers = await readWranglerJson([
1166
- "containers",
1167
- "list",
1168
- "--json",
1169
- "--per-page",
1170
- "100",
1171
- ]);
1172
- const containerEntries = exactContainerEntries(containers.value, request.hostConfig.container.applicationName);
1173
- const deployments = await readWranglerJson([
1174
- "deployments",
1175
- "list",
1176
- "--name",
1177
- request.identity.workerName,
1178
- "--json",
1179
- ]);
1180
- const deploymentEntries = exactDeploymentEntries(deployments.value);
1171
+ const { containers, deployments, containerEntries, deploymentEntries } = await readExactTargetInventory(request.identity.workerName, request.hostConfig.container.applicationName);
1181
1172
  if (containers.failed ||
1182
1173
  containerEntries === undefined ||
1183
1174
  containerEntries.length !== 1 ||
@@ -1527,7 +1518,7 @@ async function runEveDeployment(request, options, collected) {
1527
1518
  throw deploymentFailure("EVE_ORIGIN_UNAVAILABLE", "The authenticated stable workers.dev origin did not match the exact Worker target.");
1528
1519
  }
1529
1520
  const imageDigest = runtimeEvidence.imageDigest;
1530
- if (imageDigest === undefined || !/^sha256:[0-9a-f]{64}$/u.test(imageDigest)) {
1521
+ if (imageDigest === undefined || !IMAGE_ID_PATTERN.test(imageDigest)) {
1531
1522
  throw deploymentFailure("EVE_IMAGE_IDENTITY_UNAVAILABLE", "The deploy candidate did not provide an immutable runtime image digest.");
1532
1523
  }
1533
1524
  const targetKey = stableDeploymentKey(collected.projectId, accountId, request.environment, request.name);
@@ -1632,8 +1623,6 @@ async function runEveDeployment(request, options, collected) {
1632
1623
  accountId,
1633
1624
  workerName: identity.workerName,
1634
1625
  containerApplicationName: identity.containerApplicationName,
1635
- containerClassName: "EveHostDurableContainer",
1636
- containerBindingName: "EVE_CONTAINER",
1637
1626
  stableContainerInstanceName: identity.stableContainerInstanceName,
1638
1627
  deploymentId: identity.deploymentId,
1639
1628
  generationId: identity.generationId,
@@ -2027,7 +2016,6 @@ async function collectEvePreflight(request, options) {
2027
2016
  snapshot: null,
2028
2017
  toolchain: null,
2029
2018
  image: null,
2030
- runtime: null,
2031
2019
  secrets: {
2032
2020
  runtimeVariableNames: [],
2033
2021
  valuesRecorded: false,
@@ -2040,6 +2028,7 @@ async function collectEvePreflight(request, options) {
2040
2028
  redactionRegisteredBeforeChildren: false,
2041
2029
  },
2042
2030
  checks: [],
2031
+ sandboxResumePatch: "absent",
2043
2032
  candidateImageId: null,
2044
2033
  candidateImageRetainedLocally: false,
2045
2034
  writtenPaths: [],
@@ -2047,6 +2036,13 @@ async function collectEvePreflight(request, options) {
2047
2036
  };
2048
2037
  }
2049
2038
  checks.push(...packaging.checks.map(mapPackagingCheck));
2039
+ if (packaging.sandboxResumePatch === "skipped") {
2040
+ warnings.push({
2041
+ id: "EVE_SANDBOX_RESUME_PATCH",
2042
+ message: "Eve's just-bash file is not a version Eden knows; conversations may lose their sandbox after a skill change (eve#4440)",
2043
+ remediation: "Pin Eve to a version Eden knows, or update Eden so its known Eve versions include yours.",
2044
+ });
2045
+ }
2050
2046
  const discardPackagingImage = async () => {
2051
2047
  if (packaging.candidateImageId === null ||
2052
2048
  builder.discard === undefined) {
@@ -2240,7 +2236,7 @@ async function collectEvePreflight(request, options) {
2240
2236
  "VAL-BUILD-007",
2241
2237
  ];
2242
2238
  const runtimeProofComplete = requiredRuntimeChecks.every((id) => runtimeEvidence?.checks.some((value) => value.id === id && value.status === "passed"));
2243
- const runtimeImageIdentityValid = /^sha256:[0-9a-f]{64}$/u.test(runtimeEvidence.imageDigest ?? "");
2239
+ const runtimeImageIdentityValid = IMAGE_ID_PATTERN.test(runtimeEvidence.imageDigest ?? "");
2244
2240
  if (!runtimeProofComplete) {
2245
2241
  checks.push(check("VAL-BUILD-005", "failed", "The runtime seam did not return complete proof of Linux/amd64 image construction, official Eve-start boot, and real health.", "Return passed VAL-BUILD-005, VAL-BUILD-006, and VAL-BUILD-007 checks from the disposable runtime runner."));
2246
2242
  }
@@ -2672,24 +2668,10 @@ async function parseEveDeploymentRecord(recordPath, environment, name) {
2672
2668
  }
2673
2669
  async function defaultDestroyTargetRead(request) {
2674
2670
  const account = await readWranglerJson(["whoami", "--json"]);
2675
- const deployments = await readWranglerJson([
2676
- "deployments",
2677
- "list",
2678
- "--name",
2679
- request.workerName,
2680
- "--json",
2681
- ]);
2682
- const containers = await readWranglerJson([
2683
- "containers",
2684
- "list",
2685
- "--json",
2686
- "--per-page",
2687
- "100",
2688
- ]);
2671
+ const { deployments, containerEntries: entries, deploymentEntries } = await readExactTargetInventory(request.workerName, request.containerApplicationName);
2689
2672
  const accountId = authenticatedAccountId(account.value);
2690
2673
  const workerExists = !deployments.failed &&
2691
- (exactDeploymentEntries(deployments.value)?.length ?? 0) > 0;
2692
- const entries = exactContainerEntries(containers.value, request.containerApplicationName);
2674
+ (deploymentEntries?.length ?? 0) > 0;
2693
2675
  const firstContainer = entries === undefined ? undefined : entries[0];
2694
2676
  const ownedRepositories = request.registryRepositories;
2695
2677
  let registryTagsPresent;
@@ -1,5 +1,5 @@
1
- import type { EveRuntimeInputIdentity } from "./eve-runtime-config.js";
2
- export type EvePackagingCode = "ROOT_INVALID" | "UNSUPPORTED_TOOLCHAIN" | "DEPENDENCY_AMBIGUITY" | "SOURCE_RACE" | "EVE_BUILD_FAILED" | "UNSUPPORTED_EVE_OUTPUT" | "RUNTIME_CLOSURE_INCOMPLETE" | "SECRET_EXCLUSION_FAILED" | "DOCKER_PLATFORM_BLOCKED" | "UNSUPPORTED_HOST_REQUIREMENT" | "EVE_HEALTH_FAILED" | "WORLD_MIGRATION_FAILED" | "CLEANUP_UNVERIFIED" | "PACKAGE_VERIFICATION_FAILED";
1
+ import { type EveRuntimeInputIdentity } from "./eve-runtime-config.js";
2
+ export type EvePackagingCode = "ROOT_INVALID" | "UNSUPPORTED_TOOLCHAIN" | "DEPENDENCY_AMBIGUITY" | "SOURCE_RACE" | "EVE_BUILD_FAILED" | "UNSUPPORTED_EVE_OUTPUT" | "RUNTIME_CLOSURE_INCOMPLETE" | "SECRET_EXCLUSION_FAILED" | "DOCKER_PLATFORM_BLOCKED" | "UNSUPPORTED_HOST_REQUIREMENT" | "EVE_HEALTH_FAILED" | "WORLD_MIGRATION_FAILED" | "CLEANUP_UNVERIFIED";
3
3
  export interface EveRuntimeConfigExclusion {
4
4
  /**
5
5
  * This path is opaque. The packaging worker only uses its lexical identity
@@ -101,6 +101,23 @@ export interface EveProjectOutput {
101
101
  readonly outputDigest: string;
102
102
  readonly fileCount: number;
103
103
  }
104
+ /** Snapshot-relative root of Eve's prepared sandbox templates. */
105
+ export declare const EVE_SANDBOX_CACHE_ROOT: ".eve/sandbox-cache";
106
+ /**
107
+ * Evidence for the sandbox templates `eve build` prepared inside the isolated
108
+ * builder. Runtime sandboxes resolve their template at
109
+ * `<appRoot>/.eve/sandbox-cache/<provider>/templates/<key>`, so this tree must
110
+ * ship inside the runtime image or every `bash`/`read_file`/`write_file` call
111
+ * fails with "Sandbox template ... is not provisioned". `null` when this Eve
112
+ * build prepared no sandbox template.
113
+ */
114
+ export interface EveSandboxCacheOutput {
115
+ readonly present: true;
116
+ readonly root: typeof EVE_SANDBOX_CACHE_ROOT;
117
+ readonly outputDigest: string;
118
+ readonly fileCount: number;
119
+ readonly totalBytes: number;
120
+ }
104
121
  export interface EveProjectBuildCandidate {
105
122
  readonly generationId: string;
106
123
  readonly generationRoot: string;
@@ -122,6 +139,7 @@ export interface EveProjectBuildCandidate {
122
139
  readonly sourceDigest: string;
123
140
  readonly snapshotDigest: string;
124
141
  readonly generatedOutput: EveProjectOutput;
142
+ readonly sandboxCache: EveSandboxCacheOutput | null;
125
143
  readonly runtimeConfigInputIdentity?: string;
126
144
  readonly runtimeVariableNames: readonly string[];
127
145
  }
@@ -175,15 +193,6 @@ export interface EveProjectImage {
175
193
  };
176
194
  readonly generatedOutput: EveProjectOutput | null;
177
195
  }
178
- export interface EveProjectRuntime {
179
- readonly listenHost: "0.0.0.0";
180
- readonly listenPort: 8080;
181
- readonly healthMethod: "GET";
182
- readonly healthPath: "/eve/v1/health";
183
- readonly healthStatus: "not-run";
184
- readonly healthVerified: false;
185
- readonly durableLocalFilesystemClaim: false;
186
- }
187
196
  export interface EveProjectSecretsEvidence {
188
197
  readonly runtimeVariableNames: readonly string[];
189
198
  readonly valuesRecorded: false;
@@ -228,9 +237,15 @@ export interface EveProjectPackagingResult {
228
237
  readonly snapshot: EveProjectSnapshot | null;
229
238
  readonly toolchain: EveProjectToolchain | null;
230
239
  readonly image: EveProjectImage | null;
231
- readonly runtime: EveProjectRuntime | null;
232
240
  readonly secrets: EveProjectSecretsEvidence;
233
241
  readonly checks: readonly EvePackagingCheck[];
242
+ /**
243
+ * Outcome of the builder's temporary eve#4440 sandbox-resume patch:
244
+ * `applied` when the shipped just-bash binding carries it, `skipped` when
245
+ * the binding is a version Eden does not know, `absent` when this Eve
246
+ * build has no just-bash binding or packaging never reached the image.
247
+ */
248
+ readonly sandboxResumePatch: EveSandboxResumePatchStatus;
234
249
  readonly candidateImageId: string | null;
235
250
  readonly candidateImageRetainedLocally: boolean;
236
251
  readonly writtenPaths: readonly string[];
@@ -252,6 +267,64 @@ export declare class EvePackagingError extends Error {
252
267
  readonly remediation: string;
253
268
  });
254
269
  }
270
+ /**
271
+ * Eden's temporary fix for upstream https://github.com/vercel/eve/issues/4440
272
+ * (repro: https://github.com/moinulmoin/eve-justbash-resume-repro).
273
+ * Eve's just-bash provider permanently refuses to resume a conversation once
274
+ * the sandbox template changes (skills, `agent/sandbox/workspace/`, or the
275
+ * sandbox definition) and never falls back, so one `eden deploy` update would
276
+ * break every existing conversation's sandbox forever. The isolated builder
277
+ * rewrites one file in the installed Eve copy so an existing session reopens
278
+ * against the current template instead of throwing; user files under
279
+ * `/workspace` always win over the template. The patch applies only when the
280
+ * target file's sha256 matches a known binding and selects that binding's
281
+ * replacement; it is removed entirely once upstream ships the fix.
282
+ */
283
+ export declare const EVE_SANDBOX_RESUME_PATCH_KNOWN_SHA256 = "0ba0ac3a237c99af2f67a6028f1675bf7c04b22454b4ebfb4cd9d19e5bf5aaf8";
284
+ /** Eve 0.79.1 stores a template key instead of an absolute template path. */
285
+ export declare const EVE_SANDBOX_RESUME_PATCH_LATEST_SHA256 = "ab8b1ad7398af8f6fd2a1e91eb0d1ff8d2b9b9afe1836234f36ce0e896791c45";
286
+ /** Marker the patched binding always contains; proves the patch shipped. */
287
+ export declare const EVE_SANDBOX_RESUME_PATCH_SIGNATURE = "edenRefreshJustBashSessionSkills";
288
+ /** The exact `resume()` implementation in Eve 0.68.0, 0.71.2, 0.72.1, and 0.79.1. */
289
+ export declare const EVE_JUST_BASH_RESUME_ORIGINAL = "async resume(e,n,r){let i=requirePreparedJustBashArtifact(n),a=requireJustBashSessionState(r),o=createSandboxProviderIdentity({artifact:i,version:1}),s=sessionRootPath(e,i);if(a.generation!==o||a.rootPath!==s)throw Error(`just-bash session state is incompatible with this environment.`);if(!await pathExists(a.rootPath))throw Error(`just-bash session root \"${a.rootPath}\" no longer exists.`);return await openHandle(e,a.rootPath,t)}";
290
+ /**
291
+ * The replacement `resume()`: a session whose template generation moved is
292
+ * contained to the same sessions directory and reopened with its authored
293
+ * skills refreshed from the current template. A session folder that is gone
294
+ * (for example a deploy that could not carry it) is recreated from the
295
+ * current template instead of failing every later sandbox call.
296
+ */
297
+ export declare const EVE_SANDBOX_RESUME_PATCHED = "async resume(e,n,r){let i=requirePreparedJustBashArtifact(n),a=requireJustBashSessionState(r),o=createSandboxProviderIdentity({artifact:i,version:1}),s=sessionRootPath(e,i);if((a.generation!==o||a.rootPath!==s)&&dirname(a.rootPath)!==dirname(s))throw Error(`just-bash session state is incompatible with this environment.`);await ensureSessionRoot(i,a.rootPath);if(a.generation!==o)await edenRefreshJustBashSessionSkills(i.templateRootPath,a.rootPath);return await openHandle(e,a.rootPath,t)}";
298
+ /**
299
+ * Eve 0.79.1 resolves the current template key under the runtime cache.
300
+ * Its ensureSessionRoot accepts that path, not the prepared artifact.
301
+ */
302
+ export declare const EVE_SANDBOX_RESUME_PATCHED_LATEST = "async resume(e,n,r){let i=requirePreparedJustBashArtifact(n),a=requireJustBashSessionState(r),o=createSandboxProviderIdentity({artifact:i,version:1}),s=sessionRootPath(e,i);if((a.generation!==o||a.rootPath!==s)&&dirname(a.rootPath)!==dirname(s))throw Error(`just-bash session state is incompatible with this environment.`);let c=resolveTemplateRootPath(e.storagePath,i.templateKey);await ensureSessionRoot(c,a.rootPath);if(a.generation!==o)await edenRefreshJustBashSessionSkills(c,a.rootPath);return await openHandle(e,a.rootPath,t)}";
303
+ /**
304
+ * Helpers appended to the patched binding. They use only identifiers the
305
+ * module already imports (`readdir`, `rm`, `join`, `pathExists`,
306
+ * `copyDirectoryAtomically`). Skills live at `$HOME/.agents/skills` inside a
307
+ * just-bash root, so the session keeps the same path relative to its `fs`
308
+ * directory as the template; the template's `fs` is scanned because `$HOME`
309
+ * is only known inside the sandbox.
310
+ */
311
+ export declare const EVE_SANDBOX_RESUME_PATCH_HELPERS = "async function edenRefreshJustBashSessionSkills(e,t){let n=await edenFindTemplateSkillsRelativePath(join(e,\"fs\"));if(n===void 0)return;let r=join(t,\"fs\",n);await rm(r,{force:!0,recursive:!0}),await copyDirectoryAtomically(join(e,\"fs\",n),r)}\nasync function edenFindTemplateSkillsRelativePath(e){let t=[[\"\",0]];for(;t.length>0;){let n=t.shift(),r=n[0],i=n[1];if(i>3)continue;let a=[];try{a=await readdir(join(e,r),{withFileTypes:!0})}catch{a=[]}for(let o of a){if(!o.isDirectory())continue;let s=r===\"\"?o.name:r+\"/\"+o.name;if(o.name===\".agents\")return await pathExists(join(e,s,\"skills\"))?s+\"/skills\":void 0;t.push([s,i+1])}}return void 0}\n";
312
+ /**
313
+ * The CommonJS patcher the isolated builder runs between the frozen install
314
+ * and `eve build` (and again for the production reinstall). It never touches
315
+ * project files, applies only against known sha256 hashes, verifies the
316
+ * replacement matched exactly once, validates the result with `node --check`,
317
+ * and breaks hardlinks by writing a temp file and renaming it into place.
318
+ */
319
+ export declare const EVE_SANDBOX_RESUME_PATCH_SCRIPT: string;
320
+ /** Outcome of the builder's sandbox-resume patch for the packaged image. */
321
+ export type EveSandboxResumePatchStatus = "applied" | "skipped" | "absent";
322
+ export declare function sha256(value: string | Buffer): string;
323
+ export declare function jsonBytes(value: unknown): Buffer;
324
+ export declare function isWithin(root: string, candidate: string): boolean;
325
+ export declare function safeRelativePath(root: string, candidate: string): string;
326
+ export declare const IMAGE_ID_PATTERN: RegExp;
327
+ export declare function imageReference(nodeImage: EveNodeImage, reason: string, remediation: string): string;
255
328
  /**
256
329
  * The authored Eve project source the runtime stage must carry so `eve start`
257
330
  * can resolve the project context (agent/, agents/ workspaces, flat layouts,
@@ -259,6 +332,7 @@ export declare class EvePackagingError extends Error {
259
332
  * capture-time exclusion still applied; generated roots are never source.
260
333
  */
261
334
  export declare function eveSnapshotSourceEntries(snapshotRoot: string): Promise<readonly string[]>;
335
+ export declare function safeError(error: EvePackagingError): EveProjectPackagingResult["error"];
262
336
  export declare function buildEveProjectSnapshot(options: EveProjectSnapshotOptions): Promise<EveProjectPackagingResult>;
263
337
  export declare function revalidateEveProjectCandidateInputs(candidate: EveProjectBuildCandidate, runtimeConfig?: EveRuntimeConfigExclusion): Promise<void>;
264
338
  export declare function createDockerEveProjectBuilder(options: {