@ebowwa/claude-code-mcp 1.0.0 → 1.0.2

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.
Files changed (48) hide show
  1. package/dist/__tests__/advanced.test.d.ts +6 -0
  2. package/dist/__tests__/advanced.test.d.ts.map +1 -0
  3. package/dist/__tests__/advanced.test.js +354 -0
  4. package/dist/__tests__/advanced.test.js.map +1 -0
  5. package/dist/advanced.d.ts +109 -0
  6. package/dist/advanced.d.ts.map +1 -0
  7. package/dist/advanced.js +427 -0
  8. package/dist/advanced.js.map +1 -0
  9. package/dist/cli-wrapper.d.ts +202 -0
  10. package/dist/cli-wrapper.d.ts.map +1 -0
  11. package/dist/cli-wrapper.js +347 -0
  12. package/dist/cli-wrapper.js.map +1 -0
  13. package/dist/cli-wrapper.test.d.ts +12 -0
  14. package/dist/cli-wrapper.test.d.ts.map +1 -0
  15. package/dist/cli-wrapper.test.js +354 -0
  16. package/dist/cli-wrapper.test.js.map +1 -0
  17. package/dist/cli.d.ts +16 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +354 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/index.d.ts +10 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +561 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/integration.test.d.ts +12 -0
  26. package/dist/integration.test.d.ts.map +1 -0
  27. package/dist/integration.test.js +716 -0
  28. package/dist/integration.test.js.map +1 -0
  29. package/dist/queue.d.ts +87 -0
  30. package/dist/queue.d.ts.map +1 -0
  31. package/dist/queue.js +273 -0
  32. package/dist/queue.js.map +1 -0
  33. package/dist/teammates-integration.d.ts +128 -0
  34. package/dist/teammates-integration.d.ts.map +1 -0
  35. package/dist/teammates-integration.js +353 -0
  36. package/dist/teammates-integration.js.map +1 -0
  37. package/dist/test-config.d.ts +104 -0
  38. package/dist/test-config.d.ts.map +1 -0
  39. package/dist/test-config.js +439 -0
  40. package/dist/test-config.js.map +1 -0
  41. package/dist/tools.d.ts +97 -0
  42. package/dist/tools.d.ts.map +1 -0
  43. package/dist/tools.js +627 -0
  44. package/dist/tools.js.map +1 -0
  45. package/package.json +7 -1
  46. package/ARCHITECTURE.md +0 -1802
  47. package/DOCUMENTATION.md +0 -747
  48. package/TESTING.md +0 -318
