echonodesync
Version:
Autonomous, pluggable, secure memory bridge for agent/human/ritual ecosystems (DreamWeaver, EchoThreads, etc.)
95 lines (87 loc) • 3 kB
JavaScript
// 🧠🌸 EchoNodeSync: getMemory implementation (HTTP backend only)
// Retrieves a memory value for a given key from the /api/memory HTTP backend.
// Caches successful GETs as .mia/<key>.json for efficiency.
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');
const os = require('os');
function stripQuotes(str) {
if (!str) return str;
return str.replace(/^['"]+|['"]+$/g, '').trim();
}
function resolveApiUrl() {
if (process.env.ECHONODESYNC_API_URL) return stripQuotes(process.env.ECHONODESYNC_API_URL);
const envPaths = [
path.resolve(process.cwd(), '.env'),
path.resolve(os.homedir(), '.env')
];
for (const envPath of envPaths) {
if (fs.existsSync(envPath)) {
const lines = fs.readFileSync(envPath, 'utf8').split(/\r?\n/);
for (const line of lines) {
const match = line.match(/^\s*ECHONODESYNC_API_URL\s*=\s*(.+)\s*$/);
if (match) return stripQuotes(match[1]);
}
}
}
return 'http://localhost:3000/api/memory';
}
function resolveSecret() {
if (process.env.ECHONODESYNC_SECRET) return stripQuotes(process.env.ECHONODESYNC_SECRET);
const envPaths = [
path.resolve(process.cwd(), '.env'),
path.resolve(os.homedir(), '.env')
];
for (const envPath of envPaths) {
if (fs.existsSync(envPath)) {
const lines = fs.readFileSync(envPath, 'utf8').split(/\r?\n/);
for (const line of lines) {
const match = line.match(/^\s*ECHONODESYNC_SECRET\s*=\s*(.+)\s*$/);
if (match) return stripQuotes(match[1]);
}
}
}
return null;
}
const BASE_URL = resolveApiUrl().replace(/\/+$/, ''); // Remove trailing slashes
const SECRET = resolveSecret();
const CACHE_DIR = path.join(__dirname, '../.mia');
async function getMemory(key) {
// Compose URL as per OpenAPI: /api/memory?key=KEY
const url = `${BASE_URL}?key=${encodeURIComponent(key)}`;
try {
const headers = {};
if (SECRET) headers['Authorization'] = `Bearer ${SECRET}`;
const res = await fetch(url, { headers });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
// Cache result as .mia/<key>.json
if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR);
fs.writeFileSync(path.join(CACHE_DIR, `${key}.json`), JSON.stringify(data, null, 2));
console.log(data.value);
return data.value;
} catch (err) {
console.error(`Failed to fetch memory for key '${key}':`, err.message);
process.exit(1);
}
}
if (require.main === module) {
let key;
const argv = process.argv.slice(2);
if (argv.includes('--key')) {
const keyIdx = argv.indexOf('--key');
key = argv[keyIdx + 1];
if (!key) {
console.error('Usage: get-memory --key <key>');
process.exit(1);
}
} else if (argv.length === 1) {
key = argv[0];
} else {
console.error('Usage: get-memory <key> | get-memory --key <key>');
process.exit(1);
}
getMemory(key);
}
module.exports = getMemory;