claude-recall 0.9.0 โ†’ 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.
@@ -1,4 +1 @@
1
- {
2
- "hooks": {},
3
- "hooksVersion": "1.0.0"
4
- }
1
+ {"hooks": {}, "hooksVersion": "1.0.0"}
@@ -50,7 +50,6 @@ const memory_evolution_1 = require("../services/memory-evolution");
50
50
  const mcp_commands_1 = require("./commands/mcp-commands");
51
51
  const project_commands_1 = require("./commands/project-commands");
52
52
  const hook_commands_1 = require("./commands/hook-commands");
53
- const agent_commands_1 = require("./commands/agent-commands");
54
53
  const program = new commander_1.Command();
55
54
  class ClaudeRecallCLI {
56
55
  constructor(options) {
@@ -566,73 +565,82 @@ async function main() {
566
565
  }
567
566
  }
568
567
  }
569
- // Install hooks and skills to current project
570
- function installHooksAndSkills(force = false) {
568
+ // Install skills and clean up old hooks (v0.9.0+ uses Skills, not hooks)
569
+ function installSkillsAndCleanupHooks(force = false) {
571
570
  const cwd = process.cwd();
572
571
  const projectName = path.basename(cwd);
573
- console.log('\n๐Ÿ“ฆ Installing Claude Recall hooks and skills...\n');
572
+ console.log('\n๐Ÿ“ฆ Claude Recall v0.9.x Setup\n');
574
573
  console.log(`๐Ÿ“ Project: ${projectName}`);
575
574
  console.log(`๐Ÿ“ Directory: ${cwd}\n`);
576
575
  // Find the package directory (where claude-recall is installed)
577
- // When run via npx, __dirname points to dist/cli, so we go up to find .claude
578
576
  const packageDir = path.resolve(__dirname, '../..');
579
- const packageHooksDir = path.join(packageDir, '.claude/hooks');
580
577
  const packageSkillsDir = path.join(packageDir, '.claude/skills');
581
578
  const claudeDir = path.join(cwd, '.claude');
582
579
  const hooksDir = path.join(claudeDir, 'hooks');
583
- // Create .claude/hooks directory
584
- if (!fs.existsSync(hooksDir)) {
585
- fs.mkdirSync(hooksDir, { recursive: true });
586
- }
587
- // Copy single enforcement hook
588
- const hookSource = path.join(packageHooksDir, 'memory_enforcer.py');
589
- const hookDest = path.join(hooksDir, 'memory_enforcer.py');
590
- if (fs.existsSync(hookSource)) {
591
- fs.copyFileSync(hookSource, hookDest);
592
- fs.chmodSync(hookDest, 0o755);
593
- console.log('โœ… Installed memory_enforcer.py to .claude/hooks/');
594
- }
595
- else {
596
- console.log(`โš ๏ธ Hook not found at: ${packageHooksDir}`);
597
- }
598
- // Create or update .claude/settings.json with hook configuration
599
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 ===
600
615
  let settings = {};
601
616
  if (fs.existsSync(settingsPath)) {
602
617
  try {
603
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
+ }
604
627
  }
605
628
  catch (e) {
606
- settings = {};
607
- }
608
- }
609
- const CURRENT_HOOKS_VERSION = '1.0.0';
610
- const needsUpdate = force || !settings.hooks || settings.hooksVersion !== CURRENT_HOOKS_VERSION;
611
- if (needsUpdate) {
612
- settings.hooksVersion = CURRENT_HOOKS_VERSION;
613
- settings.hooks = {
614
- PreToolUse: [
615
- {
616
- matcher: "mcp__claude-recall__.*|Write|Edit|Bash|Task",
617
- hooks: [
618
- {
619
- type: "command",
620
- command: `python3 ${path.join(hooksDir, 'memory_enforcer.py')}`,
621
- }
622
- ]
623
- }
624
- ]
625
- };
626
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
627
- console.log('โœ… Configured hook in .claude/settings.json');
628
- if (force) {
629
- 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));
630
634
  }
631
635
  }
632
636
  else {
633
- 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));
634
642
  }
