diff --git a/docs-internal/registry-parity-worklist.md b/docs-internal/registry-parity-worklist.md index 221f905212..237307251f 100644 --- a/docs-internal/registry-parity-worklist.md +++ b/docs-internal/registry-parity-worklist.md @@ -701,6 +701,19 @@ real e2e tests that prove Linux-parity behavior — not smoke tests. `2026-07-08T15-00-00-0700-item12-pi-cli-sidecar-build-after-cc-restore-final.log`; `2026-07-08T15-01-00-0700-item12-pi-cli-focused-final-after-cc-restore.log`. Rev: `xqtkmsyn`. + - **claude — DONE.** Enabled the existing real `createSession('claude')` + session suite in default core Vitest coverage, projected the actual + `@agentos-software/claude-code` agent package, and replaced the missing + test-only `xu` binary dependency with a real PATH-backed `sh` command from + registry coreutils. The suite proves Claude ACP shell/tool flow, text-only + responses, nested Node `execSync`/`spawn`, session metadata/lifecycle, + modes, and raw ACP sends. The flat node_modules fixture cache now lives + outside root `node_modules` so VM mounts survive dependency refreshes. + Proof: + `2026-07-08T15-17-00-0700-item12-claude-cc-cache-restored-after-cache-move.log`; + `2026-07-08T15-17-00-0700-item12-claude-sidecar-build-after-cache-move.log`; + `2026-07-08T15-19-00-0700-item12-claude-session-after-cache-move.log`. + Rev: `rxmoulty`. - **Objective:** write real e2e tests proving each behaves like its Linux counterpart (jq processes real JSON, sed edits streams, tar round-trips archives, gzip round-trips, etc.); agents exercise the real ACP diff --git a/packages/core/tests/claude-session.test.ts b/packages/core/tests/claude-session.test.ts index f19f9111d4..f64a71235f 100644 --- a/packages/core/tests/claude-session.test.ts +++ b/packages/core/tests/claude-session.test.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; +import claude from "@agentos-software/claude-code"; import type { Fixture, LLMock, ToolCall } from "@copilotkit/llmock"; -import { moduleAccessMounts } from "./helpers/node-modules-mount.js"; import { afterAll, afterEach, @@ -17,22 +17,15 @@ import { startLlmock, stopLlmock, } from "./helpers/llmock-helper.js"; -import { - REGISTRY_SOFTWARE, - testOnlyCommandSoftware, -} from "./helpers/registry-commands.js"; - -// `xu` is a registry VM-test binary that ships in no package — project it via -// a synthesized test-only package (throws if the native build output lacks it). -const TEST_COMMAND_SOFTWARE = testOnlyCommandSoftware(["xu"]); +import { moduleAccessMounts } from "./helpers/node-modules-mount.js"; +import { REGISTRY_SOFTWARE } from "./helpers/registry-commands.js"; const MODULE_ACCESS_CWD = resolve(import.meta.dirname, ".."); -const XU_COMMAND = "xu hello-agent-os"; +const XU_COMMAND = "sh -lc 'printf xu-ok:hello-agent-os'"; const XU_OUTPUT = "xu-ok:hello-agent-os"; const NODE_EXECSYNC_CHILD_SCRIPT_PATH = "/tmp/nested-execsync-child.cjs"; const NODE_EXECSYNC_SCRIPT_PATH = "/tmp/nested-execsync.cjs"; const NODE_EXECSYNC_COMMAND = `node ${NODE_EXECSYNC_SCRIPT_PATH}`; -const NODE_EXECSYNC_OUTPUT = "child-ok"; const NODE_EXECSYNC_CHILD_SCRIPT = ` console.log("child-ok"); `.trimStart(); @@ -153,7 +146,7 @@ describe("full createSession('claude')", () => { vm = await AgentOs.create({ loopbackExemptPorts: [mockPort], mounts: moduleAccessMounts(MODULE_ACCESS_CWD), - software: [...REGISTRY_SOFTWARE, TEST_COMMAND_SOFTWARE], + software: [claude, ...REGISTRY_SOFTWARE], }); }); @@ -161,7 +154,7 @@ describe("full createSession('claude')", () => { await vm.dispose(); }); - test("createSession('claude') runs PATH-backed xu commands end-to-end", async () => { + test("createSession('claude') runs PATH-backed shell commands end-to-end", async () => { let sessionId: string | undefined; try { @@ -173,8 +166,13 @@ describe("full createSession('claude')", () => { }, }); sessionId = session.sessionId; - vm.onPermissionRequest(sessionId, (request) => { - void vm.respondPermission(sessionId!, request.permissionId, "once"); + const activeSessionId = sessionId; + vm.onPermissionRequest(activeSessionId, (request) => { + void vm.respondPermission( + activeSessionId, + request.permissionId, + "once", + ); }); const events: { method: string; params?: unknown }[] = []; @@ -228,7 +226,7 @@ describe("full createSession('claude')", () => { const promptVm = await AgentOs.create({ loopbackExemptPorts: [promptMockPort], mounts: moduleAccessMounts(MODULE_ACCESS_CWD), - software: [...REGISTRY_SOFTWARE, TEST_COMMAND_SOFTWARE], + software: [claude, ...REGISTRY_SOFTWARE], }); let sessionId: string | undefined; try { @@ -297,7 +295,7 @@ describe("full createSession('claude')", () => { const promptVm = await AgentOs.create({ loopbackExemptPorts: [promptMockPort], mounts: moduleAccessMounts(MODULE_ACCESS_CWD), - software: [...REGISTRY_SOFTWARE, TEST_COMMAND_SOFTWARE], + software: [claude, ...REGISTRY_SOFTWARE], }); let sessionId: string | undefined; try { @@ -309,9 +307,10 @@ describe("full createSession('claude')", () => { }, }); sessionId = session.sessionId; - promptVm.onPermissionRequest(sessionId, (request) => { + const activeSessionId = sessionId; + promptVm.onPermissionRequest(activeSessionId, (request) => { void promptVm.respondPermission( - sessionId!, + activeSessionId, request.permissionId, "once", ); @@ -374,7 +373,7 @@ describe("full createSession('claude')", () => { const promptVm = await AgentOs.create({ loopbackExemptPorts: [promptMockPort], mounts: moduleAccessMounts(MODULE_ACCESS_CWD), - software: [...REGISTRY_SOFTWARE, TEST_COMMAND_SOFTWARE], + software: [claude, ...REGISTRY_SOFTWARE], }); let sessionId: string | undefined; try { @@ -387,9 +386,10 @@ describe("full createSession('claude')", () => { }, }); sessionId = session.sessionId; - promptVm.onPermissionRequest(sessionId, (request) => { + const activeSessionId = sessionId; + promptVm.onPermissionRequest(activeSessionId, (request) => { void promptVm.respondPermission( - sessionId!, + activeSessionId, request.permissionId, "once", ); diff --git a/packages/core/tests/helpers/fixture-node-modules.ts b/packages/core/tests/helpers/fixture-node-modules.ts index 094914e966..f73ef24728 100644 --- a/packages/core/tests/helpers/fixture-node-modules.ts +++ b/packages/core/tests/helpers/fixture-node-modules.ts @@ -13,6 +13,7 @@ import { unlinkSync, writeFileSync, } from "node:fs"; +import { tmpdir } from "node:os"; import { dirname, join, resolve, sep } from "node:path"; /** @@ -129,12 +130,11 @@ export function ensureFlatNodeModules(cwd: string): string { const repoRoot = findRepoRoot(cwd); const safe = packageName.replace(/[^a-z0-9]+/gi, "_"); - const cacheRoot = join( - repoRoot, - "node_modules", - ".cache", - "agentos-flat-fixtures", - ); + const repoSafe = repoRoot.replace(/[^a-z0-9]+/gi, "_"); + const cacheBase = + process.env.AGENTOS_FLAT_FIXTURE_CACHE_ROOT ?? + join(tmpdir(), "agentos-flat-fixtures"); + const cacheRoot = join(cacheBase, repoSafe); mkdirSync(cacheRoot, { recursive: true }); const target = join(cacheRoot, safe); const readyMarker = join(target, ".ready"); diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index f79fb17ab8..c5c20f45fc 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -10,7 +10,6 @@ import { configDefaults, defineConfig } from "vitest/config"; const SLOW_E2E_FILES = [ "tests/wasm-commands.test.ts", // ~24m "tests/session-cleanup.test.ts", // ~12m - "tests/claude-session.test.ts", // ~7.5m "tests/execute.test.ts", "tests/filesystem.test.ts", "tests/native-sidecar-process.test.ts",