/** * v2 → v1 event mapper for the v2 event pump. * * v2 renamed/re-shaped several server events the v1 hooks depend on: * - the v2 stream carries neither `session.idle` nor busy/idle * `session.status`; lifecycle arrives as durable `session.execution.*` * events (live-verified on v2 hosts); * - `session.created` carries flat `{sessionID, parentID?}` instead of * v1's `properties.info` object; * - token/cache telemetry moved to `session.usage.updated` / * `session.step.ended` (v2 has no `message.updated`). * * Payload key: live v2 hosts deliver the event payload under `data` * (`{id, created, type, location?, durable?, metadata?, data}` — the * wire/plugin `OpenCodeEvent` shape, live-verified on v2 hosts); the * `properties` spelling is accepted as a legacy/test fallback. The v1 * consumers the synthesized shapes target all read `properties`, so every * synthesized event below writes `properties` regardless of the source key. * * `mapV2EventToV1` is additive synthesis only: the first element of the * returned array is ALWAYS the raw input event, unmodified (byte-identical * reference), so v2-native handlers (interview bridge) and any v1 handler * already tolerant of the v2 shape keep seeing it. Synthesized v1-shape * events are appended after it. * * Lifecycle note: v2 hosts publish durable * `session.execution.started/succeeded/failed/interrupted` events; the * stream carries neither `session.idle` nor busy/idle `session.status`. * The execution events are synthesized into the v1 lifecycle shapes below. * A terminal execution event synthesizes both a `session.status` idle and * a `session.idle`, so a consumer watching both must tolerate duplicate * idle delivery (the documented double-idle invariant). * * The synthesized shapes are pinned to what the v1 consumers actually read: * - `session.created` early registration (task-session-manager * event-router): `properties.info.{id,parentID,agent?}` — plugin * relevance is gated on `info.parentID` (child sessions only). * - `session.deleted` deletion cleanup (task-session-manager * rememberDeletedSession tombstone/teardown, cache-monitor session * eviction): `properties.info.id` AND `properties.sessionID` — the two * consumers read different spellings, so the synthesized event carries * both. Synthesized from v2's flat `{sessionID}` payload; no * `generation` is fabricated. * - `message.updated` telemetry (cache-monitor * parseCompletedAssistantMessage): `properties.info.{role:'assistant', * sessionID, id, time.completed, tokens.input, tokens.cache.read, * tokens.cache.write}`. * - `question.asked/replied/rejected` (companionManager, * task-session-manager input-wait tracker, orchestrator-wake): the v1 * QuestionV1 shapes `{id, sessionID, questions}` / * `{sessionID, requestID, answers}` / `{sessionID, requestID}`, * synthesized from the v2 Form flow (form.created/replied/cancelled). * Forms owned by the `"global"` sentinel session stay unsynthesized. * - `permission.asked` field mapping (same consumers): v1 names * `{id, sessionID, permission, patterns, metadata, always}` ← v2 * `{id, sessionID, action, resources, metadata?, save?}`. * `permission.replied` passes through raw — v2's shape already matches * the v1 event. */ /** * Map one v2 server event into zero or more v1-shape events. * * Returns `[rawEvent, ...synthesizedV1Shapes]` — the raw event is always * first and never mutated. Synthesis: * - `session.execution.*` → the v1 lifecycle * shapes: `started` → `session.status` `{status:{type:'busy'}}`; * `succeeded`/`interrupted` → `session.status` idle + `session.idle`; * `failed` → a v1 `session.error` (host error payload passed through * best-effort) followed by the same idle pair — error-before-idle * preserves the error-then-idle flow the task-session-manager * event-router expects (deferred inline errors are terminalized by the * following idle). Only the four known subtypes map — unknown * `session.execution.*` variants stay passthrough-only rather than * guessing a lifecycle meaning; * - child `session.created` (parentID present) → v1 early-registration * shape `{info: {id, parentID, title?, agent?}}`; * - `session.deleted` → v1 deletion-cleanup shape with the DUAL id * spelling (`properties.info.id` + `properties.sessionID`) the v1 * consumers read (cache-monitor keys on `info.id`, the event router on * either; no `generation` is fabricated so the router's * unproven-relaunch deletion fence keeps its strength); * - usage telemetry → v1 completed-assistant `message.updated`; * - `form.created/replied/cancelled` → v1 `question.asked/replied/ * rejected` (QuestionV1 shapes; "global"-owned forms skipped); * - `permission.asked` → v1 field names (permission ← action, patterns ← * resources). `permission.replied` needs no mapping (shapes match). * * `interviewBridge.handleEvent` keeps receiving the RAW v2 event (the * setup pump dispatches it before iterating this array). */ export declare function mapV2EventToV1(event: Record): Array>;