rigplane 2.7.2__tar.gz → 2.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1284) hide show
  1. {rigplane-2.7.2 → rigplane-2.8.0}/PKG-INFO +1 -1
  2. {rigplane-2.7.2 → rigplane-2.8.0}/docs/CHANGELOG.md +63 -1
  3. {rigplane-2.7.2 → rigplane-2.8.0}/docs/PROJECT.md +1 -1
  4. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/web.md +22 -0
  5. {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/validation-matrix-v1.md +7 -6
  6. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/audio-recipes.md +21 -3
  7. rigplane-2.8.0/hatch_build.py +68 -0
  8. {rigplane-2.7.2 → rigplane-2.8.0}/pyproject.toml +13 -3
  9. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/backend.py +96 -31
  10. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/bridge.py +5 -1
  11. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/bus.py +77 -5
  12. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/hamlib_bridge.py +23 -6
  13. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio.py +19 -0
  14. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/discovery.py +60 -1
  15. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/audio.py +96 -15
  16. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/control.py +3 -2
  17. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/scope.py +3 -2
  18. rigplane-2.8.0/src/rigplane/web/transport/__init__.py +14 -0
  19. rigplane-2.8.0/src/rigplane/web/transport/connection.py +50 -0
  20. rigplane-2.8.0/src/rigplane/web/transport/webrtc.py +202 -0
  21. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_backend.py +193 -0
  22. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bridge.py +33 -1
  23. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bus.py +71 -20
  24. rigplane-2.8.0/tests/test_audio_capture_tx_validator_seam.py +312 -0
  25. rigplane-2.8.0/tests/test_audio_tx_contract_consistency.py +244 -0
  26. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_discovery_responder.py +144 -1
  27. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_bridge.py +15 -0
  28. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_coverage.py +91 -1
  29. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_reconnect.py +41 -0
  30. rigplane-2.8.0/tests/test_web_transport_connection.py +116 -0
  31. rigplane-2.8.0/tests/test_webrtc_datachannel_connection.py +335 -0
  32. {rigplane-2.7.2 → rigplane-2.8.0}/uv.lock +1 -1
  33. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/analyze-failure.md +0 -0
  34. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/audit-ui.md +0 -0
  35. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/decompose-issue.md +0 -0
  36. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/generate-tests.md +0 -0
  37. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/next.md +0 -0
  38. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/refactor.md +0 -0
  39. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/regression-check.md +0 -0
  40. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/scan-issues.md +0 -0
  41. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/solve-issue.md +0 -0
  42. {rigplane-2.7.2 → rigplane-2.8.0}/.claude/skills/release/SKILL.md +0 -0
  43. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  44. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  45. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/epic.yml +0 -0
  46. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  47. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/radio_report.md +0 -0
  48. {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/ui-component.yml +0 -0
  49. {rigplane-2.7.2 → rigplane-2.8.0}/.github/pull_request_template.md +0 -0
  50. {rigplane-2.7.2 → rigplane-2.8.0}/.github/scripts/check-rebrand-allowlist.sh +0 -0
  51. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/agent-review-gate.yml +0 -0
  52. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/docs.yml +0 -0
  53. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/full.yml +0 -0
  54. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/publish.yml +0 -0
  55. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/quick.yml +0 -0
  56. {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/rebrand-gate.yml +0 -0
  57. {rigplane-2.7.2 → rigplane-2.8.0}/.gitignore +0 -0
  58. {rigplane-2.7.2 → rigplane-2.8.0}/.importlinter +0 -0
  59. {rigplane-2.7.2 → rigplane-2.8.0}/AGENTS.md +0 -0
  60. {rigplane-2.7.2 → rigplane-2.8.0}/ARCHITECTURE.md +0 -0
  61. {rigplane-2.7.2 → rigplane-2.8.0}/CHANGELOG.md +0 -0
  62. {rigplane-2.7.2 → rigplane-2.8.0}/CLAUDE.md +0 -0
  63. {rigplane-2.7.2 → rigplane-2.8.0}/CONTRIBUTING.md +0 -0
  64. {rigplane-2.7.2 → rigplane-2.8.0}/LICENSE +0 -0
  65. {rigplane-2.7.2 → rigplane-2.8.0}/README.md +0 -0
  66. {rigplane-2.7.2 → rigplane-2.8.0}/ROADMAP.md +0 -0
  67. {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/_config.toml +0 -0
  68. {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/arrl-hf.toml +0 -0
  69. {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/broadcast.toml +0 -0
  70. {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/iaru-r1.toml +0 -0
  71. {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/utility.toml +0 -0
  72. {rigplane-2.7.2 → rigplane-2.8.0}/docs/4f4bcd28cb8d426ca58ec08b5035541e.txt +0 -0
  73. {rigplane-2.7.2 → rigplane-2.8.0}/docs/AUDIO_STREAMING_PROFILE.md +0 -0
  74. {rigplane-2.7.2 → rigplane-2.8.0}/docs/CNAME +0 -0
  75. {rigplane-2.7.2 → rigplane-2.8.0}/docs/EXTENDED_PROTOCOL_RESEARCH.md +0 -0
  76. {rigplane-2.7.2 → rigplane-2.8.0}/docs/PERFORMANCE.md +0 -0
  77. {rigplane-2.7.2 → rigplane-2.8.0}/docs/SECURITY.md +0 -0
  78. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/audio.md +0 -0
  79. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/auth.md +0 -0
  80. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends-icom7610-drivers.md +0 -0
  81. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends-icom7610.md +0 -0
  82. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends.md +0 -0
  83. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/command-catalog.md +0 -0
  84. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/commander.md +0 -0
  85. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/commands.md +0 -0
  86. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/exceptions.md +0 -0
  87. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/public-api-surface.md +0 -0
  88. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/radio.md +0 -0
  89. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/radios.md +0 -0
  90. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/rig-loader.md +0 -0
  91. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/rigctld.md +0 -0
  92. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/scope.md +0 -0
  93. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/sync.md +0 -0
  94. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/transport.md +0 -0
  95. {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/types.md +0 -0
  96. {rigplane-2.7.2 → rigplane-2.8.0}/docs/architecture/open-core-policy.md +0 -0
  97. {rigplane-2.7.2 → rigplane-2.8.0}/docs/assets/scope-example.png +0 -0
  98. {rigplane-2.7.2 → rigplane-2.8.0}/docs/capabilities-matrix.md +0 -0
  99. {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/diagnostic-bundle-v1.md +0 -0
  100. {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/diagnostic-bundle-v2.md +0 -0
  101. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/cli.md +0 -0
  102. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/commands.md +0 -0
  103. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/configuration.md +0 -0
  104. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/connection.md +0 -0
  105. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/diagnostic-reports.md +0 -0
  106. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/hamlib-rigctld-provider.md +0 -0
  107. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic705-usb-setup.md +0 -0
  108. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic7300-usb-setup.md +0 -0
  109. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic7610-usb-setup.md +0 -0
  110. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic9700-usb-setup.md +0 -0
  111. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/installation.md +0 -0
  112. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/profiles.md +0 -0
  113. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/quickstart.md +0 -0
  114. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/radios.md +0 -0
  115. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/rig-profiles.md +0 -0
  116. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/troubleshooting.md +0 -0
  117. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/web-ui.md +0 -0
  118. {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/wsjtx-setup.md +0 -0
  119. {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/core-string-inventory.md +0 -0
  120. {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/locale-contract.md +0 -0
  121. {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/translating.md +0 -0
  122. {rigplane-2.7.2 → rigplane-2.8.0}/docs/index.md +0 -0
  123. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/architecture.md +0 -0
  124. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/cli-design.md +0 -0
  125. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/contributing.md +0 -0
  126. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/github-project-workflow.md +0 -0
  127. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/hamlib-provider-rollout.md +0 -0
  128. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/protocol.md +0 -0
  129. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/raw-civ-transactions.md +0 -0
  130. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/reliability-semantics.md +0 -0
  131. {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/rfc-audio-v1-mini.md +0 -0
  132. {rigplane-2.7.2 → rigplane-2.8.0}/docs/migrate.md +0 -0
  133. {rigplane-2.7.2 → rigplane-2.8.0}/docs/operations/managed-runtime-packaging.md +0 -0
  134. {rigplane-2.7.2 → rigplane-2.8.0}/docs/opuslib-macos-fix.md +0 -0
  135. {rigplane-2.7.2 → rigplane-2.8.0}/docs/overrides/main.html +0 -0
  136. {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/README.md +0 -0
  137. {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/ic7610_command_matrix.json +0 -0
  138. {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/test_mapping.md +0 -0
  139. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-03-07-ui-architecture.md +0 -0
  140. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-05-desktop-companion-architecture.md +0 -0
  141. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-09-audio-backend-design.md +0 -0
  142. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-frontend-migration-plan.md +0 -0
  143. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-parity-matrix.md +0 -0
  144. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-presentation-architecture.md +0 -0
  145. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-rx-audio-trace.md +0 -0
  146. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-shared-frontend-runtime-contract.md +0 -0
  147. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-v2-lcd-runtime-audit.md +0 -0
  148. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-12-architecture-presentation.html +0 -0
  149. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-12-target-frontend-architecture.md +0 -0
  150. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-desktop-meters-panel.md +0 -0
  151. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-lcd-display-enhancements.md +0 -0
  152. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-mobile-ia.md +0 -0
  153. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-receiver-activation.md +0 -0
  154. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-spectrum-controls.md +0 -0
  155. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-ui-refinements-execution.md +0 -0
  156. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-19-lcd-layout-redesign-v2.md +0 -0
  157. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-19-lcd-layout-redesign.md +0 -0
  158. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-modularization-discovery.md +0 -0
  159. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-modularization-plan.md +0 -0
  160. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-panel-adapter-migration.md +0 -0
  161. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-ui-v1-deprecation-audit.md +0 -0
  162. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-03-diagnostic-data-collection-design.md +0 -0
  163. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-07-audio-route-resolver-design.md +0 -0
  164. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-capability-probing.md +0 -0
  165. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-codec-policy.md +0 -0
  166. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-profile-policy-audit.md +0 -0
  167. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-usb-audio-negotiation.md +0 -0
  168. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-23-hamlib-provider-contract.md +0 -0
  169. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-28-real-radio-validation-matrix.md +0 -0
  170. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-28-universal-validation-matrix.md +0 -0
  171. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-03-04-dx-cluster.md +0 -0
  172. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-03-m5-m6-roadmap.md +0 -0
  173. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-04-19-lcd-twin-skins.md +0 -0
  174. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/build_orphan_report.py +0 -0
  175. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/classify_cycle_edges.py +0 -0
  176. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/cycles-classified.md +0 -0
  177. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/cycles.txt +0 -0
  178. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/discovery_graph.py +0 -0
  179. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/external-usage.md +0 -0
  180. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/file-inventory.json +0 -0
  181. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/file-inventory.md +0 -0
  182. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/import-graph.dot +0 -0
  183. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/importlinter-config-draft.ini +0 -0
  184. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/init-snapshot.md +0 -0
  185. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/orphan-candidates.md +0 -0
  186. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/tach-config-draft.toml +0 -0
  187. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/test-inventory.md +0 -0
  188. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/tooling-assessment.md +0 -0
  189. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/00-epic-final.md +0 -0
  190. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/00-epic.md +0 -0
  191. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/01-skeleton.md +0 -0
  192. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/02-core-foundationals.md +0 -0
  193. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/03-core-contracts.md +0 -0
  194. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/04-commands.md +0 -0
  195. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/05-profiles.md +0 -0
  196. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/06-scope.md +0 -0
  197. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/07-audio.md +0 -0
  198. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/08-runtime-radio.md +0 -0
  199. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/09-runtime-mixins.md +0 -0
  200. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/10-runtime-pollers.md +0 -0
  201. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/11-discovery-to-backends.md +0 -0
  202. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/12-cli.md +0 -0
  203. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/13-import-linter.md +0 -0
  204. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/14-followup-tests.md +0 -0
  205. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/15-followup-web-startup.md +0 -0
  206. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/2026-05-07-core-audio-pipeline-test-harness.md +0 -0
  207. {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/2026-05-07-core-audio-route-resolver.md +0 -0
  208. {rigplane-2.7.2 → rigplane-2.8.0}/docs/radio-protocol.md +0 -0
  209. {rigplane-2.7.2 → rigplane-2.8.0}/docs/robots.txt +0 -0
  210. {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/amber-lcd.png +0 -0
  211. {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/hero.png +0 -0
  212. {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/lcd-scope.png +0 -0
  213. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/running-validation.md +0 -0
  214. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/ftx1.json +0 -0
  215. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/ic7300.json +0 -0
  216. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/tx500.json +0 -0
  217. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/x6200.json +0 -0
  218. {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/universal-matrix.md +0 -0
  219. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/.gitignore +0 -0
  220. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/README.md +0 -0
  221. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/eslint.config.js +0 -0
  222. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/index.html +0 -0
  223. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/package-lock.json +0 -0
  224. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/package.json +0 -0
  225. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/playwright.config.ts +0 -0
  226. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/playwright.i18n.config.ts +0 -0
  227. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/pnpm-lock.yaml +0 -0
  228. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/apple-touch-icon.png +0 -0
  229. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-dark.svg +0 -0
  230. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-light.svg +0 -0
  231. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-mono.svg +0 -0
  232. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-dark.svg +0 -0
  233. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-light.svg +0 -0
  234. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-mono.svg +0 -0
  235. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/marketing/github-social-preview.png +0 -0
  236. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/marketing/readme-banner.png +0 -0
  237. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-dark.svg +0 -0
  238. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-light.svg +0 -0
  239. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-mono.svg +0 -0
  240. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-16.png +0 -0
  241. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-32.png +0 -0
  242. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-48.png +0 -0
  243. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon.ico +0 -0
  244. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-128.png +0 -0
  245. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-16.png +0 -0
  246. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-180.png +0 -0
  247. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-192.png +0 -0
  248. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-256.png +0 -0
  249. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-32.png +0 -0
  250. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-48.png +0 -0
  251. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-512.png +0 -0
  252. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-64.png +0 -0
  253. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon.ico +0 -0
  254. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-128.png +0 -0
  255. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-16.png +0 -0
  256. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-180.png +0 -0
  257. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-192.png +0 -0
  258. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-256.png +0 -0
  259. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-32.png +0 -0
  260. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-48.png +0 -0
  261. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-512.png +0 -0
  262. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-64.png +0 -0
  263. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon.ico +0 -0
  264. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-128.png +0 -0
  265. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-16.png +0 -0
  266. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-180.png +0 -0
  267. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-192.png +0 -0
  268. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-256.png +0 -0
  269. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-32.png +0 -0
  270. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-48.png +0 -0
  271. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-512.png +0 -0
  272. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-64.png +0 -0
  273. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/manifest.json +0 -0
  274. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/og-image.png +0 -0
  275. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/pwa-192x192.png +0 -0
  276. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/pwa-512x512.png +0 -0
  277. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/twitter-card.png +0 -0
  278. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/scripts/i18n-check.mjs +0 -0
  279. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/App.svelte +0 -0
  280. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/app.css +0 -0
  281. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/assets/svelte.svg +0 -0
  282. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/shared/Toast.svelte +0 -0
  283. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/shared/__tests__/Toast.component.test.ts +0 -0
  284. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/BandPlanOverlay.svelte +0 -0
  285. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/DxOverlay.svelte +0 -0
  286. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/EiBiBrowser.svelte +0 -0
  287. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/ScopeSettingsPopover.svelte +0 -0
  288. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumCanvas.svelte +0 -0
  289. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumPanel.svelte +0 -0
  290. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumToolbar.svelte +0 -0
  291. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/WaterfallCanvas.svelte +0 -0
  292. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/BandPlanOverlay.component.test.ts +0 -0
  293. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/DxOverlay.test.ts +0 -0
  294. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/EiBiBrowser.test.ts +0 -0
  295. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/SpectrumPanel.component.test.ts +0 -0
  296. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/SpectrumToolbar.component.test.ts +0 -0
  297. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/band-plan-overlay.test.ts +0 -0
  298. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/click-to-tune.test.ts +0 -0
  299. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/passband-geometry.test.ts +0 -0
  300. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/spectrum-panel-logic.test.ts +0 -0
  301. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/spectrum-toolbar.test.ts +0 -0
  302. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/tuning-indicator.test.ts +0 -0
  303. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/band-plan-logic.ts +0 -0
  304. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/passband-geometry.ts +0 -0
  305. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/spectrum-logic.ts +0 -0
  306. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/spectrum-toolbar-logic.ts +0 -0
  307. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/AttenuatorControl.svelte +0 -0
  308. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/BandSelector.svelte +0 -0
  309. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/BottomSheet.svelte +0 -0
  310. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/CollapsiblePanel.svelte +0 -0
  311. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ControlButtonDemo.svelte +0 -0
  312. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/InstallPrompt.svelte +0 -0
  313. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/LanguageSelector.svelte +0 -0
  314. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/PttFab.svelte +0 -0
  315. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/PullToRefresh.svelte +0 -0
  316. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/SegmentedButton.svelte +0 -0
  317. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/StatusBadge.svelte +0 -0
  318. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ThemePicker.svelte +0 -0
  319. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ValueControlLab.svelte +0 -0
  320. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/AttenuatorControl.test.ts +0 -0
  321. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/BandSelector.test.ts +0 -0
  322. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/BottomSheet.test.ts +0 -0
  323. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/CollapsiblePanel.test.ts +0 -0
  324. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/InstallPrompt.test.ts +0 -0
  325. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/LanguageSelector.test.ts +0 -0
  326. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/PullToRefresh.test.ts +0 -0
  327. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/SegmentedButton.test.ts +0 -0
  328. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/StatusBadge.test.ts +0 -0
  329. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/broadcast-presets.test.ts +0 -0
  330. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/band-utils.ts +0 -0
  331. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/broadcast-presets.ts +0 -0
  332. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/button-tokens.css +0 -0
  333. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/control-button.css +0 -0
  334. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/install-prompt-utils.ts +0 -0
  335. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/status-badge-style.ts +0 -0
  336. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/BipolarRenderer.svelte +0 -0
  337. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/DiscreteRenderer.svelte +0 -0
  338. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/DualParamRenderer.svelte +0 -0
  339. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/HBarRenderer.svelte +0 -0
  340. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/KnobRenderer.svelte +0 -0
  341. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/ValueControl.svelte +0 -0
  342. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/__tests__/ValueControl.test.ts +0 -0
  343. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/__tests__/value-control-core.test.ts +0 -0
  344. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/index.ts +0 -0
  345. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skin.ts +0 -0
  346. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skins/ProfessionalKnob.svelte +0 -0
  347. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skins/index.ts +0 -0
  348. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/value-control-core.ts +0 -0
  349. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/value-control.css +0 -0
  350. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/dialogs/SendReportDialog.svelte +0 -0
  351. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/dialogs/__tests__/SendReportDialog.test.ts +0 -0
  352. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/FrequencyDisplay.svelte +0 -0
  353. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/FrequencyDisplayInteractive.svelte +0 -0
  354. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/__tests__/FrequencyDisplay.test.ts +0 -0
  355. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/__tests__/frequency-tuning.test.ts +0 -0
  356. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/frequency-format.ts +0 -0
  357. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/frequency-tuning.ts +0 -0
  358. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/KeyboardHandler.svelte +0 -0
  359. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/LcdLayout.svelte +0 -0
  360. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/LeftSidebar.svelte +0 -0
  361. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/MobileNav.svelte +0 -0
  362. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/MobileRadioLayout.svelte +0 -0
  363. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/RadioLayout.svelte +0 -0
  364. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/RightSidebar.svelte +0 -0
  365. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/StatusBar.svelte +0 -0
  366. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/VfoHeader.svelte +0 -0
  367. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/KeyboardHandler.test.ts +0 -0
  368. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/LeftSidebar.test.ts +0 -0
  369. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/MobileRadioLayout.component.svelte.test.ts +0 -0
  370. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/RadioLayout.test.ts +0 -0
  371. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/SpectrumPanelStub.svelte +0 -0
  372. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/keyboard-map.test.ts +0 -0
  373. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/mobile-layout-logic.test.ts +0 -0
  374. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/mobile-nav.test.ts +0 -0
  375. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/top-row-visual-regression.test.ts +0 -0
  376. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/vfo-header.test.ts +0 -0
  377. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/vfo-layout-tokens.test.ts +0 -0
  378. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/keyboard-map.ts +0 -0
  379. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/layout-utils.ts +0 -0
  380. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-chip-bar.svelte +0 -0
  381. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-layout-logic.ts +0 -0
  382. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-nav-utils.ts +0 -0
  383. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/responsive.css +0 -0
  384. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/shortcut-hints.ts +0 -0
  385. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/vfo-layout-tokens.ts +0 -0
  386. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/BarGauge.svelte +0 -0
  387. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/LinearSMeter.svelte +0 -0
  388. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/NeedleGauge.svelte +0 -0
  389. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/SMeterDemo.svelte +0 -0
  390. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/BarGauge.test.ts +0 -0
  391. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/LinearSMeter.test.ts +0 -0
  392. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/NeedleGauge.test.ts +0 -0
  393. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/bar-gauge-utils.ts +0 -0
  394. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/needle-gauge-utils.ts +0 -0
  395. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/smeter-scale.ts +0 -0
  396. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AgcPanel.svelte +0 -0
  397. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AntennaPanel.svelte +0 -0
  398. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AudioRoutingControl.svelte +0 -0
  399. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/CwPanel.svelte +0 -0
  400. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/DockMeterPanel.svelte +0 -0
  401. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/DspPanel.svelte +0 -0
  402. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/EssentialsPanel.svelte +0 -0
  403. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/FilterPanel.svelte +0 -0
  404. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MemoryPanel.svelte +0 -0
  405. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MeterPanel.svelte +0 -0
  406. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MetersDockPanel.svelte +0 -0
  407. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/ModePanel.svelte +0 -0
  408. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RfFrontEnd.svelte +0 -0
  409. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RitXitPanel.svelte +0 -0
  410. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RxAudioPanel.svelte +0 -0
  411. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/ScanPanel.svelte +0 -0
  412. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/TxPanel.svelte +0 -0
  413. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/VoxPanel.svelte +0 -0
  414. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/AgcPanel.test.ts +0 -0
  415. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/AudioRoutingControl.test.ts +0 -0
  416. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/CwPanel.component.test.ts +0 -0
  417. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/DspPanel.component.test.ts +0 -0
  418. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/DspPanel.test.ts +0 -0
  419. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/FilterPanel.test.ts +0 -0
  420. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/MeterPanel.test.ts +0 -0
  421. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/MetersDockPanel.test.ts +0 -0
  422. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/ModePanel.test.ts +0 -0
  423. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RfFrontEnd.test.ts +0 -0
  424. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RitXitPanel.test.ts +0 -0
  425. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RxAudioPanel.test.ts +0 -0
  426. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/TxPanel.test.ts +0 -0
  427. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/cw-panel-logic.test.ts +0 -0
  428. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/dsp-panel-logic.test.ts +0 -0
  429. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/filter-controls.test.ts +0 -0
  430. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/agc-utils.ts +0 -0
  431. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/AudioSpectrumCanvas.svelte +0 -0
  432. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/AudioSpectrumPanel.svelte +0 -0
  433. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/__tests__/audio-spectrum-renderer.test.ts +0 -0
  434. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/audio-spectrum-renderer.ts +0 -0
  435. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-utils.ts +0 -0
  436. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/cw-panel-logic.ts +0 -0
  437. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/dsp-panel-logic.ts +0 -0
  438. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/dsp-utils.ts +0 -0
  439. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/filter-controls.ts +0 -0
  440. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/filter-utils.ts +0 -0
  441. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberAfScope.svelte +0 -0
  442. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberCockpit.svelte +0 -0
  443. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberFilterGhost.svelte +0 -0
  444. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberFrequency.svelte +0 -0
  445. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberIndStrip.svelte +0 -0
  446. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberLcdDisplay.svelte +0 -0
  447. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberMemoryStrip.svelte +0 -0
  448. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberScope.svelte +0 -0
  449. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberSmeter.svelte +0 -0
  450. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberSparkline.svelte +0 -0
  451. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberTelemetryStrip.svelte +0 -0
  452. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/LcdContrastControl.svelte +0 -0
  453. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/LcdDisplayModeControl.svelte +0 -0
  454. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/VfoControlPanel.svelte +0 -0
  455. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/__tests__/lcd-components.test.ts +0 -0
  456. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/__tests__/scope-frame.test.ts +0 -0
  457. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/lcd-vintage.css +0 -0
  458. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/meter-utils.test.ts +0 -0
  459. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/meter-utils.ts +0 -0
  460. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/rf-frontend-utils.ts +0 -0
  461. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/rit-utils.ts +0 -0
  462. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/tx-utils.ts +0 -0
  463. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/vfo/DualVfoDisplay.svelte +0 -0
  464. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/vfo/__tests__/DualVfoDisplay.test.ts +0 -0
  465. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/fonts-digital.css +0 -0
  466. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/fonts.css +0 -0
  467. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/index.ts +0 -0
  468. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/theme-switcher.ts +0 -0
  469. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/amoled-black.css +0 -0
  470. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/ayu-dark.css +0 -0
  471. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/catppuccin-latte.css +0 -0
  472. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/catppuccin-mocha.css +0 -0
  473. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/crt-green.css +0 -0
  474. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/custom-ic7610.css +0 -0
  475. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/dracula.css +0 -0
  476. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/github-light.css +0 -0
  477. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/gruvbox-dark.css +0 -0
  478. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/gruvbox-light.css +0 -0
  479. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/high-contrast.css +0 -0
  480. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/index.ts +0 -0
  481. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/lcd-blue.css +0 -0
  482. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/lcd-warm.css +0 -0
  483. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nixie-tube.css +0 -0
  484. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nord-light.css +0 -0
  485. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nord.css +0 -0
  486. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/one-dark.css +0 -0
  487. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/solarized-dark.css +0 -0
  488. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/solarized-light.css +0 -0
  489. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/tokyo-night.css +0 -0
  490. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/tokens.css +0 -0
  491. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/crt-green.css +0 -0
  492. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/index.ts +0 -0
  493. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/lcd-blue.css +0 -0
  494. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/nixie-tube.css +0 -0
  495. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/ActiveReceiverToggle.svelte +0 -0
  496. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/VfoOps.svelte +0 -0
  497. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/VfoPanel.svelte +0 -0
  498. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/ActiveReceiverToggle.test.ts +0 -0
  499. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/VfoOps.test.ts +0 -0
  500. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/VfoPanel.test.ts +0 -0
  501. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/vfo-ops-utils.ts +0 -0
  502. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/vfo-utils.ts +0 -0
  503. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/double-click.test.ts +0 -0
  504. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/focus-mode-race.test.ts +0 -0
  505. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/keyboard-wiring.test.ts +0 -0
  506. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/state-adapter.test.ts +0 -0
  507. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/vfo-wiring.test.ts +0 -0
  508. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/command-bus.ts +0 -0
  509. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/double-click.ts +0 -0
  510. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/state-adapter.ts +0 -0
  511. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/ControlButton.svelte +0 -0
  512. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/DotButton.svelte +0 -0
  513. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/FillButton.svelte +0 -0
  514. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/HardwareButton.svelte +0 -0
  515. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/HardwarePlainButton.svelte +0 -0
  516. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/StatusIndicator.svelte +0 -0
  517. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/__tests__/ControlButton.test.ts +0 -0
  518. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/__tests__/ControlledHarness.svelte +0 -0
  519. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/index.ts +0 -0
  520. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/roleMapping.ts +0 -0
  521. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/types.ts +0 -0
  522. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/SegmentedControl/index.ts +0 -0
  523. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/__tests__/drag-reorder.test.ts +0 -0
  524. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/__tests__/migrate-legacy-storage.test.ts +0 -0
  525. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/actions/keyboard.ts +0 -0
  526. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/api/__tests__/diagnostics.test.ts +0 -0
  527. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/api/diagnostics.ts +0 -0
  528. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/audio-manager.test.ts +0 -0
  529. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/constants.test.ts +0 -0
  530. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/rx-player.test.ts +0 -0
  531. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/tx-mic.test.ts +0 -0
  532. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/audio-manager.ts +0 -0
  533. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/constants.ts +0 -0
  534. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/rx-player.ts +0 -0
  535. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/tx-mic.ts +0 -0
  536. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/data/__tests__/arrl-band-plan.test.ts +0 -0
  537. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/data/arrl-band-plan.ts +0 -0
  538. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/drag-reorder.svelte.ts +0 -0
  539. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/gestures/gesture-recognizer.ts +0 -0
  540. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/gestures/use-gesture.ts +0 -0
  541. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/CONTRIBUTING.md +0 -0
  542. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/index.test.ts +0 -0
  543. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/locale-contract.test.ts +0 -0
  544. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/plural.test.ts +0 -0
  545. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/pseudo-locale.smoke.test.ts +0 -0
  546. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/pseudo.test.ts +0 -0
  547. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/runtime.test.ts +0 -0
  548. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/store.test.ts +0 -0
  549. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/index.ts +0 -0
  550. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locale-contract.ts +0 -0
  551. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/en-US.json +0 -0
  552. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/ja-JP.json +0 -0
  553. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/ru-RU.json +0 -0
  554. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/plural.ts +0 -0
  555. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/pseudo.ts +0 -0
  556. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/runtime.ts +0 -0
  557. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/store.svelte.ts +0 -0
  558. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/types.ts +0 -0
  559. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/LocalExtensionsHost.svelte +0 -0
  560. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/dock-layout.test.ts +0 -0
  561. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/host-api.test.ts +0 -0
  562. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/manifest.test.ts +0 -0
  563. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/dock-layout.ts +0 -0
  564. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/host-api.ts +0 -0
  565. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/keyboard-scope.ts +0 -0
  566. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/manifest.ts +0 -0
  567. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/media/__tests__/media-session.test.ts +0 -0
  568. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/media/media-session.ts +0 -0
  569. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/migrate-legacy-storage.ts +0 -0
  570. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/filter-controls.ts +0 -0
  571. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/pending-focus.test.ts +0 -0
  572. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/pending-focus.ts +0 -0
  573. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/__tests__/spectrum-renderer.test.ts +0 -0
  574. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/__tests__/waterfall-renderer.test.ts +0 -0
  575. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/spectrum-renderer.ts +0 -0
  576. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/waterfall-renderer.ts +0 -0
  577. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/__tests__/frontend-runtime.test.ts +0 -0
  578. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/__tests__/scope-controller.test.ts +0 -0
  579. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/audio-adapter.ts +0 -0
  580. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/capabilities-adapter.ts +0 -0
  581. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/lcd-chrome-adapter.ts +0 -0
  582. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/panel-adapters.ts +0 -0
  583. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/qsy-history-adapter.ts +0 -0
  584. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/scope-adapter.ts +0 -0
  585. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/tx-adapter.ts +0 -0
  586. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/vfo-adapter.ts +0 -0
  587. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/commands/panel-commands.ts +0 -0
  588. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/frontend-runtime.ts +0 -0
  589. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/index.ts +0 -0
  590. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/props/panel-props.ts +0 -0
  591. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/scope-controller.svelte.ts +0 -0
  592. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/system-controller.ts +0 -0
  593. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/audio.test.ts +0 -0
  594. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/capabilities.test.ts +0 -0
  595. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/commands.test.ts +0 -0
  596. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/connection.test.ts +0 -0
  597. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/radio.test.ts +0 -0
  598. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/ui.test.ts +0 -0
  599. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/audio.svelte.ts +0 -0
  600. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/capabilities.svelte.ts +0 -0
  601. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/commands.svelte.ts +0 -0
  602. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/connection.svelte.ts +0 -0
  603. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/connection.test.ts +0 -0
  604. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/layout.svelte.ts +0 -0
  605. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/lcd-contrast.svelte.ts +0 -0
  606. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/lcd-display-mode.svelte.ts +0 -0
  607. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/qsy-history.svelte.ts +0 -0
  608. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/radio.svelte.test.ts +0 -0
  609. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/radio.svelte.ts +0 -0
  610. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/tuning.svelte.ts +0 -0
  611. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/ui.svelte.ts +0 -0
  612. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/__tests__/http-client.test.ts +0 -0
  613. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/__tests__/ws-client.test.ts +0 -0
  614. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/http-client.ts +0 -0
  615. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/ws-client.ts +0 -0
  616. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/capabilities.ts +0 -0
  617. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/protocol.ts +0 -0
  618. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/state.ts +0 -0
  619. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/__tests__/battery.test.ts +0 -0
  620. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/battery.ts +0 -0
  621. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/filter-width.ts +0 -0
  622. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/haptics.ts +0 -0
  623. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/meter-utils.ts +0 -0
  624. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/smoothing.svelte.ts +0 -0
  625. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/tx-permit.ts +0 -0
  626. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/uuid.ts +0 -0
  627. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/main.ts +0 -0
  628. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/amber-lcd/LcdSkin.svelte +0 -0
  629. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/desktop-v2/DesktopSkin.svelte +0 -0
  630. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/lcd-cockpit/LcdCockpitSkin.svelte +0 -0
  631. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/lcd-scope/LcdScopeSkin.svelte +0 -0
  632. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/mobile/MobileSkin.svelte +0 -0
  633. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/registry.ts +0 -0
  634. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/sdr-test/SdrTestSkin.svelte +0 -0
  635. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/sdr-test/SdrVfoScreen.svelte +0 -0
  636. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/styles/animations.css +0 -0
  637. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/styles/tokens.css +0 -0
  638. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/types/pwa.d.ts +0 -0
  639. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/types/webcodecs.d.ts +0 -0
  640. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/static/fonts/DSEG7Classic-Bold.woff2 +0 -0
  641. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/svelte.config.js +0 -0
  642. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/README.md +0 -0
  643. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/app-shell-desktop.png +0 -0
  644. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/app-shell-mobile.png +0 -0
  645. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/connection-overlay-desktop.png +0 -0
  646. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/connection-overlay-mobile.png +0 -0
  647. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/send-report-dialog-desktop.png +0 -0
  648. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/send-report-dialog-mobile.png +0 -0
  649. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/settings-modal-desktop.png +0 -0
  650. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/settings-modal-mobile.png +0 -0
  651. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/status-bar-desktop.png +0 -0
  652. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/status-bar-mobile.png +0 -0
  653. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/toast-desktop.png +0 -0
  654. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/toast-mobile.png +0 -0
  655. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/app-shell-desktop.png +0 -0
  656. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/app-shell-mobile.png +0 -0
  657. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/connection-overlay-desktop.png +0 -0
  658. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/connection-overlay-mobile.png +0 -0
  659. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/send-report-dialog-desktop.png +0 -0
  660. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/send-report-dialog-mobile.png +0 -0
  661. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/settings-modal-desktop.png +0 -0
  662. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/settings-modal-mobile.png +0 -0
  663. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/status-bar-desktop.png +0 -0
  664. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/status-bar-mobile.png +0 -0
  665. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/toast-desktop.png +0 -0
  666. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/toast-mobile.png +0 -0
  667. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/app-shell-desktop.png +0 -0
  668. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/app-shell-mobile.png +0 -0
  669. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/connection-overlay-desktop.png +0 -0
  670. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/connection-overlay-mobile.png +0 -0
  671. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/send-report-dialog-desktop.png +0 -0
  672. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/send-report-dialog-mobile.png +0 -0
  673. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/settings-modal-desktop.png +0 -0
  674. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/settings-modal-mobile.png +0 -0
  675. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/status-bar-desktop.png +0 -0
  676. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/status-bar-mobile.png +0 -0
  677. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/toast-desktop.png +0 -0
  678. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/toast-mobile.png +0 -0
  679. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/fixtures.ts +0 -0
  680. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/i18n-visual.spec.ts +0 -0
  681. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/v2-ui-interactive.impl.ts +0 -0
  682. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.app.json +0 -0
  683. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.json +0 -0
  684. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.node.json +0 -0
  685. {rigplane-2.7.2 → rigplane-2.8.0}/frontend/vite.config.ts +0 -0
  686. {rigplane-2.7.2 → rigplane-2.8.0}/hooks/sitemap_noindex.py +0 -0
  687. {rigplane-2.7.2 → rigplane-2.8.0}/mkdocs.yml +0 -0
  688. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_keyboard-default.toml +0 -0
  689. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_schema.md +0 -0
  690. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_schema_v2.md +0 -0
  691. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/ftx1.toml +0 -0
  692. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/lab599_tx500.toml +0 -0
  693. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/sdrplay_rspdx.toml +0 -0
  694. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/xiegu_x6200.toml +0 -0
  695. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ftx1.toml +0 -0
  696. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic705.toml +0 -0
  697. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic7300.toml +0 -0
  698. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic7610.toml +0 -0
  699. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic9700.toml +0 -0
  700. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/tx500.toml +0 -0
  701. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/x6100.toml +0 -0
  702. {rigplane-2.7.2 → rigplane-2.8.0}/rigs/x6200.toml +0 -0
  703. {rigplane-2.7.2 → rigplane-2.8.0}/src/icom_lan/__init__.py +0 -0
  704. {rigplane-2.7.2 → rigplane-2.8.0}/src/icom_lan/_cli_shim.py +0 -0
  705. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/__init__.py +0 -0
  706. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/__main__.py +0 -0
  707. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_codecs.py +0 -0
  708. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_recovery.py +0 -0
  709. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_runtime_mixin.py +0 -0
  710. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_transcoder.py +0 -0
  711. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bounded_queue.py +0 -0
  712. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bridge_metrics.py +0 -0
  713. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bridge_state.py +0 -0
  714. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_civ_rx.py +0 -0
  715. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_connection_state.py +0 -0
  716. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_control_phase.py +0 -0
  717. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_dual_rx_runtime.py +0 -0
  718. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_optional_deps.py +0 -0
  719. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_platformdirs_migration.py +0 -0
  720. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_poller_types.py +0 -0
  721. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_queue_pressure.py +0 -0
  722. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_runtime_protocols.py +0 -0
  723. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_scope_runtime.py +0 -0
  724. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_shared_state_runtime.py +0 -0
  725. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_state_cache.py +0 -0
  726. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_state_queries.py +0 -0
  727. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/LAYER.md +0 -0
  728. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/__init__.py +0 -0
  729. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_bridge_metrics.py +0 -0
  730. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_bridge_state.py +0 -0
  731. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_codecs.py +0 -0
  732. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_macos_uid.py +0 -0
  733. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_transcoder.py +0 -0
  734. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_usb_resolve.py +0 -0
  735. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/analyzer.py +0 -0
  736. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/config.py +0 -0
  737. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/dsp.py +0 -0
  738. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/fft_scope.py +0 -0
  739. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/lan_stream.py +0 -0
  740. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe.py +0 -0
  741. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe_profile.py +0 -0
  742. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe_runner.py +0 -0
  743. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/resample.py +0 -0
  744. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/route.py +0 -0
  745. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/usb_driver.py +0 -0
  746. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_analyzer.py +0 -0
  747. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_bridge.py +0 -0
  748. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_bus.py +0 -0
  749. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_fft_scope.py +0 -0
  750. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/auth.py +0 -0
  751. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/LAYER.md +0 -0
  752. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/__init__.py +0 -0
  753. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/_icom_serial_base.py +0 -0
  754. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/config.py +0 -0
  755. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/discovery.py +0 -0
  756. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/factory.py +0 -0
  757. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/hamlib_models.py +0 -0
  758. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/hamlib_probe.py +0 -0
  759. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/__init__.py +0 -0
  760. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/core.py +0 -0
  761. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/serial.py +0 -0
  762. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/__init__.py +0 -0
  763. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/core.py +0 -0
  764. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/serial.py +0 -0
  765. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/__init__.py +0 -0
  766. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/core.py +0 -0
  767. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/serial.py +0 -0
  768. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/__init__.py +0 -0
  769. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/__init__.py +0 -0
  770. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/contracts.py +0 -0
  771. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_civ_link.py +0 -0
  772. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_session.py +0 -0
  773. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_stub.py +0 -0
  774. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/usb_audio.py +0 -0
  775. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/lan.py +0 -0
  776. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/serial.py +0 -0
  777. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/__init__.py +0 -0
  778. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/radio.py +0 -0
  779. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/transport.py +0 -0
  780. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/__init__.py +0 -0
  781. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/parser.py +0 -0
  782. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/poller.py +0 -0
  783. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/radio.py +0 -0
  784. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/transport.py +0 -0
  785. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/capabilities.py +0 -0
  786. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/civ.py +0 -0
  787. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/LAYER.md +0 -0
  788. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/__init__.py +0 -0
  789. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_convert.py +0 -0
  790. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_diagnose.py +0 -0
  791. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_discover_hamlib.py +0 -0
  792. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_radio_validate.py +0 -0
  793. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_validate.py +0 -0
  794. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/command_map.py +0 -0
  795. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/command_spec.py +0 -0
  796. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commander.py +0 -0
  797. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/LAYER.md +0 -0
  798. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/__init__.py +0 -0
  799. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_builders.py +0 -0
  800. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_codec.py +0 -0
  801. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_frame.py +0 -0
  802. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/antenna.py +0 -0
  803. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/command_map.py +0 -0
  804. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/command_spec.py +0 -0
  805. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/commander.py +0 -0
  806. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/config.py +0 -0
  807. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/cw.py +0 -0
  808. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/dsp.py +0 -0
  809. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/freq.py +0 -0
  810. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/levels.py +0 -0
  811. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/memory.py +0 -0
  812. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/meters.py +0 -0
  813. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/mode.py +0 -0
  814. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/power.py +0 -0
  815. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/ptt.py +0 -0
  816. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/scope.py +0 -0
  817. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/speech.py +0 -0
  818. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/system.py +0 -0
  819. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/tone.py +0 -0
  820. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/tx_band.py +0 -0
  821. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/vfo.py +0 -0
  822. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/LAYER.md +0 -0
  823. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/__init__.py +0 -0
  824. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_bounded_queue.py +0 -0
  825. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_optional_deps.py +0 -0
  826. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_queue_pressure.py +0 -0
  827. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_state_cache.py +0 -0
  828. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/auth.py +0 -0
  829. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/capabilities.py +0 -0
  830. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/civ.py +0 -0
  831. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/env_config.py +0 -0
  832. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/exceptions.py +0 -0
  833. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/protocol.py +0 -0
  834. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/radio_protocol.py +0 -0
  835. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/radio_state.py +0 -0
  836. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/transport.py +0 -0
  837. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/types.py +0 -0
  838. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cw_auto_tuner.py +0 -0
  839. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/__init__.py +0 -0
  840. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_discovery.py +0 -0
  841. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_error_ring.py +0 -0
  842. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_errors.py +0 -0
  843. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_logging.py +0 -0
  844. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_manifest.py +0 -0
  845. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/bundle.py +0 -0
  846. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributor.py +0 -0
  847. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/__init__.py +0 -0
  848. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/audio.py +0 -0
  849. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/config.py +0 -0
  850. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/dependencies.py +0 -0
  851. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/errors.py +0 -0
  852. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/invocation.py +0 -0
  853. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/logs.py +0 -0
  854. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/radio.py +0 -0
  855. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/state.py +0 -0
  856. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/system.py +0 -0
  857. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/redaction.py +0 -0
  858. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/upload.py +0 -0
  859. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/discovery.py +0 -0
  860. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/LAYER.md +0 -0
  861. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/__init__.py +0 -0
  862. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/exceptions.py +0 -0
  863. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/__init__.py +0 -0
  864. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/base.py +0 -0
  865. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/nr_scipy.py +0 -0
  866. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/pipeline.py +0 -0
  867. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/resample.py +0 -0
  868. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/tap_registry.py +0 -0
  869. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/env_config.py +0 -0
  870. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/exceptions.py +0 -0
  871. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/ic705.py +0 -0
  872. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/meter_cal.py +0 -0
  873. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/LAYER.md +0 -0
  874. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/__init__.py +0 -0
  875. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/rig_loader.py +0 -0
  876. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles_runtime.py +0 -0
  877. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/protocol.py +0 -0
  878. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/proxy.py +0 -0
  879. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/py.typed +0 -0
  880. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio.py +0 -0
  881. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_initial_state.py +0 -0
  882. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_protocol.py +0 -0
  883. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_reconnect.py +0 -0
  884. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_state.py +0 -0
  885. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_state_snapshot.py +0 -0
  886. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radios.py +0 -0
  887. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rig_loader.py +0 -0
  888. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/LAYER.md +0 -0
  889. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/__init__.py +0 -0
  890. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/audit.py +0 -0
  891. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/circuit_breaker.py +0 -0
  892. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/contract.py +0 -0
  893. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/handler.py +0 -0
  894. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/poller.py +0 -0
  895. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/protocol.py +0 -0
  896. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/routing.py +0 -0
  897. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/server.py +0 -0
  898. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/state_cache.py +0 -0
  899. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/utils.py +0 -0
  900. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/LAYER.md +0 -0
  901. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/__init__.py +0 -0
  902. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_audio_recovery.py +0 -0
  903. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_audio_runtime_mixin.py +0 -0
  904. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_civ_rx.py +0 -0
  905. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_connection_state.py +0 -0
  906. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_control_phase.py +0 -0
  907. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_dual_rx_runtime.py +0 -0
  908. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_poller_types.py +0 -0
  909. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_runtime_protocols.py +0 -0
  910. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_scope_runtime.py +0 -0
  911. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_shared_state_runtime.py +0 -0
  912. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_state_queries.py +0 -0
  913. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/cw_auto_tuner.py +0 -0
  914. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/ic705.py +0 -0
  915. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/meter_cal.py +0 -0
  916. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/profiles_runtime.py +0 -0
  917. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/proxy.py +0 -0
  918. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_initial_state.py +0 -0
  919. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_reconnect.py +0 -0
  920. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_state_snapshot.py +0 -0
  921. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radios.py +0 -0
  922. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/startup_checks.py +0 -0
  923. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/sync.py +0 -0
  924. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/LAYER.md +0 -0
  925. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/__init__.py +0 -0
  926. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/render.py +0 -0
  927. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope_render.py +0 -0
  928. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/startup_checks.py +0 -0
  929. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/sync.py +0 -0
  930. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/transport.py +0 -0
  931. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/types.py +0 -0
  932. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/usb_audio_resolve.py +0 -0
  933. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/LAYER.md +0 -0
  934. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/__init__.py +0 -0
  935. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/comparison.py +0 -0
  936. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/hardware.py +0 -0
  937. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/overrides.py +0 -0
  938. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/registry.py +0 -0
  939. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/runner.py +0 -0
  940. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/schema.py +0 -0
  941. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/LAYER.md +0 -0
  942. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/__init__.py +0 -0
  943. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/_delta_encoder.py +0 -0
  944. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/api_contract.py +0 -0
  945. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/band_plan.py +0 -0
  946. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/dx_cluster.py +0 -0
  947. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/eibi.py +0 -0
  948. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/__init__.py +0 -0
  949. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/diagnostics.py +0 -0
  950. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/protocol.py +0 -0
  951. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/radio_poller.py +0 -0
  952. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/rtc.py +0 -0
  953. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/runtime_helpers.py +0 -0
  954. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/server.py +0 -0
  955. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/apple-touch-icon.png +0 -0
  956. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/ControlButtonDemo-CnelvEOz.js +0 -0
  957. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/ControlButtonDemo-Ddi7py1_.css +0 -0
  958. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/index-CvOPafTi.css +0 -0
  959. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/index-MRf0y8eM.js +0 -0
  960. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-dark.svg +0 -0
  961. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-light.svg +0 -0
  962. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-mono.svg +0 -0
  963. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-dark.svg +0 -0
  964. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-light.svg +0 -0
  965. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-mono.svg +0 -0
  966. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/marketing/github-social-preview.png +0 -0
  967. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/marketing/readme-banner.png +0 -0
  968. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-dark.svg +0 -0
  969. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-light.svg +0 -0
  970. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-mono.svg +0 -0
  971. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-16.png +0 -0
  972. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-32.png +0 -0
  973. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-48.png +0 -0
  974. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon.ico +0 -0
  975. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-128.png +0 -0
  976. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-16.png +0 -0
  977. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-180.png +0 -0
  978. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-192.png +0 -0
  979. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-256.png +0 -0
  980. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-32.png +0 -0
  981. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-48.png +0 -0
  982. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-512.png +0 -0
  983. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-64.png +0 -0
  984. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon.ico +0 -0
  985. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-128.png +0 -0
  986. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-16.png +0 -0
  987. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-180.png +0 -0
  988. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-192.png +0 -0
  989. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-256.png +0 -0
  990. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-32.png +0 -0
  991. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-48.png +0 -0
  992. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-512.png +0 -0
  993. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-64.png +0 -0
  994. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon.ico +0 -0
  995. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-128.png +0 -0
  996. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-16.png +0 -0
  997. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-180.png +0 -0
  998. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-192.png +0 -0
  999. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-256.png +0 -0
  1000. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-32.png +0 -0
  1001. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-48.png +0 -0
  1002. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-512.png +0 -0
  1003. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-64.png +0 -0
  1004. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/index.html +0 -0
  1005. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/manifest.json +0 -0
  1006. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/og-image.png +0 -0
  1007. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/pwa-192x192.png +0 -0
  1008. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/pwa-512x512.png +0 -0
  1009. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/twitter-card.png +0 -0
  1010. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static.old/index.html +0 -0
  1011. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/tls.py +0 -0
  1012. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/web_routing.py +0 -0
  1013. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/web_startup.py +0 -0
  1014. {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/websocket.py +0 -0
  1015. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_audio_pipeline_helpers.py +0 -0
  1016. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_audio_stream_fake.py +0 -0
  1017. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_caps.py +0 -0
  1018. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_command_test_helpers.py +0 -0
  1019. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_diagnostics_mock_server.py +0 -0
  1020. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_helpers.py +0 -0
  1021. {rigplane-2.7.2 → rigplane-2.8.0}/tests/_perf_helpers.py +0 -0
  1022. {rigplane-2.7.2 → rigplane-2.8.0}/tests/conftest.py +0 -0
  1023. {rigplane-2.7.2 → rigplane-2.8.0}/tests/contracts/__init__.py +0 -0
  1024. {rigplane-2.7.2 → rigplane-2.8.0}/tests/contracts/test_lazy_imports.py +0 -0
  1025. {rigplane-2.7.2 → rigplane-2.8.0}/tests/e2e/package.json +0 -0
  1026. {rigplane-2.7.2 → rigplane-2.8.0}/tests/e2e/v2-ui-interactive.spec.ts +0 -0
  1027. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fake_rigctld.py +0 -0
  1028. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/civ_rx_frames.json +0 -0
  1029. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/hamlib_dump_caps_ts480.txt +0 -0
  1030. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/hamlib_rigctl_list.txt +0 -0
  1031. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_artifact_mixed.json +0 -0
  1032. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_artifact_reverse_sync_fail.json +0 -0
  1033. {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_template_ic7300.json +0 -0
  1034. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/dump_state_ic7610.txt +0 -0
  1035. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/dump_state_yaesu.txt +0 -0
  1036. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/fldigi_dual_rx_session.txt +0 -0
  1037. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/js8call_dual_rx_session.txt +0 -0
  1038. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/protocol_golden.json +0 -0
  1039. {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/wsjtx_dual_rx_session.txt +0 -0
  1040. {rigplane-2.7.2 → rigplane-2.8.0}/tests/hardware/test_ic7610_audio_pipeline.py +0 -0
  1041. {rigplane-2.7.2 → rigplane-2.8.0}/tests/hardware/test_x6200_serial_tx_smoke.py +0 -0
  1042. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/README.md +0 -0
  1043. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/conftest.py +0 -0
  1044. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/full_handshake.py +0 -0
  1045. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/logging_utils.py +0 -0
  1046. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/probe_handshake.py +0 -0
  1047. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/probe_login.py +0 -0
  1048. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_audio_integration.py +0 -0
  1049. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_audio_routing.py +0 -0
  1050. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_connect.py +0 -0
  1051. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_controls_extended_integration.py +0 -0
  1052. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_dsp_levels_integration.py +0 -0
  1053. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_get_freq.py +0 -0
  1054. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_media_scope_integration.py +0 -0
  1055. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_memory_set_only.py +0 -0
  1056. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_negative_auth_integration.py +0 -0
  1057. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_operator_toggles_integration.py +0 -0
  1058. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_radio_integration.py +0 -0
  1059. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_reliability_matrix_integration.py +0 -0
  1060. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_audio_pipeline.py +0 -0
  1061. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_golden_replay.py +0 -0
  1062. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_wsjtx.py +0 -0
  1063. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rit_tuner_integration.py +0 -0
  1064. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_scope_advanced_integration.py +0 -0
  1065. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_tone_tsql_integration.py +0 -0
  1066. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_vfo_dual_watch_integration.py +0 -0
  1067. {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_x6200_audio_scope_smoke.py +0 -0
  1068. {rigplane-2.7.2 → rigplane-2.8.0}/tests/mock_server.py +0 -0
  1069. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio.py +0 -0
  1070. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_analyzer.py +0 -0
  1071. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bridge_stereo.py +0 -0
  1072. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_codec.py +0 -0
  1073. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_codecs.py +0 -0
  1074. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_config.py +0 -0
  1075. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_dsp.py +0 -0
  1076. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_fft_scope.py +0 -0
  1077. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_fullduplex.py +0 -0
  1078. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_pipeline_harness.py +0 -0
  1079. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_pipeline_os_smoke.py +0 -0
  1080. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe.py +0 -0
  1081. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe_profile.py +0 -0
  1082. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe_runner.py +0 -0
  1083. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_recovery.py +0 -0
  1084. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_resample.py +0 -0
  1085. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_route.py +0 -0
  1086. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_rx_tx_transition.py +0 -0
  1087. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_scope_dispatch.py +0 -0
  1088. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_stress.py +0 -0
  1089. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_transcoder.py +0 -0
  1090. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_transcoder_coverage.py +0 -0
  1091. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_watchdog.py +0 -0
  1092. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audit.py +0 -0
  1093. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_auth.py +0 -0
  1094. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_authz_registry_gated.py +0 -0
  1095. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_backend_contract_matrix.py +0 -0
  1096. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_backend_factory.py +0 -0
  1097. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_bounded_queue.py +0 -0
  1098. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_bsr_band_switching.py +0 -0
  1099. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_circuit_breaker.py +0 -0
  1100. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ.py +0 -0
  1101. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_command_profiling.py +0 -0
  1102. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_coverage.py +0 -0
  1103. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_dispatch_golden.py +0 -0
  1104. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_mixin_host.py +0 -0
  1105. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_short_frame_robustness.py +0 -0
  1106. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_transaction_ownership.py +0 -0
  1107. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli.py +0 -0
  1108. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_async.py +0 -0
  1109. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_coverage.py +0 -0
  1110. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_diagnose.py +0 -0
  1111. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_diagnose_lazy_import.py +0 -0
  1112. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_e2e.py +0 -0
  1113. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_model.py +0 -0
  1114. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cmd29_parsing.py +0 -0
  1115. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_catalog_docs.py +0 -0
  1116. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_map_integration.py +0 -0
  1117. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_spec.py +0 -0
  1118. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commander.py +0 -0
  1119. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commands.py +0 -0
  1120. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commands_extended.py +0 -0
  1121. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_convert.py +0 -0
  1122. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_convert_cli.py +0 -0
  1123. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cw_auto_tune_wiring.py +0 -0
  1124. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cw_auto_tuner.py +0 -0
  1125. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_data_mode.py +0 -0
  1126. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_delta_encoder.py +0 -0
  1127. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_bundle.py +0 -0
  1128. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributor.py +0 -0
  1129. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch1.py +0 -0
  1130. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch2.py +0 -0
  1131. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch3.py +0 -0
  1132. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_e2e.py +0 -0
  1133. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_logging.py +0 -0
  1134. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_privacy_invariants.py +0 -0
  1135. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_redaction.py +0 -0
  1136. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_upload.py +0 -0
  1137. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_discovery.py +0 -0
  1138. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_docs_runtime_sync.py +0 -0
  1139. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_filter_family.py +0 -0
  1140. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_levels_part1.py +0 -0
  1141. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_levels_part2.py +0 -0
  1142. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_nodes.py +0 -0
  1143. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_nr_scipy.py +0 -0
  1144. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_pipeline.py +0 -0
  1145. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dx_cluster.py +0 -0
  1146. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_env_config.py +0 -0
  1147. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_exports.py +0 -0
  1148. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_fake_rigctld.py +0 -0
  1149. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_frontend_e2e_config.py +0 -0
  1150. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ftx1_audio.py +0 -0
  1151. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ftx1_radio.py +0 -0
  1152. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_golden_protocol.py +0 -0
  1153. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_dump_caps.py +0 -0
  1154. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_external_rigctld_contract.py +0 -0
  1155. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_models.py +0 -0
  1156. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_probe.py +0 -0
  1157. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_dsp_407_408.py +0 -0
  1158. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_protocol_gap_399.py +0 -0
  1159. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_sys_band.py +0 -0
  1160. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic705.py +0 -0
  1161. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic705_backend.py +0 -0
  1162. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic7300_backend.py +0 -0
  1163. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic7610_parity_matrix.py +0 -0
  1164. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic9700_backend.py +0 -0
  1165. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom7610_serial_radio.py +0 -0
  1166. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom_lan_shim.py +0 -0
  1167. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom_receiver_tier.py +0 -0
  1168. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_issue_141_core_refactor.py +0 -0
  1169. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_jitter_buffer.py +0 -0
  1170. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_lifecycle_diagnostics.py +0 -0
  1171. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_macos_audio_uid.py +0 -0
  1172. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_main_sub_tracking.py +0 -0
  1173. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_managed_runtime_packaging_doc.py +0 -0
  1174. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_memory_commands.py +0 -0
  1175. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_mock_integration.py +0 -0
  1176. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_naming_parity.py +0 -0
  1177. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_operator_toggles.py +0 -0
  1178. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_overrides.py +0 -0
  1179. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_pcm_e2e.py +0 -0
  1180. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_per_receiver_vfo_roundtrip.py +0 -0
  1181. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_performance_regressions.py +0 -0
  1182. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_platformdirs_migration.py +0 -0
  1183. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_poller.py +0 -0
  1184. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_poller_coverage.py +0 -0
  1185. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_power_unit_extension.py +0 -0
  1186. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_profiles_routing.py +0 -0
  1187. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_profiles_runtime.py +0 -0
  1188. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_protocol.py +0 -0
  1189. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_proxy.py +0 -0
  1190. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_proxy_coverage.py +0 -0
  1191. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_public_api_surface.py +0 -0
  1192. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio.py +0 -0
  1193. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_connect.py +0 -0
  1194. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_coverage.py +0 -0
  1195. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_extended.py +0 -0
  1196. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_poller_coverage.py +0 -0
  1197. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_protocol.py +0 -0
  1198. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_state.py +0 -0
  1199. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_validate.py +0 -0
  1200. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radios.py +0 -0
  1201. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rate_limiter.py +0 -0
  1202. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_raw_civ_pipe.py +0 -0
  1203. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_raw_civ_transaction.py +0 -0
  1204. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rf_gain_af_level.py +0 -0
  1205. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_ic7300.py +0 -0
  1206. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_ic7610.py +0 -0
  1207. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_loader.py +0 -0
  1208. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_multi_vendor.py +0 -0
  1209. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_schema.py +0 -0
  1210. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_client_backend.py +0 -0
  1211. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_consistency.py +0 -0
  1212. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_dump_state_snapshot.py +0 -0
  1213. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_handler.py +0 -0
  1214. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_init_coverage.py +0 -0
  1215. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_protocol.py +0 -0
  1216. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_routable_extension.py +0 -0
  1217. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_server.py +0 -0
  1218. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_server_coverage.py +0 -0
  1219. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_utils.py +0 -0
  1220. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope.py +0 -0
  1221. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_render.py +0 -0
  1222. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_render_coverage.py +0 -0
  1223. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_stress.py +0 -0
  1224. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_security_headers.py +0 -0
  1225. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_selected_freq_mode.py +0 -0
  1226. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_backend_smoke.py +0 -0
  1227. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_backend_tx_mor242.py +0 -0
  1228. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_civ_link.py +0 -0
  1229. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_session.py +0 -0
  1230. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_stub_framing.py +0 -0
  1231. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_server_wire.py +0 -0
  1232. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_shared_state_runtime.py +0 -0
  1233. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_single_rx_plain_routing.py +0 -0
  1234. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_cache.py +0 -0
  1235. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_cache_coverage.py +0 -0
  1236. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_pollable_extension.py +0 -0
  1237. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_queries.py +0 -0
  1238. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_supports_command.py +0 -0
  1239. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_swr_calibration.py +0 -0
  1240. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_sync.py +0 -0
  1241. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_sync_coverage.py +0 -0
  1242. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tap_registry.py +0 -0
  1243. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tls.py +0 -0
  1244. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_token_renewal.py +0 -0
  1245. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tone_tsql.py +0 -0
  1246. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_transport.py +0 -0
  1247. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tx_band_edge.py +0 -0
  1248. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_capable_extension.py +0 -0
  1249. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_channel_clamp_mor238.py +0 -0
  1250. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_resolve.py +0 -0
  1251. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_stub.py +0 -0
  1252. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validate_hamlib_provider.py +0 -0
  1253. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validate_overrides.py +0 -0
  1254. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_comparison.py +0 -0
  1255. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_runner.py +0 -0
  1256. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_schema.py +0 -0
  1257. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_templates.py +0 -0
  1258. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_vfo_dual_watch.py +0 -0
  1259. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_vox_tone_state.py +0 -0
  1260. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_api_contract.py +0 -0
  1261. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_audio_streaming_profile.py +0 -0
  1262. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_auth_compare_digest.py +0 -0
  1263. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_capability_guards.py +0 -0
  1264. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_command_batch_http.py +0 -0
  1265. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_cw_http_control.py +0 -0
  1266. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_diagnostics.py +0 -0
  1267. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_post_body_cap.py +0 -0
  1268. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_ptt_readonly.py +0 -0
  1269. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_runtime_helpers.py +0 -0
  1270. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server.py +0 -0
  1271. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server_coverage.py +0 -0
  1272. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server_token_redaction.py +0 -0
  1273. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_webrtc_signaling.py +0 -0
  1274. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_websocket_coverage.py +0 -0
  1275. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_x6200_rx_audio_mor236.py +0 -0
  1276. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_audio.py +0 -0
  1277. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_parser.py +0 -0
  1278. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_poller.py +0 -0
  1279. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_transport.py +0 -0
  1280. {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cli_factory.py +0 -0
  1281. {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_generator.py +0 -0
  1282. {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_generator_hamlib.py +0 -0
  1283. {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_hardware.py +0 -0
  1284. {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rigplane
3
- Version: 2.7.2
3
+ Version: 2.8.0
4
4
  Summary: Multi-vendor radio control library and Web UI with native providers and planned Hamlib-backed CAT coverage
5
5
  Project-URL: Homepage, https://rigplane.dev/
6
6
  Project-URL: Documentation, https://rigplane.dev/
@@ -11,6 +11,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [2.8.0] — 2026-06-02
15
+
16
+ ### Added
17
+
18
+ - Web transport: added a backend-neutral `Connection` protocol and retargeted
19
+ the control, scope, and audio handlers to depend on that transport seam rather
20
+ than the concrete WebSocket wrapper. This is a no-behaviour-change foundation
21
+ for alternate transports (MOR-274, #1701, 8f2b6c5b).
22
+ - WebRTC transport foundation: added optional `WebRtcDataChannelConnection`
23
+ support behind the `[webrtc]` extra, including an ordered/reliable `control`
24
+ DataChannel that drives the unchanged control handler with the same wire frame
25
+ shape as the WebSocket path (MOR-312, #1707, 047dea74).
26
+ - WebRTC multi-channel support: added `scope` and `audio` DataChannel helpers
27
+ on the same peer connection, configured unordered and lossy
28
+ (`maxRetransmits=0`) while reusing the same connection adapter and unchanged
29
+ handlers (MOR-306, #1710, f1dad721).
30
+ - Discovery: `DiscoveryResponder` can now advertise a station fleet through an
31
+ additive `radios[]` array with per-radio ids, models, urls, status, and
32
+ connection state, while preserving the legacy single-radio top-level fields
33
+ for existing discovery clients (MOR-303, #1705, eb4e2a98).
34
+
35
+ ### Changed
36
+
37
+ - Audio bus lifecycle: subscriptions now have an awaited close path and bridge
38
+ teardown waits for subscriber removal, reducing restart races and keeping
39
+ rapid start/stop diagnostics deterministic (#1568, #1708, dae97577).
40
+ - Realtime TX queue policy: bridge TX overflow now evicts the oldest queued
41
+ audio frame and keeps the newest live capture frame, preserving bounded
42
+ latency while continuing to count overruns (#1565, #1708, dae97577).
43
+ - Public docs now clarify WSJT-X loopback device direction, advisory
44
+ `/api/v1/audio` `frame_ms` semantics, validation workflow status, and command
45
+ catalog stability boundaries (#1567, #1708, dae97577).
46
+
47
+ ### Fixed
48
+
49
+ - External CAT reconnect: a leaked external-CAT ownership flag is now reset on
50
+ radio reconnect, so rigctld and web pollers resume instead of serving stale
51
+ frequency/state after a managed runtime restart (MOR-301, #1703, c3cb411d).
52
+ - Hamlib bridge startup: partial `open_transport()` failures after CAT session
53
+ acquisition now release ownership, preventing a failed listener/server setup
54
+ from leaving pollers paused (#1703, c3cb411d).
55
+ - Web audio TX cleanup: active PCM/Opus TX is now stopped or safely released
56
+ when an audio websocket disconnects, is cancelled, or exits with an exception;
57
+ explicit `audio_stop` behavior is preserved (#1566, #1708, dae97577).
58
+
59
+ ## [2.7.3] — 2026-05-31
60
+
61
+ ### Fixed
62
+
63
+ - Windows FT8 TX delivered no audio (Po=0 W): the callback/`blocksize=0` TX
64
+ capture emitted 960-byte (10 ms) frames while the PCM TX validator requires
65
+ 1920-byte (20 ms) frames; capture now re-chunks the continuous callback stream
66
+ into fixed 20 ms frames (keeps the ~50 Hz comb fix; lossless) (MOR-256, #1699,
67
+ 17492be6)
68
+
69
+ ### Changed
70
+
71
+ - Build (packaging): build the web UI during packaging so source/git installs
72
+ bundle the SPA (#1698, 55a0f81f)
73
+
14
74
  ## [2.7.2] — 2026-05-30
15
75
 
16
76
  ### Fixed
@@ -1543,7 +1603,9 @@ These deprecation closures were announced in v0.19 and dropped on schedule.
1543
1603
  - Transport layer, authentication, CI-V commands, meters, PTT, keep-alive.
1544
1604
  - Clean-room Icom LAN UDP protocol implementation.
1545
1605
 
1546
- [Unreleased]: https://github.com/rigplane/rigplane-core/compare/v2.7.2...HEAD
1606
+ [Unreleased]: https://github.com/rigplane/rigplane-core/compare/v2.8.0...HEAD
1607
+ [2.8.0]: https://github.com/rigplane/rigplane-core/compare/v2.7.3...v2.8.0
1608
+ [2.7.3]: https://github.com/rigplane/rigplane-core/compare/v2.7.2...v2.7.3
1547
1609
  [2.7.2]: https://github.com/rigplane/rigplane-core/compare/v2.7.1...v2.7.2
1548
1610
  [2.7.1]: https://github.com/rigplane/rigplane-core/compare/v2.7.0...v2.7.1
1549
1611
  [2.7.0]: https://github.com/rigplane/rigplane-core/compare/v2.6.0...v2.7.0
@@ -323,7 +323,7 @@ IC-7610 parity matrix (issue #139, 2026-03-06): 134 implemented, 0 partial, 0 mi
323
323
 
324
324
  ### Phase 12 — Dual VFO / Dual Receiver architecture overhaul (#708) 🚧 IN PROGRESS
325
325
 
326
- **Goal:** Public `Radio` protocol expresses `Transceiver → Receiver → VFO` unambiguously across IC-7610, IC-9700, IC-7300, IC-705 and FTX-1, with no model-specific branches at call sites. Audit: `.claude/workflow/dual-vfo-audit.md`; architecture: `.claude/architecture/protocol.md` "Receiver tier"; schema: `rigs/_schema_v2.md`. Landed foundation: #709 (`VfoSlotState` + per-receiver `active_slot` on `ReceiverState`), #710 (split TOML `swap_ab`/`equal_ab` vs `swap_main_sub`/`equal_main_sub` with legacy `swap`/`equal` deprecation), #711 (`ReceiverBankCapable` + `VfoSlotCapable` runtime-checkable Protocols), #713 (IC-9700 profile rewritten as `scheme = "main_sub"` with empty `cmd29.routes` per wfview `HasCommand29=false`). Pending: #712 `TransceiverBankCapable` for FTX-1, plus the phase 2–4 backend, frontend and rigctld wiring tracked under epic #708.
326
+ **Goal:** Public `Radio` protocol expresses `Transceiver → Receiver → VFO` unambiguously across IC-7610, IC-9700, IC-7300, IC-705 and FTX-1, with no model-specific branches at call sites. Audit: `.claude/workflow/dual-vfo-audit.md`; architecture: `.claude/architecture/protocol.md` "Receiver tier"; schema: `rigs/_schema_v2.md`. Landed foundation: #709 (`VfoSlotState` + per-receiver `active_slot` on `ReceiverState`), #710 (split TOML `swap_ab`/`equal_ab` vs `swap_main_sub`/`equal_main_sub` with legacy `swap`/`equal` deprecation), #711 (`ReceiverBankCapable` + `VfoSlotCapable` runtime-checkable Protocols), #713 (IC-9700 profile rewritten as `scheme = "main_sub"` with empty `cmd29.routes` per wfview `HasCommand29=false`), #712 (FTX-1 `TransceiverBankCapable` foundation), #716 (backend/API split wiring), and #727 (cross-band split backend/API regression coverage). Cross-band split backend/API tests now cover the implemented foundation. Remaining work is frontend and hardware polish plus any incremental rigctld/user-experience follow-up tracked under epic #708.
327
327
 
328
328
  ### Reliability Test Expansion (2026-03-05)
329
329
  - Added extended integration coverage scaffolding for:
@@ -117,6 +117,10 @@ machine-readable HTTP/WS command catalog — every command name, parameter shape
117
117
  capability gate, and batch-eligibility flag — is published in
118
118
  [HTTP / WebSocket Command Catalog](command-catalog.md).
119
119
 
120
+ The catalog documents the current command surface. A route or command is not a
121
+ stable API contract solely because it appears there; stability still comes from
122
+ explicit promotion into `rigplane.web.api_contract`.
123
+
120
124
  ### Internal And Diagnostic Surface
121
125
 
122
126
  Browser static files, `src/rigplane/web/static*`, handler class names, queue
@@ -952,6 +956,24 @@ and reports `scopeSource: "audio_fft"`.
952
956
  | `/api/v1/scope` | server -> client | Binary scope frames |
953
957
  | `/api/v1/audio` | bi-directional | JSON control + binary audio frames |
954
958
 
959
+ Binary audio frames use an 8-byte header followed by codec-specific payload:
960
+
961
+ | Offset | Size | Field | Notes |
962
+ |--------|------|-------|-------|
963
+ | `0` | 1 | `msg_type` | `0x10` RX, `0x11` TX |
964
+ | `1` | 1 | `codec` | `0x01` Opus, `0x02` PCM16 |
965
+ | `2` | 2 | `sequence` | uint16 little-endian |
966
+ | `4` | 2 | `sample_rate` | encoded as Hz / 100, uint16 little-endian |
967
+ | `6` | 1 | `channels` | `1` mono, `2` stereo |
968
+ | `7` | 1 | `frame_ms` | advisory frame-duration label |
969
+ | `8..` | variable | payload | codec-specific audio bytes |
970
+
971
+ `frame_ms` is advisory. Consumers must derive actual audio length from the
972
+ payload and metadata, not from a fixed frame-duration assumption. For PCM16,
973
+ use `payload_bytes / (channels * 2)` to compute sample frames and use the
974
+ header sample rate for playback timing; Opus consumers should decode the
975
+ payload and use decoder output metadata.
976
+
955
977
  ### `/api/v1/ws` command envelope
956
978
 
957
979
  ```json
@@ -13,9 +13,9 @@ validation matrix for one radio) and validation **artifacts** (the recorded
13
13
  evidence of a run). It is the spec that `rigplane.validation` builds against and
14
14
  that any tooling consuming validation output should target.
15
15
 
16
- The current release ships the **dry-run** path only. The artifact shape is
17
- forward-compatible with hardware runs, but hardware execution is intentionally
18
- not implemented and is double-gated (see [Safety policy](#safety-policy)).
16
+ The current release supports dry-run planning and gated hardware execution. The
17
+ artifact shape covers both modes, and hardware execution is double-gated (see
18
+ [Safety policy](#safety-policy)).
19
19
 
20
20
  ## Core boundary
21
21
 
@@ -140,9 +140,10 @@ skipped.
140
140
 
141
141
  Hardware execution is additionally double-gated at the CLI: `--hardware`
142
142
  requires both the `--allow-hardware` flag and the
143
- `RIGPLANE_VALIDATION_ALLOW_HARDWARE=1` environment variable. Even with both
144
- gates open, the current release refuses hardware runs (exit code `3`) because
145
- the hardware path is not implemented.
143
+ `RIGPLANE_VALIDATION_ALLOW_HARDWARE=1` environment variable. With both gates
144
+ open, the runner executes against hardware and emits a `mode: "hardware"`
145
+ artifact. If either gate is missing, the CLI keeps the run in the safe planning
146
+ path and does not touch a radio.
146
147
 
147
148
  ## Versioning
148
149
 
@@ -33,6 +33,12 @@ a diagnostic report includes `radio_native.requested`,
33
33
  `radio_native.effective`, and `web_rx` when those values are available or
34
34
  configured.
35
35
 
36
+ For WebSocket audio frames, `frame_ms` is a timing label, not an allocation
37
+ contract. Consumers should derive the actual buffer length from the payload and
38
+ frame metadata: codec, sample rate, channel count, bytes per sample for PCM, and
39
+ the binary payload size. Browser/client code must not assume every frame has a
40
+ fixed duration or fixed payload length.
41
+
36
42
  `ICOM_AUDIO_SAMPLE_RATE` remains an operator override. Set it when you need to
37
43
  force the direct LAN conninfo sample rate for testing, hardware compatibility,
38
44
  or bandwidth-constrained tunnel paths:
@@ -347,17 +353,29 @@ Run Web UI + audio bridge + rigctld in a single command:
347
353
  ```bash
348
354
  # Install (audio-bridge deps ship with the core install since v0.19)
349
355
  pip install rigplane
350
- brew install blackhole-2ch # macOS
356
+ brew install blackhole-2ch blackhole-16ch # macOS
351
357
 
352
358
  # Start everything
353
359
  rigplane --host 192.168.1.100 --user USER --pass PASS \
354
- web --bridge "BlackHole 2ch"
360
+ web --bridge "BlackHole 2ch" --bridge-tx-device "BlackHole 16ch"
355
361
 
356
362
  # WSJT-X settings:
357
363
  # Radio: Hamlib NET rigctl, localhost:4532
358
- # Audio Input/Output: BlackHole 2ch
364
+ # Audio Input: BlackHole 2ch
365
+ # Audio Output: BlackHole 16ch
359
366
  ```
360
367
 
368
+ The direction matters:
369
+
370
+ - `--bridge "BlackHole 2ch"` is the RX playback loopback:
371
+ **radio RX → rigplane → BlackHole 2ch → WSJT-X Input**.
372
+ - `--bridge-tx-device "BlackHole 16ch"` is the TX capture loopback:
373
+ **WSJT-X Output → BlackHole 16ch → rigplane → radio TX**.
374
+
375
+ Use two separate loopback devices for bidirectional operation. Reusing one
376
+ device for both WSJT-X input and output can feed rigplane's RX audio back into
377
+ its TX capture path.
378
+
361
379
  ---
362
380
 
363
381
  ## Heavy usage and deployment
@@ -0,0 +1,68 @@
1
+ """Hatchling build hook that bundles the Svelte web UI into the package.
2
+
3
+ The frontend lives in ``frontend/`` and its build output (``frontend/dist``)
4
+ is gitignored. At runtime the SPA is served from ``src/rigplane/web/static``,
5
+ so the package must ship the built assets at that location.
6
+
7
+ This hook makes every build target (wheel *and* sdist) self-contained:
8
+
9
+ * If ``frontend/dist/index.html`` is missing and a ``frontend/`` source tree is
10
+ present, it builds the SPA with ``npm`` (``npm ci``/``npm install`` then
11
+ ``npm run build``). If ``npm`` is unavailable and no prebuilt dist exists, it
12
+ raises a clear ``RuntimeError`` so the failure is actionable.
13
+ * If ``frontend/dist/index.html`` already exists, the npm build is skipped — the
14
+ hook is idempotent, so the PyPI publish flow (which prebuilds the frontend)
15
+ does not rebuild it.
16
+ * The built ``frontend/dist`` is force-included at ``src/rigplane/web/static``
17
+ for whichever target is building, centralizing the mapping in one place.
18
+
19
+ Without this, ``pip install git+https://...`` (a direct wheel build) would not
20
+ bundle the SPA and the desktop UI would 404.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import shutil
26
+ import subprocess
27
+ from pathlib import Path
28
+ from typing import Any
29
+
30
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
31
+
32
+ # Runtime location the installed package serves the SPA from. Must not change.
33
+ _RUNTIME_STATIC = "src/rigplane/web/static"
34
+
35
+
36
+ class FrontendBuildHook(BuildHookInterface): # type: ignore[type-arg]
37
+ """Build the web UI (if needed) and bundle it into the package."""
38
+
39
+ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
40
+ root = Path(self.root)
41
+ frontend_dir = root / "frontend"
42
+ dist_index = frontend_dir / "dist" / "index.html"
43
+
44
+ if not dist_index.exists() and frontend_dir.is_dir():
45
+ self._build_frontend(frontend_dir)
46
+
47
+ # Inject the force-include so the SPA lands at the runtime location for
48
+ # whichever target (wheel or sdist) is building.
49
+ force_include = build_data.setdefault("force_include", {})
50
+ force_include["frontend/dist"] = _RUNTIME_STATIC
51
+
52
+ def _build_frontend(self, frontend_dir: Path) -> None:
53
+ npm = shutil.which("npm")
54
+ if npm is None:
55
+ raise RuntimeError(
56
+ "Building rigplane from source requires Node.js/npm to build "
57
+ "the web UI (frontend/dist is not present and could not be "
58
+ "built). Install Node.js/npm, or build a wheel/sdist on a "
59
+ "machine that has them (the resulting artifact is "
60
+ "self-contained and needs no Node.js to install)."
61
+ )
62
+
63
+ lockfile = frontend_dir / "package-lock.json"
64
+ install_cmd = [npm, "ci"] if lockfile.exists() else [npm, "install"]
65
+
66
+ self.app.display_info("Building rigplane web UI (npm)...")
67
+ subprocess.run(install_cmd, cwd=frontend_dir, check=True)
68
+ subprocess.run([npm, "run", "build"], cwd=frontend_dir, check=True)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "rigplane"
7
- version = "2.7.2"
7
+ version = "2.8.0"
8
8
  description = "Multi-vendor radio control library and Web UI with native providers and planned Hamlib-backed CAT coverage"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -74,12 +74,22 @@ dev = [
74
74
 
75
75
  [tool.hatch.build.targets.wheel]
76
76
  packages = ["src/rigplane", "src/icom_lan"]
77
+ # The web UI is placed at src/rigplane/web/static exclusively via the custom
78
+ # build hook's force-include (see hatch_build.py). When building a wheel from an
79
+ # sdist (uv build's default sdist->wheel chain), the sdist has already
80
+ # materialized src/rigplane/web/static on disk; exclude it from normal project
81
+ # file selection so the force-include is the single source and the tree is not
82
+ # bundled twice.
83
+ exclude = ["src/rigplane/web/static"]
77
84
 
78
85
  [tool.hatch.build.targets.wheel.force-include]
79
86
  "rigs" = "rigplane/rigs"
80
87
 
81
- [tool.hatch.build.targets.sdist.force-include]
82
- "frontend/dist" = "src/rigplane/web/static"
88
+ # Builds the Svelte web UI during packaging (if not prebuilt) and force-includes
89
+ # the result at src/rigplane/web/static for BOTH wheel and sdist targets, so
90
+ # source/git installs are self-contained. See hatch_build.py.
91
+ [tool.hatch.build.hooks.custom]
92
+ path = "hatch_build.py"
83
93
 
84
94
  [tool.pytest.ini_options]
85
95
  asyncio_mode = "auto"
@@ -10,7 +10,6 @@ opening RX/TX audio streams, plus two concrete implementations:
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import asyncio
14
13
  import logging
15
14
  import math
16
15
  import threading
@@ -228,7 +227,35 @@ def _ensure_portaudio_deps() -> tuple[Any, Any]:
228
227
 
229
228
 
230
229
  class _PortAudioRxStream:
231
- """RxStream backed by a sounddevice InputStream."""
230
+ """RxStream backed by a callback-driven sounddevice InputStream.
231
+
232
+ Capture is clocked by PortAudio's own audio thread via an ``InputStream``
233
+ callback, mirroring the callback design of :class:`_PortAudioTxStream`.
234
+ This replaces the previous fixed-``blocksize=960`` blocking-read loop
235
+ (``stream.read(960)`` on a worker thread), whose 20 ms read straddled the
236
+ WASAPI shared-mode engine period (~10 ms) and dropped/duplicated a sample
237
+ run once per block, producing a ~50 Hz spectral comb on captured TX audio
238
+ on Windows. The stream is opened with ``blocksize=0`` (engine-native
239
+ period), mirroring a known-clean ``sd.rec`` capture. The earlier WDM-KS
240
+ capture face rejected ``blocksize=0`` (PortAudioError -9999), but companion
241
+ device selection now forces the WASAPI host-API face, on which
242
+ ``blocksize=0`` opens cleanly.
243
+
244
+ The PortAudio callback runs on the audio thread and must not block. It
245
+ copies the captured PCM (s16le) out of the engine-native, variable-size
246
+ block and *re-chunks* it into fixed ``frame_ms``-sized frames before
247
+ handing them to the consumer *callback*. The downstream PCM-TX contract
248
+ requires fixed-size frames (e.g. 20 ms = 960 samples = 1920 bytes s16le
249
+ mono @ 48 kHz); a managed core validator rejects any frame whose byte
250
+ length differs. Re-chunking a *continuous* callback stream is lossless and
251
+ introduces no scheduling seam (the ~50 Hz comb came from the old
252
+ blocking-read inter-read gap, not from re-chunking), so this preserves the
253
+ fixed-frame contract without re-introducing the comb. Sub-frame remainders
254
+ are buffered across callbacks; a trailing partial frame at stop is dropped.
255
+ The consumer contract (see :class:`RxStream`) is that the callback is cheap
256
+ and thread-safe to invoke from the audio thread; the companion bridge
257
+ marshals onto its event loop via ``call_soon_threadsafe``.
258
+ """
232
259
 
233
260
  def __init__(
234
261
  self,
@@ -237,24 +264,40 @@ class _PortAudioRxStream:
237
264
  sample_rate: int,
238
265
  channels: int,
239
266
  blocksize: int,
267
+ frame_ms: int,
240
268
  ) -> None:
241
269
  self._sd = sd
242
270
  self._device_index = device_index
243
271
  self._sample_rate = sample_rate
244
272
  self._channels = channels
273
+ # Capture is callback-driven with blocksize=0 (engine-native period),
274
+ # mirroring a clean sd.rec. blocksize=0 was previously rejected by the
275
+ # WDM-KS capture face (PortAudioError -9999), but companion device
276
+ # selection now forces the WASAPI face, on which blocksize=0 opens.
245
277
  self._blocksize = blocksize
278
+ # Fixed delivered-frame size: frame_ms worth of audio frames, each
279
+ # ``channels`` interleaved s16le samples (2 bytes/sample). The PortAudio
280
+ # stream stays blocksize=0; only the size handed to ``cb`` is fixed.
281
+ frame_samples = (sample_rate * frame_ms) // 1000
282
+ self._frame_bytes = max(1, frame_samples * channels * 2)
246
283
  self._stream: Any = None
247
- self._task: asyncio.Task[None] | None = None
284
+ self._running = False
248
285
  self._callback: Callable[[bytes], None] | None = None
286
+ # Sub-frame remainder carried between audio-thread callbacks. The audio
287
+ # thread is the only writer, so no lock is needed.
288
+ self._accumulator = bytearray()
249
289
 
250
290
  @property
251
291
  def running(self) -> bool:
252
- return self._task is not None and not self._task.done()
292
+ return self._running
253
293
 
254
294
  async def start(self, callback: Callable[[bytes], None]) -> None:
255
295
  if self.running:
256
296
  raise RuntimeError("RX stream already running.")
257
297
  self._callback = callback
298
+ self._accumulator = bytearray()
299
+ # blocksize=0 (engine-native period) mirrors a clean sd.rec on the
300
+ # WASAPI face. latency="low" matches the (clean) output stream.
258
301
  self._stream = self._sd.InputStream(
259
302
  samplerate=self._sample_rate,
260
303
  channels=self._channels,
@@ -262,17 +305,19 @@ class _PortAudioRxStream:
262
305
  device=self._device_index,
263
306
  blocksize=self._blocksize,
264
307
  latency="low",
308
+ callback=self._input_callback,
265
309
  )
266
310
  self._stream.start()
267
- self._task = asyncio.create_task(self._loop(), name="portaudio-rx")
311
+ self._running = True
268
312
 
269
313
  async def stop(self) -> None:
270
314
  stream = self._stream
271
- task = self._task
272
315
  self._stream = None
273
- self._task = None
316
+ self._running = False
274
317
  self._callback = None
275
- # Close stream FIRST unblocks executor thread stuck in stream.read()
318
+ # Drop any sub-frame remainder: an incomplete trailing frame cannot
319
+ # satisfy the fixed-size contract and is discarded at teardown.
320
+ self._accumulator = bytearray()
276
321
  if stream is not None:
277
322
  try:
278
323
  stream.stop()
@@ -282,30 +327,44 @@ class _PortAudioRxStream:
282
327
  stream.close()
283
328
  except Exception:
284
329
  logger.debug("portaudio-rx: stream close failed", exc_info=True)
285
- # Now cancel the task (thread is already unblocked)
286
- if task is not None and not task.done():
287
- task.cancel()
288
- try:
289
- await task
290
- except asyncio.CancelledError:
291
- pass
292
330
 
293
- async def _loop(self) -> None:
294
- stream = self._stream
331
+ def _input_callback(
332
+ self,
333
+ indata: Any,
334
+ _frames: int,
335
+ _time_info: Any,
336
+ _status: Any,
337
+ ) -> None:
338
+ # Runs on PortAudio's audio thread: keep it non-blocking. Copy the
339
+ # captured PCM (s16le) out of the (reused, variable-size) input buffer,
340
+ # append it to the running accumulator, then slice off whole fixed-size
341
+ # frames and deliver each to the consumer. Re-chunking a continuous
342
+ # callback stream is lossless (every sample reaches the consumer in
343
+ # order) and adds no scheduling seam, so it keeps the fixed-frame
344
+ # contract without re-introducing the comb. The consumer is
345
+ # contractually cheap/thread-safe.
346
+ cb = self._callback
347
+ if cb is None:
348
+ return
295
349
  try:
296
- while True:
297
- data, _overflowed = await asyncio.to_thread(
298
- stream.read, self._blocksize
299
- )
300
- cb = self._callback
301
- if cb is None:
302
- continue
303
- pcm = bytes(data.tobytes()) if hasattr(data, "tobytes") else bytes(data)
304
- cb(pcm)
305
- except asyncio.CancelledError:
306
- pass
350
+ pcm = (
351
+ bytes(indata.tobytes()) if hasattr(indata, "tobytes") else bytes(indata)
352
+ )
353
+ except Exception:
354
+ logger.warning("portaudio-rx: capture copy failed", exc_info=True)
355
+ return
356
+ if not pcm:
357
+ return
358
+ acc = self._accumulator
359
+ acc.extend(pcm)
360
+ frame_bytes = self._frame_bytes
361
+ try:
362
+ while len(acc) >= frame_bytes:
363
+ frame = bytes(acc[:frame_bytes])
364
+ del acc[:frame_bytes]
365
+ cb(frame)
307
366
  except Exception:
308
- logger.warning("portaudio-rx: loop failed", exc_info=True)
367
+ logger.warning("portaudio-rx: consumer callback failed", exc_info=True)
309
368
 
310
369
 
311
370
  class _PortAudioTxStream:
@@ -795,13 +854,19 @@ class PortAudioBackend:
795
854
  frame_ms: int = 20,
796
855
  ) -> RxStream:
797
856
  sd, _ = self._ensure_deps()
798
- blocksize = (sample_rate * frame_ms) // 1000
857
+ # blocksize=0 lets PortAudio use the engine-native period, mirroring a
858
+ # clean ``sd.rec`` capture. This is safe now that companion device
859
+ # selection forces the WASAPI host-API face (the WDM-KS face that
860
+ # rejected blocksize=0 with PortAudioError -9999 is no longer chosen).
861
+ # The PortAudio capture period stays engine-native; frame_ms only sizes
862
+ # the fixed frames re-chunked out to the consumer callback.
799
863
  return _PortAudioRxStream(
800
864
  sd,
801
865
  device_index=int(device),
802
866
  sample_rate=sample_rate,
803
867
  channels=channels,
804
- blocksize=blocksize,
868
+ blocksize=0,
869
+ frame_ms=frame_ms,
805
870
  )
806
871
 
807
872
  def open_tx(
@@ -536,7 +536,7 @@ class AudioBridge:
536
536
  self._rx_task = None
537
537
 
538
538
  if self._subscription is not None:
539
- self._subscription.stop()
539
+ await self._subscription.aclose()
540
540
  self._subscription = None
541
541
 
542
542
  if self._tx_task and not self._tx_task.done():
@@ -737,7 +737,11 @@ class AudioBridge:
737
737
  try:
738
738
  self._tx_queue.put_nowait(frame)
739
739
  except asyncio.QueueFull:
740
+ # Keep TX latency bounded: preserve live capture by evicting stale
741
+ # queued audio rather than dropping the newest frame.
742
+ self._tx_queue.get_nowait()
740
743
  self._tx_overruns += 1
744
+ self._tx_queue.put_nowait(frame)
741
745
 
742
746
  async def _rx_loop(self) -> None:
743
747
  """Read packets from AudioBus subscription, decode, write to device."""
@@ -47,6 +47,7 @@ logger = logging.getLogger(__name__)
47
47
  __all__ = ["AudioBus", "AudioSubscription"]
48
48
 
49
49
  _DEFAULT_QUEUE_SIZE = 64
50
+ _DEFAULT_CLOSE_TIMEOUT = 2.0
50
51
 
51
52
 
52
53
  class AudioSubscription:
@@ -73,6 +74,7 @@ class AudioSubscription:
73
74
  maxsize=queue_size,
74
75
  )
75
76
  self._active = False
77
+ self._close_task: asyncio.Task[None] | None = None
76
78
  self._dropped = 0
77
79
  self._received = 0
78
80
 
@@ -94,16 +96,86 @@ class AudioSubscription:
94
96
  """Activate this subscription (registers with the bus)."""
95
97
  if self._active:
96
98
  return
99
+ if self._close_task is not None and not self._close_task.done():
100
+ await self._close_task
97
101
  self._active = True
98
102
  await self._bus._add_subscriber(self)
99
103
 
100
104
  def stop(self) -> None:
101
- """Deactivate this subscription (unregisters from the bus)."""
105
+ """Deactivate this subscription and schedule bus removal.
106
+
107
+ This method is intentionally synchronous for backward compatibility.
108
+ Prefer :meth:`aclose` in async teardown paths when callers need to know
109
+ removal has completed.
110
+ """
102
111
  if not self._active:
103
112
  return
104
113
  self._active = False
105
- # Schedule async removal; we can't await in sync context
106
- asyncio.create_task(self._bus._remove_subscriber(self))
114
+ self._schedule_close()
115
+
116
+ async def aclose(self, timeout: float | None = _DEFAULT_CLOSE_TIMEOUT) -> None:
117
+ """Deactivate this subscription and await bus removal.
118
+
119
+ Args:
120
+ timeout: Maximum seconds to wait for teardown. ``None`` disables
121
+ the timeout for callers that intentionally want unbounded
122
+ cleanup.
123
+ """
124
+ if not self._active and self._close_task is None:
125
+ return
126
+ self._active = False
127
+
128
+ task = self._close_task
129
+ if task is None:
130
+ close_coro = self._bus._remove_subscriber(self)
131
+ if timeout is None:
132
+ await close_coro
133
+ else:
134
+ try:
135
+ await asyncio.wait_for(close_coro, timeout=timeout)
136
+ except asyncio.TimeoutError:
137
+ logger.warning(
138
+ "audio-bus: timed out closing subscriber %r",
139
+ self.name,
140
+ )
141
+ return
142
+
143
+ try:
144
+ if timeout is None:
145
+ await task
146
+ else:
147
+ await asyncio.wait_for(asyncio.shield(task), timeout=timeout)
148
+ except asyncio.TimeoutError:
149
+ logger.warning(
150
+ "audio-bus: timed out closing subscriber %r",
151
+ self.name,
152
+ )
153
+ task.cancel()
154
+ try:
155
+ await task
156
+ except asyncio.CancelledError:
157
+ pass
158
+
159
+ def _schedule_close(self) -> None:
160
+ """Schedule async bus removal for synchronous ``stop()`` callers."""
161
+ if self._close_task is not None and not self._close_task.done():
162
+ return
163
+ task = asyncio.create_task(self._bus._remove_subscriber(self))
164
+ self._close_task = task
165
+ task.add_done_callback(self._on_close_done)
166
+
167
+ def _on_close_done(self, task: asyncio.Task[None]) -> None:
168
+ if self._close_task is task:
169
+ self._close_task = None
170
+ try:
171
+ task.result()
172
+ except asyncio.CancelledError:
173
+ pass
174
+ except Exception:
175
+ logger.debug(
176
+ "audio-bus: subscriber close task failed",
177
+ exc_info=True,
178
+ )
107
179
 
108
180
  def deliver(self, packet: AudioPacket | None) -> None:
109
181
  """Called by the bus to deliver a packet (non-blocking)."""
@@ -155,7 +227,7 @@ class AudioSubscription:
155
227
  return self
156
228
 
157
229
  async def __aexit__(self, *exc: Any) -> None:
158
- self.stop()
230
+ await self.aclose()
159
231
 
160
232
 
161
233
  class AudioBus:
@@ -260,6 +332,6 @@ class AudioBus:
260
332
  async def stop(self) -> None:
261
333
  """Stop the bus and all subscribers."""
262
334
  for sub in list(self._subscribers):
263
- sub.stop()
335
+ await sub.aclose()
264
336
  if self._rx_active:
265
337
  await self._stop_rx()