Spaces:
Running
Running
| import fs from 'node:fs'; | |
| import crypto from 'node:crypto'; | |
| import { SESSIONS_FILE, allocFolder } 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() { | |
| const tmp = `${SESSIONS_FILE}.tmp`; | |
| fs.writeFileSync(tmp, JSON.stringify(sessions, null, 2)); | |
| fs.renameSync(tmp, SESSIONS_FILE); | |
| } | |
| 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 : allocFolder(cleanName)), | |
| // 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. | |
| } | |