Creating Plugins
Learn how to create, test, and publish plugins that extend Cyberstrike’s functionality.
📸 SCREENSHOT: plugin-development.png
Plugin development workflow
Getting Started
Create Plugin Project
mkdir cyberstrike-plugin-mynamecd cyberstrike-plugin-mynamenpm init -yInstall Dependencies
npm install @cyberstrike/plugin typescriptnpm install -D @types/nodeConfigure TypeScript
{ "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "node", "declaration": true, "outDir": "dist", "strict": true }, "include": ["src/**/*"]}Configure Package
{ "name": "cyberstrike-plugin-security-checks", "version": "1.0.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "dev": "tsc --watch", "test": "vitest" }, "cyberstrike": { "plugin": true }, "peerDependencies": { "@cyberstrike/plugin": "^1.0.0" }, "keywords": [ "cyberstrike", "cyberstrike-plugin", "security" ]}Plugin Interface
Basic Plugin
import { CyberstrikePlugin, ToolHook, PluginContext} from '@cyberstrike/plugin';
export default class MyPlugin implements CyberstrikePlugin { name = 'my-plugin'; version = '1.0.0'; description = 'My custom Cyberstrike plugin';
// Optional initialization async initialize(context: PluginContext): Promise<void> { console.log('Plugin initialized'); }
// Optional cleanup async destroy(): Promise<void> { console.log('Plugin destroyed'); }
// Hook definitions hooks: ToolHook[] = [ { event: 'preToolUse', matcher: 'Bash', handler: this.validateCommand.bind(this) } ];
private async validateCommand(context: PreToolUseContext) { // Implementation return { action: 'continue' }; }}Plugin with Options
import { CyberstrikePlugin, PluginOptions } from '@cyberstrike/plugin';
interface MyPluginOptions extends PluginOptions { strictMode?: boolean; allowedCommands?: string[]; logLevel?: 'debug' | 'info' | 'warn' | 'error';}
export default class MyPlugin implements CyberstrikePlugin { name = 'my-plugin'; version = '1.0.0';
private options: MyPluginOptions;
constructor(options: MyPluginOptions = {}) { this.options = { strictMode: false, allowedCommands: [], logLevel: 'info', ...options }; }
async initialize(context: PluginContext): Promise<void> { if (this.options.strictMode) { this.enableStrictMode(); } }
// ... rest of implementation}Hook Implementation
PreToolUse Hook
import { PreToolUseContext, HookResult } from '@cyberstrike/plugin';
async function validateCommand( context: PreToolUseContext): Promise<HookResult> { const { tool, args, sessionId } = context;
// Validate if (isDangerous(args.command)) { return { action: 'block', message: 'Dangerous command blocked by security policy' }; }
// Modify arguments if (needsSanitization(args.command)) { return { action: 'continue', args: { ...args, command: sanitize(args.command) } }; }
// Continue normally return { action: 'continue' };}PostToolUse Hook
import { PostToolUseContext, HookResult } from '@cyberstrike/plugin';
async function logToolUsage( context: PostToolUseContext): Promise<HookResult> { const { tool, args, result, duration } = context;
await logger.log({ timestamp: new Date(), tool, args, success: result.success, duration });
// Optionally modify result if (containsSensitiveData(result.output)) { return { action: 'continue', result: { ...result, output: redactSensitiveData(result.output) } }; }
return { action: 'continue' };}Session Hooks
import { SessionContext } from '@cyberstrike/plugin';
async function onSessionStart(context: SessionContext): Promise<void> { // Initialize session-specific state await database.createSession(context.sessionId);}
async function onSessionEnd(context: SessionContext): Promise<void> { // Cleanup and reporting await generateSessionReport(context.sessionId); await database.closeSession(context.sessionId);}State Management
Plugin State
export default class StatefulPlugin implements CyberstrikePlugin { name = 'stateful-plugin'; version = '1.0.0';
private state: Map<string, any> = new Map();
hooks = [ { event: 'preToolUse', matcher: '*', handler: async (context) => { // Track tool usage const count = this.state.get('toolCount') || 0; this.state.set('toolCount', count + 1);
return { action: 'continue' }; } } ];
getToolCount(): number { return this.state.get('toolCount') || 0; }}Persistent State
import fs from 'fs/promises';
export default class PersistentPlugin implements CyberstrikePlugin { name = 'persistent-plugin'; version = '1.0.0';
private statePath = '/tmp/cyberstrike-plugin-state.json'; private state: Record<string, any> = {};
async initialize(): Promise<void> { try { const data = await fs.readFile(this.statePath, 'utf-8'); this.state = JSON.parse(data); } catch { this.state = {}; } }
async destroy(): Promise<void> { await fs.writeFile( this.statePath, JSON.stringify(this.state, null, 2) ); }}Testing
Unit Tests
import { describe, it, expect, vi } from 'vitest';import MyPlugin from '../index';
describe('MyPlugin', () => { it('should block dangerous commands', async () => { const plugin = new MyPlugin(); const context = { tool: 'Bash', args: { command: 'rm -rf /' }, sessionId: 'test-session' };
const result = await plugin.hooks[0].handler(context);
expect(result.action).toBe('block'); expect(result.message).toContain('dangerous'); });
it('should allow safe commands', async () => { const plugin = new MyPlugin(); const context = { tool: 'Bash', args: { command: 'ls -la' }, sessionId: 'test-session' };
const result = await plugin.hooks[0].handler(context);
expect(result.action).toBe('continue'); });});Integration Tests
import { createTestClient } from '@cyberstrike/plugin/testing';import MyPlugin from '../index';
describe('MyPlugin Integration', () => { it('should integrate with Cyberstrike', async () => { const client = await createTestClient({ plugins: [new MyPlugin()] });
// Test plugin behavior const result = await client.executeTool('Bash', { command: 'echo "hello"' });
expect(result.success).toBe(true); });});Local Development
Link Plugin
# In plugin directorynpm link
# In test projectnpm link cyberstrike-plugin-mynameConfigure for Testing
{ "plugins": [ "cyberstrike-plugin-myname" ]}Watch Mode
npm run dev# Plugin reloads on changesPublishing
Prepare for Publish
- Update version in package.json
- Update CHANGELOG.md
- Build the plugin
- Run tests
Publish to npm
npm run buildnpm testnpm publish --access publicPlugin Naming
Follow the convention:
cyberstrike-plugin-<name>@org/cyberstrike-plugin-<name>
Documentation
README Template
# cyberstrike-plugin-security-checks
Security validation plugin for Cyberstrike.
## Installation
\`\`\`bashnpm install cyberstrike-plugin-security-checks\`\`\`
## Configuration
\`\`\`json{ "plugins": [ { "name": "cyberstrike-plugin-security-checks", "options": { "strictMode": true } } ]}\`\`\`
## Features
- Blocks dangerous commands- Validates file operations- Logs security events
## Options
| Option | Type | Default | Description ||--------|------|---------|-------------|| strictMode | boolean | false | Enable strict validation |
## License
MITBest Practices
- Single responsibility - One plugin, one purpose
- Fast execution - Don’t block unnecessarily
- Error handling - Handle all error cases
- Type safety - Use TypeScript
- Documentation - Document all features
- Testing - Comprehensive test coverage
- Versioning - Follow semver
Tip
Start with a simple plugin that does one thing well, then expand functionality.
Related Documentation
- Plugin Hooks - Hook reference
- Config Hooks - Simple hooks
- Hooks Overview - Hook system basics