/** * The owner's other Claude Code accounts on this machine (issue #942). * * When the owner's Claude Code account runs out of usage, agents can move to * another account of the SAME owner before falling back to other runtimes. * Each account has its own config dir and its own login — Crewly never * switches accounts inside one login (in-place switching is unreliable * upstream, anthropics/claude-code#94195): * * - config dir: `/claude-accounts//`, passed to Claude as * `CLAUDE_CONFIG_DIR` (its own history, settings and `.claude.json`) — the * only thing that selects the account; * - login: Claude Code's own (`claude auth login` with that config dir, which * Crewly relays but never reads). Claude Code keeps it in the config dir * or the keychain; Crewly stores no Claude.ai credential. Accounts signed * in by an older Crewly keep working on the token it saved until they are * signed in natively (claude-token-migration.service.ts). * * In a fallback chain an account is the entry `claude-code@`; plain * `claude-code` is the machine's default login. * * Add only Claude Code accounts that the owner owns. * * @module services/harness/claude-accounts */ import { type HarnessCredentialsStore } from './harness-credentials.store.js'; /** A runtime target: a runtime, optionally on one of the owner's accounts. */ export interface RuntimeTarget { /** Runtime id (`claude-code`, `crewly-agent`, …) */ runtime: string; /** Account name, for `claude-code@` */ account?: string; } /** One account as the API shows it. */ export interface ClaudeAccountInfo { name: string; /** Fallback chain entry (`claude-code@`) */ target: string; /** A login is stored (token) or present in its config dir */ signedIn: boolean; /** Its config dir */ configDir: string; } /** Where accounts live (injectable for tests). */ export interface ClaudeAccountsLocation { crewlyHome?: string; credentials?: Pick; } /** An invalid account name. */ export declare class ClaudeAccountNameError extends Error { } /** * Normalise an account name as written by a person. * * @param raw - e.g. "Work", " b " * @returns The name, lower-cased and trimmed */ export declare function normaliseClaudeAccountName(raw: string): string; /** * Whether a (normalised) name can be an account name. * * @param name - Candidate * @returns True for 1–32 of `a-z0-9_-`, starting with a letter or digit, not a reserved word * * @example * ```ts * isValidClaudeAccountName('work'); // true * isValidClaudeAccountName('code'); // false (reserved) * ``` */ export declare function isValidClaudeAccountName(name: string): boolean; /** * Validate and normalise an account name. * * @param raw - Name as given * @returns The normalised name * @throws ClaudeAccountNameError when it is not a valid name */ export declare function requireClaudeAccountName(raw: unknown): string; /** * Split a runtime target. * * @param target - `claude-code`, `claude-code@work`, `crewly-agent` * @returns Runtime and account * * @example * ```ts * parseRuntimeTarget('claude-code@work'); // { runtime: 'claude-code', account: 'work' } * ``` */ export declare function parseRuntimeTarget(target: string): RuntimeTarget; /** * The runtime of a target, without its account. * * @param target - Runtime target * @returns Runtime id */ export declare function baseRuntimeOf(target: string): string; /** * The account of a target. * * @param target - Runtime target * @returns Account name, or null for a runtime's default login */ export declare function accountOf(target: string): string | null; /** * Build a target. * * @param runtime - Runtime id * @param account - Account name (only Claude Code has accounts) * @returns `runtime` or `runtime@account` */ export declare function runtimeTarget(runtime: string, account?: string | null): string; /** * Whether a chain entry is one of the owner's Claude Code accounts. * * @param target - Chain entry * @returns True for `claude-code@` */ export declare function isClaudeAccountTarget(target: string): boolean; /** * Directory holding every account's config dir. * * @param crewlyHome - CREWLY_HOME * @returns Absolute path */ export declare function claudeAccountsRoot(crewlyHome?: string): string; /** * An account's config dir (its `CLAUDE_CONFIG_DIR`). * * @param account - Account name (valid) * @param crewlyHome - CREWLY_HOME * @returns Absolute path */ export declare function claudeAccountConfigDir(account: string, crewlyHome?: string): string; /** * Accounts known on this machine: a config dir exists or a token is stored. * * @param location - CREWLY_HOME / credentials overrides * @returns Sorted account names */ export declare function listClaudeAccounts(location?: ClaudeAccountsLocation): string[]; /** * Whether an account has a login. Claude Code's own state decides: its * credentials file in the account's config dir, or what `claude auth status` * last said for that config dir (it also sees a keychain login, which leaves * no file; the answer is refreshed by `refreshClaudeNativeLogins`). A token * an older Crewly saved still counts until the migration deletes it, because * it still works. * * @param account - Account name * @param location - CREWLY_HOME / credentials overrides * @returns True when signed in */ export declare function isClaudeAccountSignedIn(account: string, location?: ClaudeAccountsLocation): boolean; /** * Every known account with its login state. * * @param location - CREWLY_HOME / credentials overrides * @returns Accounts */ export declare function describeClaudeAccounts(location?: ClaudeAccountsLocation): ClaudeAccountInfo[]; /** * Env that runs Claude Code on an account: its config dir, which is what * selects the account (the login is Claude Code's own, in that dir or the * keychain). The default login's credentials are blanked so they cannot win * over the account's (an empty value counts as unset for Claude Code). * * Transition only: an account signed in by an older Crewly still has its * saved token handed over (store.legacyClaudeTokenEnv) until its native login * is verified and the token deleted; after that the env carries no token. * * @param account - Account name * @param location - CREWLY_HOME / credentials overrides * @returns Env vars to merge over the session's env * * @example * ```ts * claudeAccountEnv('work'); // { CLAUDE_CONFIG_DIR: '~/.crewly/claude-accounts/work', CLAUDE_CODE_OAUTH_TOKEN: '', ANTHROPIC_API_KEY: '' } * ``` */ export declare function claudeAccountEnv(account: string, location?: ClaudeAccountsLocation): Record; /** * Create an account's config dir (idempotent). A new dir starts with the * owner's own choices from the default login: Claude's `settings.json` and * the first-run answers in `.claude.json` (onboarding done, permission mode * accepted, theme), so an agent on the account does not stop at a first-run * screen the owner already answered. No credential is copied. * * @param account - Account name (valid) * @param options - CREWLY_HOME and the default login's location (tests) * @returns The config dir */ export declare function ensureClaudeAccountDir(account: string, options?: { crewlyHome?: string; defaultEnv?: NodeJS.ProcessEnv; homeDir?: string; }): string; /** * After an account's login: create its dir if needed and record Claude's * first-run "onboarding done" answer there (as for the default login). * * @param account - Account name (valid) * @param crewlyHome - CREWLY_HOME */ export declare function prepareClaudeAccountAfterLogin(account: string, crewlyHome?: string): void; /** * Remove an account: its legacy stored token (if any) and its config dir. * * @param account - Account name (valid) * @param location - CREWLY_HOME / credentials store */ export declare function removeClaudeAccount(account: string, location?: { crewlyHome?: string; credentials?: Pick; }): void; //# sourceMappingURL=claude-accounts.d.ts.map