import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import { once } from "node:events"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import readline from "node:readline"; import test from "node:test"; import { fileURLToPath } from "node:url"; const serverPath = fileURLToPath(new URL("./server.mjs", import.meta.url)); const preview = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=", "base64", ); async function writeTemplate(directory, name) { await fs.mkdir(path.join(directory, "agents"), { recursive: true }); await fs.mkdir(path.join(directory, "assets")); await fs.writeFile( path.join(directory, "SKILL.md"), `---\nname: ${name}\ndescription: Create a document using the smoke template.\n---\n`, ); await fs.writeFile( path.join(directory, "artifact-template.json"), JSON.stringify({ schemaVersion: 1, kind: "document", reference: "assets/reference.docx", preview: "assets/preview.png", }), ); await fs.writeFile( path.join(directory, "agents/openai.yaml"), 'interface:\n display_name: "Smoke template"\n icon_large: "assets/preview.png"\n', ); await fs.writeFile(path.join(directory, "assets/reference.docx"), "fixture"); await fs.writeFile(path.join(directory, "assets/preview.png"), preview); } for (const explicitCodexHome of [true, false]) { test( `work templates use ${explicitCodexHome ? "CODEX_HOME" : "the user's home"}`, { timeout: 10_000 }, async (t) => { const temporary = await fs.mkdtemp(path.join(os.tmpdir(), "picker-home-")); t.after(() => fs.rm(temporary, { recursive: true, force: true })); const home = path.join(temporary, "home"); const codexHome = explicitCodexHome ? path.join(temporary, "custom-codex") : path.join(home, ".codex"); await writeTemplate( path.join(codexHome, "skills/remote-skills/skill-personal"), "artifact-template-personal", ); const plugin = path.join(codexHome, "plugins/cache/local/templates/1"); await fs.mkdir(path.join(plugin, ".codex-plugin"), { recursive: true }); await fs.writeFile( path.join(plugin, ".codex-plugin/plugin.json"), JSON.stringify({ name: "templates" }), ); await writeTemplate( path.join(plugin, "skills/artifact-template-team"), "artifact-template-team", ); const env = { ...process.env, HOME: home }; delete env.CODEX_HOME; delete env.CODEX_ARTIFACT_TEMPLATE_SKILLS; if (explicitCodexHome) env.CODEX_HOME = codexHome; const server = spawn(process.execPath, [serverPath, "--work"], { env }); t.after(() => server.kill()); const lines = readline.createInterface({ input: server.stdout }); t.after(() => lines.close()); const response = once(lines, "line"); server.stdin.write( JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "list_artifact_templates", arguments: { artifactKind: "document", request: "A report" }, }, }) + "\n", ); const [line] = await response; const message = JSON.parse(line); assert.equal(message.error, undefined); const result = JSON.parse(message.result.content[0].text); assert.deepEqual( result.templates.map((template) => template.skillName).sort(), ["artifact-template-personal", "templates:artifact-template-team"], ); }, ); }