Skip to content

fix(memos-local-plugin): use POSIX-ERE-compatible pgrep pattern for hermes chat detection - #2192

Open
kiwipaulrob wants to merge 5 commits into
MemTensor:mainfrom
kiwipaulrob:fix/pgrep-ere-regex
Open

fix(memos-local-plugin): use POSIX-ERE-compatible pgrep pattern for hermes chat detection#2192
kiwipaulrob wants to merge 5 commits into
MemTensor:mainfrom
kiwipaulrob:fix/pgrep-ere-regex

Conversation

@kiwipaulrob

@kiwipaulrob kiwipaulrob commented Aug 2, 2026

Copy link
Copy Markdown

Summary

Fixes the Hermes chat process detection regex in the memos-local-plugin. The pattern introduced for #1915 used a JavaScript/PCRE non-capturing group, but pgrep -f on Linux compiles patterns with glibc's POSIX ERE engine. The invalid pattern made every detection call fail and left the daemon viewer stuck on "disconnected".

Root cause

The unit helper compiled the same string with JavaScript's RegExp, which accepts (?:...). That verified matching behavior but not whether the pattern passed to pgrep was valid ERE.

Fix

  • Build the runtime pattern with POSIX [[:space:]] character classes and capturing groups only.
  • Build the JavaScript test pattern from the same command grammar using equivalent \\s / \\S tokens.
  • Require chat to be a complete argv token, preventing false positives such as hermes chat-server.
  • Run the real pgrep binary on Linux and require an exit status of 0 or 1, so syntax errors and missing executables cannot pass silently.
  • Merge the latest main into the contributor branch.

Verification

  • Old pattern reproduction: pgrep exits 2 with a regex compilation error.
  • vitest run tests/unit/bridge/hermes-process.test.ts tests/unit/bridge-status.test.ts: 18 passed, 1 Linux-only test skipped on macOS.
  • npm run lint: passed.
  • npm run test:unit: 155 files passed; 1297 tests passed, 2 skipped.
  • npm run build: passed.

Notes

The Linux-only pgrep regression executes in CI. No runtime dependencies or generated dist/ files are added.

…ermes chat detection

The MemTensor#1915 pattern used `(?:\s+\S+)*` — a PCRE non-capturing group.
`pgrep -f` on Linux compiles patterns with glibc's POSIX ERE, which has
no non-capturing groups, so every call failed with:

    pgrep: regex error: Invalid preceding regular expression

`isHermesChatRunning()` swallows the error and returns `false`, so the
daemon viewer was permanently stuck on "disconnected" even with a
`hermes chat` session attached. The JS unit test passed because
JavaScript RegExp accepts `(?:…)` — the proxy was not faithful for ERE.

Replace the non-capturing group with a plain capturing group
`(\s+\S+)*`, which is valid in both POSIX ERE and JavaScript RegExp,
and update the doc comment to warn that the pattern must stay within
ERE. Add a regression test that runs the real `pgrep` binary and
asserts it does not exit 2 (regex syntax error), so a PCRE-ism can
never silently return.
@Memtensor-AI Memtensor-AI added area:plugin OpenClaw & Hermes status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 2, 2026
@Memtensor-AI

Memtensor-AI commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2192
Task: 8262da48899d2fa6
Base: main
Head: fix/pgrep-ere-regex

🔍 OpenCodeReview found 2 issue(s) in this PR.


1. apps/memos-local-plugin/bridge/hermes-process.ts (L42-L43)

The POSIX ERE pattern uses a capturing group ([[:space:]]|$) for the trailing delimiter, which is intentional since POSIX ERE lacks non-capturing group syntax. However, this capturing group is also present for the token-repetition group ([[:space:]]+[^[:space:]]+)*. On some pgrep implementations (e.g., macOS uses a different regex engine), POSIX ERE capturing group limits or backtracking behaviour with *-repeated capturing groups can vary. More importantly, the comment says 'capturing groups only', but $ inside an alternation group in POSIX ERE is interpreted as a literal $ by some older glibc versions rather than end-of-input. Consider documenting (or testing) which minimum glibc/pgrep version is required for ([[:space:]]|$) to work correctly as an end-of-string anchor, especially since this replaces the previously simpler \b word-boundary.

