generated from eblume/project-template
Compare commits
No commits in common. "main" and "feature/client-reconnect" have entirely different histories.
main
...
feature/cl
5 changed files with 2 additions and 63 deletions
|
|
@ -12,14 +12,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
<!-- towncrier release notes start -->
|
<!-- towncrier release notes start -->
|
||||||
|
|
||||||
## [v1.4.1] - 2026-06-08
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
- The `heph` CLI and `heph-tui` now survive a daemon restart. Previously the unix-socket client connected once and never reconnected, so an opt-in self-update or `heph daemon restart` left every subsequent call failing — `heph-tui` would sit on errors until relaunched. The client now reconnects on a dropped socket: a request that never went out is retried transparently, while a reply lost mid-request is surfaced (not silently retried) so a mutation is never double-applied. A long-running TUI self-heals on its next refresh tick.
|
|
||||||
- Quick-add popover (⌘'): hand keyboard focus back to the previously active app when it hides, and stop the (now invisible) overlay from intercepting clicks where it used to sit.
|
|
||||||
|
|
||||||
|
|
||||||
## [v1.4.0] - 2026-06-08
|
## [v1.4.0] - 2026-06-08
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -2237,8 +2237,6 @@ dependencies = [
|
||||||
"heph-core",
|
"heph-core",
|
||||||
"hephd",
|
"hephd",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2 0.6.4",
|
|
||||||
"objc2-app-kit 0.3.2",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,7 @@ global-hotkey = "0.8"
|
||||||
|
|
||||||
# macOS-only: winit for the accessory-mode activation policy (no Dock icon),
|
# macOS-only: winit for the accessory-mode activation policy (no Dock icon),
|
||||||
# pinned to the same minor eframe carries so cargo unifies to one winit; libc
|
# pinned to the same minor eframe carries so cargo unifies to one winit; libc
|
||||||
# for getppid() (orphan detection — self-exit when the supervising daemon dies);
|
# for getppid() (orphan detection — self-exit when the supervising daemon dies).
|
||||||
# objc2 + objc2-app-kit to hand keyboard focus back to the previously active app
|
|
||||||
# when the popover hides (NSApplication.hide:/unhide:). Pinned to the 0.6/0.3
|
|
||||||
# line global-hotkey already pulls in, so cargo unifies to one copy.
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
winit = "0.30"
|
winit = "0.30"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
objc2 = "0.6"
|
|
||||||
objc2-app-kit = { version = "0.3", default-features = false, features = [
|
|
||||||
"std",
|
|
||||||
"NSApplication",
|
|
||||||
"NSResponder",
|
|
||||||
] }
|
|
||||||
|
|
|
||||||
|
|
@ -226,9 +226,6 @@ impl QuickAdd {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context) {
|
fn show(&mut self, ctx: &egui::Context) {
|
||||||
// Undo the app-level hide from the previous `hide()` so we can take focus
|
|
||||||
// again (no-op the first time / off macOS).
|
|
||||||
app_take_focus();
|
|
||||||
self.visible = true;
|
self.visible = true;
|
||||||
self.focus_pending = true;
|
self.focus_pending = true;
|
||||||
self.current_hint = random_hint(self.current_hint);
|
self.current_hint = random_hint(self.current_hint);
|
||||||
|
|
@ -259,13 +256,6 @@ impl QuickAdd {
|
||||||
ctx.send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::vec2(WIN_W, BASE_H)));
|
ctx.send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::vec2(WIN_W, BASE_H)));
|
||||||
self.win_h_applied = BASE_H;
|
self.win_h_applied = BASE_H;
|
||||||
}
|
}
|
||||||
// Hand keyboard focus back to the app underneath us. winit's
|
|
||||||
// `Visible(false)` alone leaves *us* the active application, so focus
|
|
||||||
// never returns and the borderless always-on-top overlay can keep eating
|
|
||||||
// clicks where it used to sit. `NSApplication.hide:` orders our windows
|
|
||||||
// fully out and activates the next app in line — exactly the one the user
|
|
||||||
// was in (no-op off macOS).
|
|
||||||
app_yield_focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimistic submit: hide now, create in the background.
|
/// Optimistic submit: hide now, create in the background.
|
||||||
|
|
@ -606,39 +596,6 @@ impl QuickAdd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hide the popover at the *application* level so macOS hands keyboard focus
|
|
||||||
/// back to the previously active app. `NSApplication.hide:` orders all our
|
|
||||||
/// windows out and activates the next app in line — the one the user was in —
|
|
||||||
/// which a plain winit `Visible(false)` does not do. No-op off macOS.
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn app_yield_focus() {
|
|
||||||
use objc2::MainThreadMarker;
|
|
||||||
use objc2_app_kit::NSApplication;
|
|
||||||
// eframe's `update` runs on the main thread, so this marker is always Some.
|
|
||||||
if let Some(mtm) = MainThreadMarker::new() {
|
|
||||||
NSApplication::sharedApplication(mtm).hide(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
fn app_yield_focus() {}
|
|
||||||
|
|
||||||
/// Undo [`app_yield_focus`]: clear the app-level hidden flag before re-showing,
|
|
||||||
/// so the window the viewport `Focus` command then makes key actually appears.
|
|
||||||
/// (`unhide:` also re-activates us; the per-window `Focus`/`Visible` viewport
|
|
||||||
/// commands do the rest.) No-op off macOS.
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn app_take_focus() {
|
|
||||||
use objc2::MainThreadMarker;
|
|
||||||
use objc2_app_kit::NSApplication;
|
|
||||||
if let Some(mtm) = MainThreadMarker::new() {
|
|
||||||
NSApplication::sharedApplication(mtm).unhide(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
fn app_take_focus() {}
|
|
||||||
|
|
||||||
/// The current parent process id, for orphan detection. `None` off macOS (where
|
/// The current parent process id, for orphan detection. `None` off macOS (where
|
||||||
/// hephd does not supervise a helper — there is no Aqua session to inherit).
|
/// hephd does not supervise a helper — there is no Aqua session to inherit).
|
||||||
fn current_parent_pid() -> Option<i32> {
|
fn current_parent_pid() -> Option<i32> {
|
||||||
|
|
|
||||||
1
docs/changelog.d/client-reconnect.bugfix.md
Normal file
1
docs/changelog.d/client-reconnect.bugfix.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
The `heph` CLI and `heph-tui` now survive a daemon restart. Previously the unix-socket client connected once and never reconnected, so an opt-in self-update or `heph daemon restart` left every subsequent call failing — `heph-tui` would sit on errors until relaunched. The client now reconnects on a dropped socket: a request that never went out is retried transparently, while a reply lost mid-request is surfaced (not silently retried) so a mutation is never double-applied. A long-running TUI self-heals on its next refresh tick.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue