import { describe, expect, it } from "vitest"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { execute } from "@paperclipai/adapter-gemini-local/server"; async function writeFakeGeminiCommand(commandPath: string): Promise { const script = `#!/usr/bin/env node const fs = require("node:fs"); const capturePath = process.env.PAPERCLIP_TEST_CAPTURE_PATH; const payload = { argv: process.argv.slice(2), paperclipEnvKeys: Object.keys(process.env) .filter((key) => key.startsWith("PAPERCLIP_")) .sort(), }; if (capturePath) { fs.writeFileSync(capturePath, JSON.stringify(payload), "utf8"); } console.log(JSON.stringify({ type: "system", subtype: "init", session_id: "gemini-session-1", model: "gemini-2.5-pro", })); console.log(JSON.stringify({ type: "assistant", message: { content: [{ type: "output_text", text: "hello" }] }, })); console.log(JSON.stringify({ type: "result", subtype: "success", session_id: "gemini-session-1", result: "ok", })); `; await fs.writeFile(commandPath, script, "utf8"); await fs.chmod(commandPath, 0o755); } type CapturePayload = { argv: string[]; paperclipEnvKeys: string[]; }; describe("gemini execute", () => { it("passes prompt as final argument and injects paperclip env vars", async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-gemini-execute-")); const workspace = path.join(root, "workspace"); const commandPath = path.join(root, "gemini"); const capturePath = path.join(root, "capture.json"); await fs.mkdir(workspace, { recursive: true }); await writeFakeGeminiCommand(commandPath); const previousHome = process.env.HOME; process.env.HOME = root; let invocationPrompt = ""; try { const result = await execute({ runId: "run-1", agent: { id: "agent-1", companyId: "company-1", name: "Gemini Coder", adapterType: "gemini_local", adapterConfig: {}, }, runtime: { sessionId: null, sessionParams: null, sessionDisplayId: null, taskKey: null, }, config: { command: commandPath, cwd: workspace, model: "gemini-2.5-pro", yolo: true, env: { PAPERCLIP_TEST_CAPTURE_PATH: capturePath, }, promptTemplate: "Follow the paperclip heartbeat.", }, context: {}, authToken: "run-jwt-token", onLog: async () => {}, onMeta: async (meta) => { invocationPrompt = meta.prompt ?? ""; }, }); expect(result.exitCode).toBe(0); expect(result.errorMessage).toBeNull(); const capture = JSON.parse(await fs.readFile(capturePath, "utf8")) as CapturePayload; expect(capture.argv).toContain("--output-format"); expect(capture.argv).toContain("stream-json"); expect(capture.argv).toContain("--approval-mode"); expect(capture.argv).toContain("yolo"); expect(capture.argv.at(-1)).toContain("Follow the paperclip heartbeat."); expect(capture.argv.at(-1)).toContain("Paperclip runtime note:"); expect(capture.paperclipEnvKeys).toEqual( expect.arrayContaining([ "PAPERCLIP_AGENT_ID", "PAPERCLIP_API_KEY", "PAPERCLIP_API_URL", "PAPERCLIP_COMPANY_ID", "PAPERCLIP_RUN_ID", ]), ); expect(invocationPrompt).toContain("Paperclip runtime note:"); expect(invocationPrompt).toContain("PAPERCLIP_API_URL"); } finally { if (previousHome === undefined) { delete process.env.HOME; } else { process.env.HOME = previousHome; } await fs.rm(root, { recursive: true, force: true }); } }); });