@cybermem/mcp 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +203 -28
  3. package/package.json +29 -28
  4. package/requirements.txt +2 -0
  5. package/server.py +347 -0
  6. package/src/index.ts +227 -0
  7. package/test_mcp.py +111 -0
  8. package/tsconfig.json +14 -0
  9. package/dist/commands/__tests__/backup.test.js +0 -75
  10. package/dist/commands/__tests__/restore.test.js +0 -70
  11. package/dist/commands/backup.js +0 -52
  12. package/dist/commands/deploy.js +0 -242
  13. package/dist/commands/init.js +0 -65
  14. package/dist/commands/restore.js +0 -62
  15. package/dist/templates/ansible/inventory/hosts.ini +0 -3
  16. package/dist/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
  17. package/dist/templates/ansible/playbooks/stop-cybermem.yml +0 -17
  18. package/dist/templates/charts/cybermem/Chart.yaml +0 -6
  19. package/dist/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
  20. package/dist/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
  21. package/dist/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
  22. package/dist/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
  23. package/dist/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
  24. package/dist/templates/charts/cybermem/values-vps.yaml +0 -18
  25. package/dist/templates/charts/cybermem/values.yaml +0 -42
  26. package/dist/templates/docker-compose.yml +0 -236
  27. package/dist/templates/envs/local.example +0 -27
  28. package/dist/templates/envs/rpi.example +0 -27
  29. package/dist/templates/envs/vps.example +0 -25
  30. package/dist/templates/mcp-responder/Dockerfile +0 -6
  31. package/dist/templates/mcp-responder/server.js +0 -22
  32. package/dist/templates/monitoring/db_exporter/Dockerfile +0 -19
  33. package/dist/templates/monitoring/db_exporter/exporter.py +0 -313
  34. package/dist/templates/monitoring/db_exporter/requirements.txt +0 -2
  35. package/dist/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
  36. package/dist/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
  37. package/dist/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
  38. package/dist/templates/monitoring/log_exporter/Dockerfile +0 -13
  39. package/dist/templates/monitoring/log_exporter/exporter.py +0 -274
  40. package/dist/templates/monitoring/log_exporter/requirements.txt +0 -1
  41. package/dist/templates/monitoring/postgres_exporter/queries.yml +0 -22
  42. package/dist/templates/monitoring/prometheus/prometheus.yml +0 -22
  43. package/dist/templates/monitoring/traefik/dynamic/.gitkeep +0 -0
  44. package/dist/templates/monitoring/traefik/traefik.yml +0 -32
  45. package/dist/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
  46. package/dist/templates/monitoring/vector/vector.yaml +0 -106
  47. package/dist/templates/openmemory/Dockerfile +0 -19
  48. package/templates/ansible/inventory/hosts.ini +0 -3
  49. package/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
  50. package/templates/ansible/playbooks/stop-cybermem.yml +0 -17
  51. package/templates/charts/cybermem/Chart.yaml +0 -6
  52. package/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
  53. package/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
  54. package/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
  55. package/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
  56. package/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
  57. package/templates/charts/cybermem/values-vps.yaml +0 -18
  58. package/templates/charts/cybermem/values.yaml +0 -42
  59. package/templates/docker-compose.yml +0 -236
  60. package/templates/envs/local.example +0 -27
  61. package/templates/envs/rpi.example +0 -27
  62. package/templates/envs/vps.example +0 -25
  63. package/templates/mcp-responder/Dockerfile +0 -6
  64. package/templates/mcp-responder/server.js +0 -22
  65. package/templates/monitoring/db_exporter/Dockerfile +0 -19
  66. package/templates/monitoring/db_exporter/exporter.py +0 -313
  67. package/templates/monitoring/db_exporter/requirements.txt +0 -2
  68. package/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
  69. package/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
  70. package/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
  71. package/templates/monitoring/log_exporter/Dockerfile +0 -13
  72. package/templates/monitoring/log_exporter/exporter.py +0 -274
  73. package/templates/monitoring/log_exporter/requirements.txt +0 -1
  74. package/templates/monitoring/postgres_exporter/queries.yml +0 -22
  75. package/templates/monitoring/prometheus/prometheus.yml +0 -22
  76. package/templates/monitoring/traefik/dynamic/.gitkeep +0 -0
  77. package/templates/monitoring/traefik/traefik.yml +0 -32
  78. package/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
  79. package/templates/monitoring/vector/vector.yaml +0 -106
  80. package/templates/openmemory/Dockerfile +0 -19
