@cybermem/mcp 0.5.1 → 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.
- package/README.md +1 -1
- package/dist/index.js +187 -194
- package/package.json +29 -28
- package/requirements.txt +2 -0
- package/server.py +347 -0
- package/src/index.ts +227 -0
- package/test_mcp.py +111 -0
- package/tsconfig.json +14 -0
- package/dist/commands/deploy.js +0 -230
- package/dist/commands/init.js +0 -65
- package/dist/templates/ansible/inventory/hosts.ini +0 -3
- package/dist/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
- package/dist/templates/ansible/playbooks/stop-cybermem.yml +0 -17
- package/dist/templates/charts/cybermem/Chart.yaml +0 -6
- package/dist/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
- package/dist/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
- package/dist/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
- package/dist/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
- package/dist/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
- package/dist/templates/charts/cybermem/values-vps.yaml +0 -18
- package/dist/templates/charts/cybermem/values.yaml +0 -42
- package/dist/templates/docker-compose.yml +0 -219
- package/dist/templates/envs/local.example +0 -27
- package/dist/templates/envs/rpi.example +0 -27
- package/dist/templates/envs/vps.example +0 -25
- package/dist/templates/monitoring/db_exporter/Dockerfile +0 -19
- package/dist/templates/monitoring/db_exporter/exporter.py +0 -313
- package/dist/templates/monitoring/db_exporter/requirements.txt +0 -2
- package/dist/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
- package/dist/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
- package/dist/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
- package/dist/templates/monitoring/log_exporter/Dockerfile +0 -13
- package/dist/templates/monitoring/log_exporter/exporter.py +0 -274
- package/dist/templates/monitoring/log_exporter/requirements.txt +0 -1
- package/dist/templates/monitoring/postgres_exporter/queries.yml +0 -22
- package/dist/templates/monitoring/prometheus/prometheus.yml +0 -22
- package/dist/templates/monitoring/traefik/traefik.yml +0 -32
- package/dist/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
- package/dist/templates/monitoring/vector/vector.yaml +0 -106
- package/templates/ansible/inventory/hosts.ini +0 -3
- package/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
- package/templates/ansible/playbooks/stop-cybermem.yml +0 -17
- package/templates/charts/cybermem/Chart.yaml +0 -6
- package/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
- package/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
- package/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
- package/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
- package/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
- package/templates/charts/cybermem/values-vps.yaml +0 -18
- package/templates/charts/cybermem/values.yaml +0 -42
- package/templates/docker-compose.yml +0 -219
- package/templates/envs/local.example +0 -27
- package/templates/envs/rpi.example +0 -27
- package/templates/envs/vps.example +0 -25
- package/templates/monitoring/db_exporter/Dockerfile +0 -19
- package/templates/monitoring/db_exporter/exporter.py +0 -313
- package/templates/monitoring/db_exporter/requirements.txt +0 -2
- package/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
- package/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
- package/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
- package/templates/monitoring/log_exporter/Dockerfile +0 -13
- package/templates/monitoring/log_exporter/exporter.py +0 -274
- package/templates/monitoring/log_exporter/requirements.txt +0 -1
- package/templates/monitoring/postgres_exporter/queries.yml +0 -22
- package/templates/monitoring/prometheus/prometheus.yml +0 -22
- package/templates/monitoring/traefik/traefik.yml +0 -32
- package/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
- package/templates/monitoring/vector/vector.yaml +0 -106
package/dist/commands/deploy.js
DELETED
|
@@ -1,230 +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.deployCommand = void 0;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
const commander_1 = require("commander");
|
|
9
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
-
const execa_1 = __importDefault(require("execa"));
|
|
11
|
-
const fs_1 = __importDefault(require("fs"));
|
|
12
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
13
|
-
const os_1 = __importDefault(require("os"));
|
|
14
|
-
const path_1 = __importDefault(require("path"));
|
|
15
|
-
exports.deployCommand = new commander_1.Command('deploy')
|
|
16
|
-
.description('Deploy CyberMem services')
|
|
17
|
-
.option('-t, --target <target>', 'Deployment target (local, rpi, vps)', 'local')
|
|
18
|
-
.option('-h, --host <host>', 'SSH Host (user@ip) for remote deployment')
|
|
19
|
-
.option('--remote-access', 'Enable remote access via Tailscale Funnel (HTTPS)', false)
|
|
20
|
-
.option('--tailscale', 'Alias for --remote-access (deprecated)', false)
|
|
21
|
-
.option('--caddy', 'Use Caddy for automatic HTTPS (VPS only)')
|
|
22
|
-
.action(async (options) => {
|
|
23
|
-
const target = options.target;
|
|
24
|
-
const useTailscale = options.remoteAccess || options.tailscale;
|
|
25
|
-
const useCaddy = options.caddy;
|
|
26
|
-
console.log(chalk_1.default.blue(`Deploying to ${target}...`));
|
|
27
|
-
try {
|
|
28
|
-
// Resolve Template Directory (Support both Dev and Prod)
|
|
29
|
-
// Resolve Template Directory (Support both Dev and Prod)
|
|
30
|
-
// In Prod: __dirname is dist/commands, so templates is ../templates (dist/templates)
|
|
31
|
-
// In Dev (ts-node): __dirname is src/commands, so templates is ../../templates (root/packages/cli/templates)
|
|
32
|
-
// Try production path first (dist/templates)
|
|
33
|
-
let templateDir = path_1.default.resolve(__dirname, '../templates');
|
|
34
|
-
// If not found, try development path (src/../../templates)
|
|
35
|
-
if (!fs_1.default.existsSync(templateDir)) {
|
|
36
|
-
templateDir = path_1.default.resolve(__dirname, '../../templates');
|
|
37
|
-
}
|
|
38
|
-
// Final sanity check
|
|
39
|
-
if (!fs_1.default.existsSync(templateDir)) {
|
|
40
|
-
// Fallback for when running from root with ts-node directly (unlikely but possible)
|
|
41
|
-
templateDir = path_1.default.resolve(process.cwd(), 'packages/cli/templates');
|
|
42
|
-
}
|
|
43
|
-
if (!fs_1.default.existsSync(templateDir)) {
|
|
44
|
-
throw new Error(`Templates not found at ${templateDir}. Please ensure package is built correctly.`);
|
|
45
|
-
}
|
|
46
|
-
if (target === 'local') {
|
|
47
|
-
const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
|
|
48
|
-
const internalEnvExample = path_1.default.join(templateDir, 'envs/local.example');
|
|
49
|
-
if (!fs_1.default.existsSync(composeFile)) {
|
|
50
|
-
console.error(chalk_1.default.red(`Internal Error: Template not found at ${composeFile}`));
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
// Home Directory Config
|
|
54
|
-
const homeDir = os_1.default.homedir();
|
|
55
|
-
const configDir = path_1.default.join(homeDir, '.cybermem');
|
|
56
|
-
const envFile = path_1.default.join(configDir, '.env');
|
|
57
|
-
const dataDir = path_1.default.join(configDir, 'data');
|
|
58
|
-
// 1. Ensure ~/.cybermem exists
|
|
59
|
-
if (!fs_1.default.existsSync(configDir)) {
|
|
60
|
-
fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
61
|
-
fs_1.default.mkdirSync(dataDir, { recursive: true });
|
|
62
|
-
}
|
|
63
|
-
// 2. Local Mode: Simplified setup without mandatory API key
|
|
64
|
-
if (!fs_1.default.existsSync(envFile)) {
|
|
65
|
-
console.log(chalk_1.default.yellow(`Initializing local configuration in ${configDir}...`));
|
|
66
|
-
const envContent = fs_1.default.readFileSync(internalEnvExample, 'utf-8');
|
|
67
|
-
fs_1.default.writeFileSync(envFile, envContent);
|
|
68
|
-
console.log(chalk_1.default.green(`Created .env at ${envFile}`));
|
|
69
|
-
}
|
|
70
|
-
console.log(chalk_1.default.blue('Starting CyberMem services in Local Mode...'));
|
|
71
|
-
// Execute docker-compose with internal file and USER HOME env
|
|
72
|
-
// Note: We pass CYBERMEM_API_KEY="" explicitly for local mode to trigger keyless bypass
|
|
73
|
-
await (0, execa_1.default)('docker-compose', [
|
|
74
|
-
'-f', composeFile,
|
|
75
|
-
'--env-file', envFile,
|
|
76
|
-
'--project-name', 'cybermem',
|
|
77
|
-
'up', '-d', '--remove-orphans'
|
|
78
|
-
], {
|
|
79
|
-
stdio: 'inherit',
|
|
80
|
-
env: {
|
|
81
|
-
...process.env,
|
|
82
|
-
DATA_DIR: dataDir,
|
|
83
|
-
CYBERMEM_ENV_PATH: envFile,
|
|
84
|
-
CYBERMEM_API_KEY: ''
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
console.log(chalk_1.default.green('\n🎉 CyberMem Installed!'));
|
|
88
|
-
console.log('');
|
|
89
|
-
console.log(chalk_1.default.bold('Next Steps:'));
|
|
90
|
-
console.log(` 1. Open ${chalk_1.default.underline('http://localhost:3000/client-connect')} to connect your MCP clients`);
|
|
91
|
-
console.log(` 2. Default password: ${chalk_1.default.bold('admin')} (you'll be prompted to change it)`);
|
|
92
|
-
console.log('');
|
|
93
|
-
console.log(chalk_1.default.dim('Local mode is active: No API key required for connections from this laptop.'));
|
|
94
|
-
}
|
|
95
|
-
else if (target === 'rpi') {
|
|
96
|
-
const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
|
|
97
|
-
const internalEnvExample = path_1.default.join(templateDir, 'envs/rpi.example');
|
|
98
|
-
let sshHost = options.host;
|
|
99
|
-
if (!sshHost) {
|
|
100
|
-
const answers = await inquirer_1.default.prompt([
|
|
101
|
-
{
|
|
102
|
-
type: 'input',
|
|
103
|
-
name: 'host',
|
|
104
|
-
message: 'Enter SSH Host (e.g. pi@raspberrypi.local):',
|
|
105
|
-
validate: (input) => input.includes('@') ? true : 'Format must be user@host'
|
|
106
|
-
}
|
|
107
|
-
]);
|
|
108
|
-
sshHost = answers.host;
|
|
109
|
-
}
|
|
110
|
-
console.log(chalk_1.default.blue(`Remote deploying to ${sshHost}...`));
|
|
111
|
-
// 1. Create remote directory
|
|
112
|
-
await (0, execa_1.default)('ssh', [sshHost, 'mkdir -p ~/.cybermem/data']);
|
|
113
|
-
// 2. Initial Env Setup (if missing)
|
|
114
|
-
// We read remote file check using ssh
|
|
115
|
-
try {
|
|
116
|
-
await (0, execa_1.default)('ssh', [sshHost, '[ -f ~/.cybermem/.env ]']);
|
|
117
|
-
console.log(chalk_1.default.gray('Remote .env exists, skipping generation.'));
|
|
118
|
-
}
|
|
119
|
-
catch (e) {
|
|
120
|
-
console.log(chalk_1.default.yellow('Generating remote .env...'));
|
|
121
|
-
let envContent = fs_1.default.readFileSync(internalEnvExample, 'utf-8');
|
|
122
|
-
const newKey = `sk-${crypto_1.default.randomBytes(16).toString('hex')}`;
|
|
123
|
-
if (envContent.includes('CYBERMEM_API_KEY=')) {
|
|
124
|
-
envContent = envContent.replace(/CYBERMEM_API_KEY=.*/, `CYBERMEM_API_KEY=${newKey}`);
|
|
125
|
-
}
|
|
126
|
-
// Write to temp file then scp
|
|
127
|
-
const tempEnv = path_1.default.join(os_1.default.tmpdir(), 'cybermem-rpi.env');
|
|
128
|
-
fs_1.default.writeFileSync(tempEnv, envContent);
|
|
129
|
-
await (0, execa_1.default)('scp', [tempEnv, `${sshHost}:~/.cybermem/.env`]);
|
|
130
|
-
fs_1.default.unlinkSync(tempEnv);
|
|
131
|
-
}
|
|
132
|
-
// 3. Copy Docker Compose
|
|
133
|
-
console.log(chalk_1.default.blue('Uploading templates...'));
|
|
134
|
-
await (0, execa_1.default)('scp', [composeFile, `${sshHost}:~/.cybermem/docker-compose.yml`]);
|
|
135
|
-
// 4. Run Docker Compose Remotely
|
|
136
|
-
console.log(chalk_1.default.blue('Starting services on RPi...'));
|
|
137
|
-
// We pass CYBERMEM_ENV_PATH explicitly as ~/.cybermem/.env and DATA_DIR as ~/.cybermem/data
|
|
138
|
-
// The template uses ${CYBERMEM_ENV_PATH} and maps volumes.
|
|
139
|
-
// We need to set these vars in the shell when running docker-compose
|
|
140
|
-
const remoteCmd = `
|
|
141
|
-
export CYBERMEM_ENV_PATH=~/.cybermem/.env
|
|
142
|
-
export DATA_DIR=~/.cybermem/data
|
|
143
|
-
docker-compose -f ~/.cybermem/docker-compose.yml up -d --remove-orphans
|
|
144
|
-
`;
|
|
145
|
-
await (0, execa_1.default)('ssh', [sshHost, remoteCmd], { stdio: 'inherit' });
|
|
146
|
-
console.log(chalk_1.default.green('\n✅ RPi deployment successful!'));
|
|
147
|
-
// Parse host from ssh string for convenience
|
|
148
|
-
const hostIp = sshHost.split('@')[1];
|
|
149
|
-
console.log(chalk_1.default.bold('Access Points (LAN):'));
|
|
150
|
-
console.log(` - Dashboard: ${chalk_1.default.underline(`http://${hostIp}:3000`)} (admin/admin)`);
|
|
151
|
-
console.log(` - OpenMemory: ${chalk_1.default.underline(`http://${hostIp}:8080`)}`);
|
|
152
|
-
// Tailscale Funnel setup
|
|
153
|
-
if (useTailscale) {
|
|
154
|
-
console.log(chalk_1.default.blue('\n🔗 Setting up Remote Access (Tailscale Funnel)...'));
|
|
155
|
-
try {
|
|
156
|
-
// 1. Check/Install Tailscale
|
|
157
|
-
try {
|
|
158
|
-
await (0, execa_1.default)('ssh', [sshHost, 'which tailscale']);
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
console.log(chalk_1.default.yellow(' Tailscale not found. Installing...'));
|
|
162
|
-
await (0, execa_1.default)('ssh', [sshHost, 'curl -fsSL https://tailscale.com/install.sh | sh'], { stdio: 'inherit' });
|
|
163
|
-
}
|
|
164
|
-
// 2. Auth (interactive if needed)
|
|
165
|
-
console.log(chalk_1.default.blue(' Ensuring Tailscale is up...'));
|
|
166
|
-
try {
|
|
167
|
-
// Check status first to avoid re-auth if already up
|
|
168
|
-
await (0, execa_1.default)('ssh', [sshHost, 'tailscale status']);
|
|
169
|
-
}
|
|
170
|
-
catch (e) {
|
|
171
|
-
// Interactive auth
|
|
172
|
-
console.log(chalk_1.default.yellow(' ⚠️ Tailscale authentication required. Please follow the prompts:'));
|
|
173
|
-
await (0, execa_1.default)('ssh', [sshHost, 'sudo tailscale up'], { stdio: 'inherit' });
|
|
174
|
-
}
|
|
175
|
-
// 3. Configure Funnel (Verified commands)
|
|
176
|
-
console.log(chalk_1.default.blue(' Configuring HTTPS Funnel (requires sudo access)...'));
|
|
177
|
-
console.log(chalk_1.default.gray(' You may be prompted for your RPi password.'));
|
|
178
|
-
// Routes:
|
|
179
|
-
// - / -> Dashboard (3000)
|
|
180
|
-
// - /cybermem/mcp -> MCP API (8626/mcp)
|
|
181
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve reset'], { stdio: 'inherit' }).catch(() => { });
|
|
182
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg --set-path /cybermem http://127.0.0.1:8626'], { stdio: 'inherit' });
|
|
183
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg http://127.0.0.1:3000'], { stdio: 'inherit' });
|
|
184
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale funnel --bg 443'], { stdio: 'inherit' });
|
|
185
|
-
// Get DNS name
|
|
186
|
-
const { stdout } = await (0, execa_1.default)('ssh', [sshHost, "tailscale status --json | jq -r '.Self.DNSName' | sed 's/\\.$//'"], { shell: true });
|
|
187
|
-
const dnsName = stdout.trim();
|
|
188
|
-
console.log(chalk_1.default.green('\n🌐 Remote Access Active (HTTPS):'));
|
|
189
|
-
console.log(` - Dashboard: ${chalk_1.default.underline(`https://${dnsName}/`)}`);
|
|
190
|
-
console.log(` - MCP API: ${chalk_1.default.underline(`https://${dnsName}/cybermem/mcp`)}`);
|
|
191
|
-
}
|
|
192
|
-
catch (e) {
|
|
193
|
-
console.log(chalk_1.default.red('\n❌ Remote Access setup failed:'));
|
|
194
|
-
console.error(e);
|
|
195
|
-
console.log(chalk_1.default.gray('Manual setup: curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up'));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
console.log(chalk_1.default.gray('\n💡 For remote access, re-run with: cybermem deploy --target rpi --remote-access'));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
else if (target === 'vps') {
|
|
203
|
-
console.log(chalk_1.default.yellow('VPS deployment is similar to RPi.'));
|
|
204
|
-
console.log(chalk_1.default.blue('\n📋 VPS Deployment Steps:'));
|
|
205
|
-
console.log('1. Run: cybermem deploy --target rpi --host user@your-vps-ip');
|
|
206
|
-
console.log('2. For HTTPS, choose one of:');
|
|
207
|
-
console.log(chalk_1.default.gray(' a) Tailscale Funnel: --tailscale flag'));
|
|
208
|
-
console.log(chalk_1.default.gray(' b) Caddy (recommended for public VPS):'));
|
|
209
|
-
console.log(chalk_1.default.gray(' - Install Caddy: sudo apt install caddy'));
|
|
210
|
-
console.log(chalk_1.default.gray(' - Configure /etc/caddy/Caddyfile:'));
|
|
211
|
-
console.log(chalk_1.default.cyan(`
|
|
212
|
-
cybermem.yourdomain.com {
|
|
213
|
-
reverse_proxy localhost:3000
|
|
214
|
-
}
|
|
215
|
-
api.cybermem.yourdomain.com {
|
|
216
|
-
reverse_proxy localhost:8080
|
|
217
|
-
}
|
|
218
|
-
`));
|
|
219
|
-
console.log(chalk_1.default.gray(' - Restart: sudo systemctl restart caddy'));
|
|
220
|
-
console.log(chalk_1.default.green('\n📚 Full docs: https://cybermem.dev/docs#https'));
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
console.error(chalk_1.default.red(`Unknown target: ${target}. Use: local, rpi, or vps`));
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
catch (error) {
|
|
227
|
-
console.error(chalk_1.default.red('Deployment failed:'), error);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
});
|
package/dist/commands/init.js
DELETED
|
@@ -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,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,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,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: ""
|