<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/modules/ext/ui-easy.js, branch main</title>
<subtitle>newOS4 - the browser terminal that runs WebX11 user spaces</subtitle>
<id>https://newos.webx11.duckdns.org/newos4/atom?h=main</id>
<link rel='self' href='https://newos.webx11.duckdns.org/newos4/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/'/>
<updated>2026-11-07T18:03:38+00:00</updated>
<entry>
<title>fix(newos4): second review round — identity for every stock node, load dedup, sweep race, a11y</title>
<updated>2026-11-07T18:03:38+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-07T18:03:38+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=05d72563637e88825ff852d803621c567de47e34'/>
<id>urn:sha1:05d72563637e88825ff852d803621c567de47e34</id>
<content type='text'>
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-&lt;id&gt;']; 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
</content>
</entry>
<entry>
<title>feat(newos4): six interface modes (easy -&gt; cockpit) over one terminal</title>
<updated>2026-11-07T17:19:47+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-07T17:19:47+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=aac2b1c0689aefeb140e08c24278ec486611fe10'/>
<id>urn:sha1:aac2b1c0689aefeb140e08c24278ec486611fe10</id>
<content type='text'>
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 -&gt; 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 -&gt; 25/25; removing both _restoreStock()
calls measures 20/25 with five FAILs; probe-ui-modes.py --cycle against production -&gt;
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.
</content>
</entry>
</feed>
