/** * First-run canon — install is not Done until whoami works AND the first * POST /v1/execute returns 200. Shared by mcp-install, install.sh / install.ps1, * no_session recovery, and the first managed-call prompt. Do not invent a * second login command or a dead first-wow rail here. */ import { type FirstExecuteResult } from "./first-call.js"; import { type CliAuthStartArgs, type CliAuthStartResult, type OpenBrowserSpawn, type StartedPendingLogin } from "./pending-login-start.js"; export { AUTH_FIRST_CALL_COMMAND } from "./first-call.js"; /** User-facing recovery / next-step command. Never pin an unpublished version. */ export declare const AUTH_LOGIN_COMMAND = "npx @nordsym/apiclaw auth login"; /** Confirm the workspace file is live after login. */ export declare const AUTH_WHOAMI_COMMAND = "npx @nordsym/apiclaw auth whoami"; /** * Last-resort clickable auth URL when Convex mint fails. * Prefer a live `/auth/cli?authId=` URL. Never send agents to bare /sign-in. */ export declare const FALLBACK_LOGIN_URL = "https://apiclaw.cloud/auth/cli"; /** Absolute https auth URL the human can click. Never return empty or a command. */ export declare function clickableLoginUrl(pending?: string | null): string; /** * First managed call after sign-in. NASA APOD is the research rail * (zero-cost, no card). Frankfurter is the last-resort free fallback so * first_call still lands. Brave / Serper / Firecrawl need a card — not * this path. Never lead with ElevenLabs or Replicate. */ export declare const FIRST_CALL_PROMPT = "Not ready until whoami prints an email. Then fetch today's NASA Astronomy Picture of the Day: call_api with provider \"nasa\", action \"apod\", params {}. If NASA is not 200, call_api with provider \"frankfurter\", action \"latest\", params { path: \"/latest\" }. Do not lead with billed research (Brave, Serper, Firecrawl)."; export declare const FIRST_CALL_CLI = "npx @nordsym/apiclaw call nasa/apod --params '{}' --idempotency-key \"apiclaw-first-nasa-$(date +%s)\""; export interface LaunchAuthProbe { env?: NodeJS.ProcessEnv; platform?: NodeJS.Platform; stdinIsTTY?: boolean; stdoutIsTTY?: boolean; } /** * Launch `auth login` only when the user can finish browser ownership * verification on this machine. curl|bash has no stdin TTY, so stdout TTY * plus a browser opener is enough. Headless SSH must print the command. */ export declare function canLaunchInteractiveAuth(probe?: LaunchAuthProbe): boolean; /** * Open the minted Clerk URL when this machine can show a browser. * MCP on Cursor / Claude Desktop has a GUI and no TTY — do not require one. * Headless CI still mints login_url; it must not spawn open/start/xdg-open. */ export declare function canOpenAuthBrowser(probe?: LaunchAuthProbe): boolean; export declare function hasWorkingWhoami(): boolean; /** * First line is always the bare https login URL so chat clients link it * and summarizers cannot bury it in JSON or a label. Body follows. JSON last. */ export declare function formatLeadingLoginUrl(pending: string | null | undefined, body: readonly string[], payload?: Record): string; /** * Printed by CLI call / whoami / first-call when session_token is missing. * Prefer the pending Clerk URL from the in-flight `auth login` so the human * can finish the already-started browser flow. */ export declare function unsignedExecuteMessage(pendingLoginUrl?: string | null): string; export type AuthRequiredToolResult = { content: { type: "text"; text: string; }[]; isError: true; }; /** * Human/agent-visible auth text. The https URL is the first line so * chat clients make it clickable even when the host truncates or the * agent summarizes. JSON is a separate MCP content block — never in * this string. Never bury the URL inside JSON-only text or behind a label. */ export declare function formatAuthRequiredVisibleText(payload: Record): string; /** Structured payload only. Do not put this in the same text block as the URL. */ export declare function formatAuthRequiredJson(payload: Record): string; /** * Prefix every unsigned tools/list description so a harness that never * calls a tool still sees a pasteable https login URL at connect time. */ export declare function unsignedToolDescriptionPrefix(pending?: string | null): string; /** Parse a JSON auth payload, or the trailing JSON object from older combined text. */ export declare function extractAuthRequiredPayload(text: string): Record; /** MCP/CLI host-visible error. isError must be true so agents cannot treat this as success. */ export declare function authRequiredToolResult(payload: Record): AuthRequiredToolResult; /** Shared MCP / CLI payload when execute is refused for no session. */ export declare function agentAuthRequiredPayload(extra?: Record): Record; export type AgentAuthMintOptions = { openBrowser?: boolean; ensurePending?: () => Promise; /** Injected for tests. Defaults to canOpenAuthBrowser(options). */ canOpen?: (probe?: LaunchAuthProbe) => boolean; env?: NodeJS.ProcessEnv; platform?: NodeJS.Platform; stdinIsTTY?: boolean; stdoutIsTTY?: boolean; start?: (args: CliAuthStartArgs) => Promise; spawn?: OpenBrowserSpawn; now?: number; fingerprint?: string; }; /** Mint or reuse pending login, then build the host-visible auth payload. */ export declare function agentAuthRequiredPayloadAfterMint(extra?: Record, options?: AgentAuthMintOptions): Promise>; /** Unsigned first_run / execute: mint, then return an isError tool result. */ export declare function unsignedFirstRunToolResult(extra?: Record, options?: AgentAuthMintOptions): Promise; export declare function firstRunIncompleteMessage(pendingLoginUrl?: string | null): string; export declare function firstRunCompleteMessage(email?: string, summary?: string): string; export declare function firstRunExecuteFailedMessage(): string; export declare function printFirstRunIncomplete(pendingLoginUrl?: string | null): void; export declare function printFirstRunComplete(email?: string, summary?: string): void; export declare function printFirstRunExecuteFailed(): void; export interface CompleteFirstRunAuthOptions { /** When true, skip launching login (dry-run / already attempted). */ skipLaunch?: boolean; launch?: (options?: { force?: boolean; }) => Promise<{ email?: string; firstCall?: FirstExecuteResult; } | null>; /** Injected for tests. Defaults to reading ~/.apiclaw.toml. */ whoami?: () => boolean; /** Injected for tests. Defaults to NASA APOD then Frankfurter. */ firstExecute?: () => Promise; /** * Mint or reuse pending login. Defaults to ensurePendingLogin. * Must run even when there is no TTY — opening the browser is optional. */ ensurePending?: () => Promise; /** Injected for tests. Defaults to canLaunchInteractiveAuth(). */ canLaunch?: () => boolean; } export interface CompleteFirstRunAuthResult { complete: boolean; launched: boolean; email?: string; firstCall?: FirstExecuteResult; } /** * After MCP/config install: mint a pending /auth/cli?authId= URL even * without a TTY, optionally wait on interactive login, then refuse Done * until whoami works and the first execute returns 200. */ export declare function completeFirstRunAuth(options?: CompleteFirstRunAuthOptions): Promise; //# sourceMappingURL=first-run.d.ts.map