From 8366c3739b8bffb5b2e3cc97dca8583f8836e37e Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 31 May 2026 14:28:46 +0200 Subject: [PATCH] agent/app.js + docs: migrate stacking-context + OAuth + nav-link prose to docs (#713 batch 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First batch of #713 (agent per-container UI prose migration). Moves 3 substantive WHY-explanations from app.js into docs/web-ui.md::Per-agent page, replaces each in-code mention with a brief pointer. Moved to docs: - **Terminal-wrap pill anchor** (~11 lines): why the `↓ N new` pill is anchored in `.agent-main` rather than the default `.terminal-wrap` parent — backdrop-filter creates a stacking context, anchoring inside it traps the pill's z-index below the composer. - **OAuth code input** (~14 lines across two blocks): masked password + reveal toggle + `autocomplete="one-time-code"` rationale (shoulder-surfer / screenshot exposure + WHATWG semantic value + suppresses browser save-password prompt). - **NavLink kind resolution + XSS-safe DOM-build** (~8 lines): Container → same-origin, Forge → `http://:3000`, External → already absolute; agent-declared strings never reach innerHTML. Collapsed in app.js: each block becomes a 3-4 line pointer to the matching docs section. Drops #262 / #568 / #592 cookies en passant since their substance now lives in docs. The `#14` cookie on `historyUrl` / `streamUrl` is also scrubbed — the path-relative shape is the convention, not an open issue. `#375` (agent.css ID ref) drops as part of the pill-anchor block collapse since it was sole-purpose pointing inside that comment. app.js: 27 → 24 refs. Net ~35 lines of substantive prose moved out of app.js into docs/web-ui.md::Per-agent page, where it belongs. --- docs/web-ui.md | 31 +++++++++++++++++---- frontend/packages/agent/src/app.js | 43 +++++++++--------------------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/docs/web-ui.md b/docs/web-ui.md index c05e089f..ff86d9e2 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -823,7 +823,13 @@ through. Three flex columns (#394 redesign): agent has a forge account; any `hyperhive.dashboardLinks` extras (`kind = External`). A `↑ dashboard` link is prepended by the JS so the host dashboard is one click away. `GET /api/agent/{name}/links` - is the single source of truth. + is the single source of truth. Each `NavLink.kind` resolves + differently in the frontend: `Container` → same-origin path + (the agent page is itself container-local); `Forge` → + `http://:3000`; `External` → already absolute. + All anchors are built via `el()` — agent-declared icon / + label / url strings never reach `innerHTML` (XSS-safe by + construction). - Row 2 (`.agent-state-row`): alive badge + state badge + model chip + ctx badge + cost badge + last-turn chip + cancel button. - Alive badge: `● alive` (green) / `⊘ rate limited` (red) / @@ -871,11 +877,26 @@ header `

` stays short (#589 phase A). and scrolls behind the fixed header + footer. - `#status` overlay: empty when online; shows the login form / OAuth URL when `status` is `needs_login_*`. The OAuth code input is - `type="password"` with a `👁 reveal` toggle (#568 — avoids - accidental on-screen token exposure; `autocomplete="one-time-code"` - for password-manager suppression). + `type="password"` with a `👁 reveal` toggle that flips it back to + `text` on press so the operator can sanity-check the paste before + submit — avoids accidental on-screen token exposure to + shoulder-surfers or screenshots. `autocomplete="one-time-code"` + is the semantic value for OAuth codes (per WHATWG): browsers may + silently ignore `autocomplete="off"` on `type="password"`, but + `one-time-code` is honoured and suppresses the "save password + for this site?" prompt that would otherwise fire on submit. - Terminal-wrap: live event tail (sticky-bottom auto-scroll + - `↓ N new` pill when not at bottom). + `↓ N new` pill when not at bottom). The pill is **anchored in + `.agent-main`**, not in `log.parentElement = .terminal-wrap`: + `.terminal-wrap` applies `backdrop-filter: blur` for the frost + effect, which creates a CSS stacking context — anchoring the + pill inside that context would trap its `z-index` below the + fixed composer in the root stacking context, and it'd never + float. `.agent-main` has no backdrop-filter (no stacking-context + creators), so the pill's `z-index` reaches the root and properly + composites above the composer. Geometry is unchanged — + `.agent-main` and `.terminal-wrap` both `inset: 0` fill the same + area. **Fixed-overlay footer** (`