claude-recall 0.37.0 → 0.37.1
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/.claude/hooks/search_enforcer.py +29 -2
- package/README.md +1 -1
- package/dist/cli/claude-recall-cli.js +7 -2
- package/dist/memory/schema.sql +0 -0
- package/docs/hooks.md +1 -1
- package/package.json +1 -1
- package/scripts/uninstall.js +0 -0
- package/dist/cli/commands/live-test.js +0 -245
- package/dist/cli/commands/migrate.js +0 -317
- package/dist/core/patterns.js +0 -56
- package/dist/hooks/bash-failure-watcher.js +0 -253
- package/dist/mcp/memory-capture-middleware.js +0 -349
- package/dist/mcp/queue-tools.js +0 -532
- package/dist/mcp/tools/live-testing-tools.js +0 -231
- package/dist/mcp/tools/test-tools.js +0 -320
- package/dist/memory/database-adapter.js +0 -256
- package/dist/memory/pattern-store.js +0 -68
- package/dist/services/claude-json-watcher.js +0 -243
- package/dist/services/context-enhancer.js +0 -215
- package/dist/services/conversation-context-manager.js +0 -254
- package/dist/services/embedding-service.js +0 -183
- package/dist/services/memory-enhancer.js +0 -148
- package/dist/services/memory-evolution.js +0 -249
- package/dist/services/memory-usage-tracker.js +0 -227
- package/dist/services/preference-analyzer.js +0 -242
- package/dist/services/queue-api.js +0 -560
- package/dist/services/queue-integration.js +0 -409
- package/dist/services/queue-migration.js +0 -415
- package/dist/services/queue-system.js +0 -1092
- package/dist/services/restart-continuity.js +0 -361
- package/dist/services/semantic-preference-extractor.js +0 -432
- package/dist/testing/auto-correction-engine.js +0 -338
- package/dist/testing/live-testing-manager.js +0 -402
- package/dist/testing/mock-claude.js +0 -249
- package/dist/testing/observable-database.js +0 -178
- package/dist/testing/scenario-runner.js +0 -354
- package/dist/testing/test-orchestrator.js +0 -328
- package/docs/2026-07-follow-up-article-draft.md +0 -68
- package/docs/2026-07-follow-up-article-linkedin-tight.md +0 -46
- package/docs/2026-07-positioning-vs-steering-files.md +0 -92
- package/docs/design-hybrid-retrieval-fts5.md +0 -185
- package/docs/using-claude-code-subscription-instead-of-api-key.md +0 -69
|
@@ -16,7 +16,29 @@ from datetime import datetime
|
|
|
16
16
|
|
|
17
17
|
STATE_DIR = Path.home() / '.claude-recall' / 'hook-state'
|
|
18
18
|
SEARCH_TTL_MS = int(os.environ.get('CLAUDE_RECALL_SEARCH_TTL', 60 * 1000)) # 1 min default (once per task)
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _resolve_enforce_mode() -> str:
|
|
22
|
+
"""Enforcement mode: env var wins, then ~/.claude-recall/config.json
|
|
23
|
+
("enforceMode"), else default 'warn'. A file-based switch is reachable
|
|
24
|
+
from inside a running session (an agent can edit config.json to escape a
|
|
25
|
+
stuck gate); an env var set before launch is not. Default is 'warn' — this
|
|
26
|
+
gate is an advisory nudge (see module docstring), so it should never
|
|
27
|
+
hard-block a session by default."""
|
|
28
|
+
env = os.environ.get('CLAUDE_RECALL_ENFORCE_MODE')
|
|
29
|
+
if env:
|
|
30
|
+
return env.strip().lower()
|
|
31
|
+
try:
|
|
32
|
+
cfg = json.load(open(Path.home() / '.claude-recall' / 'config.json'))
|
|
33
|
+
mode = cfg.get('enforceMode')
|
|
34
|
+
if mode:
|
|
35
|
+
return str(mode).strip().lower()
|
|
36
|
+
except Exception:
|
|
37
|
+
pass
|
|
38
|
+
return 'warn'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
ENFORCE_MODE = _resolve_enforce_mode() # block, warn, off
|
|
20
42
|
MAX_BLOCKS = int(os.environ.get('CLAUDE_RECALL_MAX_BLOCKS', 3)) # degrade to warn after N blocks
|
|
21
43
|
|
|
22
44
|
# Tools that count as "search performed"
|
|
@@ -182,6 +204,7 @@ STALE RULES — consider reloading before {tool_name}
|
|
|
182
204
|
|
|
183
205
|
Rules were loaded earlier but TTL expired.
|
|
184
206
|
Run: mcp__claude-recall__load_rules({{}})
|
|
207
|
+
(If not directly callable, ToolSearch it first — see below.)
|
|
185
208
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
186
209
|
"""
|
|
187
210
|
print(msg.strip(), file=sys.stderr)
|
|
@@ -214,10 +237,14 @@ LOAD RULES REQUIRED before {tool_name} (attempt {block_count}/{MAX_BLOCKS})
|
|
|
214
237
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
215
238
|
|
|
216
239
|
Run: mcp__claude-recall__load_rules({{}})
|
|
240
|
+
(If that tool is not directly callable, first run
|
|
241
|
+
ToolSearch({{query:"select:mcp__claude-recall__load_rules"}}) —
|
|
242
|
+
some harnesses defer MCP tool schemas until discovered.)
|
|
217
243
|
|
|
218
244
|
This ensures you apply user preferences and avoid past mistakes.
|
|
219
245
|
|
|
220
|
-
To disable:
|
|
246
|
+
To disable this gate: set "enforceMode":"off" in ~/.claude-recall/config.json
|
|
247
|
+
(or export CLAUDE_RECALL_ENFORCE_MODE=off before launching Claude Code).
|
|
221
248
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
222
249
|
"""
|
|
223
250
|
print(msg.strip(), file=sys.stderr)
|
package/README.md
CHANGED
|
@@ -460,7 +460,7 @@ Defaults work out of the box; tune via environment variables as needed.
|
|
|
460
460
|
| `CLAUDE_RECALL_AUTO_CLEANUP` | `false` | Auto-kill stale MCP processes on start (otherwise reports and exits). |
|
|
461
461
|
| `CLAUDE_RECALL_COMPACT_THRESHOLD` | `10MB` | DB size at which automatic compaction kicks in. |
|
|
462
462
|
| `CLAUDE_RECALL_MAX_MEMORIES` | `10000` | Memory-row soft cap. |
|
|
463
|
-
| `CLAUDE_RECALL_ENFORCE_MODE` | `
|
|
463
|
+
| `CLAUDE_RECALL_ENFORCE_MODE` | `warn` | `block` / `warn` / `off` for the search-enforcer hook. Env wins, else `~/.claude-recall/config.json` `"enforceMode"`, else `warn`. |
|
|
464
464
|
| `CLAUDE_RECALL_LLM_TIMEOUT_MS` | `5000` | Timeout for hook-context LLM calls (classification, hindsight hints). Hooks fall back to regex when it fires. |
|
|
465
465
|
| `CLAUDE_RECALL_STOP_DEBOUNCE_MS` | `300000` | Debounce for the heavy Stop-hook pipeline (episodes, session extraction, promotion). `0` disables. |
|
|
466
466
|
| `CLAUDE_RECALL_PROJECT_ID` | *(cwd)* | Pin the project scope to a fixed id, overriding working-directory detection. |
|
|
@@ -51,9 +51,10 @@ const hook_commands_1 = require("./commands/hook-commands");
|
|
|
51
51
|
const kiro_commands_1 = require("./commands/kiro-commands");
|
|
52
52
|
const repair_1 = require("./commands/repair");
|
|
53
53
|
// v14 = add PreToolUse rule-injector + Post resolver for JITRI.
|
|
54
|
+
// v15 = bound the search_enforcer PreToolUse entry with timeout: 5.
|
|
54
55
|
// Bump when the hook block template changes — setup skips the settings
|
|
55
56
|
// rewrite when the installed hooksVersion already matches.
|
|
56
|
-
const HOOKS_VERSION = '
|
|
57
|
+
const HOOKS_VERSION = '15.0.0';
|
|
57
58
|
const parse_utils_1 = require("./parse-utils");
|
|
58
59
|
const program = new commander_1.Command();
|
|
59
60
|
class ClaudeRecallCLI {
|
|
@@ -1375,7 +1376,11 @@ async function main() {
|
|
|
1375
1376
|
hooks: [
|
|
1376
1377
|
{
|
|
1377
1378
|
type: "command",
|
|
1378
|
-
command: `python3 ${hookDest}
|
|
1379
|
+
command: `python3 ${hookDest}`,
|
|
1380
|
+
// Runs before EVERY tool call (matcher .*). Bound the python3
|
|
1381
|
+
// cold start so it can't become a per-call latency tax or an
|
|
1382
|
+
// unbounded failure mode.
|
|
1383
|
+
timeout: 5
|
|
1379
1384
|
},
|
|
1380
1385
|
{
|
|
1381
1386
|
type: "command",
|
package/dist/memory/schema.sql
CHANGED
|
File without changes
|
package/docs/hooks.md
CHANGED
|
@@ -58,7 +58,7 @@ Common read-only commands are exempt from enforcement:
|
|
|
58
58
|
| Environment Variable | Default | Description |
|
|
59
59
|
|---|---|---|
|
|
60
60
|
| `CLAUDE_RECALL_SEARCH_TTL` | `300000` (5 min) | Milliseconds a search remains valid |
|
|
61
|
-
| `CLAUDE_RECALL_ENFORCE_MODE` | `
|
|
61
|
+
| `CLAUDE_RECALL_ENFORCE_MODE` | `warn` | `block` (exit 2), `warn` (exit 0 + stderr message), or `off` (disabled). Env wins; otherwise read from `~/.claude-recall/config.json` → `"enforceMode"`; else `warn`. The file switch is reachable from inside a running session — an env var set before launch is not. |
|
|
62
62
|
|
|
63
63
|
### Exit Codes
|
|
64
64
|
|
package/package.json
CHANGED
package/scripts/uninstall.js
CHANGED
|
File without changes
|
|
@@ -1,245 +0,0 @@
|
|
|
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;
|
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.MigrateCommand = void 0;
|
|
37
|
-
const memory_1 = require("../../services/memory");
|
|
38
|
-
const fs = __importStar(require("fs"));
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
|
-
const os = __importStar(require("os"));
|
|
41
|
-
class MigrateCommand {
|
|
42
|
-
static register(program) {
|
|
43
|
-
const migrateCmd = program
|
|
44
|
-
.command('migrate')
|
|
45
|
-
.description('Migrate from file-watcher to MCP architecture');
|
|
46
|
-
migrateCmd
|
|
47
|
-
.command('check')
|
|
48
|
-
.description('Check for existing file-watcher installation')
|
|
49
|
-
.action(async () => {
|
|
50
|
-
const migrator = new MigrateCommand();
|
|
51
|
-
await migrator.checkInstallation();
|
|
52
|
-
});
|
|
53
|
-
migrateCmd
|
|
54
|
-
.command('export')
|
|
55
|
-
.description('Export memories from current installation')
|
|
56
|
-
.option('-o, --output <path>', 'Output file path', 'claude-recall-export.json')
|
|
57
|
-
.action(async (options) => {
|
|
58
|
-
const migrator = new MigrateCommand();
|
|
59
|
-
await migrator.exportMemories(options.output);
|
|
60
|
-
});
|
|
61
|
-
migrateCmd
|
|
62
|
-
.command('import')
|
|
63
|
-
.description('Import memories from export file')
|
|
64
|
-
.argument('<file>', 'Export file to import')
|
|
65
|
-
.action(async (file) => {
|
|
66
|
-
const migrator = new MigrateCommand();
|
|
67
|
-
await migrator.importMemories(file);
|
|
68
|
-
});
|
|
69
|
-
migrateCmd
|
|
70
|
-
.command('complete')
|
|
71
|
-
.description('Complete migration process')
|
|
72
|
-
.action(async () => {
|
|
73
|
-
const migrator = new MigrateCommand();
|
|
74
|
-
await migrator.completeMigration();
|
|
75
|
-
});
|
|
76
|
-
migrateCmd
|
|
77
|
-
.command('schema')
|
|
78
|
-
.description('Migrate database schema to latest version (adds missing columns)')
|
|
79
|
-
.option('--backup', 'Create backup before migration')
|
|
80
|
-
.action(async (options) => {
|
|
81
|
-
const migrator = new MigrateCommand();
|
|
82
|
-
await migrator.migrateSchema(options.backup);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
async checkInstallation() {
|
|
86
|
-
console.log('🔍 Checking for existing Claude Recall installation...\n');
|
|
87
|
-
const checks = {
|
|
88
|
-
database: this.checkDatabase(),
|
|
89
|
-
hooks: this.checkHooks(),
|
|
90
|
-
config: this.checkConfig()
|
|
91
|
-
};
|
|
92
|
-
if (checks.database) {
|
|
93
|
-
console.log('✅ Found existing database');
|
|
94
|
-
try {
|
|
95
|
-
const memoryService = memory_1.MemoryService.getInstance();
|
|
96
|
-
const stats = memoryService.getStats();
|
|
97
|
-
console.log(` Contains ${stats.total} memories`);
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
console.log(' (Unable to read memory count)');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
console.log('❌ No existing database found');
|
|
105
|
-
}
|
|
106
|
-
if (checks.hooks) {
|
|
107
|
-
console.log('✅ Found hook configuration in settings.json');
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
console.log('ℹ️ No hooks configured (or using MCP already)');
|
|
111
|
-
}
|
|
112
|
-
if (checks.database || checks.hooks) {
|
|
113
|
-
console.log('\n📋 Next steps:');
|
|
114
|
-
console.log('1. Run: claude-recall migrate export');
|
|
115
|
-
console.log('2. Install MCP server: claude mcp add claude-recall claude-recall mcp start');
|
|
116
|
-
console.log('3. Run: claude-recall migrate import claude-recall-export.json');
|
|
117
|
-
console.log('4. Run: claude-recall migrate complete');
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
console.log('\n✨ No migration needed! Set up MCP directly:');
|
|
121
|
-
console.log(' claude mcp add claude-recall claude-recall mcp start');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
async exportMemories(outputPath) {
|
|
125
|
-
console.log('📦 Exporting memories...\n');
|
|
126
|
-
try {
|
|
127
|
-
// Access database directly for export
|
|
128
|
-
const dbPath = path.join(os.homedir(), '.claude-recall', 'claude-recall.db');
|
|
129
|
-
const { MemoryStorage } = require('../../memory/storage');
|
|
130
|
-
const storage = new MemoryStorage(dbPath);
|
|
131
|
-
const db = storage.getDatabase();
|
|
132
|
-
// Get all memories from database
|
|
133
|
-
const allMemories = db.prepare('SELECT * FROM memories').all();
|
|
134
|
-
const stats = storage.getStats();
|
|
135
|
-
const exportData = {
|
|
136
|
-
version: '0.2.0',
|
|
137
|
-
exportDate: new Date().toISOString(),
|
|
138
|
-
memories: allMemories,
|
|
139
|
-
stats: stats
|
|
140
|
-
};
|
|
141
|
-
fs.writeFileSync(outputPath, JSON.stringify(exportData, null, 2));
|
|
142
|
-
console.log(`✅ Exported ${allMemories.length} memories to ${outputPath}`);
|
|
143
|
-
}
|
|
144
|
-
catch (error) {
|
|
145
|
-
console.error('❌ Export failed:', error);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
async importMemories(filePath) {
|
|
150
|
-
console.log('📥 Importing memories...\n');
|
|
151
|
-
try {
|
|
152
|
-
if (!fs.existsSync(filePath)) {
|
|
153
|
-
throw new Error(`File not found: ${filePath}`);
|
|
154
|
-
}
|
|
155
|
-
const exportData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
156
|
-
const memoryService = memory_1.MemoryService.getInstance();
|
|
157
|
-
let imported = 0;
|
|
158
|
-
for (const memory of exportData.memories) {
|
|
159
|
-
try {
|
|
160
|
-
memoryService.store({
|
|
161
|
-
key: memory.key || `imported_${Date.now()}_${Math.random()}`,
|
|
162
|
-
value: memory.value,
|
|
163
|
-
type: memory.type || 'imported',
|
|
164
|
-
context: memory.context || {}
|
|
165
|
-
});
|
|
166
|
-
imported++;
|
|
167
|
-
}
|
|
168
|
-
catch (err) {
|
|
169
|
-
console.warn(`⚠️ Failed to import memory: ${err}`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
console.log(`✅ Imported ${imported}/${exportData.memories.length} memories`);
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
console.error('❌ Import failed:', error);
|
|
176
|
-
process.exit(1);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
async completeMigration() {
|
|
180
|
-
console.log('🎯 Completing migration to MCP architecture...\n');
|
|
181
|
-
// Remove old hooks from settings.json
|
|
182
|
-
console.log('1. Cleaning up old hooks...');
|
|
183
|
-
const removed = await this.removeOldHooks();
|
|
184
|
-
if (removed) {
|
|
185
|
-
console.log(' ✅ Removed file-watcher hooks');
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
console.log(' ℹ️ No hooks to remove');
|
|
189
|
-
}
|
|
190
|
-
// Verify MCP is working
|
|
191
|
-
console.log('\n2. Verifying MCP server...');
|
|
192
|
-
try {
|
|
193
|
-
const { execSync } = require('child_process');
|
|
194
|
-
const result = execSync('echo \'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\' | claude-recall mcp start', { timeout: 5000 }).toString();
|
|
195
|
-
if (result.includes('claude-recall')) {
|
|
196
|
-
console.log(' ✅ MCP server is working');
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
throw new Error('MCP server not responding correctly');
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
console.log(' ❌ MCP server test failed');
|
|
204
|
-
console.log(' Please ensure: claude mcp add claude-recall claude-recall mcp start');
|
|
205
|
-
}
|
|
206
|
-
console.log('\n✨ Migration complete!');
|
|
207
|
-
console.log('Claude Recall is now using the MCP architecture.');
|
|
208
|
-
}
|
|
209
|
-
checkDatabase() {
|
|
210
|
-
const dbPath = path.join(os.homedir(), '.claude-recall', 'claude-recall.db');
|
|
211
|
-
return fs.existsSync(dbPath);
|
|
212
|
-
}
|
|
213
|
-
checkHooks() {
|
|
214
|
-
// Check if settings.json has our hooks
|
|
215
|
-
const settingsPath = path.join(os.homedir(), '.claude-code', 'settings.json');
|
|
216
|
-
if (fs.existsSync(settingsPath)) {
|
|
217
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
218
|
-
return settings.hooks && Object.keys(settings.hooks).some(k => settings.hooks[k] && settings.hooks[k].includes('claude-recall'));
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
checkConfig() {
|
|
223
|
-
const configPath = path.join(os.homedir(), '.claude-recall', 'config.json');
|
|
224
|
-
return fs.existsSync(configPath);
|
|
225
|
-
}
|
|
226
|
-
async removeOldHooks() {
|
|
227
|
-
const settingsPath = path.join(os.homedir(), '.claude-code', 'settings.json');
|
|
228
|
-
if (!fs.existsSync(settingsPath)) {
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
try {
|
|
232
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
233
|
-
let modified = false;
|
|
234
|
-
if (settings.hooks) {
|
|
235
|
-
for (const hookName of Object.keys(settings.hooks)) {
|
|
236
|
-
if (settings.hooks[hookName] && settings.hooks[hookName].includes('claude-recall')) {
|
|
237
|
-
delete settings.hooks[hookName];
|
|
238
|
-
modified = true;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
if (modified) {
|
|
243
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
console.error('Failed to modify settings.json:', error);
|
|
249
|
-
}
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
async migrateSchema(createBackup = false) {
|
|
253
|
-
console.log('📋 Migrating database schema...\n');
|
|
254
|
-
try {
|
|
255
|
-
const dbPath = path.join(os.homedir(), '.claude-recall', 'claude-recall.db');
|
|
256
|
-
if (!fs.existsSync(dbPath)) {
|
|
257
|
-
console.log('❌ Database not found. Nothing to migrate.');
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
// Create backup if requested
|
|
261
|
-
if (createBackup) {
|
|
262
|
-
const backupPath = `${dbPath}.backup.${Date.now()}`;
|
|
263
|
-
console.log(`📦 Creating backup: ${backupPath}`);
|
|
264
|
-
fs.copyFileSync(dbPath, backupPath);
|
|
265
|
-
console.log('✅ Backup created\n');
|
|
266
|
-
}
|
|
267
|
-
// Access storage to trigger migration
|
|
268
|
-
const { MemoryStorage } = require('../../memory/storage');
|
|
269
|
-
const storage = new MemoryStorage(dbPath);
|
|
270
|
-
// Check what columns exist
|
|
271
|
-
const db = storage.getDatabase();
|
|
272
|
-
const columns = db.prepare("PRAGMA table_info(memories)").all();
|
|
273
|
-
const columnNames = columns.map((c) => c.name);
|
|
274
|
-
console.log('Current schema columns:');
|
|
275
|
-
console.log(' ' + columnNames.join(', '));
|
|
276
|
-
const hasSophistication = columnNames.includes('sophistication_level');
|
|
277
|
-
const hasScope = columnNames.includes('scope');
|
|
278
|
-
if (hasSophistication && hasScope) {
|
|
279
|
-
console.log('\n✅ Schema is already up to date!');
|
|
280
|
-
console.log(' All required columns are present.');
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
console.log('\n📋 Schema update needed:');
|
|
284
|
-
if (!hasSophistication) {
|
|
285
|
-
console.log(' - Missing: sophistication_level (added in v0.7.0)');
|
|
286
|
-
}
|
|
287
|
-
if (!hasScope) {
|
|
288
|
-
console.log(' - Missing: scope (added in v0.7.2)');
|
|
289
|
-
}
|
|
290
|
-
console.log('\n⚙️ Running migration...');
|
|
291
|
-
// The migration happens automatically when MemoryStorage initializes
|
|
292
|
-
// Just force a re-init by creating a new instance
|
|
293
|
-
const { MemoryStorage: Storage2 } = require('../../memory/storage');
|
|
294
|
-
new Storage2(dbPath);
|
|
295
|
-
console.log('\n✅ Migration complete!');
|
|
296
|
-
console.log(' Database schema is now up to date.');
|
|
297
|
-
}
|
|
298
|
-
// Display stats
|
|
299
|
-
console.log('\n📊 Database stats:');
|
|
300
|
-
const stats = storage.getStats();
|
|
301
|
-
console.log(` Total memories: ${stats.total}`);
|
|
302
|
-
if (stats.byType) {
|
|
303
|
-
console.log(' By type:');
|
|
304
|
-
for (const [type, count] of Object.entries(stats.byType)) {
|
|
305
|
-
console.log(` ${type}: ${count}`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
catch (error) {
|
|
310
|
-
console.error('\n❌ Migration failed:', error);
|
|
311
|
-
console.log('\nIf you created a backup, you can restore it manually:');
|
|
312
|
-
console.log(` cp ~/.claude-recall/claude-recall.db.backup.* ~/.claude-recall/claude-recall.db`);
|
|
313
|
-
process.exit(1);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
exports.MigrateCommand = MigrateCommand;
|