diff --git a/docs-internal/registry-parity-worklist.md b/docs-internal/registry-parity-worklist.md index 237307251f..f588f47acb 100644 --- a/docs-internal/registry-parity-worklist.md +++ b/docs-internal/registry-parity-worklist.md @@ -714,6 +714,16 @@ real e2e tests that prove Linux-parity behavior — not smoke tests. `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`. + - **opencode — DONE.** Added default core Vitest coverage for real + `createSession('opencode')` initialization through the projected + `@agentos-software/opencode` agent package. The focused suite proves the + sidecar resolves the OpenCode ACP package, initializes the adapter, exposes + agent metadata/capabilities/modes, and registers the session through the + Agent OS session API. Proof: + `2026-07-08T15-36-00-0700-item12-opencode-cc-cache-restored-focused.log`; + `2026-07-08T15-36-00-0700-item12-opencode-sidecar-build-focused.log`; + `2026-07-08T15-37-00-0700-item12-opencode-real-session-final.log`. + Rev: `xtnuomsw`. - **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/opencode-real-session.test.ts b/packages/core/tests/opencode-real-session.test.ts new file mode 100644 index 0000000000..c47f4b2cd6 --- /dev/null +++ b/packages/core/tests/opencode-real-session.test.ts @@ -0,0 +1,76 @@ +import { resolve } from "node:path"; +import opencode from "@agentos-software/opencode"; +import { describe, expect, test } from "vitest"; +import type { AgentCapabilities, AgentInfo } from "../src/agent-os.js"; +import { AgentOs } from "../src/agent-os.js"; +import { + DEFAULT_TEXT_FIXTURE, + startLlmock, + stopLlmock, +} from "./helpers/llmock-helper.js"; +import { moduleAccessMounts } from "./helpers/node-modules-mount.js"; +import { + createVmOpenCodeHome, + createVmWorkspace, +} from "./helpers/opencode-helper.js"; + +const MODULE_ACCESS_CWD = resolve(import.meta.dirname, ".."); + +async function createOpenCodeVm(mockUrl: string): Promise { + return AgentOs.create({ + loopbackExemptPorts: [Number(new URL(mockUrl).port)], + mounts: moduleAccessMounts(MODULE_ACCESS_CWD), + software: [opencode], + }); +} + +describe("real createSession('opencode')", () => { + test("initializes the projected OpenCode ACP package inside the VM", async () => { + const { mock, url } = await startLlmock([DEFAULT_TEXT_FIXTURE]); + const vm = await createOpenCodeVm(url); + + let sessionId: string | undefined; + try { + const homeDir = await createVmOpenCodeHome(vm, url); + const workspaceDir = await createVmWorkspace(vm); + sessionId = ( + await vm.createSession("opencode", { + cwd: workspaceDir, + env: { + HOME: homeDir, + ANTHROPIC_API_KEY: "mock-key", + }, + }) + ).sessionId; + + const agentInfo = vm.getSessionAgentInfo(sessionId) as AgentInfo; + expect(agentInfo.name).toBe("OpenCode"); + expect(agentInfo.version).toBeTruthy(); + + const capabilities = vm.getSessionCapabilities( + sessionId, + ) as AgentCapabilities; + expect(capabilities.promptCapabilities).toMatchObject({ + embeddedContext: true, + image: true, + }); + + const modes = vm.getSessionModes(sessionId); + expect(modes?.currentModeId).toBe("build"); + expect(modes?.availableModes.map((mode) => mode.id)).toEqual( + expect.arrayContaining(["build", "plan"]), + ); + + expect(vm.listSessions()).toContainEqual({ + sessionId, + agentType: "opencode", + }); + } finally { + if (sessionId) { + vm.closeSession(sessionId); + } + await vm.dispose(); + await stopLlmock(mock); + } + }, 120_000); +});