85e11aaa00a8ea3c4defb328a124d8a31b9bc080
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4b7229d612 |
fix(icons): commit generated icons; installs and regular builds never render
User installs failed with 'resvg-py is missing' because the web/desktop source builds rendered icons on whatever python was on PATH. The default brand outputs are now committed; source_build, apps/desktop build.mjs and the npm/docusaurus pre-hooks consume them directly. Flavored release bundles (canary/commit) still render into their own product dir. icons-freshness-check now regenerates and fails on any byte diff. |
||
|
|
f5b56a2746 |
feat(icons): no-frame wordmarks, squircle BrandMarks, on-demand generation
- website wordmarks (logo.png/logo-dark.png) drop the black/white frame: the girl alone on transparency, black for light navbar / white for dark (docusaurus srcDark stays) - BrandMark marks are now the app-icon squircle itself (transparent corners, 824px safe-zone composition) instead of plain tiles; the components no longer paint a tile/rounding - generated icon outputs are NOT committed anymore: all 35 targets are gitignored and regenerated on demand by the consuming pipelines via the new scripts/generate-icons.mjs (website prebuild, desktop prebuild+dev, installer prebuild, web prebuild) - freshness lane switched from byte-compare to structural verification (sizes, squircle corner transparency, ICO frame sets via header parse) — no more windows/ubuntu byte drift dance - marks saved as 8-bit palette PNGs (FASTOCTREE quantize keeps per-index alpha tRNS -> 2.5KB, AA edges preserved); compose_svg renders in the background's native space so resvg scales per output size |
||
|
|
1c729b39f7 |
fix(icons): commit linux-truth regenerated icons; drop harvest temp
Refresh the 35 generated targets from the ubuntu freshness lane (the windows regen compresses PNG differently per host zlib; CI checks against linux bytes). Girl marks + masters are host-stable (stored deflate blocks / plain text). Removes the temporary artifact-harvest step now that the committed set matches the check lane. |
||
|
|
1fa5fea74f |
feat(icons): derive every icon from nous-girl SVGs + platform backgrounds
The icon pipeline now composes all 35 targets from two source axes instead of a single hand-edited master: - girl art: assets/nous-girl-black.svg / nous-girl-white.svg (brand kit) - backgrounds: assets/backgrounds/ (squircle light/dark, logo frames, BrandMark tiles) assets/icon-master*.svg are generated artifacts (squircle background + girl nested in the 824px HIG content safe zone). New dark-appearance artifacts (icon-dark.* containers, appx *-dark logos, logo-dark wordmark, nous-logo-dark) land everywhere a surface consumes them: docusaurus navbar srcDark, BrandMark dark tile (keyed off renderedMode). nous-girl.jpg jpgs are replaced by lossless 8-bit palette PNGs saved with compress_level=0 (stored deflate blocks, byte-identical across hosts for the CI freshness lane). Includes the temp linux-truth harvest step in icons-freshness-check.yml so the committed compressed bytes can be refreshed from the ubuntu regen. |
||
|
|
0ee0bd903e |
fix(icons): commit linux-truth regenerated icons; drop harvest temp
resvg-py 0.4.0 rasterizes identically per-host but the committed set was generated on Windows (22440-byte icon.png) while the freshness lane runs on linux (24200). Harvested linux regeneration via a temp artifact step, committed it (all 23 targets now match linux output), reverted the temp. |
||
|
|
096e4dbe68 |
fix(icons): regenerate all 23 targets from icon-master.svg (audit RED: --check drift)
generate_icons.py --check was RED on 23 targets — committed files diverged from icon-master.svg output (large stale binaries: logo.png 1.3MB→60KB, icon.icns 1.5MB→94KB). Regenerated via the single-master pipeline; --check now passes. Also gates the icons-freshness-check CI lane that ci.yaml calls. |
||
|
|
f49afd3122 |
feat(web): add /api/pty WebSocket bridge to embed TUI in dashboard
Exposes hermes --tui over a PTY-backed WebSocket so the dashboard can
embed the real TUI rather than reimplement its surface. The browser
attaches xterm.js to the socket; keystrokes flow in, PTY output bytes
flow out.
Architecture:
browser <Terminal> (xterm.js)
│ onData ───► ws.send(keystrokes)
│ onResize ► ws.send('\x1b[RESIZE:cols;rows]')
│ write ◄── ws.onmessage (PTY bytes)
▼
FastAPI /api/pty (token-gated, loopback-only)
▼
PtyBridge (ptyprocess) ── spawns node ui-tui/dist/entry.js ──► tui_gateway + AIAgent
Components
----------
hermes_cli/pty_bridge.py
Thin wrapper around ptyprocess.PtyProcess: byte-safe read/write on the
master fd via os.read/os.write (not PtyProcessUnicode — ANSI is
inherently byte-oriented and UTF-8 boundaries may land mid-read),
non-blocking select-based reads, TIOCSWINSZ resize, idempotent
SIGHUP→SIGTERM→SIGKILL teardown, platform guard (POSIX-only; Windows
is WSL-supported only).
hermes_cli/web_server.py
@app.websocket("/api/pty") endpoint gated by the existing
_SESSION_TOKEN (via ?token= query param since browsers can't set
Authorization on WS upgrades). Loopback-only enforcement. Reader task
uses run_in_executor to pump PTY bytes without blocking the event
loop. Writer loop intercepts a custom \x1b[RESIZE:cols;rows] escape
before forwarding to the PTY. The endpoint resolves the TUI argv
through a _resolve_chat_argv hook so tests can inject fake commands
without building the real TUI.
Tests
-----
tests/hermes_cli/test_pty_bridge.py — 12 unit tests: spawn, stdout,
stdin round-trip, EOF, resize (via TIOCSWINSZ + tput readback), close
idempotency, cwd, env forwarding, unavailable-platform error.
tests/hermes_cli/test_web_server.py — TestPtyWebSocket adds 7 tests:
missing/bad token rejection (close code 4401), stdout streaming,
stdin round-trip, resize escape forwarding, unavailable-platform ANSI
error frame + 1011 close, resume parameter forwarding to argv.
96 tests pass under scripts/run_tests.sh.
(cherry picked from commit
|
||
|
|
923539a46b | fix: add nous-research/ui package | ||
|
|
e2a9b5369f |
feat: web UI dashboard for managing Hermes Agent (#8756)
* feat: web UI dashboard for managing Hermes Agent (salvage of #8204/#7621) Adds an embedded web UI dashboard accessible via `hermes web`: - Status page: agent version, active sessions, gateway status, connected platforms - Config editor: schema-driven form with tabbed categories, import/export, reset - API Keys page: set, clear, and view redacted values with category grouping - Sessions, Skills, Cron, Logs, and Analytics pages Backend: - hermes_cli/web_server.py: FastAPI server with REST endpoints - hermes_cli/config.py: reload_env() utility for hot-reloading .env - hermes_cli/main.py: `hermes web` subcommand (--port, --host, --no-open) - cli.py / commands.py: /reload slash command for .env hot-reload - pyproject.toml: [web] optional dependency extra (fastapi + uvicorn) - Both update paths (git + zip) auto-build web frontend when npm available Frontend: - Vite + React + TypeScript + Tailwind v4 SPA in web/ - shadcn/ui-style components, Nous design language - Auto-refresh status page, toast notifications, masked password inputs Security: - Path traversal guard (resolve().is_relative_to()) on SPA file serving - CORS localhost-only via allow_origin_regex - Generic error messages (no internal leak), SessionDB handles closed properly Tests: 47 tests covering reload_env, redact_key, API endpoints, schema generation, path traversal, category merging, internal key stripping, and full config round-trip. Original work by @austinpickett (PR #1813), salvaged by @kshitijk4poor (PR #7621 → #8204), re-salvaged onto current main with stale-branch regressions removed. * fix(web): clean up status page cards, always rebuild on `hermes web` - Remove config version migration alert banner from status page - Remove config version card (internal noise, not surfaced in TUI) - Reorder status cards: Agent → Gateway → Active Sessions (3-col grid) - `hermes web` now always rebuilds from source before serving, preventing stale web_dist when editing frontend files * feat(web): full-text search across session messages - Add GET /api/sessions/search endpoint backed by FTS5 - Auto-append prefix wildcards so partial words match (e.g. 'nimb' → 'nimby') - Debounced search (300ms) with spinner in the search icon slot - Search results show FTS5 snippets with highlighted match delimiters - Expanding a search hit auto-scrolls to the first matching message - Matching messages get a warning ring + 'match' badge - Inline term highlighting within Markdown (text, bold, italic, headings, lists) - Clear button (x) on search input for quick reset --------- Co-authored-by: emozilla <emozilla@nousresearch.com> |