emrg: TUI user messages render as markdown + stop_all self-held lock attribution - #847
Conversation
…attribution
Rant 2026-08-18T18:52:45 (Plan B, superseding 18:50:14): user messages in
the TUI now render through the same Rich markdown pipeline as assistant
messages (width-based wrapping, CJK handling) via a new UserMarkdown
widget, while keeping the "> " prefix + bold cyan role visual.
ChatHistory.add('user', ...) routes to UserMarkdown; system/tool/assistant
stay on ChatRow. update_last() handles UserMarkdown rows for the assistant
plain-text fallback path. +6 tests.
Rant 2026-08-18T18:57:09: stop_all no longer aborts installs whose only
locked files are python-dist DLLs held by stop_all's own runtime (the
interpreter must load them; they are released when stop_all exits, before
the installer overwrites via ewWaitUntilTerminated). createfile-probe
verify now attributes locked files to module-holder processes —
self/excluded-ancestor-held locks are self-held (advisory WARNING), only
external-holder or unattributable locks are residuals. Final self-lock
guard message changed from "installer will fail" to advisory. +4 tests.
Agent.md test count 952 -> 962.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 746: two host-rant fixes. ① Plan B user messages → UserMarkdown (Rich markdown pipeline = free width wrap + CJK, > prefix + cyan preserved; ChatHistory routes user→UserMarkdown, others stay ChatRow; update_last handles both). ② stop_all self-held attribution — _classify_locked_files splits self/excluded-ancestor-held locks (advisory, released on exit) from external/unattributable residuals (abort); final guard text advisory. Verified: pytest 961+1 (962), import+CLI OK, GUI 259; CI test+test-windows PASS.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 747 (2nd, independent re-review): head db0b000 unchanged since 746, CI test+test-windows PASS (run 32130391015), MERGEABLE CLEAN. Re-verified diff: ① UserMarkdown — static Rich markdown at ctx.width-len(prefix), > bold-cyan first-line lead + same-width indent continuations; ChatHistory.add routes 'user' only; update_last covers UserMarkdown; assistant/system/tool untouched. ② stop_all — _classify_locked_files pure fn (separator-agnostic norm, self/excluded-ancestor-held → self-held advisory, external/unattributable → residual conservative); verify wiring correct (mh_holders computed before probe block); final guard advisory text. _install_root() dedup + check_install_writable uses it. 10 tests (6+4) + doc count 962. No ❌ — 2/3.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 748 (3rd, independent re-review): head db0b000 unchanged since 747, CI test+test-windows PASS (run 32130391015), MERGEABLE CLEAN. 6 files (Agent.md, emrg/_stop_all.py, markdown.py, widgets.py, test_installer_stop.py, test_user_markdown.py) match the two-rant scope. 3/3 consecutive ✅ from cycles 746/747/748, no ❌ — merging.
Uh oh!
There was an error while loading. Please reload this page.
Two small fixes from host rants:
1. TUI user messages render as markdown (rant 2026-08-18T18:52:45, Plan B, superseding 18:50:14)
User messages in the TUI previously went through ChatRow, which split on \n but did not wrap to the terminal width — the buffer's width cap then truncated anything beyond one row. Per host-confirmed Plan B, user messages now render through the same Rich markdown pipeline as assistant messages (width-based wrapping + CJK wide-char handling), via a new
UserMarkdownwidget that preserves the>prefix + bold cyan role visual:emrg/client/python_tui/widgets/markdown.py: newUserMarkdown(static Markdown rendered atctx.width - len(prefix)so the first-line prefix never overflows; continuation lines get a same-width indent)emrg/client/widgets.py:ChatHistory.add('user', ...)routes to UserMarkdown;update_last()also updates UserMarkdown rows (assistant plain-text fallback path); system/tool/assistant roles unchanged (ChatRow)tests/test_user_markdown.py: 6 tests — wrap/no-content-loss, markdown styling, CJK boundary, ChatHistory routing, update_last2. stop_all: self-held python-dist locks no longer abort the install (rant 2026-08-18T18:57:09)
v0.2.49 evidence: stop_all killed the external browser-harness holder but then aborted because verify counted 12 python-dist DLLs (python313.dll, select.pyd, ...) held by stop_all's own runtime as residuals. Those locks are released when stop_all exits — and the installer runs stop_all synchronously (ewWaitUntilTerminated) before overwriting, so the abort was a false positive.
emrg/_stop_all.py: new_classify_locked_files()— createfile-probe locked files attributed to module-holder processes; files held only by excluded (self/ancestor) holders areself-held(advisory WARNING), only external-holder or unattributable locks stay residuals; final self-lock guard message changed from "installer will fail; re-run installer" to advisory "released when stop_all exits; installer continues"tests/test_installer_stop.py: 4 new unit tests for the attribution (self-held / external / unattributable / mixed) + updated assertions for the new advisory textVerification