export type LeaseLifecycleRunner = (args: string[]) => boolean; type LifecycleEvent = { reason?: unknown; toolName?: unknown; }; type LifecycleHandler = ( event: LifecycleEvent, context: Record, ) => unknown | Promise; export interface LeaseLifecyclePiApi { on(event: string, handler: LifecycleHandler): void; } const ROLLOVER_REASONS = new Set(['reload', 'new', 'resume', 'fork']); function eventReason(event: LifecycleEvent): string { return typeof event.reason === 'string' && event.reason.length > 0 ? event.reason : 'unknown'; } /** * Register redundant Pi compaction observers and same-PID generation rollover. * * A failed pre-compaction observer cancels compaction. A failed post-compaction * observer or generation rollover locally blocks later tools in addition to the * broker-backed all-tools gate. */ export function registerLeaseLifecycleHooks( pi: LeaseLifecyclePiApi, runRevoker: LeaseLifecycleRunner, ): void { let postCompactReason: string | null = null; let postCompactFailure = false; let rolloverFailure = false; pi.on('session_before_compact', async (event) => { const reason = eventReason(event); const revoked = runRevoker([ '--runtime', 'pi', '--reason', `pi-session-before-compact:${reason}`, ]); if (!revoked) return { cancel: true }; return undefined; }); pi.on('session_compact', async (event) => { postCompactReason = eventReason(event); }); pi.on('context', async () => { if (postCompactReason === null) return undefined; const reason = postCompactReason; const revoked = runRevoker([ '--runtime', 'pi', '--reason', `pi-context-after-compact:${reason}`, ]); if (revoked) { postCompactReason = null; postCompactFailure = false; } else { postCompactFailure = true; } return undefined; }); pi.on('session_start', async (event) => { const reason = eventReason(event); if (!ROLLOVER_REASONS.has(reason)) return undefined; const revoked = runRevoker([ '--runtime', 'pi', '--reason', `pi-session-start:${reason}`, '--bump-generation', ]); rolloverFailure = !revoked; return undefined; }); pi.on('tool_call', async () => { if (!postCompactFailure && !rolloverFailure) return undefined; return { block: true, reason: 'BLOCKED: Mosaic lease lifecycle revoke failed; runtime remains UNVERIFIED.', }; }); }