<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/modules/test/test-shell-stdin.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-10-27T15:26:30+00:00</updated>
<entry>
<title>fix(newos4): piped grep searched the working directory instead of its input</title>
<updated>2026-10-27T15:26:30+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-27T15:26:30+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=fd24b52c87d53bad5bd9c81d8e008511f160eda5'/>
<id>urn:sha1:fd24b52c87d53bad5bd9c81d8e008511f160eda5</id>
<content type='text'>
The stdin work in 5cf5010 fixed wc/head/tail but left grep alone, and grep's no-operand branch
sweeps the cwd. Measured on v4.6.115: `cat /gdir/in.txt | grep zzz` answered
`other.txt:1: zzz in a cwd file` — a file that was never piped, and `cat in.txt | grep bbb`
reported the match twice (`in.txt` from the cwd sweep plus `__pipebuf__` from the injected file).

- module-fs.js: when terminal._pipeInput is set and no file operand was given, grep searches the
  staged text and prints `&lt;line&gt;: &lt;text&gt;` (stdin has no filename, as in GNU). The cwd sweep stays
  for a bare interactive `grep x`.
- shell.js: _isPipeAware now covers only sort/cut/uniq/expand. grep/head/tail/wc read _pipeInput
  themselves, so injecting the __pipebuf__ file produced duplicate hits and named stdin results.

Verification:
- test-shell-stdin.js 20 asserts (+4 for grep: no cwd match, non-match reports none, match prints
  no filename, -c counts stdin). RED on HEAD: G1/G2/G3 fail with `other.txt:1: zzz in a cwd file`.
- Suite 18/18 files; maintain --fix "node tests 18/18 pass".
- Live v4.6.116 after `cd /gdir` (where other.txt contains zzz):
  `cat /gdir/in.txt | grep zzz` -&gt; (no matches) · `| grep bbb` -&gt; `2: bbb` · `| grep -c b` -&gt; 1 ·
  `| head -n 2` -&gt; aaa,bbb · `| tail -n 1` -&gt; ccc · `| wc -l` -&gt; 3.

Credit: the false-positive grep was reported by the stdin subagent as an aside; re-derived here
against the live terminal before fixing.
</content>
</entry>
<entry>
<title>feat(newos4): the script runner runs scripts — control flow, variables, globs, redirects, stdin</title>
<updated>2026-10-27T15:23:21+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-27T15:23:21+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=f325b6d15179bb02147039c89e9fcfac6d8e067b'/>
<id>urn:sha1:f325b6d15179bb02147039c89e9fcfac6d8e067b</id>
<content type='text'>
MAINT-021 and MAINT-017, executed from .hermes/plans/2026-10-27_145500-newos4-script-runner.md.

- shell.js: new block parser (_parseBlocks) and executor (_runInstructions/_runSimple/_runCommand/
  _dispatchOne). `for`/`while`/`if` bodies now run, including one-line `if [ -f x ]; then y; fi`.
  Variables expand through _expandVars ($VAR, ${VAR}, $?, single quotes literal), globs expand
  through _expandGlobs (unquoted args only, per-command), and `&gt;`/`&gt;&gt;` capture the command's output
  into the VFS instead of being passed to the command as text.
- shell.js: a script never answers an unknown command by calling the AI any more. It prints
  `script:&lt;path&gt;:&lt;line&gt;: &lt;cmd&gt;: command not found` and sets $? — the AI fallback stays for typing.
- shell.js: unclosed blocks and bad `for` headers surface as `Script &lt;path&gt; failed: …` (the parse
  used to sit outside the try, so a bad script crashed the runner).
- shell.js: interactive path gets the same treatment — prompt globbing and `echo hi &gt; /f` now work.
  Cause of the asymmetry: the two code paths had separate dispatch.
- shell.js: `_isPipeAware` no longer injects the __pipebuf__ file into wc (it reads _pipeInput), and
  the module registers itself with a versioned URL and calls its own init() — registerModule() does
  not call init(), so the executeCommand wrapper was never installed from the boot bundle.
- module-fs.js: wc/head/tail/grep read piped stdin when no file operand is given; `cat` accepts
  several operands (`cat *.txt`); `ls &lt;file&gt;` names the file instead of printing "(empty)".
- main.html: shell.js removed from the extension list — it is already inside
  critical-ext-bundle.js, and loading it twice produced two ShellModule instances that could
  disagree about their version.

Verification:
- test-shell-script.js 27 asserts (parser, variables, globs, executor, redirect, command-not-found,
  one-line if, parse error). RED on HEAD: `TypeError: shell._parseBlocks is not a function`.
- test-shell-stdin.js 16 asserts (added by a subagent): wc -l/-c, head -n, tail -n over stdin, and
  the file-argument path unchanged.
- Suite 18/18 files; maintain --fix "node tests 18/18 pass".
- Live on v4.6.115, through the real executeCommand:
  `ls /n*.txt` -&gt; /n1.txt · `cat /n*.txt` -&gt; one|two · `echo hi &gt; /r.txt` then `cat /r.txt` -&gt; hi ·
  `cat /probe.txt | wc -l` -&gt; 3 (bare, no __pipebuf__) ·
  `script /run.sh` -&gt; item 1 / item 2 / item 3 / exists / command not found, exit 1, no AI routing.
</content>
</entry>
</feed>
