| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
dedup, sweep race, a11y
Four models (kimi-k2.7-code, deepseek-v4-pro, minimax-m3, glm-5.3) reviewed the shipped change
set. Review log with every accepted and rejected finding:
.hermes/plans/2026-11-07_163420-newos4-six-ui-modes.review-log.md
- identity guard now covers every snapshot node, not just #terminal-container: terminal.js also
binds #output, #command-input, #input-area and #status-bar, so a cloned one leaves the terminal
writing into a detached node while the page looks perfect
- _restoreStock anchors on the next stock node already home, then on the recorded trailing
sibling; a raw child index was measured wrong (terminal,input,status-bar,quick-actions)
- _loading map: a double-clicked card or a repeated 'ui easy' loads the mode once
- _sweepPending returns while that id is in flight instead of declaring failure at 6 s and
overwriting the stored preference
- _syncChrome() on every switch (quick-actions was left in the tab order behind the mode root)
- picker: role=dialog/aria-modal/labelledby/focus, shown after 600 ms instead of waiting for a
registration that never happens with lazy modes, and suppressed when ?ui= already applied
- ?ui= must be one of the six; _loadMode only accepts packages['ui-<id>']; hasOwnProperty on modes
- VFS names are shell-quoted before reaching api.exec (cat/edit)
- refresh generation no longer bumps per tick (slow captures left later panes at '...')
- easy: padding shorthand reset the 34 px footer reserve (footer overlapped the composer)
- cockpit panes get tabIndex and focus; F1/F12 left to the browser; nothing swallowed in inputs
- api.el lost its unused innerHTML sink; the test lost its _parseArgs stub (it hid the regression)
- v4.6.155
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
handling
Reviewed the shipped change set with kimi-k2.7-code, deepseek-v4-pro, glm-5.3 and minimax-m3.
Findings below are the ones that survived verification against file:line; the rest are in
.hermes/plans/2026-11-07_163420-newos4-six-ui-modes.review-log.md
Accepted and fixed:
- apply() had no generation token: a lazy mode load that finished after the user switched to
another mode force-applied the abandoned one (`apply(want,{force:true})` in the .then).
Every apply() now bumps `_loadSeq` and the callback acts only while its token is newest.
Same token also removes a double mount: registerMode() already applies the mode as it
registers, so the callback was mounting every lazy mode twice (teardown+cleanup twice).
- _restoreStock() used the recorded `nextSibling` as insert anchor. Every real mode moves
SEVERAL stock nodes (terminal, input, status bar), so the recorded sibling is inside the
mode container and every insert fell through to append. Now anchors on the next stock node
that is already back home. A raw child index also fails (elements removed shift the
indices) — measured order terminal,input,status-bar,quick-actions.
- _abortToClassic() left the broken mode persisted and `_pending` set, so the next reload
retried the same failure with no way out. It now clears both and stores 'classic'.
- ?ui= reached classList.add('wx11-ui-' + id) unvalidated: a space or colon throws a
DOMException and boot dies. Validated against /^[a-z][a-z0-9-]{0,15}$/ and no longer
persisted (the comment always claimed it was a request, not a preference).
- Modes hide .prompt-label, so #command-input had no accessible name at all. The shell sets
aria-label once when a mode reparents it.
- cockpit: preventDefault on all F1-F8 killed help, the address bar and devtools. F1/F12 are
left to the browser and nothing is swallowed when focus is in a text field.
- commander: Ctrl/Cmd+K opened the palette even while typing in the composer. Ignored from
inside editable elements now.
- picker: role=dialog + aria-modal + aria-labelledby + focus on the first card.
- api.capture(): strip the quoting characters from argv (capturePipeOutput takes argv).
- stale `wx11-ui-*` body class removed on switch instead of accumulating.
Rejected with evidence:
- "loadModuleFromURL may not return a boolean" — modules/core/module-manager.js:56 returns
true on success and :60 false in the catch. Verified by reading the function.
- "_abortToClassic does not clear _pending" — it did not; that one is accepted above. The
sibling claim that it "leaves the broken mode persisted" was verified by reading the
function: it never touched localStorage, so also accepted.
- "mm.LATEST_VER / webx11_cache_ver are never set, so the mode URL falls back to ?v=0" —
modules/core/module-loader.js:12 sets window.webx11.moduleManager.LATEST_VER and :14-15
writes webx11_cache_ver. Verified live: the mode fetch carries ?v=v4.6.152.
- "moduleManager.modules may be a Map" — it is a plain object (terminal.moduleManager.modules
.CryptoGzipModule is the documented access path), so ui-commander's Object.keys works.
Verified: node modules/test/test-ui-shell.js -> 25/25 (the test now moves TWO stock nodes; a
raw-index restore fails it with "terminal-container,input-area,status-bar,quick-actions");
probe-ui-modes.py --cycle against production -> ALL PASS, 13 checks.
|
|
|
Symptom: newOS4 had exactly one layout. A first-time user had no way in that did
not require learning commands, and an operator had no surface showing live runtime
state; the only way to see heap/VFS/tool-call telemetry was to type cat /sys/...
Root cause: no UI layer existed. main.html hard-codes one flex column, and
terminal.js binds the stock nodes by id at construction, so an alternative layout
had to either duplicate the output stream or reparent the real nodes.
Fix:
- modules/core/module-uishell.js (new): mode registry, #ui-root, stock-node
snapshot/restore, identity check that reverts to classic when a mode removes or
clones #terminal-container, shell-docked #ui-foot (the AI stop button exists in
every mode), ui command, gated first-run picker, ?ui= honoured only if the mode
actually registers, lazy mode loading via the same loader ext modules use.
- modules/ext/ui-{easy,chat,studio,workspace,commander,cockpit}.js (new): six
reparenting skins with scoped CSS. Workspace/commander/cockpit read real /sys/*
mounts and captured command output; no value on screen is invented.
- modules/test/test-ui-shell.js (new): 25 assertions - teardown, clone rejection,
failed-mount fallback, footer docking, destructive-mode rejection.
- terminal.js: register the shell; make one failing ext module stop aborting the
rest of the serial load loop (it did, silently, which is why six ui-* files at
the end of extKeys never loaded).
- module-loader.js: LATEST_VER v4.6.152. The six ui-* keys are deliberately NOT
in extKeys - see the rate-limit note below.
- admin/scripts/probe-ui-modes.py (new): 6 modes x 2 viewports plus a --cycle pass
that switches all seven states on ONE page and asserts the output node keeps its
identity.
Also fixed, found while testing (pre-existing, production-affecting):
- nginx limit_req zone=webx11 burst 50 -> 200. One newOS4 boot fans out ~40 assets;
the bucket emptied mid-boot and every later module got 503. Measured in
webx11.error.log: "limiting requests, excess: 50.696 by zone webx11" against
modules/ext/ui-chat.js. A reload within ~50 s silently broke modules. Sustained
rate unchanged at 60r/m.
Verified: node modules/test/test-ui-shell.js -> 25/25; removing both _restoreStock()
calls measures 20/25 with five FAILs; probe-ui-modes.py --cycle against production ->
ALL PASS, 13 checks; served bytes: v4.6.152 x3 in main.html, class UIShellModule x1
in core-bundle.js, six ui-* packages in packages.json.
|