💡 Suggested Change

Before:

export const HERMES_CHAT_PROCESS_PATTERN =
  "hermes([[:space:]]+[^[:space:]]+)*[[:space:]]+chat([[:space:]]|$)";

After:

// Verified against glibc >= 2.17 (Linux kernel >= 3.x). macOS pgrep uses
// a different ERE engine; this pattern is Linux-only.
export const HERMES_CHAT_PROCESS_PATTERN =
  "hermes([[:space:]]+[^[:space:]]+)*[[:space:]]+chat([[:space:]]|$)";

2. apps/memos-local-plugin/bridge/hermes-process.ts (L47)

The JS pattern (?:\s|$) correctly replaces the old \b word-boundary for end-of-token detection. However, \b in the old pattern also guarded against matches like hermes chat-server (since - is a non-word character, \b still matched after chat there). The new (?:\s|$) is stricter and correct: it only matches when chat is followed by whitespace or end-of-string, which does properly reject chat-server. No regression here — but note that chatter would also be correctly rejected since chatter does not have \s|$ after chat. This is fine. Confirm this intent is covered by the unit tests, as the comment in HERMES_CHAT_PROCESS_PATTERN only mentions chatter and chat-server as rejection cases.

💡 Suggested Change

Before:

const HERMES_CHAT_JS_PATTERN = /hermes(?:\s+\S+)*\s+chat(?:\s|$)/;

After:

// Rejects: 'hermes chatter', 'hermes chat-server', 'hermes --profile=chat'
// Accepts: 'hermes chat', 'hermes chat --flag', 'hermes --skills x chat'
const HERMES_CHAT_JS_PATTERN = /hermes(?:\s+\S+)*\s+chat(?:\s|$)/;

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

⚠️ Automated Test Results: ENV ISSUE

The test environment encountered an issue that requires manual attention.

Details: Environment preparation failed before any gating tests executed. Failed scopes: memos_local_plugin
Branch: fix/pgrep-ere-regex

@kiwipaulrob

Copy link
Copy Markdown
Author

Thanks for running the checks. A quick note on the AutoTest result:

This failure is an environment-preparation issue, not a test failure. The report states "Environment preparation failed before any gating tests executed" — the runner never reached the memos_local_plugin test suite, so there is no test result from this run to act on.

For reference, here's what does validate this change:

  • open-code-review: no findings (context open-code-review, success)
  • CI sync check: passed
  • Unit tests: 15/15 pass locally (vitest run tests/unit/bridge/hermes-process.test.ts), including the new regression test that runs the real pgrep binary
  • Independent verification of the core claim: on a Linux host, the old pattern hermes(?:\s+\S+)*\s+chat\b makes pgrep -f exit 2 with regex error: Invalid preceding regular expression; the new pattern hermes(\s+\S+)*\s+chat\b exits 0/1 with no error. The fixed pattern also matches a live hermes process command line.

Could the AutoTest environment be re-run when convenient (or is there a known issue with environment prep for the memos_local_plugin scope)? Happy to help debug the env setup if logs are available.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (35/35 executed). memos_local_plugin/unit: 35/35. Duration: 5s

Branch: fix/pgrep-ere-regex

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 6, 2026
@syzsunshine219

Copy link
Copy Markdown
Collaborator

Maintainer follow-up completed on 02aa0d8b:

  • merged the latest main without conflicts;
  • changed the runtime expression to POSIX ERE character classes and kept a separate, semantically equivalent JavaScript regex;
  • added the complete-token regression for hermes chat-server and made the real-pgrep check Linux-only and strict about setup errors;
  • verified locally with TypeScript lint, build, targeted bridge tests, and the full unit suite (155 files, 1297 passed, 2 skipped);
  • AutoTest passed 35/35 and the GitHub Python matrix passed all 16 OS/Python combinations. One macOS runner initially failed during action download with Service Unavailable; rerunning that failed job passed.

OCR completed successfully. Its two remaining notes are non-blocking: the Linux target executes the exact pgrep pattern in CI, and the complete-token intent is covered by explicit chatter and chat-server tests.

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

Labels

area:plugin OpenClaw & Hermes status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants