@trlc/super-memory 1.0.0 → 1.1.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/1 +32 -0
- package/dashboard/index.html +851 -0
- package/dashboard/package-lock.json +1158 -0
- package/dashboard/package.json +15 -0
- package/dashboard/server.js +355 -0
- package/dist/commands/categorize.js +70 -0
- package/dist/commands/curate.js +220 -0
- package/dist/commands/dashboard.js +165 -0
- package/dist/commands/flush.js +70 -0
- package/dist/commands/indexUpdate.js +57 -0
- package/dist/commands/maintenance.js +68 -0
- package/dist/index.js +93 -0
- package/dist/utils/config.js +44 -0
- package/package.json +3 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Command
|
|
3
|
+
* Starts a local web server with the Super Memory dashboard
|
|
4
|
+
*/
|
|
5
|
+
import { spawn, execSync } from 'child_process';
|
|
6
|
+
import { existsSync, readFileSync } from 'fs';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import net from 'net';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
// Get dashboard directory (relative to compiled output)
|
|
14
|
+
function getDashboardDir() {
|
|
15
|
+
// When running from dist/, dashboard is at ../dashboard
|
|
16
|
+
const fromDist = join(__dirname, '..', '..', 'dashboard');
|
|
17
|
+
if (existsSync(fromDist)) {
|
|
18
|
+
return fromDist;
|
|
19
|
+
}
|
|
20
|
+
// When running from src/, dashboard is at ../../dashboard
|
|
21
|
+
const fromSrc = join(__dirname, '..', '..', 'dashboard');
|
|
22
|
+
if (existsSync(fromSrc)) {
|
|
23
|
+
return fromSrc;
|
|
24
|
+
}
|
|
25
|
+
throw new Error('Dashboard directory not found');
|
|
26
|
+
}
|
|
27
|
+
// Get config
|
|
28
|
+
function loadConfig() {
|
|
29
|
+
const configPath = join(homedir(), '.openclaw', 'workspace', '.super-memory', 'config.json');
|
|
30
|
+
if (!existsSync(configPath)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Check if a port is available
|
|
41
|
+
async function isPortAvailable(port) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const server = net.createServer();
|
|
44
|
+
server.once('error', () => resolve(false));
|
|
45
|
+
server.once('listening', () => {
|
|
46
|
+
server.close(() => resolve(true));
|
|
47
|
+
});
|
|
48
|
+
server.listen(port, '127.0.0.1');
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Find an available port
|
|
52
|
+
async function findAvailablePort(startPort) {
|
|
53
|
+
for (let port = startPort; port < startPort + 100; port++) {
|
|
54
|
+
if (await isPortAvailable(port)) {
|
|
55
|
+
return port;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return startPort; // fallback
|
|
59
|
+
}
|
|
60
|
+
// Open browser
|
|
61
|
+
function openBrowser(url) {
|
|
62
|
+
try {
|
|
63
|
+
const platform = process.platform;
|
|
64
|
+
let command;
|
|
65
|
+
if (platform === 'darwin') {
|
|
66
|
+
command = `open "${url}"`;
|
|
67
|
+
}
|
|
68
|
+
else if (platform === 'win32') {
|
|
69
|
+
command = `start "" "${url}"`;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Linux - try various commands
|
|
73
|
+
const browsers = ['xdg-open', 'sensible-browser', 'x-www-browser', 'gnome-open'];
|
|
74
|
+
for (const browser of browsers) {
|
|
75
|
+
try {
|
|
76
|
+
execSync(`which ${browser}`, { stdio: 'ignore' });
|
|
77
|
+
command = `${browser} "${url}"`;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!command) {
|
|
85
|
+
console.log(`💡 Open your browser to: ${url}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
execSync(command, { stdio: 'ignore' });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
console.log(`💡 Open your browser to: ${url}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export async function startDashboard(options = {}) {
|
|
96
|
+
const config = loadConfig();
|
|
97
|
+
console.log(`
|
|
98
|
+
🦞 ============================================
|
|
99
|
+
SUPER MEMORY DASHBOARD
|
|
100
|
+
The Red Lobster Cartel
|
|
101
|
+
============================================
|
|
102
|
+
`);
|
|
103
|
+
if (!config) {
|
|
104
|
+
console.log('⚠️ Not initialized yet. The dashboard will show setup instructions.');
|
|
105
|
+
console.log(' Run: super-memory init --license=YOUR_KEY\n');
|
|
106
|
+
}
|
|
107
|
+
const dashboardDir = getDashboardDir();
|
|
108
|
+
const packageJsonPath = join(dashboardDir, 'package.json');
|
|
109
|
+
const nodeModulesPath = join(dashboardDir, 'node_modules');
|
|
110
|
+
// Check if dependencies are installed
|
|
111
|
+
if (!existsSync(nodeModulesPath)) {
|
|
112
|
+
console.log('📦 Installing dashboard dependencies...');
|
|
113
|
+
try {
|
|
114
|
+
execSync('npm install', {
|
|
115
|
+
cwd: dashboardDir,
|
|
116
|
+
stdio: 'inherit',
|
|
117
|
+
});
|
|
118
|
+
console.log('✅ Dependencies installed\n');
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.error('❌ Failed to install dependencies');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Find available port
|
|
126
|
+
const defaultPort = options.port || 8765;
|
|
127
|
+
const port = await findAvailablePort(defaultPort);
|
|
128
|
+
if (port !== defaultPort) {
|
|
129
|
+
console.log(`⚠️ Port ${defaultPort} is in use, using ${port} instead\n`);
|
|
130
|
+
}
|
|
131
|
+
// Start the server
|
|
132
|
+
console.log('🚀 Starting dashboard server...\n');
|
|
133
|
+
const serverPath = join(dashboardDir, 'server.js');
|
|
134
|
+
const server = spawn('node', [serverPath], {
|
|
135
|
+
cwd: dashboardDir,
|
|
136
|
+
env: {
|
|
137
|
+
...process.env,
|
|
138
|
+
SUPER_MEMORY_PORT: port.toString(),
|
|
139
|
+
},
|
|
140
|
+
stdio: 'inherit',
|
|
141
|
+
});
|
|
142
|
+
// Wait a bit for server to start
|
|
143
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
144
|
+
const url = `http://localhost:${port}`;
|
|
145
|
+
// Open browser
|
|
146
|
+
if (!options.noBrowser) {
|
|
147
|
+
console.log(`🌐 Opening browser to ${url}\n`);
|
|
148
|
+
openBrowser(url);
|
|
149
|
+
}
|
|
150
|
+
// Handle server exit
|
|
151
|
+
server.on('close', (code) => {
|
|
152
|
+
if (code !== 0) {
|
|
153
|
+
console.error(`\n❌ Dashboard server exited with code ${code}`);
|
|
154
|
+
process.exit(code || 1);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
// Handle SIGINT
|
|
158
|
+
process.on('SIGINT', () => {
|
|
159
|
+
console.log('\n\n👋 Shutting down dashboard...');
|
|
160
|
+
server.kill();
|
|
161
|
+
process.exit(0);
|
|
162
|
+
});
|
|
163
|
+
// Keep process alive
|
|
164
|
+
await new Promise(() => { });
|
|
165
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flush Command
|
|
3
|
+
* Saves critical context before session compaction
|
|
4
|
+
*/
|
|
5
|
+
import { loadConfig, getConvexUrl } from '../utils/config.js';
|
|
6
|
+
export async function cmdFlush(args) {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
if (!config) {
|
|
9
|
+
console.error('❌ Not initialized. Run: super-memory init --license=YOUR_KEY');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
// Get context from args or prompt
|
|
13
|
+
let context = args.find(arg => !arg.startsWith('--'));
|
|
14
|
+
let title = args.find(arg => arg.startsWith('--title='))?.split('=')[1];
|
|
15
|
+
if (!context) {
|
|
16
|
+
const readline = await import('readline');
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout
|
|
20
|
+
});
|
|
21
|
+
context = await new Promise((resolve) => {
|
|
22
|
+
rl.question('📝 Enter context to flush (critical info to save): ', (answer) => {
|
|
23
|
+
rl.close();
|
|
24
|
+
resolve(answer.trim());
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (!context) {
|
|
29
|
+
console.error('❌ No context provided');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
console.log('\n🚨 Flushing critical context...\n');
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch(`${getConvexUrl()}/api/mutation`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: { 'Content-Type': 'application/json' },
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
path: 'sync:flush',
|
|
39
|
+
args: {
|
|
40
|
+
licenseKey: config.licenseKey,
|
|
41
|
+
context,
|
|
42
|
+
title,
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new Error(`API error: ${response.status}`);
|
|
48
|
+
}
|
|
49
|
+
const result = await response.json();
|
|
50
|
+
if (result.status === 'error') {
|
|
51
|
+
throw new Error(result.errorMessage || 'Unknown error');
|
|
52
|
+
}
|
|
53
|
+
const data = result.value;
|
|
54
|
+
if (data.success) {
|
|
55
|
+
console.log('✅ Context flushed successfully!\n');
|
|
56
|
+
console.log(` Memory ID: ${data.memoryId}`);
|
|
57
|
+
console.log(` Title: ${title || 'Flushed Context'}`);
|
|
58
|
+
console.log('\n💡 This context is now safely stored in Layer 1 (Session)');
|
|
59
|
+
console.log(' and will be preserved even if your session context overflows.\n');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.error('❌ Failed to flush context');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error(`❌ Error: ${error.message}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index Update Command
|
|
3
|
+
* Creates progressive memory index (~70% token savings)
|
|
4
|
+
* Now includes AUTO-CURATE automatically!
|
|
5
|
+
*/
|
|
6
|
+
import { loadConfig, getConvexUrl } from '../utils/config.js';
|
|
7
|
+
import { cmdCurate } from './curate.js';
|
|
8
|
+
export async function cmdIndexUpdate(args = []) {
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
if (!config) {
|
|
11
|
+
console.error('❌ Not initialized. Run: super-memory init --license=YOUR_KEY');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const skipCurate = args.includes('--skip-curate');
|
|
15
|
+
console.log('\n📚 Updating memory index...\n');
|
|
16
|
+
try {
|
|
17
|
+
const response = await fetch(`${getConvexUrl()}/api/mutation`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { 'Content-Type': 'application/json' },
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
path: 'sync:indexUpdate',
|
|
22
|
+
args: { licenseKey: config.licenseKey },
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`API error: ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
const result = await response.json();
|
|
29
|
+
if (result.status === 'error') {
|
|
30
|
+
throw new Error(result.errorMessage || 'Unknown error');
|
|
31
|
+
}
|
|
32
|
+
const data = result.value;
|
|
33
|
+
if (data.success) {
|
|
34
|
+
console.log('✅ Index updated successfully!\n');
|
|
35
|
+
console.log(` Entries indexed: ${data.entriesAdded}`);
|
|
36
|
+
console.log(` Index size: ${data.indexSize.toLocaleString()} chars`);
|
|
37
|
+
console.log(` Estimated savings: ${data.estimatedSavings}`);
|
|
38
|
+
console.log('\n💡 The progressive index provides ~70% token savings');
|
|
39
|
+
console.log(' when searching and reviewing your memories.\n');
|
|
40
|
+
// AUTO-CURATE: Run automatically after index update
|
|
41
|
+
if (!skipCurate) {
|
|
42
|
+
console.log('────────────────────────────────────────');
|
|
43
|
+
console.log('🧠 Running AUTO-CURATE...\n');
|
|
44
|
+
await cmdCurate(['--silent']);
|
|
45
|
+
console.log('✅ Auto-curate completed! MEMORY.md updated.\n');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.error('❌ Failed to update index');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(`❌ Error: ${error.message}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintenance Command
|
|
3
|
+
* Weekly review with smart suggestions
|
|
4
|
+
*/
|
|
5
|
+
import { loadConfig, getConvexUrl } from '../utils/config.js';
|
|
6
|
+
export async function cmdMaintenance() {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
if (!config) {
|
|
9
|
+
console.error('❌ Not initialized. Run: super-memory init --license=YOUR_KEY');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
console.log('\n🔧 Running maintenance check...\n');
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(`${getConvexUrl()}/api/query`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
path: 'dashboard:getMaintenance',
|
|
19
|
+
args: { licenseKey: config.licenseKey },
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`API error: ${response.status}`);
|
|
24
|
+
}
|
|
25
|
+
const result = await response.json();
|
|
26
|
+
if (result.status === 'error') {
|
|
27
|
+
throw new Error(result.errorMessage || 'Unknown error');
|
|
28
|
+
}
|
|
29
|
+
const data = result.value;
|
|
30
|
+
if (data.success) {
|
|
31
|
+
console.log('📊 Memory Statistics');
|
|
32
|
+
console.log('===================');
|
|
33
|
+
console.log(`Total Memories: ${data.stats.totalMemories}`);
|
|
34
|
+
console.log(`Average per Day: ${data.stats.avgMemoriesPerDay}`);
|
|
35
|
+
console.log(`Oldest Memory: ${data.stats.oldestMemoryDays} days old`);
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log('Category Balance:');
|
|
38
|
+
console.log(` 🔴 Gotchas: ${data.stats.categoryBalance.gotcha}`);
|
|
39
|
+
console.log(` 🟡 Problem-Fix: ${data.stats.categoryBalance.problem}`);
|
|
40
|
+
console.log(` 🟤 Decisions: ${data.stats.categoryBalance.decision}`);
|
|
41
|
+
console.log(` 🟣 Discoveries: ${data.stats.categoryBalance.discovery}`);
|
|
42
|
+
console.log('');
|
|
43
|
+
if (data.suggestions.length === 0) {
|
|
44
|
+
console.log('✅ No maintenance suggestions - your memory is healthy!\n');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log('🔍 Suggestions');
|
|
48
|
+
console.log('===============');
|
|
49
|
+
for (const suggestion of data.suggestions) {
|
|
50
|
+
const priorityEmoji = suggestion.priority === 'high' ? '🔴' :
|
|
51
|
+
suggestion.priority === 'medium' ? '🟡' : '🟢';
|
|
52
|
+
console.log(`${priorityEmoji} ${suggestion.title}`);
|
|
53
|
+
console.log(` ${suggestion.description}`);
|
|
54
|
+
console.log(` Action: ${suggestion.action}`);
|
|
55
|
+
console.log('');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.error('❌ Failed to get maintenance suggestions');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(`❌ Error: ${error.message}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,16 @@
|
|
|
9
9
|
* super-memory search "query term"
|
|
10
10
|
* super-memory sync
|
|
11
11
|
* super-memory status
|
|
12
|
+
* super-memory dashboard [--port=8765] [--no-browser]
|
|
13
|
+
* super-memory curate [--days=7] [--dry-run] ← NEW!
|
|
12
14
|
*/
|
|
13
15
|
import { execSync } from 'child_process';
|
|
16
|
+
import { startDashboard } from './commands/dashboard.js';
|
|
17
|
+
import { cmdIndexUpdate } from './commands/indexUpdate.js';
|
|
18
|
+
import { cmdFlush } from './commands/flush.js';
|
|
19
|
+
import { cmdMaintenance } from './commands/maintenance.js';
|
|
20
|
+
import { cmdCategorize } from './commands/categorize.js';
|
|
21
|
+
import { cmdCurate } from './commands/curate.js';
|
|
14
22
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, appendFileSync } from 'fs';
|
|
15
23
|
import { homedir } from 'os';
|
|
16
24
|
import { join } from 'path';
|
|
@@ -193,6 +201,45 @@ async function cmdInit(args) {
|
|
|
193
201
|
|
|
194
202
|
---
|
|
195
203
|
|
|
204
|
+
*Powered by The Red Lobster Cartel 🦞*
|
|
205
|
+
`);
|
|
206
|
+
}
|
|
207
|
+
// Create MEMORY.md (Long-Term Memory) - Layer 3
|
|
208
|
+
const baseDir = getBaseDir();
|
|
209
|
+
const longTermPath = join(baseDir, 'MEMORY.md');
|
|
210
|
+
if (!existsSync(longTermPath)) {
|
|
211
|
+
writeFileSync(longTermPath, `# 🧠 Long-Term Memory
|
|
212
|
+
|
|
213
|
+
**Installed:** ${today}
|
|
214
|
+
**Plan:** ${validation.plan}
|
|
215
|
+
**System:** Super Memory 5-Layer Architecture
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 👤 User Identity
|
|
220
|
+
|
|
221
|
+
*Add your personal information, preferences, and context here.*
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 🎯 Current Projects
|
|
226
|
+
|
|
227
|
+
*Track your active projects and their status.*
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 🔴 Gotchas & Learnings
|
|
232
|
+
|
|
233
|
+
*Important lessons, pitfalls, and discoveries.*
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 📊 System Status
|
|
238
|
+
|
|
239
|
+
**Last Updated:** ${today}
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
196
243
|
*Powered by The Red Lobster Cartel 🦞*
|
|
197
244
|
`);
|
|
198
245
|
}
|
|
@@ -390,6 +437,23 @@ COMMANDS:
|
|
|
390
437
|
|
|
391
438
|
status Show status and stats
|
|
392
439
|
|
|
440
|
+
index-update Update progressive MEMORY_INDEX.md (Layer 4)
|
|
441
|
+
Also auto-curates to MEMORY.md
|
|
442
|
+
|
|
443
|
+
curate Auto-curate important entries to MEMORY.md (Layer 3)
|
|
444
|
+
Extracts gotchas, problems, decisions, discoveries
|
|
445
|
+
from recent daily logs automatically
|
|
446
|
+
|
|
447
|
+
flush <context> Save critical context before compaction
|
|
448
|
+
|
|
449
|
+
maintenance Run weekly review and get suggestions
|
|
450
|
+
|
|
451
|
+
categorize <id> Auto-categorize memory entry
|
|
452
|
+
|
|
453
|
+
dashboard Open web dashboard
|
|
454
|
+
--port=8765 Custom port
|
|
455
|
+
--no-browser Don't auto-open browser
|
|
456
|
+
|
|
393
457
|
help Show this help
|
|
394
458
|
|
|
395
459
|
EXAMPLES:
|
|
@@ -398,11 +462,22 @@ EXAMPLES:
|
|
|
398
462
|
super-memory search "cors error"
|
|
399
463
|
super-memory sync
|
|
400
464
|
super-memory status
|
|
465
|
+
super-memory dashboard
|
|
466
|
+
super-memory dashboard --port=3000 --no-browser
|
|
401
467
|
|
|
402
468
|
WEBSITE: https://theredlobstercartel.com/super-memory
|
|
403
469
|
SUPPORT: support@theredlobstercartel.com
|
|
404
470
|
`);
|
|
405
471
|
}
|
|
472
|
+
// COMMAND: dashboard
|
|
473
|
+
async function cmdDashboard(args) {
|
|
474
|
+
const portArg = args.find(arg => arg.startsWith('--port='))?.split('=')[1];
|
|
475
|
+
const noBrowser = args.includes('--no-browser');
|
|
476
|
+
await startDashboard({
|
|
477
|
+
port: portArg ? parseInt(portArg, 10) : undefined,
|
|
478
|
+
noBrowser,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
406
481
|
// Main
|
|
407
482
|
async function main() {
|
|
408
483
|
const args = process.argv.slice(2);
|
|
@@ -424,6 +499,24 @@ async function main() {
|
|
|
424
499
|
case 'status':
|
|
425
500
|
await cmdStatus(cmdArgs);
|
|
426
501
|
break;
|
|
502
|
+
case 'dashboard':
|
|
503
|
+
await cmdDashboard(cmdArgs);
|
|
504
|
+
break;
|
|
505
|
+
case 'index-update':
|
|
506
|
+
await cmdIndexUpdate(cmdArgs);
|
|
507
|
+
break;
|
|
508
|
+
case 'curate':
|
|
509
|
+
await cmdCurate(cmdArgs);
|
|
510
|
+
break;
|
|
511
|
+
case 'flush':
|
|
512
|
+
await cmdFlush(cmdArgs);
|
|
513
|
+
break;
|
|
514
|
+
case 'maintenance':
|
|
515
|
+
await cmdMaintenance();
|
|
516
|
+
break;
|
|
517
|
+
case 'categorize':
|
|
518
|
+
await cmdCategorize(cmdArgs);
|
|
519
|
+
break;
|
|
427
520
|
case 'help':
|
|
428
521
|
case '--help':
|
|
429
522
|
case '-h':
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config utilities
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
const CONVEX_URL = 'https://clear-lemming-473.convex.cloud';
|
|
8
|
+
export function getBaseDir() {
|
|
9
|
+
return join(homedir(), '.openclaw', 'workspace');
|
|
10
|
+
}
|
|
11
|
+
export function getMemoryDir() {
|
|
12
|
+
return join(getBaseDir(), 'memory');
|
|
13
|
+
}
|
|
14
|
+
export function getConfigDir() {
|
|
15
|
+
return join(getBaseDir(), '.super-memory');
|
|
16
|
+
}
|
|
17
|
+
export function getConfigPath() {
|
|
18
|
+
return join(getConfigDir(), 'config.json');
|
|
19
|
+
}
|
|
20
|
+
export function getConvexUrl() {
|
|
21
|
+
return CONVEX_URL;
|
|
22
|
+
}
|
|
23
|
+
export function loadConfig() {
|
|
24
|
+
const configPath = getConfigPath();
|
|
25
|
+
if (!existsSync(configPath)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function saveConfig(config) {
|
|
36
|
+
const configDir = getConfigDir();
|
|
37
|
+
if (!existsSync(configDir)) {
|
|
38
|
+
mkdirSync(configDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
|
|
41
|
+
}
|
|
42
|
+
export function isValidLicenseKey(key) {
|
|
43
|
+
return /^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(key);
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trlc/super-memory",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Super Memory CLI - AI-powered persistent memory by The Red Lobster Cartel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
|
+
"postinstall": "cd dashboard && npm install --silent || true",
|
|
13
|
+
"dashboard": "node dashboard/server.js",
|
|
12
14
|
"prepublishOnly": "npm run build",
|
|
13
15
|
"test": "node dist/index.js --help"
|
|
14
16
|
},
|