Architecture

Rewrite logic (wispr_pro.py)

response body ── contains marker key "total_trial_days"? ──no──→ pass through
      │ yes
      ▼
parses as a JSON object? ──no──→ pass through
      │ yes
      ▼
patch fields: status, plan, credits, is_subscribed, trial days, daysLeft
      │
      ▼
Content-Encoding removed, Content-Length fixed, body replaced

Everything else — other hosts, endpoints, non-JSON payloads — is untouched.

Config merge chain

defaults ──> config.toml [rewrite] ──> CLI flags
  • toml days_left maps to the API field daysLeft (camelCase).
  • load_patch() is called by the addon at request time (in-process), so config edits apply on the next response without restarting the proxy.

Plan & status enums (from the app's own enums)

  • Plans: FLOW_BASIC, FLOW_PRO_MONTHLY, FLOW_PRO_YEARLY, student/team/business variants.
  • Statuses: active, trialing, canceled, none, past_due, …

Runtime model

  • Foreground only. start runs mitmproxy in-process (DumpMaster + asyncio) and blocks — no child processes. This is deliberate: a spawned child of a PyInstaller onefile binary loses its extraction directory when the parent exits (base_library.zip FileNotFoundError crash — the previous design bug).
  • Background via nohup … &; stop/status read proxy.pid.

Build pipeline

wispr_pro.py
   │  PyInstaller --onefile --collect-all mitmproxy
   ▼
dist/wispr-pro   (single Mach-O, arm64 / universal2)
   │  build_app.py assembles bundle + codesign
   ▼
dist/Wispr Proxyflow.app
   │  GitHub Action: hdiutil create (UDZO)
   ▼
dist/Wispr-Pro-<version>.dmg