feat: DX improvements — dark mode, status command, memory previews#102
feat: DX improvements — dark mode, status command, memory previews#102
Conversation
…oken savings Viewer: - Dark mode toggle (persists to localStorage, respects prefers-color-scheme) - Fix hardcoded canvas colors for dark theme (grid, labels, tooltips) - Memory search shows 2-line content preview with search term highlighting - Concept tags shown inline on memory cards (max 4) - Token Savings stat card on dashboard (estimates savings vs full context) CLI: - New `agentmemory status` command — shows connection, health, sessions, graph stats, viewer URL without opening browser README: - SkillKit universal install: `npx skillkit install agentmemory` (32+ agents) - "First Steps After Install" section with worked Session 1 → Session 2 example - Shows actual compressed observation format and context injection - "How to verify" checklist
📝 WalkthroughWalkthroughAdded a CLI Changes
Sequence Diagram(s)sequenceDiagram
participant User as CLI User
participant CLI as agentmemory CLI
participant Engine as REST Engine
participant Health as /agentmemory/health
participant Sessions as /agentmemory/sessions
participant Graph as /agentmemory/graph/stats
User->>CLI: npx agentmemory status
CLI->>Engine: probe engine (isEngineRunning)
alt Engine reachable
par Concurrent requests
CLI->>Health: GET /agentmemory/health (5s timeout)
CLI->>Sessions: GET /agentmemory/sessions (5s timeout)
CLI->>Graph: GET /agentmemory/graph/stats (5s timeout)
and
Health-->>CLI: health payload
Sessions-->>CLI: sessions payload
Graph-->>CLI: graph stats
end
CLI->>CLI: format status report
CLI->>User: print report + viewer URL
else Engine unreachable
CLI->>User: print error and exit 1
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@README.md`:
- Around line 313-316: The two new fenced code blocks that currently start with
You: "Add JWT auth to the Express API" and the similar block later (the one
showing You:/Agent lines) are missing a language tag and trigger markdownlint
MD040; update each fence to use the text language identifier (change ``` to
```text) so the rendered output is unchanged but the MD040 warning is resolved.
In `@src/cli.ts`:
- Around line 260-270: The sessions count is computed from sessionsRes as if it
were an array, but the endpoint returns an object with a sessions array; update
the sessions computation in src/cli.ts so it checks sessionsRes?.sessions and
uses its length when it is an array (e.g., replace Array.isArray(sessionsRes) ?
sessionsRes.length : 0 with Array.isArray(sessionsRes?.sessions) ?
sessionsRes.sessions.length : 0), leaving the surrounding Promise.all and
health/version logic (healthRes, graphRes, h, status, version, memories)
unchanged.
In `@src/viewer/index.html`:
- Around line 1021-1026: The token-savings calculation hardcodes 2000 per
session (estInjected) instead of using the configured TOKEN_BUDGET; update the
logic that computes estInjected and the displayed subtitle to use the
TOKEN_BUDGET value (falling back to 2000 if TOKEN_BUDGET is undefined/invalid)
so savings and the "~X vs ~Y full" text reflect the actual budget; modify the
variables used in the block (totalObs, estFull, estInjected, savings and the
HTML string generation) to reference TOKEN_BUDGET rather than the literal 2000.
- Around line 817-826: applyTheme currently always writes to localStorage which
causes an auto-detected theme to be saved as a manual override; change
applyTheme to accept a second optional parameter (e.g., persist = false) and
only call localStorage.setItem when persist is true, update window.toggleTheme
to call applyTheme(!isDarkMode(), true) so user toggles persist, and on startup
call applyTheme(true) only if savedTheme exists (otherwise call
applyTheme(true/false based on prefers-color-scheme) with persist=false) so
auto-detection does not get persisted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 310c6c4b-ce01-4ebf-8aaa-2774e0797dd5
📒 Files selected for processing (3)
README.mdsrc/cli.tssrc/viewer/index.html
- README: add `text` language tag to fenced code blocks (MD040)
- cli.ts: sessions endpoint returns {sessions: [...]}, not a raw array
- viewer: token budget from URL param instead of hardcoded 2000
- viewer: applyTheme takes persist param, auto-detection doesn't save to
localStorage (prevents OS preference from being overridden on first load)
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/viewer/index.html (1)
768-768: Consider extracting inline styles to a CSS class.The theme toggle button uses inline styles. For consistency with the rest of the codebase, consider defining a CSS class for the toggle button styling.
♻️ Suggested refactor
Add to CSS:
.btn-theme-toggle { font-size: 9px; padding: 3px 10px; letter-spacing: 0.1em; margin-right: 8px; }Then update the button:
-<button id="theme-toggle" class="btn" style="font-size:9px;padding:3px 10px;letter-spacing:0.1em;margin-right:8px;" onclick="toggleTheme()">DARK</button> +<button id="theme-toggle" class="btn btn-theme-toggle" onclick="toggleTheme()">DARK</button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/viewer/index.html` at line 768, The inline styles on the theme toggle button should be moved into a CSS class for consistency: create a CSS class (e.g., .btn-theme-toggle) with the rules font-size:9px; padding:3px 10px; letter-spacing:0.1em; margin-right:8px;, add that class to the element with id "theme-toggle" (keeping the existing "btn" class and onclick="toggleTheme()"), and remove the inline style attribute so styling is centralized and maintainable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/viewer/index.html`:
- Around line 1023-1029: The tokenBudget in the viewer is read only from URL
params (the parseInt(new URLSearchParams(...).get('tokenBudget') ...) logic) and
can diverge from the server's TOKEN_BUDGET; update the viewer to prefer a
server-injected value (e.g. window.__TOKEN_BUDGET__ or a data-token-budget
attribute on a root element) before falling back to the URL/default, and modify
the server to inject TOKEN_BUDGET into the served HTML (or add documentation
advising to append ?tokenBudget=VALUE); specifically change the tokenBudget
assignment to first check the injected global/data value, then URL, then 2000,
and ensure the server template inserts the environment TOKEN_BUDGET into
window.__TOKEN_BUDGET__ or data-token-budget.
---
Nitpick comments:
In `@src/viewer/index.html`:
- Line 768: The inline styles on the theme toggle button should be moved into a
CSS class for consistency: create a CSS class (e.g., .btn-theme-toggle) with the
rules font-size:9px; padding:3px 10px; letter-spacing:0.1em; margin-right:8px;,
add that class to the element with id "theme-toggle" (keeping the existing "btn"
class and onclick="toggleTheme()"), and remove the inline style attribute so
styling is centralized and maintainable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 53737d8b-8ff7-4abe-860f-8605dfa8e1a5
📒 Files selected for processing (3)
README.mdsrc/cli.tssrc/viewer/index.html
🚧 Files skipped from review as they are similar to previous changes (2)
- README.md
- src/cli.ts
| var totalObs = d.sessions.reduce(function(a, s) { return a + (s.observationCount || 0); }, 0); | ||
| var tokenBudget = parseInt(new URLSearchParams(window.location.search).get('tokenBudget') || '2000', 10) || 2000; | ||
| var estFull = totalObs * 80; | ||
| var estInjected = d.sessions.length * tokenBudget; | ||
| var savings = estFull > 0 ? Math.round((1 - estInjected / Math.max(estFull, 1)) * 100) : 0; | ||
| if (savings < 0) savings = 0; | ||
| html += '<div class="stat-card"><div class="label">Token Savings</div><div class="value">' + savings + '%</div><div class="sub">~' + estInjected.toLocaleString() + ' vs ~' + estFull.toLocaleString() + ' full (budget: ' + tokenBudget + ')</div></div>'; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
How do single-page applications typically pass server-side configuration values to client-side JavaScript?
💡 Result:
Single-page apps typically get server-side config into client JavaScript using one (or a mix) of these patterns:
-
Inline
<script>that assigns a global- Server renders something like
window.APP_CONFIG = {...}(JSON-serialized) so the SPA can read it immediately during bootstrap. This is a commonly recommended approach when the values are needed on initial load. [1], [2]
- Server renders something like
-
JSON embedded in the HTML (non-executing)
- Server renders a
<script type="application/json" ...>containing JSON; client code reads the tag’s text andJSON.parses it. Many frameworks/libraries use this to declaratively provide initial configuration. [3]
- Server renders a
-
data-*attributes on a DOM element- Server places values on the root element (or a dedicated element) like
<div id="app" data-api-base="...">; client reads them viaelement.dataset. [4], [5]
- Server places values on the root element (or a dedicated element) like
-
Fetch config from an endpoint at runtime
- SPA starts with minimal HTML/JS, then calls something like
/config.json(or an API route) to obtain environment-specific settings—useful when config must vary at deploy/runtime. (Often paired with one of the above for a “config URL” pointer.) [2]
- SPA starts with minimal HTML/JS, then calls something like
Sources:
[1] Stack Overflow – “Best practice for passing server-side variables to javascript?” (stackoverflow.com)
[2] javaspring.net – “Best Ways to Pass Server-Side Variables to Client-Side JavaScript…” (javaspring.net)
[3] UI5 Web Components – “Configuration” (JSON config via <script type="application/json">) (ui5.github.io)
[4] MDN – “Use data attributes” (developer.mozilla.org)
[5] MDN – HTMLElement.dataset (developer.mozilla.org)
Citations:
- 1: https://stackoverflow.com/questions/5927824/best-practice-for-passing-server-side-variables-to-javascript?utm_source=openai
- 2: https://www.javaspring.net/blog/what-is-the-best-way-to-pass-server-side-variables-to-javascript-on-the-client-side/?utm_source=openai
- 3: https://ui5.github.io/webcomponents/docs/advanced/configuration/?utm_source=openai
- 4: https://developer.mozilla.org/docs/Web/HTML/How_to/Use_data_attributes?utm_source=openai
- 5: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset?utm_source=openai
🏁 Script executed:
# Search for TOKEN_BUDGET references in the codebase
rg "TOKEN_BUDGET" --no-heading -nRepository: rohitg00/agentmemory
Length of output: 172
🏁 Script executed:
# Check the viewer directory structure and nearby configuration files
fd . src/viewer --type f -x basename {} \; | head -20Repository: rohitg00/agentmemory
Length of output: 84
🏁 Script executed:
# Look for any server/backend code that might have TOKEN_BUDGET config
rg "tokenBudget|token.*budget" --no-heading -n -iRepository: rohitg00/agentmemory
Length of output: 2507
🏁 Script executed:
# Check README or documentation files for deployment/configuration info
fd -e md -e txt -e json | xargs grep -l "token\|budget\|config" -i | head -10Repository: rohitg00/agentmemory
Length of output: 208
🏁 Script executed:
# Check how the viewer is served - look at server.ts
cat -n src/viewer/server.ts | head -100Repository: rohitg00/agentmemory
Length of output: 3462
🏁 Script executed:
# Also check if viewer HTML is embedded or referenced
rg "index.html" src/ -B 2 -A 2Repository: rohitg00/agentmemory
Length of output: 905
🏁 Script executed:
# Check more of server.ts to see if it modifies HTML before serving
sed -n '95,150p' src/viewer/server.tsRepository: rohitg00/agentmemory
Length of output: 1704
🏁 Script executed:
# Look for any pattern where server might inject config into responses
rg "html|HTML" src/viewer/server.ts -B 2 -A 2Repository: rohitg00/agentmemory
Length of output: 664
🏁 Script executed:
# Check README for deployment instructions
sed -n '700,750p' README.mdRepository: rohitg00/agentmemory
Length of output: 1377
🏁 Script executed:
# Look for viewer-related documentation
rg "viewer|TOKEN_BUDGET" README.md -B 2 -A 2 | head -40Repository: rohitg00/agentmemory
Length of output: 1800
Token budget calculation requires manual synchronization with server configuration.
The viewer reads tokenBudget from URL parameters (defaulting to 2000), but the server's actual TOKEN_BUDGET environment variable (configured at deployment) is not automatically synced to the viewer. If a deployment uses TOKEN_BUDGET=5000, the token savings estimates will be incorrect unless the URL is manually appended with ?tokenBudget=5000.
The server serves the viewer HTML as a static file without injecting the configured budget value. To fix this misalignment, either:
- Have the server inject
TOKEN_BUDGETinto the viewer HTML (e.g., as a<script>tag ordata-*attribute) when serving it, or - Document prominently that
tokenBudgetmust be appended to the viewer URL to match the deployment'sTOKEN_BUDGETsetting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/viewer/index.html` around lines 1023 - 1029, The tokenBudget in the
viewer is read only from URL params (the parseInt(new
URLSearchParams(...).get('tokenBudget') ...) logic) and can diverge from the
server's TOKEN_BUDGET; update the viewer to prefer a server-injected value (e.g.
window.__TOKEN_BUDGET__ or a data-token-budget attribute on a root element)
before falling back to the URL/default, and modify the server to inject
TOKEN_BUDGET into the served HTML (or add documentation advising to append
?tokenBudget=VALUE); specifically change the tokenBudget assignment to first
check the injected global/data value, then URL, then 2000, and ensure the server
template inserts the environment TOKEN_BUDGET into window.__TOKEN_BUDGET__ or
data-token-budget.
Summary
Closes the DX gap with graphify by adding polish that makes the value visible.
<mark>. Concept tags shown inline (max 4 badges).statuscommand:npx @agentmemory/agentmemory statusshows health, sessions, graph stats, viewer URL without opening browser.npx skillkit install agentmemoryfor 32+ agents.Test plan
npx @agentmemory/agentmemory statusSummary by CodeRabbit
New Features
statuscommand for engine health, sessions, and graph statsDocumentation