claude-recall 0.2.10 → 0.2.12

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 (53) hide show
  1. package/README.md +36 -0
  2. package/dist/cli/claude-recall-cli.js +13 -2
  3. package/dist/cli/commands/live-test.js +245 -0
  4. package/dist/hooks/minimal/post-tool-trigger.js +117 -0
  5. package/dist/hooks/minimal/pre-tool-trigger.js +117 -0
  6. package/dist/hooks/minimal/user-prompt-submit-trigger.js +117 -0
  7. package/dist/mcp/queue-tools.js +532 -0
  8. package/dist/mcp/server.js +26 -2
  9. package/dist/mcp/tools/live-testing-tools.js +231 -0
  10. package/dist/mcp/tools/test-tools.js +320 -0
  11. package/dist/scripts/claude-integration.js +318 -0
  12. package/dist/scripts/fix-test-timeouts.js +77 -0
  13. package/dist/scripts/install.js +138 -0
  14. package/dist/scripts/live-mcp-test.sh +138 -0
  15. package/dist/scripts/mcp-postinstall.js +27 -0
  16. package/dist/scripts/platform-utils.js +258 -0
  17. package/dist/scripts/production-checklist.sh +104 -0
  18. package/dist/scripts/test-claude-code-integration.sh +38 -0
  19. package/dist/scripts/test-memory-search.sh +67 -0
  20. package/dist/scripts/test-persistence.sh +55 -0
  21. package/dist/scripts/test-rate-limiting.sh +63 -0
  22. package/dist/scripts/uninstall.js +100 -0
  23. package/dist/services/hook.js +507 -0
  24. package/dist/services/queue-api.js +549 -0
  25. package/dist/services/queue-consolidation.js +303 -0
  26. package/dist/services/queue-integration.js +378 -0
  27. package/dist/services/queue-migration.js +415 -0
  28. package/dist/services/queue-system-fixed.js +826 -0
  29. package/dist/services/queue-system.js +962 -0
  30. package/dist/services/restart-continuity.js +351 -0
  31. package/dist/testing/auto-correction-engine.js +338 -0
  32. package/dist/testing/live-testing-manager.js +402 -0
  33. package/dist/testing/mock-claude.js +249 -0
  34. package/dist/testing/observable-database.js +178 -0
  35. package/dist/testing/scenario-runner.js +354 -0
  36. package/dist/testing/test-orchestrator.js +328 -0
  37. package/docs/AI_TESTING_ARCHITECTURE.md +351 -0
  38. package/docs/AI_TESTING_IMPLEMENTATION_SUMMARY.md +226 -0
  39. package/docs/hook-configuration-COMPLETED.md +85 -0
  40. package/docs/hook-configuration-implementation-required.md +329 -0
  41. package/docs/sqlite-queue-implementation-final-review.md +219 -0
  42. package/docs/sqlite-queue-implementation-final-status.md +268 -0
  43. package/docs/sqlite-queue-implementation-fixes-summary.md +215 -0
  44. package/docs/sqlite-queue-implementation-fixes.md +255 -0
  45. package/docs/sqlite-queue-implementation-for-hooks-and-mcp-integration.md +428 -0
  46. package/docs/sqlite-queue-implementation-improvements-summary.md +211 -0
  47. package/docs/sqlite-queue-implementation-issues-5.md +211 -0
  48. package/docs/sqlite-queue-implementation-issues-6.md +273 -0
  49. package/docs/sqlite-queue-implementation-issues-7.md +253 -0
  50. package/docs/sqlite-queue-implementation-issues-8.md +252 -0
  51. package/docs/sqlite-queue-implementation-review.md +275 -0
  52. package/docs/test-isolation-improvements.md +222 -0
  53. package/package.json +3 -9
package/README.md CHANGED
@@ -16,6 +16,8 @@ Every time you start a new conversation with Claude, you're starting from scratc
16
16
  - **MCP Native**: Built on Anthropic's official Model Context Protocol for seamless integration
17
17
  - **Zero Configuration**: Start capturing memories immediately after installation
18
18
  - **Lightweight**: SQLite database with automatic memory management
19
+ - **Restart Continuity**: Maintains state across Claude Code restarts for uninterrupted workflows
20
+ - **Live Testing**: AI-driven testing with automatic restart and recovery capabilities
19
21
 
20
22
  ## 🚀 Quick Start
21
23
 
@@ -169,6 +171,40 @@ No manual configuration needed!
169
171
  - **You Own Your Data**: Export and delete at any time
