154 lines
3.7 KiB
JavaScript
154 lines
3.7 KiB
JavaScript
/**
|
|
* JSONL session store under BRIDGE_SWARM_STORAGE/agent/sessions/.
|
|
*/
|
|
|
|
const path = require('bare-path');
|
|
const fs = require('bare-fs');
|
|
const { ensureAgentRoot, ensureDir, sanitizeId } = require('../capabilities/paths.js');
|
|
|
|
function sessionsRoot() {
|
|
return ensureDir(path.join(ensureAgentRoot(), 'sessions'));
|
|
}
|
|
|
|
function sessionDir(id) {
|
|
return ensureDir(path.join(sessionsRoot(), sanitizeId(id)));
|
|
}
|
|
|
|
function readJsonl(file) {
|
|
try {
|
|
const raw = fs.readFileSync(file, 'utf8');
|
|
return raw
|
|
.split('\n')
|
|
.map((l) => l.trim())
|
|
.filter(Boolean)
|
|
.map((l) => {
|
|
try {
|
|
return JSON.parse(l);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
})
|
|
.filter(Boolean);
|
|
} catch (_) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function appendJsonl(file, obj) {
|
|
fs.appendFileSync(file, JSON.stringify(obj) + '\n');
|
|
}
|
|
|
|
function makeId() {
|
|
return 'sess_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 10);
|
|
}
|
|
|
|
function create(meta) {
|
|
const id = meta.sessionId || makeId();
|
|
const dir = sessionDir(id);
|
|
const summary = {
|
|
id,
|
|
origin: meta.origin || '',
|
|
cwd: meta.cwd || '',
|
|
model: meta.model || '',
|
|
title: meta.title || 'New session',
|
|
hostWorkspace: meta.hostWorkspace !== false,
|
|
workspace: meta.workspace || meta.cwd || '',
|
|
builtinTools: meta.builtinTools,
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
plan: [],
|
|
planMode: meta.planMode || { state: 'inactive', planPath: 'plan.md', reminderCount: 0 },
|
|
goal: meta.goal || null,
|
|
};
|
|
fs.writeFileSync(path.join(dir, 'summary.json'), JSON.stringify(summary, null, 2));
|
|
fs.writeFileSync(path.join(dir, 'chat_history.jsonl'), '');
|
|
return summary;
|
|
}
|
|
|
|
function load(id) {
|
|
const dir = sessionDir(id);
|
|
let summary;
|
|
try {
|
|
summary = JSON.parse(fs.readFileSync(path.join(dir, 'summary.json'), 'utf8'));
|
|
} catch (_) {
|
|
throw new Error('session not found: ' + id);
|
|
}
|
|
summary.history = readJsonl(path.join(dir, 'chat_history.jsonl'));
|
|
summary.updates = readJsonl(path.join(dir, 'updates.jsonl'));
|
|
return summary;
|
|
}
|
|
|
|
function saveSummary(summary) {
|
|
summary.updatedAt = Date.now();
|
|
const copy = Object.assign({}, summary);
|
|
delete copy.history;
|
|
delete copy.updates;
|
|
fs.writeFileSync(path.join(sessionDir(summary.id), 'summary.json'), JSON.stringify(copy, null, 2));
|
|
}
|
|
|
|
function appendHistory(id, msg) {
|
|
appendJsonl(path.join(sessionDir(id), 'chat_history.jsonl'), Object.assign({ ts: Date.now() }, msg));
|
|
}
|
|
|
|
function appendUpdate(id, update) {
|
|
appendJsonl(path.join(sessionDir(id), 'updates.jsonl'), Object.assign({ ts: Date.now() }, update));
|
|
}
|
|
|
|
function replaceHistory(id, history) {
|
|
const file = path.join(sessionDir(id), 'chat_history.jsonl');
|
|
const body = (history || []).map((m) => JSON.stringify(m)).join('\n');
|
|
fs.writeFileSync(file, body ? body + '\n' : '');
|
|
}
|
|
|
|
function planFile(id) {
|
|
return path.join(sessionDir(id), 'plan.md');
|
|
}
|
|
|
|
function readPlan(id) {
|
|
try {
|
|
return fs.readFileSync(planFile(id), 'utf8');
|
|
} catch (_) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function writePlan(id, text) {
|
|
const file = planFile(id);
|
|
fs.writeFileSync(file, String(text != null ? text : ''));
|
|
return file;
|
|
}
|
|
|
|
function list() {
|
|
const root = sessionsRoot();
|
|
let names = [];
|
|
try {
|
|
names = fs.readdirSync(root);
|
|
} catch (_) {
|
|
return [];
|
|
}
|
|
const out = [];
|
|
for (const name of names) {
|
|
try {
|
|
const summary = JSON.parse(fs.readFileSync(path.join(root, name, 'summary.json'), 'utf8'));
|
|
out.push(summary);
|
|
} catch (_) {}
|
|
}
|
|
out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
|
return out;
|
|
}
|
|
|
|
module.exports = {
|
|
create,
|
|
load,
|
|
saveSummary,
|
|
appendHistory,
|
|
appendUpdate,
|
|
replaceHistory,
|
|
sessionDir,
|
|
planFile,
|
|
readPlan,
|
|
writePlan,
|
|
list,
|
|
makeId,
|
|
};
|