diff --git a/src/lib/actions/maintenance.ts b/src/lib/actions/maintenance.ts index a3b1eaba171..e10a589c018 100644 --- a/src/lib/actions/maintenance.ts +++ b/src/lib/actions/maintenance.ts @@ -8,7 +8,7 @@ import { type GarbageCollectImagesOptions, normalizeGarbageCollectImagesOptions, } from "../domain/lifecycle/options"; -import { dockerListImagesFormat, dockerRmi } from "../docker"; +import { dockerListImagesFormat, dockerRmi } from "../adapters/docker"; import { findOrphanedSandboxImages, parseSandboxImageRows } from "../domain/maintenance/images"; import { captureOpenshell } from "../adapters/openshell/runtime"; import * as registry from "../state/registry"; diff --git a/src/lib/actions/sandbox/destroy.ts b/src/lib/actions/sandbox/destroy.ts index d7ce7fc0e1b..79e27da0537 100644 --- a/src/lib/actions/sandbox/destroy.ts +++ b/src/lib/actions/sandbox/destroy.ts @@ -48,7 +48,7 @@ function cleanupGatewayAfterLastSandbox(): void { const { runOpenshell } = require("../../adapters/openshell/runtime") as { runOpenshell: (args: string[], opts?: Record) => { status: number | null }; }; - const { dockerRemoveVolumesByPrefix } = require("../../docker") as { + const { dockerRemoveVolumesByPrefix } = require("../../adapters/docker") as { dockerRemoveVolumesByPrefix: (prefix: string, opts?: { ignoreError?: boolean }) => void; }; @@ -123,7 +123,7 @@ export function removeSandboxImage( ): void { const getSandbox = deps.getSandbox ?? registry.getSandbox; const removeImage = - deps.dockerRmi ?? (require("../../docker") as { dockerRmi: DockerRmi }).dockerRmi; + deps.dockerRmi ?? (require("../../adapters/docker") as { dockerRmi: DockerRmi }).dockerRmi; const sb = getSandbox(sandboxName); if (!sb?.imageTag) return; const result = removeImage(sb.imageTag, { ignoreError: true }); diff --git a/src/lib/actions/sandbox/snapshot.ts b/src/lib/actions/sandbox/snapshot.ts index 42c85bf81f0..024f36c54a9 100644 --- a/src/lib/actions/sandbox/snapshot.ts +++ b/src/lib/actions/sandbox/snapshot.ts @@ -7,7 +7,7 @@ import fs from "node:fs"; import path from "node:path"; import { CLI_NAME } from "../../branding"; -import { dockerCapture, dockerInspect } from "../../docker"; +import { dockerCapture, dockerInspect } from "../../adapters/docker"; import { parseLiveSandboxNames } from "../../runtime-recovery"; import { ROOT, run, shellQuote, validateName } from "../../runner"; import { captureOpenshell, getOpenshellBinary } from "../../adapters/openshell/runtime"; diff --git a/src/lib/docker/container.ts b/src/lib/adapters/docker/container.ts similarity index 100% rename from src/lib/docker/container.ts rename to src/lib/adapters/docker/container.ts diff --git a/src/lib/docker/exec.ts b/src/lib/adapters/docker/exec.ts similarity index 100% rename from src/lib/docker/exec.ts rename to src/lib/adapters/docker/exec.ts diff --git a/src/lib/docker/image.ts b/src/lib/adapters/docker/image.ts similarity index 95% rename from src/lib/docker/image.ts rename to src/lib/adapters/docker/image.ts index 1de29f2f847..5c932b64f33 100644 --- a/src/lib/docker/image.ts +++ b/src/lib/adapters/docker/image.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { ROOT } from "../runner"; +import { ROOT } from "../../runner"; import { dockerCapture, dockerRun, type DockerCaptureOptions, type DockerRunOptions } from "./run"; export function dockerBuild( diff --git a/src/lib/docker/index.test.ts b/src/lib/adapters/docker/index.test.ts similarity index 99% rename from src/lib/docker/index.test.ts rename to src/lib/adapters/docker/index.test.ts index 0011a226c71..0321b6ba771 100644 --- a/src/lib/docker/index.test.ts +++ b/src/lib/adapters/docker/index.test.ts @@ -6,7 +6,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const runMock = vi.fn(); const runCaptureMock = vi.fn(); -vi.mock("../runner", () => ({ +vi.mock("../../runner", () => ({ ROOT: "/repo/root", run: (...args: unknown[]) => runMock(...args), runCapture: (...args: unknown[]) => runCaptureMock(...args), diff --git a/src/lib/docker/index.ts b/src/lib/adapters/docker/index.ts similarity index 100% rename from src/lib/docker/index.ts rename to src/lib/adapters/docker/index.ts diff --git a/src/lib/docker/info.ts b/src/lib/adapters/docker/info.ts similarity index 100% rename from src/lib/docker/info.ts rename to src/lib/adapters/docker/info.ts diff --git a/src/lib/docker/inspect.ts b/src/lib/adapters/docker/inspect.ts similarity index 100% rename from src/lib/docker/inspect.ts rename to src/lib/adapters/docker/inspect.ts diff --git a/src/lib/docker/login.ts b/src/lib/adapters/docker/login.ts similarity index 100% rename from src/lib/docker/login.ts rename to src/lib/adapters/docker/login.ts diff --git a/src/lib/docker/pull.ts b/src/lib/adapters/docker/pull.ts similarity index 100% rename from src/lib/docker/pull.ts rename to src/lib/adapters/docker/pull.ts diff --git a/src/lib/docker/run.ts b/src/lib/adapters/docker/run.ts similarity index 92% rename from src/lib/docker/run.ts rename to src/lib/adapters/docker/run.ts index 58fb786a102..6e54d82dfbf 100644 --- a/src/lib/docker/run.ts +++ b/src/lib/adapters/docker/run.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { run, runCapture } from "../runner"; +import { run, runCapture } from "../../runner"; export type DockerRunOptions = Parameters[1]; export type DockerCaptureOptions = Parameters[1]; diff --git a/src/lib/docker/volume.ts b/src/lib/adapters/docker/volume.ts similarity index 100% rename from src/lib/docker/volume.ts rename to src/lib/adapters/docker/volume.ts diff --git a/src/lib/agent-base-image.test.ts b/src/lib/agent-base-image.test.ts index 83ff0508489..08c4d0b740a 100644 --- a/src/lib/agent-base-image.test.ts +++ b/src/lib/agent-base-image.test.ts @@ -5,8 +5,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { AgentDefinition } from "./agent-defs"; type AgentOnboardModule = typeof import("../../dist/lib/agent-onboard"); -type DockerImageModule = typeof import("../../dist/lib/docker/image"); -type DockerInspectModule = typeof import("../../dist/lib/docker/inspect"); +type DockerImageModule = typeof import("../../dist/lib/adapters/docker/image"); +type DockerInspectModule = typeof import("../../dist/lib/adapters/docker/inspect"); /** * Build a minimal Hermes agent manifest for base-image provisioning tests. @@ -56,9 +56,9 @@ function withMockedDocker( }) => T, ): T { // eslint-disable-next-line @typescript-eslint/no-require-imports - const dockerImageModule = require("../../dist/lib/docker/image") as DockerImageModule; + const dockerImageModule = require("../../dist/lib/adapters/docker/image") as DockerImageModule; // eslint-disable-next-line @typescript-eslint/no-require-imports - const dockerInspectModule = require("../../dist/lib/docker/inspect") as DockerInspectModule; + const dockerInspectModule = require("../../dist/lib/adapters/docker/inspect") as DockerInspectModule; // eslint-disable-next-line @typescript-eslint/no-require-imports const runnerModule = require("../../dist/lib/runner") as { ROOT: string }; const originalDockerBuild = dockerImageModule.dockerBuild; diff --git a/src/lib/agent-onboard.ts b/src/lib/agent-onboard.ts index e14bc339326..45928a3014c 100644 --- a/src/lib/agent-onboard.ts +++ b/src/lib/agent-onboard.ts @@ -9,9 +9,9 @@ import fs from "fs"; import os from "os"; import path from "path"; +import { dockerBuild, dockerImageInspect } from "./adapters/docker"; import { type AgentDefinition, loadAgent, resolveAgentName } from "./agent-defs"; import { getAgentBranding } from "./branding"; -import { dockerBuild, dockerImageInspect } from "./docker"; import { getProviderSelectionConfig } from "./inference-config"; import type { JsonObject as LooseObject, JsonValue as LooseValue } from "./json-types"; import * as onboardSession from "./onboard-session"; diff --git a/src/lib/debug.ts b/src/lib/debug.ts index 4a5c95aea2a..aabdc7dbf8f 100644 --- a/src/lib/debug.ts +++ b/src/lib/debug.ts @@ -3,7 +3,7 @@ import { execFileSync, spawnSync } from "node:child_process"; import { existsSync, mkdtempSync, rmSync, unlinkSync, writeFileSync } from "node:fs"; -import { dockerExecFileSync } from "./docker/exec"; +import { dockerExecFileSync } from "./adapters/docker/exec"; import { platform, tmpdir } from "node:os"; import { basename, dirname, join } from "node:path"; diff --git a/src/lib/nim.ts b/src/lib/nim.ts index 1fda93a4c49..a3e4491e807 100644 --- a/src/lib/nim.ts +++ b/src/lib/nim.ts @@ -14,7 +14,7 @@ const { dockerRm, dockerRunDetached, dockerStop, -} = require("./docker"); +} = require("./adapters/docker"); const { sleepSeconds } = require("./wait"); const nimImages = require("../../bin/lib/nim-images.json"); diff --git a/src/lib/onboard-vllm.ts b/src/lib/onboard-vllm.ts index 03d75ac1788..7fe47989c2f 100644 --- a/src/lib/onboard-vllm.ts +++ b/src/lib/onboard-vllm.ts @@ -6,7 +6,7 @@ // right profile per platform and running the install. const { runCapture, runShell } = require("./runner"); -const { dockerCapture, dockerSpawn } = require("./docker"); +const { dockerCapture, dockerSpawn } = require("./adapters/docker"); const { VLLM_PORT } = require("./ports"); const { getGpuIndicesByName } = require("./nim"); diff --git a/src/lib/onboard.ts b/src/lib/onboard.ts index 0642c2f677a..beb103086d0 100644 --- a/src/lib/onboard.ts +++ b/src/lib/onboard.ts @@ -55,7 +55,7 @@ const { ROOT, SCRIPTS, redact, run, runShell, runCapture, runFile, shellQuote, v runner; const nameValidation: typeof import("./name-validation") = require("./name-validation"); const { NAME_ALLOWED_FORMAT, getNameValidationGuidance } = nameValidation; -const docker: typeof import("./docker") = require("./docker"); +const docker: typeof import("./adapters/docker") = require("./adapters/docker"); const { dockerContainerInspectFormat, dockerExecArgv, diff --git a/src/lib/sandbox-config.ts b/src/lib/sandbox-config.ts index 5762a8428d5..6270c44a9d9 100644 --- a/src/lib/sandbox-config.ts +++ b/src/lib/sandbox-config.ts @@ -19,7 +19,7 @@ const path = require("path"); const { promises: dnsPromises } = require("node:dns"); const { isIP } = require("node:net"); const { validateName } = require("./runner"); -const { dockerExecFileSync } = require("./docker/exec"); +const { dockerExecFileSync } = require("./adapters/docker/exec"); const credentialFilter: typeof import("./credential-filter") = require("./credential-filter"); const { stripCredentials, isConfigObject, isConfigValue, isCredentialField } = credentialFilter; const { appendAuditEntry } = require("./shields-audit"); diff --git a/src/lib/services.ts b/src/lib/services.ts index d32df737bbd..e6dd5088e10 100644 --- a/src/lib/services.ts +++ b/src/lib/services.ts @@ -16,7 +16,7 @@ import { import { join } from "node:path"; import { AGENT_PRODUCT_NAME, CLI_DISPLAY_NAME } from "./branding"; -import { dockerSpawnSync } from "./docker"; +import { dockerSpawnSync } from "./adapters/docker"; import { DASHBOARD_PORT } from "./ports"; import { resolveOpenshell } from "./adapters/openshell/resolve"; import { buildSubprocessEnv } from "./subprocess-env"; diff --git a/src/lib/shields.ts b/src/lib/shields.ts index d1d518a7d32..fb84e767e26 100644 --- a/src/lib/shields.ts +++ b/src/lib/shields.ts @@ -14,7 +14,7 @@ const fs = require("fs"); const path = require("path"); const { fork } = require("child_process"); const { run, runCapture, validateName, shellQuote } = require("./runner"); -const { dockerExecFileSync } = require("./docker/exec"); +const { dockerExecFileSync } = require("./adapters/docker/exec"); const { buildPolicyGetCommand, buildPolicySetCommand, diff --git a/src/nemoclaw.ts b/src/nemoclaw.ts index 3e4448a1edc..8a9d699ff5a 100644 --- a/src/nemoclaw.ts +++ b/src/nemoclaw.ts @@ -33,7 +33,7 @@ const { dockerInspect, dockerRemoveVolumesByPrefix, dockerRmi, -} = require("./lib/docker"); +} = require("./lib/adapters/docker"); const { resolveOpenshell } = require("./lib/adapters/openshell/resolve"); const { hydrateCredentialEnv, isNonInteractive } = require("./lib/onboard"); const registry = require("./lib/state/registry"); diff --git a/test/docker-abstraction-guard.test.ts b/test/docker-abstraction-guard.test.ts index 8673ab18cb3..0dea2d8b464 100644 --- a/test/docker-abstraction-guard.test.ts +++ b/test/docker-abstraction-guard.test.ts @@ -9,7 +9,7 @@ import { describe, expect, it } from "vitest"; const REPO_ROOT = path.join(import.meta.dirname, ".."); const TSX = path.join(REPO_ROOT, "node_modules", ".bin", "tsx"); const INVENTORY_SCRIPT = path.join(REPO_ROOT, "scripts", "list-command-helper-uses.ts"); -const DOCKER_ABSTRACTION_PREFIX = "src/lib/docker/"; +const DOCKER_ABSTRACTION_PREFIX = "src/lib/adapters/docker/"; type CommandUse = { filePath: string; @@ -36,7 +36,7 @@ function listCommandUses(): CommandUse[] { } describe("Docker command abstraction guard", () => { - it("keeps direct docker process launches inside src/lib/docker", () => { + it("keeps direct docker process launches inside src/lib/adapters/docker", () => { const directDockerCalls = listCommandUses().filter( (entry) => entry.kind === "call" && @@ -52,7 +52,7 @@ describe("Docker command abstraction guard", () => { ) .join("\n"); throw new Error( - `Direct docker process launches must use the src/lib/docker abstractions.\n` + + `Direct docker process launches must use the src/lib/adapters/docker abstractions.\n` + `Do not add calls like run(["docker", ...]), runCapture(["docker", ...]), ` + `spawnSync("docker", ...), or execFileSync("docker", ...) outside ${DOCKER_ABSTRACTION_PREFIX}.\n` + `Add or reuse a helper under ${DOCKER_ABSTRACTION_PREFIX} (for example dockerRun(), dockerCapture(), dockerPull(), dockerRmi(), dockerExecFileSync(), or dockerSpawnSync()) and call that instead.\n` + diff --git a/test/repro-2681-group-writable.test.ts b/test/repro-2681-group-writable.test.ts index 7230f1410f2..834caa4eeb0 100644 --- a/test/repro-2681-group-writable.test.ts +++ b/test/repro-2681-group-writable.test.ts @@ -42,7 +42,7 @@ function modeBits(filePath: string): number { function withMockedDockerExecFileSync(calls: string[][], run: () => T): T { // eslint-disable-next-line @typescript-eslint/no-require-imports - const dockerExecModule = require("../dist/lib/docker/exec.js") as { + const dockerExecModule = require("../dist/lib/adapters/docker/exec.js") as { dockerExecFileSync: (args: readonly string[]) => string; }; const originalDockerExecFileSync = dockerExecModule.dockerExecFileSync; @@ -173,7 +173,7 @@ const Module = require("node:module"); const originalLoad = Module._load; const calls = []; Module._load = function patchedLoad(request, parent, isMain) { - if (request === "./docker/exec") { + if (request === "./adapters/docker/exec") { return { dockerExecFileSync(args) { const separator = args.indexOf("--"); @@ -235,7 +235,7 @@ const Module = require("node:module"); const originalLoad = Module._load; const calls = []; Module._load = function patchedLoad(request, parent, isMain) { - if (request === "./docker/exec") { + if (request === "./adapters/docker/exec") { return { dockerExecFileSync(args) { const separator = args.indexOf("--");