blob: 7cf8f79b0c094cfab197046f96114b7bb616fcfa [file]
import {
assertShellRunIdentifier,
assertShellRunPatch,
assertShellRunSessionId,
nextShellRunRecord,
normalizeShellRunRecord,
shellRunNotFoundError,
type ShellRunPatch,
type ShellRunRecord,
type ShellRunStore,
} from '@maka/core';
/**
* Task-lifetime ShellRun store for headless benchmark cells.
*
* A managed shell session only means anything while the process that owns it is
* alive, and a benchmark cell owns its processes for exactly one task attempt:
* there is no resume, no second reader, and no cross-process recovery to
* support. So this store keeps the records in memory instead of taking a
* headless storage-root lease it would never read back.
*
* The invariants are NOT re-implemented here — every rule the SQLite store
* enforces comes from the shared @maka/core helpers, so ShellRunProcessManager
* observes one state machine regardless of which store it was handed.
*/
export function createTaskShellRunStore(): ShellRunStore {
const runs = new Map<string, ShellRunRecord>();
const key = (sessionId: string, shellRunId: string) => `${sessionId}:${shellRunId}`;
const read = (sessionId: string, shellRunId: string): ShellRunRecord => {
const record = runs.get(key(sessionId, shellRunId));
if (!record) throw shellRunNotFoundError(shellRunId);
return record;
};
return {
async createShellRun(record) {
assertShellRunSessionId(record.sessionId);
assertShellRunIdentifier(record.shellRunId);
const normalized = normalizeShellRunRecord(record, record.sessionId, record.shellRunId);
const recordKey = key(normalized.sessionId, normalized.shellRunId);
if (runs.has(recordKey)) {
throw new Error(`ShellRun already exists: ${normalized.shellRunId}`);
}
runs.set(recordKey, normalized);
return normalized;
},
async updateShellRun(sessionId: string, shellRunId: string, patch: ShellRunPatch) {
assertShellRunSessionId(sessionId);
assertShellRunIdentifier(shellRunId);
assertShellRunPatch(patch);
const current = read(sessionId, shellRunId);
const next = nextShellRunRecord(current, patch);
if (next !== current) runs.set(key(sessionId, shellRunId), next);
return next;
},
async readShellRun(sessionId: string, shellRunId: string) {
assertShellRunSessionId(sessionId);
assertShellRunIdentifier(shellRunId);
return read(sessionId, shellRunId);
},
async listSessionShellRuns(sessionId: string) {
assertShellRunSessionId(sessionId);
return [...runs.values()]
.filter((record) => record.sessionId === sessionId)
.sort((left, right) =>
left.startedAt === right.startedAt
? left.shellRunId.localeCompare(right.shellRunId)
: left.startedAt - right.startedAt,
);
},
};
}