feat: add "Anthropic — via Claude CLI" as a first-class provider

Replaces the stray useClaudeCli settings checkbox + onboarding question
with a proper provider-card UX. The card lives next to OAuth + API-key
cards in onboarding and settings, with Enable/Disable + Test actions.

Backend:
 - Vendors rchern/pi-claude-cli@0.3.1 as packages/pi-claude-cli
   (MIT, attribution in UPSTREAM.md). Lets us bump peer-dep on
   pi-coding-agent in lockstep with Fusion (upstream pinned ^0.52.0
   vs ours ^0.62.0) and fix bugs without waiting on upstream.
 - Adds @fusion/pi-claude-cli as a workspace dep of @runfusion/fusion
   so users don't have to `npm install -g pi-claude-cli` manually.
 - serve/daemon/dashboard conditionally load the extension via
   discoverAndLoadExtensions() when GlobalSettings.useClaudeCli is on;
   no side-effects on user ~/.fusion/agent/settings.json.
 - New GET /api/providers/claude-cli/status: claude --version probe
   + toggle state + cached extension resolution.
 - New POST /api/auth/claude-cli: flips useClaudeCli, refuses if the
   claude binary is missing, fires the existing skill-backfill hook.
 - /api/auth/status now injects a synthetic {id:"claude-cli", type:"cli"}
   provider entry so onboarding + settings see a consistent list.

Frontend:
 - New ClaudeCliProviderCard component shared between ModelOnboardingModal
   and SettingsModal's Authentication section.
 - New AuthProvider.type = "cli" variant.
 - Removed the old "Route AI calls through the Claude CLI" checkbox from
   Global Models settings and the opt-in step from the onboarding wizard.
 - ProviderIcon gets a composite Anthropic-mark-plus-terminal glyph for
   the claude-cli provider id.

Tests:
 - 8 unit tests for extension resolution (@fusion/pi-claude-cli is
   workspace-linked so these run in-tree).
 - 2 unit tests for the binary probe.
 - Existing /auth/status tests filter out the new synthetic entry so
   they keep asserting structural OAuth/API-key behavior in isolation.
 - The vendored package's own 296 tests still pass unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-23 16:48:57 -07:00
parent 82b4c696d8
commit f4e0850f9d
44 changed files with 9390 additions and 76 deletions

View File

@@ -926,12 +926,56 @@ export interface AuthProvider {
id: string;
name: string;
authenticated: boolean;
/** Whether this provider uses OAuth or API key authentication */
type?: "oauth" | "api_key";
/**
* How this provider authenticates / is activated.
* - "oauth": OAuth flow (user clicks Login → redirect)
* - "api_key": API key stored locally
* - "cli": a locally-installed CLI binary is the backing transport
* (e.g. the synthetic `claude-cli` provider). Cards should render a
* one-click Enable/Disable + Test button rather than login/key inputs.
*/
type?: "oauth" | "api_key" | "cli";
/** Masked hint of the stored API key (first 3 + bullets + last 4 chars) */
keyHint?: string;
}
/**
* Snapshot of the Claude-CLI-via-pi health state. Powers the
* "Anthropic — via Claude CLI" provider card.
*/
export interface ClaudeCliStatus {
binary: {
available: boolean;
version?: string;
binaryPath?: string;
reason?: string;
probeDurationMs: number;
};
enabled: boolean;
extension: {
status: "ok" | "not-installed" | "missing-entry" | "error";
path?: string;
packageVersion?: string;
reason?: string;
} | null;
ready: boolean;
}
/** Probe the local Claude CLI binary + setting + extension state. */
export function fetchClaudeCliStatus(): Promise<ClaudeCliStatus> {
return api<ClaudeCliStatus>("/providers/claude-cli/status");
}
/** Enable or disable the Claude CLI provider. Refuses enable if binary is missing. */
export function setClaudeCliEnabled(
enabled: boolean,
): Promise<{ enabled: boolean; restartRequired: boolean }> {
return api<{ enabled: boolean; restartRequired: boolean }>("/auth/claude-cli", {
method: "POST",
body: JSON.stringify({ enabled }),
});
}
/** Fetch authentication status for all OAuth providers */
export function fetchAuthStatus(): Promise<{
providers: AuthProvider[];