package/DOCUMENTATION.md DELETED
@@ -1,747 +0,0 @@
1
- # @mcp/claude-code
2
-
3
- MCP server for managing Claude Code CLI sessions with Doppler integration.
4
-
5
- This MCP server **complements** `@mcp/claude-code-history` by providing session management capabilities while the history server handles conversation data access.
6
-
7
- ## Features
8
-
9
- - **Start Sessions**: Launch new Claude Code sessions with project context
10
- - **Resume Sessions**: Resume existing sessions by UUID with Doppler support
11
- - **List Sessions**: Discover active and recent sessions
12
- - **Kill Sessions**: Terminate running sessions
13
- - **Message Pass-through**: Send messages to active sessions
14
- - **Context Sync**: Synchronize context between sessions
15
- - **Doppler Integration**: Seamless secret management for API keys and environment
16
- - **Stream Output**: Real-time output streaming from sessions
17
- - **Wait for Completion**: Block until session completes with optional timeout
18
-
19
- ## Relationship to Other MCPs
20
-
21
- | MCP Server | Purpose | How They Work Together |
22
- |------------|---------|------------------------|
23
- | `@mcp/claude-code` | **Session Management** - Start, resume, kill sessions | Manages the lifecycle of Claude Code CLI processes |
24
- | `@mcp/claude-code-history` | **History Access** - Read past conversations | Reads conversation data from completed/active sessions |
25
- | `@mcp/claude-code-config` | **Configuration** - Manage Claude Code settings | Manages CLAUDE.md, keybindings, MCP server configs |
26
-
27
- **Typical Workflow:**
28
- 1. Use `@mcp/claude-code` to start/resume a session
29
- 2. Use `@mcp/claude-code-history` to search past context
30
- 3. Use `@mcp/claude-code-config` to update settings if needed
31
-
32
- ## Installation
33
-
34
- ```bash
35
- cd /Users/ebowwa/Desktop/codespaces/packages/mcp/claude-code
36
- bun install
37
- bun run build
38
- ```
39
-
40
- ## Doppler Setup
41
-
42
- The Doppler workaround is essential for session resumption. Claude Code's `--resume` flag requires the `ANTHROPIC_API_KEY` to be set, which we manage through Doppler.
43
-
44
- ### 1. Install Doppler CLI
45
-
46
- ```bash
47
- # macOS
48
- brew install dopplerlabs/tap/doppler
49
-
50
- # Linux
51
- curl -sSL https://dl.doppler.com/install.sh | sh
52
- ```
53
-
54
- ### 2. Configure Doppler Project
55
-
56
- ```bash
57
- # Login to Doppler
58
- doppler login
59
-
60
- # Create a new project
61
- doppler projects create claude-code-mcp
62
-
63
- # Setup your config
64
- doppler setup
65
- ```
66
-
67
- ### 3. Set Required Secrets
68
-
69
- ```bash
70
- # Set your Anthropic API key
71
- doppler secrets set ANTHROPIC_API_KEY sk-ant-xxx
72
-
73
- # Optional: Set multiple keys for rotation (rolling keys)
74
- doppler secrets set ANTHROPIC_API_KEYS '["sk-ant-key1","sk-ant-key2"]'
75
-
76
- # Optional: Set Claude directory path
77
- doppler secrets set CLAUDE_DIR /Users/yourname/.claude
78
- ```
79
-
80
- ### 4. Verify Configuration
81
-
82
- ```bash
83
- # List all secrets
84
- doppler secrets list
85
-
86
- # Run a test command with secrets loaded
87
- doppler run -- env | grep ANTHROPIC
88
- ```
89
-
90
- ## Usage
91
-
92
- ### Add to Claude Code MCP Configuration
93
-
94
- Add to your `~/.claude.json` or project `.mcp.json`:
95
-
96
- ```json
97
- {
98
- "mcpServers": {
99
- "claude-code": {
100
- "command": "doppler",
101
- "args": [
102
- "run",
103
- "--config",
104
- "dev",
105
- "--",
106
- "bun",
107
- "/Users/ebowwa/Desktop/codespaces/packages/mcp/claude-code/src/index.ts"
108
- ],
109
- "env": {
110
- "DOPPLER_PROJECT": "claude-code-mcp",
111
- "DOPPLER_CONFIG": "dev"
112
- }
113
- }
114
- }
115
- }
116
- ```
117
-
118
- **Key Pattern:** The `doppler run --` wrapper ensures `ANTHROPIC_API_KEY` is available when using `--resume` flag.
119
-
120
- ## Available Tools
121
-
122
- ### Session Management
123
-
124
- #### 1. `start_session`
125
-
126
- Start a new Claude Code session.
127
-
128
- ```json
129
- {
130
- "name": "start_session",
131
- "arguments": {
132
- "projectPath": "/path/to/project",
133
- "message": "Initial message to send",
134
- "options": {
135
- "timeout": 300000,
136
- "stream": false
137
- }
138
- }
139
- }
140
- ```
141
-
142
- **Parameters:**
143
- - `projectPath` (required): Absolute path to project directory
144
- - `message` (optional): Initial message to send to the session
145
- - `options` (optional):
146
- - `timeout`: Session timeout in milliseconds (default: 300000)
147
- - `stream`: Enable output streaming (default: false)
148
-
149
- **Example:**
150
- ```typescript
151
- const result = await client.callTool({
152
- name: 'start_session',
153
- arguments: {
154
- projectPath: '/Users/ebowwa/Desktop/codespaces',
155
- message: 'Review the PR for the rolling-keys package',
156
- options: {
157
- timeout: 600000,
158
- stream: true
159
- }
160
- }
161
- });
162
- ```
163
-
164
- #### 2. `resume_session`
165
-
166
- Resume an existing Claude Code session by UUID.
167
-
168
- **CRITICAL:** Requires Doppler to inject `ANTHROPIC_API_KEY` for the `--resume` flag to work.
169
-
170
- ```json
171
- {
172
- "name": "resume_session",
173
- "arguments": {
174
- "sessionId": "uuid-here",
175
- "message": "Message to send on resume",
176
- "options": {
177
- "useDoppler": true,
178
- "timeout": 300000
179
- }
180
- }
181
- }
182
- ```
183
-
184
- **Parameters:**
185
- - `sessionId` (required): UUID of the session to resume
186
- - `message` (optional): Message to send after resuming
187
- - `options` (optional):
188
- - `useDoppler`: Use Doppler wrapper (default: true)
189
- - `timeout`: Session timeout in milliseconds (default: 300000)
190
- - `stream`: Enable output streaming (default: false)
191
-
192
- **The Doppler Workaround:**
193
- When `useDoppler` is true, the session is resumed using:
194
- ```bash
195
- doppler run --command "claude --resume UUID -- 'message'"
196
- ```
197
-
198
- This ensures `ANTHROPIC_API_KEY` is available for the resumed session.
199
-
200
- **Example:**
201
- ```typescript
202
- const result = await client.callTool({
203
- name: 'resume_session',
204
- arguments: {
205
- sessionId: 'abc-123-def-456',
206
- message: 'Continue with the next task',
207
- options: {
208
- useDoppler: true,
209
- timeout: 600000
210
- }
211
- }
212
- });
213
- ```
214
-
215
- #### 3. `list_sessions`
216
-
217
- List all Claude Code sessions (active and recent).
218
-
219
- ```json
220
- {
221
- "name": "list_sessions",
222
- "arguments": {
223
- "status": "all",
224
- "limit": 20
225
- }
226
- }
227
- ```
228
-
229
- **Parameters:**
230
- - `status` (optional): Filter by status - "active", "completed", "all" (default: "all")
231
- - `limit` (optional): Maximum number of sessions to return (default: 20)
232
- - `projectPath` (optional): Filter sessions by project path
233
-
234
- **Example:**
235
- ```typescript
236
- const result = await client.callTool({
237
- name: 'list_sessions',
238
- arguments: {
239
- status: 'active',
240
- projectPath: '/Users/ebowwa/Desktop/codespaces'
241
- }
242
- });
243
- ```
244
-
245
- #### 4. `kill_session`
246
-
247
- Terminate a running session.
248
-
249
- ```json
250
- {
251
- "name": "kill_session",
252
- "arguments": {
253
- "sessionId": "uuid-here",
254
- "force": false
255
- }
256
- }
257
- ```
258
-
259
- **Parameters:**
260
- - `sessionId` (required): UUID of the session to kill
261
- - `force` (optional): Force kill without graceful shutdown (default: false)
262
-
263
- **Example:**
264
- ```typescript
265
- const result = await client.callTool({
266
- name: 'kill_session',
267
- arguments: {
268
- sessionId: 'abc-123-def-456',
269
- force: true
270
- }
271
- });
272
- ```
273
-
274
- ### Message & Context Management
275
-
276
- #### 5. `send_message`
277
-
278
- Send a message to an active session.
279
-
280
- ```json
281
- {
282
- "name": "send_message",
283
- "arguments": {
284
- "sessionId": "uuid-here",
285
- "message": "Your message here",
286
- "waitForResponse": true
287
- }
288
- }
289
- ```
290
-
291
- **Parameters:**
292
- - `sessionId` (required): UUID of the target session
293
- - `message` (required): Message content to send
294
- - `waitForResponse` (optional): Wait for response before returning (default: true)
295
-
296
- **Example:**
297
- ```typescript
298
- const result = await client.callTool({
299
- name: 'send_message',
300
- arguments: {
301
- sessionId: 'abc-123-def-456',
302
- message: 'What is the current status of the rolling-key tests?',
303
- waitForResponse: true
304
- }
305
- });
306
- ```
307
-
308
- #### 6. `sync_context`
309
-
310
- Synchronize context between sessions or update context for a session.
311
-
312
- ```json
313
- {
314
- "name": "sync_context",
315
- "arguments": {
316
- "sourceSessionId": "source-uuid",
317
- "targetSessionId": "target-uuid",
318
- "contextType": "all"
319
- }
320
- }
321
- ```
322
-
323
- **Parameters:**
324
- - `sourceSessionId` (optional): Source session UUID (if syncing between sessions)
325
- - `targetSessionId` (optional): Target session UUID
326
- - `contextType` (optional): Type of context to sync - "all", "history", "files", "state" (default: "all")
327
- - `contextData` (optional): Direct context data to apply (JSON object)
328
-
329
- **Example:**
330
- ```typescript
331
- // Sync context between sessions
332
- const result = await client.callTool({
333
- name: 'sync_context',
334
- arguments: {
335
- sourceSessionId: 'abc-123-def-456',
336
- targetSessionId: 'xyz-789-uvw-012',
337
- contextType: 'history'
338
- }
339
- });
340
-
341
- // Update context directly
342
- const result2 = await client.callTool({
343
- name: 'sync_context',
344
- arguments: {
345
- targetSessionId: 'xyz-789-uvw-012',
346
- contextData: {
347
- files: ['/path/to/file1.ts', '/path/to/file2.ts'],
348
- lastMessage: 'Here is the context you need'
349
- }
350
- }
351
- });
352
- ```
353
-
354
- ### Advanced Features
355
-
356
- #### 7. `stream_output`
357
-
358
- Enable real-time output streaming from a session.
359
-
360
- ```json
361
- {
362
- "name": "stream_output",
363
- "arguments": {
364
- "sessionId": "uuid-here",
365
- "lines": 100
366
- }
367
- }
368
- ```
369
-
370
- **Parameters:**
371
- - `sessionId` (required): UUID of the session
372
- - `lines` (optional): Number of recent lines to stream (default: 100, 0 for all)
373
- - "follow" (optional): Continue streaming new output (default: false)
374
-
375
- **Example:**
376
- ```typescript
377
- const result = await client.callTool({
378
- name: 'stream_output',
379
- arguments: {
380
- sessionId: 'abc-123-def-456',
381
- lines: 50,
382
- follow: true
383
- }
384
- });
385
- ```
386
-
387
- #### 8. `wait_for_completion`
388
-
389
- Wait for a session to complete with optional timeout.
390
-
391
- ```json
392
- {
393
- "name": "wait_for_completion",
394
- "arguments": {
395
- "sessionId": "uuid-here",
396
- "timeout": 300000,
397
- "pollInterval": 1000
398
- }
399
- }
400
- ```
401
-
402
- **Parameters:**
403
- - `sessionId` (required): UUID of the session to wait for
404
- - `timeout` (optional): Maximum time to wait in milliseconds (default: 300000)
405
- - `pollInterval` (optional): Polling interval in milliseconds (default: 1000)
406
-
407
- **Example:**
408
- ```typescript
409
- const result = await client.callTool({
410
- name: 'wait_for_completion',
411
- arguments: {
412
- sessionId: 'abc-123-def-456',
413
- timeout: 600000,
414
- pollInterval: 2000
415
- }
416
- });
417
- ```
418
-
419
- ## Session Management Patterns
420
-
421
- ### Pattern 1: Sequential Task Execution
422
-
423
- Start a session, wait for completion, then process results:
424
-
425
- ```typescript
426
- // 1. Start session
427
- const { sessionId } = await client.callTool({
428
- name: 'start_session',
429
- arguments: {
430
- projectPath: '/path/to/project',
431
- message: 'Fix the authentication bug'
432
- }
433
- });
434
-
435
- // 2. Wait for completion
436
- await client.callTool({
437
- name: 'wait_for_completion',
438
- arguments: { sessionId, timeout: 600000 }
439
- });
440
-
441
- // 3. Stream output to see results
442
- const output = await client.callTool({
443
- name: 'stream_output',
444
- arguments: { sessionId, lines: 0 }
445
- });
446
- ```
447
-
448
- ### Pattern 2: Long-Running Background Task
449
-
450
- Start a session, let it run in background, check status later:
451
-
452
- ```typescript
453
- // 1. Start session
454
- const { sessionId } = await client.callTool({
455
- name: 'start_session',
456
- arguments: {
457
- projectPath: '/path/to/project',
458
- message: 'Run full test suite and generate coverage report',
459
- options: { timeout: 3600000 } // 1 hour
460
- }
461
- });
462
-
463
- // 2. Store sessionId for later...
464
- // 3. Check status later
465
- const sessions = await client.callTool({
466
- name: 'list_sessions',
467
- arguments: { status: 'active' }
468
- });
469
-
470
- // 4. Resume if needed
471
- await client.callTool({
472
- name: 'resume_session',
473
- arguments: {
474
- sessionId,
475
- message: 'What is the current progress?',
476
- options: { useDoppler: true }
477
- }
478
- });
479
- ```
480
-
481
- ### Pattern 3: Multi-Session Collaboration
482
-
483
- Run multiple sessions in parallel, sync context between them:
484
-
485
- ```typescript
486
- // 1. Start backend session
487
- const backend = await client.callTool({
488
- name: 'start_session',
489
- arguments: {
490
- projectPath: '/path/to/backend',
491
- message: 'Implement the user authentication endpoint'
492
- }
493
- });
494
-
495
- // 2. Start frontend session
496
- const frontend = await client.callTool({
497
- name: 'start_session',
498
- arguments: {
499
- projectPath: '/path/to/frontend',
500
- message: 'Create the login form component'
501
- }
502
- });
503
-
504
- // 3. Sync context from backend to frontend
505
- await client.callTool({
506
- name: 'sync_context',
507
- arguments: {
508
- sourceSessionId: backend.sessionId,
509
- targetSessionId: frontend.sessionId,
510
- contextType: 'history'
511
- }
512
- });
513
-
514
- // 4. Send API contract info to frontend
515
- await client.callTool({
516
- name: 'send_message',
517
- arguments: {
518
- sessionId: frontend.sessionId,
519
- message: 'The backend API endpoint is: POST /api/auth/login with { email, password }'
520
- }
521
- });
522
- ```
523
-
524
- ### Pattern 4: Iterative Development with Resume
525
-
526
- Use resume to continue work on previous sessions:
527
-
528
- ```typescript
529
- // 1. List recent sessions
530
- const sessions = await client.callTool({
531
- name: 'list_sessions',
532
- arguments: { status: 'completed', limit: 10 }
533
- });
534
-
535
- // 2. Find the session you want to continue
536
- const targetSession = sessions.find(s => s.summary.includes('auth fix'));
537
-
538
- // 3. Resume with new context
539
- await client.callTool({
540
- name: 'resume_session',
541
- arguments: {
542
- sessionId: targetSession.id,
543
- message: 'I need to add error handling for the auth endpoint',
544
- options: { useDoppler: true } // CRITICAL: Enables Doppler workaround
545
- }
546
- });
547
- ```
548
-
549
- ## Troubleshooting
550
-
551
- ### "Session not found"
552
-
553
- - Verify the session UUID is correct
554
- - Check if the session has been cleaned up (sessions are purged after 24 hours by default)
555
- - Use `list_sessions` to find valid session IDs
556
-
557
- ### "Resume failed: API key not found"
558
-
559
- This means the Doppler workaround is not working:
560
-
561
- ```bash
562
- # Verify Doppler is configured
563
- doppler secrets list
564
-
565
- # Check ANTHROPIC_API_KEY is set
566
- doppler run -- env | grep ANTHROPIC
567
-
568
- # Ensure useDoppler: true in resume_session options
569
- ```
570
-
571
- ### "Session timeout"
572
-
573
- Increase the timeout value:
574
-
575
- ```typescript
576
- const result = await client.callTool({
577
- name: 'start_session',
578
- arguments: {
579
- projectPath: '/path/to/project',
580
- message: 'Long running task',
581
- options: { timeout: 3600000 } // 1 hour
582
- }
583
- });
584
- ```
585
-
586
- ### "Context sync failed"
587
-
588
- - Verify both sessions exist and are accessible
589
- - Check contextType is valid ("all", "history", "files", "state")
590
- - Ensure source session has the requested context data
591
-
592
- ### Doppler authentication issues
593
-
594
- ```bash
595
- # Verify Doppler is authenticated
596
- doppler me
597
-
598
- # Check available projects
599
- doppler projects
600
-
601
- # Verify secrets are set
602
- doppler secrets list
603
-
604
- # Test Doppler run
605
- doppler run -- echo "Doppler works: $ANTHROPIC_API_KEY"
606
- ```
607
-
608
- ## Environment Variables
609
-
610
- | Variable | Description | Default |
611
- |----------|-------------|---------|
612
- | `CLAUDE_DIR` | Path to Claude Code directory | `~/.claude` |
613
- | `DOPPLER_PROJECT` | Doppler project name | - |
614
- | `DOPPLER_CONFIG` | Doppler config name | `dev` |
615
- | `DOPPLER_TOKEN` | Doppler auth token | - |
616
- | `ANTHROPIC_API_KEY` | Anthropic API key | (from Doppler) |
617
- | `SESSION_TIMEOUT` | Default session timeout (ms) | `300000` |
618
- | `SESSION_CLEANUP_AGE` | Age to clean up sessions (ms) | `86400000` (24h) |
619
-
620
- ## Development
621
-
622
- ```bash
623
- # Install dependencies
624
- bun install
625
-
626
- # Run in development mode
627
- bun run dev
628
-
629
- # Run tests
630
- bun run test
631
-
632
- # Run specific test suites
633
- bun run test:cli-wrapper
634
- bun run test:integration
635
-
636
- # Watch mode for tests
637
- bun run test:watch
638
-
639
- # Build
640
- bun run build
641
-
642
- # Start built server
643
- bun run start
644
- ```
645
-
646
- ## Testing
647
-
648
- Comprehensive test suite with unit and integration tests:
649
-
650
- ### Test Structure
651
-
652
- - **cli-wrapper.test.ts** - Unit tests for CLI wrapper and Doppler integration
653
- - **integration.test.ts** - Integration tests with mock Claude binary
654
- - **test-config.ts** - Shared test utilities and mock helpers
655
-
656
- ### Running Tests
657
-
658
- ```bash
659
- # Run all tests
660
- bun test
661
-
662
- # Run with watch mode
663
- bun run test:watch
664
-
665
- # Run specific test file
666
- bun test src/cli-wrapper.test.ts
667
-
668
- # Run specific test
669
- bun test src/cli-wrapper.test.ts -t "should spawn Claude Code without Doppler"
670
- ```
671
-
672
- ### Key Test Cases
673
-
674
- **CLI Wrapper Tests:**
675
- - Process spawning with/without Doppler
676
- - Doppler workaround for `--resume` flag
677
- - Graceful and forceful process termination
678
- - Rolling API keys integration
679
- - Message escaping (quotes, newlines, special chars)
680
- - Malformed UUID handling
681
- - Missing Doppler configuration
682
-
683
- **Integration Tests:**
684
- - Full tool call lifecycle
685
- - Session state management
686
- - Context synchronization
687
- - Output streaming
688
- - Wait for completion with timeout
689
-
690
- See [TESTING.md](./TESTING.md) for detailed testing documentation.
691
-
692
- ## Integration Examples
693
-
694
- ### With claude-code-history
695
-
696
- ```typescript
697
- // 1. Start a session
698
- const { sessionId } = await client.callTool({
699
- name: 'start_session',
700
- arguments: { projectPath: '/path/to/project' }
701
- });
702
-
703
- // 2. Wait for completion
704
- await client.callTool({
705
- name: 'wait_for_completion',
706
- arguments: { sessionId }
707
- });
708
-
709
- // 3. Use claude-code-history to search the conversation
710
- const history = await historyClient.callTool({
711
- name: 'get_conversation_history',
712
- arguments: { sessionId }
713
- });
714
- ```
715
-
716
- ### With claude-code-config
717
-
718
- ```typescript
719
- // 1. Update CLAUDE.md before starting session
720
- await configClient.callTool({
721
- name: 'write_global_claude_md',
722
- arguments: {
723
- content: '# Special Instructions\n\nFocus on performance optimization.'
724
- }
725
- });
726
-
727
- // 2. Start session with new context
728
- const { sessionId } = await client.callTool({
729
- name: 'start_session',
730
- arguments: { projectPath: '/path/to/project' }
731
- });
732
- ```
733
-
734
- ## Dependencies
735
-
736
- This package requires the following workspace dependencies:
737
-
738
- - `@modelcontextprotocol/sdk` - MCP SDK for server implementation
739
- - `zod` - Runtime type validation
740
-
741
- ## License
742
-
743
- MIT
744
-
745
- ## Author
746
-
747
- ebowwa