diff --git a/src/agents/bash-tools.ts b/src/agents/bash-tools.ts index a5de2577b..9360ad277 100644 --- a/src/agents/bash-tools.ts +++ b/src/agents/bash-tools.ts @@ -114,6 +114,7 @@ export type BashToolDetails = sessionId: string; pid?: number; startedAt: number; + cwd?: string; tail?: string; } | { @@ -121,6 +122,7 @@ export type BashToolDetails = exitCode: number | null; durationMs: number; aggregated: string; + cwd?: string; }; export function createBashTool( @@ -316,6 +318,7 @@ export function createBashTool( sessionId, pid: session.pid ?? undefined, startedAt, + cwd: session.cwd, tail: session.tail, }, }); @@ -356,6 +359,7 @@ export function createBashTool( sessionId, pid: session.pid ?? undefined, startedAt, + cwd: session.cwd, tail: session.tail, }, }), @@ -431,6 +435,7 @@ export function createBashTool( exitCode: code ?? 0, durationMs, aggregated, + cwd: session.cwd, }, }), ); diff --git a/src/agents/cli-credentials.test.ts b/src/agents/cli-credentials.test.ts index ff6f6c4dd..01e742528 100644 --- a/src/agents/cli-credentials.test.ts +++ b/src/agents/cli-credentials.test.ts @@ -136,10 +136,12 @@ describe("cli credentials", () => { const first = readClaudeCliCredentialsCached({ allowKeychainPrompt: true, ttlMs: 15 * 60 * 1000, + platform: "darwin", }); const second = readClaudeCliCredentialsCached({ allowKeychainPrompt: false, ttlMs: 15 * 60 * 1000, + platform: "darwin", }); expect(first).toBeTruthy(); @@ -167,6 +169,7 @@ describe("cli credentials", () => { const first = readClaudeCliCredentialsCached({ allowKeychainPrompt: true, ttlMs: 15 * 60 * 1000, + platform: "darwin", }); vi.advanceTimersByTime(15 * 60 * 1000 + 1); @@ -174,6 +177,7 @@ describe("cli credentials", () => { const second = readClaudeCliCredentialsCached({ allowKeychainPrompt: true, ttlMs: 15 * 60 * 1000, + platform: "darwin", }); expect(first).toBeTruthy(); diff --git a/src/agents/cli-credentials.ts b/src/agents/cli-credentials.ts index 8ce0f8758..42ffd5f8d 100644 --- a/src/agents/cli-credentials.ts +++ b/src/agents/cli-credentials.ts @@ -111,8 +111,11 @@ function readClaudeCliKeychainCredentials(): ClaudeCliCredential | null { export function readClaudeCliCredentials(options?: { allowKeychainPrompt?: boolean; + platform?: NodeJS.Platform; + homeDir?: string; }): ClaudeCliCredential | null { - if (process.platform === "darwin" && options?.allowKeychainPrompt !== false) { + const platform = options?.platform ?? process.platform; + if (platform === "darwin" && options?.allowKeychainPrompt !== false) { const keychainCreds = readClaudeCliKeychainCredentials(); if (keychainCreds) { log.info("read anthropic credentials from claude cli keychain", { @@ -122,7 +125,7 @@ export function readClaudeCliCredentials(options?: { } } - const credPath = resolveClaudeCliCredentialsPath(); + const credPath = resolveClaudeCliCredentialsPath(options?.homeDir); const raw = loadJsonFile(credPath); if (!raw || typeof raw !== "object") return null; @@ -158,10 +161,12 @@ export function readClaudeCliCredentials(options?: { export function readClaudeCliCredentialsCached(options?: { allowKeychainPrompt?: boolean; ttlMs?: number; + platform?: NodeJS.Platform; + homeDir?: string; }): ClaudeCliCredential | null { const ttlMs = options?.ttlMs ?? 0; const now = Date.now(); - const cacheKey = resolveClaudeCliCredentialsPath(); + const cacheKey = resolveClaudeCliCredentialsPath(options?.homeDir); if ( ttlMs > 0 && claudeCliCache && @@ -172,6 +177,8 @@ export function readClaudeCliCredentialsCached(options?: { } const value = readClaudeCliCredentials({ allowKeychainPrompt: options?.allowKeychainPrompt, + platform: options?.platform, + homeDir: options?.homeDir, }); if (ttlMs > 0) { claudeCliCache = { value, readAt: now, cacheKey }; diff --git a/src/agents/pi-tools.workspace-paths.test.ts b/src/agents/pi-tools.workspace-paths.test.ts index 98b37d484..e34977843 100644 --- a/src/agents/pi-tools.workspace-paths.test.ts +++ b/src/agents/pi-tools.workspace-paths.test.ts @@ -5,9 +5,6 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; import { createClawdbotCodingTools } from "./pi-tools.js"; -const normalizeText = (value?: string) => - (value ?? "").replace(/\r\n/g, "\n").trim(); - async function withTempDir(prefix: string, fn: (dir: string) => Promise) { const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); try { @@ -120,11 +117,17 @@ describe("workspace path resolution", () => { expect(bashTool).toBeDefined(); const result = await bashTool?.execute("ws-bash", { - command: 'node -e "console.log(process.cwd())"', + command: "echo ok", }); - const output = normalizeText(getTextContent(result)); + const cwd = + result?.details && + typeof result.details === "object" && + "cwd" in result.details + ? (result.details as { cwd?: string }).cwd + : undefined; + expect(cwd).toBeTruthy(); const [resolvedOutput, resolvedWorkspace] = await Promise.all([ - fs.realpath(output), + fs.realpath(String(cwd)), fs.realpath(workspaceDir), ]); expect(resolvedOutput).toBe(resolvedWorkspace); @@ -139,12 +142,18 @@ describe("workspace path resolution", () => { expect(bashTool).toBeDefined(); const result = await bashTool?.execute("ws-bash-override", { - command: 'node -e "console.log(process.cwd())"', + command: "echo ok", workdir: overrideDir, }); - const output = normalizeText(getTextContent(result)); + const cwd = + result?.details && + typeof result.details === "object" && + "cwd" in result.details + ? (result.details as { cwd?: string }).cwd + : undefined; + expect(cwd).toBeTruthy(); const [resolvedOutput, resolvedOverride] = await Promise.all([ - fs.realpath(output), + fs.realpath(String(cwd)), fs.realpath(overrideDir), ]); expect(resolvedOutput).toBe(resolvedOverride);