/** * Dual-host marketplace plugin manager (#2854). * * Claude Code and Codex keep separate plugin registries. This service drives * each host's own plugin CLI (never its caches) with a literal argv, so one * `ruflo plugins host ...` call can apply the same state to both. * * Results are reported per host and per plugin. A failure on one host never * hides the other's outcome, and `ok` is false if any requested host failed. * * `sync` policy (documented choice): the target enabled set is the UNION of * the plugins enabled in either host. It is additive: a plugin missing from a * host is installed there; nothing is ever removed; a plugin a host has * installed but explicitly disabled is left disabled and reported. */ import { type HostId, type HostInvocation, type HostSystemDeps } from './host-executable.js'; export * from './host-executable.js'; export type HostAction = 'install' | 'update' | 'uninstall' | 'enable' | 'disable'; export type HostScope = 'user' | 'project' | 'local'; export declare const DEFAULT_MARKETPLACE_SOURCE = "ruvnet/ruflo"; export declare const DEFAULT_MARKETPLACE_NAME = "ruflo"; export declare class HostPluginInputError extends Error { } /** Validate a plugin name (or `name@`) before it can reach an argv. */ export declare function validatePluginName(raw: string, marketplaceName?: string): string; export declare function validateMarketplace(source: string, name: string): void; export interface MarketplaceRef { source: string; name: string; } /** One argv to run against one host. */ export interface HostStep { argv: string[]; purpose: string; } export type HostArgvPlan = { supported: true; steps: HostStep[]; } | { supported: false; reason: string; manual: string; }; /** Pure argv builder for a plugin action on one host. */ export declare function buildActionArgv(host: HostId, action: HostAction, plugin: string, scope: HostScope, mp: MarketplaceRef): HostArgvPlan; export declare function buildMarketplaceArgv(host: HostId, op: 'add' | 'update', mp: MarketplaceRef): string[]; export declare function buildListArgv(kind: 'plugins' | 'marketplaces'): string[]; export interface HostPluginState { version: string; enabled: boolean; } export interface HostState { plugins: Map; /** null: no marketplace with our name. Otherwise its normalized source. */ marketplaceSource: string | null; } /** github repo / git URL / local path → comparable form (`owner/repo` or `dir:`). */ export declare function normalizeMarketplaceSource(raw: string): string; /** Parse ` plugin list --json` + ` plugin marketplace list --json`. */ export declare function parseHostState(host: HostId, pluginsJson: string, marketplacesJson: string, mp: MarketplaceRef, scope: HostScope, cwd: string): HostState; export type HostOutcome = 'ok' | 'unchanged' | 'planned' | 'failed' | 'unsupported' | 'refused' | 'not-detected'; export interface HostStepResult { argv: string[]; display: string; purpose: string; ok?: boolean; stderr?: string; error?: string; } export interface HostTargetResult { host: HostId; /** Plugin name, or `(marketplace)` for a marketplace step. */ target: string; outcome: HostOutcome; steps: HostStepResult[]; message?: string; manual?: string; } export interface HostOperationReport { action: HostAction | 'sync'; dryRun: boolean; ok: boolean; results: HostTargetResult[]; } export type HostSelection = 'claude' | 'codex' | 'both' | 'auto'; export interface HostOperationOptions { hosts?: HostSelection; scope?: HostScope; marketplace?: Partial; dryRun?: boolean; cwd?: string; } export interface SyncPlanEntry { host: HostId; target: string; argv: string[] | null; note: string; } /** * Pure sync planner. Marketplace first (add when absent, refresh when it is * the canonical source, refuse a foreign source), then union-of-enabled installs. */ export declare function planSync(states: Record, mp: MarketplaceRef): SyncPlanEntry[]; export interface StatusRow { plugin: string; claude: HostPluginState | null; codex: HostPluginState | null; drift: string[]; } export declare function computeStatus(states: Partial>): StatusRow[]; export declare class HostPluginManager { private readonly deps; constructor(deps?: HostSystemDeps); private marketplace; /** Resolve every requested host before anything mutates. */ resolveHosts(selection?: HostSelection): Promise<{ present: HostInvocation[]; missing: HostTargetResult[]; required: Set; }>; private readState; private execSteps; /** install | update | uninstall | enable | disable on every selected host. */ apply(action: HostAction, rawPlugins: string[], opts?: HostOperationOptions): Promise; /** Make both hosts match: same marketplace, union of enabled plugins (additive). */ sync(opts?: HostOperationOptions): Promise; /** Installed version per plugin per host, with drift flags. Read-only. */ status(opts?: HostOperationOptions): Promise<{ ok: boolean; rows: StatusRow[]; hosts: HostTargetResult[]; marketplaces: Partial>; }>; } //# sourceMappingURL=host-plugin-manager.d.ts.map