Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:39:56 +08:00
commit e862bbb341
40 changed files with 10597 additions and 0 deletions

View File

@@ -0,0 +1,796 @@
# Claude Code Plugin Development Best Practices
This guide covers best practices for developing high-quality, maintainable, and secure Claude Code plugins.
## Code Quality Standards
### TypeScript Best Practices
#### Configuration
```json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
```
#### Interface Design
```typescript
// Use clear interfaces
interface PluginConfig {
name: string;
version: string;
settings: PluginSettings;
}
interface PluginSettings {
enabled: boolean;
autoUpdate: boolean;
customOptions: Record<string, unknown>;
}
// Use generic types for flexibility
class PluginManager<T extends PluginConfig> {
private plugins: Map<string, T> = new Map();
register(plugin: T): void {
this.plugins.set(plugin.name, plugin);
}
get<K extends keyof T>(name: string, key: K): T[K] | undefined {
const plugin = this.plugins.get(name);
return plugin?.[key];
}
}
```
#### Error Handling
```typescript
// Implement proper error handling
class PluginError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly pluginName: string
) {
super(message);
this.name = 'PluginError';
}
}
// Use async/await for asynchronous operations
async function loadPlugin(pluginPath: string): Promise<Plugin> {
try {
const manifest = await loadManifest(pluginPath);
const plugin = await import(pluginPath);
return new plugin.default(manifest);
} catch (error) {
throw new PluginError(`Failed to load plugin from ${pluginPath}`, 'LOAD_ERROR', pluginPath);
}
}
```
### Code Organization
#### Directory Structure
```
src/
├── types/
│ ├── plugin.ts
│ ├── command.ts
│ └── skill.ts
├── core/
│ ├── plugin-manager.ts
│ ├── command-registry.ts
│ └── skill-loader.ts
├── utils/
│ ├── file-utils.ts
│ ├── validation.ts
│ └── logger.ts
├── commands/
│ ├── base-command.ts
│ └── implementations/
├── skills/
│ ├── base-skill.ts
│ └── implementations/
└── index.ts
```
#### Naming Conventions
```typescript
// Use descriptive names
class PluginConfigurationValidator {} // Good
class PCV {} // Bad
// Use consistent patterns
interface PluginManifest {} // Interface
class PluginLoader {} // Class
const DEFAULT_PLUGIN_PATH = '/plugins'; // Constant
function validatePluginManifest() {} // Function
// File naming
plugin - manager.ts; // kebab-case for files
PluginManager; // PascalCase for classes
validatePlugin(); // camelCase for functions
```
## Performance Optimization
### Lazy Loading
```typescript
class PluginRegistry {
private plugins = new Map<string, () => Promise<Plugin>>();
private loadedPlugins = new Map<string, Plugin>();
async get(name: string): Promise<Plugin> {
// Check if already loaded
if (this.loadedPlugins.has(name)) {
return this.loadedPlugins.get(name)!;
}
// Load plugin on demand
const loader = this.plugins.get(name);
if (!loader) {
throw new Error(`Plugin not found: ${name}`);
}
const plugin = await loader();
this.loadedPlugins.set(name, plugin);
return plugin;
}
}
```
### Caching Strategies
```typescript
interface CacheEntry<T> {
value: T;
timestamp: number;
ttl: number;
}
class Cache<T> {
private cache = new Map<string, CacheEntry<T>>();
set(key: string, value: T, ttl: number = 300000): void {
// 5 minutes default
this.cache.set(key, {
value,
timestamp: Date.now(),
ttl,
});
}
get(key: string): T | undefined {
const entry = this.cache.get(key);
if (!entry) {
return undefined;
}
if (Date.now() - entry.timestamp > entry.ttl) {
this.cache.delete(key);
return undefined;
}
return entry.value;
}
// Cleanup expired entries
cleanup(): void {
const now = Date.now();
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > entry.ttl) {
this.cache.delete(key);
}
}
}
}
```
### Resource Management
```typescript
class ResourceManager {
private resources = new Set<() => Promise<void>>();
register(cleanup: () => Promise<void>): void {
this.resources.add(cleanup);
}
async cleanup(): Promise<void> {
const cleanupPromises = Array.from(this.resources).map(async cleanup => {
try {
await cleanup();
} catch (error) {
console.error('Cleanup error:', error);
}
});
await Promise.allSettled(cleanupPromises);
this.resources.clear();
}
}
// Usage with automatic cleanup
class Plugin {
private resourceManager = new ResourceManager();
async initialize(): Promise<void> {
// Register cleanup functions
this.resourceManager.register(async () => {
await this.closeConnections();
});
this.resourceManager.register(async () => {
await this.cleanupTempFiles();
});
}
async destroy(): Promise<void> {
await this.resourceManager.cleanup();
}
}
```
## Security Considerations
### Input Validation
```typescript
import Joi from 'joi';
const pluginConfigSchema = Joi.object({
name: Joi.string().alphanum().min(1).max(50).required(),
version: Joi.string()
.pattern(/^\d+\.\d+\.\d+$/)
.required(),
description: Joi.string().max(500).optional(),
permissions: Joi.array().items(Joi.string()).optional(),
});
class PluginValidator {
static validateConfig(config: unknown): PluginConfig {
const { error, value } = pluginConfigSchema.validate(config);
if (error) {
throw new ValidationError(`Invalid plugin configuration: ${error.message}`);
}
return value;
}
static sanitizeInput(input: string): string {
return input
.replace(/[<>]/g, '') // Remove HTML tags
.replace(/javascript:/gi, '') // Remove javascript protocol
.trim()
.substring(0, 1000); // Limit length
}
}
```
### Permission Management
```typescript
enum Permission {
FILE_READ = 'file:read',
FILE_WRITE = 'file:write',
NETWORK_REQUEST = 'network:request',
SYSTEM_EXEC = 'system:exec',
ENV_READ = 'env:read',
}
class PermissionManager {
private permissions = new Set<Permission>();
constructor(permissions: Permission[]) {
this.permissions = new Set(permissions);
}
has(permission: Permission): boolean {
return this.permissions.has(permission);
}
require(permission: Permission): void {
if (!this.has(permission)) {
throw new SecurityError(`Permission required: ${permission}`);
}
}
checkFileAccess(path: string, mode: 'read' | 'write'): void {
const permission = mode === 'read' ? Permission.FILE_READ : Permission.FILE_WRITE;
this.require(permission);
// Additional path validation
if (path.includes('..')) {
throw new SecurityError('Path traversal detected');
}
if (path.startsWith('/etc/') || path.startsWith('/sys/')) {
throw new SecurityError('Access to system directories denied');
}
}
}
```
### Secure Plugin Execution
```typescript
interface SecureExecutionContext {
permissions: Permission[];
timeout: number;
memoryLimit: number;
}
class SecurePluginRunner {
async executePlugin(plugin: Plugin, context: SecureExecutionContext): Promise<unknown> {
const permissionManager = new PermissionManager(context.permissions);
const monitor = new ResourceMonitor(context.memoryLimit);
try {
// Set up timeout
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Plugin execution timeout')), context.timeout);
});
// Execute plugin with monitoring
const executionPromise = this.executeWithMonitoring(plugin, permissionManager, monitor);
const result = await Promise.race([executionPromise, timeoutPromise]);
return result;
} finally {
monitor.stop();
}
}
}
```
## Error Handling and Logging
### Structured Error Handling
```typescript
abstract class PluginError extends Error {
abstract readonly code: string;
abstract readonly category: ErrorCategory;
constructor(
message: string,
public readonly context?: Record<string, unknown>
) {
super(message);
this.name = this.constructor.name;
}
toJSON(): ErrorRecord {
return {
name: this.name,
message: this.message,
code: this.code,
category: this.category,
context: this.context,
stack: this.stack,
timestamp: new Date().toISOString(),
};
}
}
enum ErrorCategory {
CONFIGURATION = 'configuration',
EXECUTION = 'execution',
VALIDATION = 'validation',
NETWORK = 'network',
FILESYSTEM = 'filesystem',
SECURITY = 'security',
}
```
### Comprehensive Logging
```typescript
interface LogEntry {
level: LogLevel;
message: string;
timestamp: string;
context?: Record<string, unknown>;
error?: ErrorRecord;
plugin?: string;
operation?: string;
}
class Logger {
private transports: LogTransport[] = [];
constructor(private minLevel: LogLevel = LogLevel.INFO) {}
addTransport(transport: LogTransport): void {
this.transports.push(transport);
}
debug(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.DEBUG, message, context);
}
info(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.INFO, message, context);
}
warn(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.WARN, message, context);
}
error(message: string, error?: Error, context?: Record<string, unknown>): void {
const errorRecord = error
? {
name: error.name,
message: error.message,
stack: error.stack,
}
: undefined;
this.log(LogLevel.ERROR, message, context, errorRecord);
}
private log(
level: LogLevel,
message: string,
context?: Record<string, unknown>,
error?: ErrorRecord
): void {
if (level < this.minLevel) {
return;
}
const entry: LogEntry = {
level,
message,
timestamp: new Date().toISOString(),
context,
error,
plugin: context?.plugin as string,
operation: context?.operation as string,
};
this.transports.forEach(transport => {
try {
transport.log(entry);
} catch (transportError) {
console.error('Transport error:', transportError);
}
});
}
}
```
## Testing Strategies
### Unit Testing
```typescript
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { PluginManager } from '../src/plugin-manager';
import { MockPlugin } from './mocks/mock-plugin';
describe('PluginManager', () => {
let pluginManager: PluginManager;
beforeEach(() => {
pluginManager = new PluginManager();
});
afterEach(() => {
pluginManager.cleanup();
});
describe('registerPlugin', () => {
it('should register a valid plugin', () => {
const plugin = new MockPlugin('test-plugin', '1.0.0');
expect(() => pluginManager.register(plugin)).not.toThrow();
expect(pluginManager.isRegistered('test-plugin')).toBe(true);
});
it('should reject plugin with invalid name', () => {
const plugin = new MockPlugin('', '1.0.0');
expect(() => pluginManager.register(plugin)).toThrow(
'Plugin name must be a non-empty string'
);
});
});
});
```
### Integration Testing
```typescript
describe('Plugin Integration', () => {
let client: ClaudeCodeClient;
let server: TestServer;
beforeAll(async () => {
server = new TestServer();
await server.start();
client = new ClaudeCodeClient({
endpoint: server.getUrl(),
timeout: 5000,
});
});
afterAll(async () => {
await server.stop();
});
it('should install and execute plugin end-to-end', async () => {
// Install plugin
const installResult = await client.installPlugin({
name: 'integration-test-plugin',
version: '1.0.0',
source: './test-fixtures/integration-plugin',
});
expect(installResult.success).toBe(true);
// Execute command
const commandResult = await client.executeCommand('/integration-test', {
input: 'test data',
});
expect(commandResult.success).toBe(true);
expect(commandResult.output).toContain('processed: test data');
});
});
```
### Performance Testing
```typescript
describe('Performance Tests', () => {
it('should handle high load without memory leaks', async () => {
const monitor = new PerformanceMonitor();
const plugin = new TestPlugin();
const initialMemory = process.memoryUsage().heapUsed;
const iterations = 1000;
for (let i = 0; i < iterations; i++) {
await monitor.measure(() => plugin.process(`test-data-${i}`), 'process-operation');
}
const finalMemory = process.memoryUsage().heapUsed;
const memoryIncrease = finalMemory - initialMemory;
// Memory increase should be reasonable (less than 10MB)
expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024);
});
});
```
## Documentation Standards
### Code Documentation
````typescript
/**
* Plugin manager for handling plugin lifecycle and execution.
*
* This class provides a centralized way to manage Claude Code plugins,
* including registration, execution, and cleanup operations.
*
* @example
* ```typescript
* const manager = new PluginManager();
* const plugin = new MyPlugin();
*
* manager.register(plugin);
* const result = await manager.executeCommand('my-command', { param: 'value' });
* ```
*/
export class PluginManager {
/**
* Registers a plugin with the manager.
*
* @param plugin - The plugin to register
* @throws {ValidationError} If plugin validation fails
* @throws {DuplicateError} If a plugin with the same name is already registered
*/
register(plugin: Plugin): void {
this.validatePlugin(plugin);
this.checkDuplicate(plugin.name);
this.plugins.set(plugin.name, plugin);
}
}
````
### README Template
````markdown
# Plugin Name
> Brief description of what the plugin does
## Features
- Feature 1
- Feature 2
- Feature 3
## Installation
```bash
claude marketplace install plugin-name
```
````
## Usage
### Basic Usage
```bash
/command-name --param=value
```
## Configuration
Add to your `.claude/settings.json`:
```json
{
"plugins": {
"plugin-name": {
"setting1": "value1",
"setting2": "value2"
}
}
}
```
## Development
### Building
```bash
npm run build
```
### Testing
```bash
npm test
```
## License
License information.
````
## Version Management
### Semantic Versioning
```typescript
class VersionManager {
static parseVersion(version: string): Version {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
if (!match) {
throw new Error(`Invalid version format: ${version}`);
}
return {
major: parseInt(match[1], 10),
minor: parseInt(match[2], 10),
patch: parseInt(match[3], 10),
prerelease: match[4] || null,
};
}
static compareVersions(v1: string, v2: string): number {
const version1 = this.parseVersion(v1);
const version2 = this.parseVersion(v2);
if (version1.major !== version2.major) {
return version1.major - version2.major;
}
if (version1.minor !== version2.minor) {
return version1.minor - version2.minor;
}
if (version1.patch !== version2.patch) {
return version1.patch - version2.patch;
}
return 0;
}
}
````
## Design Patterns
### Plugin Factory Pattern
```typescript
abstract class PluginFactory {
abstract create(config: PluginConfig): Plugin;
static register(type: string, factory: PluginFactory): void {
this.factories.set(type, factory);
}
static create(type: string, config: PluginConfig): Plugin {
const factory = this.factories.get(type);
if (!factory) {
throw new Error(`Unknown plugin type: ${type}`);
}
return factory.create(config);
}
private static factories = new Map<string, PluginFactory>();
}
```
### Observer Pattern for Plugin Events
```typescript
class PluginEventEmitter {
private handlers = new Map<string, PluginEventHandler[]>();
on(eventType: string, handler: PluginEventHandler): void {
if (!this.handlers.has(eventType)) {
this.handlers.set(eventType, []);
}
this.handlers.get(eventType)!.push(handler);
}
emit(event: PluginEvent): void {
const handlers = this.handlers.get(event.type);
if (handlers) {
handlers.forEach(handler => {
try {
handler(event);
} catch (error) {
console.error(`Error in event handler for ${event.type}:`, error);
}
});
}
}
}
```
## Quality Assurance Checklist
### Before Release
- [ ] Code follows all style guidelines
- [ ] All tests pass successfully
- [ ] Documentation is complete and accurate
- [ ] Security review passed
- [ ] Performance benchmarks met
- [ ] Plugin tested in multiple environments
- [ ] Error handling comprehensive
- [ ] Dependencies validated
### Code Review
- [ ] Functions have clear single responsibilities
- [ ] Error handling is comprehensive
- [ ] Logging is appropriate and informative
- [ ] Tests cover edge cases
- [ ] Security considerations are addressed
- [ ] Performance implications are considered
---
_Following these best practices will help ensure your Claude Code plugins are high-quality, secure, and well-maintained._

View File

@@ -0,0 +1,201 @@
# Claude Code Plugin Quick Start
This reference provides a quick-start guide for creating your first Claude Code plugin.
## Prerequisites
- Claude Code installed and working
- Basic knowledge of TypeScript/JavaScript
- Text editor (VS Code recommended)
- Git for version control
## Step 1: Create Plugin Structure
```bash
mkdir my-first-plugin
cd my-first-plugin
mkdir -p .claude-plugin commands skills agents hooks
```
## Step 2: Create Plugin Manifest
Create `.claude-plugin/plugin.json`:
```json
{
"name": "my-first-plugin",
"version": "1.0.0",
"description": "My first Claude Code plugin",
"author": "Your Name",
"license": "MIT",
"repository": "https://github.com/username/my-first-plugin",
"main": "index.js",
"claude": {
"minVersion": "1.0.0",
"maxVersion": "2.0.0"
},
"permissions": ["file:read", "file:write", "network:request"],
"dependencies": {},
"keywords": ["utility", "productivity"]
}
```
## Step 3: Add a Custom Command
Create `commands/hello.md`:
````markdown
---
name: hello
description: 'Say hello with a custom message'
parameters:
- name: name
type: string
description: 'Name to greet'
required: false
default: 'World'
---
Hello! This is a custom command from my first plugin.
## Usage
```bash
/hello --name="Claude"
```
````
## Output
```
Hello, Claude! This message comes from my-first-plugin.
```
````
## Step 4: Create a Skill
Create `skills/my-skill/SKILL.md`:
```markdown
---
name: my-skill
description: "A simple skill for demonstration"
category: utility
tags: ["demo", "example"]
triggers:
- type: keyword
pattern: "demo task"
priority: 2
---
This skill demonstrates basic plugin functionality.
## When to Use
Use this skill when you need to perform simple demonstration tasks.
## Capabilities
- Basic text processing
- Simple calculations
- File operations
- Example workflows
````
## Step 5: Test Your Plugin
```bash
# Install plugin locally
claude marketplace install ./my-first-plugin
# Test the command
claude
/hello --name="Test User"
# Test the skill
claude
I need help with a demo task
```
## Step 6: Package for Distribution
```bash
# Create distribution package
claude plugin package
# Or manually zip the plugin
zip -r my-first-plugin.zip . -x ".git/*" "node_modules/*" "dist/*"
```
## Common Templates
### Basic Command Template
````markdown
---
name: command-name
description: 'Brief description of the command'
parameters:
- name: param1
type: string
description: 'Description of parameter'
required: true
- name: param2
type: boolean
description: 'Description of optional parameter'
required: false
default: false
---
Command description and usage examples.
## Examples
```bash
/command-name --param1="value" --param2
```
````
````
### Basic Skill Template
```markdown
---
name: skill-name
description: "Brief description of the skill"
category: utility
tags: ["tag1", "tag2"]
triggers:
- type: keyword
pattern: "trigger phrase"
priority: 2
---
Skill description explaining when and how to use it.
## When to Use
Use this skill when you need to...
## Capabilities
List of what the skill can do.
````
## Next Steps
1. Add more commands and skills
2. Implement custom logic
3. Add configuration options
4. Write tests
5. Create documentation
6. Publish to marketplace
## Resources
- [Full Plugin Development Guide](../plugin-development-guide.md)
- [API Reference](../api-reference.md)
- [Best Practices](../best-practices.md)
- [Troubleshooting Guide](../troubleshooting.md)

View File

@@ -0,0 +1,585 @@
# Claude Code Plugin Troubleshooting Guide
This guide provides solutions to common problems encountered when developing, installing, or using Claude Code plugins.
## Installation Issues
### Plugin Not Found
**Symptoms**: Plugin cannot be found in marketplace or installation fails with "plugin not found" error.
**Causes**:
- Incorrect plugin name or marketplace
- Marketplace not configured properly
- Network connectivity issues
- Plugin repository not accessible
**Solutions**:
```bash
# Check available marketplaces
claude marketplace list
# Search for the plugin
claude marketplace search plugin-name
# Add missing marketplace
claude marketplace add https://github.com/marketplace-url
# Verify marketplace connectivity
curl -I https://github.com/marketplace-url
# Install with full specification
claude marketplace install plugin-name@marketplace-name
```
**Debug Steps**:
1. Verify marketplace configuration in `~/.claude/settings.json`
2. Check network connectivity
3. Validate plugin name spelling
4. Confirm plugin exists in specified marketplace
### Permission Denied During Installation
**Symptoms**: Installation fails with permission errors.
**Causes**:
- Insufficient file system permissions
- Protected directories
- Antivirus software blocking installation
**Solutions**:
```bash
# Check directory permissions
ls -la ~/.claude/
ls -la ~/.claude/plugins/
# Fix permissions (use with caution)
chmod -R 755 ~/.claude/
chmod 600 ~/.claude/settings.json
# Install in alternative directory
mkdir -p ~/claude-plugins
export CLAUDE_PLUGIN_DIR=~/claude-plugins
claude marketplace install plugin-name
```
### Version Conflicts
**Symptoms**: Installation fails due to version conflicts with dependencies.
**Causes**:
- Incompatible dependency versions
- Semantic versioning constraints
- Circular dependencies
**Solutions**:
```bash
# Check dependency tree
claude plugin deps plugin-name
# Force specific version
claude marketplace install plugin-name@1.2.3
# Resolve conflicts automatically
claude plugin resolve-conflicts
# Clean installation
claude plugin uninstall plugin-name
claude marketplace install plugin-name --force
```
## Runtime Errors
### Plugin Loading Failures
**Symptoms**: Plugin fails to load during startup.
**Causes**:
- Missing dependencies
- Code syntax errors
- Initialization failures
**Debug Commands**:
```bash
# Enable debug logging
export CLAUDE_DEBUG=true
claude --verbose
# Check plugin status
claude plugin list
claude plugin status plugin-name
# Load plugin manually
claude plugin load plugin-name --debug
# Check logs
tail -f ~/.claude/logs/plugin-loading.log
```
**Example Debug Code**:
```typescript
// plugin-loader.ts
class PluginLoader {
async loadPlugin(pluginPath: string): Promise<Plugin> {
try {
console.log(`Loading plugin from: ${pluginPath}`);
// Validate manifest
const manifest = await this.loadManifest(pluginPath);
console.log(`Plugin manifest loaded: ${manifest.name}@${manifest.version}`);
// Check dependencies
await this.checkDependencies(manifest);
console.log('Dependencies verified');
// Load plugin module
const PluginClass = await import(path.join(pluginPath, manifest.main));
const plugin = new PluginClass.default(manifest);
// Initialize plugin
await plugin.initialize(this.createPluginContext(manifest));
console.log(`Plugin initialized successfully: ${manifest.name}`);
return plugin;
} catch (error) {
console.error(`Failed to load plugin from ${pluginPath}:`, error);
throw error;
}
}
}
```
### Command Execution Failures
**Symptoms**: Plugin commands fail to execute or return errors.
**Debug Steps**:
```bash
# Execute command with debug information
claude /command-name --param=value --debug
# Check command registration
claude plugin commands plugin-name
# Test command in isolation
claude plugin test-command plugin-name command-name --params '{"key":"value"}'
```
**Error Handling Template**:
```typescript
// command-handler.ts
class CommandHandler {
async handleCommand(
command: Command,
parameters: Record<string, unknown>,
context: CommandContext
): Promise<CommandResult> {
try {
context.logger.debug(`Executing command: ${command.name}`, { parameters });
// Validate parameters
await this.validateParameters(command, parameters);
// Execute command
const result = await command.handler(parameters, context);
context.logger.debug(`Command executed successfully: ${command.name}`);
return result;
} catch (error) {
context.logger.error(`Command execution failed: ${command.name}`, error);
return {
success: false,
error: {
message: error.message,
code: error.code || 'COMMAND_ERROR',
details: this.extractErrorDetails(error),
},
};
}
}
}
```
### Skill Invocation Issues
**Symptoms**: Skills are not being triggered or are failing to execute.
**Debug Solutions**:
```bash
# Check available skills
claude skill list
# Test skill manually
claude skill test skill-name "test input"
# Check skill triggers
claude skill triggers skill-name
# Enable skill debugging
export CLAUDE_SKILL_DEBUG=true
```
## Performance Issues
### Slow Plugin Loading
**Optimization Strategies**:
1. **Lazy Loading**:
```typescript
class LazyPluginManager {
private plugins = new Map<string, () => Promise<Plugin>>();
private loadedPlugins = new Map<string, Plugin>();
async getPlugin(name: string): Promise<Plugin> {
if (this.loadedPlugins.has(name)) {
return this.loadedPlugins.get(name)!;
}
const loader = this.plugins.get(name);
if (!loader) {
throw new Error(`Plugin not found: ${name}`);
}
const plugin = await loader();
this.loadedPlugins.set(name, plugin);
return plugin;
}
}
```
2. **Async Initialization**:
```typescript
class AsyncPluginInitializer {
async initializePlugins(plugins: Plugin[]): Promise<void> {
const initPromises = plugins.map(plugin =>
this.initializePlugin(plugin).catch(error => {
console.error(`Failed to initialize plugin ${plugin.name}:`, error);
return null;
})
);
await Promise.allSettled(initPromises);
}
}
```
### Memory Leaks
**Detection and Solutions**:
```typescript
// memory-monitor.ts
class MemoryMonitor {
private snapshots: MemorySnapshot[] = [];
private readonly maxSnapshots = 100;
takeSnapshot(label: string): void {
const usage = process.memoryUsage();
const snapshot: MemorySnapshot = {
label,
timestamp: Date.now(),
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
external: usage.external,
};
this.snapshots.push(snapshot);
this.checkMemoryGrowth();
}
private checkMemoryGrowth(): void {
if (this.snapshots.length < 10) return;
const recent = this.snapshots.slice(-10);
const older = this.snapshots.slice(-20, -10);
if (older.length === 0) return;
const recentAvg = recent.reduce((sum, s) => sum + s.heapUsed, 0) / recent.length;
const olderAvg = older.reduce((sum, s) => sum + s.heapUsed, 0) / older.length;
const growth = (recentAvg - olderAvg) / olderAvg;
if (growth > 0.5) {
// 50% growth
console.warn(`Memory growth detected: ${(growth * 100).toFixed(1)}%`);
}
}
}
```
## Security and Permissions
### Permission Denied Errors
**Solutions**:
```bash
# Check current permissions
claude permissions list
# Grant specific permissions
claude permissions grant plugin-name filesystem:read
claude permissions grant plugin-name network:request
# Check permission usage
claude permissions audit plugin-name
# Reset permissions
claude permissions reset plugin-name
```
**Permission Management Implementation**:
```typescript
// permission-manager.ts
class PermissionManager {
private permissions = new Set<Permission>();
has(permission: Permission): boolean {
return this.permissions.has(permission);
}
require(permission: Permission): void {
if (!this.has(permission)) {
throw new PermissionError(`Permission required: ${permission}`);
}
}
checkFileAccess(path: string, mode: 'read' | 'write'): void {
const permission = mode === 'read' ? Permission.FILE_READ : Permission.FILE_WRITE;
this.require(permission);
// Security checks
this.validatePath(path);
}
private validatePath(path: string): void {
// Prevent path traversal
if (path.includes('..')) {
throw new SecurityError('Path traversal detected');
}
// Prevent access to sensitive directories
const restrictedPaths = ['/etc', '/sys', '/proc', '~/.ssh'];
for (const restricted of restrictedPaths) {
if (path.startsWith(restricted)) {
throw new SecurityError(`Access to ${restricted} is not allowed`);
}
}
}
}
```
## Development Debugging
### Local Development Setup
**Development Environment Setup**:
```bash
# Create development workspace
mkdir claude-plugin-dev
cd claude-plugin-dev
# Initialize development environment
npm init -y
npm install --save-dev typescript @types/node ts-node nodemon
# Create development configuration
cat > tsconfig.json << EOF
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
EOF
```
### Debug Logging
**Implementation**:
```typescript
// debug-logger.ts
class DebugLogger {
private logLevel: LogLevel;
private logFile?: string;
constructor(logLevel: LogLevel = LogLevel.INFO, logFile?: string) {
this.logLevel = logLevel;
this.logFile = logFile;
}
debug(message: string, data?: unknown): void {
this.log(LogLevel.DEBUG, message, data);
}
info(message: string, data?: unknown): void {
this.log(LogLevel.INFO, message, data);
}
warn(message: string, data?: unknown): void {
this.log(LogLevel.WARN, message, data);
}
error(message: string, error?: Error | unknown): void {
this.log(LogLevel.ERROR, message, error);
}
private log(level: LogLevel, message: string, data?: unknown): void {
if (level < this.logLevel) return;
const timestamp = new Date().toISOString();
const levelName = LogLevel[level];
const dataStr = data ? ` ${JSON.stringify(data)}` : '';
const logEntry = `[${timestamp}] ${levelName}: ${message}${dataStr}`;
console.log(logEntry);
if (this.logFile) {
this.writeToFile(logEntry);
}
}
}
```
## Advanced Troubleshooting
### Plugin Isolation
**Create isolated test environment**:
```bash
# Create isolated environment
claude environment create test-env
claude environment activate test-env
# Install only required plugins
claude marketplace install plugin-to-test
# Test in isolation
claude /test-command
# Clean up environment
claude environment deactivate
claude environment delete test-env
```
### Emergency Recovery
**Reset and recovery procedures**:
```bash
# Emergency plugin reset
claude plugin reset --all
# Backup current configuration
cp -r ~/.claude ~/.claude.backup.$(date +%Y%m%d-%H%M%S)
# Clean installation
rm -rf ~/.claude/plugins
claude marketplace reinstall-all
# Verify functionality
claude --help
claude plugin list
```
**Recovery Script**:
```bash
#!/bin/bash
# emergency-recovery.sh
set -euo pipefail
BACKUP_DIR="$HOME/.claude.backup.$(date +%Y%m%d-%H%M%S)"
CONFIG_DIR="$HOME/.claude"
echo "Claude Code Emergency Recovery"
echo "=============================="
# Create backup
echo "Creating backup in $BACKUP_DIR..."
if [ -d "$CONFIG_DIR" ]; then
cp -r "$CONFIG_DIR" "$BACKUP_DIR"
echo "✅ Backup created"
else
echo "⚠️ No existing configuration to backup"
fi
# Reset plugin configuration
echo "Resetting plugin configuration..."
rm -rf "$CONFIG_DIR/plugins"
mkdir -p "$CONFIG_DIR/plugins"
echo "✅ Emergency recovery completed"
echo "📁 Backup available at: $BACKUP_DIR"
echo "🔄 Please restart Claude Code"
```
## Getting Help
### Support Resources
1. **Official Documentation**: https://docs.claude.com
2. **Community Forums**: https://community.anthropic.com
3. **GitHub Issues**: https://github.com/anthropics/claude-code/issues
4. **Discord Community**: Claude Code Discord server
### Reporting Issues
When reporting issues, include:
- Claude Code version
- Plugin name and version
- Operating system and Node.js version
- Complete error messages and stack traces
- Steps to reproduce the issue
- Expected vs actual behavior
### Debug Information Collection
```bash
# Collect system information
claude --version
node --version
npm --version
# Collect plugin information
claude plugin list
claude plugin status
# Collect configuration
cat ~/.claude/settings.json
cat ~/.claude/marketplaces.json
# Collect logs
tail -n 100 ~/.claude/logs/*.log
```