@agiflowai/hooks-adapter 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # @agiflowai/hooks-adapter
2
+
3
+ Hook adapters for normalizing AI agent hook formats (Claude Code, Gemini, etc.). This library provides a unified interface for handling hooks from different AI coding agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @agiflowai/hooks-adapter
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Hook Execution
14
+
15
+ ```typescript
16
+ import { AdapterProxyService, PRE_TOOL_USE, POST_TOOL_USE } from '@agiflowai/hooks-adapter';
17
+ import { CLAUDE_CODE } from '@agiflowai/coding-agent-bridge';
18
+
19
+ // Define your hook callback
20
+ const myPreToolUseHook = async (context) => {
21
+ console.log('Tool:', context.toolName);
22
+ console.log('File:', context.filePath);
23
+
24
+ return {
25
+ decision: 'allow',
26
+ message: 'Proceeding with operation',
27
+ };
28
+ };
29
+
30
+ // Execute the hook
31
+ await AdapterProxyService.execute(CLAUDE_CODE, PRE_TOOL_USE, myPreToolUseHook);
32
+ ```
33
+
34
+ ### Hook Types
35
+
36
+ The library exports two hook type constants:
37
+
38
+ - `PRE_TOOL_USE` - Hook that runs before a tool is executed
39
+ - `POST_TOOL_USE` - Hook that runs after a tool is executed
40
+
41
+ ### Hook Context
42
+
43
+ The normalized `HookContext` passed to callbacks includes:
44
+
45
+ ```typescript
46
+ interface HookContext {
47
+ toolName: string; // Name of the tool (e.g., "Read", "Write", "Edit")
48
+ toolInput: Record<string, any>; // Input parameters
49
+ filePath?: string; // File path for file operations
50
+ operation?: 'read' | 'write' | 'edit'; // Operation type
51
+ cwd: string; // Current working directory
52
+ sessionId: string; // Unique session identifier
53
+ llmTool?: string; // Optional LLM tool identifier
54
+ }
55
+ ```
56
+
57
+ ### Hook Response
58
+
59
+ Callbacks should return a `HookResponse`:
60
+
61
+ ```typescript
62
+ interface HookResponse {
63
+ decision: 'allow' | 'deny' | 'ask' | 'skip'; // Permission decision
64
+ message: string; // Message for the LLM
65
+ userMessage?: string; // Optional message for the user only
66
+ updatedInput?: Record<string, any>; // Optional updated input parameters
67
+ }
68
+ ```
69
+
70
+ ### Decision Types
71
+
72
+ - `allow` - Allow the operation to proceed
73
+ - `deny` - Block the operation
74
+ - `ask` - Ask the user for confirmation
75
+ - `skip` - Skip the hook silently (no output)
76
+
77
+ ## Adapters
78
+
79
+ ### ClaudeCodeAdapter
80
+
81
+ Adapter for Claude Code PreToolUse hooks. Parses Claude Code's JSON stdin format and formats responses accordingly.
82
+
83
+ ### ClaudeCodePostToolUseAdapter
84
+
85
+ Adapter for Claude Code PostToolUse hooks. Handles post-execution hook format with tool response data.
86
+
87
+ ### BaseAdapter
88
+
89
+ Abstract base class for creating custom adapters. Implements the Template Method pattern for hook execution flow.
90
+
91
+ ## Services
92
+
93
+ ### AdapterProxyService
94
+
95
+ Routes hook execution to the appropriate adapter based on agent and hook type.
96
+
97
+ ```typescript
98
+ AdapterProxyService.execute(agentName, hookType, callback);
99
+ ```
100
+
101
+ ### ExecutionLogService
102
+
103
+ Tracks hook executions to prevent duplicate actions within a session.
104
+
105
+ ```typescript
106
+ // Check if already executed
107
+ const executed = await ExecutionLogService.hasExecuted(sessionId, filePath, decision);
108
+
109
+ // Log an execution
110
+ await ExecutionLogService.logExecution({
111
+ sessionId,
112
+ filePath,
113
+ operation: 'read',
114
+ decision: 'allow',
115
+ });
116
+
117
+ // Check if file has changed since last execution
118
+ const changed = await ExecutionLogService.hasFileChanged(sessionId, filePath, decision);
119
+ ```
120
+
121
+ ## License
122
+
123
+ AGPL-3.0
package/dist/index.cjs ADDED
@@ -0,0 +1,513 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let node_fs_promises = require("node:fs/promises");
25
+ node_fs_promises = __toESM(node_fs_promises);
26
+ let node_path = require("node:path");
27
+ node_path = __toESM(node_path);
28
+ let node_os = require("node:os");
29
+ node_os = __toESM(node_os);
30
+ let node_crypto = require("node:crypto");
31
+ node_crypto = __toESM(node_crypto);
32
+ let __agiflowai_coding_agent_bridge = require("@agiflowai/coding-agent-bridge");
33
+
34
+ //#region src/constants/index.ts
35
+ /**
36
+ * @agiflowai/hooks-adapter - Constants
37
+ *
38
+ * DESIGN PATTERNS:
39
+ * - Strongly-typed constant exports for compile-time safety
40
+ * - Immutable by default (as const assertions)
41
+ *
42
+ * CODING STANDARDS:
43
+ * - Primitive constants: UPPER_SNAKE_CASE
44
+ * - Always include JSDoc with purpose and usage
45
+ *
46
+ * AVOID:
47
+ * - Mutable exports (let, var)
48
+ * - Magic strings without explanation
49
+ */
50
+ /**
51
+ * Hook type identifiers for different hook events
52
+ */
53
+ const PRE_TOOL_USE = "PreToolUse";
54
+ const POST_TOOL_USE = "PostToolUse";
55
+
56
+ //#endregion
57
+ //#region src/adapters/BaseAdapter.ts
58
+ /**
59
+ * Abstract base adapter for normalizing AI agent hook formats
60
+ */
61
+ var BaseAdapter = class {
62
+ /**
63
+ * Execute hook callback with normalized context
64
+ * Template method that orchestrates the hook execution flow
65
+ *
66
+ * @param callback - Hook callback function to execute
67
+ */
68
+ async execute(callback) {
69
+ try {
70
+ const stdin = await this.readStdin();
71
+ const response = await callback(this.parseInput(stdin));
72
+ if (response.decision === "skip") {
73
+ process.exit(0);
74
+ return;
75
+ }
76
+ const output = this.formatOutput(response);
77
+ console.log(output);
78
+ process.exit(0);
79
+ } catch (error) {
80
+ this.handleError(error);
81
+ }
82
+ }
83
+ /**
84
+ * Read stdin from AI agent
85
+ * @returns Promise resolving to stdin content
86
+ */
87
+ readStdin() {
88
+ return new Promise((resolve, reject) => {
89
+ const chunks = [];
90
+ process.stdin.on("data", (chunk) => {
91
+ chunks.push(chunk);
92
+ });
93
+ process.stdin.on("end", () => {
94
+ resolve(Buffer.concat(chunks).toString("utf8"));
95
+ });
96
+ process.stdin.on("error", (error) => {
97
+ reject(error);
98
+ });
99
+ });
100
+ }
101
+ /**
102
+ * Handle errors with fail-open behavior
103
+ * Allows operation to proceed with warning message
104
+ *
105
+ * @param error - Error that occurred during hook execution
106
+ */
107
+ handleError(error) {
108
+ const errorMessage = error instanceof Error ? error.message : String(error);
109
+ const output = this.formatOutput({
110
+ decision: "allow",
111
+ message: `⚠️ Hook error: ${errorMessage}`
112
+ });
113
+ console.log(output);
114
+ process.exit(0);
115
+ }
116
+ };
117
+
118
+ //#endregion
119
+ //#region src/adapters/ClaudeCodeAdapter.ts
120
+ /**
121
+ * ClaudeCodeAdapter - Adapter for Claude Code hook format
122
+ *
123
+ * DESIGN PATTERNS:
124
+ * - Adapter pattern: Converts Claude Code format to normalized format
125
+ * - Parser pattern: Extracts file paths and operations from tool inputs
126
+ *
127
+ * CODING STANDARDS:
128
+ * - Parse Claude Code JSON stdin format exactly as specified
129
+ * - Format output to match Claude Code hook response schema
130
+ * - Handle missing/optional fields gracefully
131
+ *
132
+ * AVOID:
133
+ * - Assuming all fields are present
134
+ * - Hardcoding tool names (use constants if needed)
135
+ * - Mutating input objects
136
+ */
137
+ /**
138
+ * Adapter for Claude Code hook format
139
+ */
140
+ var ClaudeCodeAdapter = class extends BaseAdapter {
141
+ /**
142
+ * Parse Claude Code stdin into normalized HookContext
143
+ *
144
+ * @param stdin - Raw JSON string from Claude Code
145
+ * @returns Normalized hook context
146
+ */
147
+ parseInput(stdin) {
148
+ const input = JSON.parse(stdin);
149
+ return {
150
+ toolName: input.tool_name,
151
+ toolInput: input.tool_input,
152
+ filePath: this.extractFilePath(input.tool_name, input.tool_input),
153
+ operation: this.extractOperation(input.tool_name),
154
+ cwd: input.cwd,
155
+ sessionId: input.session_id,
156
+ llmTool: input.llm_tool
157
+ };
158
+ }
159
+ /**
160
+ * Format normalized HookResponse into Claude Code output
161
+ *
162
+ * @param response - Normalized hook response
163
+ * @returns JSON string for Claude Code
164
+ */
165
+ formatOutput(response) {
166
+ if (response.decision === "skip") return JSON.stringify({}, null, 2);
167
+ const output = { hookSpecificOutput: {
168
+ hookEventName: "PreToolUse",
169
+ permissionDecision: response.decision,
170
+ permissionDecisionReason: response.message
171
+ } };
172
+ if (response.updatedInput) output.hookSpecificOutput.updatedInput = response.updatedInput;
173
+ return JSON.stringify(output, null, 2);
174
+ }
175
+ /**
176
+ * Extract file path from tool input
177
+ *
178
+ * @param toolName - Name of the tool
179
+ * @param toolInput - Tool input parameters
180
+ * @returns File path if this is a file operation
181
+ */
182
+ extractFilePath(toolName, toolInput) {
183
+ if ([
184
+ "Read",
185
+ "Write",
186
+ "Edit"
187
+ ].includes(toolName)) return toolInput.file_path;
188
+ }
189
+ /**
190
+ * Extract operation type from tool name
191
+ *
192
+ * @param toolName - Name of the tool
193
+ * @returns Operation type if this is a file operation
194
+ */
195
+ extractOperation(toolName) {
196
+ return {
197
+ Read: "read",
198
+ Write: "write",
199
+ Edit: "edit"
200
+ }[toolName];
201
+ }
202
+ };
203
+
204
+ //#endregion
205
+ //#region src/adapters/ClaudeCodePostToolUseAdapter.ts
206
+ /**
207
+ * ClaudeCodePostToolUseAdapter - Adapter for Claude Code PostToolUse hook format
208
+ *
209
+ * DESIGN PATTERNS:
210
+ * - Adapter pattern: Converts Claude Code PostToolUse format to normalized format
211
+ * - Parser pattern: Extracts file paths and operations from tool response
212
+ *
213
+ * CODING STANDARDS:
214
+ * - Parse Claude Code JSON stdin format exactly as specified
215
+ * - Format output to match Claude Code PostToolUse hook response schema
216
+ * - Handle missing/optional fields gracefully
217
+ *
218
+ * AVOID:
219
+ * - Assuming all fields are present
220
+ * - Hardcoding tool names (use constants if needed)
221
+ * - Mutating input objects
222
+ */
223
+ /**
224
+ * Adapter for Claude Code PostToolUse hook format
225
+ */
226
+ var ClaudeCodePostToolUseAdapter = class extends BaseAdapter {
227
+ /**
228
+ * Parse Claude Code PostToolUse stdin into normalized HookContext
229
+ *
230
+ * @param stdin - Raw JSON string from Claude Code
231
+ * @returns Normalized hook context
232
+ */
233
+ parseInput(stdin) {
234
+ const input = JSON.parse(stdin);
235
+ return {
236
+ toolName: input.tool_name,
237
+ toolInput: input.tool_input,
238
+ filePath: this.extractFilePath(input.tool_name, input.tool_input, input.tool_response),
239
+ operation: this.extractOperation(input.tool_name),
240
+ cwd: input.cwd,
241
+ sessionId: input.session_id,
242
+ llmTool: input.llm_tool
243
+ };
244
+ }
245
+ /**
246
+ * Format normalized HookResponse into Claude Code PostToolUse output
247
+ *
248
+ * @param response - Normalized hook response
249
+ * @returns JSON string for Claude Code
250
+ */
251
+ formatOutput(response) {
252
+ const output = { hookSpecificOutput: { hookEventName: "PostToolUse" } };
253
+ if (response.decision === "deny") {
254
+ output.decision = "block";
255
+ output.reason = response.message;
256
+ }
257
+ if (response.decision === "allow" && response.message) output.hookSpecificOutput.additionalContext = response.message;
258
+ return JSON.stringify(output, null, 2);
259
+ }
260
+ /**
261
+ * Extract file path from tool input or response
262
+ *
263
+ * @param toolName - Name of the tool
264
+ * @param toolInput - Tool input parameters
265
+ * @param toolResponse - Tool response data
266
+ * @returns File path if this is a file operation
267
+ */
268
+ extractFilePath(toolName, toolInput, toolResponse) {
269
+ if ([
270
+ "Read",
271
+ "Write",
272
+ "Edit"
273
+ ].includes(toolName)) return toolInput.file_path || toolResponse.filePath;
274
+ }
275
+ /**
276
+ * Extract operation type from tool name
277
+ *
278
+ * @param toolName - Name of the tool
279
+ * @returns Operation type if this is a file operation
280
+ */
281
+ extractOperation(toolName) {
282
+ return {
283
+ Read: "read",
284
+ Write: "write",
285
+ Edit: "edit"
286
+ }[toolName];
287
+ }
288
+ };
289
+
290
+ //#endregion
291
+ //#region src/services/ExecutionLogService.ts
292
+ /**
293
+ * ExecutionLogService - Tracks hook executions to prevent duplicate actions
294
+ *
295
+ * DESIGN PATTERNS:
296
+ * - Repository pattern: Abstracts data access to execution log
297
+ * - Query pattern: Provides efficient lookups for hook execution history
298
+ * - Singleton cache: In-memory cache for performance
299
+ *
300
+ * CODING STANDARDS:
301
+ * - Use static methods for stateless operations
302
+ * - Handle file system errors gracefully
303
+ * - Optimize for performance with efficient data structures
304
+ *
305
+ * AVOID:
306
+ * - Loading entire log file into memory
307
+ * - Blocking I/O operations
308
+ * - Complex parsing logic (keep it simple)
309
+ */
310
+ /**
311
+ * Service for tracking hook executions using an append-only log
312
+ * Prevents duplicate hook actions (e.g., showing design patterns twice for same file)
313
+ */
314
+ var ExecutionLogService = class ExecutionLogService {
315
+ /** Log file path - stored in system temp directory */
316
+ static LOG_FILE = node_path.join(node_os.tmpdir(), "hook-adapter-executions.jsonl");
317
+ /** In-memory cache of recent executions (last 1000 entries) */
318
+ static cache = null;
319
+ /** Max cache size to prevent memory bloat */
320
+ static MAX_CACHE_SIZE = 1e3;
321
+ /**
322
+ * Check if a specific action was already taken for this file in this session
323
+ *
324
+ * @param sessionId - Session identifier
325
+ * @param filePath - File path to check
326
+ * @param decision - Decision to check for (e.g., 'deny' means we already showed patterns)
327
+ * @returns true if the action was already taken
328
+ */
329
+ static async hasExecuted(sessionId, filePath, decision) {
330
+ const entries = await ExecutionLogService.loadLog();
331
+ for (let i = entries.length - 1; i >= 0; i--) {
332
+ const entry = entries[i];
333
+ if (entry.sessionId === sessionId && entry.filePath === filePath && entry.decision === decision) return true;
334
+ }
335
+ return false;
336
+ }
337
+ /**
338
+ * Log a hook execution
339
+ *
340
+ * @param params - Log execution parameters
341
+ */
342
+ static async logExecution(params) {
343
+ const entry = {
344
+ timestamp: Date.now(),
345
+ sessionId: params.sessionId,
346
+ filePath: params.filePath,
347
+ operation: params.operation,
348
+ decision: params.decision,
349
+ filePattern: params.filePattern,
350
+ fileMtime: params.fileMtime,
351
+ fileChecksum: params.fileChecksum
352
+ };
353
+ try {
354
+ await node_fs_promises.appendFile(ExecutionLogService.LOG_FILE, `${JSON.stringify(entry)}\n`, "utf-8");
355
+ if (ExecutionLogService.cache) {
356
+ ExecutionLogService.cache.push(entry);
357
+ if (ExecutionLogService.cache.length > ExecutionLogService.MAX_CACHE_SIZE) ExecutionLogService.cache = ExecutionLogService.cache.slice(-ExecutionLogService.MAX_CACHE_SIZE);
358
+ }
359
+ } catch (error) {
360
+ console.error("Failed to log hook execution:", error);
361
+ }
362
+ }
363
+ /**
364
+ * Load execution log from file
365
+ * Uses in-memory cache for performance
366
+ */
367
+ static async loadLog() {
368
+ if (ExecutionLogService.cache !== null) return ExecutionLogService.cache;
369
+ try {
370
+ const lines = (await node_fs_promises.readFile(ExecutionLogService.LOG_FILE, "utf-8")).trim().split("\n").filter(Boolean);
371
+ const entries = [];
372
+ for (const line of lines) try {
373
+ entries.push(JSON.parse(line));
374
+ } catch {}
375
+ ExecutionLogService.cache = entries.slice(-ExecutionLogService.MAX_CACHE_SIZE);
376
+ return ExecutionLogService.cache;
377
+ } catch (error) {
378
+ if (error.code === "ENOENT") {
379
+ ExecutionLogService.cache = [];
380
+ return ExecutionLogService.cache;
381
+ }
382
+ console.error("Failed to load execution log:", error);
383
+ ExecutionLogService.cache = [];
384
+ return ExecutionLogService.cache;
385
+ }
386
+ }
387
+ /**
388
+ * Clear the execution log (for testing)
389
+ */
390
+ static async clearLog() {
391
+ try {
392
+ await node_fs_promises.unlink(ExecutionLogService.LOG_FILE);
393
+ ExecutionLogService.cache = [];
394
+ } catch (error) {
395
+ if (error.code !== "ENOENT") throw error;
396
+ }
397
+ }
398
+ /**
399
+ * Get log statistics (for debugging)
400
+ */
401
+ static async getStats() {
402
+ const entries = await ExecutionLogService.loadLog();
403
+ const sessions = new Set(entries.map((e) => e.sessionId));
404
+ const files = new Set(entries.map((e) => e.filePath));
405
+ return {
406
+ totalEntries: entries.length,
407
+ uniqueSessions: sessions.size,
408
+ uniqueFiles: files.size
409
+ };
410
+ }
411
+ /**
412
+ * Get file metadata (mtime and checksum) for a file
413
+ *
414
+ * @param filePath - Path to the file
415
+ * @returns File metadata or null if file doesn't exist
416
+ */
417
+ static async getFileMetadata(filePath) {
418
+ try {
419
+ const content = await node_fs_promises.readFile(filePath, "utf-8");
420
+ const checksum = node_crypto.createHash("md5").update(content).digest("hex");
421
+ return {
422
+ mtime: (await node_fs_promises.stat(filePath)).mtimeMs,
423
+ checksum
424
+ };
425
+ } catch {
426
+ return null;
427
+ }
428
+ }
429
+ /**
430
+ * Check if a file has changed since the last execution for this session
431
+ * Returns true if the file should be reviewed (new file or content changed)
432
+ *
433
+ * @param sessionId - Session identifier
434
+ * @param filePath - File path to check
435
+ * @param decision - Decision type to check for
436
+ * @returns true if file has changed or no previous execution found
437
+ */
438
+ static async hasFileChanged(sessionId, filePath, decision) {
439
+ const entries = await ExecutionLogService.loadLog();
440
+ let lastExecution = null;
441
+ for (let i = entries.length - 1; i >= 0; i--) {
442
+ const entry = entries[i];
443
+ if (entry.sessionId === sessionId && entry.filePath === filePath && entry.decision === decision) {
444
+ lastExecution = entry;
445
+ break;
446
+ }
447
+ }
448
+ if (!lastExecution || !lastExecution.fileChecksum) return true;
449
+ const currentMetadata = await ExecutionLogService.getFileMetadata(filePath);
450
+ if (!currentMetadata) return true;
451
+ return currentMetadata.checksum !== lastExecution.fileChecksum;
452
+ }
453
+ };
454
+
455
+ //#endregion
456
+ //#region src/services/AdapterProxyService.ts
457
+ /**
458
+ * AdapterProxyService - Routes hook execution to appropriate adapter
459
+ *
460
+ * DESIGN PATTERNS:
461
+ * - Proxy pattern: Routes requests to appropriate handlers
462
+ * - Factory pattern: Creates adapter instances based on agent name
463
+ *
464
+ * CODING STANDARDS:
465
+ * - Use static methods for stateless operations
466
+ * - Provide clear error messages for invalid inputs
467
+ * - Follow TitleCase naming convention for service classes
468
+ *
469
+ * AVOID:
470
+ * - Creating adapter instances unnecessarily
471
+ * - Silently falling back to defaults
472
+ * - Complex conditional logic (use lookup tables)
473
+ */
474
+ /**
475
+ * Proxy service for routing hook execution
476
+ * Eliminates duplication across commands by centralizing hook routing logic
477
+ */
478
+ var AdapterProxyService = class AdapterProxyService {
479
+ /**
480
+ * Execute hook with the appropriate adapter for the agent
481
+ *
482
+ * @param agentName - Agent identifier (e.g., "claude-code")
483
+ * @param hookType - Type of hook ("PreToolUse" or "PostToolUse")
484
+ * @param callback - Hook callback function to execute
485
+ */
486
+ static async execute(agentName, hookType, callback) {
487
+ await AdapterProxyService.getAdapter(agentName, hookType).execute(callback);
488
+ }
489
+ /**
490
+ * Get adapter instance for agent and hook type
491
+ *
492
+ * @param agentName - Name of the AI agent (e.g., "claude-code")
493
+ * @param hookType - Type of hook ("PreToolUse" or "PostToolUse")
494
+ * @returns Adapter instance
495
+ */
496
+ static getAdapter(agentName, hookType) {
497
+ switch (agentName) {
498
+ case __agiflowai_coding_agent_bridge.CLAUDE_CODE:
499
+ if (hookType === POST_TOOL_USE) return new ClaudeCodePostToolUseAdapter();
500
+ return new ClaudeCodeAdapter();
501
+ default: throw new Error(`Unknown agent: ${agentName}. Supported: ${__agiflowai_coding_agent_bridge.CLAUDE_CODE}`);
502
+ }
503
+ }
504
+ };
505
+
506
+ //#endregion
507
+ exports.AdapterProxyService = AdapterProxyService;
508
+ exports.BaseAdapter = BaseAdapter;
509
+ exports.ClaudeCodeAdapter = ClaudeCodeAdapter;
510
+ exports.ClaudeCodePostToolUseAdapter = ClaudeCodePostToolUseAdapter;
511
+ exports.ExecutionLogService = ExecutionLogService;
512
+ exports.POST_TOOL_USE = POST_TOOL_USE;
513
+ exports.PRE_TOOL_USE = PRE_TOOL_USE;