Files
PodTui/AGENTS.md
Michael Freno d7aec4e810 fix(memory): bound visualizer PCM cache and feed episode cache
The visualizer's PCM cache decoded the entire episode into RAM (22050 Hz
mono s16 ~160 MB/hr of audio) and held it until stop() — a 3-hour episode
pinned ~500 MB and long-form content hit 2.5 GB. The 4x decode also pulled
the whole remote file even when only minutes were listened to.

- audio-pcm-cache: sliding window around the playback position — the
  decode head caps at maxAheadSec (600s) ahead of the cursor, segments
  older than keepBehindSec (300s) are pruned, and the tail refills as
  playback advances. Steady state ~40 MB regardless of episode length;
  a backward seek past the window restarts a segment there (the existing
  seek-hole mechanism, no new failure mode).
- feed: cap the full-parse episode cache at 1000 episodes/feed so
  archive-heavy subscriptions can't pin their entire history in RAM;
  the visible list stays bounded by the user's cache preference and
  fetch-more keeps working within the ceiling.
- tests: pin the new head-cap and prune contracts (8/8 in
  audio-pcm-cache.test.ts; full suite 193 pass).

Also includes the in-flight cleanup/refactor pass (cover-art resolve
helper, page and comment tightening, ESLint config removal).
2026-08-12 21:02:19 -04:00

3.6 KiB

AGENTS.md

Build, Lint, and Test Commands

Development

  • bun start - Run the application
  • bun run dev - Run with hot reload (watch mode)

Build

  • bun run build - Build JavaScript bundle to dist/
  • bun run build:native - Build native libraries (requires scripts/build-cavacore.sh)

Testing

  • bun test - Run all tests
  • bun tests/cavacore-smoke.ts - Run specific native library smoke test

Linting

  • bun run lint - Run the TypeScript typecheck (bun tsc --noEmit)

Code Style Guidelines

TypeScript Configuration

  • Target: ESNext with bundler module resolution
  • Strict mode enabled
  • Path alias: @/* maps to src/*
  • JSX: Use @opentui/solid as import source

Import Organization

  1. Third-party framework imports (solid-js, @opentui/solid)
  2. Local utility imports
  3. Type imports (separate from value imports)

Naming Conventions

  • Components: PascalCase (e.g., FeedPage, Player)
  • Hooks: use* prefix (e.g., useAudio, useAppKeyboard)
  • Stores: create* factory + use* accessor (e.g., createFeedStore, useFeedStore)
  • Utilities: camelCase (e.g., parseRSSFeed, detectPlayers)
  • Constants: UPPER_SNAKE_CASE (e.g., MAX_EPISODES_REFRESH)
  • Types/interfaces: PascalCase (e.g., Feed, AudioBackend)
  • Enums: PascalCase (e.g., FeedVisibility)

Code Structure

  • Section Dividers: Use // ── Section Name ──────────────────────────────────────────────────────────── format
  • Helper Functions: Define before main logic
  • Factory Functions: Use for store creation (return object with state, computed, actions)
  • Singleton Pattern: Stores use module-level singleton with use* accessor

Type Definitions

  • Use interface for object shapes
  • Use type for unions, intersections, and complex types
  • Use enum for constant sets
  • Export types from src/types/ directory
  • Include JSDoc comments for complex types

Error Handling

  • Use try/catch for async operations
  • For expected failures, use .catch(() => {}) to suppress errors
  • Return default values on failure (e.g., return [] or return null)
  • Use catch blocks with descriptive comments for unexpected errors
  • For UI components, wrap in ErrorBoundary with clear fallback

Async Patterns

  • Fire-and-forget async operations: .catch(() => {}) with comment
  • Async store initialization: IIFE (async () => { ... })()
  • Promise handling: Use .catch() to return defaults

Comments

  • File headers: Brief description of file purpose
  • Complex functions: JSDoc-style comments explaining behavior
  • Section dividers: Visual separators for code organization
  • Inline comments: Explain non-obvious logic, especially async patterns

Code Formatting

  • 2-space indentation
  • No semicolons (Bun style)
  • Arrow functions with implicit return where appropriate
  • Object shorthand where possible
  • Prefer const over let

Reactivity (Solid.js)

  • Use createSignal for primitive state
  • Use createMemo for computed values
  • Use createEffect for side effects
  • Component functions return JSX
  • Store functions return plain objects with state, computed, and actions

Persistence

  • Async persistence operations fire-and-forget
  • Use .catch(() => {}) to suppress errors
  • Update state synchronously, persist asynchronously
  • Use setFeeds() pattern to update state and trigger save

Testing

  • Test files in tests/ directory
  • Use Bun's test framework
  • Include JSDoc comments explaining test purpose
  • Native library tests use bun:ffi for FFI calls