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.
- package/.claude/settings.json +1 -4
- package/dist/cli/claude-recall-cli.js +68 -61
- package/package.json +3 -9
- package/scripts/postinstall.js +80 -51
- package/dist/cli/commands/agent-commands.js +0 -249
- package/dist/pubnub/agent-cli.js +0 -216
- package/dist/pubnub/config.js +0 -182
- package/dist/pubnub/memory-agent.js +0 -395
- package/dist/pubnub/publisher-cli.js +0 -58
- package/dist/pubnub/publisher.js +0 -122
- package/dist/pubnub/test-integration.js +0 -168
package/.claude/settings.json
CHANGED
|
@@ -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
|
|
570
|
-
function
|
|
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๐ฆ
|
|
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
|
-
|
|
610
|
-
|
|
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
|
-
|
|
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โ
|
|
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
|
|
656
|
+
// Setup command - shows activation instructions or installs skills
|
|
648
657
|
program
|
|
649
658
|
.command('setup')
|
|
650
|
-
.description('Show activation instructions or install
|
|
651
|
-
.option('--install', 'Install
|
|
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
|
|
655
|
-
|
|
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 -
|
|
689
|
+
// Repair command - cleans up old hooks and installs skills
|
|
681
690
|
program
|
|
682
691
|
.command('repair')
|
|
683
|
-
.description('
|
|
684
|
-
.option('--force', 'Force overwrite existing
|
|
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
|
-
|
|
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 (
|
|
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.
|
|
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
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -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
|
|
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
|
-
//
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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');
|