@felixgeelhaar/cclint
Version:
Catch CLAUDE.md drift before Claude misbehaves. Lints CLAUDE.md, skills, subagents, and hooks for Claude Code projects.
126 lines • 4.41 kB
TypeScript
import type { Plugin, PluginModule } from '../domain/CustomRule.js';
import type { RuleRegistry } from './RuleRegistry.js';
import type { PluginConfig } from '../domain/Config.js';
/**
* Result of plugin loading operation
*/
export interface PluginLoadResult {
loaded: string[];
failed: Array<{
name: string;
error: Error;
}>;
/**
* Plugins that were declared in configuration but NOT loaded because the
* out-of-band trust gate (see {@link LoadPluginsOptions.allowPlugins}) was
* not satisfied. These are never imported or executed.
*/
skipped: string[];
}
/**
* Options controlling how config-declared plugins are loaded.
*/
export interface LoadPluginsOptions {
/**
* Explicit trust gate. Config-declared plugins execute arbitrary code
* IN-PROCESS, so they are only loaded when the operator opts in out-of-band
* (e.g. the `--allow-plugins` CLI flag or `CCLINT_ALLOW_PLUGINS=1`). A linted
* repository's own config CANNOT set this, which closes the RCE where a
* malicious `.cclintrc.json` / `package.json#cclint` auto-loads a plugin.
*
* Defaults to `false` — plugins declared in config are skipped by default.
*/
allowPlugins?: boolean;
}
/**
* Handles dynamic loading and management of custom rule plugins
*/
export declare class PluginLoader {
private loadedPlugins;
private registry;
private pathValidator;
private trustedPlugins;
constructor(registry: RuleRegistry);
/**
* Dynamic import wrapper with security checks
*/
protected importPlugin(pluginName: string): Promise<PluginModule>;
/**
* Check if a plugin is from a trusted source
*/
private isPluginTrusted;
/**
* Load a single plugin by name
* @param pluginName The name/path of the plugin to load
* @param options Optional configuration for the plugin
*/
loadPlugin(pluginName: string, _options?: Record<string, unknown>): Promise<void>;
/**
* Check if a plugin name is already loaded
*/
private isPluginNameLoaded;
/**
* Check plugin for potential security issues
*/
private checkPluginSecurity;
/**
* Load multiple plugins from configuration.
*
* SECURITY: config-declared plugins are executed in-process. They are only
* loaded when `options.allowPlugins` is explicitly `true` (an out-of-band
* trust gate the linted repo cannot set). Otherwise every enabled plugin is
* reported in `result.skipped` and NOT imported.
*
* @param pluginConfigs Array of plugin configurations
* @param options Trust-gate options controlling whether plugins load
* @returns Result object with loaded, failed, and skipped plugins
*/
loadPluginsFromConfig(pluginConfigs: PluginConfig[], options?: LoadPluginsOptions): Promise<PluginLoadResult>;
/**
* Unload a plugin and all its rules
* @param pluginName The name of the plugin to unload
*/
unloadPlugin(pluginName: string): void;
/**
* Check if a plugin is currently loaded
* @param pluginName The name of the plugin to check
* @returns True if the plugin is loaded
*/
isPluginLoaded(pluginName: string): boolean;
/**
* Get information about a loaded plugin
* @param pluginName The name of the plugin
* @returns Plugin information or undefined if not loaded
*/
getPluginInfo(pluginName: string): Plugin | undefined;
/**
* Get all loaded plugin names
* @returns Array of loaded plugin names
*/
getLoadedPlugins(): string[];
/**
* Reload a plugin (unload and load again)
* @param pluginName The name of the plugin to reload
* @param options Optional new configuration
*/
reloadPlugin(pluginName: string, _options?: Record<string, unknown>): Promise<void>;
/**
* Validate plugin structure and requirements
* @param plugin The plugin to validate
* @param pluginName The name of the plugin for error messages
*/
private validatePlugin;
/**
* Get statistics about loaded plugins
*/
getStats(): {
loadedPlugins: number;
totalRulesFromPlugins: number;
pluginDetails: Array<{
name: string;
version: string;
rules: number;
}>;
};
}
//# sourceMappingURL=PluginLoader.d.ts.map