Skip to content

emrg: installer pre-stop — gracefully close GUI/TUI/daemon before overwriting (rant 2026-08-10T08:50:44) - #606

Merged
argszero merged 2 commits into
masterfrom
feature/installer-pre-stop
Aug 10, 2026
Merged

emrg: installer pre-stop — gracefully close GUI/TUI/daemon before overwriting (rant 2026-08-10T08:50:44)#606
argszero merged 2 commits into
masterfrom
feature/installer-pre-stop

Conversation

@argszero

Copy link
Copy Markdown
Owner

Windows installs of v0.2.10/v0.2.11 got stuck at "停止已有进程" (stopping existing processes) and the host had to reboot. Root cause: the Inno Setup installer overwrites %USERPROFILE%\.emrg\install (the daemon's runtime dir) without stopping running processes — the windowless pythonw.exe -m emrg.server daemon holds file locks, and Inno CloseApplications cannot see windowless processes.

Fix (pre-install graceful shutdown, order GUI → TUI → daemon):

  • new bin/stop-emrg.cmd: ① GUI taskkill /IM EMRG.exe (graceful WM_CLOSE, ~5s, then /F fallback) ② TUI python.exe -m emrg via command-line filter (wmic %%-escaped LIKE, PowerShell CIM fallback for Win11 24H2+ where wmic is removed; daemon pythonw -m emrg.server excluded) ③ daemon: emrg server stop protocol shutdown via the old install's CLI (present since emrg: Phase 4 packaging 资产 + daemon ping 响应补 type 字段(rant #12 §3/§6/§10/§12/§13) #364 — version-safe), emrgd.pid poll (≤10s), then taskkill /F /PID fallback. Returns 0 when nothing survives, 1 otherwise (installer aborts with a clear message instead of hanging). Clean installs skip everything.
  • bin/emrgd.cmd: new stop branch → python -m emrg server stop (reuses the tested _stop_daemon path; label flow so %errorlevel% expands after the child exits).
  • packaging/make-installer.sh: .iss gains [Files] dontcopy entry + [Code] PrepareToInstall that extracts and runs stop-emrg.cmd (via {cmd}, SW_HIDE) before file overwrite; non-zero exit aborts with actionable message.
  • packaging/build-runtime.sh: bundles stop-emrg.cmd into runtime bin/.
  • +4 tests (tests/test_installer_stop.py, text-assertion wiring — no iscc/cmd on macOS/CI): stop-emrg.cmd step coverage + order, emrgd.cmd stop branch, .iss PrepareToInstall/dontcopy/SW_HIDE, build-runtime copy. Doc counts synced: 670 → 674 pytest (README.md / Agent.md / README.cn.md).

Verification on this host: 674 pytest green, import + CLI checks green. Windows behavior must be validated by the host on the next release (expected per the new status rules, feedback flows back via new rants).

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle

Reviewed the full diff on branch feature/installer-pre-stop and verified locally:

  • Full suite: 674 passed (4 new tests in tests/test_installer_stop.py green), doc counts synced (README.md / README.cn.md / Agent.md 670→674), import + CLI checks green.
  • bin/stop-emrg.cmd: GUI graceful WM_CLOSE → /F fallback, TUI command-line filter (wmic %% escaped LIKE + PowerShell CIM fallback, daemon pythonw -m emrg.server excluded), daemon protocol stop via old-install CLI + emrgd.pid poll (≤10s) + taskkill /F fallback; clean-install safe (skips to exit 0).
  • bin/emrgd.cmd stop branch: label flow avoids %errorlevel% expansion trap; 'emrg server stop' confirmed present in emrg/main.py (line 62/104/158 _stop_daemon).
  • make-installer.sh: [Files] dontcopy + [Code] PrepareToInstall via {cmd} SW_HIDE, non-zero exit aborts with actionable message — consistent with the #592 no-console-window discipline and Inno CloseApplications blind spot for windowless pythonw.
  • build-runtime.sh bundles stop-emrg.cmd into runtime bin/.

Windows real-machine validation flows back via new rants per PR #605's updated status rules.

…ed parse-time %DPID% (rant 2026-08-10T08:50:44)

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle 20260810-091234. Re-reviewed the batch script and found + fixed a latent cmd.exe delayed-expansion bug in the :verify block (parse-time %DPID% inside a parenthesized block would make the daemon-alive check always false → false 'clean' exit). Now uses setlocal enabledelayedexpansion + !DPID!, with a discriminating regression assertion in tests/test_installer_stop.py. Local suite: 674 pytest green, import + CLI checks pass.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle 20260810-091736 (3rd approval). Final diff re-verified: delayed-expansion fix present, PrepareToInstall/dontcopy wiring intact, doc counts synced (674). CI green on updated branch.

@argszero
argszero merged commit bf2012e into master Aug 10, 2026
1 check passed
argszero pushed a commit that referenced this pull request Aug 10, 2026
argszero added a commit that referenced this pull request Aug 10, 2026
…ller pre-stop entries (#607)

* emrg: evolution_prompt quick-ref — add #605 status rules + #606 installer pre-stop entries

* emrg: quick-ref #606 — avoid literal {cmd} placeholder (test_build_prompt_all_variables_substituted)

---------

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
@pm25coder

Copy link
Copy Markdown
Contributor

I tested this PR on the Windows host (the exact target platform) after it was merged, and the Windows-specific logic checks out:

  • tests/test_installer_stop.py: 4/4 pass on real Windows; from emrg.client.app import run_client import + emrg --help CLI checks green.
  • Version-safe daemon stop claim holds: emrg server stop is confirmed present in master's emrg/__main__.py (since emrg: Phase 4 packaging 资产 + daemon ping 响应补 type 字段(rant #12 §3/§6/§10/§12/§13) #364), so calling the old install's emrg.cmd server stop is safe across versions.
  • Daemon-kill path verified end-to-end on a throwaway copy (home dir redirected so no live processes were touched): the script reads emrgd.pid, force-kills the PID after the ≤10s poll, and the :verify block returns 0 when nothing survives and 1 while a process remains — the delayed-expansion fix (setlocal enabledelayedexpansion + !DPID! in the parenthesized block) works as the regression test asserts.
  • GUI-kill path verified with tracing: with a freshly launched GUI (4 EMRG.exe processes), taskkill /IM EMRG.exe (graceful WM_CLOSE) closed the entire Electron tree within the 5s window — the after-check tasklist/findstr returned not-found, so the /F fallback was correctly skipped and the final process count was 0.

One observation worth carrying into the host-side validation: on a GUI session that had been running ~15h (started the previous evening), two runs of the full script did not terminate it, while a direct taskkill /IM EMRG.exe did. This looks like a state-dependent WM_CLOSE deferral on a long-lived Electron session rather than a script defect (fresh GUI closes reliably within 5s), but it may be worth a slightly longer graceful wait or an unconditional /F after timeout so an old GUI session can never hold the installer hostage.

Full local verification was done on master bf2012e (the merge commit) with a clean tree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants