diff options
| author | Agando <roduccomm@gmail.com> | 2026-11-07 19:03:38 +0100 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-11-07 19:03:38 +0100 |
| commit | 05d72563637e88825ff852d803621c567de47e34 (patch) | |
| tree | 9ac21e6a6bcce3983d7df1a8304bb2896f2a9afa /modules/ext/ui-commander.js | |
| parent | e0b87c7b5a902dea69ac45ffa2e525387edebf42 (diff) | |
fix(newos4): second review round — identity for every stock node, load 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
Diffstat (limited to 'modules/ext/ui-commander.js')
| -rw-r--r-- | modules/ext/ui-commander.js | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/modules/ext/ui-commander.js b/modules/ext/ui-commander.js index 4ffdc8b..03af5be 100644 --- a/modules/ext/ui-commander.js +++ b/modules/ext/ui-commander.js @@ -82,7 +82,16 @@ body[data-ui-mode="commander"] #ui-root { display: grid; grid-template-columns: const name = String(entry.name); const isDir = entry.type === 'dir' || entry._virtual; const it = api.el('div', { class: 'item', text: (isDir ? '📁 ' : '📄 ') + name }); - it.addEventListener('click', () => api.exec((isDir ? 'ls ' : 'cat ') + name)); + // Quote the path: a VFS name with a space split into two arguments, and a leading `-` + // became an option flag (found by review). + const quoted = "'" + String(name).replace(/'/g, "'\\''") + "'"; + const run = () => api.exec((isDir ? 'ls ' : 'cat ') + quoted); + it.addEventListener('click', run); + it.tabIndex = 0; + it.setAttribute('role', 'button'); + it.addEventListener('keydown', (ev) => { + if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); run(); } + }); left.appendChild(it); }); } catch (e) { left.appendChild(api.el('div', { class: 'item', text: '(' + e.message + ')' })); } |