mirror of
https://github.com/bybrooklyn/openbitdo.git
synced 2026-03-19 04:12:56 -04:00
release: prepare v0.0.1-rc.4
This commit is contained in:
@@ -9,7 +9,7 @@ resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
version = "0.0.1-rc.2"
|
||||
version = "0.0.1-rc.4"
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
[workspace.dependencies]
|
||||
|
||||
179
sdk/README.md
179
sdk/README.md
@@ -1,135 +1,90 @@
|
||||
# OpenBitdo SDK
|
||||
|
||||
OpenBitdo SDK includes:
|
||||
- `bitdo_proto`: protocol/transport/session library
|
||||
- `bitdo_app_core`: shared firmware-first workflow and policy layer
|
||||
- `bitdo_tui`: Ratatui/Crossterm terminal app
|
||||
- `openbitdo`: beginner-first launcher (`openbitdo` starts guided TUI)
|
||||
This workspace contains the OpenBitdo runtime, protocol layer, and release packaging scripts.
|
||||
|
||||
## Crates
|
||||
|
||||
- `bitdo_proto`: command registry, transport, session, and diagnostics behavior
|
||||
- `bitdo_app_core`: firmware policy, device workflows, and support-tier gating
|
||||
- `bitdo_tui`: terminal UI, app state, runtime loop, persistence, and headless API
|
||||
- `openbitdo`: beginner-first launcher binary
|
||||
|
||||
## Build And Test
|
||||
|
||||
From `cleanroom/sdk`:
|
||||
|
||||
## Build
|
||||
```bash
|
||||
cargo build --workspace
|
||||
```
|
||||
|
||||
## Test
|
||||
```bash
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace --all-targets
|
||||
```
|
||||
|
||||
## Guard
|
||||
```bash
|
||||
./scripts/cleanroom_guard.sh
|
||||
```
|
||||
|
||||
## Hardware smoke report
|
||||
```bash
|
||||
./scripts/run_hardware_smoke.sh
|
||||
```
|
||||
## Local Run
|
||||
|
||||
## TUI app examples (`openbitdo`)
|
||||
```bash
|
||||
cargo run -p openbitdo --
|
||||
cargo run -p openbitdo -- --mock
|
||||
```
|
||||
|
||||
## CLI surface
|
||||
- `openbitdo [--mock]`: interactive dashboard flow (mouse-primary, minimal keyboard).
|
||||
|
||||
## Interactive behavior (`openbitdo`)
|
||||
- dashboard starts with:
|
||||
- searchable device list (left)
|
||||
- quick actions (center)
|
||||
- persistent event panel (right)
|
||||
- primary quick actions:
|
||||
- `Refresh`
|
||||
- `Diagnose`
|
||||
- `Recommended Update`
|
||||
- `Edit Mapping` (capability-gated)
|
||||
- `Settings`
|
||||
- `Quit`
|
||||
- firmware transfer path:
|
||||
- preflight generation
|
||||
- explicit confirm/cancel action
|
||||
- updating progress and final result screen
|
||||
- mapping editors are draft-first with:
|
||||
- apply
|
||||
- undo
|
||||
- reset
|
||||
- restore backup
|
||||
- recovery lock behavior is preserved when rollback fails.
|
||||
|
||||
## Headless library API
|
||||
- headless automation remains available as a Rust API in `bitdo_tui`:
|
||||
- `run_headless`
|
||||
- `RunLaunchOptions`
|
||||
- `HeadlessOutputMode`
|
||||
- `openbitdo` CLI does not expose a headless command surface.
|
||||
|
||||
## Config schema (v2)
|
||||
- persisted fields:
|
||||
- `schema_version`
|
||||
- `advanced_mode`
|
||||
- `report_save_mode`
|
||||
- `device_filter_text`
|
||||
- `dashboard_layout_mode`
|
||||
- `last_panel_focus`
|
||||
- v1 files are read with compatibility defaults and normalized to v2 fields at load time.
|
||||
`openbitdo` intentionally exposes a single interactive CLI surface.
|
||||
Headless automation remains available through the Rust API in `bitdo_tui`.
|
||||
|
||||
## Packaging
|
||||
|
||||
```bash
|
||||
./scripts/package-linux.sh v0.0.1-rc.2 x86_64
|
||||
./scripts/package-linux.sh v0.0.1-rc.2 aarch64
|
||||
./scripts/package-macos.sh v0.0.1-rc.2 arm64 aarch64-apple-darwin
|
||||
./scripts/package-linux.sh v0.0.0-local x86_64
|
||||
./scripts/package-linux.sh v0.0.0-local aarch64
|
||||
./scripts/package-macos.sh v0.0.0-local arm64 aarch64-apple-darwin
|
||||
```
|
||||
|
||||
Packaging outputs use:
|
||||
- `openbitdo-<version>-<os>-<arch>.tar.gz`
|
||||
- `openbitdo-<version>-<os>-<arch>` standalone binary
|
||||
- `.sha256` checksum file for each artifact
|
||||
- macOS arm64 additionally emits `.pkg` (unsigned/ad-hoc for RC)
|
||||
Outputs:
|
||||
|
||||
## Release Workflow
|
||||
- CI checks remain in `.github/workflows/ci.yml`.
|
||||
- Tag-based release workflow is in `.github/workflows/release.yml`.
|
||||
- Release tags must originate from `main`.
|
||||
- `v0.0.1-rc.2` style tags publish GitHub pre-releases.
|
||||
- Release notes are sourced from `/Users/brooklyn/data/8bitdo/cleanroom/CHANGELOG.md`.
|
||||
- Package-manager publish runs only after release assets are published.
|
||||
- `openbitdo-<version>-linux-x86_64.tar.gz`
|
||||
- `openbitdo-<version>-linux-aarch64.tar.gz`
|
||||
- `openbitdo-<version>-macos-arm64.tar.gz`
|
||||
- standalone binaries for each packaged target
|
||||
- `.sha256` files for every artifact
|
||||
- macOS `.pkg` from `pkgbuild`
|
||||
|
||||
## Public RC Gate
|
||||
- No open GitHub issues with label `release-blocker`.
|
||||
- Scope-completeness gate:
|
||||
- JP108 RC scope is dedicated mapping only (`A/B/K1-K8`).
|
||||
- Ultimate2 RC scope is expanded mapping for required fields only.
|
||||
- Clean-tree requirement from `/Users/brooklyn/data/8bitdo/cleanroom/RC_CHECKLIST.md` must be satisfied before tagging.
|
||||
Current macOS packaging remains unsigned and non-notarized by design.
|
||||
|
||||
## Distribution Prep
|
||||
- Homebrew install path for public RC:
|
||||
- `brew tap bybrooklyn/openbitdo`
|
||||
- `brew install openbitdo`
|
||||
- Homebrew Core inclusion is not required for `v0.0.1-rc.2`.
|
||||
- Homebrew formula scaffold: `/Users/brooklyn/data/8bitdo/cleanroom/packaging/homebrew/Formula/openbitdo.rb`
|
||||
- Homebrew tap sync script (disabled by default): `/Users/brooklyn/data/8bitdo/cleanroom/packaging/homebrew/sync_tap.sh`
|
||||
- Tap repository: `bybrooklyn/homebrew-openbitdo`
|
||||
- AUR package sources:
|
||||
- `/Users/brooklyn/data/8bitdo/cleanroom/packaging/aur/openbitdo-bin`
|
||||
- AUR package names:
|
||||
- `openbitdo-bin`
|
||||
- Release metadata renderer:
|
||||
- `/Users/brooklyn/data/8bitdo/cleanroom/packaging/scripts/render_release_metadata.sh`
|
||||
- AUR publish workflow:
|
||||
- `/Users/brooklyn/data/8bitdo/cleanroom/.github/workflows/aur-publish.yml`
|
||||
- gated by `AUR_PUBLISH_ENABLED=1`
|
||||
- Homebrew publish path:
|
||||
- `release.yml` renders checksum-pinned formula and runs `sync_tap.sh`
|
||||
- gated by `HOMEBREW_PUBLISH_ENABLED=1`
|
||||
- macOS `.pkg` caveat:
|
||||
- unsigned/ad-hoc is accepted for `v0.0.1-rc.2`
|
||||
- notarization required for `v0.1.0`
|
||||
## Release Flow
|
||||
|
||||
## CI Gates
|
||||
- required:
|
||||
- `guard`
|
||||
- `test`
|
||||
- `tui-smoke-test`
|
||||
- `aur-validate`
|
||||
- `build-macos-arm64`
|
||||
1. Tag from `main` using a `v*` tag.
|
||||
2. `release.yml` verifies CI, secrets, and release blockers.
|
||||
3. Linux and macOS artifacts are built and uploaded.
|
||||
4. GitHub prerelease assets are published from those artifacts.
|
||||
5. AUR and Homebrew metadata are rendered from published release assets.
|
||||
6. AUR and Homebrew publication run only when their repo-variable gates are enabled.
|
||||
|
||||
## Package Manager Publishing
|
||||
|
||||
- AUR workflow: `.github/workflows/aur-publish.yml`
|
||||
- Homebrew workflow: `.github/workflows/homebrew-publish.yml`
|
||||
- Release metadata renderer: `packaging/scripts/render_release_metadata.sh`
|
||||
- AUR source of truth:
|
||||
- tracked package metadata in `packaging/aur/openbitdo-bin`
|
||||
- template in `packaging/aur/openbitdo-bin/PKGBUILD.tmpl`
|
||||
- Homebrew source of truth:
|
||||
- template in `packaging/homebrew/Formula/openbitdo.rb.tmpl`
|
||||
- published tap repo `bybrooklyn/homebrew-openbitdo`
|
||||
|
||||
Current repo-variable contract:
|
||||
|
||||
- `AUR_PUBLISH_ENABLED=1`
|
||||
- `HOMEBREW_PUBLISH_ENABLED=1` when Homebrew publication is enabled
|
||||
- `HOMEBREW_TAP_REPO=bybrooklyn/homebrew-openbitdo`
|
||||
|
||||
Required secrets:
|
||||
|
||||
- `AUR_USERNAME`
|
||||
- `AUR_SSH_PRIVATE_KEY`
|
||||
- `HOMEBREW_TAP_TOKEN`
|
||||
|
||||
## Docs Map
|
||||
|
||||
- Public project overview: [`../README.md`](../README.md)
|
||||
- RC checklist: [`../RC_CHECKLIST.md`](../RC_CHECKLIST.md)
|
||||
- Process docs: [`../process`](../process)
|
||||
- Spec docs: [`../spec`](../spec)
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
---
|
||||
source: crates/bitdo_tui/src/tests.rs
|
||||
assertion_line: 196
|
||||
expression: rendered
|
||||
---
|
||||
╭Session───────────────────────────────────────────────────────────────────────╮
|
||||
│OpenBitDo Dashboard • 3 devices • reports fail-only • safe │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Search filter────────────────╮╭Device full──────────╮╭Actions Enter/click──╮
|
||||
│Search active ││Ultimate2 2dc8:5209 ││› Refresh • scan │
|
||||
╰──────────────────────────────╯│Support: supported ││ Diagnose • probe │
|
||||
╭Search filter────────────────╮╭Device supported─────╮╭Actions Enter/click──╮
|
||||
│Search active ││Ultimate2 2dc8:5209 ││› Refresh • look for│
|
||||
╰──────────────────────────────╯│Support: Supported ││ Diagnose • run saf│
|
||||
╭Controllers detected─────────╮│Protocol: Standard64 ││ Recommended Update │
|
||||
│› 2dc8:5209 Ultimate2 ││Evidence: Confirmed ││ Edit Mapping • map│
|
||||
│full • S64 • conf ││ ││ Settings • prefs │
|
||||
│ 2dc8:6009 Ultimate ││Capabilities ││ Quit • exit │
|
||||
│ro • S64 • infer ││• firmware ││ │
|
||||
│ 2dc8:901a Candidate ││• profile rw │╰──────────────────────╯
|
||||
│ro • unknown • untest ││• mode switch │╭Activity events──────╮
|
||||
│ ││• JP108 mapping ││ │
|
||||
│ ││• U2 slot + map ││ │
|
||||
│› 2dc8:5209 Ultimate2 ││Evidence: Confirmed ││ Edit Mapping • cha│
|
||||
│supported • standard64 • confi││ ││ Settings • report │
|
||||
│ 2dc8:6009 Ultimate ││Capabilities ││ Quit • close OpenB│
|
||||
│read-only • standard64 • infer││• firmware updates ││ │
|
||||
│ 2dc8:901a Candidate ││• profile read and wri│╰──────────────────────╯
|
||||
│read-only • unknown • untested││• mode switching │╭Activity events──────╮
|
||||
│ ││• JP108 dedicated mapp││ │
|
||||
│ ││• Ultimate 2 slot and ││ │
|
||||
│ ││ ││ │
|
||||
│ ││ ││ │
|
||||
│ ││ ││ │
|
||||
@@ -25,5 +24,5 @@ expression: rendered
|
||||
╰──────────────────────────────╯╰──────────────────────╯╰──────────────────────╯
|
||||
╭Status────────────────────────────────────────────────────────────────────────╮
|
||||
│Ready │
|
||||
│Ultimate2 • click • arrows • Enter • Esc/q │
|
||||
│Ultimate2 • click a device or action • arrows, Enter, Esc, and q still work │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
source: crates/bitdo_tui/src/tests.rs
|
||||
assertion_line: 317
|
||||
expression: rendered
|
||||
---
|
||||
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
@@ -8,7 +7,7 @@ expression: rendered
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮
|
||||
│3/5 passed • 2 issues • 2 experimental │
|
||||
│Tier: full • Family: Standard64 • Transport: ready │
|
||||
│Tier: supported • Family: Standard64 • Transport: ready │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮
|
||||
@@ -22,7 +21,7 @@ expression: rendered
|
||||
│ ATTN Version invalid response… ││Validator: test:GetPid │
|
||||
│ │╰──────────────────────────────────────────────────────╯
|
||||
│ │╭Next Steps guidance──────────────────────────────────╮
|
||||
│ ││Action: Return to the dashboard and choose Recomme… │
|
||||
│ ││Action: Return to the dashboard for update or mapp… │
|
||||
│ ││Summary: 3/5 checks passed. Experimental checks: 1… │
|
||||
│ ││Saved report: not yet saved in this screen │
|
||||
│ ││ │
|
||||
@@ -31,5 +30,5 @@ expression: rendered
|
||||
╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯
|
||||
╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮
|
||||
│Run Again ││Save Report ││Back │
|
||||
│rerun safe-read probe ││write support report ││return to dashboard │
|
||||
│run the safe checks again ││save a shareable support re… ││return to dashboard │
|
||||
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
source: crates/bitdo_tui/src/tests.rs
|
||||
assertion_line: 327
|
||||
expression: rendered
|
||||
---
|
||||
╭Session───────────────────────────────────────────────────────────────────────╮
|
||||
@@ -8,7 +7,7 @@ expression: rendered
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Diagnostics summary──────────────────────────────────────────────────────────╮
|
||||
│3/5 passed • 2 issues • 2 experimental │
|
||||
│Tier: full • Family: Standard64 • Transport: ready │
|
||||
│Tier: supported • Family: Standard64 • Transport: ready │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Checks tab cycles filter─────────────────────────────────────────────────────╮
|
||||
@@ -21,9 +20,9 @@ expression: rendered
|
||||
│Severity: Ok │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Next Steps guidance──────────────────────────────────────────────────────────╮
|
||||
│Action: Return to the dashboard and choose Recommended Update or Edit Mapp… │
|
||||
│Action: Return to the dashboard for update or mapping if this device still… │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Run Again───────────────╮╭Save Report──────────────╮╭Back────────────────────╮
|
||||
│Run Again ││Save Report ││Back │
|
||||
│rerun safe-read probe ││write support report ││return to dashboard │
|
||||
│run the safe checks … ││save a shareable supp… ││return to dashboard │
|
||||
╰────────────────────────╯╰─────────────────────────╯╰────────────────────────╯
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
source: crates/bitdo_tui/src/tests.rs
|
||||
assertion_line: 343
|
||||
expression: rendered
|
||||
---
|
||||
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
@@ -8,7 +7,7 @@ expression: rendered
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮
|
||||
│3/5 passed • 2 issues • 2 experimental │
|
||||
│Tier: full • Family: Standard64 • Transport: ready │
|
||||
│Tier: supported • Family: Standard64 • Transport: ready │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮
|
||||
@@ -22,7 +21,7 @@ expression: rendered
|
||||
│ ││Validator: test:Version │
|
||||
│ │╰──────────────────────────────────────────────────────╯
|
||||
│ │╭Next Steps guidance──────────────────────────────────╮
|
||||
│ ││Action: Return to the dashboard and choose Recomme… │
|
||||
│ ││Action: Return to the dashboard for update or mapp… │
|
||||
│ ││Summary: 3/5 checks passed. Experimental checks: 1… │
|
||||
│ ││Saved report: /tmp/openbitdo-diag-report.toml │
|
||||
│ ││ │
|
||||
@@ -31,5 +30,5 @@ expression: rendered
|
||||
╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯
|
||||
╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮
|
||||
│Run Again ││Save Report ││Back │
|
||||
│rerun safe-read probe ││write support report ││return to dashboard │
|
||||
│run the safe checks again ││save a shareable support re… ││return to dashboard │
|
||||
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
---
|
||||
source: crates/bitdo_tui/src/tests.rs
|
||||
assertion_line: 212
|
||||
expression: rendered
|
||||
---
|
||||
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│OpenBitDo Workflow • Ready • reports fail-only • safe │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭Preflight status and intent──────────────────────────────────────────────────────────────────────╮
|
||||
│Preflight Workflow preflight safety check │
|
||||
╭Safety Check status and intent───────────────────────────────────────────────────────────────────╮
|
||||
│Safety Check Workflow reviewing update safety │
|
||||
│ │
|
||||
│Ready to confirm transfer │
|
||||
│ │
|
||||
@@ -17,9 +16,9 @@ expression: rendered
|
||||
│ ││█████ 12% │
|
||||
│ │╰────────────────────────────────────────╯
|
||||
│ │╭Context current session────────────────╮
|
||||
│ ││Stage: preflight safety check │
|
||||
│ ││Current stage: reviewing update safety │
|
||||
│ ││Progress: 12% │
|
||||
│ ││Reports: failure_only │
|
||||
│ ││Report policy: failure_only │
|
||||
│ ││Ready │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
@@ -31,5 +30,5 @@ expression: rendered
|
||||
╰────────────────────────────────────────────────────────╯╰────────────────────────────────────────╯
|
||||
╭Confirm────────────────────────╮╭Cancel─────────────────────────╮╭Back───────────────────────────╮
|
||||
│Confirm ││Cancel ││Back │
|
||||
│acknowledge risk + start ││stop this workflow ││return to dashboard │
|
||||
│acknowledge risk and start … ││stop and discard this step ││leave this screen │
|
||||
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯
|
||||
|
||||
@@ -15,8 +15,12 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
.split(area);
|
||||
|
||||
let status_hint = match state.dashboard_layout_mode {
|
||||
DashboardLayoutMode::Compact => "compact layout • resize for full three-panel view",
|
||||
DashboardLayoutMode::Wide => "click • arrows • Enter • Esc/q",
|
||||
DashboardLayoutMode::Compact => {
|
||||
"compact layout • resize for three panels or keep using click, arrows, and Enter"
|
||||
}
|
||||
DashboardLayoutMode::Wide => {
|
||||
"click a device or action • arrows, Enter, Esc, and q still work"
|
||||
}
|
||||
};
|
||||
let selected_summary = state
|
||||
.selected_device()
|
||||
@@ -94,7 +98,7 @@ fn render_devices(frame: &mut Frame<'_>, state: &AppState, area: Rect, map: &mut
|
||||
let filter = Paragraph::new(Line::from(vec![
|
||||
Span::styled("Search ", crate::ui::theme::title_style()),
|
||||
Span::raw(if filter_label.is_empty() {
|
||||
"type a model, VID, or PID".to_owned()
|
||||
"type a model name or USB ID".to_owned()
|
||||
} else {
|
||||
filter_label
|
||||
}),
|
||||
@@ -194,7 +198,7 @@ fn render_selected_device(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
|
||||
if device.support_tier != bitdo_proto::SupportTier::Full {
|
||||
details.push(Line::from(""));
|
||||
details.push(Line::from(Span::styled(
|
||||
"Write actions stay blocked until hardware confirmation lands.",
|
||||
"This device is still read-only here. Safe diagnostics work, but mapping and update stay blocked until hardware confirmation lands.",
|
||||
crate::ui::theme::warning_style(),
|
||||
)));
|
||||
}
|
||||
@@ -333,17 +337,31 @@ fn truncate_reason(reason: &str) -> String {
|
||||
|
||||
fn action_caption(action: crate::app::action::QuickAction) -> &'static str {
|
||||
match action {
|
||||
crate::app::action::QuickAction::Refresh => "scan",
|
||||
crate::app::action::QuickAction::Diagnose => "probe",
|
||||
crate::app::action::QuickAction::RecommendedUpdate => "safe update",
|
||||
crate::app::action::QuickAction::EditMappings => "mapping",
|
||||
crate::app::action::QuickAction::Settings => "prefs",
|
||||
crate::app::action::QuickAction::Quit => "exit",
|
||||
crate::app::action::QuickAction::Refresh => "look for connected controllers",
|
||||
crate::app::action::QuickAction::Diagnose => {
|
||||
"run safe diagnostics and build a support summary"
|
||||
}
|
||||
crate::app::action::QuickAction::RecommendedUpdate => {
|
||||
"download and stage a verified firmware update"
|
||||
}
|
||||
crate::app::action::QuickAction::EditMappings => {
|
||||
"change supported buttons on supported devices"
|
||||
}
|
||||
crate::app::action::QuickAction::Settings => "report saving and interface preferences",
|
||||
crate::app::action::QuickAction::Quit => "close OpenBitdo",
|
||||
_ => "available",
|
||||
}
|
||||
}
|
||||
|
||||
fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
|
||||
match tier {
|
||||
bitdo_proto::SupportTier::Full => "Supported",
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => "Read-only candidate",
|
||||
bitdo_proto::SupportTier::DetectOnly => "Detection only",
|
||||
}
|
||||
}
|
||||
|
||||
fn support_tier_short(tier: bitdo_proto::SupportTier) -> &'static str {
|
||||
match tier {
|
||||
bitdo_proto::SupportTier::Full => "supported",
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => "read-only",
|
||||
@@ -351,34 +369,26 @@ fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn support_tier_short(tier: bitdo_proto::SupportTier) -> &'static str {
|
||||
match tier {
|
||||
bitdo_proto::SupportTier::Full => "full",
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => "ro",
|
||||
bitdo_proto::SupportTier::DetectOnly => "detect",
|
||||
}
|
||||
}
|
||||
|
||||
fn capability_lines(device: &bitdo_app_core::AppDevice) -> Vec<String> {
|
||||
let mut lines = Vec::new();
|
||||
|
||||
if device.capability.supports_firmware {
|
||||
lines.push("• firmware".to_owned());
|
||||
lines.push("• firmware updates".to_owned());
|
||||
}
|
||||
if device.capability.supports_profile_rw {
|
||||
lines.push("• profile rw".to_owned());
|
||||
lines.push("• profile read and write".to_owned());
|
||||
}
|
||||
if device.capability.supports_mode {
|
||||
lines.push("• mode switch".to_owned());
|
||||
lines.push("• mode switching".to_owned());
|
||||
}
|
||||
if device.capability.supports_jp108_dedicated_map {
|
||||
lines.push("• JP108 mapping".to_owned());
|
||||
lines.push("• JP108 dedicated mapping".to_owned());
|
||||
}
|
||||
if device.capability.supports_u2_button_map || device.capability.supports_u2_slot_config {
|
||||
lines.push("• U2 slot + map".to_owned());
|
||||
lines.push("• Ultimate 2 slot and mapping".to_owned());
|
||||
}
|
||||
if lines.is_empty() {
|
||||
lines.push("• detect only".to_owned());
|
||||
lines.push("• detection only".to_owned());
|
||||
}
|
||||
|
||||
lines
|
||||
@@ -396,7 +406,9 @@ fn compact_reason(reason: &str) -> String {
|
||||
|
||||
fn protocol_short(protocol: bitdo_proto::ProtocolFamily) -> &'static str {
|
||||
match protocol {
|
||||
bitdo_proto::ProtocolFamily::Standard64 => "S64",
|
||||
bitdo_proto::ProtocolFamily::Standard64 => "standard64",
|
||||
bitdo_proto::ProtocolFamily::DInput => "dinput",
|
||||
bitdo_proto::ProtocolFamily::JpHandshake => "jp",
|
||||
bitdo_proto::ProtocolFamily::Unknown => "unknown",
|
||||
_ => "other",
|
||||
}
|
||||
@@ -404,8 +416,8 @@ fn protocol_short(protocol: bitdo_proto::ProtocolFamily) -> &'static str {
|
||||
|
||||
fn evidence_short(evidence: bitdo_proto::SupportEvidence) -> &'static str {
|
||||
match evidence {
|
||||
bitdo_proto::SupportEvidence::Confirmed => "conf",
|
||||
bitdo_proto::SupportEvidence::Inferred => "infer",
|
||||
bitdo_proto::SupportEvidence::Untested => "untest",
|
||||
bitdo_proto::SupportEvidence::Confirmed => "confirmed",
|
||||
bitdo_proto::SupportEvidence::Inferred => "inferred",
|
||||
bitdo_proto::SupportEvidence::Untested => "untested",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,8 +467,8 @@ fn render_next_steps(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
|
||||
|
||||
fn diagnostics_action_caption(action: QuickAction) -> &'static str {
|
||||
match action {
|
||||
QuickAction::RunAgain => "rerun safe-read probe",
|
||||
QuickAction::SaveReport => "write support report",
|
||||
QuickAction::RunAgain => "run the safe checks again",
|
||||
QuickAction::SaveReport => "save a shareable support report",
|
||||
QuickAction::Back => "return to dashboard",
|
||||
_ => "available",
|
||||
}
|
||||
@@ -477,13 +477,13 @@ fn diagnostics_action_caption(action: QuickAction) -> &'static str {
|
||||
fn recommended_next_action(diagnostics: &crate::app::state::DiagnosticsState) -> &'static str {
|
||||
match diagnostics.result.support_tier {
|
||||
bitdo_proto::SupportTier::Full => {
|
||||
"Return to the dashboard and choose Recommended Update or Edit Mapping if needed."
|
||||
"Return to the dashboard for update or mapping if this device still needs work."
|
||||
}
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => {
|
||||
"Save or share the report. Update and mapping remain blocked until confirmation lands."
|
||||
"Save or share the report. Update and mapping stay blocked until this device family is hardware-confirmed."
|
||||
}
|
||||
bitdo_proto::SupportTier::DetectOnly => {
|
||||
"Diagnostics only. Do not attempt update or mapping for this device."
|
||||
"Use diagnostics only. This device is not ready for update or mapping flows."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,8 +514,8 @@ fn severity_style(has_issues: bool) -> Style {
|
||||
|
||||
fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
|
||||
match tier {
|
||||
bitdo_proto::SupportTier::Full => "full",
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => "candidate-readonly",
|
||||
bitdo_proto::SupportTier::Full => "supported",
|
||||
bitdo_proto::SupportTier::CandidateReadOnly => "read-only candidate",
|
||||
bitdo_proto::SupportTier::DetectOnly => "detect-only",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,18 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
let adv = Paragraph::new(vec![
|
||||
Line::from(Span::styled(
|
||||
if state.advanced_mode {
|
||||
"Advanced mode is on"
|
||||
"Advanced controls are on"
|
||||
} else {
|
||||
"Advanced mode is off"
|
||||
"Advanced controls are off"
|
||||
},
|
||||
crate::ui::theme::screen_title_style(),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
"Toggle to expose expert-only report and workflow options.",
|
||||
"Turn this on only if you want expert labels and extra workflow options.",
|
||||
crate::ui::theme::subtle_style(),
|
||||
)),
|
||||
])
|
||||
.block(panel_block("Advanced", Some("press t or click"), true));
|
||||
.block(panel_block("Advanced", Some("toggle"), true));
|
||||
frame.render_widget(adv, rows[0]);
|
||||
|
||||
let report = Paragraph::new(vec![
|
||||
@@ -44,11 +44,11 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
crate::ui::theme::screen_title_style(),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
"Cycle report persistence policy with r or mouse.",
|
||||
"Choose whether support reports save automatically after diagnostics or firmware work.",
|
||||
crate::ui::theme::subtle_style(),
|
||||
)),
|
||||
])
|
||||
.block(panel_block("Reports", Some("press r or click"), true));
|
||||
.block(panel_block("Reports", Some("save policy"), true));
|
||||
frame.render_widget(report, rows[1]);
|
||||
|
||||
let settings_path = state
|
||||
@@ -61,11 +61,11 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
Line::from(""),
|
||||
Line::from(format!("Config path: {settings_path}")),
|
||||
Line::from(Span::styled(
|
||||
"Dashboard layout and filter state persist when a settings path is configured.",
|
||||
"Dashboard layout, filters, and report preferences persist when this path is available.",
|
||||
crate::ui::theme::subtle_style(),
|
||||
)),
|
||||
])
|
||||
.block(panel_block("Status", Some("saved preferences"), true));
|
||||
.block(panel_block("Status", Some("persistence"), true));
|
||||
frame.render_widget(status, rows[2]);
|
||||
|
||||
let actions = state
|
||||
@@ -95,7 +95,7 @@ fn inner_click_rect(rect: Rect) -> Rect {
|
||||
fn settings_action_caption(action: crate::app::action::QuickAction) -> &'static str {
|
||||
match action {
|
||||
crate::app::action::QuickAction::Back => "return to dashboard",
|
||||
crate::app::action::QuickAction::Quit => "exit openbitdo",
|
||||
crate::app::action::QuickAction::Quit => "close OpenBitdo",
|
||||
_ => "available",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
let task = state.task_state.as_ref();
|
||||
let title = match task.map(|t| t.mode) {
|
||||
Some(TaskMode::Diagnostics) => "Diagnostics",
|
||||
Some(TaskMode::Preflight) => "Preflight",
|
||||
Some(TaskMode::Updating) => "Updating",
|
||||
Some(TaskMode::Preflight) => "Safety Check",
|
||||
Some(TaskMode::Updating) => "Update In Progress",
|
||||
Some(TaskMode::Final) => "Result",
|
||||
None => "Task",
|
||||
};
|
||||
@@ -51,7 +51,7 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
|
||||
crate::ui::theme::screen_title_style(),
|
||||
)),
|
||||
Line::from(""),
|
||||
Line::from("Select a device action from the dashboard to begin."),
|
||||
Line::from("Choose a controller action from the dashboard to begin."),
|
||||
]
|
||||
};
|
||||
|
||||
@@ -96,14 +96,20 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
|
||||
let mut lines = vec![Line::from(task.status.clone())];
|
||||
if let Some(plan) = task.plan.as_ref() {
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(format!("Session: {:?}", plan.session_id)));
|
||||
lines.push(Line::from(format!(
|
||||
"Transfer session: {:?}",
|
||||
plan.session_id
|
||||
)));
|
||||
lines.push(Line::from(format!("Chunk size: {} bytes", plan.chunk_size)));
|
||||
lines.push(Line::from(format!("Chunks: {}", plan.chunks_total)));
|
||||
lines.push(Line::from(format!("Estimated: {}s", plan.expected_seconds)));
|
||||
lines.push(Line::from(format!("Total chunks: {}", plan.chunks_total)));
|
||||
lines.push(Line::from(format!(
|
||||
"Estimated transfer time: {}s",
|
||||
plan.expected_seconds
|
||||
)));
|
||||
if !plan.warnings.is_empty() {
|
||||
lines.push(Line::from(""));
|
||||
lines.push(Line::from(Span::styled(
|
||||
"Warnings",
|
||||
"Safety notes",
|
||||
crate::ui::theme::warning_style(),
|
||||
)));
|
||||
for warning in &plan.warnings {
|
||||
@@ -145,16 +151,19 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
|
||||
|
||||
let summary_lines = if let Some(task) = task {
|
||||
vec![
|
||||
Line::from(format!("Stage: {}", task_mode_caption(task.mode))),
|
||||
Line::from(format!("Current stage: {}", task_mode_caption(task.mode))),
|
||||
Line::from(format!("Progress: {progress}%")),
|
||||
Line::from(format!("Reports: {}", state.report_save_mode.as_str())),
|
||||
Line::from(format!(
|
||||
"Report policy: {}",
|
||||
state.report_save_mode.as_str()
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
state.status_line.clone(),
|
||||
crate::ui::theme::subtle_style(),
|
||||
)),
|
||||
]
|
||||
} else {
|
||||
vec![Line::from("Select an action to see task details.")]
|
||||
vec![Line::from("Choose an action to see its workflow details.")]
|
||||
};
|
||||
let summary =
|
||||
Paragraph::new(summary_lines).block(panel_block("Context", Some("current session"), true));
|
||||
@@ -163,18 +172,18 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
|
||||
|
||||
fn task_mode_caption(mode: TaskMode) -> &'static str {
|
||||
match mode {
|
||||
TaskMode::Diagnostics => "diagnostic probe",
|
||||
TaskMode::Preflight => "preflight safety check",
|
||||
TaskMode::Updating => "firmware transfer",
|
||||
TaskMode::Final => "final outcome",
|
||||
TaskMode::Diagnostics => "running safe diagnostics",
|
||||
TaskMode::Preflight => "reviewing update safety",
|
||||
TaskMode::Updating => "sending verified firmware",
|
||||
TaskMode::Final => "showing the final result",
|
||||
}
|
||||
}
|
||||
|
||||
fn task_action_caption(action: crate::app::action::QuickAction) -> &'static str {
|
||||
match action {
|
||||
crate::app::action::QuickAction::Confirm => "acknowledge risk + start",
|
||||
crate::app::action::QuickAction::Cancel => "stop this workflow",
|
||||
crate::app::action::QuickAction::Back => "return to dashboard",
|
||||
crate::app::action::QuickAction::Confirm => "acknowledge risk and start the update",
|
||||
crate::app::action::QuickAction::Cancel => "stop and discard this step",
|
||||
crate::app::action::QuickAction::Back => "leave this screen",
|
||||
_ => "available",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,25 @@ use bitdo_tui::{run_ui, UiLaunchOptions};
|
||||
use clap::Parser;
|
||||
use openbitdo::{load_user_settings, user_settings_path, BuildInfo, UserSettings};
|
||||
|
||||
const CLI_AFTER_HELP: &str = "\
|
||||
Examples:
|
||||
openbitdo
|
||||
openbitdo --mock
|
||||
|
||||
Install:
|
||||
Homebrew: brew tap bybrooklyn/openbitdo && brew install openbitdo
|
||||
AUR: paru -S openbitdo-bin
|
||||
Releases: download a tarball, then run bin/openbitdo
|
||||
|
||||
Notes:
|
||||
--mock starts the app without real hardware.
|
||||
macOS packages are currently unsigned and non-notarized.
|
||||
";
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "openbitdo")]
|
||||
#[command(about = "OpenBitdo beginner-first launcher")]
|
||||
#[command(about = "Beginner-first 8BitDo controller utility")]
|
||||
#[command(after_help = CLI_AFTER_HELP)]
|
||||
struct Cli {
|
||||
#[arg(long, help = "Use mock transport/devices")]
|
||||
mock: bool,
|
||||
|
||||
@@ -9,8 +9,16 @@ fn help_mentions_single_command_surface() {
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Usage: openbitdo [OPTIONS]"))
|
||||
.stdout(predicate::str::contains("--mock"))
|
||||
.stdout(predicate::str::contains("Examples:"))
|
||||
.stdout(predicate::str::contains(
|
||||
"Homebrew: brew tap bybrooklyn/openbitdo && brew install openbitdo",
|
||||
))
|
||||
.stdout(predicate::str::contains(
|
||||
"macOS packages are currently unsigned and non-notarized.",
|
||||
))
|
||||
.stdout(predicate::str::contains("Commands:").not())
|
||||
.stdout(predicate::str::contains("ui").not())
|
||||
.stdout(predicate::str::contains("run").not());
|
||||
.stdout(predicate::str::contains("run [OPTIONS]").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
26
sdk/scripts/check_docs_consistency.sh
Executable file
26
sdk/scripts/check_docs_consistency.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
if rg -n \
|
||||
--glob '*.md' \
|
||||
--glob '*.yml' \
|
||||
--glob '*.sh' \
|
||||
--glob '*.rb' \
|
||||
--glob 'PKGBUILD' \
|
||||
--glob '.SRCINFO' \
|
||||
-g '!CHANGELOG.md' \
|
||||
'v0\.0\.1-rc\.1|v0\.0\.1-rc\.2|0\.0\.1-rc\.1|0\.0\.1-rc\.2|0\.0\.1rc1|0\.0\.1rc2' \
|
||||
.github \
|
||||
README.md \
|
||||
MIGRATION.md \
|
||||
RC_CHECKLIST.md \
|
||||
packaging \
|
||||
process \
|
||||
sdk \
|
||||
spec; then
|
||||
echo "stale rc.1/rc.2 references remain outside CHANGELOG.md" >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPO_ROOT="$(cd "$ROOT/.." && pwd)"
|
||||
VERSION="${1:-v0.0.1-rc.1}"
|
||||
VERSION="${1:-v0.0.0-local}"
|
||||
ARCH_LABEL="${2:-$(uname -m)}"
|
||||
TARGET_TRIPLE="${3:-}"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPO_ROOT="$(cd "$ROOT/.." && pwd)"
|
||||
VERSION="${1:-v0.0.1-rc.1}"
|
||||
VERSION="${1:-v0.0.0-local}"
|
||||
ARCH_LABEL="${2:-arm64}"
|
||||
TARGET_TRIPLE="${3:-aarch64-apple-darwin}"
|
||||
INSTALL_PREFIX="${4:-/opt/homebrew/bin}"
|
||||
|
||||
Reference in New Issue
Block a user