import type { BusEvent } from './types.js'; export interface RoleStats { messagesSent: number; toolsAllowed: number; toolsDenied: number; tokens: number; /** Input + output only — the basis `budget_tokens` is enforced on by * default (policy.ts budgetedUsage). A usage event without the ADR-O001 * breakdown counts entirely here. `tokens - uncachedTokens` is cache. */ uncachedTokens: number; /** Sum of the USD costs the runtime reported; null when no usage event * carried one (the runtime reports no cost — unknown, never $0). */ costUsd: number | null; /** false when any of the role's usage events carried no cost: `costUsd` is * then a lower bound (or null when none did). */ costComplete: boolean; crashed: boolean; } export interface RunSummary { org: string; run: string; startedAt: number | null; endedAt: number | null; durationMs: number | null; events: number; messages: number; xorgMessages: number; assets: string[]; crashes: string[]; /** Roles terminated by our own stop signal (exit 143), not real crashes. */ cutShort: string[]; /** #302: only ever set from a status event with reason 'org-complete' — * i.e. only when a boss's org_complete call was actually ALLOWED (a * refusal never emits that event). `status`/`summary` are the boss's own * claim. */ outcome: { status: string; summary: string; by: string; } | null; /** #302: recorded TOP-LEVEL, a sibling of `outcome` rather than nested * inside it — deliberately, per review: `outcome` is null on every * non-org_complete stop path (idle watchdog, manual stop, a scheduled * deadline, ...), the same way `crashes`/`cutShort` are top-level so they * survive a stop that never produces an `outcome`. Only ever set alongside * a genuine `outcome: 'partial'` (the only shape `blocker` accompanies — * `checkCompletion` never lets a bare/invalid blocker through), so in * practice it appears exactly when `outcome` does; the point is that a * renderer must not have to reach INTO `outcome` to find it, and a future * path that wants to record an attempted-but-refused blocker claim can * populate this independently of whether `outcome` ever gets set. */ blocker?: string; blockerDetail?: string; /** #302 truth gate: how the run actually ended, from the 'org-stopped' * event `finishStop` always emits — the UNIVERSAL choke point every stop * path funnels through (`stopOrg` → `finishStop`; `stopAll` fans out to * `stopOrg`), so this is set correctly regardless of which of the many * call sites triggered the stop: 'org-complete' for a boss's own, * gate-checked call; 'idle-stop' | 'failed-start' | 'scheduled-deadline' | * 'boss-restart' | 'boss-restart-exhausted' for an automated path that * ends the run without boss consent; undefined for a bare manual * `org stop`/shutdown. (A process-level crash is recorded separately, in * runtime.json only, by `persistCrashStateAll` — it never reaches this * event at all, since the process has no time left for a graceful stop. * KNOWN, REASONED GAP — an 11th path: `org mark-complete` (org.ts) also * writes `closedBy: 'mark-complete'` directly to runtime.json, with a * bare writeFileSync, and only runs once the daemon's pid is already * gone. It never touches the bus or calls stopOrg/finishStop, so this * RunSummary field — and `runnableTasksAtStop` — are simply absent for * that run: there is no history.jsonl entry for it at all, since a * SIGKILLed daemon never ran finishStop's history-append either. This is * arguably correct (there is no stop to record if it never ran), but the * absence is deliberate, not an oversight — a renderer must not assume * every `closedBy` on runtime.json came from this truth gate.) * Renderers MUST consult this before ever describing a run as * "completed" — outcome alone is not enough, since a run that never * called org_complete has a null outcome regardless of why it stopped. */ closedBy?: string; /** #302: `org_tasks` entries still non-terminal at the moment this run * stopped — 0 for a DAG-less run or one that finished every task. */ runnableTasksAtStop: number; roles: Record; totalTokens: number; /** Sum of the reported USD costs; null when no role reported any. */ totalCostUsd: number | null; /** false when any usage event carried no cost: `totalCostUsd` is then a * lower bound (or null when none did). */ costComplete: boolean; } /** Aggregate one run's bus events into a summary. */ export declare function summarizeRun(events: BusEvent[]): RunSummary; /** #302 truth gate: the one-word-ish outcome label a renderer may print for a * run, honest about how it actually ended. A run with a genuine outcome (an * ALLOWED org_complete call) reports that claim's status. Otherwise, a real * crash wins (unchanged from before this item); otherwise an automated stop * path's own recorded cause is reported, with the runnable-task count if any * work was left outstanding — NEVER a plain "completed" for those, which is * the exact misreading #302 exists to close (an idle-stopped run with a full * backlog previously rendered identically to one whose boss finished * cleanly). Only a bare manual stop with no crash and no automated cause * falls back to "completed", same as before this item. */ export declare function describeRunOutcome(s: RunSummary): string; /** run directories for an org, newest first (by name — run-YYYYMMDDHHMMSS-xxxx sorts naturally). */ export declare function listRunDirs(cwd: string, org: string): string[]; export declare function readRunEvents(cwd: string, org: string, run: string): BusEvent[]; /** history.jsonl — one RunSummary line per completed run, appended by the daemon at stopOrg. */ export declare function historyFile(cwd: string, org: string): string; export declare function readHistory(cwd: string, org: string): RunSummary[]; /** `HH:MM:SSZ` */ export declare function utcTime(ts: number): string; /** `YYYY-MM-DD HH:MMZ` */ export declare function utcDateMinute(ts: number): string; /** One bus event as a compact human-readable log line. */ export declare function formatEvent(e: BusEvent): string; //# sourceMappingURL=reporting.d.ts.map