@@ -1,242 +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.deploy = deploy;
7
- const chalk_1 = __importDefault(require("chalk"));
8
- const crypto_1 = __importDefault(require("crypto"));
9
- const execa_1 = __importDefault(require("execa"));
10
- const fs_1 = __importDefault(require("fs"));
11
- const inquirer_1 = __importDefault(require("inquirer"));
12
- const os_1 = __importDefault(require("os"));
13
- const path_1 = __importDefault(require("path"));
14
- async function deploy(options) {
15
- // Determine target from flags
16
- let target = 'local';
17
- if (options.rpi)
18
- target = 'rpi';
19
- if (options.vps)
20
- target = 'vps';
21
- const useTailscale = options.remoteAccess;
22
- console.log(chalk_1.default.blue(`Deploying CyberMem (${target})...`));
23
- try {
24
- // Resolve Template Directory (Support both Dev and Prod)
25
- let templateDir = path_1.default.resolve(__dirname, '../../templates');
26
- if (!fs_1.default.existsSync(templateDir)) {
27
- templateDir = path_1.default.resolve(__dirname, '../../../templates');
28
- }
29
- if (!fs_1.default.existsSync(templateDir)) {
30
- templateDir = path_1.default.resolve(process.cwd(), 'packages/cli/templates');
31
- }
32
- if (!fs_1.default.existsSync(templateDir)) {
33
- // Fallback for different build structures
34
- templateDir = path_1.default.resolve(__dirname, '../templates');
35
- }
36
- if (!fs_1.default.existsSync(templateDir)) {
37
- throw new Error(`Templates not found at ${templateDir}. Please ensure package is built correctly.`);
38
- }
39
- if (target === 'local') {
40
- const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
41
- const internalEnvExample = path_1.default.join(templateDir, 'envs/local.example');
42
- if (!fs_1.default.existsSync(composeFile)) {
43
- console.error(chalk_1.default.red(`Internal Error: Template not found at ${composeFile}`));
44
- process.exit(1);
45
- }
46
- // Home Directory Config
47
- const homeDir = os_1.default.homedir();
48
- const configDir = path_1.default.join(homeDir, '.cybermem');
49
- const envFile = path_1.default.join(configDir, '.env');
50
- const dataDir = path_1.default.join(configDir, 'data');
51
- // 1. Ensure ~/.cybermem exists
52
- if (!fs_1.default.existsSync(configDir)) {
53
- fs_1.default.mkdirSync(configDir, { recursive: true });
54
- fs_1.default.mkdirSync(dataDir, { recursive: true });
55
- }
56
- // 2. Local Mode: Simplified setup without mandatory API key
57
- if (!fs_1.default.existsSync(envFile)) {
58
- console.log(chalk_1.default.yellow(`Initializing local configuration in ${configDir}...`));
59
- const envContent = fs_1.default.readFileSync(internalEnvExample, 'utf-8');
60
- fs_1.default.writeFileSync(envFile, envContent);
61
- console.log(chalk_1.default.green(`Created .env at ${envFile}`));
62
- }
63
- console.log(chalk_1.default.blue('Starting CyberMem services in Local Mode...'));
64
- await (0, execa_1.default)('docker-compose', [
65
- '-f', composeFile,
66
- '--env-file', envFile,
67
- '--project-name', 'cybermem',
68
- 'up', '-d', '--remove-orphans'
69
- ], {
70
- stdio: 'inherit',
71
- env: {
72
- ...process.env,
73
- DATA_DIR: dataDir,
74
- CYBERMEM_ENV_PATH: envFile,
75
- OM_API_KEY: ''
76
- }
77
- });
78
- console.log(chalk_1.default.green('\n🎉 CyberMem Installed!'));
79
- console.log('');
80
- console.log(chalk_1.default.bold('Next Steps:'));
81
- console.log(` 1. Open ${chalk_1.default.underline('http://localhost:3000/client-connect')} to connect your MCP clients`);
82
- console.log(` 2. Default password: ${chalk_1.default.bold('admin')} (you'll be prompted to change it)`);
83
- console.log('');
84
- console.log(chalk_1.default.dim('Local mode is active: No API key required for connections from this laptop.'));
85
- }
86
- else if (target === 'rpi') {
87
- const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
88
- const internalEnvExample = path_1.default.join(templateDir, 'envs/rpi.example');
89
- let sshHost = options.host;
90
- if (!sshHost) {
91
- const answers = await inquirer_1.default.prompt([
92
- {
93
- type: 'input',
94
- name: 'host',
95
- message: 'Enter SSH Host (e.g. pi@raspberrypi.local):',
96
- validate: (input) => input.includes('@') ? true : 'Format must be user@host'
97
- }
98
- ]);
99
- sshHost = answers.host;
100
- }
101
- console.log(chalk_1.default.blue(`Remote deploying to ${sshHost}...`));
102
- // 1. Create remote directory
103
- await (0, execa_1.default)('ssh', [sshHost, 'mkdir -p ~/.cybermem/data']);
104
- // 1.5 Check and fix Docker architecture (64-bit kernel with 32-bit Docker)
105
- console.log(chalk_1.default.blue('Checking Docker architecture...'));
106
- try {
107
- const { stdout: kernelArch } = await (0, execa_1.default)('ssh', [sshHost, 'uname -m']);
108
- const { stdout: dockerArch } = await (0, execa_1.default)('ssh', [sshHost, 'docker version --format "{{.Server.Arch}}" 2>/dev/null || echo "unknown"']);
109
- if (kernelArch.trim() === 'aarch64' && dockerArch.trim() !== 'arm64') {
110
- console.log(chalk_1.default.yellow(`⚠️ Docker is ${dockerArch.trim()}, kernel is aarch64. Installing arm64 Docker...`));
111
- const installCmd = `
112
- sudo systemctl stop docker docker.socket 2>/dev/null || true
113
- curl -fsSL https://download.docker.com/linux/static/stable/aarch64/docker-27.5.1.tgz -o /tmp/docker.tgz
114
- sudo tar -xzf /tmp/docker.tgz -C /usr/local/bin --strip-components=1
115
- sudo /usr/local/bin/dockerd &
116
- sleep 5
117
- docker version --format "{{.Server.Arch}}"
118
- `;
119
- const { stdout } = await (0, execa_1.default)('ssh', [sshHost, installCmd], { shell: true });
120
- if (stdout.includes('arm64')) {
121
- console.log(chalk_1.default.green('✅ Docker arm64 installed successfully'));
122
- }
123
- else {
124
- console.log(chalk_1.default.yellow('⚠️ Docker arm64 install may need manual verification'));
125
- }
126
- }
127
- else if (dockerArch.trim() === 'arm64') {
128
- console.log(chalk_1.default.green(`✅ Docker is already arm64`));
129
- }
130
- else {
131
- console.log(chalk_1.default.gray(`Docker arch: ${dockerArch.trim()}, kernel: ${kernelArch.trim()}`));
132
- }
133
- }
134
- catch (e) {
135
- console.log(chalk_1.default.yellow(`⚠️ Docker arch check skipped: ${e.message}`));
136
- }
137
- // 2. Initial Env Setup (if missing)
138
- try {
139
- await (0, execa_1.default)('ssh', [sshHost, '[ -f ~/.cybermem/.env ]']);
140
- console.log(chalk_1.default.gray('Remote .env exists, skipping generation.'));
141
- }
142
- catch (e) {
143
- console.log(chalk_1.default.yellow('Generating remote .env...'));
144
- let envContent = fs_1.default.readFileSync(internalEnvExample, 'utf-8');
145
- const newKey = `sk-${crypto_1.default.randomBytes(16).toString('hex')}`;
146
- // Replace OM_API_KEY with generated key
147
- if (envContent.includes('OM_API_KEY=')) {
148
- envContent = envContent.replace(/OM_API_KEY=.*/, `OM_API_KEY=${newKey}`);
149
- }
150
- else {
151
- envContent += `\nOM_API_KEY=${newKey}\n`;
152
- }
153
- const tempEnv = path_1.default.join(os_1.default.tmpdir(), 'cybermem-rpi.env');
154
- fs_1.default.writeFileSync(tempEnv, envContent);
155
- await (0, execa_1.default)('scp', [tempEnv, `${sshHost}:~/.cybermem/.env`]);
156
- fs_1.default.unlinkSync(tempEnv);
157
- }
158
- // 3. Copy Docker Compose
159
- console.log(chalk_1.default.blue('Uploading templates...'));
160
- await (0, execa_1.default)('scp', [composeFile, `${sshHost}:~/.cybermem/docker-compose.yml`]);
161
- // 4. Run Docker Compose Remotely
162
- console.log(chalk_1.default.blue('Starting services on RPi...'));
163
- // DOCKER_DEFAULT_PLATFORM=linux/arm64 forces arm64 images on RPi with 64-bit kernel but 32-bit Docker
164
- const remoteCmd = `
165
- export CYBERMEM_ENV_PATH=~/.cybermem/.env
166
- export DATA_DIR=~/.cybermem/data
167
- export DOCKER_DEFAULT_PLATFORM=linux/arm64
168
- docker-compose -f ~/.cybermem/docker-compose.yml up -d --remove-orphans
169
- `;
170
- await (0, execa_1.default)('ssh', [sshHost, remoteCmd], { stdio: 'inherit' });
171
- console.log(chalk_1.default.green('\n✅ RPi deployment successful!'));
172
- const hostIp = sshHost.split('@')[1];
173
- console.log(chalk_1.default.bold('Access Points (LAN):'));
174
- console.log(` - Dashboard: ${chalk_1.default.underline(`http://${hostIp}:3000`)} (admin/admin)`);
175
- console.log(` - OpenMemory: ${chalk_1.default.underline(`http://${hostIp}:8080`)}`);
176
- // Tailscale Funnel setup
177
- if (useTailscale) {
178
- console.log(chalk_1.default.blue('\n🔗 Setting up Remote Access (Tailscale Funnel)...'));
179
- try {
180
- try {
181
- await (0, execa_1.default)('ssh', [sshHost, 'which tailscale']);
182
- }
183
- catch (e) {
184
- console.log(chalk_1.default.yellow(' Tailscale not found. Installing...'));
185
- await (0, execa_1.default)('ssh', [sshHost, 'curl -fsSL https://tailscale.com/install.sh | sh'], { stdio: 'inherit' });
186
- }
187
- console.log(chalk_1.default.blue(' Ensuring Tailscale is up...'));
188
- try {
189
- await (0, execa_1.default)('ssh', [sshHost, 'tailscale status']);
190
- }
191
- catch (e) {
192
- console.log(chalk_1.default.yellow(' ⚠️ Tailscale authentication required. Please follow the prompts:'));
193
- await (0, execa_1.default)('ssh', [sshHost, 'sudo tailscale up'], { stdio: 'inherit' });
194
- }
195
- console.log(chalk_1.default.blue(' Configuring HTTPS Funnel (requires sudo access)...'));
196
- console.log(chalk_1.default.gray(' You may be prompted for your RPi password.'));
197
- await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve reset'], { stdio: 'inherit' }).catch(() => { });
198
- await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg --set-path /cybermem http://127.0.0.1:8626'], { stdio: 'inherit' });
199
- await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg http://127.0.0.1:3000'], { stdio: 'inherit' });
200
- await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale funnel --bg 443'], { stdio: 'inherit' });
201
- const { stdout } = await (0, execa_1.default)('ssh', [sshHost, "tailscale status --json | jq -r '.Self.DNSName' | sed 's/\\.$//'"]);
202
- const dnsName = stdout.trim();
203
- console.log(chalk_1.default.green('\n🌐 Remote Access Active (HTTPS):'));
204
- console.log(` - Dashboard: ${chalk_1.default.underline(`https://${dnsName}/`)}`);
205
- console.log(` - MCP API: ${chalk_1.default.underline(`https://${dnsName}/cybermem/mcp`)}`);
206
- }
207
- catch (e) {
208
- console.log(chalk_1.default.red('\n❌ Remote Access setup failed:'));
209
- console.error(e);
210
- console.log(chalk_1.default.gray('Manual setup: curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up'));
211
- }
212
- }
213
- else {
214
- console.log(chalk_1.default.gray('\n💡 For remote access, re-run with: npx @cybermem/mcp --rpi --remote-access'));
215
- }
216
- }
217
- else if (target === 'vps') {
218
- console.log(chalk_1.default.yellow('VPS deployment is similar to RPi.'));
219
- console.log(chalk_1.default.blue('\n📋 VPS Deployment Steps:'));
220
- console.log('1. Run: npx @cybermem/mcp --rpi --host user@your-vps-ip');
221
- console.log('2. For HTTPS, choose one of:');
222
- console.log(chalk_1.default.gray(' a) Tailscale Funnel: --remote-access flag'));
223
- console.log(chalk_1.default.gray(' b) Caddy (recommended for public VPS):'));
224
- console.log(chalk_1.default.gray(' - Install Caddy: sudo apt install caddy'));
225
- console.log(chalk_1.default.gray(' - Configure /etc/caddy/Caddyfile:'));
226
- console.log(chalk_1.default.cyan(`
227
- cybermem.yourdomain.com {
228
- reverse_proxy localhost:3000
229
- }
230
- api.cybermem.yourdomain.com {
231
- reverse_proxy localhost:8080
232
- }
233
- `));
234
- console.log(chalk_1.default.gray(' - Restart: sudo systemctl restart caddy'));
235
- console.log(chalk_1.default.green('\n📚 Full docs: https://cybermem.dev/docs#https'));
236
- }
237
- }
238
- catch (error) {
239
- console.error(chalk_1.default.red('Deployment failed:'), error);
240
- process.exit(1);
241
- }
242
- }
@@ -1,65 +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.initCommand = void 0;
7
- const chalk_1 = __importDefault(require("chalk"));
8
- const commander_1 = require("commander");
9
- const fs_1 = __importDefault(require("fs"));
10
- const inquirer_1 = __importDefault(require("inquirer"));
11
- const path_1 = __importDefault(require("path"));
12
- exports.initCommand = new commander_1.Command('init')
13
- .description('Initialize CyberMem configuration')
14
- .action(async () => {
15
- console.log(chalk_1.default.bold.blue('🤖 CyberMem Setup Wizard'));
16
- const { target } = await inquirer_1.default.prompt([
17
- {
18
- type: 'list',
19
- name: 'target',
20
- message: 'Where do you want to deploy?',
21
- choices: [
22
- { name: 'Local (Docker Compose)', value: 'local' },
23
- { name: 'Raspberry Pi (Ansible)', value: 'rpi' },
24
- { name: 'VPS (Kubernetes/Helm)', value: 'vps' }
25
- ]
26
- }
27
- ]);
28
- console.log(chalk_1.default.green(`Selected target: ${target}`));
29
- if (target === 'local') {
30
- const { confirm } = await inquirer_1.default.prompt([
31
- {
32
- type: 'confirm',
33
- name: 'confirm',
34
- message: 'This will create docker-compose.yml and .env in current directory. Continue?',
35
- default: true
36
- }
37
- ]);
38
- if (confirm) {
39
- const templateDir = path_1.default.resolve(__dirname, '../../templates');
40
- const envSrc = path_1.default.join(templateDir, 'envs/local.example');
41
- if (!fs_1.default.existsSync(envSrc)) {
42
- console.error(chalk_1.default.red(`Template not found at ${envSrc}.`));
43
- return;
44
- }
45
- // Generate .env
46
- let envContent = fs_1.default.readFileSync(envSrc, 'utf-8');
47
- const crypto = require('crypto');
48
- const newKey = `sk-${crypto.randomBytes(16).toString('hex')}`;
49
- // Replace placeholder or key
50
- if (envContent.includes('key-change-me') || envContent.includes('OM_API_KEY=')) {
51
- envContent = envContent.replace(/OM_API_KEY=.*/, `OM_API_KEY=${newKey}`);
52
- }
53
- else {
54
- envContent += `\nOM_API_KEY=${newKey}\n`;
55
- }
56
- fs_1.default.writeFileSync('.env', envContent);
57
- console.log(chalk_1.default.gray('Created .env with generated API Key'));
58
- console.log(chalk_1.default.gray('(Docker Compose configuration is managed internally by the CLI)'));
59
- console.log(chalk_1.default.green('\nInitialization complete! Run "cybermem deploy" to start.'));
60
- }
61
- }
62
- else {
63
- console.log(chalk_1.default.yellow('Target init not fully implemented in CLI yet.'));
64
- }
65
- });
@@ -1,62 +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.restore = restore;
7
- const chalk_1 = __importDefault(require("chalk"));
8
- const execa_1 = __importDefault(require("execa"));
9
- const fs_1 = __importDefault(require("fs"));
10
- const path_1 = __importDefault(require("path"));
11
- async function restore(file, options) {
12
- if (!file) {
13
- console.error(chalk_1.default.red('Error: Please specify the backup file to restore.'));
14
- console.log(`Usage: npx @cybermem/mcp restore <file>`);
15
- process.exit(1);
16
- }
17
- const backupPath = path_1.default.resolve(process.cwd(), file);
18
- if (!fs_1.default.existsSync(backupPath)) {
19
- console.error(chalk_1.default.red(`Error: File not found at ${backupPath}`));
20
- process.exit(1);
21
- }
22
- console.log(chalk_1.default.blue(`♻️ Restoring from: ${path_1.default.basename(backupPath)}...`));
23
- console.log(chalk_1.default.yellow('⚠️ This will overwrite current data!'));
24
- try {
25
- // 1. Stop the OpenMemory service to safely write to DB
26
- console.log(chalk_1.default.blue('Stopping OpenMemory service...'));
27
- try {
28
- await (0, execa_1.default)('docker', ['stop', 'cybermem-openmemory']);
29
- }
30
- catch (e) {
31
- console.log(chalk_1.default.gray('Container not running (or not found), proceeding...'));
32
- }
33
- // 2. Restore data using transient alpine container
34
- console.log(chalk_1.default.blue('Extracting data to volume...'));
35
- // We handle both absolute paths (by mounting dir) or relative
36
- const dir = path_1.default.dirname(backupPath);
37
- const filename = path_1.default.basename(backupPath);
38
- const cmd = [
39
- 'run', '--rm',
40
- '--volumes-from', 'cybermem-openmemory', // Access the volume even if container is stopped
41
- '-v', `${dir}:/backup`,
42
- 'alpine',
43
- 'sh', '-c',
44
- // Extract to root / (since backup was relative to /data we need to be careful how it was packed)
45
- // In backup we did: tar czf ... -C / data
46
- // So it contains "data/..."
47
- // Extracting to / will put it in /data
48
- `tar xzf /backup/${filename} -C / && chown -R 1001:1001 /data`
49
- ];
50
- await (0, execa_1.default)('docker', cmd, { stdio: 'inherit' });
51
- // 3. Restart the service
52
- console.log(chalk_1.default.blue('Restarting OpenMemory service...'));
53
- await (0, execa_1.default)('docker', ['start', 'cybermem-openmemory']);
54
- console.log(chalk_1.default.green(`\n✅ Restore completed successfully!`));
55
- console.log('Your memory has been recovered.');
56
- }
57
- catch (error) {
58
- console.error(chalk_1.default.red('Restore failed:'), error);
59
- console.log(chalk_1.default.yellow('Suggestion: Check if Docker is running and "cybermem-openmemory" container exists.'));
60
- process.exit(1);
61
- }
62
- }
@@ -1,3 +0,0 @@
1
- [rpi]
2
- # Replace with your RPi IP address
3
- raspberrypi.local ansible_user=pi ansible_ssh_pass=Darwin1809 ansible_python_interpreter=/usr/bin/python3
@@ -1,71 +0,0 @@
1
- ---
2
- - name: Deploy CyberMem to Raspberry Pi
3
- hosts: rpi
4
- become: yes
5
- vars:
6
- project_dir: /home/{{ ansible_user }}/cybermem
7
- env_file: .env.rpi
8
-
9
- tasks:
10
- - name: Update apt cache
11
- apt:
12
- update_cache: yes
13
- cache_valid_time: 3600
14
-
15
- - name: Install dependencies
16
- apt:
17
- name:
18
- - git
19
- - rsync
20
- state: present
21
-
22
- - name: Ensure Docker service is running
23
- service:
24
- name: docker
25
- state: started
26
- enabled: yes
27
-
28
- - name: Add user to docker group
29
- user:
30
- name: "{{ ansible_user }}"
31
- groups: docker
32
- append: yes
33
-
34
- - name: Create project directory
35
- file:
36
- path: "{{ project_dir }}"
37
- state: directory
38
- owner: "{{ ansible_user }}"
39
- group: "{{ ansible_user }}"
40
- mode: "0755"
41
-
42
- - name: Synchronize project files
43
- synchronize:
44
- src: "{{ playbook_dir }}/../../"
45
- dest: "{{ project_dir }}"
46
- rsync_opts:
47
- - "--exclude=.git"
48
- - "--exclude=node_modules"
49
- - "--exclude=.next"
50
- - "--exclude=dashboard/.next"
51
- - "--exclude=*.log"
52
- - "--exclude=tmp"
53
- - "--exclude=__pycache__"
54
-
55
- - name: Copy environment file
56
- copy:
57
- src: "../../{{ env_file }}"
58
- dest: "{{ project_dir }}/.env"
59
- owner: "{{ ansible_user }}"
60
- group: "{{ ansible_user }}"
61
- mode: "0600"
62
-
63
- - name: Pull and start services
64
- command: docker-compose -f docker-compose.prod.yml --profile ollama up -d --pull always
65
- args:
66
- chdir: "{{ project_dir }}"
67
- register: compose_output
68
-
69
- - name: Show deployment status
70
- debug:
71
- var: compose_output.stdout_lines
@@ -1,17 +0,0 @@
1
- ---
2
- - name: Stop CyberMem on Raspberry Pi
3
- hosts: rpi
4
- become: yes
5
- vars:
6
- project_dir: /home/{{ ansible_user }}/cybermem
7
-
8
- tasks:
9
- - name: Stop services
10
- command: docker-compose down
11
- args:
12
- chdir: "{{ project_dir }}"
13
- register: down_output
14
-
15
- - name: Show stop status
16
- debug:
17
- var: down_output.stdout_lines
@@ -1,6 +0,0 @@
1
- apiVersion: v2
2
- name: cybermem
3
- description: A Helm chart for CyberMem AI Memory System
4
- type: application
5
- version: 0.1.0
6
- appVersion: "1.0.0"
@@ -1,29 +0,0 @@
1
- apiVersion: apps/v1
2
- kind: Deployment
3
- metadata:
4
- name: {{ .Chart.Name }}-dashboard
5
- labels:
6
- app.kubernetes.io/name: dashboard
7
- spec:
8
- replicas: {{ .Values.dashboard.replicaCount }}
9
- selector:
10
- matchLabels:
11
- app.kubernetes.io/name: dashboard
12
- template:
13
- metadata:
14
- labels:
15
- app.kubernetes.io/name: dashboard
16
- spec:
17
- containers:
18
- - name: dashboard
19
- image: "{{ .Values.dashboard.image.repository }}:{{ .Values.dashboard.image.tag }}"
20
- imagePullPolicy: {{ .Values.dashboard.image.pullPolicy }}
21
- ports:
22
- - name: http
23
- containerPort: 3000
24
- protocol: TCP
25
- env:
26
- - name: NEXT_PUBLIC_API_URL
27
- value: "http://{{ .Chart.Name }}-openmemory:8080"
28
- resources:
29
- {{- toYaml .Values.dashboard.resources | nindent 12 }}
@@ -1,20 +0,0 @@
1
- apiVersion: v1
2
- kind: Service
3
- metadata:
4
- name: {{ .Chart.Name }}-dashboard
5
- spec:
6
- type: {{ .Values.dashboard.service.type }}
7
- ports:
8
- - port: {{ .Values.dashboard.service.port }}
9
- targetPort: http
10
- protocol: TCP
11
- name: http
12
- {{- if eq .Values.dashboard.service.type "NodePort" }}
13
- - port: {{ .Values.dashboard.service.port }}
14
- targetPort: http
15
- nodePort: {{ .Values.dashboard.service.nodePort }}
16
- protocol: TCP
17
- name: http-node
18
- {{- end }}
19
- selector:
20
- app.kubernetes.io/name: dashboard
@@ -1,40 +0,0 @@
1
- apiVersion: apps/v1
2
- kind: Deployment
3
- metadata:
4
- name: {{ .Chart.Name }}-openmemory
5
- labels:
6
- app.kubernetes.io/name: openmemory
7
- spec:
8
- replicas: {{ .Values.openmemory.replicaCount }}
9
- selector:
10
- matchLabels:
11
- app.kubernetes.io/name: openmemory
12
- template:
13
- metadata:
14
- labels:
15
- app.kubernetes.io/name: openmemory
16
- spec:
17
- containers:
18
- - name: openmemory
19
- image: "{{ .Values.openmemory.image.repository }}:{{ .Values.openmemory.image.tag }}"
20
- imagePullPolicy: {{ .Values.openmemory.image.pullPolicy }}
21
- ports:
22
- - name: http
23
- containerPort: 8080
24
- protocol: TCP
25
- env:
26
- - name: OPENMEMORY_API_KEY
27
- value: {{ .Values.env.OPENMEMORY_API_KEY | quote }}
28
- - name: OPENAI_API_KEY
29
- value: {{ .Values.env.OPENAI_API_KEY | quote }}
30
- - name: DB_PATH
31
- value: "/data/openmemory.sqlite"
32
- volumeMounts:
33
- - name: data
34
- mountPath: /data
35
- resources:
36
- {{- toYaml .Values.openmemory.resources | nindent 12 }}
37
- volumes:
38
- - name: data
39
- persistentVolumeClaim:
40
- claimName: {{ .Chart.Name }}-openmemory-pvc
@@ -1,10 +0,0 @@
1
- apiVersion: v1
2
- kind: PersistentVolumeClaim
3
- metadata:
4
- name: {{ .Chart.Name }}-openmemory-pvc
5
- spec:
6
- accessModes:
7
- - {{ .Values.openmemory.persistence.accessMode }}
8
- resources:
9
- requests:
10
- storage: {{ .Values.openmemory.persistence.size }}
@@ -1,13 +0,0 @@
1
- apiVersion: v1
2
- kind: Service
3
- metadata:
4
- name: {{ .Chart.Name }}-openmemory
5
- spec:
6
- type: {{ .Values.openmemory.service.type }}
7
- ports:
8
- - port: {{ .Values.openmemory.service.port }}
9
- targetPort: http
10
- protocol: TCP
11
- name: http
12
- selector:
13
- app.kubernetes.io/name: openmemory
@@ -1,18 +0,0 @@
1
- # VPS Overrides
2
-
3
- openmemory:
4
- image:
5
- repository: ghcr.io/mikhailkogan17/cybermem-openmemory
6
- pullPolicy: Always
7
- service:
8
- type: ClusterIP
9
-
10
- dashboard:
11
- image:
12
- repository: ghcr.io/mikhailkogan17/cybermem-dashboard
13
- pullPolicy: Always
14
-
15
- env:
16
- OPENMEMORY_API_KEY: "prod-secret-key-CHANGE-ME"
17
- # Add your OpenAI Key here for production
18
- OPENAI_API_KEY: "sk-..."
@@ -1,42 +0,0 @@
1
- # Default values for cybermem.
2
-
3
- openmemory:
4
- image:
5
- repository: cybermem-openmemory
6
- pullPolicy: IfNotPresent
7
- tag: "latest"
8
- replicaCount: 1
9
- service:
10
- type: ClusterIP
11
- port: 8080
12
- persistence:
13
- enabled: true
14
- size: 10Gi
15
- accessMode: ReadWriteOnce
16
- resources:
17
- limits:
18
- cpu: 1000m
19
- memory: 1Gi
20
- requests:
21
- cpu: 100m
22
- memory: 256Mi
23
- env:
24
- # Passed to the container
25
- OM_PORT: "8080"
26
-
27
- dashboard:
28
- image:
29
- repository: cybermem-dashboard
30
- pullPolicy: IfNotPresent
31
- tag: "latest"
32
- replicaCount: 1
33
- service:
34
- type: ClusterIP
35
- port: 3000
36
- nodePort: 30000 # For k3d/local access if needed
37
- resources: {}
38
-
39
- env:
40
- # Shared secrets
41
- OPENMEMORY_API_KEY: "dev-secret-key"
42
- OPENAI_API_KEY: ""