import * as NodeAssert from "node:assert/strict"; import * as NodeServices from "@effect/platform-node/NodeServices";import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2";import { it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Fiber from "effect/Fiber";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Path from "effect/Path";import * as Queue from "effect/Queue";import { HostProcessEnvironment, HostProcessExecutablePath, HostProcessPlatform,} from "@t3tools/shared/hostProcess"; import { OpenCodeRuntime, OpenCodeRuntimeLive } from "./opencodeRuntime.ts"; const testLayer = OpenCodeRuntimeLive.pipe(Layer.provideMerge(NodeServices.layer)); it.layer(testLayer)("OpenCodeRuntime inventory", (it) => { it.effect("aborts pending SDK requests when inventory loading is interrupted", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime; const started = yield* Queue.make<void>(); const aborted = yield* Queue.make<string>(); const client = createOpencodeClient({ baseUrl: "http://opencode.test", fetch: Object.assign( (input: string | Request | URL) => { const request = input instanceof Request ? input : new Request(input.toString()); return new Promise<Response>((_resolve, reject) => { request.signal.addEventListener( "abort", () => { Queue.offerUnsafe(aborted, new URL(request.url).pathname); reject(request.signal.reason); }, { once: true }, ); Queue.offerUnsafe(started, undefined); }); }, { preconnect: () => undefined }, ), }); const inventoryFiber = yield* runtime.loadOpenCodeInventory(client).pipe(Effect.forkChild); yield* Queue.takeN(started, 3); yield* Fiber.interrupt(inventoryFiber); NodeAssert.deepEqual((yield* Queue.takeAll(aborted)).toSorted(), [ "/agent", "/provider", "/skill", ]); }), ); it.effect("keeps provider inventory when agent discovery fails", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime; const client = { provider: { list: () => Promise.resolve({ data: { connected: ["openai"], all: [], default: {}, }, }), }, app: { agents: () => Promise.reject(new Error("agents endpoint unavailable")), skills: () => Promise.resolve({ data: [] }), }, } as unknown as OpencodeClient; const inventory = yield* runtime.loadOpenCodeInventory(client); NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]); NodeAssert.deepEqual(inventory.agents, []); NodeAssert.deepEqual(inventory.skills, []); }), ); it.effect("keeps provider inventory when skill discovery fails", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime; const client = { provider: { list: () => Promise.resolve({ data: { connected: ["openai"], all: [], default: {}, }, }), }, app: { agents: () => Promise.resolve({ data: [] }), skills: () => Promise.reject(new Error("skills endpoint unavailable")), }, } as unknown as OpencodeClient; const inventory = yield* runtime.loadOpenCodeInventory(client); NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]); NodeAssert.deepEqual(inventory.agents, []); NodeAssert.deepEqual(inventory.skills, []); }), ); it.effect("keeps only SDK skill metadata in inventory", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime; const client = { provider: { list: () => Promise.resolve({ data: { connected: ["openai"], all: [], default: {}, }, }), }, app: { agents: () => Promise.resolve({ data: [] }), skills: () => Promise.resolve({ data: [ { name: "review", description: "Review code changes", location: "/skills/review/SKILL.md", content: "unused skill content", }, ], }), }, } as unknown as OpencodeClient; const inventory = yield* runtime.loadOpenCodeInventory(client); NodeAssert.deepEqual(inventory.skills, [ { name: "review", description: "Review code changes", location: "/skills/review/SKILL.md", }, ]); }), ); it.effect("drops oversized CLI skill output without losing the model inventory", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const hostEnvironment = yield* HostProcessEnvironment; const executablePath = yield* HostProcessExecutablePath; const hostPlatform = yield* HostProcessPlatform; const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" }); const isWindows = hostPlatform === "win32"; const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode"); const scriptPath = path.join(tempDir, "opencode.mjs"); const oversizedContentBytes = 8 * 1024 * 1024 + 1; yield* fs.writeFileString( scriptPath, [ 'if (process.argv[2] === "models") {', ' process.stdout.write(`openai/gpt-test\\n{"id":"gpt-test","providerID":"openai","name":"GPT Test"}\\n`);', '} else if (process.argv[2] === "debug") {', ` const content = "x".repeat(${oversizedContentBytes});`, ' process.stdout.write(`[{"name":"oversized","content":"${content}"}]`);', "}", "", ].join("\n"), ); yield* fs.writeFileString( binaryPath, [ ...(isWindows ? ["@echo off"] : ["#!/bin/sh"]), isWindows ? '"%T3_TEST_NODE_BINARY%" "%T3_TEST_OPENCODE_SCRIPT%" %*' : 'exec "$T3_TEST_NODE_BINARY" "$T3_TEST_OPENCODE_SCRIPT" "$@"', "", ].join("\n"), ); if (!isWindows) { yield* fs.chmod(binaryPath, 0o755); } const runtime = yield* OpenCodeRuntime; const inventory = yield* runtime.loadInventoryFromCli({ binaryPath, cwd: tempDir, environment: { ...hostEnvironment, T3_TEST_NODE_BINARY: executablePath, T3_TEST_OPENCODE_SCRIPT: scriptPath, }, }); NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]); NodeAssert.equal(inventory.skills.length, 0); }), ); it.effect("caps and drains command stdout and stderr when requested", () => Effect.gen(function* () { const runtime = yield* OpenCodeRuntime; const executablePath = yield* HostProcessExecutablePath; const outputBytes = 2 * 1024 * 1024; const result = yield* runtime.runOpenCodeCommand({ binaryPath: executablePath, args: [ "-e", `process.stdout.write("o".repeat(${outputBytes})); process.stderr.write("e".repeat(${outputBytes}));`, ], maxOutputBytes: 64, }); NodeAssert.equal(result.stdout, "o".repeat(64)); NodeAssert.equal(result.stderr, "e".repeat(64)); NodeAssert.equal(result.code, 0); }), );});
import * as NodeAssert from "node:assert/strict";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2";
import { it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as Path from "effect/Path";
import * as Queue from "effect/Queue";
import {
HostProcessEnvironment,
HostProcessExecutablePath,
HostProcessPlatform,
} from "@t3tools/shared/hostProcess";
import { OpenCodeRuntime, OpenCodeRuntimeLive } from "./opencodeRuntime.ts";
const testLayer = OpenCodeRuntimeLive.pipe(Layer.provideMerge(NodeServices.layer));
it.layer(testLayer)("OpenCodeRuntime inventory", (it) => {
it.effect("aborts pending SDK requests when inventory loading is interrupted", () =>
Effect.gen(function* () {
const runtime = yield* OpenCodeRuntime;
const started = yield* Queue.make<void>();
const aborted = yield* Queue.make<string>();
const client = createOpencodeClient({
baseUrl: "http://opencode.test",
fetch: Object.assign(
(input: string | Request | URL) => {
const request = input instanceof Request ? input : new Request(input.toString());
return new Promise<Response>((_resolve, reject) => {
request.signal.addEventListener(
"abort",
() => {
Queue.offerUnsafe(aborted, new URL(request.url).pathname);
reject(request.signal.reason);
},
{ once: true },
);
Queue.offerUnsafe(started, undefined);
});
},
{ preconnect: () => undefined },
),
});
const inventoryFiber = yield* runtime.loadOpenCodeInventory(client).pipe(Effect.forkChild);
yield* Queue.takeN(started, 3);
yield* Fiber.interrupt(inventoryFiber);
NodeAssert.deepEqual((yield* Queue.takeAll(aborted)).toSorted(), [
"/agent",
"/provider",
"/skill",
]);
}),
);
it.effect("keeps provider inventory when agent discovery fails", () =>
Effect.gen(function* () {
const runtime = yield* OpenCodeRuntime;
const client = {
provider: {
list: () =>
Promise.resolve({
data: {
connected: ["openai"],
all: [],
default: {},
},
}),
},
app: {
agents: () => Promise.reject(new Error("agents endpoint unavailable")),
skills: () => Promise.resolve({ data: [] }),
},
} as unknown as OpencodeClient;
const inventory = yield* runtime.loadOpenCodeInventory(client);
NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]);
NodeAssert.deepEqual(inventory.agents, []);
NodeAssert.deepEqual(inventory.skills, []);
}),
);
it.effect("keeps provider inventory when skill discovery fails", () =>
Effect.gen(function* () {
const runtime = yield* OpenCodeRuntime;
const client = {
provider: {
list: () =>
Promise.resolve({
data: {
connected: ["openai"],
all: [],
default: {},
},
}),
},
app: {
agents: () => Promise.resolve({ data: [] }),
skills: () => Promise.reject(new Error("skills endpoint unavailable")),
},
} as unknown as OpencodeClient;
const inventory = yield* runtime.loadOpenCodeInventory(client);
NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]);
NodeAssert.deepEqual(inventory.agents, []);
NodeAssert.deepEqual(inventory.skills, []);
}),
);
it.effect("keeps only SDK skill metadata in inventory", () =>
Effect.gen(function* () {
const runtime = yield* OpenCodeRuntime;
const client = {
provider: {
list: () =>
Promise.resolve({
data: {
connected: ["openai"],
all: [],
default: {},
},
}),
},
app: {
agents: () => Promise.resolve({ data: [] }),
skills: () =>
Promise.resolve({
data: [
{
name: "review",
description: "Review code changes",
location: "/skills/review/SKILL.md",
content: "unused skill content",
},
],
}),
},
} as unknown as OpencodeClient;
const inventory = yield* runtime.loadOpenCodeInventory(client);
NodeAssert.deepEqual(inventory.skills, [
{
name: "review",
description: "Review code changes",
location: "/skills/review/SKILL.md",
},
]);
}),
);
it.effect("drops oversized CLI skill output without losing the model inventory", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const hostEnvironment = yield* HostProcessEnvironment;
const executablePath = yield* HostProcessExecutablePath;
const hostPlatform = yield* HostProcessPlatform;
const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-opencode-inventory-" });
const isWindows = hostPlatform === "win32";
const binaryPath = path.join(tempDir, isWindows ? "opencode.cmd" : "opencode");
const scriptPath = path.join(tempDir, "opencode.mjs");
const oversizedContentBytes = 8 * 1024 * 1024 + 1;
yield* fs.writeFileString(
scriptPath,
[
'if (process.argv[2] === "models") {',
' process.stdout.write(`openai/gpt-test\\n{"id":"gpt-test","providerID":"openai","name":"GPT Test"}\\n`);',
'} else if (process.argv[2] === "debug") {',
` const content = "x".repeat(${oversizedContentBytes});`,
' process.stdout.write(`[{"name":"oversized","content":"${content}"}]`);',
"}",
"",
].join("\n"),
);
yield* fs.writeFileString(
binaryPath,
[
...(isWindows ? ["@echo off"] : ["#!/bin/sh"]),
isWindows
? '"%T3_TEST_NODE_BINARY%" "%T3_TEST_OPENCODE_SCRIPT%" %*'
: 'exec "$T3_TEST_NODE_BINARY" "$T3_TEST_OPENCODE_SCRIPT" "$@"',
"",
].join("\n"),
);
if (!isWindows) {
yield* fs.chmod(binaryPath, 0o755);
}
const runtime = yield* OpenCodeRuntime;
const inventory = yield* runtime.loadInventoryFromCli({
binaryPath,
cwd: tempDir,
environment: {
...hostEnvironment,
T3_TEST_NODE_BINARY: executablePath,
T3_TEST_OPENCODE_SCRIPT: scriptPath,
},
});
NodeAssert.deepEqual(inventory.providerList.connected, ["openai"]);
NodeAssert.equal(inventory.skills.length, 0);
}),
);
it.effect("caps and drains command stdout and stderr when requested", () =>
Effect.gen(function* () {
const runtime = yield* OpenCodeRuntime;
const executablePath = yield* HostProcessExecutablePath;
const outputBytes = 2 * 1024 * 1024;
const result = yield* runtime.runOpenCodeCommand({
binaryPath: executablePath,
args: [
"-e",
`process.stdout.write("o".repeat(${outputBytes})); process.stderr.write("e".repeat(${outputBytes}));`,
],
maxOutputBytes: 64,
});
NodeAssert.equal(result.stdout, "o".repeat(64));
NodeAssert.equal(result.stderr, "e".repeat(64));
NodeAssert.equal(result.code, 0);
}),
);
});