/** * The credential the CLI signs in with, and the identity it displays. * * READING is not done here. Every read goes through `fleet-credentials.ts` → * `@hasna/contracts/client`, so the argument, the env pointer, the macOS * Keychain, `~/.hasna/skills/config/credentials` and `HASNA_SKILLS_API_KEY` are * consulted in the fleet's one order, on every call. There is no cache: a * credential is mutable state, and a value captured at process start is the * defect the ladder exists to remove (a shell that outlives a key rotation). * * WRITING lands in exactly one file — `~/.hasna/skills/config/credentials`, * mode 0600, the shared seam's disk tier — so `skills auth login` on this * machine and a station wrapper reading the same file cannot disagree. * `HASNA_HOME` / `HASNA_CONFIG_HOME` relocate it; `$HASNA_SKILLS_DIR` does not, * because that variable relocates this app's DATA (corpus, database, config), * and the fleet credential is not app data — it is the machine's, shared with * every other Hasna CLI. * * The display identity (`email`, org, user ids) is NOT a credential and lives * beside it in `identity.json`. It is only ever what the server's `whoami` * returned; nothing here invents a field. * * `~/.skills/auth.json` and `~/.hasna/skills/auth.json` are retired locations and * are not read. `skills auth login` writes the credentials file; an operator * still holding an old auth.json is told to sign in again. */ import { type SkillsFleetOptions } from "./fleet-credentials.js"; export { normalizeSkillsApiOrigin } from "./fleet-credentials.js"; type Env = Record; /** The credentials file this package writes and the shared seam reads. */ export declare function getAuthFilePath(env?: Env): string; /** * Write-free path resolution for read-only paths (e.g. `sync --dry-run`). * * Identical to getAuthFilePath(): nothing in the credential path writes as a * side effect of resolving any more. Kept as a separate name so the read-only * callers keep reading as read-only. */ export declare function getAuthFilePathReadOnly(env?: Env): string; /** The display identity file beside the credential. Never holds a secret. */ export declare function getIdentityFilePath(env?: Env): string; /** * Stored credentials for a Skills API instance. * * `apiKey` is the credential the ladder resolved — not necessarily one this CLI * wrote. The identity fields are display metadata echoed back from the * instance's `whoami`, so they are optional: an instance that does not return * them leaves them unset. They are never invented locally — a placeholder * written here is indistinguishable from a value the server actually returned. */ export interface AuthConfig { /** * The credential the ladder resolved, or null when it is a vault POINTER that * only the async path can complete (see {@link getApiKeyAsync}). Callers that * need to SEND it must resolve it there; the display surfaces below only need * to know that one is configured. */ apiKey: string | null; email?: string; orgId?: string; orgSlug?: string; userId?: string; } /** The identity half, on its own: what `whoami` said, with no credential. */ export type AuthIdentity = Omit; /** * What `saveAuthConfig` is handed: a key this CLI actually holds. * * Distinct from {@link AuthConfig}, whose `apiKey` may be null for a vault * pointer — there is nothing to write to disk in that case, and writing an * empty line would masquerade as a stored credential. */ export type StoredAuthConfig = AuthIdentity & { apiKey: string; }; export declare function getAuthIdentity(env?: Env): AuthIdentity; /** * The credential in effect plus whatever identity was recorded for it, or null * when no credential resolves anywhere on the ladder. */ export declare function getAuthConfig(env?: Env, options?: SkillsFleetOptions): AuthConfig | null; /** Alias kept for the read-only callers; resolution never writes. */ export declare function getAuthConfigReadOnly(env?: Env, options?: SkillsFleetOptions): AuthConfig | null; /** * How the stored key was obtained. `sign-in` keys were minted for this CLI by a * browser/device or email sign-in, so `skills logout` may revoke them on the * server; an `api-key` the user pasted is theirs to manage and is only * forgotten locally. Recorded in identity.json (never a secret). */ export type StoredKeyIssuer = "sign-in" | "api-key"; export declare function saveAuthConfig(config: StoredAuthConfig, env?: Env, authenticatedOrigin?: string, issuedBy?: StoredKeyIssuer): string; /** * Who put the active profile's stored credential there — the question * `skills logout` has to answer before it touches it (Instructions rule * global-cli-logout-semantics, points 1 and 2). * * sign-in — minted for this CLI by `skills login` (browser, device code, * email code) or workspace enrollment. Revoked on logout by default. * api-key — brought by the user with `skills login --api-key`. Deleted * locally on logout; revoked only with an explicit `--revoke`. * legacy — stored by an older `skills auth login` that did not record how * the key was issued, so it cannot be revoked automatically. * external — no sign-in record at all: a provisioned key, a vault pointer, or * one written by another tool. Logout leaves it alone. */ export type StoredCredentialOrigin = StoredKeyIssuer | "legacy" | "external"; /** The active profile's stored credential, as `skills logout` sees it. The key is never printed. */ export interface StoredCredential { /** The credentials file. A path: safe to print. */ file: string; /** The stored key, or null when the file holds only a vault pointer. Never printed or logged. */ apiKey: string | null; /** The instance the credential belongs to: its recorded binding, else the file URL, else the internal gateway. */ origin: string; storedBy: StoredCredentialOrigin; /** True when the file's URL line is there only because `skills login` wrote it; logout then removes it too. */ urlWrittenByLogin: boolean; } /** * Read the active profile's stored credential WITHOUT the resolution ladder: * logout must act on exactly the credential login stored for this profile, * never on one the environment or the Keychain would supply instead. */ export declare function readStoredCredential(env?: Env): StoredCredential | null; /** * Delete the stored credential for the active profile, and throw when it cannot * be deleted: the key, its binding, any vault pointer and the display identity. * * `removeUrl` also deletes the URL line, for a URL that `skills login` wrote * (the product default or a `--url` given only to login). Leaving it would let * a later environment-only key pair with a server nobody configured. A URL the * user configured (`skills setup --api-url`) stays. */ export declare function deleteStoredCredential(env?: Env, removeUrl?: boolean): string; /** Store (or clear, with null) the API URL beside the credential. */ export declare function saveApiUrl(apiUrl: string | null, env?: Env): string; /** The API URL recorded in the credentials file, or null. */ export declare function readStoredApiUrl(env?: Env): string | null; /** * Remove the credential this CLI wrote. * * Only the file is cleared: a key injected from the environment or held in the * Keychain belongs to the machine, not to this command, and silently appearing * to remove it would be a lie. The caller is told whether one still resolves. */ export declare function clearAuthConfig(env?: Env): { stillResolves: boolean; }; /** * The credential in effect, resolved fresh through the shared ladder. * * SYNCHRONOUS, so it cannot complete a vault pointer * (`HASNA_SKILLS_API_KEY_REF`): for that tier it returns null, because the * pointer's own value is the empty string and handing THAT back as a key is how * `Authorization: Bearer ` reached the wire. Any path that is about to SEND the * key must use {@link getApiKeyAsync} (or `resolveSkillsApiKey`), which fetches * the vault item and refuses loudly when it cannot. */ export declare function getApiKey(env?: Env, options?: SkillsFleetOptions): string | null; /** * The credential in effect, completing a vault pointer through the secrets * vault. Null only in local mode; throws when a configured credential cannot * be produced. Use this wherever the key is about to be sent. */ export declare function getApiKeyAsync(env?: Env, options?: SkillsFleetOptions): Promise; /** Identical to getApiKey(): resolution has no write side effects. */ export declare function getApiKeyReadOnly(env?: Env, options?: SkillsFleetOptions): string | null; /** * Origin every credential-bearing request is sent to. * * The AUTHORITY, not the whole hosted resolution: `skills auth login` runs * before there is a credential, and requiring one here would make signing in * impossible. Throws when nothing names a service: an install that named none * must not decide on the user's behalf where their email address, login code, * or API key goes. */ export declare function getApiUrl(action?: string, env?: Env, options?: SkillsFleetOptions): string; /** Permission bits of the credentials file, for `skills auth status`-style output. */ export declare function credentialFileMode(env?: Env): number | null;