From b6718f389b9261cf043ec9345bb5ee10a56ed8f0 Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Fri, 31 Jul 2026 14:58:09 +0000 Subject: [PATCH] refactor(eve): resolve every sandbox path through one resolver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1459 added `resolveSandboxModelPath` to expand a leading `$HOME` for the sandbox file tools, but left two older paths doing the same work their own way. `resolveSandboxSkillRoot` kept its own probe-and-join, which needed `HOME_SKILL_SUFFIX` — a second spelling of the `.agents/skills` tail that `MODEL_SKILL_ROOT` already carries, with nothing to keep the two in step. Resolving `MODEL_SKILL_ROOT` through the new resolver produces the same root in both the usable-home and fallback cases, so the join helper and the duplicate suffix are gone and the skills location is written once. `resolveSandboxSeedFilePath` had become a wrapper that narrowed the resolver to skill paths only. Seed files come from exactly two roots — `WORKSPACE_ROOT` and `MODEL_SKILL_ROOT` — so the narrowing could not change any real input, and the single call site now calls the resolver directly. `MODEL_SKILL_ROOT` is derived from `MODEL_HOME_ROOT` so `$HOME` also appears once. Signed-off-by: Chad Hietala --- .changeset/skill-path-single-resolver.md | 5 ++++ .../sandbox/bindings/local-backend-utils.ts | 4 +-- packages/eve/src/shared/skill-paths.test.ts | 3 +- packages/eve/src/shared/skill-paths.ts | 28 ++++++------------- 4 files changed, 16 insertions(+), 24 deletions(-) create mode 100644 .changeset/skill-path-single-resolver.md diff --git a/.changeset/skill-path-single-resolver.md b/.changeset/skill-path-single-resolver.md new file mode 100644 index 000000000..871feef7f --- /dev/null +++ b/.changeset/skill-path-single-resolver.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +Resolve sandbox skill roots and seed-file paths through the same `$HOME` resolver the file tools use, so the skills location is spelled once instead of twice. diff --git a/packages/eve/src/execution/sandbox/bindings/local-backend-utils.ts b/packages/eve/src/execution/sandbox/bindings/local-backend-utils.ts index bf436bd3b..340ba0591 100644 --- a/packages/eve/src/execution/sandbox/bindings/local-backend-utils.ts +++ b/packages/eve/src/execution/sandbox/bindings/local-backend-utils.ts @@ -4,7 +4,7 @@ import { dirname, join } from "node:path"; import { bufferToStream, streamToBuffer } from "#execution/sandbox/stream-utils.js"; import { WORKSPACE_ROOT } from "#runtime/workspace/types.js"; -import { resolveSandboxSeedFilePath } from "#shared/skill-paths.js"; +import { resolveSandboxModelPath } from "#shared/skill-paths.js"; import type { SandboxSeedFile } from "#shared/sandbox-backend.js"; import type { InternalSandboxSession, @@ -116,7 +116,7 @@ export async function writeSandboxSeedFiles( seedFiles: ReadonlyArray, ): Promise { for (const file of seedFiles) { - const path = await resolveSandboxSeedFilePath({ + const path = await resolveSandboxModelPath({ path: file.path, sandbox: session, }); diff --git a/packages/eve/src/shared/skill-paths.test.ts b/packages/eve/src/shared/skill-paths.test.ts index c4a60ece6..3ba456cf7 100644 --- a/packages/eve/src/shared/skill-paths.test.ts +++ b/packages/eve/src/shared/skill-paths.test.ts @@ -7,7 +7,6 @@ import { formatFallbackSkillPath, formatSkillModelPath, resolveSandboxModelPath, - resolveSandboxSeedFilePath, resolveSandboxSkillReadPaths, resolveSandboxSkillRoot, } from "#shared/skill-paths.js"; @@ -126,7 +125,7 @@ describe("skill path helpers", () => { }); await expect( - resolveSandboxSeedFilePath({ + resolveSandboxModelPath({ path: `${MODEL_SKILL_ROOT}/research/references/catalog.md`, sandbox: sandbox.session, }), diff --git a/packages/eve/src/shared/skill-paths.ts b/packages/eve/src/shared/skill-paths.ts index 04faddd35..f4486e5b9 100644 --- a/packages/eve/src/shared/skill-paths.ts +++ b/packages/eve/src/shared/skill-paths.ts @@ -1,10 +1,10 @@ import type { SandboxSession } from "#shared/sandbox-session.js"; -export const MODEL_SKILL_ROOT = "$HOME/.agents/skills"; +const MODEL_HOME_ROOT = "$HOME"; + +export const MODEL_SKILL_ROOT = `${MODEL_HOME_ROOT}/.agents/skills`; export const FALLBACK_SKILL_ROOT = "/workspace/skills"; -const MODEL_HOME_ROOT = "$HOME"; -const HOME_SKILL_SUFFIX = ".agents/skills"; const HOME_PROBE_COMMAND = `printf '%s\\n' "$HOME"`; const sandboxHomeCache = new WeakMap>(); @@ -30,11 +30,14 @@ export function formatFallbackSkillPath(input: { }); } +/** + * Resolves where skills live in the sandbox: under the probed home when it has + * one, and under {@link FALLBACK_SKILL_ROOT} when it does not. + */ export async function resolveSandboxSkillRoot(input: { readonly sandbox: SandboxSession; }): Promise { - const home = await resolveSandboxHome(input.sandbox); - return home === null ? FALLBACK_SKILL_ROOT : joinHomeSkillRoot(home); + return await resolveSandboxModelPath({ path: MODEL_SKILL_ROOT, sandbox: input.sandbox }); } /** @@ -90,17 +93,6 @@ export async function resolveSandboxSkillWritePath(input: { }); } -export async function resolveSandboxSeedFilePath(input: { - readonly path: string; - readonly sandbox: SandboxSession; -}): Promise { - if (!isModelSkillPath(input.path)) { - return input.path; - } - - return await resolveSandboxModelPath(input); -} - function formatSkillPath(input: { readonly name: string; readonly relativePath: string; @@ -156,10 +148,6 @@ function isUsableSandboxHome(path: string): boolean { ); } -function joinHomeSkillRoot(home: string): string { - return `${home === "/" ? "" : home}/${HOME_SKILL_SUFFIX}`; -} - function normalizeSandboxHome(home: string): string { return home === "/" ? home : home.replace(/\/+$/, ""); }