lite has pager, index, log, commit, diff, merge/install and chat — but none of be's four basic READ views: list (github-style dir browser: entry + last-commit summary + age), cat (a file's own bytes, syntax-painted, no diff), tree (raw git-tree rows for a rev), blob (a blob by sha, emitted as a hunk like cat). All four exist in be as compact views (be/views/{list,cat,tree,blob}/*.js, 174–264 lines each) with mission comments naming their rulings; the port is the LITE-010 pattern — same view logic, lite's ODB access (git.tree/git.getHex, index/resolve.js, index/refs.js) instead of be's store/wtlog/resolve_hash stack, and lite's hunk/pager/plain output instead of core/emit.
be sources and their rulings, binding here: views/list/list.js (LIST-001: one row per entry, wt marker + name + pale last-commit summary + rel-age; a dir = newest commit under it), views/cat/cat.js (JAB-020 ruling: cat shows the file's OWN bytes, diff belongs to diff), views/tree/tree.js (JAB-008: <mode6> <type6> <sha40>\t<name>[/] rows in raw git-tree order, .. row when below root, fixed-format bytes), views/blob/blob.js (JAB-007 ruling: blob emits a HUNK like cat, banner blob <sha>, NOT a raw dump).
index/resolve.js (FSEG partial-path against a commit, LITE-011), index/refs.js, index/log.js's history walk, view/bro.js tokenize+hunk, view/pager.js, the --plain convention.be/test/list/{e2e,fuse.js}, be/test/cat/{links,nav-escape,rev}, be/test/blob/fullsha; tree has no dedicated dir — its contract is pinned in the view header.index/*.js bodies (LITE-014/016 wiring); tests are test/<topic>/run.sh, dash-safe, $LITEJAB runtime.Four new lite verbs, each paging as a coloured hunk at a tty and dumping plain bytes when piped or under --plain, ODB-only where possible (usable in a repo whose .git/be was never built; list's last-commit fuse may use the LITE-006 index the way lite log does).
lite list [<path>][?<rev>] — one row per entry: name + last-commit summary + short rel-age; dirs = newest commit under them; wt-change markers only if lite can classify cheaply, else drop the marker column and record it.lite cat <path>[?<rev>] — the file's own bytes, syntax-painted at a tty, verbatim under --plain; banner cat <path>.lite tree [<hex>|<path>] — the fixed <mode6> <type6> <sha40>\t<name>[/] rows, raw git-tree order, .. row when descended; plain bytes must byte-match the be shape.lite blob <hexlet> — the blob as a banner'd hunk, cat-alike, full-sha resolution from a 6..40 hexlet.///lite/, work there, jab put + report, never post.be/ and jab/ are READ-ONLY precedent; never read beagle/; scratch and builds in ~/tmp.$'\t'; no hand-rolled URI parsing — ?<rev> splitting follows whatever lite's existing verbs do (lite log/lite diff arg forms).Made, not proposed — each confirmed against the code before it was built on.
index/{list,cat,tree,blob}.js are the verbs, and index/read.js holds what all four share — the arg split, the path gate, the rev resolution, the tree descent, the bytes→hunk builder, relAge/verbCol. index/weave.js (shared by diff and merge) is the precedent; four private copies of a path gate would not be.<path>?<rev> splits through the uri._parse binding (quickjab/uri.c over abc/URI), never a hand-rolled scan for a '?'. The rev resolves as a REFNAME first, then any 6..40 hexlet — be's own order (resolveTip).cat/list/tree name a path IN the repository (the ?<rev> form has no other meaning), so the arg resolves against the cwd like log/diff and a .. climb above the root is refused. That is BE-011's ruling; be raises NAVESCAPE, lite says it in plain words. The bare lite <path> pager is a FILESYSTEM view and still confines nothing — pinned as its own check so nobody "fixes" it.hunk BANNER — the log/commit convention. tree --plain is therefore the JAB-008 row block byte for byte, cat --plain is cat(1), blob --plain is git cat-file blob. The banner rides the tty hunk, which is where JAB-007's "a HUNK, not a raw dump" actually bites.bro.buildFileHunk already mmaps a whole file into one.diff.js blobSha) — one sha1 per file in the one directory listed. So eq/mod/del for files and a FLAT dir: rolling wt dirtiness up into a dir marker costs a subtree walk per row and is not worth a column.list LISTS THE TRACKED TREE, not the raw worktree. lite has no ignore machinery, so a worktree scan would put .git and every build output in the browser. An untracked file has no row and be's new bucket never appears.index/log.js fileLog prefix scan on the LITE-006 lane, capped at its newest rev — exact, no walk at all. A DIR cannot be (INDEXES.mkd: the lane hashes a path one way, so it can never enumerate what lies under one), so dirs ride index/log.js ancestry newest-first, taking the first commit whose subtree sha differs from its first parent's. That IS O(history) → CAPPED at DIR_WALK_CAP = 512 LITE-013-style; past the cap an entry keeps its row with no summary and no age, which is be's own ceiling behaviour and is pinned as such.U spans per navigable row, not one. The pager reads a click target as "the span FOLLOWING the one under the cursor" (_targetAt), so Enter (row start) and a click on the name need one each. U bytes take no column, so the visible row stays the plain one to the byte. Found by the pty leg, not by reading.tree /root/sub/, cat /root/a.txt) while the banner stays repo-relative, so navigation works from a subdirectory too.view/bro.js gained three THEME slots — E/X/Q from the same dog/THEME.c status-verb table — for the marker column. No other view emits them.CATNOFILE/NAVESCAPE/TREENONE/BLOBFAIL (the errors-in-plain-words ruling). The ported legs assert the contract — non-zero, nothing on stdout, no secret bytes — and the words, not the codes.cat emits NO per-token U click-target: be's BRO-006 targets are grep #<word> and lite has no grep verb. It needs none — LITE-015 already makes an F token in a file hunk a reference the pager's door resolves. So be's links test ports minus its U half; what ports is the load-bearing half (the hunk body IS the source, verbatim, spans laid over it).blob takes a HEXLET only. be's <path>?<ref> blob slot is lite cat <path>?<rev>, which is where a path belongs.list has no banner line, so be's e2e "the banner is the list scheme" check (which proved be's DISPATCH, a problem lite does not have) has nothing to assert here.160000 commit ROW in tree (the view reports the object) but gets no click target — its commit lives in another ODB. list/cat/diff still drop gitlinks, as index.js's readTree always has.list ?<rev> off the indexed branch attributes nothing (the CPAR ancestry has no rows for it) — blank summaries, never a wrong one.work/LITE-017, clone ///lite/, base-date check (byte-identical to main lite/)lite tree + lite blob (the thin pair), be byte-shape paritylite cat incl. ?<rev> ODB formlite list with the last-commit fuse; marker column KEPT (files only), recordedLITEJAB)README.mkd usage lines, INDEXES.mkd fuse note, suggested commit message in OutcomeNone. Two things bit and were fixed in place: opts.from governed which repo was opened but not which dir a path arg resolved against (headless callers landed outside the repo), and the single U span per row made Enter say "nothing to follow" on a live pty though every headless span check passed — the second is exactly why the pty leg exists.
Landed in the worktree, jab put only. Five new index/ modules (read/list/cat/tree/blob, 640 lines), four thin 640 checks, runtime built from this tree (main.js wrappers plus four entries in the pager's VERBS door, three THEME slots in view/bro.js, and four new test dirs (test/{tree,cat,blob,list}, 173 checks) including a pty leg that navigates list → cat, list → list and tree → blob on a real tty. Whole lite suite green: 11 dirs, cmake -DJAB_JSRC=<wt> -DQUICKJAB_JSRC_PACK=ON).
Suggested commit message:
LITE-017: list/cat/tree/blob read views