635
- // Copy skills directory
643
+ // === INSTALL: Copy skills directory ===
636
644
  if (fs.existsSync(packageSkillsDir)) {
637
645
  const skillsDir = path.join(claudeDir, 'skills');
638
646
  copyDirRecursive(packageSkillsDir, skillsDir);
@@ -641,18 +649,19 @@ async function main() {
641
649
  else {
642
650
  console.log(`โš ๏ธ Skills not found at: ${packageSkillsDir}`);
643
651
  }
644
- 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.');
645
654
  console.log('Restart Claude Code to activate.\n');
646
655
  }
647
- // Setup command - shows activation instructions or installs hooks/skills
656
+ // Setup command - shows activation instructions or installs skills
648
657
  program
649
658
  .command('setup')
650
- .description('Show activation instructions or install hooks/skills')
651
- .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')
652
661
  .action((options) => {
653
662
  if (options.install) {
654
- // Install hooks and skills to current project
655
- installHooksAndSkills();
663
+ // Install skills and clean up old hooks
664
+ installSkillsAndCleanupHooks();
656
665
  }
657
666
  else {
658
667
  // Show activation instructions
@@ -677,13 +686,13 @@ async function main() {
677
686
  }
678
687
  process.exit(0);
679
688
  });
680
- // Repair command - simple alias for setup --install
689
+ // Repair command - cleans up old hooks and installs skills
681
690
  program
682
691
  .command('repair')
683
- .description('Repair broken or missing hooks and skills')
684
- .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')
685
694
  .action((options) => {
686
- installHooksAndSkills(options.force || false);
695
+ installSkillsAndCleanupHooks(options.force || false);
687
696
  process.exit(0);
688
697
  });
689
698
  // Check hooks function
@@ -967,10 +976,8 @@ async function main() {
967
976
  project_commands_1.ProjectCommands.register(program);
968
977
  // Migration commands
969
978
  migrate_1.MigrateCommand.register(program);
970
- // Hook commands (used by Claude Code hooks)
979
+ // Hook commands (legacy, kept for backwards compatibility)
971
980
  hook_commands_1.HookCommands.register(program);
972
- // Agent commands (autonomous memory agent management)
973
- agent_commands_1.AgentCommands.register(program);
974
981
  // Register live test command
975
982
  new live_test_1.LiveTestCommand().register(program);
976
983
  // Search command
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.9.0",
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": {
@@ -49,12 +49,7 @@
49
49
  "mcp:dev": "ts-node src/cli/claude-recall-cli.ts mcp start",
50
50
  "mcp:debug": "NODE_ENV=development DEBUG=claude-recall:* ts-node src/cli/claude-recall-cli.ts mcp start",
51
51
  "mcp:test": "echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}' | npm run mcp:start",
52
- "mcp:health": "echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"health/check\",\"params\":{}}' | npm run mcp:start",
53
- "agent:start": "node dist/pubnub/agent-cli.js start",
54
- "agent:stop": "node dist/pubnub/agent-cli.js stop",
55
- "agent:status": "node dist/pubnub/agent-cli.js status",
56
- "agent:logs": "node dist/pubnub/agent-cli.js logs",
57
- "test:pubnub": "node dist/pubnub/test-integration.js"
52
+ "mcp:health": "echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"health/check\",\"params\":{}}' | npm run mcp:start"
58
53
  },
59
54
  "keywords": [
60
55
  "claude-code",
@@ -94,7 +89,6 @@
94
89
  "dependencies": {
95
90
  "better-sqlite3": "^12.2.0",
96
91
  "chalk": "^5.5.0",
97
- "commander": "^12.1.0",
98
- "pubnub": "^10.2.3"
92
+ "commander": "^12.1.0"
99
93
  }
100
94
  }
@@ -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) {
@@ -1,249 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AgentCommands = void 0;
7
- const fs_1 = require("fs");
8
- const os_1 = require("os");
9
- const path_1 = require("path");
10
- const child_process_1 = require("child_process");
11
- const chalk_1 = __importDefault(require("chalk"));
12
- /**
13
- * Memory Agent Management Commands
14
- *
15
- * Provides CLI commands for managing the autonomous memory agent:
16
- * - start: Start the memory agent daemon
17
- * - stop: Stop the memory agent
18
- * - restart: Restart the agent
19
- * - status: Check agent status
20
- * - logs: View agent logs
21
- */
22
- class AgentCommands {
23
- static register(program) {
24
- const agentCmd = program
25
- .command('agent')
26
- .description('Manage the autonomous memory agent');
27
- // agent start - Start the memory agent daemon
28
- agentCmd
29
- .command('start')
30
- .description('Start the memory agent daemon')
31
- .option('--project <id>', 'Project ID to monitor')
32
- .action(async (options) => {
33
- await AgentCommands.start(options.project);
34
- });
35
- // agent stop - Stop the memory agent
36
- agentCmd
37
- .command('stop')
38
- .description('Stop the memory agent')
39
- .action(() => {
40
- AgentCommands.stop();
41
- });
42
- // agent restart - Restart the agent
43
- agentCmd
44
- .command('restart')
45
- .description('Restart the memory agent')
46
- .option('--project <id>', 'Project ID to monitor')
47
- .action(async (options) => {
48
- await AgentCommands.restart(options.project);
49
- });
50
- // agent status - Check agent status
51
- agentCmd
52
- .command('status')
53
- .description('Check memory agent status')
54
- .action(() => {
55
- AgentCommands.status();
56
- });
57
- // agent logs - Show agent logs
58
- agentCmd
59
- .command('logs')
60
- .description('Show memory agent logs')
61
- .option('--lines <number>', 'Number of lines to show', '50')
62
- .action((options) => {
63
- AgentCommands.logs(parseInt(options.lines));
64
- });
65
- }
66
- /**
67
- * Ensure agent directory exists
68
- */
69
- static ensureAgentDir() {
70
- if (!(0, fs_1.existsSync)(AgentCommands.AGENT_DIR)) {
71
- const fs = require('fs');
72
- fs.mkdirSync(AgentCommands.AGENT_DIR, { recursive: true });
73
- }
74
- }
75
- /**
76
- * Start the memory agent as a background daemon
77
- */
78
- static async start(projectId) {
79
- AgentCommands.ensureAgentDir();
80
- // Check if already running
81
- if ((0, fs_1.existsSync)(AgentCommands.PID_FILE)) {
82
- const pid = parseInt((0, fs_1.readFileSync)(AgentCommands.PID_FILE, 'utf-8').trim());
83
- try {
84
- process.kill(pid, 0); // Check if process exists
85
- console.log(chalk_1.default.yellow('โš  Memory agent already running'));
86
- console.log(` PID: ${chalk_1.default.cyan(pid)}`);
87
- console.log(` Use ${chalk_1.default.cyan('npx claude-recall agent stop')} to stop it`);
88
- console.log();
89
- return;
90
- }
91
- catch {
92
- // Process doesn't exist, remove stale PID file
93
- (0, fs_1.unlinkSync)(AgentCommands.PID_FILE);
94
- }
95
- }
96
- console.log(chalk_1.default.cyan('\n๐Ÿค– Starting Memory Agent\n'));
97
- // Spawn agent as detached background process
98
- const agentPath = (0, path_1.join)(__dirname, '..', '..', 'pubnub', 'memory-agent.js');
99
- const args = projectId ? [projectId] : [];
100
- const child = (0, child_process_1.spawn)('node', [agentPath, ...args], {
101
- detached: true,
102
- stdio: ['ignore', 'pipe', 'pipe'],
103
- });
104
- // Write PID file
105
- (0, fs_1.writeFileSync)(AgentCommands.PID_FILE, child.pid.toString());
106
- // Pipe logs to file
107
- const logStream = require('fs').createWriteStream(AgentCommands.LOG_FILE, { flags: 'a' });
108
- child.stdout?.pipe(logStream);
109
- child.stderr?.pipe(logStream);
110
- // Detach from parent
111
- child.unref();
112
- console.log(chalk_1.default.green('โœ“ Memory agent started'));
113
- console.log(` PID: ${chalk_1.default.cyan(child.pid)}`);
114
- console.log(` Project: ${chalk_1.default.yellow(projectId || 'global')}`);
115
- console.log(` Logs: ${chalk_1.default.gray(AgentCommands.LOG_FILE)}`);
116
- console.log();
117
- console.log(chalk_1.default.gray(`๐Ÿ’ก Use ${chalk_1.default.cyan('npx claude-recall agent logs')} to view logs`));
118
- console.log(chalk_1.default.gray(`๐Ÿ’ก Use ${chalk_1.default.cyan('npx claude-recall agent status')} to check status`));
119
- console.log();
120
- // Wait a bit to ensure startup, then exit cleanly
121
- await new Promise((resolve) => setTimeout(resolve, 500));
122
- process.exit(0);
123
- }
124
- /**
125
- * Stop the memory agent
126
- */
127
- static stop() {
128
- if (!(0, fs_1.existsSync)(AgentCommands.PID_FILE)) {
129
- console.log(chalk_1.default.gray('โœ— Memory agent is not running'));
130
- console.log();
131
- return;
132
- }
133
- const pid = parseInt((0, fs_1.readFileSync)(AgentCommands.PID_FILE, 'utf-8').trim());
134
- try {
135
- console.log(chalk_1.default.cyan('\n๐Ÿ›‘ Stopping Memory Agent\n'));
136
- console.log(`Stopping agent (PID: ${chalk_1.default.yellow(pid)})...`);
137
- process.kill(pid, 'SIGTERM');
138
- // Wait for process to exit
139
- let attempts = 0;
140
- const maxAttempts = 10;
141
- const checkInterval = setInterval(() => {
142
- try {
143
- process.kill(pid, 0);
144
- attempts++;
145
- if (attempts >= maxAttempts) {
146
- console.log(chalk_1.default.yellow('โš  Agent did not stop gracefully, forcing...'));
147
- process.kill(pid, 'SIGKILL');
148
- clearInterval(checkInterval);
149
- (0, fs_1.unlinkSync)(AgentCommands.PID_FILE);
150
- console.log(chalk_1.default.green('โœ“ Memory agent stopped (forced)'));
151
- console.log();
152
- }
153
- }
154
- catch {
155
- // Process no longer exists
156
- clearInterval(checkInterval);
157
- (0, fs_1.unlinkSync)(AgentCommands.PID_FILE);
158
- console.log(chalk_1.default.green('โœ“ Memory agent stopped'));
159
- console.log();
160
- }
161
- }, 500);
162
- }
163
- catch (error) {
164
- console.error(chalk_1.default.red(`โœ— Failed to stop agent: ${error}`));
165
- // Remove stale PID file
166
- (0, fs_1.unlinkSync)(AgentCommands.PID_FILE);
167
- console.log();
168
- }
169
- }
170
- /**
171
- * Restart the memory agent
172
- */
173
- static async restart(projectId) {
174
- console.log(chalk_1.default.cyan('\n๐Ÿ”„ Restarting Memory Agent\n'));
175
- // Stop if running
176
- if ((0, fs_1.existsSync)(AgentCommands.PID_FILE)) {
177
- AgentCommands.stop();
178
- await new Promise((resolve) => setTimeout(resolve, 2000));
179
- }
180
- // Start again
181
- await AgentCommands.start(projectId);
182
- }
183
- /**
184
- * Check agent status
185
- */
186
- static status() {
187
- console.log(chalk_1.default.cyan('\n๐Ÿ“Š Memory Agent Status\n'));
188
- if (!(0, fs_1.existsSync)(AgentCommands.PID_FILE)) {
189
- console.log(`Status: ${chalk_1.default.gray('โœ— Not running')}`);
190
- console.log();
191
- console.log(chalk_1.default.gray(`๐Ÿ’ก Start with: ${chalk_1.default.cyan('npx claude-recall agent start')}`));
192
- console.log();
193
- return;
194
- }
195
- const pid = parseInt((0, fs_1.readFileSync)(AgentCommands.PID_FILE, 'utf-8').trim());
196
- try {
197
- process.kill(pid, 0);
198
- console.log(`Status: ${chalk_1.default.green('โœ“ Running')}`);
199
- console.log(`PID: ${chalk_1.default.cyan(pid)}`);
200
- console.log(`Logs: ${chalk_1.default.gray(AgentCommands.LOG_FILE)}`);
201
- // Check log file size
202
- if ((0, fs_1.existsSync)(AgentCommands.LOG_FILE)) {
203
- const stats = require('fs').statSync(AgentCommands.LOG_FILE);
204
- const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
205
- console.log(`Size: ${chalk_1.default.gray(sizeMB)} ${chalk_1.default.gray('MB')}`);
206
- }
207
- console.log();
208
- console.log(chalk_1.default.gray(`๐Ÿ’ก View logs: ${chalk_1.default.cyan('npx claude-recall agent logs')}`));
209
- console.log(chalk_1.default.gray(`๐Ÿ’ก Stop agent: ${chalk_1.default.cyan('npx claude-recall agent stop')}`));
210
- console.log();
211
- }
212
- catch {
213
- console.log(`Status: ${chalk_1.default.yellow('โœ— Not running')} ${chalk_1.default.gray('(stale PID file)')}`);
214
- console.log();
215
- (0, fs_1.unlinkSync)(AgentCommands.PID_FILE);
216
- }
217
- }
218
- /**
219
- * Show agent logs
220
- */
221
- static logs(lines = 50) {
222
- if (!(0, fs_1.existsSync)(AgentCommands.LOG_FILE)) {
223
- console.log(chalk_1.default.gray('โœ— No logs found'));
224
- console.log();
225
- console.log(chalk_1.default.gray(`๐Ÿ’ก Start agent first: ${chalk_1.default.cyan('npx claude-recall agent start')}`));
226
- console.log();
227
- return;
228
- }
229
- console.log(chalk_1.default.cyan(`\n๐Ÿ“‹ Memory Agent Logs (last ${lines} lines)\n`));
230
- try {
231
- // Use tail to show last N lines
232
- const output = (0, child_process_1.execSync)(`tail -n ${lines} "${AgentCommands.LOG_FILE}"`, {
233
- encoding: 'utf-8',
234
- });
235
- console.log(output);
236
- }
237
- catch (error) {
238
- // Fallback: read entire file
239
- const logs = (0, fs_1.readFileSync)(AgentCommands.LOG_FILE, 'utf-8');
240
- const logLines = logs.split('\n');
241
- console.log(logLines.slice(-lines).join('\n'));
242
- }
243
- console.log();
244
- }
245
- }
246
- exports.AgentCommands = AgentCommands;
247
- AgentCommands.AGENT_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude-recall', 'agent');
248
- AgentCommands.PID_FILE = (0, path_1.join)(AgentCommands.AGENT_DIR, 'memory-agent.pid');
249
- AgentCommands.LOG_FILE = (0, path_1.join)(AgentCommands.AGENT_DIR, 'memory-agent.log');