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.
- {rigplane-2.7.2 → rigplane-2.8.0}/PKG-INFO +1 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/CHANGELOG.md +63 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/PROJECT.md +1 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/web.md +22 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/validation-matrix-v1.md +7 -6
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/audio-recipes.md +21 -3
- rigplane-2.8.0/hatch_build.py +68 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/pyproject.toml +13 -3
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/backend.py +96 -31
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/bridge.py +5 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/bus.py +77 -5
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/hamlib_bridge.py +23 -6
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio.py +19 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/discovery.py +60 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/audio.py +96 -15
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/control.py +3 -2
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/scope.py +3 -2
- rigplane-2.8.0/src/rigplane/web/transport/__init__.py +14 -0
- rigplane-2.8.0/src/rigplane/web/transport/connection.py +50 -0
- rigplane-2.8.0/src/rigplane/web/transport/webrtc.py +202 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_backend.py +193 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bridge.py +33 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bus.py +71 -20
- rigplane-2.8.0/tests/test_audio_capture_tx_validator_seam.py +312 -0
- rigplane-2.8.0/tests/test_audio_tx_contract_consistency.py +244 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_discovery_responder.py +144 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_bridge.py +15 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_coverage.py +91 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_reconnect.py +41 -0
- rigplane-2.8.0/tests/test_web_transport_connection.py +116 -0
- rigplane-2.8.0/tests/test_webrtc_datachannel_connection.py +335 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/uv.lock +1 -1
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/analyze-failure.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/audit-ui.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/decompose-issue.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/generate-tests.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/next.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/refactor.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/regression-check.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/scan-issues.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/commands/solve-issue.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.claude/skills/release/SKILL.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/epic.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/radio_report.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/ISSUE_TEMPLATE/ui-component.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/pull_request_template.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/scripts/check-rebrand-allowlist.sh +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/agent-review-gate.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/docs.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/full.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/publish.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/quick.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.github/workflows/rebrand-gate.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.gitignore +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/.importlinter +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/AGENTS.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/ARCHITECTURE.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/CHANGELOG.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/CLAUDE.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/CONTRIBUTING.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/LICENSE +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/README.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/ROADMAP.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/_config.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/arrl-hf.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/broadcast.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/iaru-r1.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/band-plans/utility.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/4f4bcd28cb8d426ca58ec08b5035541e.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/AUDIO_STREAMING_PROFILE.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/CNAME +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/EXTENDED_PROTOCOL_RESEARCH.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/PERFORMANCE.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/SECURITY.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/audio.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/auth.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends-icom7610-drivers.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends-icom7610.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/backends.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/command-catalog.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/commander.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/commands.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/exceptions.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/public-api-surface.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/radio.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/radios.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/rig-loader.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/rigctld.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/scope.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/sync.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/transport.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/api/types.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/architecture/open-core-policy.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/assets/scope-example.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/capabilities-matrix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/diagnostic-bundle-v1.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/contracts/diagnostic-bundle-v2.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/cli.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/commands.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/configuration.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/connection.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/diagnostic-reports.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/hamlib-rigctld-provider.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic705-usb-setup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic7300-usb-setup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic7610-usb-setup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/ic9700-usb-setup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/installation.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/profiles.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/quickstart.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/radios.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/rig-profiles.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/troubleshooting.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/web-ui.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/guide/wsjtx-setup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/core-string-inventory.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/locale-contract.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/i18n/translating.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/index.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/architecture.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/cli-design.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/contributing.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/github-project-workflow.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/hamlib-provider-rollout.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/protocol.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/raw-civ-transactions.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/reliability-semantics.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/internals/rfc-audio-v1-mini.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/migrate.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/operations/managed-runtime-packaging.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/opuslib-macos-fix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/overrides/main.html +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/README.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/ic7610_command_matrix.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/parity/test_mapping.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-03-07-ui-architecture.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-05-desktop-companion-architecture.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-09-audio-backend-design.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-frontend-migration-plan.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-parity-matrix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-presentation-architecture.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-rx-audio-trace.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-shared-frontend-runtime-contract.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-11-v2-lcd-runtime-audit.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-12-architecture-presentation.html +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-12-target-frontend-architecture.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-desktop-meters-panel.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-lcd-display-enhancements.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-mobile-ia.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-receiver-activation.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-spectrum-controls.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-18-ui-refinements-execution.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-19-lcd-layout-redesign-v2.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-19-lcd-layout-redesign.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-modularization-discovery.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-modularization-plan.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-panel-adapter-migration.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-04-29-ui-v1-deprecation-audit.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-03-diagnostic-data-collection-design.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-07-audio-route-resolver-design.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-capability-probing.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-codec-policy.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-audio-profile-policy-audit.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-08-usb-audio-negotiation.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-23-hamlib-provider-contract.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-28-real-radio-validation-matrix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/2026-05-28-universal-validation-matrix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-03-04-dx-cluster.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-03-m5-m6-roadmap.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/archive/2026-04-19-lcd-twin-skins.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/build_orphan_report.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/classify_cycle_edges.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/cycles-classified.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/cycles.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/discovery_graph.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/external-usage.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/file-inventory.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/file-inventory.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/import-graph.dot +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/importlinter-config-draft.ini +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/init-snapshot.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/orphan-candidates.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/tach-config-draft.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/test-inventory.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/discovery-artifacts/tooling-assessment.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/00-epic-final.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/00-epic.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/01-skeleton.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/02-core-foundationals.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/03-core-contracts.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/04-commands.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/05-profiles.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/06-scope.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/07-audio.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/08-runtime-radio.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/09-runtime-mixins.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/10-runtime-pollers.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/11-discovery-to-backends.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/12-cli.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/13-import-linter.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/14-followup-tests.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/15-followup-web-startup.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/2026-05-07-core-audio-pipeline-test-harness.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/plans/issue-drafts/2026-05-07-core-audio-route-resolver.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/radio-protocol.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/robots.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/amber-lcd.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/hero.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/screenshots/lcd-scope.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/running-validation.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/ftx1.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/ic7300.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/tx500.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/templates/x6200.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/docs/validation/universal-matrix.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/.gitignore +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/README.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/eslint.config.js +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/index.html +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/package-lock.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/package.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/playwright.config.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/playwright.i18n.config.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/pnpm-lock.yaml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/apple-touch-icon.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/lockup-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/mark-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/marketing/github-social-preview.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/marketing/readme-banner.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/brand/wordmark-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/ink/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/paper/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/favicons/transparent/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/manifest.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/og-image.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/pwa-192x192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/pwa-512x512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/public/twitter-card.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/scripts/i18n-check.mjs +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/App.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/app.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/assets/svelte.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/shared/Toast.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/shared/__tests__/Toast.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/BandPlanOverlay.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/DxOverlay.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/EiBiBrowser.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/ScopeSettingsPopover.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumCanvas.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/SpectrumToolbar.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/WaterfallCanvas.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/BandPlanOverlay.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/DxOverlay.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/EiBiBrowser.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/SpectrumPanel.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/SpectrumToolbar.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/band-plan-overlay.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/click-to-tune.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/passband-geometry.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/spectrum-panel-logic.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/spectrum-toolbar.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/__tests__/tuning-indicator.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/band-plan-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/passband-geometry.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/spectrum-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components/spectrum/spectrum-toolbar-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/AttenuatorControl.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/BandSelector.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/BottomSheet.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/CollapsiblePanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ControlButtonDemo.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/InstallPrompt.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/LanguageSelector.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/PttFab.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/PullToRefresh.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/SegmentedButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/StatusBadge.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ThemePicker.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/ValueControlLab.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/AttenuatorControl.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/BandSelector.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/BottomSheet.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/CollapsiblePanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/InstallPrompt.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/LanguageSelector.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/PullToRefresh.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/SegmentedButton.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/StatusBadge.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/__tests__/broadcast-presets.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/band-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/broadcast-presets.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/button-tokens.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/control-button.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/install-prompt-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/status-badge-style.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/BipolarRenderer.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/DiscreteRenderer.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/DualParamRenderer.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/HBarRenderer.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/KnobRenderer.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/ValueControl.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/__tests__/ValueControl.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/__tests__/value-control-core.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skin.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skins/ProfessionalKnob.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/skins/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/value-control-core.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/controls/value-control/value-control.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/dialogs/SendReportDialog.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/dialogs/__tests__/SendReportDialog.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/FrequencyDisplay.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/FrequencyDisplayInteractive.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/__tests__/FrequencyDisplay.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/__tests__/frequency-tuning.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/frequency-format.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/display/frequency-tuning.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/KeyboardHandler.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/LcdLayout.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/LeftSidebar.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/MobileNav.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/MobileRadioLayout.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/RadioLayout.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/RightSidebar.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/StatusBar.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/VfoHeader.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/KeyboardHandler.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/LeftSidebar.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/MobileRadioLayout.component.svelte.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/RadioLayout.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/SpectrumPanelStub.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/keyboard-map.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/mobile-layout-logic.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/mobile-nav.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/top-row-visual-regression.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/vfo-header.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/__tests__/vfo-layout-tokens.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/keyboard-map.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/layout-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-chip-bar.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-layout-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/mobile-nav-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/responsive.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/shortcut-hints.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/layout/vfo-layout-tokens.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/BarGauge.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/LinearSMeter.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/NeedleGauge.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/SMeterDemo.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/BarGauge.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/LinearSMeter.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/__tests__/NeedleGauge.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/bar-gauge-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/needle-gauge-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/meters/smeter-scale.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AgcPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AntennaPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/AudioRoutingControl.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/CwPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/DockMeterPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/DspPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/EssentialsPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/FilterPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MemoryPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MeterPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/MetersDockPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/ModePanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RfFrontEnd.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RitXitPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/RxAudioPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/ScanPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/TxPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/VoxPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/AgcPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/AudioRoutingControl.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/CwPanel.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/DspPanel.component.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/DspPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/FilterPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/MeterPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/MetersDockPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/ModePanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RfFrontEnd.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RitXitPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/RxAudioPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/TxPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/cw-panel-logic.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/dsp-panel-logic.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/__tests__/filter-controls.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/agc-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/AudioSpectrumCanvas.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/AudioSpectrumPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/__tests__/audio-spectrum-renderer.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-scope/audio-spectrum-renderer.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/audio-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/cw-panel-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/dsp-panel-logic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/dsp-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/filter-controls.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/filter-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberAfScope.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberCockpit.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberFilterGhost.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberFrequency.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberIndStrip.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberLcdDisplay.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberMemoryStrip.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberScope.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberSmeter.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberSparkline.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/AmberTelemetryStrip.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/LcdContrastControl.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/LcdDisplayModeControl.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/VfoControlPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/__tests__/lcd-components.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/__tests__/scope-frame.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/lcd/lcd-vintage.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/meter-utils.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/meter-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/rf-frontend-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/rit-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/tx-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/vfo/DualVfoDisplay.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/panels/vfo/__tests__/DualVfoDisplay.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/fonts-digital.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/fonts.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/theme-switcher.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/amoled-black.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/ayu-dark.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/catppuccin-latte.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/catppuccin-mocha.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/crt-green.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/custom-ic7610.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/dracula.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/github-light.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/gruvbox-dark.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/gruvbox-light.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/high-contrast.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/lcd-blue.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/lcd-warm.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nixie-tube.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nord-light.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/nord.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/one-dark.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/solarized-dark.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/solarized-light.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/themes/tokyo-night.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/tokens.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/crt-green.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/lcd-blue.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/theme/vfo-themes/nixie-tube.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/ActiveReceiverToggle.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/VfoOps.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/VfoPanel.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/ActiveReceiverToggle.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/VfoOps.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/__tests__/VfoPanel.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/vfo-ops-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/vfo/vfo-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/double-click.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/focus-mode-race.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/keyboard-wiring.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/state-adapter.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/__tests__/vfo-wiring.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/command-bus.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/double-click.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/components-v2/wiring/state-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/ControlButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/DotButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/FillButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/HardwareButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/HardwarePlainButton.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/StatusIndicator.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/__tests__/ControlButton.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/__tests__/ControlledHarness.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/roleMapping.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/Button/types.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/SegmentedControl/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/__tests__/drag-reorder.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/__tests__/migrate-legacy-storage.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/actions/keyboard.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/api/__tests__/diagnostics.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/api/diagnostics.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/audio-manager.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/constants.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/rx-player.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/__tests__/tx-mic.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/audio-manager.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/constants.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/rx-player.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/audio/tx-mic.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/data/__tests__/arrl-band-plan.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/data/arrl-band-plan.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/drag-reorder.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/gestures/gesture-recognizer.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/gestures/use-gesture.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/CONTRIBUTING.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/index.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/locale-contract.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/plural.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/pseudo-locale.smoke.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/pseudo.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/runtime.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/__tests__/store.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locale-contract.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/en-US.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/ja-JP.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/locales/ru-RU.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/plural.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/pseudo.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/runtime.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/store.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/i18n/types.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/LocalExtensionsHost.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/dock-layout.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/host-api.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/__tests__/manifest.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/dock-layout.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/host-api.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/keyboard-scope.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/local-extensions/manifest.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/media/__tests__/media-session.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/media/media-session.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/migrate-legacy-storage.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/filter-controls.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/pending-focus.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/radio/pending-focus.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/__tests__/spectrum-renderer.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/__tests__/waterfall-renderer.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/spectrum-renderer.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/renderers/waterfall-renderer.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/__tests__/frontend-runtime.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/__tests__/scope-controller.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/audio-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/capabilities-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/lcd-chrome-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/panel-adapters.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/qsy-history-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/scope-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/tx-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/adapters/vfo-adapter.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/commands/panel-commands.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/frontend-runtime.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/index.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/props/panel-props.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/scope-controller.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/runtime/system-controller.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/audio.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/capabilities.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/commands.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/connection.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/radio.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/__tests__/ui.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/audio.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/capabilities.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/commands.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/connection.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/connection.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/layout.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/lcd-contrast.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/lcd-display-mode.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/qsy-history.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/radio.svelte.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/radio.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/tuning.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/stores/ui.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/__tests__/http-client.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/__tests__/ws-client.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/http-client.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/transport/ws-client.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/capabilities.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/protocol.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/types/state.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/__tests__/battery.test.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/battery.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/filter-width.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/haptics.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/meter-utils.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/smoothing.svelte.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/tx-permit.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/lib/utils/uuid.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/main.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/amber-lcd/LcdSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/desktop-v2/DesktopSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/lcd-cockpit/LcdCockpitSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/lcd-scope/LcdScopeSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/mobile/MobileSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/registry.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/sdr-test/SdrTestSkin.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/skins/sdr-test/SdrVfoScreen.svelte +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/styles/animations.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/styles/tokens.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/types/pwa.d.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/src/types/webcodecs.d.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/static/fonts/DSEG7Classic-Bold.woff2 +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/svelte.config.js +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/README.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/app-shell-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/app-shell-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/connection-overlay-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/connection-overlay-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/send-report-dialog-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/send-report-dialog-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/settings-modal-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/settings-modal-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/status-bar-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/status-bar-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/toast-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/en-US/toast-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/app-shell-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/app-shell-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/connection-overlay-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/connection-overlay-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/send-report-dialog-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/send-report-dialog-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/settings-modal-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/settings-modal-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/status-bar-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/status-bar-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/toast-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/ja-JP/toast-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/app-shell-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/app-shell-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/connection-overlay-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/connection-overlay-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/send-report-dialog-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/send-report-dialog-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/settings-modal-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/settings-modal-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/status-bar-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/status-bar-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/toast-desktop.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/__screenshots__/i18n/qps-ploc/toast-mobile.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/fixtures.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/i18n/i18n-visual.spec.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tests/e2e/v2-ui-interactive.impl.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.app.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/tsconfig.node.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/frontend/vite.config.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/hooks/sitemap_noindex.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/mkdocs.yml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_keyboard-default.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_schema.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/_schema_v2.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/ftx1.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/lab599_tx500.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/sdrplay_rspdx.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/examples/xiegu_x6200.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ftx1.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic705.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic7300.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic7610.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/ic9700.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/tx500.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/x6100.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/rigs/x6200.toml +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/icom_lan/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/icom_lan/_cli_shim.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/__main__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_codecs.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_recovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_runtime_mixin.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_audio_transcoder.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bounded_queue.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bridge_metrics.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_bridge_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_civ_rx.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_connection_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_control_phase.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_dual_rx_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_optional_deps.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_platformdirs_migration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_poller_types.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_queue_pressure.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_runtime_protocols.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_scope_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_shared_state_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_state_cache.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/_state_queries.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_bridge_metrics.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_bridge_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_codecs.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_macos_uid.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_transcoder.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/_usb_resolve.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/analyzer.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/dsp.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/fft_scope.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/lan_stream.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe_profile.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/probe_runner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/resample.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/route.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio/usb_driver.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_analyzer.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_bridge.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_bus.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/audio_fft_scope.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/auth.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/_icom_serial_base.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/discovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/factory.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/hamlib_models.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/hamlib_probe.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/core.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic705/serial.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/core.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic7300/serial.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/core.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/ic9700/serial.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/contracts.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_civ_link.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_session.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/serial_stub.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/drivers/usb_audio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/lan.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/icom7610/serial.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/rigctld_client/transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/parser.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/poller.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/backends/yaesu_cat/transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/capabilities.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/civ.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_convert.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_diagnose.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_discover_hamlib.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_radio_validate.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cli/_validate.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/command_map.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/command_spec.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commander.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_builders.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_codec.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/_frame.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/antenna.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/command_map.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/command_spec.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/commander.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/cw.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/dsp.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/freq.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/levels.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/memory.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/meters.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/mode.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/power.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/ptt.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/scope.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/speech.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/system.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/tone.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/tx_band.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/commands/vfo.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_bounded_queue.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_optional_deps.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_queue_pressure.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/_state_cache.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/auth.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/capabilities.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/civ.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/env_config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/exceptions.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/radio_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/radio_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/core/types.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/cw_auto_tuner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_discovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_error_ring.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_errors.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_logging.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/_manifest.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/bundle.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributor.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/audio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/dependencies.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/errors.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/invocation.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/logs.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/contributors/system.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/redaction.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/diagnostics/upload.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/discovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/exceptions.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/base.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/nodes/nr_scipy.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/pipeline.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/resample.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/dsp/tap_registry.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/env_config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/exceptions.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/ic705.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/meter_cal.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles/rig_loader.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/profiles_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/proxy.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/py.typed +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_initial_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_reconnect.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radio_state_snapshot.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/radios.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rig_loader.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/audit.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/circuit_breaker.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/contract.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/handler.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/poller.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/routing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/state_cache.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/rigctld/utils.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_audio_recovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_audio_runtime_mixin.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_civ_rx.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_connection_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_control_phase.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_dual_rx_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_poller_types.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_runtime_protocols.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_scope_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_shared_state_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/_state_queries.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/cw_auto_tuner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/ic705.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/meter_cal.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/profiles_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/proxy.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_initial_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_reconnect.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radio_state_snapshot.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/radios.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/startup_checks.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/runtime/sync.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope/render.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/scope_render.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/startup_checks.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/sync.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/types.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/usb_audio_resolve.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/comparison.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/hardware.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/overrides.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/registry.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/runner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/validation/schema.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/LAYER.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/_delta_encoder.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/api_contract.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/band_plan.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/dx_cluster.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/eibi.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/handlers/diagnostics.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/radio_poller.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/rtc.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/runtime_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/apple-touch-icon.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/ControlButtonDemo-CnelvEOz.js +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/ControlButtonDemo-Ddi7py1_.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/index-CvOPafTi.css +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/assets/index-MRf0y8eM.js +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/lockup-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/mark-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/marketing/github-social-preview.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/marketing/readme-banner.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-dark.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-light.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/brand/wordmark-mono.svg +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/ink/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/paper/favicon.ico +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-128.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-16.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-180.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-256.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-32.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-48.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/favicons/transparent/favicon-64.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/index.html +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/manifest.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/og-image.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/pwa-192x192.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/pwa-512x512.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static/twitter-card.png +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/static.old/index.html +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/tls.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/web_routing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/web_startup.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/src/rigplane/web/websocket.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_audio_pipeline_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_audio_stream_fake.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_caps.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_command_test_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_diagnostics_mock_server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/_perf_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/conftest.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/contracts/__init__.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/contracts/test_lazy_imports.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/e2e/package.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/e2e/v2-ui-interactive.spec.ts +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fake_rigctld.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/civ_rx_frames.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/hamlib_dump_caps_ts480.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/hamlib_rigctl_list.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_artifact_mixed.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_artifact_reverse_sync_fail.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/fixtures/validation_template_ic7300.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/dump_state_ic7610.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/dump_state_yaesu.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/fldigi_dual_rx_session.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/js8call_dual_rx_session.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/protocol_golden.json +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/golden/wsjtx_dual_rx_session.txt +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/hardware/test_ic7610_audio_pipeline.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/hardware/test_x6200_serial_tx_smoke.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/README.md +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/conftest.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/full_handshake.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/logging_utils.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/probe_handshake.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/probe_login.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_audio_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_audio_routing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_connect.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_controls_extended_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_dsp_levels_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_get_freq.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_media_scope_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_memory_set_only.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_negative_auth_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_operator_toggles_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_radio_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_reliability_matrix_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_audio_pipeline.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_golden_replay.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rigctld_wsjtx.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_rit_tuner_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_scope_advanced_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_tone_tsql_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_vfo_dual_watch_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/integration/test_x6200_audio_scope_smoke.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/mock_server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_analyzer.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_bridge_stereo.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_codec.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_codecs.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_dsp.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_fft_scope.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_fullduplex.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_pipeline_harness.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_pipeline_os_smoke.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe_profile.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_probe_runner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_recovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_resample.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_route.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_rx_tx_transition.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_scope_dispatch.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_stress.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_transcoder.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_transcoder_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audio_watchdog.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_audit.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_auth.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_authz_registry_gated.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_backend_contract_matrix.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_backend_factory.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_bounded_queue.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_bsr_band_switching.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_circuit_breaker.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_command_profiling.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_dispatch_golden.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_mixin_host.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_rx_short_frame_robustness.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_civ_transaction_ownership.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_async.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_diagnose.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_diagnose_lazy_import.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_e2e.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cli_model.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cmd29_parsing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_catalog_docs.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_map_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_command_spec.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commander.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commands.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_commands_extended.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_convert.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_convert_cli.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cw_auto_tune_wiring.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_cw_auto_tuner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_data_mode.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_delta_encoder.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_bundle.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributor.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch1.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch2.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_contributors_batch3.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_e2e.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_logging.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_privacy_invariants.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_redaction.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_diagnostics_upload.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_discovery.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_docs_runtime_sync.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_filter_family.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_levels_part1.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_levels_part2.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_nodes.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_nr_scipy.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dsp_pipeline.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_dx_cluster.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_env_config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_exports.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_fake_rigctld.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_frontend_e2e_config.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ftx1_audio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ftx1_radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_golden_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_dump_caps.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_external_rigctld_contract.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_models.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_hamlib_probe.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_dsp_407_408.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_protocol_gap_399.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_handlers_sys_band.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic705.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic705_backend.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic7300_backend.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic7610_parity_matrix.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_ic9700_backend.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom7610_serial_radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom_lan_shim.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_icom_receiver_tier.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_issue_141_core_refactor.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_jitter_buffer.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_lifecycle_diagnostics.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_macos_audio_uid.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_main_sub_tracking.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_managed_runtime_packaging_doc.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_memory_commands.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_mock_integration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_naming_parity.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_operator_toggles.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_overrides.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_pcm_e2e.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_per_receiver_vfo_roundtrip.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_performance_regressions.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_platformdirs_migration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_poller.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_poller_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_power_unit_extension.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_profiles_routing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_profiles_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_proxy.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_proxy_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_public_api_surface.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_connect.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_extended.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_poller_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radio_validate.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_radios.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rate_limiter.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_raw_civ_pipe.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_raw_civ_transaction.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rf_gain_af_level.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_ic7300.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_ic7610.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_loader.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_multi_vendor.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rig_schema.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_client_backend.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_consistency.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_dump_state_snapshot.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_handler.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_init_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_protocol.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_routable_extension.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_server_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_rigctld_utils.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_render.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_render_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_scope_stress.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_security_headers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_selected_freq_mode.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_backend_smoke.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_backend_tx_mor242.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_civ_link.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_session.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_serial_stub_framing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_server_wire.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_shared_state_runtime.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_single_rx_plain_routing.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_cache.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_cache_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_pollable_extension.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_state_queries.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_supports_command.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_swr_calibration.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_sync.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_sync_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tap_registry.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tls.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_token_renewal.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tone_tsql.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_tx_band_edge.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_capable_extension.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_channel_clamp_mor238.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_resolve.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_usb_audio_stub.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validate_hamlib_provider.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validate_overrides.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_comparison.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_runner.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_schema.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_validation_templates.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_vfo_dual_watch.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_vox_tone_state.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_api_contract.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_audio_streaming_profile.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_auth_compare_digest.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_capability_guards.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_command_batch_http.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_cw_http_control.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_diagnostics.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_post_body_cap.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_ptt_readonly.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_runtime_helpers.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_web_server_token_redaction.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_webrtc_signaling.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_websocket_coverage.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_x6200_rx_audio_mor236.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_audio.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_parser.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_poller.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cat_transport.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/test_yaesu_cli_factory.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_generator.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_generator_hamlib.py +0 -0
- {rigplane-2.7.2 → rigplane-2.8.0}/tests/validation/test_hardware.py +0 -0
- {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.
|
|
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.
|
|
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`)
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
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.
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
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
|
+
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
|
-
|
|
82
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
316
|
+
self._running = False
|
|
274
317
|
self._callback = None
|
|
275
|
-
#
|
|
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
|
-
|
|
294
|
-
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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:
|
|
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
|
|
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=
|
|
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.
|
|
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
|
|
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
|
-
|
|
106
|
-
|
|
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.
|
|
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.
|
|
335
|
+
await sub.aclose()
|
|
264
336
|
if self._rx_active:
|
|
265
337
|
await self._stop_rx()
|