From c2f2ea62503f81c07f4d36d7c3a798b91146153e Mon Sep 17 00:00:00 2001 From: Agando Date: Mon, 2 Nov 2026 21:05:58 +0100 Subject: fix(newos4): WebDAV listing sizes + pull, and five MemoryGraph defects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 -> 0.7 -> 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 -> "21.0 KB", _formatSize(2GiB) "2.0 GB", slug Cyrillic "исправить-парсер-ошибок", 0 console errors. --- modules/ext/webdav.js | 52 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'modules/ext/webdav.js') diff --git a/modules/ext/webdav.js b/modules/ext/webdav.js index 7f3e7a7..e78e876 100644 --- a/modules/ext/webdav.js +++ b/modules/ext/webdav.js @@ -453,7 +453,7 @@ class WebDAVModule { const isDir = href.endsWith('/'); let size = 0; if (!isDir && sizeStr !== '-') { - size = parseInt(sizeStr) || 0; + size = this._parseAutoindexSize(sizeStr); } entries.push({ name: name, @@ -506,6 +506,25 @@ class WebDAVModule { return entries; } + // nginx autoindex with `autoindex_exact_size off` (our template) emits + // HUMANISED sizes: '512', '21K', '45K', '1.2M'. parseInt() read the leading + // digits and dropped the suffix, so a 21 397-byte file was reported as 21 B. + // Parse the suffix here, 1024-based, to match _formatSize() below. + _parseAutoindexSize(sizeStr) { + if (sizeStr === null || sizeStr === undefined) return 0; + const s = String(sizeStr).trim(); + const m = s.match(/^(\d+(?:\.\d+)?)\s*([KMG]?)i?B?$/i); + if (!m) return 0; + const num = parseFloat(m[1]); + if (!isFinite(num) || num < 0) return 0; + const unit = (m[2] || '').toUpperCase(); + const mult = unit === 'K' ? 1024 + : unit === 'M' ? 1024 * 1024 + : unit === 'G' ? 1024 * 1024 * 1024 + : 1; + return Math.round(num * mult); + } + _parseNginxDate(dateStr) { if (!dateStr) return null; // nginx default: 02-Aug-2026 14:30 @@ -1095,8 +1114,26 @@ class WebDAVModule { const resp = await self._webdavRequest('GET', remotePath); if (!resp.ok) throw new Error('HTTP ' + resp.status); const content = await resp.text(); - self.terminal.fs.writeFile(vfsPath, content); - self.terminal.print('Pulled: ' + remotePath + ' → ' + vfsPath + ' (' + content.length + ' bytes)', 'success'); + // Create the local parent chain FIRST: fs.writeFile() returns false + // when the parent directory is missing (_resolvePath bails), and the + // old code ignored that return and printed a success line for a + // write that never happened. + const slash = vfsPath.lastIndexOf('/'); + const parentDir = slash > 0 ? vfsPath.slice(0, slash) : ''; + if (parentDir && typeof self.terminal.fs.mkdirRecursive === 'function') { + if (self.terminal.fs.mkdirRecursive(parentDir) === false) { + self.terminal.print('Pull failed: cannot create local directory ' + parentDir, 'error'); + return; + } + } + const wrote = self.terminal.fs.writeFile(vfsPath, content); + if (!wrote) { + self.terminal.print('Pull failed: cannot write local file ' + vfsPath + + ' (missing directory or path is a directory) — nothing saved', 'error'); + return; + } + const _bytes = (typeof TextEncoder !== 'undefined') ? new TextEncoder().encode(content).length : content.length; + self.terminal.print('Pulled: ' + remotePath + ' → ' + vfsPath + ' (' + _bytes + ' bytes)', 'success'); } catch (e) { self.terminal.print('Pull error: ' + e.message, 'error'); } @@ -2442,8 +2479,11 @@ class WebDAVModule { } _formatSize(bytes) { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; - return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; + const n = Number(bytes); + if (!Number.isFinite(n) || n < 0) return '—'; + if (n < 1024) return n + ' B'; + if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB'; + if (n < 1024 * 1024 * 1024) return (n / (1024 * 1024)).toFixed(1) + ' MB'; + return (n / (1024 * 1024 * 1024)).toFixed(1) + ' GB'; } } -- cgit v1.2.3