Fix #2278: [Bug] memos-local-plugin: --daemon entry never starts the status heartbeat — hea - #2280
Conversation
The pure-ESM bridge entry (bridge.mts -> dist/bridge.mjs, preferred by the launcher since MemTensor#1998) only started the bridge-status.json heartbeat in its stdio branch; the --daemon branch never called markConnected() / startHeartbeat(), so daemon spawns never refreshed the status file and the health endpoint reported "Hermes bridge heartbeat is stale" forever while RPC kept working. Mirror the stdio pattern into the daemon branch after the viewer binds (and stop the heartbeat on shutdown). Apply the same parity fix to legacy bridge.cts, whose daemon path had the identical gap. Add a source-level regression guard (pattern of bridge-startup-ordering.test.ts). Fixes MemTensor#2278
🤖 Open Code ReviewTarget: PR #2280 ✅ OpenCodeReview: Review skipped: no items were selected. Generated by cloud-assistant via Open Code Review. |
|
|
We hit this exact bug in production after upgrading a Hermes deployment from v2.0.7 to v2.0.16 — the launcher switched from
Deploying the two-line fix (daemon branch calls Also reviewed this PR against our equivalent patch (#2279, now closed in favor of this one). This is the better fix: it repairs both entries — including the |
|
Thanks for investigating #2278 and for adding regression coverage. We reproduced the reported stale-heartbeat behavior and replaced this approach on The replacement makes the stdio bridge the sole status writer and keeps daemon mode read-only. It reconciles expired status with the actual Hermes Chat process state without rewriting Closing this PR as superseded by the safer ownership model in |
Description
Fixes #2278: the memos-local-plugin
--daemonbridge entry never started the bridge-status heartbeat, so a daemon-spawned bridge never refreshed bridge-status.json and the health endpoint permanently reported "Hermes bridge heartbeat is stale" while RPC kept working.Root cause: the pure-ESM entry
apps/memos-local-plugin/bridge.mts(built todist/bridge.mjs, which the Python launcher has preferred since #1998) only calledmarkConnected()/startHeartbeat()inside its stdio branch (if (!args.daemon)); the--daemonbranch had no status calls at all. A source-level git-history check confirmed the legacybridge.ctsdaemon path had the same gap (never called there even in the original signal-light commit 22ccacb), which is why the ESM translation lost it.Fix: mirror the stdio pattern into the daemon branch of both entries — after the viewer bind-retry loop succeeds, call
bridgeStatus?.markConnected()andbridgeHeartbeat = bridgeStatus?.startHeartbeat(); stop the heartbeat inshutdownDaemon(SIGINT/SIGTERM). The bridge core is fully initialized before the daemon block, so "connected" is never claimed prematurely; OpenClaw is unaffected (all calls are?.-guarded no-ops sincebridgeStatusis null for openclaw); the heartbeat timer is unref()ed and does not hold the daemon open. Stdio-mode behavior is unchanged and pinned by the new regression test.Regression guard: added
apps/memos-local-plugin/tests/unit/bridge/bridge-daemon-heartbeat.test.ts, a source-level guard following the existingbridge-startup-ordering.test.tspattern (#1747). It asserts both entries start the heartbeat inside theif (args.daemon)branch while the stdio branch keeps its own calls. Verified TDD-style: the test fails on the pre-fix code (both entries) and passes after the fix.Test evidence (real output):
vitest run tests/unit/bridge tests/unit/bridge-status.test.ts-> 8 files / 39 tests passed;tsc -p tsconfig.json --noEmit-> exit 0;vitest run tests/unit-> 164 files / 1351 passed, 1 skipped. (An initial full-suite run showed failures in unrelated modules caused by pnpm skipping native build scripts locally — better-sqlite3/esbuild/onnxruntime/sharp; after approving those builds the entire suite is green. The change touches only bridge.mts, bridge.cts, and the new test.)opsp artifacts archived to the memos-autodev-specs repo (task.md + proposal/spec/design/tasks/test-cases/verification-report) on commit b89a59e.
Related Issue (Required): Fixes #2278
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Automated tests are pending.
Checklist
@whipser030, @hijzy please review this PR.
Reviewer Checklist