Spaces:
Sleeping
Sleeping
File size: 2,747 Bytes
5b5da0e cae0460 5b5da0e ece21ed 5b5da0e fd0a8b6 5b5da0e fd0a8b6 5b5da0e fd0a8b6 5b5da0e cae0460 5b5da0e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | import fs from 'node:fs';
import crypto from 'node:crypto';
import { SESSIONS_FILE } from './config.js';
let sessions = [];
function load() {
try {
sessions = JSON.parse(fs.readFileSync(SESSIONS_FILE, 'utf8'));
if (!Array.isArray(sessions)) sessions = [];
} catch {
sessions = [];
}
}
function persist() {
// A FUSE write hiccup must not throw out of a timer/handler and crash us.
try {
const tmp = `${SESSIONS_FILE}.tmp`;
fs.writeFileSync(tmp, JSON.stringify(sessions, null, 2));
fs.renameSync(tmp, SESSIONS_FILE);
} catch (e) { console.error('[sessions.persist]', e && e.message); }
}
function slugify(name) {
return (
name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 32) || 'session'
);
}
export function init() {
load();
let changed = false;
for (const s of sessions) {
if (!s.sessionUuid) { s.sessionUuid = crypto.randomUUID(); changed = true; }
}
if (changed) persist();
// NOTE: `path` migration from the old folder/group-folder model happens in
// index.js (it needs the groups store).
}
export function list() {
return sessions.slice();
}
export function get(id) {
return sessions.find((s) => s.id === id) || null;
}
export function create({ name, cli, path }) {
const cleanName = (name || '').trim() || 'session';
const id = `${slugify(cleanName)}-${crypto.randomBytes(3).toString('hex')}`;
// `path` is the workspace-relative folder the agent runs in, chosen at
// creation (or defaulted by the caller). It is a plain recorded value — the
// display name can change freely without touching disk, and nothing tracks
// the folder afterwards (deleted/moved folders are simply re-created empty on
// next start). Files agents may use null = browse the whole workspace root.
const session = {
id,
name: cleanName,
cli,
path: path ?? (cli === 'files' ? null : ''),
// Stable per-session conversation id. Lets agents that share a folder (a
// group) each resume their OWN conversation instead of all latching onto
// the most-recent one in that directory.
sessionUuid: crypto.randomUUID(),
createdAt: new Date().toISOString(),
everStarted: false,
};
sessions.push(session);
persist();
return session;
}
export function update(id, patch) {
const s = get(id);
if (!s) return null;
Object.assign(s, patch);
persist();
return s;
}
export function remove(id) {
const before = sessions.length;
sessions = sessions.filter((s) => s.id !== id);
if (sessions.length !== before) persist();
// NOTE: the working directory under DATA_DIR/workspaces/<id> is intentionally
// left on disk so a delete never destroys the user's files.
}
|