11/**
22 * Abstract base adapter — all integration adapters extend this
3+ *
4+ * Provides common functionality for executing skills through different backends
5+ * (Claude Code CLI, API endpoints, etc.) with health checking and reconnection support.
6+ *
7+ * @abstract
8+ * @example
9+ * ```typescript
10+ * class MyAdapter extends BaseAdapter {
11+ * readonly name = 'my-adapter';
12+ * readonly description = 'Connects to my backend';
13+ *
14+ * async isAvailable(): Promise<boolean> {
15+ * // Check if backend is accessible
16+ * return true;
17+ * }
18+ *
19+ * async execute(request: ExecutionRequest): Promise<ExecutionResult> {
20+ * // Execute skill and return results
21+ * return { response: '...', tokens: 100, latency: 500 };
22+ * }
23+ *
24+ * async healthCheck(): Promise<boolean> {
25+ * // Verify connection is healthy
26+ * return this.isAvailable();
27+ * }
28+ * }
29+ * ```
330 */
431
5- import type { ExecutionRequest , ExecutionResult , SkillVerification , AdapterInfo } from '../types/index.js' ;
32+ import type { ExecutionRequest , ExecutionResult , SkillVerification , AdapterInfo , HealthCheckResult } from '../types/index.js' ;
633
34+ /**
35+ * Base class for all integration adapters.
36+ *
37+ * Adapters connect the skill-lint framework to various execution backends,
38+ * enabling integration testing with real or simulated skill execution.
39+ */
740export abstract class BaseAdapter {
41+ /**
42+ * Unique adapter identifier (e.g., 'claude-code', 'mock', 'api')
43+ */
844 abstract readonly name : string ;
45+
46+ /**
47+ * Human-readable description of the adapter and its backend
48+ */
949 abstract readonly description : string ;
1050
51+ /**
52+ * Check if the adapter's backend is available and ready to execute skills.
53+ *
54+ * This is a lightweight check performed before test execution. For more
55+ * detailed health information, use `healthCheck()`.
56+ *
57+ * @returns True if backend is available, false otherwise
58+ *
59+ * @example
60+ * ```typescript
61+ * if (await adapter.isAvailable()) {
62+ * const result = await adapter.execute(request);
63+ * } else {
64+ * console.warn('Adapter not available, skipping test');
65+ * }
66+ * ```
67+ */
1168 abstract isAvailable ( ) : Promise < boolean > ;
69+
70+ /**
71+ * Verify that a specific skill is loaded and accessible through this adapter.
72+ *
73+ * @param skillId - Unique skill identifier (e.g., skill name or file path)
74+ * @returns Verification result with status and optional error details
75+ *
76+ * @example
77+ * ```typescript
78+ * const verification = await adapter.verifySkillLoaded('my-skill');
79+ * if (!verification.loaded) {
80+ * console.error(`Skill not loaded: ${verification.error}`);
81+ * }
82+ * ```
83+ */
1284 abstract verifySkillLoaded ( skillId : string ) : Promise < SkillVerification > ;
85+
86+ /**
87+ * Execute a skill with the given request parameters.
88+ *
89+ * This is the main adapter method for running integration tests. Implementations
90+ * should handle timeouts, retries, and error recovery internally.
91+ *
92+ * @param request - Execution request with prompt, skill context, and options
93+ * @returns Execution result with response, token usage, and performance metrics
94+ * @throws Should not throw - return error in ExecutionResult instead
95+ *
96+ * @example
97+ * ```typescript
98+ * const result = await adapter.execute({
99+ * prompt: 'Create a new React component',
100+ * skillId: 'react-component-creator',
101+ * timeout: 30000,
102+ * });
103+ *
104+ * if (result.error) {
105+ * console.error('Execution failed:', result.error);
106+ * } else {
107+ * console.log('Response:', result.response);
108+ * }
109+ * ```
110+ */
13111 abstract execute ( request : ExecutionRequest ) : Promise < ExecutionResult > ;
14112
113+ /**
114+ * Perform a comprehensive health check on the adapter and its backend.
115+ *
116+ * Unlike `isAvailable()`, this method performs thorough diagnostics including:
117+ * - Network connectivity
118+ * - Authentication status
119+ * - Resource availability (memory, disk space, API quotas)
120+ * - Backend responsiveness
121+ *
122+ * Default implementation delegates to `isAvailable()`. Override for more
123+ * detailed health monitoring.
124+ *
125+ * @returns Health check result with status and diagnostic details
126+ *
127+ * @example
128+ * ```typescript
129+ * const health = await adapter.healthCheck();
130+ * if (!health.healthy) {
131+ * console.error('Health check failed:', health.details);
132+ * if (health.reconnectable) {
133+ * await adapter.reconnect();
134+ * }
135+ * }
136+ * ```
137+ */
138+ async healthCheck ( ) : Promise < HealthCheckResult > {
139+ try {
140+ const available = await this . isAvailable ( ) ;
141+ return {
142+ healthy : available ,
143+ details : available ? 'Adapter is available' : 'Adapter is not available' ,
144+ reconnectable : ! available ,
145+ timestamp : Date . now ( ) ,
146+ } ;
147+ } catch ( error ) {
148+ return {
149+ healthy : false ,
150+ details : `Health check failed: ${ error instanceof Error ? error . message : String ( error ) } ` ,
151+ reconnectable : true ,
152+ timestamp : Date . now ( ) ,
153+ } ;
154+ }
155+ }
156+
157+ /**
158+ * Attempt to reconnect or reinitialize the adapter after a failure.
159+ *
160+ * Use this method to recover from transient errors, network interruptions,
161+ * or backend restarts. The adapter should attempt to restore full functionality.
162+ *
163+ * Default implementation is a no-op. Override to implement reconnection logic.
164+ *
165+ * @returns True if reconnection succeeded, false otherwise
166+ *
167+ * @example
168+ * ```typescript
169+ * if (!(await adapter.healthCheck()).healthy) {
170+ * console.log('Attempting to reconnect...');
171+ * if (await adapter.reconnect()) {
172+ * console.log('Reconnection successful');
173+ * } else {
174+ * console.error('Reconnection failed');
175+ * }
176+ * }
177+ * ```
178+ */
179+ async reconnect ( ) : Promise < boolean > {
180+ // Default: no reconnection logic
181+ // Subclasses should override if reconnection is supported
182+ return await this . isAvailable ( ) ;
183+ }
184+
185+ /**
186+ * Get adapter metadata and capabilities.
187+ *
188+ * @returns Adapter information including name, description, and capabilities
189+ *
190+ * @example
191+ * ```typescript
192+ * const info = adapter.getInfo();
193+ * console.log(`Using ${info.name}: ${info.description}`);
194+ * if (info.requiresApiKey) {
195+ * console.log('API key required');
196+ * }
197+ * ```
198+ */
15199 getInfo ( ) : AdapterInfo {
16200 return {
17201 name : this . name ,
@@ -21,6 +205,24 @@ export abstract class BaseAdapter {
21205 } ;
22206 }
23207
208+ /**
209+ * Clean up adapter resources (connections, processes, temp files, etc.).
210+ *
211+ * Called automatically after validation completes. Implementations should
212+ * release all resources and handle cleanup errors gracefully.
213+ *
214+ * Default implementation is a no-op. Override if cleanup is needed.
215+ *
216+ * @example
217+ * ```typescript
218+ * try {
219+ * await adapter.cleanup();
220+ * } catch (error) {
221+ * console.warn('Cleanup error:', error);
222+ * // Non-critical - continue anyway
223+ * }
224+ * ```
225+ */
24226 async cleanup ( ) : Promise < void > {
25227 // Default: no cleanup
26228 }
0 commit comments