Skip to content

Feat/vibebar#40

Merged
ZephyrKeXiner merged 6 commits into
AhakeyAI:vibebarfrom
ZephyrKeXiner:feat/vibebar
Jun 28, 2026
Merged

Feat/vibebar#40
ZephyrKeXiner merged 6 commits into
AhakeyAI:vibebarfrom
ZephyrKeXiner:feat/vibebar

Conversation

@ZephyrKeXiner

Copy link
Copy Markdown
Contributor

1. Summary / 修改概述

Summary / 概述:

This pull request introduces several key improvements to device connection diagnostics, BLE management, and package structure. The main focus is on providing more granular feedback about device connection states, improving reliability when the device is connected via system Bluetooth/HID, and enhancing package modularity and dependency management.

Device connection diagnostics and BLE management:

  • Added a new LinkDiagnostic enum to track and expose detailed device connection states, enabling the UI to provide actionable feedback to users about where the device is "stuck" in the connection process.
  • Refactored BLE device name matching to use a whitelist of prefixes (including both "AhaKey" and "vibe code"), improving compatibility with official and third-party firmware [1] [2] [3] [4] [5] [6] [7].
  • Enhanced automatic connection logic to distinguish between various failure modes (e.g., Bluetooth off, unauthorized, device connected via system but not config service), and to update linkDiagnostic accordingly [1] [2] [3] [4] [5] [6].

Package and dependency management:

  • Updated the Swift package manifest to require macOS 13, added new products (AhaKeyPluginKit, PluginShowcase), and integrated the local vibebar package as a dependency [1] [2] [3].
  • Added a resolved package file for DynamicNotchKit, ensuring reproducible builds.

App integration and reliability:

  • Integrated VibeBar into the main app, attaching it to the BLE manager and starting the controller on app launch.
  • Improved agent startup logic to detect and recover from failed agent launches by falling back to direct app connection, ensuring the keyboard remains usable.

These changes significantly improve the user experience by providing clearer connection status, better handling of edge cases, and a more modular codebase.


2. Type of change / 修改类型

请选择本次 PR 的类型。
Please select the type of this PR.

  • Bug fix / Bug 修复
  • Documentation / 文档修改
  • New feature / 新功能
  • Refactor / 重构
  • Build or packaging / 构建或打包
  • Protocol example / 协议示例
  • Community project or showcase / 社区项目或展示
  • Other / 其他

3. Area / 涉及范围

请选择本次修改涉及的部分。
Please select the area affected by this PR.

  • desktop
  • protocol
  • awesome-ahakey
  • firmware
  • docs
  • macOS
  • Windows
  • Other / 其他

ZephyrKeXiner and others added 6 commits June 21, 2026 16:32
…er (Issue AhakeyAI#34)

macOS Studio showed a flat "等待设备" whenever the 0x7340 config link wasn't
up, so users couldn't tell a half-connected device (HID/voice up, config link
down) from a device that's simply absent — see AhakeyAI#34.

Root cause: once the keyboard is connected via the system BLE / voice (HID)
link it stops advertising, so the advertising-based
scanForPeripherals(withServices:[0x7340]) never finds it, and the
retrieveConnectedPeripherals(withServices:[0x7340]) fallback is empty when no
one has discovered 0x7340 yet — both fallbacks miss and we scan forever.

- Root-cause fix (B): connectAutomatically() now retrieves system-connected
  peripherals using a wider standard-service set (0x7340/180A/180F/1812),
  matches by "AhaKey" name prefix, and actively connects; didConnect's
  discoverServices then brings up 0x7340 even when the device isn't advertising.
- Diagnostics (A): new LinkDiagnostic enum distinguishes scanning / connecting /
  connected / bluetoothOff / bluetoothUnauthorized / ownedByAgent /
  systemConnectedNoConfigLink / noDeviceFound, each with short + actionable
  text. Scan timeout re-probes via the wide set to pick the right state.
- UI: top-bar pill shows the diagnostic instead of "等待设备", with the detailed
  explanation as a tooltip.

Builds clean (swift build). Runtime behavior against real hardware not yet
verified — needs a device exhibiting the issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CH582m vibe-coding firmware advertises as "vibe code XXXX", but both the
app and the standalone agent only matched a hard-coded "AhaKey" name prefix,
so such devices were filtered out of scan results and connected-peripheral
lookups — the app scanned forever / showed "未发现设备".

