reflexive 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 (49) hide show
  1. package/dashboard/out/404/index.html +1 -1
  2. package/dashboard/out/404.html +1 -1
  3. package/dashboard/out/__next.__PAGE__.txt +2 -2
  4. package/dashboard/out/__next._full.txt +3 -3
  5. package/dashboard/out/__next._head.txt +1 -1
  6. package/dashboard/out/__next._index.txt +2 -2
  7. package/dashboard/out/__next._tree.txt +2 -2
  8. package/dashboard/out/_next/static/chunks/209a165917e29ad7.css +3 -0
  9. package/dashboard/out/_next/static/chunks/{5be66f773d014294.js → 875b2f53bcfbbafb.js} +3 -3
  10. package/dashboard/out/_not-found/__next._full.txt +2 -2
  11. package/dashboard/out/_not-found/__next._head.txt +1 -1
  12. package/dashboard/out/_not-found/__next._index.txt +2 -2
  13. package/dashboard/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  14. package/dashboard/out/_not-found/__next._not-found.txt +1 -1
  15. package/dashboard/out/_not-found/__next._tree.txt +2 -2
  16. package/dashboard/out/_not-found/index.html +1 -1
  17. package/dashboard/out/_not-found/index.txt +2 -2
  18. package/dashboard/out/index.html +1 -1
  19. package/dashboard/out/index.txt +3 -3
  20. package/dist/cli.d.ts +0 -1
  21. package/dist/cli.d.ts.map +1 -1
  22. package/dist/cli.js +164 -42
  23. package/dist/cli.js.map +1 -1
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +102 -4
  27. package/dist/index.js.map +1 -1
  28. package/dist/managers/process-manager.d.ts +22 -8
  29. package/dist/managers/process-manager.d.ts.map +1 -1
  30. package/dist/managers/process-manager.js +50 -42
  31. package/dist/managers/process-manager.js.map +1 -1
  32. package/dist/mcp/knowledge-tools.d.ts +16 -0
  33. package/dist/mcp/knowledge-tools.d.ts.map +1 -0
  34. package/dist/mcp/knowledge-tools.js +206 -0
  35. package/dist/mcp/knowledge-tools.js.map +1 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types/index.d.ts.map +1 -1
  38. package/dist/types/index.js.map +1 -1
  39. package/docs/README.md +87 -0
  40. package/docs/api-reference.md +1422 -0
  41. package/docs/deployment.md +885 -0
  42. package/docs/developer-guide.md +899 -0
  43. package/docs/getting-started.md +374 -0
  44. package/docs/index.md +158 -0
  45. package/docs/user-guide.md +990 -0
  46. package/package.json +2 -1
  47. package/dashboard/out/_next/static/chunks/82bbed47af1fbb39.css +0 -3
  48. /package/dashboard/out/_next/static/{vYzD8icR4qocco4JtUfu3 → Y9FaARzAOsacwE8LNVv_4}/_buildManifest.js +0 -0
  49. /package/dashboard/out/_next/static/{vYzD8icR4qocco4JtUfu3 → Y9FaARzAOsacwE8LNVv_4}/_ssgManifest.js +0 -0
