claude-recall 0.9.1 โ†’ 0.9.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.
@@ -565,73 +565,82 @@ async function main() {
565
565
  }
566
566
  }
567
567
  }
568
- // Install hooks and skills to current project
569
- function installHooksAndSkills(force = false) {
568
+ // Install skills and clean up old hooks (v0.9.0+ uses Skills, not hooks)
569
+ function installSkillsAndCleanupHooks(force = false) {
570
570
  const cwd = process.cwd();
571
571
  const projectName = path.basename(cwd);
572
- console.log('\n๐Ÿ“ฆ Installing Claude Recall hooks and skills...\n');
572
+ console.log('\n๐Ÿ“ฆ Claude Recall v0.9.x Setup\n');
573
573
  console.log(`๐Ÿ“ Project: ${projectName}`);
574
574
  console.log(`๐Ÿ“ Directory: ${cwd}\n`);
575
575
  // Find the package directory (where claude-recall is installed)
576
- // When run via npx, __dirname points to dist/cli, so we go up to find .claude
577
576
  const packageDir = path.resolve(__dirname, '../..');
578
- const packageHooksDir = path.join(packageDir, '.claude/hooks');
579
577
  const packageSkillsDir = path.join(packageDir, '.claude/skills');
580
578
  const claudeDir = path.join(cwd, '.claude');
581
579
  const hooksDir = path.join(claudeDir, 'hooks');
582
- // Create .claude/hooks directory
583
- if (!fs.existsSync(hooksDir)) {
584
- fs.mkdirSync(hooksDir, { recursive: true });
585
- }
586
- // Copy single enforcement hook
587
- const hookSource = path.join(packageHooksDir, 'memory_enforcer.py');
588
- const hookDest = path.join(hooksDir, 'memory_enforcer.py');
589
- if (fs.existsSync(hookSource)) {
590
- fs.copyFileSync(hookSource, hookDest);
591
- fs.chmodSync(hookDest, 0o755);
592
- console.log('โœ… Installed memory_enforcer.py to .claude/hooks/');
593
- }
594
- else {
595
- console.log(`โš ๏ธ Hook not found at: ${packageHooksDir}`);
596
- }
597
- // Create or update .claude/settings.json with hook configuration
598
580
  const settingsPath = path.join(claudeDir, 'settings.json');
581
+ // === CLEANUP: Remove old hooks (v0.9.0+ doesn't use hooks) ===
582
+ if (fs.existsSync(hooksDir)) {
583
+ const oldHooks = [
584
+ 'memory_enforcer.py',
585
+ 'pre_tool_search_enforcer.py',
586
+ 'mcp_tool_tracker.py',
587
+ 'pubnub_pre_tool_hook.py',
588
+ 'pubnub_prompt_hook.py',
589
+ 'user_prompt_capture.py',
590
+ 'user_prompt_reminder.py'
591
+ ];
592
+ let removedCount = 0;
593
+ for (const hook of oldHooks) {
594
+ const hookPath = path.join(hooksDir, hook);
595
+ if (fs.existsSync(hookPath)) {
596
+ fs.unlinkSync(hookPath);
597
+ removedCount++;
598
+ }
599
+ }
600
+ // Remove hooks directory if empty
601
+ try {
602
+ const remaining = fs.readdirSync(hooksDir);
603
+ if (remaining.length === 0) {
604
+ fs.rmdirSync(hooksDir);
605
+ }
606
+ }
607
+ catch (e) {
608
+ // Ignore
609
+ }
610
+ if (removedCount > 0) {
611
+ console.log(`๐Ÿงน Removed ${removedCount} old hook file(s) from .claude/hooks/`);
612
+ }
613
+ }
614
+ // === CLEANUP: Clear hook configuration from settings.json ===
599
615
  let settings = {};
600
616
  if (fs.existsSync(settingsPath)) {
601
617
  try {
602
618
  settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
619
+ const hadHooks = settings.hooks && Object.keys(settings.hooks).length > 0;
620
+ // Clear hooks - v0.9.0+ uses Skills instead
621
+ settings.hooks = {};
622
+ settings.hooksVersion = '2.0.0';
623
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
624
+ if (hadHooks) {
625
+ console.log('๐Ÿงน Cleared old hook configuration from .claude/settings.json');
626
+ }
603
627
  }
604
628
  catch (e) {
605
- settings = {};
606
- }
607
- }
608
- const CURRENT_HOOKS_VERSION = '1.0.0';
609
- const needsUpdate = force || !settings.hooks || settings.hooksVersion !== CURRENT_HOOKS_VERSION;
610
- if (needsUpdate) {
611
- settings.hooksVersion = CURRENT_HOOKS_VERSION;
612
- settings.hooks = {
613
- PreToolUse: [
614
- {
615
- matcher: "mcp__claude-recall__.*|Write|Edit|Bash|Task",
616
- hooks: [
617
- {
618
- type: "command",
619
- command: `python3 ${path.join(hooksDir, 'memory_enforcer.py')}`,
620
- }
621
- ]
622
- }
623
- ]
624
- };
625
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
626
- console.log('โœ… Configured hook in .claude/settings.json');
627
- if (force) {
628
- console.log(' โ†’ Force flag: overwrote existing configuration');
629
+ // If settings.json is invalid, create fresh one
630
+ if (!fs.existsSync(claudeDir)) {
631
+ fs.mkdirSync(claudeDir, { recursive: true });
632
+ }
633
+ fs.writeFileSync(settingsPath, JSON.stringify({ hooks: {}, hooksVersion: '2.0.0' }, null, 2));
629
634
  }
630
635
  }
631
636
  else {
632
- console.log(`โ„น๏ธ Hooks already at version ${CURRENT_HOOKS_VERSION}`);
637
+ // Create new settings.json without hooks
638
+ if (!fs.existsSync(claudeDir)) {
639
+ fs.mkdirSync(claudeDir, { recursive: true });
640
+ }
641
+ fs.writeFileSync(settingsPath, JSON.stringify({ hooks: {}, hooksVersion: '2.0.0' }, null, 2));
633
642
  }
634
- // Copy skills directory
643
+ // === INSTALL: Copy skills directory ===
635
644
  if (fs.existsSync(packageSkillsDir)) {
636
645
  const skillsDir = path.join(claudeDir, 'skills');
637
646
  copyDirRecursive(packageSkillsDir, skillsDir);
@@ -640,18 +649,19 @@ async function main() {
640
649
  else {
641
650
  console.log(`โš ๏ธ Skills not found at: ${packageSkillsDir}`);
642
651
  }
643
- console.log('\nโœ… Installation complete!\n');
652
+ console.log('\nโœ… Setup complete!\n');
653
+ console.log('โ„น๏ธ v0.9.0+ uses native Claude Skills instead of hooks.');
644
654
  console.log('Restart Claude Code to activate.\n');
645
655
  }
646
- // Setup command - shows activation instructions or installs hooks/skills
656
+ // Setup command - shows activation instructions or installs skills
647
657
  program
648
658
  .command('setup')
649
- .description('Show activation instructions or install hooks/skills')
650
- .option('--install', 'Install hooks and skills to current project')
659
+ .description('Show activation instructions or install skills')
660
+ .option('--install', 'Install skills and clean up old hooks')
651
661
  .action((options) => {
652
662
  if (options.install) {
653
- // Install hooks and skills to current project
654
- installHooksAndSkills();
663
+ // Install skills and clean up old hooks
664
+ installSkillsAndCleanupHooks();
655
665
  }
656
666
  else {
657
667
  // Show activation instructions
@@ -676,13 +686,13 @@ async function main() {
676
686
  }
677
687
  process.exit(0);
678
688
  });
679
- // Repair command - simple alias for setup --install
689
+ // Repair command - cleans up old hooks and installs skills
680
690
  program
681
691
  .command('repair')
682
- .description('Repair broken or missing hooks and skills')
683
- .option('--force', 'Force overwrite existing hook configuration')
692
+ .description('Clean up old hooks and install skills (v0.9.0+ migration)')
693
+ .option('--force', 'Force overwrite existing configuration')
684
694
  .action((options) => {
685
- installHooksAndSkills(options.force || false);
695
+ installSkillsAndCleanupHooks(options.force || false);
686
696
  process.exit(0);
687
697
  });
688
698
  // Check hooks function
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Persistent memory for Claude Code with native Skills integration, automatic capture, failure learning, and project scoping via MCP server",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
6
 
7
- console.log('\n๐Ÿš€ Setting up Claude Recall...\n');
7
+ console.log('\n๐Ÿš€ Setting up Claude Recall v0.9.x...\n');
8
8
 
9
9
  const { execSync } = require('child_process');
10
10
 
@@ -28,6 +28,22 @@ function copyDirRecursive(src, dest) {
28
28
  }
29
29
  }
30
30
 
31
+ // Helper function to remove directory recursively
32
+ function rmDirRecursive(dir) {
33
+ if (fs.existsSync(dir)) {
34
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
35
+ for (const entry of entries) {
36
+ const fullPath = path.join(dir, entry.name);
37
+ if (entry.isDirectory()) {
38
+ rmDirRecursive(fullPath);
39
+ } else {
40
+ fs.unlinkSync(fullPath);
41
+ }
42
+ }
43
+ fs.rmdirSync(dir);
44
+ }
45
+ }
46
+
31
47
  try {
32
48
  // Set up database location in user's home directory
33
49
  const dbDir = path.join(os.homedir(), '.claude-recall');
@@ -88,78 +104,90 @@ try {
88
104
  console.log('โš ๏ธ Failed to register project (non-fatal):', error.message);
89
105
  }
90
106
 
91
- // Install hook and skill to .claude/ directory
107
+ // Install skills and clean up old hooks (v0.9.0+ uses Skills, not hooks)
92
108
  try {
93
109
  const cwd = process.cwd();
94
110
  const projectName = path.basename(cwd);
95
- const packageHooksDir = path.join(__dirname, '../.claude/hooks');
96
111
  const packageSkillsDir = path.join(__dirname, '../.claude/skills');
97
112
 
98
113
  if (projectName !== 'claude-recall' && !cwd.includes('node_modules/.pnpm') && !cwd.includes('node_modules/claude-recall')) {
99
114
  const claudeDir = path.join(cwd, '.claude');
100
115
  const hooksDir = path.join(claudeDir, 'hooks');
116
+ const settingsPath = path.join(claudeDir, 'settings.json');
101
117
 
102
- // Create .claude/hooks directory
103
- if (!fs.existsSync(hooksDir)) {
104
- fs.mkdirSync(hooksDir, { recursive: true });
105
- }
106
-
107
- // Copy single enforcement hook
108
- const hookSource = path.join(packageHooksDir, 'memory_enforcer.py');
109
- const hookDest = path.join(hooksDir, 'memory_enforcer.py');
118
+ // === CLEANUP: Remove old hooks (v0.9.0+ doesn't use hooks) ===
119
+ if (fs.existsSync(hooksDir)) {
120
+ // Remove known hook files from previous versions
121
+ const oldHooks = [
122
+ 'memory_enforcer.py',
123
+ 'pre_tool_search_enforcer.py',
124
+ 'mcp_tool_tracker.py',
125
+ 'pubnub_pre_tool_hook.py',
126
+ 'pubnub_prompt_hook.py',
127
+ 'user_prompt_capture.py',
128
+ 'user_prompt_reminder.py'
129
+ ];
130
+
131
+ let removedCount = 0;
132
+ for (const hook of oldHooks) {
133
+ const hookPath = path.join(hooksDir, hook);
134
+ if (fs.existsSync(hookPath)) {
135
+ fs.unlinkSync(hookPath);
136
+ removedCount++;
137
+ }
138
+ }
110
139
 
111
- if (fs.existsSync(hookSource)) {
112
- fs.copyFileSync(hookSource, hookDest);
113
- fs.chmodSync(hookDest, 0o755);
114
- console.log('โœ… Installed memory_enforcer.py to .claude/hooks/');
115
- }
140
+ // Remove hooks directory if empty
141
+ try {
142
+ const remaining = fs.readdirSync(hooksDir);
143
+ if (remaining.length === 0) {
144
+ fs.rmdirSync(hooksDir);
145
+ }
146
+ } catch (e) {
147
+ // Ignore
148
+ }
116
149
 
117
- // Copy skills directory
118
- if (fs.existsSync(packageSkillsDir)) {
119
- const skillsDir = path.join(claudeDir, 'skills');
120
- copyDirRecursive(packageSkillsDir, skillsDir);
121
- console.log('โœ… Installed SKILL.md to .claude/skills/');
150
+ if (removedCount > 0) {
151
+ console.log(`๐Ÿงน Removed ${removedCount} old hook file(s) from .claude/hooks/`);
152
+ }
122
153
  }
123
154
 
124
- // Create .claude/settings.json with hook configuration
125
- const settingsPath = path.join(claudeDir, 'settings.json');
126
- let settings = {};
127
-
155
+ // === CLEANUP: Clear hook configuration from settings.json ===
128
156
  if (fs.existsSync(settingsPath)) {
129
157
  try {
130
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
158
+ let settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
159
+ const hadHooks = settings.hooks && Object.keys(settings.hooks).length > 0;
160
+
161
+ // Clear hooks - v0.9.0+ uses Skills instead
162
+ settings.hooks = {};
163
+ settings.hooksVersion = '2.0.0'; // Bump version to indicate skills-based
164
+
165
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
166
+
167
+ if (hadHooks) {
168
+ console.log('๐Ÿงน Cleared old hook configuration from .claude/settings.json');
169
+ }
131
170
  } catch (e) {
132
- settings = {};
171
+ // If settings.json is invalid, create fresh one
172
+ fs.writeFileSync(settingsPath, JSON.stringify({ hooks: {}, hooksVersion: '2.0.0' }, null, 2));
133
173
  }
174
+ } else {
175
+ // Create new settings.json without hooks
176
+ if (!fs.existsSync(claudeDir)) {
177
+ fs.mkdirSync(claudeDir, { recursive: true });
178
+ }
179
+ fs.writeFileSync(settingsPath, JSON.stringify({ hooks: {}, hooksVersion: '2.0.0' }, null, 2));
134
180
  }
135
181
 
136
- const CURRENT_HOOKS_VERSION = '1.0.0';
137
- const needsUpdate = !settings.hooks || settings.hooksVersion !== CURRENT_HOOKS_VERSION;
138
-
139
- if (needsUpdate) {
140
- settings.hooksVersion = CURRENT_HOOKS_VERSION;
141
- settings.hooks = {
142
- PreToolUse: [
143
- {
144
- matcher: "mcp__claude-recall__.*|Write|Edit|Bash|Task",
145
- hooks: [
146
- {
147
- type: "command",
148
- command: `python3 ${path.join(hooksDir, 'memory_enforcer.py')}`
149
- }
150
- ]
151
- }
152
- ]
153
- };
154
-
155
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
156
- console.log('โœ… Configured hook in .claude/settings.json');
157
- } else {
158
- console.log(`โ„น๏ธ Hooks already at version ${CURRENT_HOOKS_VERSION}`);
182
+ // === INSTALL: Copy skills directory ===
183
+ if (fs.existsSync(packageSkillsDir)) {
184
+ const skillsDir = path.join(claudeDir, 'skills');
185
+ copyDirRecursive(packageSkillsDir, skillsDir);
186
+ console.log('โœ… Installed SKILL.md to .claude/skills/');
159
187
  }
160
188
  }
161
189
  } catch (error) {
162
- console.log('โš ๏ธ Failed to install hooks/skills (non-fatal):', error.message);
190
+ console.log('โš ๏ธ Failed to install skills (non-fatal):', error.message);
163
191
  }
164
192
 
165
193
  console.log('\nโœ… Installation complete!\n');
@@ -173,6 +201,7 @@ try {
173
201
  console.log('');
174
202
  console.log('โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”');
175
203
  console.log('');
204
+ console.log('โ„น๏ธ v0.9.0+ uses native Claude Skills instead of hooks.');
176
205
  console.log('๐Ÿ’ก Your memories persist across conversations and restarts.\n');
177
206
 
178
207
  } catch (error) {