@trlc/super-memory 1.3.7 → 1.3.9
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/index.js +85 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import { homedir } from 'os';
|
|
|
22
22
|
import { join } from 'path';
|
|
23
23
|
import readline from 'readline';
|
|
24
24
|
const CONVEX_URL = 'https://clear-lemming-473.convex.cloud';
|
|
25
|
-
const VERSION = '1.3.
|
|
25
|
+
const VERSION = '1.3.9';
|
|
26
26
|
// Paths
|
|
27
27
|
const getBaseDir = () => join(homedir(), '.openclaw', 'workspace');
|
|
28
28
|
const getMemoryDir = () => join(getBaseDir(), 'memory');
|
|
@@ -497,6 +497,8 @@ async function cmdSync(args) {
|
|
|
497
497
|
console.log('📤 Checking for local memories to upload...');
|
|
498
498
|
const localMemories = getLocalMemoriesForSync();
|
|
499
499
|
let uploadedCount = 0;
|
|
500
|
+
// Track successful uploads to mark as synced (with offset adjustment)
|
|
501
|
+
const successfulUploads = [];
|
|
500
502
|
for (const mem of localMemories) {
|
|
501
503
|
try {
|
|
502
504
|
// Generate salt for this memory
|
|
@@ -527,12 +529,47 @@ async function cmdSync(args) {
|
|
|
527
529
|
const pushResult = await pushResponse.json();
|
|
528
530
|
if (pushResult.status === 'success') {
|
|
529
531
|
uploadedCount++;
|
|
532
|
+
// Track for marking as synced
|
|
533
|
+
successfulUploads.push({
|
|
534
|
+
filePath: mem.filePath,
|
|
535
|
+
lineIndex: mem.lineIndex
|
|
536
|
+
});
|
|
537
|
+
// Log audit
|
|
538
|
+
await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
539
|
+
method: 'POST',
|
|
540
|
+
headers: { 'Content-Type': 'application/json' },
|
|
541
|
+
body: JSON.stringify({
|
|
542
|
+
path: 'audit:logCli',
|
|
543
|
+
args: {
|
|
544
|
+
licenseKey: config.licenseKey,
|
|
545
|
+
action: 'memory_save',
|
|
546
|
+
details: `Saved ${mem.category}: ${mem.content.substring(0, 50)}...`,
|
|
547
|
+
ipAddress: 'cli',
|
|
548
|
+
deviceInfo: config.deviceId,
|
|
549
|
+
},
|
|
550
|
+
}),
|
|
551
|
+
});
|
|
530
552
|
}
|
|
531
553
|
}
|
|
532
554
|
catch (err) {
|
|
533
555
|
console.warn(`⚠️ Error uploading memory: ${err}`);
|
|
534
556
|
}
|
|
535
557
|
}
|
|
558
|
+
// Mark all successfully uploaded memories as synced
|
|
559
|
+
// Process by file to handle line index offsets correctly
|
|
560
|
+
const uploadsByFile = new Map();
|
|
561
|
+
for (const upload of successfulUploads) {
|
|
562
|
+
const existing = uploadsByFile.get(upload.filePath) || [];
|
|
563
|
+
existing.push(upload.lineIndex);
|
|
564
|
+
uploadsByFile.set(upload.filePath, existing);
|
|
565
|
+
}
|
|
566
|
+
for (const [filePath, lineIndexes] of uploadsByFile) {
|
|
567
|
+
// Sort in reverse order to prevent index shifting issues
|
|
568
|
+
const sortedIndexes = lineIndexes.sort((a, b) => b - a);
|
|
569
|
+
for (const lineIndex of sortedIndexes) {
|
|
570
|
+
markMemoryAsSynced(filePath, lineIndex);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
536
573
|
if (uploadedCount > 0) {
|
|
537
574
|
console.log(`✅ Uploaded ${uploadedCount} memories to cloud\n`);
|
|
538
575
|
}
|
|
@@ -598,6 +635,21 @@ async function cmdSync(args) {
|
|
|
598
635
|
console.log(` Uploaded: ${uploadedCount} memories`);
|
|
599
636
|
console.log(` Downloaded: ${syncedCount} memories`);
|
|
600
637
|
console.log(` Last sync: ${new Date().toLocaleString()}\n`);
|
|
638
|
+
// Log sync audit
|
|
639
|
+
await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
640
|
+
method: 'POST',
|
|
641
|
+
headers: { 'Content-Type': 'application/json' },
|
|
642
|
+
body: JSON.stringify({
|
|
643
|
+
path: 'audit:logCli',
|
|
644
|
+
args: {
|
|
645
|
+
licenseKey: config.licenseKey,
|
|
646
|
+
action: 'sync_push',
|
|
647
|
+
details: `Sync: ${uploadedCount} up, ${syncedCount} down`,
|
|
648
|
+
ipAddress: 'cli',
|
|
649
|
+
deviceInfo: config.deviceId,
|
|
650
|
+
},
|
|
651
|
+
}),
|
|
652
|
+
});
|
|
601
653
|
}
|
|
602
654
|
catch (error) {
|
|
603
655
|
console.error(`❌ Sync failed: ${error.message}\n`);
|
|
@@ -701,6 +753,7 @@ function getLocalStats() {
|
|
|
701
753
|
return stats;
|
|
702
754
|
}
|
|
703
755
|
// Helper: Get local memories for sync (push to cloud)
|
|
756
|
+
// Now tracks file/line and ignores already synced memories
|
|
704
757
|
function getLocalMemoriesForSync() {
|
|
705
758
|
const memories = [];
|
|
706
759
|
const memoryDir = getMemoryDir();
|
|
@@ -711,9 +764,16 @@ function getLocalMemoriesForSync() {
|
|
|
711
764
|
const filePath = join(memoryDir, file);
|
|
712
765
|
const content = readFileSync(filePath, 'utf-8');
|
|
713
766
|
const lines = content.split('\n');
|
|
714
|
-
for (
|
|
767
|
+
for (let i = 0; i < lines.length; i++) {
|
|
768
|
+
const line = lines[i];
|
|
715
769
|
const emojiMatch = line.match(/^(🔴|🟡|🟤|🟣)\s*\[?(GOTCHA|PROBLEM|DECISION|DISCOVERY)\]?\s*(.+)$/i);
|
|
716
770
|
if (emojiMatch) {
|
|
771
|
+
// Check if next line is a sync marker
|
|
772
|
+
const nextLine = lines[i + 1] || '';
|
|
773
|
+
if (nextLine.trim().startsWith('<!-- synced:')) {
|
|
774
|
+
// Already synced, skip this memory
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
717
777
|
const emoji = emojiMatch[1];
|
|
718
778
|
const categoryMap = {
|
|
719
779
|
'🔴': 'gotcha',
|
|
@@ -722,16 +782,37 @@ function getLocalMemoriesForSync() {
|
|
|
722
782
|
'🟣': 'discovery',
|
|
723
783
|
};
|
|
724
784
|
const category = categoryMap[emoji] || 'discovery';
|
|
725
|
-
const
|
|
785
|
+
const memContent = emojiMatch[3].trim();
|
|
726
786
|
// Extract timestamp from filename (YYYY-MM-DD.md)
|
|
727
787
|
const dateStr = file.replace('.md', '');
|
|
728
788
|
const timestamp = new Date(dateStr).getTime() || Date.now();
|
|
729
|
-
memories.push({
|
|
789
|
+
memories.push({
|
|
790
|
+
content: memContent,
|
|
791
|
+
category,
|
|
792
|
+
timestamp,
|
|
793
|
+
filePath,
|
|
794
|
+
lineIndex: i
|
|
795
|
+
});
|
|
730
796
|
}
|
|
731
797
|
}
|
|
732
798
|
}
|
|
733
799
|
return memories;
|
|
734
800
|
}
|
|
801
|
+
// Helper: Mark a memory as synced by adding marker after the line
|
|
802
|
+
function markMemoryAsSynced(filePath, lineIndex) {
|
|
803
|
+
try {
|
|
804
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
805
|
+
const lines = content.split('\n');
|
|
806
|
+
// Create sync marker with ISO timestamp
|
|
807
|
+
const syncMarker = `<!-- synced: ${new Date().toISOString()} -->`;
|
|
808
|
+
// Insert marker after the memory line
|
|
809
|
+
lines.splice(lineIndex + 1, 0, syncMarker);
|
|
810
|
+
writeFileSync(filePath, lines.join('\n'));
|
|
811
|
+
}
|
|
812
|
+
catch (err) {
|
|
813
|
+
console.warn(`⚠️ Failed to mark memory as synced: ${err}`);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
735
816
|
// COMMAND: help
|
|
736
817
|
function cmdHelp() {
|
|
737
818
|
console.log(`
|