mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-21 16:41:57 +08:00
Users need one settings surface to discover and install skills without manually navigating provider-specific directories. Add provider-backed global skill installation for Claude, Codex, Gemini, and Cursor, while keeping OpenCode read-only because it reuses other providers' skill locations. Add a responsive Skills settings tab with scoped discovery, search, refresh controls, markdown and folder uploads, upload feedback, and overflow-safe layouts. Validate bundled skill files and paths before writing them, preserve scripts and assets, and cover provider discovery and installation behavior with tests.
167 lines
5.9 KiB
TypeScript
167 lines
5.9 KiB
TypeScript
import type {
|
|
FetchHistoryOptions,
|
|
FetchHistoryResult,
|
|
LLMProvider,
|
|
McpScope,
|
|
NormalizedMessage,
|
|
ProviderSkill,
|
|
ProviderSkillListOptions,
|
|
ProviderAuthStatus,
|
|
ProviderChangeActiveModelInput,
|
|
ProviderCurrentActiveModel,
|
|
ProviderModelsDefinition,
|
|
ProviderMcpServer,
|
|
ProviderSessionActiveModelChange,
|
|
ProviderSkillCreateInput,
|
|
UpsertProviderMcpServerInput,
|
|
} from '@/shared/types.js';
|
|
|
|
//----------------- PROVIDER CONTRACT INTERFACES ------------
|
|
/**
|
|
* Main provider contract for CLI and SDK integrations.
|
|
*
|
|
* Each concrete provider owns its MCP/auth handlers plus the provider-specific
|
|
* logic for converting native events/history into the app's normalized shape.
|
|
*/
|
|
export interface IProvider {
|
|
readonly id: LLMProvider;
|
|
readonly models: IProviderModels;
|
|
readonly mcp: IProviderMcp;
|
|
readonly auth: IProviderAuth;
|
|
readonly skills: IProviderSkills;
|
|
readonly sessions: IProviderSessions;
|
|
readonly sessionSynchronizer: IProviderSessionSynchronizer;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER MODEL INTERFACE ------------
|
|
/**
|
|
* Model catalog contract for one provider.
|
|
*
|
|
* Implementations are responsible for resolving the provider's currently
|
|
* supported models and converting them into the shared
|
|
* `ProviderModelsDefinition` shape used by backend routes and frontend model
|
|
* pickers. The `DEFAULT` field should be the most appropriate default selection
|
|
* for that provider at the time the catalog is read.
|
|
*/
|
|
export interface IProviderModels {
|
|
/**
|
|
* Returns the provider's currently supported model catalog.
|
|
*/
|
|
getSupportedModels(): Promise<ProviderModelsDefinition>;
|
|
|
|
/**
|
|
* Returns the currently active model for one session or provider runtime.
|
|
*
|
|
* Implementations must use the provider-specific lookup mechanism approved
|
|
* for that provider and fall back only to the provider catalog default when
|
|
* no active model can be resolved.
|
|
*/
|
|
getCurrentActiveModel(sessionId?: string): Promise<ProviderCurrentActiveModel>;
|
|
|
|
/**
|
|
* Persists a session-scoped model override that the next resumed turn should
|
|
* honor for this provider.
|
|
*
|
|
* This does not require the provider to mutate an already running remote
|
|
* session in-place. Instead, adapters store the user's explicit model choice
|
|
* so the backend resume path can add the correct provider-native model option
|
|
* on the next CLI/SDK invocation for the same session.
|
|
*/
|
|
changeActiveModel(
|
|
input: ProviderChangeActiveModelInput,
|
|
): Promise<ProviderSessionActiveModelChange>;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER AUTH INTERFACE ------------
|
|
/**
|
|
* Auth contract for one provider.
|
|
*
|
|
* Implementations should return a complete installation/authentication status
|
|
* without throwing for normal "not installed" or "not authenticated" states.
|
|
*/
|
|
export interface IProviderAuth {
|
|
/**
|
|
* Checks whether the provider is installed and has usable credentials.
|
|
*/
|
|
getStatus(): Promise<ProviderAuthStatus>;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER SKILLS INTERFACE ------------
|
|
/**
|
|
* Skills contract for one provider.
|
|
*
|
|
* Implementations discover provider-native skill markdown locations and return
|
|
* normalized skill records with the exact command syntax expected by that
|
|
* provider. Each skill is read from a `SKILL.md` file under its skill directory.
|
|
*/
|
|
export interface IProviderSkills {
|
|
/**
|
|
* Lists all skills visible to this provider for the optional workspace.
|
|
*/
|
|
listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]>;
|
|
|
|
/**
|
|
* Writes one or more global user-scoped skills for this provider.
|
|
*
|
|
* Implementations should install the supplied markdown entries into the
|
|
* provider's writable user skill folder and return the normalized skill
|
|
* records that were written.
|
|
*/
|
|
addSkills(input: ProviderSkillCreateInput): Promise<ProviderSkill[]>;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER MCP INTERFACE ------------
|
|
/**
|
|
* MCP contract for one provider.
|
|
*
|
|
* Implementations must map provider-native MCP config formats to shared
|
|
* `ProviderMcpServer` records used by routes and frontend state.
|
|
*/
|
|
export interface IProviderMcp {
|
|
listServers(options?: { workspacePath?: string }): Promise<Record<McpScope, ProviderMcpServer[]>>;
|
|
listServersForScope(scope: McpScope, options?: { workspacePath?: string }): Promise<ProviderMcpServer[]>;
|
|
upsertServer(input: UpsertProviderMcpServerInput): Promise<ProviderMcpServer>;
|
|
removeServer(
|
|
input: { name: string; scope?: McpScope; workspacePath?: string },
|
|
): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER SESSION INTERFACE ------------
|
|
/**
|
|
* Session/history contract for one provider.
|
|
*
|
|
* Implementations normalize provider-specific events and message history into
|
|
* shared transport shapes consumed by API routes and realtime streams.
|
|
*/
|
|
export interface IProviderSessions {
|
|
normalizeMessage(raw: unknown, sessionId: string | null): NormalizedMessage[];
|
|
fetchHistory(sessionId: string, options?: FetchHistoryOptions): Promise<FetchHistoryResult>;
|
|
}
|
|
|
|
// ---------------------------
|
|
//----------------- PROVIDER SESSION SYNCHRONIZER INTERFACE ------------
|
|
/**
|
|
* Session indexing contract for one provider.
|
|
*
|
|
* Implementations scan provider-specific session artifacts on disk and upsert
|
|
* normalized session metadata into the database. The service layer uses this
|
|
* interface for both full rescans and single-file incremental sync triggered
|
|
* by filesystem watcher events.
|
|
*/
|
|
export interface IProviderSessionSynchronizer {
|
|
/**
|
|
* Scans provider session artifacts and upserts discovered sessions into DB.
|
|
*/
|
|
synchronize(since?: Date): Promise<number>;
|
|
|
|
/**
|
|
* Parses and upserts one provider artifact file without running a full scan.
|
|
*/
|
|
synchronizeFile(filePath: string): Promise<string | null>;
|
|
}
|