15-runtime-adapter-type-safety.md 3.1 KB

Runtime adapter type safety

Reduce unsafe casts at browser and third-party integration boundaries.


Summary

Several integration points rely on as any or unknown as casts (terminal internals, speech recognition, add-on internals, generic trigger props). This spec introduces typed adapters and narrow interfaces to improve maintainability and make type errors actionable.


Goals

  • Remove or significantly reduce unsafe casts in scoped files.
  • Introduce explicit adapter interfaces around unstable third-party APIs.
  • Preserve behavior with no UX changes.
  • Improve maintainability of terminal and speech integrations.

Non-goals

  • No server health dedupe work (owned by spec 14).
  • No large architectural changes to terminal or speech subsystems.
  • No changes to business logic semantics.

Parallel ownership (important)

This workstream owns:

  • packages/app/src/components/terminal.tsx
  • packages/app/src/utils/speech.ts
  • packages/app/src/addons/serialize.ts
  • packages/app/src/components/dialog-select-model.tsx
  • New utility files under packages/app/src/utils/** related to adapter typing

This workstream must not edit:

  • components/dialog-select-server.tsx, components/status-popover.tsx, context/server.tsx (spec 14)
  • components/prompt-input.tsx (spec 11)

Current state

  • Explicit as any appears in serialize.ts and speech.ts.
  • Multiple unknown as casts in terminal.tsx for option/disposable access.
  • Generic trigger props in dialog-select-model.tsx use as any spread.

Proposed approach

  1. Add narrow adapter types for third-party internals:
  • terminal option setter/disposable handles
  • speech recognition constructor on window
  • serialize addon internal terminal buffer access
  1. Introduce tiny helper guards/utilities:
  • isDisposable(value): value is { dispose(): void }
  • hasSetOption(value): value is { setOption(...): void }
  1. Replace broad casts with adapter functions and runtime checks.

Phased steps

  1. Refactor terminal helpers (setOption, disposal cleanups) to typed guards.
  2. Refactor speech recognition window access to typed constructor lookup.
  3. Replace serialize.ts as any internals with explicit local interface.
  4. Remove dialog-select-model.tsx as any trigger props cast via stricter generic typing.

Acceptance criteria

  • No as any remains in the scoped files (or document unavoidable cases inline).
  • unknown as usage in scoped files is minimized and justified.
  • Typecheck passes with no new suppression comments.
  • Runtime behavior remains unchanged.

Validation plan

  • Typecheck: bun run typecheck (from packages/app).
  • Targeted e2e checks:
    • e2e/terminal/terminal.spec.ts
    • e2e/models/model-picker.spec.ts
  • Manual checks:
    • terminal open/connect/resize/cleanup
    • speech start/stop and interim/final behavior

Handoff notes

  • Prefer small typed wrapper functions over inline complex narrowing.
  • Keep adapter names explicit and local to their integration point.
  • If a cast cannot be removed safely, add a short comment describing why.