diff --git a/src/agents/cli-runner.spawn.test.ts b/src/agents/cli-runner.spawn.test.ts index 4045196f3b79..b31cfcd02d8f 100644 --- a/src/agents/cli-runner.spawn.test.ts +++ b/src/agents/cli-runner.spawn.test.ts @@ -83,7 +83,7 @@ afterEach(() => { }); function buildPreparedCliRunContext(params: { - provider: "claude-cli" | "codex-cli"; + provider: "claude-cli" | "codex-cli" | "google-gemini-cli"; model: string; runId: string; prompt?: string; @@ -106,33 +106,46 @@ function buildPreparedCliRunContext(params: { // Produces a prepared context without invoking prepare.runtime, keeping spawn // assertions focused on execute/runtime behavior. const workspaceDir = params.workspaceDir ?? "/tmp"; - const baseBackend = - params.provider === "claude-cli" - ? { - command: "claude", - args: ["-p", "--output-format", "stream-json"], - output: "jsonl" as const, - input: "stdin" as const, - modelArg: "--model", - sessionArg: "--session-id", - sessionMode: "always" as const, - systemPromptFileArg: "--append-system-prompt-file", - systemPromptWhen: "first" as const, - serialize: true, - } - : { - command: "codex", - args: ["exec", "--json"], - resumeArgs: ["exec", "resume", "{sessionId}", "--skip-git-repo-check"], - output: "text" as const, - input: "arg" as const, - modelArg: "--model", - sessionMode: "existing" as const, - systemPromptFileConfigArg: "-c", - systemPromptFileConfigKey: "model_instructions_file", - systemPromptWhen: "first" as const, - serialize: true, - }; + const baseBackend = (() => { + if (params.provider === "claude-cli") { + return { + command: "claude", + args: ["-p", "--output-format", "stream-json"], + output: "jsonl" as const, + input: "stdin" as const, + modelArg: "--model", + sessionArg: "--session-id", + sessionMode: "always" as const, + systemPromptFileArg: "--append-system-prompt-file", + systemPromptWhen: "first" as const, + serialize: true, + }; + } + if (params.provider === "google-gemini-cli") { + return { + command: "gemini", + args: ["--skip-trust", "--output-format", "json", "--prompt", "{prompt}"], + output: "json" as const, + input: "arg" as const, + modelArg: "--model", + sessionMode: "existing" as const, + serialize: true, + }; + } + return { + command: "codex", + args: ["exec", "--json"], + resumeArgs: ["exec", "resume", "{sessionId}", "--skip-git-repo-check"], + output: "text" as const, + input: "arg" as const, + modelArg: "--model", + sessionMode: "existing" as const, + systemPromptFileConfigArg: "-c", + systemPromptFileConfigKey: "model_instructions_file", + systemPromptWhen: "first" as const, + serialize: true, + }; + })(); const backend = { ...baseBackend, ...params.backend }; return { params: { @@ -158,7 +171,12 @@ function buildPreparedCliRunContext(params: { id: params.provider, config: backend, bundleMcp: params.provider === "claude-cli", - pluginId: params.provider === "claude-cli" ? "anthropic" : "openai", + pluginId: + params.provider === "claude-cli" + ? "anthropic" + : params.provider === "google-gemini-cli" + ? "google" + : "openai", resolveExecutionArgs: params.resolveExecutionArgs, }, preparedBackend: { @@ -562,6 +580,30 @@ describe("runCliAgent spawn path", () => { ); }); + it("logs Gemini CLI runtime env key diagnostics without debug output enabled", async () => { + mockSuccessfulCliRun(); + const infoSpy = vi.spyOn(cliBackendLog, "info"); + + await executePreparedCliRun( + buildPreparedCliRunContext({ + provider: "google-gemini-cli", + model: "gemini-3.1-pro-preview", + runId: "run-gemini-env-diagnostics", + preparedEnv: { + GEMINI_CLI_HOME: "/tmp/openclaw-gemini-profile-home", + GEMINI_CLI_SYSTEM_SETTINGS_PATH: "/tmp/openclaw-gemini-system-settings.json", + }, + }), + ); + + const envLog = infoSpy.mock.calls + .map((call) => String(call[0])) + .find((line) => line.startsWith("cli env auth:")); + expect(envLog).toContain("runtimeChild=GEMINI_CLI_HOME,GEMINI_CLI_SYSTEM_SETTINGS_PATH"); + expect(envLog).not.toContain("/tmp/openclaw-gemini-profile-home"); + expect(envLog).not.toContain("/tmp/openclaw-gemini-system-settings.json"); + }); + it("passes OpenClaw skills to Claude as a session plugin", async () => { const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cli-skills-")); const skillDir = path.join(workspaceDir, "skills", "weather"); diff --git a/src/agents/cli-runner/execute.ts b/src/agents/cli-runner/execute.ts index 6e1749b37188..a97546422c49 100644 --- a/src/agents/cli-runner/execute.ts +++ b/src/agents/cli-runner/execute.ts @@ -715,6 +715,8 @@ export async function executePreparedCliRun( return next; })(); + const logCliEnvDiagnostics = + logOutputText || context.backendResolved.id === "google-gemini-cli"; if (logOutputText) { const logArgs = buildCliLogArgs({ args, @@ -725,6 +727,8 @@ export async function executePreparedCliRun( argsPrompt, }); cliBackendLog.info(`cli argv: ${backend.command} ${logArgs.join(" ")}`); + } + if (logCliEnvDiagnostics) { cliBackendLog.info(`cli env auth: ${buildCliEnvAuthLog(env)}`); if (env.OPENCLAW_MCP_TOKEN || env.OPENCLAW_MCP_SESSION_KEY || env.OPENCLAW_MCP_AGENT_ID) { cliBackendLog.info(`cli env mcp: ${buildCliEnvMcpLog(env)}`);