feat(webui): read-only Queue, Business and Settings views (#1543, row 54)
The Console gains three read-only views. Queue lists every row from
rows() in packages/queue (lead decision 83: the same lock-free read as
`queue list`, writing nothing), run in a child with a timeout and an
output cap; a row page shows the full row. Business shows names, an
allowlist of vars, arbiters, authority per action and credential
metadata (service, account, role, date, never a value, file or
variable). Settings shows RELEASE, the board origin and the notifier
binding. Every route is GET only, and every string in a body or
refusal passes a redactor: the config directory and dataRoot become
<config> and <dataRoot>, other absolute, ~/ and file:// paths <path>,
and 17 to 20 digit runs <id>. A queue-read that fails to start sends a
fixed message, never node's stderr.
Four fixes to HEAD behaviour, each with a test: the bus view's refresh
timer is cleared at render, a same-page refresh keeps focus on the H1,
#conv-pick is emptied when a conversation opens, and error() returns
focus to <main> only when something had focus. Filbert's T8 tests the
failed first read.
Dewey built it in two rounds. Round 1 (dba2429e) got changes from
Filbert (27185: After rendered [object Object], ~/ and :/ paths leaked)
and Darkwing (27186: Arbiters always none, queue-read import failure
leaked a file:// path and stack). Round 2 (afb2ae0e) was approved by
Filbert (27190) and Darkwing (27191, correction 27192). Sage's gate on
d64f434f plus the candidate: 13 package node suites 0 failed (queue
149, webui 39), every scripts/test-*.sh 0 failed (task 98/0 with
Docker, 26/0 without; release 14/0), build-tokens --check current.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+102
-10
@@ -40,7 +40,8 @@ bytes. Do not expose either unauthenticated server through a public proxy.
|
||||
with a warning. There are no automatic action retries.
|
||||
- Palette and appearance come from `tokens.css` (see "Shell" below) and persist
|
||||
in this browser when local storage is available. Appearance defaults to
|
||||
System. No settings screen is added.
|
||||
System. Settings (row 54) shows the same control and nothing else that
|
||||
changes.
|
||||
- History opens a read-only conversation view for a seat, from its Waiting
|
||||
card, its table row or its inspector (#1507, CHAT-02). It shows the whole
|
||||
branch with nothing clipped. Tool calls, tool results and thinking start
|
||||
@@ -52,7 +53,8 @@ bytes. Do not expose either unauthenticated server through a public proxy.
|
||||
or a rewritten file each shows a marker with a button to open the other
|
||||
history. Reloading after a rewrite keeps the branch the view was on; if that
|
||||
branch is gone, the view opens the latest one and says so. Session lists
|
||||
older sessions for the seat. Only repository Pi seats
|
||||
older sessions for the seat, and is empty while the list is read or when
|
||||
that read fails. Only repository Pi seats
|
||||
have history; other harnesses say so.
|
||||
|
||||
Drafts and receipts stay in page memory, including across refresh, inspector
|
||||
@@ -90,9 +92,10 @@ note is `agents/dewey/work/wui/SLICE1-VIEWS.md`.
|
||||
- Views refresh on the board's ten-second interval and stop on Pause. Focus,
|
||||
open sections and the copy status survive a refresh.
|
||||
- A failed read keeps the last good answer for that read and says it is old,
|
||||
with the time it was read. A refusal (403, `not-configured` or `no-bus-host`)
|
||||
never shows kept rows (row 53), and it drops every kept bus read: the Inbox
|
||||
count and the palette's decisions and tasks go too, until a read succeeds.
|
||||
with the time it was read. A refusal (403, `not-configured`, `no-bus-host`,
|
||||
or row 54's `queue-refused`) never shows kept rows (row 53), and it drops
|
||||
every kept read: the Inbox count and the palette's decisions, tasks and
|
||||
queue rows go too, until a read succeeds.
|
||||
A page never read, or refused, shows the failure instead,
|
||||
titled "Bus refused the read" (403: the bus refused the Console's read, for
|
||||
example `human-required` from a Console started inside an agent run), "No bus to read" (no system
|
||||
@@ -118,8 +121,8 @@ only: no new data, route or write.
|
||||
(v2.304); `assets/fonts/jetbrains-mono-sources.txt` has the URL and sha256
|
||||
of the archive and each file, and `jetbrains-mono-OFL.txt` the licence.
|
||||
Manrope has no 800 file here, so 800 headings render at 700.
|
||||
- Ctrl+K (or the search field) opens the palette over views, inbox decisions
|
||||
and tasks; arrows move, Enter opens, Esc closes and returns focus. Arrow
|
||||
- Ctrl+K (or the search field) opens the palette over views, inbox decisions,
|
||||
tasks and (row 54) queue rows from the last queue read; arrows move, Enter opens, Esc closes and returns focus. Arrow
|
||||
keys also move between task links in the bus tables.
|
||||
- Copy reports in a toast. If the clipboard is unavailable, the toast stays
|
||||
until dismissed and the command is selected for Ctrl+C. When no toast shows,
|
||||
@@ -132,11 +135,54 @@ only: no new data, route or write.
|
||||
the board was not read. A failed read with no scan held, after a refusal or
|
||||
before the first scan, shows the board empty and says the read failed; it
|
||||
never brings back rows from a refused scan. A refusal also closes an open
|
||||
conversation and clears its history.
|
||||
conversation and clears its history. If that removes what had focus, focus
|
||||
moves to the page.
|
||||
- From 760px the footer is a one-line status bar and the side column fits
|
||||
between it and the command bar. Below 760px the section list is one strip
|
||||
that scrolls inside itself.
|
||||
|
||||
## Queue, Business and Settings (row 54, #1543)
|
||||
|
||||
Three read-only views, in the section list and the palette. Each has the
|
||||
same five states as the bus views: loading (the skeleton names the source),
|
||||
normal, empty, a failed read over kept data (labelled stale, with its time),
|
||||
and a refusal that shows nothing kept. The command bar names the source:
|
||||
"Queue read …", "Business not read: refused". A refusal shows the code in
|
||||
mono and the module's own message, redacted by the server.
|
||||
|
||||
- `#/queue` lists every row with its state, owner, reviewers, brief and last
|
||||
update, filterable by state. `#/queue/<id>` adds the gate, issues, claim,
|
||||
`after`, note and review rounds. Rows move only with
|
||||
`scripts/mosaic queue move` in a terminal; the row page shows that command
|
||||
with a Copy button and has no button that moves a row. The brief is shown
|
||||
as its path and anchor, because Console serves no repository files.
|
||||
- `#/business` shows the business named by `--business`, else the running
|
||||
bus host's business: the human, the arbiters as instance and kind ("pm
|
||||
(delivery), cto (technical)"), projects, launch rules, the vars
|
||||
on an allowlist, each role instance with its holder and harness, the
|
||||
authority of each instance for each action as the business package
|
||||
classifies it (`resolveInstance`, `classify`), and credentials as
|
||||
metadata only: service, account, role, expiry or rotate-by date, and a
|
||||
state worked out from the date alone. A missing or invalid business file
|
||||
is a `not-configured` refusal with the business module's own text.
|
||||
- `#/settings` shows appearance (the row 53 control, kept in this browser),
|
||||
the notifier binding by name only, and about: the Console's loopback
|
||||
address, `RELEASE`, the business and the board URL. A Settings refusal
|
||||
still shows appearance, because it needs no read.
|
||||
|
||||
Console never reads a token, a token file or a credential variable, and no
|
||||
response, page or log carries one, a file path or a Discord channel, guild or
|
||||
user id. The server redacts every message and string field before it answers
|
||||
(`redactor` in `src/reads.mjs`): the config directory becomes `<config>`, the
|
||||
data root `<dataRoot>`, any other absolute or `~/` path `<path>`, a 17 to 20
|
||||
digit run `<id>`, and a JSON parse error's quote of the file is dropped. The
|
||||
startup log goes through the same redactor. A path starts at the beginning
|
||||
of the text or after a space, an opening bracket, a quote, `=`, `,`, `<` or
|
||||
`:`, so `file:/x` and `file:///x` are redacted and `https://host/x` is not.
|
||||
Known gap: a path stops at the first space, so a path containing a space is
|
||||
redacted only up to that space and the rest shows. A bare `~` or `~user/`
|
||||
is not treated as a path, and neither is a relative path.
|
||||
|
||||
## Data and boundaries
|
||||
|
||||
GET `/api/board`, `/api/conversations` and `/api/conversation`, and POST
|
||||
@@ -165,6 +211,25 @@ that can't be used. The bus needs the system config
|
||||
(`~/.config/mosaic-dev/config.json`); without it the board still serves and
|
||||
the bus routes answer `not-configured`.
|
||||
|
||||
GET `/api/queue`, `/api/queue/<id>`, `/api/business` and `/api/settings` are
|
||||
row 54's reads (`src/reads.mjs`), under the same Host, Origin and CSP rules.
|
||||
Any other method is 405, and a queue id that is not a positive integer is
|
||||
400. The queue is read in a child process (`src/queue-read.mjs`) through
|
||||
`rows()` from `packages/queue/src/store.mjs` (lead decision 83): the same
|
||||
read as `queue list`, with no write and no network. Like `list`, it takes
|
||||
the queue lock only to recheck a disagreement before reporting it. The child
|
||||
imports the store inside its `try`, so a store that fails to load reports
|
||||
"the queue read failed". Only the store's exit 2 (invalid data or refused)
|
||||
forwards the child's text, as `queue-refused`; any other exit is the fixed
|
||||
`read-failed` message "the queue read failed (exit N)", because that stderr
|
||||
may be Node's own, with a `file://` path and a stack. The business
|
||||
read uses `packages/business` in process. No read writes, calls out or adds a
|
||||
dependency. Answers carry `at`; failures are `{ error, message }` with 503
|
||||
for `not-configured`, `no-bus-host`, `queue-refused` and `read-failed`, 404
|
||||
for a row that isn't there, 400 for a bad address and 502 otherwise. Settings
|
||||
answers 200 even without a system config, so appearance always works; its
|
||||
notifier part then says `not-configured`.
|
||||
|
||||
Console's shared CSS, Console CSS, brand.js and local Manrope fonts were copied
|
||||
unchanged from `agents/dewey/work/wui/`. Font license and source URLs accompany
|
||||
the files under `src/public/assets/fonts/`. `live.css` contains the live-page
|
||||
@@ -182,6 +247,7 @@ WEBUI_EVIDENCE=/tmp/webui-evidence node --test packages/webui/tests/browser.test
|
||||
WEBUI_EVIDENCE=/tmp/webui-evidence node --test packages/webui/tests/conversation.test.mjs
|
||||
WEBUI_EVIDENCE=/tmp/webui-evidence node --test packages/webui/tests/bus-browser.test.mjs
|
||||
WEBUI_EVIDENCE=/tmp/webui-evidence node --test packages/webui/tests/shell.test.mjs
|
||||
node --test packages/webui/tests/reads.test.mjs packages/webui/tests/views.test.mjs
|
||||
```
|
||||
|
||||
Node's test runner and installed `/usr/bin/chromium` are required. Set `CHROMIUM`
|
||||
@@ -215,8 +281,9 @@ the human CLI against a live bus.
|
||||
Shell tests (`shell.test.mjs`) check the copies, the font hashes and the kept
|
||||
strings, and in the browser at 400px: System mode under an emulated dark and
|
||||
light OS, the empty, stale and refused states of the board and the bus views
|
||||
(a board refusal with the inspector open and a project picked, then a failed
|
||||
read, and a refusal with a conversation open), not found, the palette, the toast,
|
||||
(a failed first read drawn empty, a board refusal with the inspector open and a project picked, then a failed
|
||||
read, a failed session list, and a refusal with a conversation open and where
|
||||
focus lands after it), not found, the palette, the toast,
|
||||
keyboard and visible focus, the section strip at 360 and 400px, no sideways
|
||||
scroll, no script error and no request other than GET. A second test walks
|
||||
the Board, Inbox, Tasks, Agents and a decision trail through loading (a held
|
||||
@@ -225,6 +292,31 @@ read), normal, a failed read over kept rows, and a refusal by the bus
|
||||
refusal empties the palette and the Inbox count, from a view, from the
|
||||
palette's own reads and from the board page, and that palette labels are text.
|
||||
|
||||
Row 54's tests share the seeded fixture in `reads-fixture.mjs`: a scratch
|
||||
queue whose row note names an id and token paths shaped like real notes
|
||||
(absolute, `~/` and after `file:`; the store refuses `<` in a note, so the
|
||||
`<…>` case is in the redactor test), and a business,
|
||||
notifier config and Discord binding that hold token files, an environment
|
||||
variable name, an agent `model` var holding a path, and guild, channel, bot
|
||||
and user ids. Row 9's After entry has the `{id, when}` shape the real queue
|
||||
stores. `reads.test.mjs` checks each
|
||||
route's body and status, the redactor, the credential state, methods and
|
||||
Origin, and that no body carries any seeded value or the temporary directory;
|
||||
that a `store.mjs` with a syntax error, or none, gives the fixed message with
|
||||
no path; and that the child's timeout, output cap and non-2 exits hold, over a
|
||||
fake child script.
|
||||
`views.test.mjs` walks Queue, a queue row, Business and Settings through the
|
||||
five states over a stub read, with each refusal code the view can meet, at
|
||||
400px; checks that a refusal leaves no queue row in the palette, that no view
|
||||
has a control but Copy and Read again, and that the row page shows the
|
||||
`queue move` command, that the 10 s refresh keeps focus on a Settings mirror
|
||||
select, and that the palette keeps its queue rows after its own inbox and tasks
|
||||
reads answer; then, over the seeded fixture, that the Arbiters line reads the
|
||||
business file's object, that neither the page nor
|
||||
any response it read carries a seeded value, that a missing or invalid
|
||||
business file shows the module's text, and that the startup log names no
|
||||
config path.
|
||||
|
||||
No root CI workflow is configured for this package. These local tests are not a
|
||||
claim of CI, deployment, live-seat delivery or user acceptance.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user