@@ -0,0 +1,899 @@
1
+ # Developer Guide
2
+
3
+ Guide for developers who want to understand Reflexive's architecture, contribute code, or extend functionality.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Architecture](#architecture)
8
+ - [Project Structure](#project-structure)
9
+ - [Module Overview](#module-overview)
10
+ - [Data Flow](#data-flow)
11
+ - [Design Principles](#design-principles)
12
+ - [Development Setup](#development-setup)
13
+ - [Prerequisites](#prerequisites)
14
+ - [Cloning and Installation](#cloning-and-installation)
15
+ - [Building from Source](#building-from-source)
16
+ - [Running Tests](#running-tests)
17
+ - [Code Organization](#code-organization)
18
+ - [Types](#types)
19
+ - [Core Modules](#core-modules)
20
+ - [Managers](#managers)
21
+ - [MCP Tools](#mcp-tools)
22
+ - [Sandbox Utilities](#sandbox-utilities)
23
+ - [API Layer](#api-layer)
24
+ - [Testing](#testing)
25
+ - [Test Structure](#test-structure)
26
+ - [Running Tests](#running-tests-1)
27
+ - [Writing Tests](#writing-tests)
28
+ - [Mock System](#mock-system)
29
+ - [Contributing](#contributing)
30
+ - [Code Style](#code-style)
31
+ - [Commit Messages](#commit-messages)
32
+ - [Pull Request Process](#pull-request-process)
33
+ - [Issue Guidelines](#issue-guidelines)
34
+ - [Extending Reflexive](#extending-reflexive)
35
+ - [Adding Custom Tools](#adding-custom-tools)
36
+ - [Creating New Managers](#creating-new-managers)
37
+ - [Adding Storage Providers](#adding-storage-providers)
38
+
39
+ ## Architecture
40
+
41
+ Reflexive is built as a modular TypeScript project with clear separation of concerns.
42
+
43
+ ### Project Structure
44
+
45
+ ```
46
+ reflexive/
47
+ ├── src/
48
+ │ ├── index.ts # Library mode entry point, public API
49
+ │ ├── cli.ts # CLI entry point
50
+ │ ├── types/ # TypeScript type definitions
51
+ │ │ ├── index.ts # Core types (LogEntry, Capabilities, Config)
52
+ │ │ ├── sandbox.ts # Sandbox-specific types
53
+ │ │ ├── manager.ts # Manager interface types
54
+ │ │ └── mcp.ts # MCP tool types
55
+ │ ├── core/ # Core infrastructure
56
+ │ │ ├── app-state.ts # Circular log buffer, custom state store
57
+ │ │ ├── config-loader.ts # Config file discovery and merging
58
+ │ │ ├── dashboard.ts # HTML dashboard generator
59
+ │ │ ├── chat-stream.ts # SSE chat streaming via Claude Agent SDK
60
+ │ │ └── http-server.ts # Minimal HTTP server utilities
61
+ │ ├── managers/ # Process and sandbox managers
62
+ │ │ ├── process-manager.ts # Child process spawning, restart logic
63
+ │ │ ├── remote-debugger.ts # V8 Inspector protocol client
64
+ │ │ ├── sandbox-manager.ts # Single Vercel Sandbox wrapper
65
+ │ │ └── multi-sandbox-manager.ts # Multi-tenant sandbox pool
66
+ │ ├── mcp/ # MCP tool definitions
67
+ │ │ ├── tools.ts # Base tool helpers (createTool, textResult)
68
+ │ │ ├── local-tools.ts # Tools for local file operations
69
+ │ │ ├── cli-tools.ts # Tools for CLI mode (process control, logs)
70
+ │ │ ├── sandbox-tools.ts # Tools for sandbox mode
71
+ │ │ └── hosted-tools.ts # Tools for hosted multi-tenant mode
72
+ │ ├── sandbox/ # Sandbox utilities
73
+ │ │ ├── inject.ts # Sandbox injection script
74
+ │ │ ├── snapshot.ts # Filesystem snapshot/restore
75
+ │ │ └── storage.ts # S3/R2/Memory storage providers
76
+ │ ├── api/ # REST API for hosted mode
77
+ │ │ ├── routes.ts # REST endpoint definitions
78
+ │ │ └── auth.ts # API key auth and rate limiting
79
+ │ └── __tests__/ # Test suites (vitest)
80
+ │ ├── unit/ # Unit tests
81
+ │ ├── integration/ # Integration tests
82
+ │ ├── e2e/ # End-to-end tests
83
+ │ ├── fixtures/ # Test fixtures
84
+ │ └── mocks/ # Mock implementations
85
+ ├── dist/ # Compiled output (gitignored)
86
+ ├── package.json
87
+ ├── tsconfig.json
88
+ ├── tsconfig.build.json
89
+ ├── vitest.config.ts
90
+ └── eslint.config.js
91
+ ```
92
+
93
+ ### Module Overview
94
+
95
+ #### Core Modules (`src/core/`)
96
+
97
+ **app-state.ts**
98
+ - Circular log buffer (500 entries by default)
99
+ - Custom key-value state storage
100
+ - Event emitter for state changes
101
+ - Process status tracking
102
+
103
+ **config-loader.ts**
104
+ - Configuration file discovery (reflexive.config.js, .reflexiverc, etc.)
105
+ - Config merging and validation
106
+ - Environment variable handling
107
+ - Default configuration generation
108
+
109
+ **dashboard.ts**
110
+ - Self-contained HTML dashboard generator
111
+ - No external dependencies, inline CSS/JS
112
+ - Real-time log viewer with ANSI color support
113
+ - Chat interface with SSE streaming
114
+ - Process control UI
115
+
116
+ **chat-stream.ts**
117
+ - SSE (Server-Sent Events) streaming for AI responses
118
+ - Claude Agent SDK integration
119
+ - Tool call handling and response formatting
120
+ - Error handling and recovery
121
+
122
+ **http-server.ts**
123
+ - Minimal HTTP server utilities
124
+ - Request parsing (JSON, URL params)
125
+ - Response helpers (JSON, HTML, errors)
126
+ - CORS handling
127
+
128
+ #### Managers (`src/managers/`)
129
+
130
+ **process-manager.ts**
131
+ - Child process lifecycle (spawn, kill, restart)
132
+ - stdout/stderr capture and parsing
133
+ - File watching with debounced restart
134
+ - stdin proxy for interactive apps
135
+ - Injection script management
136
+ - Integration with RemoteDebugger
137
+
138
+ **remote-debugger.ts**
139
+ - V8 Inspector protocol client over WebSocket
140
+ - Breakpoint management (set, remove, list)
141
+ - Execution control (pause, resume, step over/into/out)
142
+ - Call stack inspection
143
+ - Scope variable evaluation
144
+ - Script source mapping
145
+
146
+ **sandbox-manager.ts**
147
+ - Single Vercel Sandbox wrapper
148
+ - File upload/download
149
+ - Command execution
150
+ - Log polling from sandbox
151
+ - State synchronization
152
+ - Injection script deployment
153
+
154
+ **multi-sandbox-manager.ts**
155
+ - Multi-tenant sandbox pool
156
+ - Sandbox lifecycle management
157
+ - Snapshot creation and restoration
158
+ - Storage provider integration
159
+ - Per-sandbox state isolation
160
+
161
+ #### MCP Tools (`src/mcp/`)
162
+
163
+ **tools.ts**
164
+ - Base tool creation helpers
165
+ - Result formatting (text, JSON, error)
166
+ - Zod schema integration
167
+ - Tool combination and filtering
168
+
169
+ **local-tools.ts**
170
+ - File operations (read, write, delete, search)
171
+ - Directory listing
172
+ - Shell command execution
173
+
174
+ **cli-tools.ts**
175
+ - Process control tools
176
+ - Log retrieval and search
177
+ - State inspection
178
+ - stdin sending
179
+
180
+ **sandbox-tools.ts**
181
+ - Sandbox-specific operations
182
+ - File manipulation in sandbox
183
+ - Command execution
184
+
185
+ **hosted-tools.ts**
186
+ - Multi-sandbox management
187
+ - Snapshot operations
188
+ - Cross-sandbox queries
189
+
190
+ #### Sandbox Utilities (`src/sandbox/`)
191
+
192
+ **inject.ts**
193
+ - Injection script source
194
+ - Console interception
195
+ - HTTP request/response tracking (diagnostics_channel)
196
+ - GC event monitoring
197
+ - Event loop latency tracking
198
+ - Custom state API (process.reflexive)
199
+
200
+ **snapshot.ts**
201
+ - Filesystem snapshot creation
202
+ - Snapshot restoration
203
+ - Directory traversal and archiving
204
+ - Compression and validation
205
+
206
+ **storage.ts**
207
+ - Storage provider abstraction
208
+ - Memory storage (in-process)
209
+ - S3 storage (AWS S3, Cloudflare R2)
210
+ - Provider factory
211
+
212
+ #### API Layer (`src/api/`)
213
+
214
+ **routes.ts**
215
+ - REST endpoint definitions
216
+ - Request validation
217
+ - Response formatting
218
+ - Route matching (string and regex)
219
+
220
+ **auth.ts**
221
+ - API key authentication
222
+ - Rate limiting (token bucket)
223
+ - Public path handling
224
+ - Middleware creation
225
+
226
+ ### Data Flow
227
+
228
+ #### CLI Mode Data Flow
229
+
230
+ ```
231
+ ┌─────────────┐
232
+ │ User │
233
+ │ Terminal │
234
+ └──────┬──────┘
235
+ │ reflexive app.js
236
+
237
+ ┌─────────────────────────────────────────┐
238
+ │ Reflexive CLI │
239
+ │ - Parse args │
240
+ │ - Load config │
241
+ │ - Create ProcessManager │
242
+ │ - Start HTTP server │
243
+ └──────┬──────────────────────────────────┘
244
+
245
+
246
+ ┌─────────────────┐ ┌───────────────┐
247
+ │ ProcessManager │◄─────┤ AppState │
248
+ │ - Spawn app.js │ │ - Logs │
249
+ │ - Capture stdout│ │ - State │
250
+ │ - Watch files │ │ - Events │
251
+ └────────┬────────┘ └───────────────┘
252
+
253
+
254
+ ┌─────────────────┐
255
+ │ app.js │
256
+ │ (Child Process) │
257
+ └─────────────────┘
258
+
259
+ ┌──────────────────────────────────┐
260
+ │ HTTP Server │
261
+ │ - Dashboard UI │
262
+ │ - Chat endpoint (SSE) │
263
+ │ - Status/logs endpoints │
264
+ └────────┬─────────────────────────┘
265
+
266
+
267
+ ┌──────────────────┐
268
+ │ Browser Client │
269
+ │ - Chat UI │
270
+ │ - Log viewer │
271
+ │ - Controls │
272
+ └──────────────────┘
273
+ ```
274
+
275
+ #### Sandbox Mode Data Flow
276
+
277
+ ```
278
+ ┌─────────────┐
279
+ │ CLI │
280
+ └──────┬──────┘
281
+ │ reflexive --sandbox app.js
282
+
283
+ ┌─────────────────────────────────────┐
284
+ │ SandboxManager (Local) │
285
+ │ - Create Vercel Sandbox │
286
+ │ - Upload files │
287
+ │ - Upload inject script │
288
+ │ - Start process │
289
+ │ - Poll logs │
290
+ └──────┬──────────────────────────────┘
291
+
292
+ │ WebSocket/HTTP
293
+
294
+ ┌─────────────────────────────────────┐
295
+ │ Vercel Sandbox (Remote) │
296
+ │ - Isolated filesystem │
297
+ │ - Run app.js │
298
+ │ - Write logs to /tmp/... │
299
+ └──────┬──────────────────────────────┘
300
+
301
+ │ Log polling
302
+
303
+ ┌─────────────────┐
304
+ │ AppState │
305
+ │ - Store logs │
306
+ │ - Track state │
307
+ └─────────────────┘
308
+ ```
309
+
310
+ #### Hosted Mode Data Flow
311
+
312
+ ```
313
+ ┌─────────────┐
314
+ │ API Client │
315
+ └──────┬──────┘
316
+ │ POST /api/sandboxes
317
+
318
+ ┌─────────────────────────────────────┐
319
+ │ REST API Server │
320
+ │ - Auth middleware │
321
+ │ - Rate limiting │
322
+ │ - Route handling │
323
+ └──────┬──────────────────────────────┘
324
+
325
+
326
+ ┌─────────────────────────────────────┐
327
+ │ MultiSandboxManager │
328
+ │ - Create sandbox │
329
+ │ - Manage lifecycle │
330
+ │ - Create snapshots │
331
+ │ - Restore from snapshots │
332
+ └──────┬──────────────────────────────┘
333
+
334
+
335
+ ┌─────────────────┬────────────────────┐
336
+ │ SandboxManager │ StorageProvider │
337
+ │ (per sandbox) │ (S3/R2/Memory) │
338
+ └─────────────────┴────────────────────┘
339
+ ```
340
+
341
+ ### Design Principles
342
+
343
+ 1. **Modularity**: Each module has a single responsibility
344
+ 2. **Type Safety**: Strict TypeScript for compile-time guarantees
345
+ 3. **Testability**: Dependency injection, mockable interfaces
346
+ 4. **Extensibility**: Plugin system for custom tools and storage
347
+ 5. **Safety**: Explicit opt-in for dangerous operations
348
+ 6. **Performance**: Circular buffers, efficient log polling
349
+ 7. **Developer Experience**: Clear APIs, comprehensive types
350
+
351
+ ## Development Setup
352
+
353
+ ### Prerequisites
354
+
355
+ - Node.js >= 18.0.0
356
+ - npm or yarn
357
+ - Git
358
+ - Claude API access (for testing chat features)
359
+
360
+ ### Cloning and Installation
361
+
362
+ ```bash
363
+ # Clone repository
364
+ git clone https://github.com/yourusername/reflexive.git
365
+ cd reflexive
366
+
367
+ # Install dependencies
368
+ npm install
369
+
370
+ # Build TypeScript
371
+ npm run build
372
+
373
+ # Run tests
374
+ npm test
375
+ ```
376
+
377
+ ### Building from Source
378
+
379
+ ```bash
380
+ # Clean previous build
381
+ npm run clean
382
+
383
+ # Type check (no emit)
384
+ npm run typecheck
385
+
386
+ # Build
387
+ npm run build
388
+
389
+ # Watch mode for development
390
+ npm run dev
391
+ ```
392
+
393
+ Build output goes to `dist/` directory.
394
+
395
+ ### Running Tests
396
+
397
+ ```bash
398
+ # Run all tests once
399
+ npm test
400
+
401
+ # Watch mode for development
402
+ npm run test:watch
403
+
404
+ # With coverage report
405
+ npm run test:coverage
406
+
407
+ # Run specific test file
408
+ npx vitest src/__tests__/unit/app-state.test.ts
409
+ ```
410
+
411
+ ## Code Organization
412
+
413
+ ### Types
414
+
415
+ All TypeScript types are in `src/types/`:
416
+
417
+ **index.ts**: Core types used across the codebase
418
+ - `LogEntry`, `LogType`
419
+ - `AppStatus`, `ProcessState`
420
+ - `Capabilities`, `ReflexiveConfig`
421
+
422
+ **sandbox.ts**: Sandbox-specific types
423
+ - `SandboxStatus`, `SandboxInstance`
424
+ - `Snapshot`, `SnapshotFile`
425
+ - `CommandResult`
426
+
427
+ **manager.ts**: Manager interface definitions
428
+ - `BaseManager`
429
+ - `SandboxManagerInterface`
430
+ - `MultiSandboxManagerInterface`
431
+
432
+ **mcp.ts**: MCP tool types
433
+ - `McpTool`, `ToolResult`
434
+ - `ChatStreamEvent`, `ChatOptions`
435
+
436
+ ### Core Modules
437
+
438
+ **AppState** manages application state:
439
+ ```typescript
440
+ class AppState {
441
+ private logs: LogEntry[] = []; // Circular buffer
442
+ private customState: Map<string, unknown> = new Map();
443
+
444
+ log(type: LogType, message: string, meta?: unknown): void
445
+ getLogs(count?: number, type?: string): LogEntry[]
446
+ setState(key: string, value: unknown): void
447
+ getState(key?: string): unknown
448
+ }
449
+ ```
450
+
451
+ **ConfigLoader** handles configuration:
452
+ ```typescript
453
+ export function loadConfig(configPath?: string): ReflexiveConfig
454
+ export function findConfigFile(): string | null
455
+ export function getDefaultConfig(): ReflexiveConfig
456
+ ```
457
+
458
+ ### Managers
459
+
460
+ Managers follow a common interface pattern:
461
+
462
+ ```typescript
463
+ interface BaseManager {
464
+ start(entry: string, args?: string[]): Promise<void>;
465
+ stop(): Promise<void>;
466
+ restart(): Promise<void>;
467
+ isRunning(): boolean;
468
+ on(event: string, handler: EventHandler): void;
469
+ }
470
+ ```
471
+
472
+ **ProcessManager** for local processes:
473
+ ```typescript
474
+ class ProcessManager implements BaseManager {
475
+ private child: ChildProcess | null;
476
+ private watcher: FSWatcher | null;
477
+ private debugger: RemoteDebugger | null;
478
+
479
+ async start(): Promise<void>
480
+ async stop(): Promise<void>
481
+ async sendInput(text: string): Promise<void>
482
+ getState(): ProcessState
483
+ }
484
+ ```
485
+
486
+ ### MCP Tools
487
+
488
+ Tools are created using the `createTool` helper:
489
+
490
+ ```typescript
491
+ import { createTool, textResult } from './tools.js';
492
+ import { z } from 'zod';
493
+
494
+ export const readFileTool = createTool(
495
+ 'read_file',
496
+ 'Read file contents',
497
+ z.object({
498
+ path: z.string().describe('File path to read')
499
+ }),
500
+ async ({ path }) => {
501
+ const content = await fs.readFile(path, 'utf-8');
502
+ return textResult(content);
503
+ }
504
+ );
505
+ ```
506
+
507
+ Tool result helpers:
508
+ ```typescript
509
+ textResult(text: string): ToolResult
510
+ jsonResult(data: unknown): ToolResult
511
+ errorResult(message: string): ToolResult
512
+ ```
513
+
514
+ ### Sandbox Utilities
515
+
516
+ **Injection script** provides runtime APIs:
517
+ ```typescript
518
+ // In sandbox/inject.ts
519
+ process.reflexive = {
520
+ setState(key: string, value: unknown): void,
521
+ emit(event: string, data: unknown): void,
522
+ log(level: string, ...args: unknown[]): void
523
+ };
524
+ ```
525
+
526
+ **Snapshot** creates filesystem archives:
527
+ ```typescript
528
+ export async function createSnapshot(
529
+ dir: string,
530
+ options?: CreateSnapshotOptions
531
+ ): Promise<Snapshot>
532
+
533
+ export async function restoreFromSnapshot(
534
+ snapshot: Snapshot,
535
+ targetDir: string
536
+ ): Promise<RestoreResult>
537
+ ```
538
+
539
+ ### API Layer
540
+
541
+ **Routes** define REST endpoints:
542
+ ```typescript
543
+ export interface Route {
544
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
545
+ path: string | RegExp;
546
+ handler: RequestHandler;
547
+ }
548
+
549
+ export function createApiRoutes(config: ApiRoutesConfig): Route[]
550
+ ```
551
+
552
+ **Auth** provides middleware:
553
+ ```typescript
554
+ export function createAuthMiddleware(
555
+ config: AuthConfig
556
+ ): (req, res, pathname) => Promise<boolean>
557
+
558
+ export function createRateLimiter(
559
+ config: RateLimitConfig
560
+ ): (req, res) => boolean
561
+ ```
562
+
563
+ ## Testing
564
+
565
+ ### Test Structure
566
+
567
+ Tests are organized by type:
568
+
569
+ ```
570
+ src/__tests__/
571
+ ├── unit/ # Unit tests (isolated)
572
+ ├── integration/ # Integration tests (multiple modules)
573
+ ├── e2e/ # End-to-end tests (full workflows)
574
+ ├── fixtures/ # Test data and sample apps
575
+ └── mocks/ # Mock implementations
576
+ ```
577
+
578
+ ### Running Tests
579
+
580
+ ```bash
581
+ # All tests
582
+ npm test
583
+
584
+ # Unit tests only
585
+ npx vitest src/__tests__/unit/
586
+
587
+ # Integration tests
588
+ npx vitest src/__tests__/integration/
589
+
590
+ # E2E tests (requires credentials)
591
+ npx vitest src/__tests__/e2e/
592
+
593
+ # Specific file
594
+ npx vitest src/__tests__/unit/app-state.test.ts
595
+
596
+ # Watch mode
597
+ npm run test:watch
598
+
599
+ # Coverage report
600
+ npm run test:coverage
601
+ ```
602
+
603
+ ### Writing Tests
604
+
605
+ Use Vitest with TypeScript:
606
+
607
+ ```typescript
608
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
609
+ import { AppState } from '../../core/app-state.js';
610
+
611
+ describe('AppState', () => {
612
+ let appState: AppState;
613
+
614
+ beforeEach(() => {
615
+ appState = new AppState();
616
+ });
617
+
618
+ describe('log()', () => {
619
+ it('adds log entry with timestamp', () => {
620
+ appState.log('info', 'test message');
621
+ const logs = appState.getLogs();
622
+
623
+ expect(logs).toHaveLength(1);
624
+ expect(logs[0].type).toBe('info');
625
+ expect(logs[0].message).toBe('test message');
626
+ expect(logs[0].timestamp).toBeDefined();
627
+ });
628
+
629
+ it('maintains circular buffer', () => {
630
+ // Add more than maxLogs
631
+ for (let i = 0; i < 600; i++) {
632
+ appState.log('info', `message ${i}`);
633
+ }
634
+
635
+ const logs = appState.getLogs();
636
+ expect(logs).toHaveLength(500);
637
+ expect(logs[0].message).toBe('message 100');
638
+ });
639
+ });
640
+ });
641
+ ```
642
+
643
+ ### Mock System
644
+
645
+ Mocks for testing without external dependencies:
646
+
647
+ **MockSandbox** (`__tests__/mocks/sandbox-mock.ts`):
648
+ ```typescript
649
+ export class MockSandbox {
650
+ files: Map<string, string> = new Map();
651
+ commands: { cmd: string; args: string[] }[] = [];
652
+
653
+ async writeFiles(files: SandboxFile[]): Promise<void>
654
+ async runCommand(options: any): Promise<CommandResult>
655
+ async stop(): Promise<void>
656
+ }
657
+ ```
658
+
659
+ **MockAnthropicClient** (`__tests__/mocks/anthropic-mock.ts`):
660
+ ```typescript
661
+ export function createMockQuery() {
662
+ return async function* (options: any) {
663
+ yield { type: 'text', content: 'Mock response' };
664
+ yield { type: 'done' };
665
+ };
666
+ }
667
+ ```
668
+
669
+ Usage in tests:
670
+ ```typescript
671
+ import { vi } from 'vitest';
672
+ import { MockSandbox } from '../mocks/sandbox-mock.js';
673
+
674
+ vi.mock('@vercel/sandbox', () => ({
675
+ Sandbox: MockSandbox
676
+ }));
677
+ ```
678
+
679
+ ## Contributing
680
+
681
+ ### Code Style
682
+
683
+ - **TypeScript**: Strict mode enabled
684
+ - **Formatting**: Prettier with 2-space indents
685
+ - **Linting**: ESLint with TypeScript rules
686
+ - **Naming**:
687
+ - Classes: PascalCase (`AppState`, `ProcessManager`)
688
+ - Functions: camelCase (`loadConfig`, `createTool`)
689
+ - Constants: UPPER_SNAKE_CASE (`MAX_LOGS`)
690
+ - Types/Interfaces: PascalCase (`LogEntry`, `ReflexiveConfig`)
691
+
692
+ Run before committing:
693
+ ```bash
694
+ npm run lint
695
+ npm run typecheck
696
+ npm test
697
+ ```
698
+
699
+ ### Commit Messages
700
+
701
+ Follow conventional commits:
702
+
703
+ ```
704
+ feat: add sandbox snapshot creation
705
+ fix: resolve memory leak in log buffer
706
+ docs: update API reference for new tools
707
+ test: add integration tests for ProcessManager
708
+ refactor: extract config loading to separate module
709
+ chore: update dependencies
710
+ ```
711
+
712
+ ### Pull Request Process
713
+
714
+ 1. **Fork and Branch**
715
+ ```bash
716
+ git checkout -b feature/my-feature
717
+ ```
718
+
719
+ 2. **Make Changes**
720
+ - Write code with tests
721
+ - Update documentation
722
+ - Run linter and tests
723
+
724
+ 3. **Commit**
725
+ ```bash
726
+ git add .
727
+ git commit -m "feat: add my feature"
728
+ ```
729
+
730
+ 4. **Push and PR**
731
+ ```bash
732
+ git push origin feature/my-feature
733
+ ```
734
+ - Open PR on GitHub
735
+ - Fill in PR template
736
+ - Link related issues
737
+
738
+ 5. **Review**
739
+ - Address review comments
740
+ - Keep PR updated with main
741
+
742
+ 6. **Merge**
743
+ - Squash and merge
744
+ - Delete branch
745
+
746
+ ### Issue Guidelines
747
+
748
+ **Bug Reports** should include:
749
+ - Reflexive version
750
+ - Node.js version
751
+ - Operating system
752
+ - Minimal reproduction
753
+ - Expected vs actual behavior
754
+ - Logs/screenshots
755
+
756
+ **Feature Requests** should include:
757
+ - Use case description
758
+ - Proposed API/UX
759
+ - Alternatives considered
760
+ - Willingness to implement
761
+
762
+ ## Extending Reflexive
763
+
764
+ ### Adding Custom Tools
765
+
766
+ Create a custom tool module:
767
+
768
+ ```typescript
769
+ // tools/database-tools.ts
770
+ import { createTool, textResult, jsonResult } from 'reflexive/mcp/tools';
771
+ import { z } from 'zod';
772
+
773
+ export const queryDatabaseTool = createTool(
774
+ 'query_database',
775
+ 'Execute SQL query',
776
+ z.object({
777
+ sql: z.string().describe('SQL query to execute')
778
+ }),
779
+ async ({ sql }) => {
780
+ const results = await db.query(sql);
781
+ return jsonResult(results);
782
+ }
783
+ );
784
+
785
+ export const getDatabaseStatsTool = createTool(
786
+ 'get_database_stats',
787
+ 'Get database statistics',
788
+ z.object({}),
789
+ async () => {
790
+ const stats = await db.getStats();
791
+ return textResult(`Tables: ${stats.tables}, Size: ${stats.size}`);
792
+ }
793
+ );
794
+ ```
795
+
796
+ Use in your app:
797
+ ```typescript
798
+ import { makeReflexive } from 'reflexive';
799
+ import { queryDatabaseTool, getDatabaseStatsTool } from './tools/database-tools.js';
800
+
801
+ const r = makeReflexive({
802
+ tools: [queryDatabaseTool, getDatabaseStatsTool]
803
+ });
804
+ ```
805
+
806
+ ### Creating New Managers
807
+
808
+ Implement the `BaseManager` interface:
809
+
810
+ ```typescript
811
+ import { BaseManager } from 'reflexive/types/manager';
812
+ import { AppState } from 'reflexive/core/app-state';
813
+ import { EventEmitter } from 'events';
814
+
815
+ export class CustomManager extends EventEmitter implements BaseManager {
816
+ private appState: AppState;
817
+ private running = false;
818
+
819
+ constructor(options: CustomManagerOptions) {
820
+ super();
821
+ this.appState = options.appState || new AppState();
822
+ }
823
+
824
+ async start(entry: string, args?: string[]): Promise<void> {
825
+ // Implementation
826
+ this.running = true;
827
+ this.emit('start', { entry });
828
+ }
829
+
830
+ async stop(): Promise<void> {
831
+ // Implementation
832
+ this.running = false;
833
+ this.emit('stop');
834
+ }
835
+
836
+ async restart(): Promise<void> {
837
+ await this.stop();
838
+ await this.start();
839
+ }
840
+
841
+ isRunning(): boolean {
842
+ return this.running;
843
+ }
844
+
845
+ getLogs(count?: number): LogEntry[] {
846
+ return this.appState.getLogs(count);
847
+ }
848
+
849
+ // ... implement other BaseManager methods
850
+ }
851
+ ```
852
+
853
+ ### Adding Storage Providers
854
+
855
+ Implement the `StorageProvider` interface:
856
+
857
+ ```typescript
858
+ import { StorageProvider, Snapshot } from 'reflexive/sandbox/storage';
859
+
860
+ export class CustomStorageProvider implements StorageProvider {
861
+ async save(snapshot: Snapshot): Promise<string> {
862
+ // Save snapshot, return ID
863
+ const id = generateId();
864
+ await this.backend.write(id, JSON.stringify(snapshot));
865
+ return id;
866
+ }
867
+
868
+ async load(id: string): Promise<Snapshot> {
869
+ // Load snapshot by ID
870
+ const data = await this.backend.read(id);
871
+ return JSON.parse(data);
872
+ }
873
+
874
+ async delete(id: string): Promise<void> {
875
+ // Delete snapshot
876
+ await this.backend.delete(id);
877
+ }
878
+
879
+ async list(): Promise<Snapshot[]> {
880
+ // List all snapshots
881
+ const ids = await this.backend.listIds();
882
+ return Promise.all(ids.map(id => this.load(id)));
883
+ }
884
+ }
885
+ ```
886
+
887
+ Register the provider:
888
+ ```typescript
889
+ import { createStorageProvider } from 'reflexive/sandbox/storage';
890
+
891
+ const storage = createStorageProvider({
892
+ provider: 'custom',
893
+ config: { /* ... */ }
894
+ });
895
+ ```
896
+
897
+ ---
898
+
899
+ **Next**: See [Deployment Guide](./deployment.md) for production deployment instructions.