@cybermem/cli 0.6.1 ā 0.6.5
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/dist/commands/deploy.js +11 -14
- package/dist/commands/reset.js +63 -0
- package/dist/index.js +5 -1
- package/dist/templates/docker-compose.yml +21 -1
- package/dist/templates/monitoring/db_exporter/exporter.py +303 -94
- package/dist/templates/monitoring/instructions_injector/Dockerfile +15 -0
- package/dist/templates/monitoring/instructions_injector/injector.py +137 -0
- package/dist/templates/monitoring/instructions_injector/requirements.txt +3 -0
- package/dist/templates/monitoring/log_exporter/exporter.py +7 -3
- package/package.json +1 -1
- package/templates/docker-compose.yml +21 -1
- package/templates/monitoring/db_exporter/exporter.py +303 -94
- package/templates/monitoring/instructions_injector/Dockerfile +15 -0
- package/templates/monitoring/instructions_injector/injector.py +137 -0
- package/templates/monitoring/instructions_injector/requirements.txt +3 -0
- package/templates/monitoring/log_exporter/exporter.py +7 -3
package/dist/commands/deploy.js
CHANGED
|
@@ -86,18 +86,15 @@ async function deploy(options) {
|
|
|
86
86
|
else if (target === 'rpi') {
|
|
87
87
|
const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
|
|
88
88
|
const internalEnvExample = path_1.default.join(templateDir, 'envs/rpi.example');
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
]);
|
|
99
|
-
sshHost = answers.host;
|
|
100
|
-
}
|
|
89
|
+
const answers = await inquirer_1.default.prompt([
|
|
90
|
+
{
|
|
91
|
+
type: 'input',
|
|
92
|
+
name: 'host',
|
|
93
|
+
message: 'Enter SSH Host (e.g. pi@raspberrypi.local):',
|
|
94
|
+
validate: (input) => input.includes('@') ? true : 'Format must be user@host'
|
|
95
|
+
}
|
|
96
|
+
]);
|
|
97
|
+
const sshHost = answers.host;
|
|
101
98
|
console.log(chalk_1.default.blue(`Remote deploying to ${sshHost}...`));
|
|
102
99
|
// 1. Create remote directory
|
|
103
100
|
await (0, execa_1.default)('ssh', [sshHost, 'mkdir -p ~/.cybermem/data']);
|
|
@@ -211,13 +208,13 @@ async function deploy(options) {
|
|
|
211
208
|
}
|
|
212
209
|
}
|
|
213
210
|
else {
|
|
214
|
-
console.log(chalk_1.default.gray('\nš” For remote access, re-run with: npx @cybermem/
|
|
211
|
+
console.log(chalk_1.default.gray('\nš” For remote access, re-run with: npx @cybermem/cli --rpi --remote-access'));
|
|
215
212
|
}
|
|
216
213
|
}
|
|
217
214
|
else if (target === 'vps') {
|
|
218
215
|
console.log(chalk_1.default.yellow('VPS deployment is similar to RPi.'));
|
|
219
216
|
console.log(chalk_1.default.blue('\nš VPS Deployment Steps:'));
|
|
220
|
-
console.log('1. Run: npx @cybermem/
|
|
217
|
+
console.log('1. Run: npx @cybermem/cli --rpi pi@your-vps-ip');
|
|
221
218
|
console.log('2. For HTTPS, choose one of:');
|
|
222
219
|
console.log(chalk_1.default.gray(' a) Tailscale Funnel: --remote-access flag'));
|
|
223
220
|
console.log(chalk_1.default.gray(' b) Caddy (recommended for public VPS):'));
|
|
@@ -0,0 +1,63 @@
|
|
|
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.reset = reset;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const ora_1 = __importDefault(require("ora"));
|
|
10
|
+
async function reset() {
|
|
11
|
+
const spinner = (0, ora_1.default)('Resetting CyberMem database...').start();
|
|
12
|
+
try {
|
|
13
|
+
const containerName = 'cybermem-openmemory';
|
|
14
|
+
// Check if container exists
|
|
15
|
+
try {
|
|
16
|
+
(0, child_process_1.execSync)(`docker inspect ${containerName}`, { stdio: 'pipe' });
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
spinner.fail('Container not found. Is CyberMem running?');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
// Remove SQLite files
|
|
23
|
+
spinner.text = 'Removing database files...';
|
|
24
|
+
(0, child_process_1.execSync)(`docker exec ${containerName} sh -c 'rm -f /data/openmemory.sqlite*'`, {
|
|
25
|
+
stdio: 'pipe'
|
|
26
|
+
});
|
|
27
|
+
// Restart container
|
|
28
|
+
spinner.text = 'Restarting container...';
|
|
29
|
+
(0, child_process_1.execSync)(`docker restart ${containerName}`, { stdio: 'pipe' });
|
|
30
|
+
// Wait for health
|
|
31
|
+
spinner.text = 'Waiting for health check...';
|
|
32
|
+
let healthy = false;
|
|
33
|
+
for (let i = 0; i < 30; i++) {
|
|
34
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
35
|
+
try {
|
|
36
|
+
(0, child_process_1.execSync)('curl -s http://localhost:8626/health | grep -q ok', { stdio: 'pipe' });
|
|
37
|
+
healthy = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Still starting up
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!healthy) {
|
|
45
|
+
spinner.fail('Container failed to become healthy');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
// Restart exporters
|
|
49
|
+
spinner.text = 'Restarting exporters...';
|
|
50
|
+
try {
|
|
51
|
+
(0, child_process_1.execSync)('docker restart cybermem-log-exporter cybermem-db-exporter', { stdio: 'pipe' });
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Exporters may not exist
|
|
55
|
+
}
|
|
56
|
+
spinner.succeed(chalk_1.default.green('Database reset successfully!'));
|
|
57
|
+
console.log(chalk_1.default.gray(' All memories have been deleted.'));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
spinner.fail(`Reset failed: ${error.message}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const backup_1 = require("./commands/backup");
|
|
6
6
|
const deploy_1 = require("./commands/deploy");
|
|
7
|
+
const reset_1 = require("./commands/reset");
|
|
7
8
|
const restore_1 = require("./commands/restore");
|
|
8
9
|
const program = new commander_1.Command();
|
|
9
10
|
program
|
|
@@ -16,7 +17,6 @@ program
|
|
|
16
17
|
.description('Deploy CyberMem (Default)')
|
|
17
18
|
.option('--rpi', 'Deploy to Raspberry Pi (default: local)')
|
|
18
19
|
.option('--vps', 'Deploy to VPS/Cloud server')
|
|
19
|
-
.option('-h, --host <host>', 'SSH Host (user@ip) for remote deployment')
|
|
20
20
|
.option('--remote-access', 'Enable Tailscale Funnel for HTTPS remote access')
|
|
21
21
|
.action(deploy_1.deploy);
|
|
22
22
|
program
|
|
@@ -28,4 +28,8 @@ program
|
|
|
28
28
|
.description('Restore CyberMem data from a backup file')
|
|
29
29
|
.argument('<file>', 'Backup file to restore')
|
|
30
30
|
.action(restore_1.restore);
|
|
31
|
+
program
|
|
32
|
+
.command('reset')
|
|
33
|
+
.description('Reset (wipe) the CyberMem database - DESTRUCTIVE!')
|
|
34
|
+
.action(reset_1.reset);
|
|
31
35
|
program.parse(process.argv);
|
|
@@ -40,6 +40,26 @@ services:
|
|
|
40
40
|
- traefik.http.services.mcp-get.loadbalancer.server.port=8081
|
|
41
41
|
restart: unless-stopped
|
|
42
42
|
|
|
43
|
+
# Instructions injector: adds 'instructions' field to MCP initialize responses
|
|
44
|
+
instructions-injector:
|
|
45
|
+
build:
|
|
46
|
+
context: ./monitoring/instructions_injector
|
|
47
|
+
dockerfile: Dockerfile
|
|
48
|
+
container_name: cybermem-instructions-injector
|
|
49
|
+
environment:
|
|
50
|
+
UPSTREAM_URL: http://openmemory:8080
|
|
51
|
+
PORT: "8081"
|
|
52
|
+
labels:
|
|
53
|
+
- traefik.enable=true
|
|
54
|
+
# Route POST /mcp through injector (higher priority than openmemory)
|
|
55
|
+
- traefik.http.routers.mcp-inject.entrypoints=web
|
|
56
|
+
- traefik.http.routers.mcp-inject.rule=Method(`POST`) && Path(`/mcp`)
|
|
57
|
+
- traefik.http.routers.mcp-inject.priority=150
|
|
58
|
+
- traefik.http.services.mcp-inject.loadbalancer.server.port=8081
|
|
59
|
+
restart: unless-stopped
|
|
60
|
+
depends_on:
|
|
61
|
+
- openmemory
|
|
62
|
+
|
|
43
63
|
openmemory:
|
|
44
64
|
build:
|
|
45
65
|
context: ./openmemory
|
|
@@ -79,7 +99,7 @@ services:
|
|
|
79
99
|
labels:
|
|
80
100
|
- traefik.enable=true
|
|
81
101
|
- traefik.http.routers.openmemory.entrypoints=web
|
|
82
|
-
- traefik.http.routers.openmemory.rule=PathPrefix(`/memory`) || PathPrefix(`/health`) || PathPrefix(`/v1`) || PathPrefix(`/api`) || PathPrefix(`/all`) || PathPrefix(`/add`) || PathPrefix(`/
|
|
102
|
+
- traefik.http.routers.openmemory.rule=PathPrefix(`/memory`) || PathPrefix(`/health`) || PathPrefix(`/v1`) || PathPrefix(`/api`) || PathPrefix(`/all`) || PathPrefix(`/add`) || PathPrefix(`/sse`)
|
|
83
103
|
- traefik.http.services.openmemory.loadbalancer.server.port=8080
|
|
84
104
|
healthcheck:
|
|
85
105
|
test:
|