170
172
  - **Open Source**: Inspect the code yourself
171
173
 
174
+ ## Restart Continuity & Live Testing (v0.2.11+)
175
+
176
+ Claude Recall now includes advanced restart continuity and live testing capabilities, ensuring your workflows continue seamlessly even when Claude Code needs to restart.
177
+
178
+ ### Restart Continuity
179
+
180
+ Maintains state across Claude Code restarts:
181
+ - **Automatic Recovery**: Resumes interrupted tests and workflows after restart
182
+ - **Checkpoint System**: Save progress points for granular recovery
183
+ - **Session Tracking**: Preserves session context through restarts
184
+ - **Pending Actions**: Queues actions to be processed after restart
185
+
186
+ ### Live Testing
187
+
188
+ AI-driven testing with automatic restart capability:
189
+ ```bash
190
+ # Start live testing with auto-restart
191
+ claude-recall live-test start -s memory_persistence search_compliance
192
+
193
+ # Check status
194
+ claude-recall live-test status
195
+
196
+ # View continuity state
197
+ claude-recall live-test continuity
198
+ ```
199
+
200
+ **Features:**
201
+ - **Auto-Restart on Changes**: Detects hook/CLI changes and restarts automatically
202
+ - **Test Recovery**: Resumes tests from last checkpoint after restart
203
+ - **Result Injection**: Test results stored as searchable memories
204
+ - **Configurable Policies**: Control restart behavior and limits
205
+
206
+ See [RESTART_CONTINUITY.md](docs/RESTART_CONTINUITY.md) for detailed documentation.
207
+
172
208
  ## Advanced Usage
173
209
 
174
210
  ### Custom Memory Storage
@@ -43,6 +43,7 @@ const pattern_service_1 = require("../services/pattern-service");
43
43
  const migrate_1 = require("./commands/migrate");
44
44
  const server_1 = require("../mcp/server");
45
45
  const search_monitor_1 = require("../services/search-monitor");
46
+ const live_test_1 = require("./commands/live-test");
46
47
  const program = new commander_1.Command();
47
48
  class ClaudeRecallCLI {
48
49
  constructor(options) {
@@ -252,7 +253,7 @@ async function main() {
252
253
  program
253
254
  .name('claude-recall')
254
255
  .description('Memory-enhanced Claude Code via MCP')
255
- .version('0.2.10')
256
+ .version('0.2.12')
256
257
  .option('--verbose', 'Enable verbose logging')
257
258
  .option('--config <path>', 'Path to custom config file');
258
259
  // MCP command
@@ -318,6 +319,8 @@ async function main() {
318
319
  });
319
320
  // Migration commands
320
321
  migrate_1.MigrateCommand.register(program);
322
+ // Register live test command
323
+ new live_test_1.LiveTestCommand().register(program);
321
324
  // Search command
322
325
  program
323
326
  .command('search <query>')
@@ -330,6 +333,7 @@ async function main() {
330
333
  limit: parseInt(options.limit),
331
334
  json: options.json
332
335
  });
336
+ process.exit(0);
333
337
  });
334
338
  // Stats command
335
339
  program
@@ -338,6 +342,7 @@ async function main() {
338
342
  .action(() => {
339
343
  const cli = new ClaudeRecallCLI(program.opts());
340
344
  cli.showStats();
345
+ process.exit(0);
341
346
  });
342
347
  // Export command
343
348
  program
@@ -347,6 +352,7 @@ async function main() {
347
352
  .action(async (output, options) => {
348
353
  const cli = new ClaudeRecallCLI(program.opts());
349
354
  await cli.export(output, options);
355
+ process.exit(0);
350
356
  });
351
357
  // Import command
352
358
  program
@@ -355,6 +361,7 @@ async function main() {
355
361
  .action(async (input) => {
356
362
  const cli = new ClaudeRecallCLI(program.opts());
357
363
  await cli.import(input);
364
+ process.exit(0);
358
365
  });
359
366
  // Clear command
360
367
  program
@@ -365,6 +372,7 @@ async function main() {
365
372
  .action(async (options) => {
366
373
  const cli = new ClaudeRecallCLI(program.opts());
367
374
  await cli.clear(options);
375
+ process.exit(0);
368
376
  });
369
377
  // Status command
370
378
  program
@@ -373,6 +381,7 @@ async function main() {
373
381
  .action(async () => {
374
382
  const cli = new ClaudeRecallCLI(program.opts());
375
383
  await cli.status();
384
+ process.exit(0);
376
385
  });
377
386
  // Test memory search command
378
387
  program
@@ -412,6 +421,7 @@ async function main() {
412
421
  }
413
422
  console.log('\n📊 Memory search monitoring is active.');
414
423
  console.log(' Check logs to verify search calls are being made.\n');
424
+ process.exit(0);
415
425
  });
416
426
  // Search monitor command
417
427
  program
@@ -423,7 +433,7 @@ async function main() {
423
433
  if (options.clear) {
424
434
  monitor.clearLogs();
425
435
  console.log('✅ Search monitoring logs cleared.\n');
426
- return;
436
+ process.exit(0);
427
437
  }
428
438
  console.log('\n📊 Memory Search Monitoring Statistics\n');
429
439
  const stats = monitor.getSearchStats();
@@ -459,6 +469,7 @@ async function main() {
459
469
  });
460
470
  }
461
471
  console.log('\n');
472
+ process.exit(0);
462
473
  });
