@bobfrankston/rmfmail 1.2.284 → 1.2.285

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.
package/.commitmsg CHANGED
@@ -1,37 +1,37 @@
1
- Pressing the icon while it is running raises the window instead of restarting
2
-
3
- "Why does it show and disappear? Are you assuring only a single instance? ...
4
- you should still put me in the running version when I press the icon on the
5
- task bar."
6
-
7
- Single instance was assured by REPLACEMENT. Every launch that wasn't a
8
- share/mailto handoff ran replace-on-launch: SIGTERM the running daemon, wait,
9
- SIGKILL, then boot fresh. Press the taskbar icon and the window you already had
10
- is killed, disappears, and a new one fades up seconds later. From outside it
11
- reads as the app flickering out of existence for no reason.
12
-
13
- Replace-on-launch was written for the upgrade case — an older or orphaned daemon
14
- surviving a partial upgrade and leaving two windows on two versions — but it
15
- fired on every launch, ordinary ones included.
16
-
17
- instance.json already records the running version, so the two cases separate
18
- without guessing:
19
-
20
- same version the user wants the app, and it is already there — write
21
- pending-activate.json, let the running daemon raise its
22
- window, exit 0. Nothing is killed.
23
- different an upgrade landed; replace as before.
24
-
25
- The daemon answers with the same fs.watch + { _msgerWindow: "focus" } shape the
26
- mailto and share handoffs already use that native control message exists
27
- precisely so a background daemon can surface its window, which is exactly this
28
- situation. It also consumes a request that arrived while it was still booting,
29
- since fs.watch only sees files that land after it is installed.
30
-
31
- `-another` still opts out entirely, and every handoff path still returns before
32
- reaching any of this.
33
-
34
- Verified against the live daemon before publishing: launching a second copy
35
- printed "already running (PID 34012, v1.2.283) — raising its window", exited 0,
36
- wrote the request, and left the running daemon alive where the old code would
37
- have killed it.
1
+ Close the window where three daemons could start at once
2
+
3
+ "This does not look like a single instance ... but not one of the windows came
4
+ to the front." It wasn't one. Three daemons were running:
5
+
6
+ PID 1452 23:52:15.9
7
+ PID 34012 23:52:19.9 <- the only one instance.json knew about
8
+ PID 94964 23:52:25.0
9
+
10
+ Launched 4 and 5 seconds apart, each with its own window, and replace-on-launch
11
+ could never clean them up because it only ever knew about the last one to
12
+ register. Win+4 could not raise "the" window because there were three of them
13
+ and nothing owned the taskbar identity.
14
+
15
+ The hole: the launcher spawns a DETACHED daemon and exits immediately, while
16
+ the daemon does not register itself until it has built the store, started the
17
+ popout server and opened its window several seconds later. Every launch
18
+ arriving inside that gap reads instance.json, sees nothing alive, and starts
19
+ another daemon. Three launches within ten seconds, three daemons.
20
+
21
+ The launcher now claims the slot for its child the moment spawn returns, before
22
+ it exits. The child is alive from that instant and pidIsMailx is a liveness
23
+ check, so the claim is valid straight away; when the daemon later reaches its
24
+ own registration it writes the same PID again. A launch landing mid-boot now
25
+ takes the activate path added in the previous release and drops
26
+ pending-activate.json, which the daemon consumes as soon as it starts watching
27
+ which is exactly why that path checks for a request that arrived while it was
28
+ booting.
29
+
30
+ Also: startedAt was recomputed on EVERY write, and every popup and popout
31
+ window rewrites this file, so the field reported the last window event rather
32
+ than when the daemon started. It now survives childPids updates. That one cost
33
+ a wrong turn while diagnosing this — the file claimed the daemon had started
34
+ seconds ago when it had been up for minutes.
35
+
36
+ Ships separately from the activate fix in 1.2.284verified that release did
37
+ not already contain it.
package/npmchanges.md CHANGED
@@ -788,3 +788,43 @@ anything quieter no longer renders.
788
788
 
789
789
  Findings are unaffected: they never depended on the score.
790
790
 
791
+ ## v1.2.284 — 2026-08-27
792
+
793
+ Pressing the icon while it is running raises the window instead of restarting
794
+
795
+ "Why does it show and disappear? Are you assuring only a single instance? ...
796
+ you should still put me in the running version when I press the icon on the
797
+ task bar."
798
+
799
+ Single instance was assured — by REPLACEMENT. Every launch that wasn't a
800
+ share/mailto handoff ran replace-on-launch: SIGTERM the running daemon, wait,
801
+ SIGKILL, then boot fresh. Press the taskbar icon and the window you already had
802
+ is killed, disappears, and a new one fades up seconds later. From outside it
803
+ reads as the app flickering out of existence for no reason.
804
+
805
+ Replace-on-launch was written for the upgrade case — an older or orphaned daemon
806
+ surviving a partial upgrade and leaving two windows on two versions — but it
807
+ fired on every launch, ordinary ones included.
808
+
809
+ instance.json already records the running version, so the two cases separate
810
+ without guessing:
811
+
812
+ same version the user wants the app, and it is already there — write
813
+ pending-activate.json, let the running daemon raise its
814
+ window, exit 0. Nothing is killed.
815
+ different an upgrade landed; replace as before.
816
+
817
+ The daemon answers with the same fs.watch + { _msgerWindow: "focus" } shape the
818
+ mailto and share handoffs already use — that native control message exists
819
+ precisely so a background daemon can surface its window, which is exactly this
820
+ situation. It also consumes a request that arrived while it was still booting,
821
+ since fs.watch only sees files that land after it is installed.
822
+
823
+ `-another` still opts out entirely, and every handoff path still returns before
824
+ reaching any of this.
825
+
826
+ Verified against the live daemon before publishing: launching a second copy
827
+ printed "already running (PID 34012, v1.2.283) — raising its window", exited 0,
828
+ wrote the request, and left the running daemon alive — where the old code would
829
+ have killed it.
830
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/rmfmail",
3
- "version": "1.2.284",
3
+ "version": "1.2.285",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",