diff --git a/CLAUDE.md b/CLAUDE.md index 2452574d..a9112e6e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -232,6 +232,7 @@ After running, the Coding Agent should: - **`SMC_DATA_DIR=~/.super-multica-e2e`** isolates E2E test sessions from dev (`~/.super-multica-dev`) and production (`~/.super-multica`) data. Always set this. - **`MULTICA_API_URL=https://api-dev.copilothub.ai`** is required for `web_search` and `data` tools. Without it, these tools fail with `MULTICA_API_URL is required`. +- **Auth for `web_search`/`data`**: These tools need dev backend auth. The auth store auto-falls back to `~/.super-multica-dev/auth.json`. If missing, run `pnpm dev:local` first and log in through the Desktop app. - Default provider is `kimi-coding`. Override with `--provider`. - Run-log and session data are at `~/.super-multica-e2e/sessions/{sessionId}/` - Detailed guide with feature-specific test playbooks: `docs/e2e-testing-guide.md` diff --git a/docs/e2e-testing-guide.md b/docs/e2e-testing-guide.md index e25eff0d..3892f5b7 100644 --- a/docs/e2e-testing-guide.md +++ b/docs/e2e-testing-guide.md @@ -23,6 +23,7 @@ This approach is superior to static assertions because: 3. **Default provider**: `kimi-coding` (Kimi Code, free tier available). Can override with `--provider` 4. **`MULTICA_API_URL`**: Required for `web_search` and `data` tools. Set to `https://api-dev.copilothub.ai` for dev environment. Without this, web search and financial data tools will fail with `MULTICA_API_URL is required` 5. **`SMC_DATA_DIR`**: Set to `~/.super-multica-e2e` to isolate E2E test sessions from dev (`~/.super-multica-dev`) and production (`~/.super-multica`) data. Without this, test sessions pollute the production sessions directory +6. **Dev auth for `web_search`/`data` tools**: These tools authenticate via `auth.json` (session ID + device ID). The auth store automatically falls back to `~/.super-multica-dev/auth.json` when the E2E data dir has no auth. If `~/.super-multica-dev/auth.json` doesn't exist, run `pnpm dev:local` first and log in through the Desktop app to create it ## Running a Test diff --git a/packages/core/src/hub/api-client.ts b/packages/core/src/hub/api-client.ts index c3254463..d739cc9d 100644 --- a/packages/core/src/hub/api-client.ts +++ b/packages/core/src/hub/api-client.ts @@ -19,7 +19,7 @@ export function getAuthHeaders(context?: string): Record { if (!auth) { const suffix = context ? ` ${context}` : ""; throw new Error( - `Not logged in. Please sign in via the Desktop app${suffix}.`, + `Not logged in${suffix}. Sign in via the Desktop app, or run pnpm dev:local and log in there.`, ); } return { diff --git a/packages/core/src/hub/auth-store.ts b/packages/core/src/hub/auth-store.ts index ff2342ba..23c88c41 100644 --- a/packages/core/src/hub/auth-store.ts +++ b/packages/core/src/hub/auth-store.ts @@ -1,18 +1,16 @@ import { readFileSync } from "node:fs"; +import { homedir } from "node:os"; import { join } from "node:path"; import { DATA_DIR } from "@multica/utils"; const AUTH_FILE_PATH = join(DATA_DIR, "auth.json"); +const DEV_AUTH_FILE_PATH = join(homedir(), ".super-multica-dev", "auth.json"); export type LocalAuthData = { sid: string; deviceId: string }; -/** - * Read sid and deviceId from ~/.super-multica/auth.json. - * Returns null if the file is missing, unreadable, or incomplete. - */ -export function getLocalAuth(): LocalAuthData | null { +function tryReadAuth(filePath: string): LocalAuthData | null { try { - const raw = readFileSync(AUTH_FILE_PATH, "utf8").trim(); + const raw = readFileSync(filePath, "utf8").trim(); if (!raw) return null; const data = JSON.parse(raw); @@ -32,3 +30,26 @@ export function getLocalAuth(): LocalAuthData | null { return null; } } + +/** + * Read sid and deviceId from auth.json. + * + * Lookup order: + * 1. {DATA_DIR}/auth.json (current data dir, respects SMC_DATA_DIR) + * 2. ~/.super-multica-dev/auth.json (dev environment fallback — + * allows E2E tests and other custom SMC_DATA_DIR setups to + * share the dev auth created by `pnpm dev:local`) + * + * Returns null if no valid auth is found. + */ +export function getLocalAuth(): LocalAuthData | null { + const primary = tryReadAuth(AUTH_FILE_PATH); + if (primary) return primary; + + // Fallback to dev auth when using a custom data dir (e.g. E2E tests) + if (AUTH_FILE_PATH !== DEV_AUTH_FILE_PATH) { + return tryReadAuth(DEV_AUTH_FILE_PATH); + } + + return null; +}