<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/modules/ext/webdav.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-06T10:45:21+00:00</updated>
<entry>
<title>release(v4.6.150): commit the module work that has been live but uncommitted</title>
<updated>2026-11-06T10:45:21+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-06T10:45:21+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=03143a6e88832d06c7b08cdbf8de96ba79bda7d6'/>
<id>urn:sha1:03143a6e88832d06c7b08cdbf8de96ba79bda7d6</id>
<content type='text'>
Operator commit-approve, 2026-11-06. These changes have been served since
2026-11-02/03 while git HEAD still stamped v4.6.146, so the mirror published a
tree four builds behind the running instance and the release tag named the
wrong build.

module-orchestrator.js — orchestrate-parallel reported success it could not
prove. Results are now recorded by sub-task id through a resultSink handed to
delegateTask (harvest matched by currentTask/lastTask strings, which a later
delegation on the same agent overwrote, losing finished work as "agent not
found"); the tally counts summaries with status ok instead of
Promise.allSettled resolutions (a spawn refusal fulfils with undefined and used
to print green); and a busy agent is no longer reused at pool cap, where two
siblings erased each other's lease. Guard:
modules/test/test-orchestrator-parallel-harvest.js (16 cases, reproduces the
one-agent three-sub-task cap case that printed 3/3 succeeded).

module-billing.js — the balance said "not signed in — newOS4 sends no session
token", which was already false: the browser sends the HttpOnly cookie and
parse_bearer_token() falls back to it. `cost` is on by default (the flag was
opt-in and nobody knew the command existed; `cost off` opts out) and the
command now prints today's platform spend from GET /api/billing/usage?days=1
alongside the session estimate.

modules/ext/webdav.js — the inline WebView detector missed "Version/4.0"
Android WebViews, including the operator's own phone, so the login offered a
Telegram widget that cannot complete there. It now delegates to
modules/wx11-tg-webview.js when the page loaded it and keeps a matching
fallback (wv token, Version/4.0-Android, Telegram, FBAN/Instagram/Line).

modules/ext/media.js — text analysis model renamed deepseek-v4-flash -&gt;
deepseek-v4.1-flash in both the field and the printed label.

main.html + module-loader.js — v4.6.146 -&gt; v4.6.150 in LATEST_VER and the three
asset queries; core-bundle.js rebuilt (rebuild-bundles.py reports it already
in sync, 1,250,569 bytes).

Verified: node --check on all six scripts and the new test; the 16-case
orchestrator guard passes against the deployed bundle (ORCH_SRC=...); bundle
rebuild is a no-op; core-bundle.js?v=v4.6.150 answers 200.
</content>
</entry>
<entry>
<title>fix(auth-ui): stop offering a Telegram widget where it cannot work</title>
<updated>2026-11-02T21:02:45+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-02T21:02:45+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=d01d94bed3038b4fc122b2cc17f0773b9bf4dc9f'/>
<id>urn:sha1:d01d94bed3038b4fc122b2cc17f0773b9bf4dc9f</id>
<content type='text'>
Two hosts cannot complete the widget flow and both are in use: an Android WebView /
in-app browser (the operator's phone UA ends "; wv)") and a desktop browser that blocks
the popup or hands the link to the Telegram app. The widget needs a popup that can
postMessage back into the opener; in those hosts the link lands in a browser tab or in
Chrome with no opener, onTelegramAuth never fires, and the login card looks dead —
"it opens my default browser" (reported twice: phone, then Max's laptop).

modules/wx11-tg-webview.js (new)
  WX11TG.isWebView()  -&gt; "; wv)", Telegram in-app, Meta in-app UAs
  WX11TG.dropWidgets()-&gt; removes already-rendered oauth.telegram.org iframes/scripts

dashboard.html
  code box is open by default and drops the nested &lt;details&gt;
  WebView: widget removed + "cannot work inside an app window" hint
  desktop: if the widget was clicked and onTelegramAuth has not fired in 12 s, open the
  code flow with a hint instead of leaving a dead card

spaces/newos4 (webdav-login panel)
  in a WebView the widget is never injected, the mount is hidden and the device-code
  flow starts by itself; desktop keeps the widget unchanged
  version v4.6.145

Measured with playwright (390x844 WebView UA and 1440x900 Chrome):
  WebView  -&gt; 0 Telegram iframes, hint shown, code box open, real WX11- code minted
  desktop  -&gt; widget still rendered, code box open, real WX11- code minted
  newOS4 WebView -&gt; no widget injected, code area auto-visible, code WX11-..., no JS errors
  newOS4 desktop -&gt; widget still offered
</content>
</entry>
<entry>
<title>fix(newos4): memory-graph loads stop rewriting user data; unknown sizes say unknown</title>
<updated>2026-11-02T20:15:28+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-02T20:15:28+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=3b894c31c456592a21b36a7696423ad0936edab7'/>
<id>urn:sha1:3b894c31c456592a21b36a7696423ad0936edab7</id>
<content type='text'>
Three follow-ups from the merge review, each with the assertion that pins it.

module-memory-graph.js
- _normalizeEdges no longer mutates stored weights. It capped legacy 'failed' edges
  from 0.8 to 0.2 in memory, and the next debounced save made that permanent - an
  irreversible migration of the user's graph with no schema version. The cap moved to
  _effectiveWeight(), which ranking (showStats "Strongest relationships"), the session
  view and prune() now use; the stored record is left exactly as written.
- config.json is stamped version: 2 so a future format change can migrate deliberately.

ext/webdav.js
- the two fallback parsers emit size: null instead of 0. They cannot see the size
  column, and 0 rendered as "0 B" - the same "every file looks empty" symptom as the
  parseInt bug fixed in e639c2d, one regex miss away.
- _formatSize(null) renders '—' (unknown) rather than '0 B'; 0 still renders '0 B'.

module-aiassist.js
- the lock timeout now says what to do: "AI is still busy with another turn (waited Ns).
  Wait for it to finish, or run 'ai-stop' and retry - the running turn's lock is left
  alone." It used to be a dead-end string.

Tests: test-memory-graph 39 (T6.4 rewritten to the read-time contract: stored weight
stays 0.8, effective 0.2, success unaffected), test-webdav-sizes 28 (A14d null -&gt; '—').
maintain 26/26, live v4.6.141: _effectiveWeight 0.2 with the edge object unchanged,
_formatSize(null) '—', '0 B' still '0 B'.
</content>
</entry>
<entry>
<title>fix(newos4): WebDAV listing sizes + pull, and five MemoryGraph defects</title>
<updated>2026-11-02T20:05:58+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-02T20:05:58+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=35ca5324ca5a0b3e1e6f02663e1e44d6e06e50ba'/>
<id>urn:sha1:35ca5324ca5a0b3e1e6f02663e1e44d6e06e50ba</id>
<content type='text'>
Closes STEER-20261102-205416-facd and STEER-20261102-204031-f82a.

WebDAV (modules/ext/webdav.js):
- listings showed "21 B" for a 21 KB file: nginx emits humanised sizes
  (autoindex_exact_size off, vhost :412) and _parseAutoindex did parseInt("21K").
  _parseAutoindexSize() handles K/M/G, decimals, lowercase and "-"; PROPFIND's
  exact getcontentlength path is untouched.
- webdav-pull into a missing local directory printed "Pulled: ... (N bytes)" and
  wrote nothing: it ignored fs.writeFile's false return (virtual-fs.js:561).
  It now creates the parent chain, checks the write, and only reports success
  after a confirmed write. The byte count uses TextEncoder, not .length
  (a Cyrillic file under-reported ~2x).
- _formatSize gained the GB branch the parser already accepted (3 GB printed
  "3072.0 MB") and no longer prints "NaN MB" for a missing size.

MemoryGraph (modules/core/module-memory-graph.js):
- addEdge averages weights, so every repeat pulled a strong edge toward the
  call site's constant (0.9 -&gt; 0.7 -&gt; 0.6). Now Math.max, with decay left to
  applyDecay(); prune() untouched.
- task ids were `task-${Date.now()}`, so re-submitting a task never deduped:
  now a hash of agent + normalised text.
- recordFileAccess no longer records the graph's own /.memory_graph/ store.
- failed tool calls were weighted 0.8 vs success 0.5, so showStats ranked
  failures as strongest: now 0.2. Legacy 0.8 failures are capped on load.
- concept ids keep punctuation ("concept:(v2!),"): slugged, and the slug uses
  \p{L}\p{N} so Cyrillic/CJK/accented text still yields nodes -- an a-z0-9 slug
  silently produced none.

Review findings folded in from the regression pass: the non-Latin regression
(a-z0-9 slug), the GB formatter asymmetry, and the pull byte count were all
found by review, not by the patch authors, and each now has a test.

Tests: test-webdav-sizes.js 27 (was RED 15/24 before the fix), test-memory-graph.js
37 (RED 17/32), both auto-discovered by newos4-maintain -- 26/26 node tests.
Live on v4.6.140: _parseAutoindexSize('21K') 21504, _formatSize -&gt; "21.0 KB",
_formatSize(2GiB) "2.0 GB", slug Cyrillic "исправить-парсер-ошибок", 0 console errors.
</content>
</entry>
<entry>
<title>feat(newos4): cut/copy in Files, paste into WebDAV (Issue D2)</title>
<updated>2026-10-26T14:25:58+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T14:25:58+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=132185e96034fca3bd2fc95998dd778e9e22258b'/>
<id>urn:sha1:132185e96034fca3bd2fc95998dd778e9e22258b</id>
<content type='text'>
The two panes kept separate clipboards (filemgr._clipboard vs webdav._selected), so "cut here, paste
there" did not exist — the operator's last phone-test item.

filemgr.js  _openOverlay() publishes a read-only view of its clipboard on the terminal object:
            webx11.fileClipboard() / fileClipboardClear() / fileClipboardSet(paths, mode).
webdav.js   the bulk bar gains "📥 Paste N" (hidden when the clipboard is empty). Handler: for each
            path readFile -&gt; _webdavRequest('PUT', dest + '/' + name, {body}); only 200/201/204 counts.
            For mode "cut" the local file is deleted AFTER the server accepted the bytes, never
            before. A failed PUT keeps the local copy, prints "📥 Paste failed: &lt;name&gt; — HTTP n",
            and leaves that path in the clipboard so "📥 Paste 1" is a retry. Successes leave it.
            Summary "📥 Pasted N item(s) to &lt;path&gt;" (+ "— M failed"), then the pane reopens there.

Semantics: cut moves (upload then delete local), copy leaves the local file and keeps the clipboard so
the same files can go into several folders.

Verified with the transport stubbed in the live page (this browser has no WebDAV credential):
  button "📥 Paste 2" for a 2-path cut
  PUT ok (201)  -&gt; local file null        (moved)
  PUT fail(500) -&gt; local file "BBB"       (kept)
  clipboard after -&gt; {mode:"cut", paths:["/fail-d.txt"]}, button "📥 Paste 1"
node --check both modules, no-undef clean (55 files), v4.6.101 x3 in main.html, syntax OK, help 362/362.
</content>
</entry>
<entry>
<title>fix(newos4): four phone-test defects — no preview close, single-file share, dead-end fullscreen, silent WebDAV move</title>
<updated>2026-10-26T14:21:14+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T14:21:14+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=7904f3e9300a4ee02243728c185e8bfce0953bb1'/>
<id>urn:sha1:7904f3e9300a4ee02243728c185e8bfce0953bb1</id>
<content type='text'>
All four came from the operator's phone pass on v4.6.95 and each collapsed to a line of code.

A "No file selected to download": the preview pane had no close control; the only ✕ was the file
  manager's own, and it calls _closeOverlay() which wipes _multiSelect/_selectedFile/_selectMode.
  On a phone the preview covers the list, so closing it before pressing Download always emptied the
  selection. The toolbar now starts with ✕ -&gt; _clearPreview(), which keeps the selection and leaves
  fullscreen first; Download with no targets names the fix instead of stating a dead end.
B share/copy: 🔗 existed only in the preview toolbar and took a single path, and after the Android
  share sheet there was no copy affordance. Added _sharePaths(paths, mode) used by both the toolbar
  (1 path, 📋 copy and 🔗 share) and a new action-bar 🔗 Share (whole selection), plus
  _inlineLinkBox() which renders a selectable input/textarea with all URLs when neither the share
  sheet nor the clipboard is available. No prompt() anywhere on this path.
C fullscreen: requestFullscreen targeted .fm-preview-body, which sits INSIDE the pane but excludes
  the toolbar, so ⛶ and ✗ disappeared and only the OS back gesture got out. Now fullscreens
  #filemgr-preview — toolbar, ✕ and ⛶ stay on screen and ⛶ toggles.
D webdav move: bulk Move asked for the destination with prompt(), which returns null in iOS
  standalone PWAs and most Android WebViews, so it silently did nothing and looked unimplemented.
  Destination is now an inline row in the bulk bar (44px input + "Move here"/"Cancel", prefilled).

Verified on the served code: ext bundle md5 5f440c77b6ab5529729aee8019a6c351 (served == local),
webdav.js carries wdav-move-dest x2, and a headless browser probe on the real page shows the toolbar
as ["✕","⛶","📋","🔗"], closing the preview prints "Preview closed — selection kept" with the
selection intact, selecting 3 files and copying yields a textarea with the 3 real WebDAV URLs, and
Download with nothing selected explains what to do. 6 PASS on the URL test, no-undef clean,
v4.6.99, help 362/362.

Not done, deliberately: cut/copy + paste across the VFS/WebDAV border. Recorded as Issue D2 in the
plan with the exact insertion points, the upload-then-delete ordering rule and the failure case.
</content>
</entry>
<entry>
<title>fix(newos4): download link uses the user's space; WebDAV share copies verified file links; preview fullscreen+share; files-&gt;WebDAV upload button (v4.6.45)</title>
<updated>2026-10-21T20:34:12+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-21T20:34:12+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=82de48abbac8ae50f3c3859a4118a606145fc55a'/>
<id>urn:sha1:82de48abbac8ae50f3c3859a4118a606145fc55a</id>
<content type='text'>
- download: URL built from _resolveSpaceName() (config url = logged-in user), not the page space
- WebDAV browser 🔗: shares selected FILES only, URL-encoded, HEAD-verified (200) before claiming success;
  folders offer a tar fallback instead of a guaranteed-403 link
- file manager preview: ⛶ fullscreen + 🔗 copy-link toolbar (was none)
- file manager toolbar: ☁ WebDAV publishes selected/current file via webdav-push
- modules/test/test-download-url.js: 4 PASS
- rebuild bundles, bump v4.6.44 -&gt; v4.6.45 (loader + 3 script tags)
</content>
</entry>
<entry>
<title>auto: 2026-07-29_20:45 changes</title>
<updated>2026-10-15T03:00:13+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-15T03:00:13+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=6fe4a66e98adf722a56bf185a0a8f2083f13dcb2'/>
<id>urn:sha1:6fe4a66e98adf722a56bf185a0a8f2083f13dcb2</id>
<content type='text'>
</content>
</entry>
<entry>
<title>auto: 2026-07-29_20:45 changes</title>
<updated>2026-10-08T03:06:06+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-08T03:06:06+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=d3a325187ea222f6c4c368b6335f11de79a1162c'/>
<id>urn:sha1:d3a325187ea222f6c4c368b6335f11de79a1162c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>newOS4 v4.6.18: nginx dav trailing-slash semantics</title>
<updated>2026-10-02T19:25:46+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-02T19:25:46+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=2ec6532511eb5cae90d4ec2813742000914853a7'/>
<id>urn:sha1:2ec6532511eb5cae90d4ec2813742000914853a7</id>
<content type='text'>
Discovered by dav-health-check.sh E2E (10/10 pass now):
- nginx dav module REQUIRES trailing slash on MKCOL (no-slash → 409)
  and on directory DELETE (no-slash → 409/404); existing dir + slash
  MKCOL → 405 (the real 'already exists' signal)
- _normalizeRemotePath now PRESERVES trailing slashes (collection ops)
- _ensureDir MKCOLs with trailing slash
- _deleteFile retries with slash on 409/404 (collection delete)
- health-check expectations corrected (405 = existing, slash required)
</content>
</entry>
</feed>
