The 180 s query cap was enforced independently by the backend clamp, the agent limits, and the container supervisor. All three now follow CONFLUENCE_WEB_MAX_DEADLINE_SECONDS (default 900, allowed 60-3600): the backend passes it into the container at launch, the supervisor reads it and forwards it to the bridge, and both fall back to 900 s on invalid input. The query timeout must not exceed it (startup fails otherwise). The supervisor keeps a separate 180 s guard for a container that never receives a start frame. Add assets/book.svg as the tab icon: the backend serves assets/ and the CSP allows same-origin images (the sanitizer still never emits <img>).
Confluence Research - Web UI
Minimalist, secure Web UI for Confluence Research, designed to operate against the backend API contracts specified in docs/SPECIFICATION.md and docs/implementation/CONTRACTS.md.
Directory Layout
frontend/
├── index.html # Main HTML entrypoint (clean white minimalist theme)
├── css/
│ └── style.css # Responsive styling, accessible components, thinking-orb and logo styles
├── js/
│ ├── app.js # State transitions, keyboard handling, memory credentials, staleness guards
│ ├── api.js # Relative /api/v1/... fetch boundary with UTF-8 byte validation
│ ├── render.js # marked.js + DOMPurify, fail-safe render, bounded sectioning
│ ├── history.js # Sources, lazy bounded history serialization, artifacts listing
│ ├── orb.js # Vanilla canvas driver for the vendored thinking-orbs engine (loading view)
│ └── logo.js # Book logo playback: CSS cover flip on page open and brand hover
├── vendor/ # Pinned vendor libraries & licenses (locally served)
├── assets/
│ └── book.svg # Favicon (same book shape as the CSS logo)
│ ├── marked.min.js
│ ├── marked.LICENSE
│ ├── purify.min.js
│ ├── dompurify.LICENSE
│ ├── thinking-orbs.engine.js # Framework-free engine build of thinking-orbs 0.3.1
│ └── thinking-orbs.LICENSE
├── dev/
│ ├── mock-server.js # Zero-dependency same-origin mock server & scenario runner
│ ├── scenario-toolbar.js # External dev toolbar script (CSP compliant, no inline scripts)
│ └── scenario-toolbar.css # External dev toolbar styling (CSP compliant, no inline styles)
├── tests/
│ ├── contract.test.js # Wire format, status code, header, & scenario tests (14 tests)
│ ├── api.test.js # UTF-8 byte boundary and credential validation tests (6 tests)
│ ├── render.test.js # Markdown section partitioning and fallback tests (10 tests)
│ └── e2e_runner.js # End-to-end browser test runner connecting to Chrome (9444) via CDP (16 tests)
├── package.json
├── package-lock.json
├── .gitignore
└── README.md
Security & Architecture Highlights
- In-Memory Credentials:
- Confluence Base URL and Personal Access Token (PAT) reside strictly in browser JavaScript memory.
- Never written to
localStorage,sessionStorage, cookies, query parameters, console logs, or exported files. - A
cw_sessionHttpOnly cookie is set by the origin for artifact download ownership.
- Content Security Policy (CSP):
default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; img-src 'self'; media-src 'none'; font-src 'self'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'- Completely prevents automatic third-party network requests, tracking pixels, and unauthorized script injection. Images are same-origin only (the favicon); the sanitizer allowlist never emits
<img>from agent output. - Verified via browser network tracing (zero automatic external requests).
- Markdown Sanitization & Link Safety:
- Restricted element allowlist using locally vendored DOMPurify.
- Fail-safe rendering: if parser or sanitizer are absent or fail, displays a safe notice without ever injecting raw untrusted HTML.
- All links rewritten to require explicit user clicks with
target="_blank"andrel="noopener noreferrer". - Disallowed protocols (
javascript:,data:,file:) havehrefstripped.
- Large Result Handling & Memory Bounding:
- Large answers partitioned into bounded sections (~48 KiB soft target, ~64 KiB hard cap) rendered on demand.
- Giant code fences (e.g. 12 MB) are safely split and re-opened so every section is a valid Markdown code block.
- Tables preserve row boundaries and repeat column headers across sections.
- Pathological blocks fall back to a bounded plain-text preview with full export available.
- "Export to MD" always exports the complete, untouched raw Markdown client-side via Blob.
- Tool call results in history are rendered lazily with bounded serialization buffers (
serializeBounded).
Development & Testing
Running the Dev Mock Server
The mock server runs entirely with Node.js built-ins (zero dependencies) on loopback:
cd frontend
npm run dev
# Or custom port:
node dev/mock-server.js --port 5173
Open http://127.0.0.1:5173/ in your browser. A floating dev toolbar in the bottom-right corner allows toggling between all 13 deterministic mock scenarios (e.g. normal shared example, 403 verify, 409 busy, 504 timeout, malicious content, large output, delayed cancellation).
Running Unit & Contract Tests
Tests verify API limits, wire contracts, headers, cookies, and markdown partitioning (30 tests):
cd frontend
npm test
Running E2E Browser Tests
Runs comprehensive browser tests against Chrome on port 9444 via CDP (16 tests):
cd frontend
npm run test:e2e