463
474
  // Parse arguments
464
475
  await program.parseAsync(process.argv);
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LiveTestCommand = void 0;
4
+ const live_testing_manager_1 = require("../../testing/live-testing-manager");
5
+ const restart_continuity_1 = require("../../services/restart-continuity");
6
+ const logging_1 = require("../../services/logging");
7
+ class LiveTestCommand {
8
+ constructor() {
9
+ this.liveTestManager = live_testing_manager_1.LiveTestingManager.getInstance();
10
+ this.continuityManager = restart_continuity_1.RestartContinuityManager.getInstance();
11
+ this.logger = logging_1.LoggingService.getInstance();
12
+ }
13
+ register(program) {
14
+ const liveTestCmd = program
15
+ .command('live-test')
16
+ .description('Manage live testing with automatic restart capability');
17
+ // Start live testing
18
+ liveTestCmd
19
+ .command('start')
20
+ .description('Start a live testing session')
21
+ .option('-s, --scenario <scenarios...>', 'Test scenarios to run', ['memory_persistence', 'search_compliance'])
22
+ .option('-a, --auto-restart', 'Enable automatic restart on changes', true)
23
+ .option('-r, --restart-on-failure', 'Restart on test failures', true)
24
+ .option('-m, --max-restarts <number>', 'Maximum restart attempts', '3')
25
+ .option('-i, --inject-results', 'Inject test results as memories', true)
26
+ .action(async (options) => {
27
+ await this.startLiveTest(options);
28
+ });
29
+ // Check status
30
+ liveTestCmd
31
+ .command('status')
32
+ .description('Check live testing and continuity status')
33
+ .action(() => {
34
+ this.showStatus();
35
+ });
36
+ // Stop testing
37
+ liveTestCmd
38
+ .command('stop')
39
+ .description('Stop the current live testing session')
40
+ .action(async () => {
41
+ await this.stopLiveTest();
42
+ });
43
+ // Check continuity
44
+ liveTestCmd
45
+ .command('continuity')
46
+ .description('Show continuity state and restart information')
47
+ .action(() => {
48
+ this.showContinuity();
49
+ });
50
+ // Add checkpoint
51
+ liveTestCmd
52
+ .command('checkpoint <name>')
53
+ .description('Add a checkpoint for restart recovery')
54
+ .action((name) => {
55
+ this.addCheckpoint(name);
56
+ });
57
+ // Simulate restart
58
+ liveTestCmd
59
+ .command('restart')
60
+ .description('Simulate a restart for testing')
61
+ .option('-r, --reason <reason>', 'Reason for restart', 'manual_test')
62
+ .action((options) => {
63
+ this.simulateRestart(options.reason);
64
+ });
65
+ }
66
+ async startLiveTest(options) {
67
+ console.log('🚀 Starting Live Testing Session');
68
+ console.log('━'.repeat(50));
69
+ try {
70
+ // Parse scenarios
71
+ const scenarios = options.scenario.map((name) => ({
72
+ name,
73
+ params: {},
74
+ sessionId: `cli_${Date.now()}`
75
+ }));
76
+ // Configure live testing
77
+ this.liveTestManager.updateConfig({
78
+ autoRestart: options.autoRestart,
79
+ restartOnFailure: options.restartOnFailure,
80
+ maxRestartAttempts: parseInt(options.maxRestarts),
81
+ restartDelay: 2000,
82
+ watchFiles: [
83
+ 'src/hooks/**/*.sh',
84
+ 'src/cli/claude-recall-cli.ts',
85
+ 'src/services/**/*.ts'
86
+ ],
87
+ injectResults: options.injectResults
88
+ });
89
+ // Start session
90
+ const sessionId = await this.liveTestManager.startLiveTestSession(scenarios);
91
+ console.log('✅ Live testing session started');
92
+ console.log(`Session ID: ${sessionId}`);
93
+ console.log(`Scenarios: ${scenarios.map(s => s.name).join(', ')}`);
94
+ console.log();
95
+ console.log('Configuration:');
96
+ console.log(` • Auto-restart: ${options.autoRestart ? 'enabled' : 'disabled'}`);
97
+ console.log(` • Restart on failure: ${options.restartOnFailure ? 'enabled' : 'disabled'}`);
98
+ console.log(` • Max restarts: ${options.maxRestarts}`);
99
+ console.log(` • Inject results: ${options.injectResults ? 'enabled' : 'disabled'}`);
100
+ console.log();
101
+ console.log('Watching for file changes...');
102
+ console.log('Use "claude-recall live-test status" to check progress');
103
+ }
104
+ catch (error) {
105
+ console.error('❌ Failed to start live testing:', error.message);
106
+ process.exit(1);
107
+ }
108
+ }
109
+ showStatus() {
110
+ console.log('📊 Live Testing Status');
111
+ console.log('━'.repeat(50));
112
+ // Get live test status
113
+ const liveStatus = this.liveTestManager.getSessionStatus();
114
+ if (liveStatus.status === 'no_active_session') {
115
+ console.log('No active live testing session');
116
+ }
117
+ else {
118
+ console.log(`Session ID: ${liveStatus.sessionId}`);
119
+ console.log(`Status: ${this.getStatusEmoji(liveStatus.status)} ${liveStatus.status}`);
120
+ console.log(`Progress: ${liveStatus.testsRun}/${liveStatus.totalTests} tests`);
121
+ console.log(`Restart attempts: ${liveStatus.restartAttempts}`);
122
+ if (liveStatus.results && liveStatus.results.length > 0) {
123
+ console.log();
124
+ console.log('Test Results:');
125
+ liveStatus.results.forEach((result) => {
126
+ const emoji = result.status === 'passed' ? '✅' : result.status === 'failed' ? '❌' : '⚠️';
127
+ console.log(` ${emoji} ${result.test}: ${result.status}`);
128
+ });
129
+ }
130
+ }
131
+ // Get continuity status
132
+ const continuityState = this.continuityManager.getCurrentState();
133
+ if (continuityState) {
134
+ console.log();
135
+ console.log('🔄 Continuity State');
136
+ console.log('━'.repeat(50));
137
+ console.log(`Session: ${continuityState.sessionId}`);
138
+ console.log(`Restarts: ${continuityState.restartCount}`);
139
+ console.log(`Test in progress: ${continuityState.testInProgress ? 'yes' : 'no'}`);
140
+ if (continuityState.currentTest) {
141
+ console.log(`Current test: ${continuityState.currentTest.name}`);
142
+ console.log(`Checkpoints: ${continuityState.currentTest.checkpoints.length}`);
143
+ }
144
+ if (continuityState.pendingActions.length > 0) {
145
+ console.log();
146
+ console.log(`Pending actions: ${continuityState.pendingActions.length}`);
147
+ }
148
+ }
149
+ // Stop monitoring to allow process to exit
150
+ this.continuityManager.stopMonitoring();
151
+ }
152
+ async stopLiveTest() {
153
+ console.log('🛑 Stopping Live Testing');
154
+ try {
155
+ await this.liveTestManager.stopLiveTestSession();
156
+ console.log('✅ Live testing session stopped');
157
+ }
158
+ catch (error) {
159
+ console.error('❌ Failed to stop live testing:', error.message);
160
+ }
161
+ }
162
+ showContinuity() {
163
+ console.log('🔄 Continuity Information');
164
+ console.log('━'.repeat(50));
165
+ const state = this.continuityManager.getCurrentState();
166
+ if (!state) {
167
+ console.log('No continuity state available');
168
+ return;
169
+ }
170
+ console.log('Session Information:');
171
+ console.log(` • ID: ${state.sessionId}`);
172
+ console.log(` • Restart count: ${state.restartCount}`);
173
+ console.log(` • Last activity: ${new Date(state.lastActivity).toLocaleString()}`);
174
+ console.log();
175
+ if (state.testInProgress && state.currentTest) {
176
+ console.log('Current Test:');
177
+ console.log(` • Name: ${state.currentTest.name}`);
178
+ console.log(` • Started: ${new Date(state.currentTest.startTime).toLocaleString()}`);
179
+ console.log(` • Checkpoints: ${state.currentTest.checkpoints.length}`);
180
+ if (state.currentTest.checkpoints.length > 0) {
181
+ console.log(' • Recent checkpoints:');
182
+ state.currentTest.checkpoints.slice(-3).forEach(cp => {
183
+ console.log(` - ${cp}`);
184
+ });
185
+ }
186
+ }
187
+ else {
188
+ console.log('No test currently in progress');
189
+ }
190
+ if (state.pendingActions.length > 0) {
191
+ console.log();
192
+ console.log(`Pending Actions (${state.pendingActions.length}):`);
193
+ state.pendingActions.forEach(action => {
194
+ console.log(` • ${action.type} - ${new Date(action.timestamp).toLocaleString()}`);
195
+ });
196
+ }
197
+ // Stop monitoring to allow process to exit
198
+ this.continuityManager.stopMonitoring();
199
+ }
200
+ addCheckpoint(name) {
201
+ console.log('➕ Adding Checkpoint');
202
+ try {
203
+ this.continuityManager.addCheckpoint(name);
204
+ console.log(`✅ Checkpoint added: ${name}`);
205
+ const state = this.continuityManager.getCurrentState();
206
+ if (state?.currentTest) {
207
+ console.log(`Total checkpoints: ${state.currentTest.checkpoints.length}`);
208
+ }
209
+ }
210
+ catch (error) {
211
+ console.error('❌ Failed to add checkpoint:', error.message);
212
+ }
213
+ finally {
214
+ // Stop monitoring to allow process to exit
215
+ this.continuityManager.stopMonitoring();
216
+ }
217
+ }
218
+ simulateRestart(reason) {
219
+ console.log('🔄 Simulating Restart');
220
+ console.log('━'.repeat(50));
221
+ console.log(`Reason: ${reason}`);
222
+ console.log('Note: This simulates a restart for testing purposes');
223
+ console.log('In production, Claude Code would actually restart');
224
+ // Add restart action to continuity
225
+ this.continuityManager.addPendingAction('simulated_restart', {
226
+ reason,
227
+ timestamp: Date.now()
228
+ });
229
+ console.log();
230
+ console.log('✅ Restart simulation recorded');
231
+ console.log('The restart will be detected on next actual restart');
232
+ // Stop monitoring to allow process to exit
233
+ this.continuityManager.stopMonitoring();
234
+ }
235
+ getStatusEmoji(status) {
236
+ switch (status) {
237
+ case 'running': return '🏃';
238
+ case 'completed': return '✅';
239
+ case 'failed': return '❌';
240
+ case 'restarting': return '🔄';
241
+ default: return '❓';
242
+ }
243
+ }
244
+ }
245
+ exports.LiveTestCommand = LiveTestCommand;
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Minimal Post-Tool Hook Trigger
5
+ *
6
+ * This is a lightweight trigger that delegates all business logic
7
+ * to the claude-recall-cli service layer. This hook only handles
8
+ * data forwarding and process management.
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ const child_process_1 = require("child_process");
45
+ const path = __importStar(require("path"));
46
+ // Determine CLI path - prefer built version, fallback to source
47
+ const CLI_PATHS = [
48
+ path.join(__dirname, '../../dist/cli/claude-recall-cli.js'),
49
+ path.join(__dirname, '../../cli/claude-recall-cli.js'),
50
+ 'claude-recall-cli' // Global installation
51
+ ];
52
+ function findCliPath() {
53
+ const fs = require('fs');
54
+ for (const cliPath of CLI_PATHS) {
55
+ try {
56
+ if (fs.existsSync(cliPath)) {
57
+ return cliPath;
58
+ }
59
+ }
60
+ catch (error) {
61
+ // Continue to next path
62
+ }
63
+ }
64
+ // Fallback to global command
65
+ return 'claude-recall-cli';
66
+ }
67
+ async function executeCLI() {
68
+ return new Promise((resolve, reject) => {
69
+ const cliPath = findCliPath();
70
+ const isGlobal = cliPath === 'claude-recall-cli';
71
+ // Spawn the CLI process
72
+ const child = (0, child_process_1.spawn)(isGlobal ? cliPath : 'node', isGlobal ? ['post-tool'] : [cliPath, 'post-tool'], {
73
+ stdio: ['pipe', 'inherit', 'inherit'],
74
+ env: process.env
75
+ });
76
+ // Forward stdin data to CLI
77
+ process.stdin.pipe(child.stdin);
78
+ child.on('close', (code) => {
79
+ if (code === 0) {
80
+ resolve();
81
+ }
82
+ else {
83
+ reject(new Error(`CLI process exited with code ${code}`));
84
+ }
85
+ });
86
+ child.on('error', (error) => {
87
+ reject(error);
88
+ });
89
+ // Handle process signals
90
+ process.on('SIGTERM', () => child.kill('SIGTERM'));
91
+ process.on('SIGINT', () => child.kill('SIGINT'));
92
+ });
93
+ }
94
+ // Main execution
95
+ async function main() {
96
+ try {
97
+ await executeCLI();
98
+ process.exit(0);
99
+ }
100
+ catch (error) {
101
+ console.error('Post-tool hook error:', error);
102
+ process.exit(1);
103
+ }
104
+ }
105
+ // Handle timeout at process level
106
+ const timeout = parseInt(process.env.CLAUDE_RECALL_HOOK_TIMEOUT || '5000');
107
+ const timeoutHandle = setTimeout(() => {
108
+ console.error('Post-tool hook timeout');
109
+ process.exit(1);
110
+ }, timeout);
111
+ // Clear timeout when we start processing
112
+ process.stdin.once('data', () => {
113
+ clearTimeout(timeoutHandle);
114
+ });
115
+ if (require.main === module) {
116
+ main();
117
+ }
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Minimal Pre-Tool Hook Trigger
5
+ *
6
+ * This is a lightweight trigger that delegates all business logic
7
+ * to the claude-recall-cli service layer. This hook only handles
8
+ * data forwarding and process management.
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ const child_process_1 = require("child_process");
45
+ const path = __importStar(require("path"));
46
+ // Determine CLI path - prefer built version, fallback to source
47
+ const CLI_PATHS = [
48
+ path.join(__dirname, '../../dist/cli/claude-recall-cli.js'),
49
+ path.join(__dirname, '../../cli/claude-recall-cli.js'),
50
+ 'claude-recall-cli' // Global installation
51
+ ];
52
+ function findCliPath() {
53
+ const fs = require('fs');
54
+ for (const cliPath of CLI_PATHS) {
55
+ try {
56
+ if (fs.existsSync(cliPath)) {
57
+ return cliPath;
58
+ }
59
+ }
60
+ catch (error) {
61
+ // Continue to next path
62
+ }
63
+ }
64
+ // Fallback to global command
65
+ return 'claude-recall-cli';
66
+ }
67
+ async function executeCLI() {
68
+ return new Promise((resolve, reject) => {
69
+ const cliPath = findCliPath();
70
+ const isGlobal = cliPath === 'claude-recall-cli';
71
+ // Spawn the CLI process
72
+ const child = (0, child_process_1.spawn)(isGlobal ? cliPath : 'node', isGlobal ? ['pre-tool'] : [cliPath, 'pre-tool'], {
73
+ stdio: ['pipe', 'inherit', 'inherit'],
74
+ env: process.env
75
+ });
76
+ // Forward stdin data to CLI
77
+ process.stdin.pipe(child.stdin);
78
+ child.on('close', (code) => {
79
+ if (code === 0) {
80
+ resolve();
81
+ }
82
+ else {
83
+ reject(new Error(`CLI process exited with code ${code}`));
84
+ }
85
+ });
86
+ child.on('error', (error) => {
87
+ reject(error);
88
+ });
89
+ // Handle process signals
90
+ process.on('SIGTERM', () => child.kill('SIGTERM'));
91
+ process.on('SIGINT', () => child.kill('SIGINT'));
92
+ });
93
+ }
94
+ // Main execution
95
+ async function main() {
96
+ try {
97
+ await executeCLI();
98
+ process.exit(0);
99
+ }
100
+ catch (error) {
101
+ console.error('Pre-tool hook error:', error);
102
+ process.exit(1);
103
+ }
104
+ }
105
+ // Handle timeout at process level
106
+ const timeout = parseInt(process.env.CLAUDE_RECALL_HOOK_TIMEOUT || '5000');
107
+ const timeoutHandle = setTimeout(() => {
108
+ console.error('Pre-tool hook timeout');
109
+ process.exit(1);
110
+ }, timeout);
111
+ // Clear timeout when we start processing
112
+ process.stdin.once('data', () => {
113
+ clearTimeout(timeoutHandle);
114
+ });
115
+ if (require.main === module) {
116
+ main();
117
+ }