Rocko's round 2 candidate e09313aba4d155a1c5af7bfb227ec397e96c0d57444782cd0b48593102bcc684
(38 paths, base 23533625d), approved by Dewey in #1618 comment 28923 (queue rev 1757).
Packet: agents/rocko/work/queue-124/r2/.
- Schema 3g to 3h: packages/bus/src/migrations/3g-3h.sql adds an append-only
usage_records table; nothing earlier changes. usage_records is in timedTables.
- The transcript usage-source module reads token counts from Pi and Claude
Code session transcripts and follows no symlink.
- `mosaic usage` in the CLI and a read-only usage section in the Console's
Settings (one GET route; 400 on a query string).
Decision 123 go: Mos, mos-0737. Activation (3g to 3h) is a migrating run
with Jason present, in Mos's combined re-pin; landing changes nothing live.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
114 lines
5.4 KiB
JavaScript
114 lines
5.4 KiB
JavaScript
// REQ-LIMIT-4: hostile transcripts are a best reading, never proof of usage.
|
|
// Linux dirfds anchor every lookup; no caller-provided symlink is followed.
|
|
import { constants, openSync, closeSync, fstatSync, readSync, opendirSync } from 'node:fs';
|
|
import { isAbsolute } from 'node:path';
|
|
|
|
export const interfaceVersion = 1;
|
|
const MAX_BYTES = 8 * 1024 * 1024;
|
|
const MAX_LINE = 1024 * 1024;
|
|
const MAX_ENTRIES = 512;
|
|
const MAX_RECORDS = 20000;
|
|
const ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
const NAME = /^[A-Za-z0-9_.-]{1,240}$/;
|
|
const DIR = constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW;
|
|
const FILE = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
|
|
const refuse = code => { throw Object.assign(new Error(code), { code }); };
|
|
const at = (fd, name) => `/proc/self/fd/${fd}/${name}`;
|
|
|
|
function rootFd(root) {
|
|
if (typeof root !== 'string' || !isAbsolute(root) || root.split('/').includes('..')) refuse('transcript-path');
|
|
let fd = openSync('/', DIR);
|
|
try {
|
|
for (const part of root.split('/').filter(Boolean)) {
|
|
const next = openSync(at(fd, part), DIR);
|
|
closeSync(fd); fd = next;
|
|
}
|
|
return fd;
|
|
} catch (e) { closeSync(fd); throw e; }
|
|
}
|
|
function readFile(parent, name, budget) {
|
|
const fd = openSync(at(parent, name), FILE);
|
|
try {
|
|
const before = fstatSync(fd);
|
|
if (!before.isFile() || before.nlink !== 1) refuse('transcript-path');
|
|
if (before.size > MAX_BYTES - budget.bytes) refuse('transcript-size');
|
|
const parts = [];
|
|
let total = 0;
|
|
const buffer = Buffer.alloc(65536);
|
|
for (;;) {
|
|
const n = readSync(fd, buffer, 0, Math.min(buffer.length, MAX_BYTES - budget.bytes + 1), null);
|
|
if (!n) break;
|
|
total += n; budget.bytes += n;
|
|
if (budget.bytes > MAX_BYTES) refuse('transcript-size');
|
|
parts.push(Buffer.from(buffer.subarray(0, n)));
|
|
}
|
|
const after = fstatSync(fd);
|
|
if (before.size !== after.size || total !== after.size || before.mtimeMs !== after.mtimeMs ||
|
|
before.ctimeMs !== after.ctimeMs) refuse('transcript-changed');
|
|
return Buffer.concat(parts);
|
|
} finally { closeSync(fd); }
|
|
}
|
|
function counters(usage, harness) {
|
|
if (!usage || typeof usage !== 'object' || Array.isArray(usage)) refuse('transcript-usage');
|
|
const fields = harness === 'pi' ? ['input', 'output', 'cacheWrite', 'cacheRead'] :
|
|
['input_tokens', 'output_tokens', 'cache_creation_input_tokens', 'cache_read_input_tokens'];
|
|
const values = fields.map((key, i) => harness === 'claude-code' && i > 1 ? (usage[key] ?? 0) : usage[key]);
|
|
if (values.some(n => !Number.isSafeInteger(n) || n < 0)) refuse('transcript-usage');
|
|
return Object.fromEntries(['input', 'output', 'cacheWrite', 'cacheRead'].map((key, i) => [key, values[i]]));
|
|
}
|
|
function parse(bytes, harness, file, entries, budget) {
|
|
let text;
|
|
try { text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); }
|
|
catch { refuse('transcript-parse'); }
|
|
if (text && !text.endsWith('\n')) refuse('transcript-parse');
|
|
for (const line of text.split('\n')) {
|
|
if (!line.trim()) continue;
|
|
if (Buffer.byteLength(line) > MAX_LINE) refuse('transcript-line');
|
|
if (++budget.records > MAX_RECORDS) refuse('transcript-records');
|
|
let record;
|
|
try { record = JSON.parse(line); } catch { refuse('transcript-parse'); }
|
|
if (!record || typeof record !== 'object' || Array.isArray(record)) refuse('transcript-parse');
|
|
if (harness === 'pi' ? record.type !== 'message' || record.message?.role !== 'assistant' : record.type !== 'assistant') continue;
|
|
const id = harness === 'pi' ? record.id : record.message?.id;
|
|
if (typeof id !== 'string' || !ID.test(id)) refuse('transcript-usage');
|
|
const value = counters(record.message?.usage, harness);
|
|
const key = `${file}:${id}`;
|
|
if (Object.hasOwn(entries, key) && JSON.stringify(entries[key]) !== JSON.stringify(value)) refuse('transcript-usage');
|
|
entries[key] = value;
|
|
}
|
|
}
|
|
function walk(fd, harness, depth, prefix, entries, budget) {
|
|
const directory = opendirSync(`/proc/self/fd/${fd}`);
|
|
try {
|
|
let entry;
|
|
while ((entry = directory.readSync())) {
|
|
if (++budget.entries > MAX_ENTRIES) refuse('transcript-entries');
|
|
if (!NAME.test(entry.name) || entry.name === '.' || entry.name === '..') refuse('transcript-path');
|
|
if (harness === 'claude-code' && depth === 0) {
|
|
// Only the standard project directory / session.jsonl shape is admitted.
|
|
if (entry.isFile()) continue;
|
|
const child = openSync(at(fd, entry.name), DIR);
|
|
try { walk(child, harness, 1, entry.name + '/', entries, budget); }
|
|
finally { closeSync(child); }
|
|
} else if (entry.name.endsWith('.jsonl')) {
|
|
parse(readFile(fd, entry.name, budget), harness, prefix + entry.name, entries, budget);
|
|
}
|
|
}
|
|
} finally { directory.closeSync(); }
|
|
}
|
|
export async function readTurn({ harness, root }) {
|
|
let fd;
|
|
try {
|
|
if (!['pi', 'claude-code'].includes(harness)) refuse('transcript-harness');
|
|
fd = rootFd(root);
|
|
const entries = Object.create(null);
|
|
walk(fd, harness, 0, '', entries, { bytes: 0, entries: 0, records: 0 });
|
|
return { status: 'known', entries };
|
|
} catch (e) {
|
|
// A new run can have no transcript directory before its first turn.
|
|
if (e.code === 'ENOENT' && fd === undefined) return { status: 'known', entries: {} };
|
|
const code = typeof e.code === 'string' && e.code.startsWith('transcript-') ? e.code : 'transcript-path';
|
|
return { status: 'unknown', code };
|
|
} finally { if (fd !== undefined) closeSync(fd); }
|
|
}
|