Replace the single deviceNamePrefix with a prefix allow-list
["AhaKey", "vibe code"] plus a matchesDeviceName() helper, applied in both
AhaKeyBLEManager (scan callback + wide-service system-connected fallback) and
AhaKeyAgent.

Verified end to end: app auto-connects to a real "vibe code B1D2" device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt can't run

If a LaunchAgent plist exists but the agent can't actually run (e.g. it points
at a stale build path, or the binary crashes), `launchctl start` does not error
and the socket never appears — so the keyboard stays "given to the agent" with
nobody actually connecting it, and the app is stuck on "Agent 占用中" until the
user manually re-connects. (Hit in practice via a 6/2 plist pointing at a
deleted Xcode DerivedData path.)

In the agentDaemon branch, after load+start, wait up to ~2.5s for the agent to
come up; if it doesn't, release BLE suppression and let the app connect directly
(plus a non-launch user alert). Liveness is checked with a real connect() probe
(agentSocketAlive) rather than checkRunning()'s file-exists test, so a leftover
dead socket no longer masks a non-running agent.

Verified: with a broken plist + no agent, app falls back and scans/connects;
with a clean state it auto-connects to "vibe code B1D2" on launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… command

The UI stopped reflecting live keyboard changes (knob/mode/light) until a manual
reconnect. Root cause: status polling is gated by `guard protocolResponseWaiters.isEmpty`,
and that set could leak forever.

In sendCommandAwaitingResponse the timeout child task only `throw`s; it never
resumes the pending CheckedContinuation. Since CheckedContinuation ignores task
cancellation, withThrowingTaskGroup keeps awaiting the never-finishing waiter
task on timeout, so the function never returns, its `defer` cleanup never runs,
and the waiter entry stays in protocolResponseWaiters — permanently blocking the
1.5s status poll. Reproduced on connect: reading picture-state for a mode the
firmware doesn't answer (mode=3) left waiter[0x83] stuck.

Fix: on timeout, atomically remove the waiter and resume its continuation
(throwing) on the main actor before throwing, so the group can finish, defer
runs, and the waiter set drains. removeValue is atomic vs the response handler,
so no double-resume.

Verified: in App-direct mode the app now polls every ~1.5s and picks up live
mode changes (3->0) without a reconnect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pulls vibebar (notch-style dynamic island, based on DynamicNotchKit) into
the repo as a SwiftPM sub-package and wires it through the main macOS app
as an in-process module rather than a sibling executable. The island now
reflects live app state — keyboard connection + battery, lever auto/ask
flag, and voice-agent activity — and offers a tile that calls back into
the app to reopen the main window.

- vibebar/ — new sub-package: VibeBar library + VibeBarSmoke executable
  for standalone UI smoke tests; depends on DynamicNotchKit 1.0.0,
  pinned at 3c40593
- ahakeyconfig-mac/Package.swift — split AhaKeyPluginKit/AhaKeyPlugin/
  PluginShowcase into their own targets so the root package actually
  compiles; bump min macOS to 13 (DynamicNotchKit floor); depend on
  ../vibebar and link VibeBar into AhaKeyConfig
- ahakeyconfig-mac/scripts/build.sh — bump default
  MACOS_DEPLOYMENT_TARGET to 13 to match the package floor
- AhaKeyConfigApp.swift — own a VibeBarBridge, attach on .onAppear,
  start VibeBarController.shared with the bridged state
- VibeBarBridge.swift — Combine mirror of BLE manager + voice services
  onto VibeBarState; lever maps switchState==0 to auto, preferring the
  agent's cached value when the app's own BLE link is dormant; fail-safe
  to leverKnown=false when neither source has answered

Root Package.swift also updated for parity (path: "vibebar") so swift
build from the repo root keeps working.
Closing the main window with the red close button doesn't terminate the
app (macOS convention), so reopening the window rebuilds ContentView and
resets all @State. That meant dismissedIncompleteOnboardingThisSession
went back to false every time, and as long as any permission was still
missing the unified onboarding sheet popped up again — even though the
user had already been through it.

Per product intent: once unifiedOnboardingCompleted is true, never show
the onboarding again. Permission gaps surface through the main UI's own
indicators instead. Drops the session-scoped dismissal flag entirely.
@ZephyrKeXiner ZephyrKeXiner self-assigned this Jun 28, 2026
@ZephyrKeXiner ZephyrKeXiner merged commit 3827c89 into AhakeyAI:vibebar Jun 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant