feat(dashboard): nous-blue theme, bulk sessions, schedule picker - #37383
Conversation
Batch of related dashboard improvements gathered on
austin/fix/dashboard-changes:
* Nous Blue theme — faithful port of the LENS_5I overlay system onto
the existing DashboardTheme. Lifts the foreground inversion layer to
z-index 200 to fix the long-standing hover / loading visual artifact,
adds an explicit swatchColors slot so the theme picker shows the
post-inversion preview, and migrates the legacy "lens-5i" theme key
from localStorage / API to "nous-blue" on first read.
* Theme-aware series colors: new --series-input-token /
--series-output-token CSS vars consumed by Analytics + Models
charts; ToolCall + ModelInfoCard switched to semantic
--color-success for diff lines and the Tools capability badge.
* Analytics + Models headers: consolidate period selector + refresh
next to the page title and drop the redundant period badge.
* Bulk session management — "Delete empty (N)" button + per-row
checkboxes with shift-click range select and a bulk-delete action
bar. Backed by SessionDB.delete_sessions() /
delete_empty_sessions() plus POST /api/sessions/bulk-delete and
DELETE /api/sessions/empty (registered before the templated
/api/sessions/{session_id} family so they don't get shadowed).
Hard cap of 500 IDs per bulk request. Full pytest coverage.
* Cron page — human-readable schedule picker (every-interval / daily
/ weekly / monthly / once / custom) replaces the raw cron
expression input; the job list now renders "Weekly on Mon, Wed,
Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals
for monthly schedules so non-English locales don't get incorrect
suffixes.
* example-dashboard plugin moved from plugins/ to tests/fixtures/ so
stock installs no longer ship the demo. Tests install it
dynamically via a pytest fixture that also reorders the FastAPI
routes.
* i18n: 40+ new keys for the bulk-select UI and schedule
picker/describer translated across all 16 locales.
Co-authored-by: Cursor <cursoragent@cursor.com>
The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR batches several Hermes dashboard improvements that share overlapping surfaces (theming, Sessions, Cron, Analytics/Models visuals) to reduce i18n churn while shipping a cohesive UX update.
Changes:
- Add a new “Nous Blue” inverted-lens theme, including theme-migration aliases and theme-aware series color tokens.
- Implement bulk session management (empty-session sweep + checkbox multi-select + bulk delete) with new backend endpoints and tests.
- Replace the raw cron expression input with a multi-mode schedule picker plus human-readable schedule descriptions, and move the example-dashboard plugin to a test-only fixture.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/themes/types.ts | Adds ThemeSeriesColors and optional swatchColors support for theme-aware data-series accents and picker swatches. |
| web/src/themes/presets.ts | Introduces the nousBlueTheme preset and registers it in BUILTIN_THEMES. |
| web/src/themes/context.tsx | Adds theme-name migration (lens-5i → nous-blue) and emits/clears series color CSS vars on theme switch. |
| web/src/components/Backdrop.tsx | Reworks overlay stacking (FG inversion at z=200, noise above it) and adds CSS-var-driven blend-mode hooks. |
| web/src/components/ThemeSwitcher.tsx | Uses theme.swatchColors when present to render accurate swatches for inverted themes. |
| web/src/index.css | Defines default --series-input-token / --series-output-token CSS vars. |
| web/src/pages/AnalyticsPage.tsx | Uses theme series vars for token visuals; moves period controls next to the title. |
| web/src/pages/ModelsPage.tsx | Uses theme series vars for token visuals; moves period controls next to the title; updates “Tools” badge styling. |
| web/src/components/ToolCall.tsx | Switches diff “+” line styling to semantic text-success. |
| web/src/components/ModelInfoCard.tsx | Switches “Tools” capability badge to semantic success token classes. |
| web/src/lib/schedule.ts | Adds pure helpers to build schedules and describe common cron shapes in human-readable form. |
| web/src/components/ScheduleBuilder.tsx | Adds the controlled, multi-mode schedule picker UI used by Cron create/edit. |
| web/src/pages/CronPage.tsx | Integrates ScheduleBuilder, uses describeSchedule for list display, and supports English ordinals. |
| web/src/lib/api.ts | Adds client helpers for empty-session count/delete and bulk session delete endpoints. |
| web/src/pages/SessionsPage.tsx | Adds “Delete empty (N)”, row checkboxes with shift-range select, and bulk delete action bar. |
| web/src/i18n/types.ts | Extends translation types with bulk session and schedule-picker keys. |
| web/src/i18n/en.ts | Adds bulk session + schedule-picker translations (English). |
| web/src/i18n/de.ts | Adds bulk session + schedule-picker translations (German). |
| web/src/i18n/es.ts | Adds bulk session + schedule-picker translations (Spanish). |
| web/src/i18n/fr.ts | Adds bulk session + schedule-picker translations (French). |
| web/src/i18n/ga.ts | Adds bulk session + schedule-picker translations (Irish). |
| web/src/i18n/hu.ts | Adds bulk session + schedule-picker translations (Hungarian). |
| web/src/i18n/it.ts | Adds bulk session + schedule-picker translations (Italian). |
| web/src/i18n/ja.ts | Adds bulk session + schedule-picker translations (Japanese). |
| web/src/i18n/ko.ts | Adds bulk session + schedule-picker translations (Korean). |
| web/src/i18n/pt.ts | Adds bulk session + schedule-picker translations (Portuguese). |
| web/src/i18n/ru.ts | Adds bulk session + schedule-picker translations (Russian). |
| web/src/i18n/tr.ts | Adds bulk session + schedule-picker translations (Turkish). |
| web/src/i18n/uk.ts | Adds bulk session + schedule-picker translations (Ukrainian). |
| web/src/i18n/zh.ts | Adds bulk session + schedule-picker translations (Simplified Chinese). |
| web/src/i18n/zh-hant.ts | Adds bulk session + schedule-picker translations (Traditional Chinese). |
| hermes_state.py | Adds delete_sessions, count_empty_sessions, and delete_empty_sessions DB operations. |
| hermes_cli/web_server.py | Adds session bulk-delete/empty-delete endpoints and registers nous-blue in builtin theme list. |
| tests/test_hermes_state.py | Adds unit tests for bulk session deletion and empty-session sweep behavior. |
| tests/hermes_cli/test_web_server.py | Adds endpoint tests, plus a fixture to install the example-dashboard plugin from a test fixture. |
| tests/fixtures/plugins/example-dashboard/dashboard/plugin_api.py | Adds test-only plugin API fixture (stable endpoint for auth/asset tests). |
| tests/fixtures/plugins/example-dashboard/dashboard/manifest.json | Updates fixture manifest to clarify test-only usage. |
| plugins/example-dashboard/dashboard/plugin_api.py | Removes the example-dashboard plugin from stock installs (moved to test fixture). |
| AGENTS.md | Removes example-dashboard from the bundled plugins list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Backdrop layer-stack comment claimed LENS_5I-style themes override
--component-backdrop-bg-blend-mode to multiply, but our only
LENS_5I-style theme (nous-blue) keeps the default difference.
Reword to describe what the code actually does and present the
var as a forward-looking extension hook.
- /api/sessions/bulk-delete docstring promised the response would
echo back the list of deleted IDs, but the implementation only
returns {ok, deleted}. Tighten the docstring to match the wire
format; the client already knows what it asked to delete, so the
IDs aren't needed.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@copilot review |
…changes Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # hermes_cli/web_server.py # web/src/lib/api.ts # web/src/pages/SessionsPage.tsx # web/src/pages/SystemPage.tsx
… checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@copilot review |
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-import |
1 |
First entries
tests/fixtures/plugins/example-dashboard/dashboard/plugin_api.py:16: [unresolved-import] unresolved-import: Cannot resolve imported module `fastapi`
✅ Fixed issues (1):
| Rule | Count |
|---|---|
unresolved-import |
1 |
First entries
plugins/example-dashboard/dashboard/plugin_api.py:9: [unresolved-import] unresolved-import: Cannot resolve imported module `fastapi`
Unchanged: 5013 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
combatsheep
left a comment
There was a problem hiding this comment.
Bulk session deletion, empty-session cleanup, schedule picking, and theme changes are all routed through with the route-order guard in place and solid test coverage. Approving.
Reviewed |
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR #37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…sResearch#37383) * feat(dashboard): nous-blue theme, bulk sessions, schedule picker Batch of related dashboard improvements gathered on austin/fix/dashboard-changes: * Nous Blue theme — faithful port of the LENS_5I overlay system onto the existing DashboardTheme. Lifts the foreground inversion layer to z-index 200 to fix the long-standing hover / loading visual artifact, adds an explicit swatchColors slot so the theme picker shows the post-inversion preview, and migrates the legacy "lens-5i" theme key from localStorage / API to "nous-blue" on first read. * Theme-aware series colors: new --series-input-token / --series-output-token CSS vars consumed by Analytics + Models charts; ToolCall + ModelInfoCard switched to semantic --color-success for diff lines and the Tools capability badge. * Analytics + Models headers: consolidate period selector + refresh next to the page title and drop the redundant period badge. * Bulk session management — "Delete empty (N)" button + per-row checkboxes with shift-click range select and a bulk-delete action bar. Backed by SessionDB.delete_sessions() / delete_empty_sessions() plus POST /api/sessions/bulk-delete and DELETE /api/sessions/empty (registered before the templated /api/sessions/{session_id} family so they don't get shadowed). Hard cap of 500 IDs per bulk request. Full pytest coverage. * Cron page — human-readable schedule picker (every-interval / daily / weekly / monthly / once / custom) replaces the raw cron expression input; the job list now renders "Weekly on Mon, Wed, Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals for monthly schedules so non-English locales don't get incorrect suffixes. * example-dashboard plugin moved from plugins/ to tests/fixtures/ so stock installs no longer ship the demo. Tests install it dynamically via a pytest fixture that also reorders the FastAPI routes. * i18n: 40+ new keys for the bulk-select UI and schedule picker/describer translated across all 16 locales. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(dashboard): dedupe memory provider picker The memory provider <Select> lived on both /system and /plugins, writing the same config.yaml field through two different endpoints with no cross-page refresh. Remove the picker from /system in favor of a read-only status row + link to /plugins, where it pairs with the context-engine picker under "Plugin providers". /system retains the destructive admin controls (file sizes, Reset MEMORY.md / USER.md / all). The api.setMemoryProvider client and PUT /api/memory/provider backend endpoint are left in place for CLI / script callers. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(dashboard): address Copilot review on PR NousResearch#37383 - Backdrop layer-stack comment claimed LENS_5I-style themes override --component-backdrop-bg-blend-mode to multiply, but our only LENS_5I-style theme (nous-blue) keeps the default difference. Reword to describe what the code actually does and present the var as a forward-looking extension hook. - /api/sessions/bulk-delete docstring promised the response would echo back the list of deleted IDs, but the implementation only returns {ok, deleted}. Tighten the docstring to match the wire format; the client already knows what it asked to delete, so the IDs aren't needed. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(dashboard): address copilot review on cron describe + bulk-select checkbox - schedule.ts: restrict `describeCronExpression` to strictly 5-field cron expressions. The backend `parse_schedule` also accepts the 6-field `min hour dom month dow year` form, and humanising those by destructuring only the first five fields would silently drop the year (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field expressions now fall through to the raw-string fallback so the user sees what's actually scheduled. - SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's ``onClick`` directly instead of attaching it to a parent ``<span>`` with a no-op ``onCheckedChange``. Radix forwards onClick to the underlying ``<button role=checkbox>``, so the same handler now drives both mouse clicks (preserving shift-key state for range select) and keyboard activation (Space on the focused checkbox, which the browser synthesises as a click on the <button>). Improves a11y / keyboard UX without changing the controlled-selection model. - SessionsPage.tsx: also extend ``SessionRowProps`` with the new ``onRename`` / ``onExport`` props introduced on main so the row's destructured prop types resolve after the merge. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
What does this PR do?
Batch of related dashboard improvements gathered on this branch — each is small on its own, but they touch the same surface (theming, Sessions, Cron, Analytics, Models) and ship together to keep i18n churn down. Headline items:
DashboardTheme. Fixes a long-standing visual artifact on hover / loading by lifting the foreground inversion layer toz-index: 200.POST /api/sessions/bulk-delete.Inputwith a six-mode picker (every-interval / daily / weekly / monthly / once / custom). Job list now rendersWeekly on Mon, Wed, Fri at 14:30instead of30 14 * * 1,3,5.example-dashboardplugin removed from stock installs (moved undertests/fixtures/and loaded dynamically by an explicit pytest fixture).Related Issue
Fixes #
Type of Change
Changes Made
Theming
web/src/themes/presets.ts— newnousBlueThemepreset. Pre-inverteddestructive/success/warningso colors look right post-differenceblend. AddsswatchColors(white / blue / light-blue) for the theme picker.web/src/themes/types.ts— adds optionalswatchColors: [string, string, string]and a newThemeSeriesColorsinterface (inputTokenAccent,outputTokenAccent).web/src/themes/context.tsx— wiresseriesColorVarsintoapplyTheme, exposes--series-input-token/--series-output-token, and addsTHEME_NAME_ALIASESto silently migrate the legacylens-5ikey from localStorage and the API tonous-blue.web/src/components/Backdrop.tsx— overlay stack reimplemented to consume the new theme CSS vars; the FG inversion layer moves toz-index: 200(and the noise layer to201) so the inversion correctly covers hover overlays and the loading spinner.web/src/components/ThemeSwitcher.tsx—ThemeSwatchhonourstheme.swatchColorswhen present.web/src/index.css— default--series-input-token: #ffe6cband--series-output-token: #34d399for themes that don't override them.Analytics / Models pages
web/src/pages/AnalyticsPage.tsx,web/src/pages/ModelsPage.tsx— period selector + refresh consolidated next to the title viasetAfterTitle; redundant period badge removed. Hardcoded#ffe6cb/emerald-*colors replaced withvar(--series-input-token)/var(--series-output-token).web/src/components/ToolCall.tsx— diff-line color migrated fromtext-emerald-*totext-success.web/src/components/ModelInfoCard.tsx— Tools capability badge migrated frombg-emerald-500/10 text-emerald-*tobg-success/10 text-success.Bulk session management
hermes_state.py— addsSessionDB.delete_sessions(ids, sessions_dir=None)anddelete_empty_sessions(sessions_dir=None) → count. Both orphan children (no cascade), filterNone/ duplicate IDs, and clean transcript files whensessions_diris provided.hermes_cli/web_server.py— addsPOST /api/sessions/bulk-delete(hard-cap 500 IDs/req),GET /api/sessions/empty/count, andDELETE /api/sessions/empty. All three are registered before the templated/api/sessions/{session_id}family to avoid Starlette's first-match-wins shadowing.web/src/lib/api.ts—api.bulkDeleteSessions(ids),api.getEmptySessionsCount(),api.deleteEmptySessions().web/src/pages/SessionsPage.tsx— "Delete empty (N)" button (rendered whenemptyCount > 0and not searching), per-row RadixCheckbox, shift-click range select vialastClickedIndexRef, bulk-action bar (N selected · Select all on page · Clear · Delete N), selected-row tint, two confirm dialogs, automatic selection-clear on page / search / view changes (done via wrapped setters to dodgereact-hooks/set-state-in-effect).tests/test_hermes_state.py— 14 new tests (TestBulkDeleteSessions,TestDeleteEmptySessions).tests/hermes_cli/test_web_server.py— 12 new tests (TestBulkDeleteSessionsEndpoint,TestDeleteEmptySessionsEndpoint) including a guard that the bulk-delete route isn't shadowed by/api/sessions/{session_id}.Cron schedule picker
web/src/lib/schedule.ts— pure helpers:buildScheduleString(state)(interval →every Nm, daily/weekly/monthly → 5-field cron, once → ISO timestamp, custom → pass-through),describeSchedule(schedule, fallback, strings)(recognises common cron shapes, falls back to the raw expression on anything exotic),englishOrdinal().web/src/components/ScheduleBuilder.tsx— six-mode picker, mode-specific inputs (number+unit,<input type=time>, weekday toggle buttons, day-of-month,<input type=datetime-local>, raw cron). State slots preserved across mode flips. InlineSends as: every 30mpreview.web/src/pages/CronPage.tsx— create modal mountsScheduleBuilder; job list usesdescribeSchedule(...)with English-only ordinals.Bundled plugins
plugins/example-dashboard/removed from stock installs.tests/fixtures/plugins/example-dashboard/added with a docstring/description noting it's test-only._install_example_plugincopies it intoHERMES_HOME, busts_dashboard_plugins_cache, and reorders API routes so literal paths beat templated ones for the tests that need the example plugin to be installed.AGENTS.mdupdated to removeexample-dashboardfrom the list of bundled plugins.i18n
web/src/i18n/types.ts+ all 16 locale files (af,de,en,es,fr,ga,hu,it,ja,ko,pt,ru,tr,uk,zh,zh-hant) get:selectSession,selectAllOnPage,clearSelection,selectedCount,deleteSelected,deleteSelectedConfirmTitle/Message,selectedSessionsDeleted,failedToDeleteSelected).deleteEmpty,deleteEmptyConfirmTitle/Message,emptySessionsDeleted,failedToDeleteEmpty).scheduleMode,scheduleModes.*,scheduleDescribe.*, including a 7-tupleweekdaysShort).How to Test
lens-5ilocalStorage value should resolve tonous-blueautomatically./sessions, "Delete empty (N)" appears next to the search; confirm the count, run it, watch the toast and the rows vanish./sessions, click the checkbox on one row, then shift-click a checkbox several rows down. The whole range selects. Action bar shows "N selected · Select all on page · Clear · Delete N". Run Delete N, confirm the toast count matches./cron, hit "Create". Try every mode (interval / daily / weekly / monthly / once / custom). The "Sends as" preview should always show a valid backend-ready string. Submit each; the resulting job in the list should render with a human-readable description (e.g. "Weekly on Mon, Wed, Fri at 14:30").pytest tests/test_hermes_state.py tests/hermes_cli/test_web_server.py -q— 459 passed.cd web && ./node_modules/.bin/tsc --noEmit— clean../node_modules/.bin/vite build— clean.Checklist
Code
feat(dashboard): …)pytest tests/ -qand all tests pass (459 passed intests/test_hermes_state.py+tests/hermes_cli/test_web_server.py)Documentation & Housekeeping
AGENTS.md—example-dashboardremoved from bundled plugins list)cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows<input type=time>/<input type=datetime-local>, both supported on every desktop browser; backend bulk-delete uses the same SQLite primitives as single-deleteScreenshots / Logs