| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Closes STEER-20261102-201234-7200 (read_file capped at 6000 while the schema
promised 32000).
Budgets (module-aiassist.js + new modules/core/model-profiles.js):
- one resolver, precedence: call arg -> loop profile -> model profile ->
ai-config -> code default. Keys: read-page-chars, read-result-chars,
tool-context-budget, fetch-chars.
- model classes tiny/small/mid/large keyed by id then by size token; `mid`
reproduces the old numbers so nothing moves for a mid model.
- _clipToolResult now clips the `content` field, never the serialised JSON
envelope: clipping the envelope deleted truncated/next_offset, so a 16k page
lost its continuation pointer (the reported symptom).
- read_file's schema no longer promises a number the model class may not give.
Telemetry:
- _recordToolCall keeps sizes, duration, ok and a 120-char arg preview instead
of the whole payload; ai-stats prints calls / ok% / avg ms / KB / truncation
from localStorage webx11_tool_stats.
Server (api/proxy-api.py):
- /api/extract honours max_chars (default 12000, cap 100000) and returns
content_chars + truncated; the bs4 branch is no longer uncapped while the
regex fallback was silently cut at 10 000.
BEHAVIOUR CHANGE: num_ctx for a model with no explicit setting now follows the
class default (16384 -> 65536 for cloud/large, 8192 for tiny). Cloud models bill
on tokens used, so cost is unchanged; local models get a bigger KV cache.
Two build traps, both now documented in AGENTS.md:
- model-profiles.js must be the FIRST entry in CORE_FILES and must export the
MODEL_PROFILES global (a TDZ typeof throws; without the global every budget
silently falls back to the code default).
- a budget key needs the setter branch AND the constructor loader at
module-aiassist.js:49 - persisting without restoring looks fine until reload.
Verified: test-tool-context-bound 23/23 (RED before: E1-E4 + TypeError on
_toolLimit); live bundle read_page 32000 / result 12000 / budget 48000 /
fetch 12000 and _ctxTokens 65536 for gemma4:31b-cloud; /api/extract 28970 ->
500 chars with truncated true; ai-config write+restore probe 6/6.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
status (v4.6.131)
Four items closed in one batch; three ran as parallel subagents on disjoint files, the bundle was
rebuilt once by the parent (rebuild-bundles.py serialises the working tree, which carries other
sessions' work — see 161372f).
1. PIPE STAGES KEEP THEIR QUOTES. `js "a b".length | wc -c` reached eval as `a b.length` and printed
a ReferenceError. terminal.js executePipeChain() now keeps `stages[i]` aligned 1:1 with
`pipeParts[i]` (the `.filter(argv => argv.length > 0)` shifted the index; replaced by a lastStage
scan + `if (argv.length === 0) continue`) and forwards the stage's own text to the dispatcher.
The core path alone was dead code: ShellModule.init() replaces terminal.executePipeChain
(shell.js:144), and that override is what runs in the browser (`executePipeChain.toString()`
contained `cmdText.split`, not `lastStage`). Both now pass `cmdText`/`pipeParts[i]`.
test-pipe-guard.js was rewritten for the new shape and now also asserts the shell override
forwards raw text — the assertion that would have caught the shadowing. RED on HEAD: both flags
false; GREEN now.
2. MAINTENANCE --fix CAN CLEAR ITS OWN WARN. check_index() ran before check_atlas(), which is what
regenerates course/atlas.json, so --fix rebuilt modules-index.json from the stale atlas and the
same WARN reappeared every run. check_atlas() now runs immediately before check_index().
modules-index.json regenerated: cost/usage present, 349 commands, version 2026-10-29-atlas.
3. `cost` DOCUMENTED. modules/core/module-billing.js registers `cost [on|off]` (an alias of `usage`);
help.html had no row. Added above the `usage` row. help coverage 362/363 -> 363/363.
4. SHIPPED PLANS STOP ASKING FOR A DECISION. The applier only flips review<->safe, so every executed
review-gated plan kept counting as an open decision (5 of 5). newos4-feedback-collect.py now reads
the body: a `## Status` / `## Implementation` heading followed by shipped|executed plus a version,
commit or date is `status: done`; those stay in `plans` (visible as shipped) but leave
plans_review and awaiting_decision. Counts: plans_review 5 -> 0, awaiting_decision 4 -> 1
(the remaining one is a real open report, RPT-20261027-160751).
admin/feedback.html read `it.status[0]`, which would render `d` for a string status; it now
prefers `status_lines[0]`.
Also carried, authored by earlier uncommitted sessions and already live in the bundle (attributed,
not silently absorbed): modules/core/module-billing.js (new, BillingModule: cost/usage),
its CORE_FILES entry in scripts/rebuild-bundles.py, and the BillingModule registry entry in
terminal.js. The bundle was rebuilt from HEAD + this batch with ollama-manager.js taken from HEAD,
so another session's in-flight `_httpError` refactor is deliberately NOT in the shipped bundle
(grep -c _httpError core-bundle.js = 0).
Verification
node modules/test/test-pipe-guard.js -> {"empty":[],"blank":[],"classifyGuarded":true,"pipeGuarded":true,"shellForwardsRaw":true}
node modules/test/test-parse-args.js -> 28/28 pass
maintained job -> node tests 21/21 pass
scripts/newos4-maintain.py -> maintenance result: OK (modules-index 349, help 363/363,
changelog current v4.6.131)
live v4.6.131 (real DOM, no print monkey-patch):
js "a b".length | wc -c -> 1 (js printed 3, one byte)
js "a b".length -> 3
js "abc".toUpperCase() -> ABC
echo "two words" -> two words
node -e "import('fs')" -> red error + Node-builtin hint
js 6*7 -> 42
unhandledrejection -> 0
livePipeImpl: shell-override, livePipeForwardsRaw: true, costRegistered: true
|
| | |
|
| | |
|
| | |
|
| |
|