fix(#291): add graceful `jcode server reload` and wire installers to it
Adds a deterministic, directional upgrade path so an installed binary is
picked up without leaving a stale daemon running old code, and without ever
downgrading a newer/dev daemon.
- protocol: Request::Reload gains a serde-default `force` field (defaults to
true for legacy/desktop clients that omit it, preserving unconditional
reload). Roundtrip + legacy-default tests added.
- server: handle_reload(force) gates non-forced reloads on
server_has_newer_binary() (strict mtime direction). A skipped reload emits a
ReloadProgress{step:"skip"} + Done so callers can distinguish
already-current from an actual reload. This also avoids re-entering the
#277 reload-loop family.
- client_api: reload_with_force(force) returns the request id; reload() stays
force=true. TUI /reload and stale-server self-heal keep forcing.
- cli: new `jcode server reload [--force] [--json]` drives the request to a
terminal state, treats a mid-reload disconnect as the expected exec handoff,
waits (bounded) for await_reload_handoff, and reaps a dead socket when no
server is running. `server stop` now requires --force (deliberate hard kill).
- installers: install.sh / install_release.sh / install.ps1 best-effort invoke
`server reload` after swapping the binary (skippable via
JCODE_SKIP_SERVER_RELOAD=1).
Validated against an isolated live daemon: same-version -> no-op; strictly
newer candidate -> graceful exec reload; older candidate -> no-op
(anti-downgrade); 5x idempotent no-op (no loop); dead-socket reap. J
jeremy committed
c5818ecb719b3a559b3643930c9b6310c16cedfa
Parent: 6de6f92