diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b431b625..6f015ff1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Groups: `whatsapp.groups`, `telegram.groups`, and `imessage.groups` now act as allowlists when set. Add `"*"` to keep allow-all behavior. ### Fixes +- Onboarding: write auth profiles to the multi-agent path (`~/.clawdbot/agents/main/agent/`) so the gateway finds credentials on first startup. Thanks @minghinmatthewlam for PR #327. - Docs: add missing `ui:install` setup step in the README. Thanks @hugobarauna for PR #300. - Build: import tool-display JSON as a module instead of runtime file reads. Thanks @mukhtharcm for PR #312. - Browser: fix `browser snapshot`/`browser act` timeouts under Bun by patching Playwright’s CDP WebSocket selection. Thanks @azade-c for PR #307. diff --git a/src/agents/agent-scope.ts b/src/agents/agent-scope.ts index 4b3ea01d6..e462abbcf 100644 --- a/src/agents/agent-scope.ts +++ b/src/agents/agent-scope.ts @@ -53,3 +53,12 @@ export function resolveAgentDir(cfg: ClawdbotConfig, agentId: string) { const root = resolveStateDir(process.env, os.homedir); return path.join(root, "agents", id, "agent"); } + +/** + * Resolve the agent directory for the default agent without requiring config. + * Used by onboarding when writing auth profiles before config is fully set up. + */ +export function resolveDefaultAgentDir(): string { + const root = resolveStateDir(process.env, os.homedir); + return path.join(root, "agents", DEFAULT_AGENT_ID, "agent"); +} diff --git a/src/commands/onboard-auth.test.ts b/src/commands/onboard-auth.test.ts index 71526c61d..f50ab2823 100644 --- a/src/commands/onboard-auth.test.ts +++ b/src/commands/onboard-auth.test.ts @@ -36,9 +36,10 @@ describe("writeOAuthCredentials", () => { delete process.env.CLAWDBOT_OAUTH_DIR; }); - it("writes auth-profiles.json under CLAWDBOT_STATE_DIR/agent", async () => { + it("writes auth-profiles.json under CLAWDBOT_STATE_DIR/agents/main/agent", async () => { tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-oauth-")); process.env.CLAWDBOT_STATE_DIR = tempStateDir; + // Even if legacy env vars are set, onboarding should write to the multi-agent path. process.env.CLAWDBOT_AGENT_DIR = path.join(tempStateDir, "agent"); process.env.PI_CODING_AGENT_DIR = process.env.CLAWDBOT_AGENT_DIR; @@ -50,8 +51,11 @@ describe("writeOAuthCredentials", () => { await writeOAuthCredentials("anthropic", creds); + // Now writes to the multi-agent path: agents/main/agent const authProfilePath = path.join( tempStateDir, + "agents", + "main", "agent", "auth-profiles.json", ); @@ -64,5 +68,12 @@ describe("writeOAuthCredentials", () => { access: "access-token", type: "oauth", }); + + await expect( + fs.readFile( + path.join(tempStateDir, "agent", "auth-profiles.json"), + "utf8", + ), + ).rejects.toThrow(); }); }); diff --git a/src/commands/onboard-auth.ts b/src/commands/onboard-auth.ts index f2032f8ad..f35f5a59c 100644 --- a/src/commands/onboard-auth.ts +++ b/src/commands/onboard-auth.ts @@ -1,4 +1,5 @@ import type { OAuthCredentials, OAuthProvider } from "@mariozechner/pi-ai"; +import { resolveDefaultAgentDir } from "../agents/agent-scope.js"; import { upsertAuthProfile } from "../agents/auth-profiles.js"; import type { ClawdbotConfig } from "../config/config.js"; @@ -6,6 +7,8 @@ export async function writeOAuthCredentials( provider: OAuthProvider, creds: OAuthCredentials, ): Promise { + // Write to the multi-agent path so gateway finds credentials on startup + const agentDir = resolveDefaultAgentDir(); upsertAuthProfile({ profileId: `${provider}:${creds.email ?? "default"}`, credential: { @@ -13,10 +16,13 @@ export async function writeOAuthCredentials( provider, ...creds, }, + agentDir, }); } export async function setAnthropicApiKey(key: string) { + // Write to the multi-agent path so gateway finds credentials on startup + const agentDir = resolveDefaultAgentDir(); upsertAuthProfile({ profileId: "anthropic:default", credential: { @@ -24,6 +30,7 @@ export async function setAnthropicApiKey(key: string) { provider: "anthropic", key, }, + agentDir, }); }