- Collapsible legend: click "Legend" to expand/collapse (caret rotates,
pointer-events re-enabled now that the legend has something clickable).
- "Isolate connected component" detail-panel action: a pure
_componentNodeIds() BFS (undirected, no DOM dependency) feeds into
_applyFilters() alongside the existing category filter, with a toggle
button and a banner reporting how many memories are shown. Clears on
background click and on every graph reload.
- Keyboard shortcuts: `f` focuses the search box; arrow keys cycle
selection through the currently visible (filter-respecting) nodes and
re-center the camera. Both guarded against firing while typing or
while the modal is minimized.
- MODULE_SUMMARY.md: documented the memoryGraph.js module.
Cytoscape.js-based interactive graph over the memory system's
derived edges (similarity/session/manual), following the repo's
no-bundler vendoring and lazy-modal conventions.
- static/js/memoryGraph.js: modal shell, lazy Cytoscape load, fetch +
client-side filter/search, node/edge styling with dark/light theme
support via CSS custom properties, node selection + neighborhood
highlighting, link-mode manual relationship editing, detail panel
(pin/edit/delete/link management), demo-data fallback.
- static/lib/cytoscape.min.js: vendored 3.34.0 (MIT) via npm pack.
- static/index.html, static/app.js, static/js/init.js: "Memory Graph"
nav item (mirrors the Calendar entry), privilege gating
(can_manage_memory), Customize-UI visibility entry, /memory-graph
deep link.
- static/style.css: .memory-graph-* block, appended only.
Visually verified end-to-end against a real seeded dataset (render,
node click + neighborhood highlight, detail panel, inline edit,
search, category filters, similarity slider, link-mode create,
theme switch) — fixed two bugs found in that pass along the way:
the detail panel's `hidden` class was never removed on selection,
and search left stale selection-highlight opacity masking matches.
The placeholder-restore pass in mdToHtml put code, math, mermaid and
allowed-HTML blocks back with a string replacement, so String.replace read
`$&`, `` $` ``, `$'` and `$$` in the *replacement* as substitution patterns.
A fenced block containing them rendered corrupted: `$&` re-inserted the
placeholder (`perl -pe 's/world/$& again/'` became
`s/world/___CODE_BLOCK_0___amp; again/`), `` $` `` and `$'` spliced in the
surrounding document, and `$$` collapsed to a single `$`.
Pass a function replacer at all four sites, matching the inline-code site
below them, which was already fixed this way. A function's return value is
inserted verbatim with no `$` interpretation.
The inline-code comment claimed `echo $1` would be read as a back-reference;
with a string search value there are no capture groups, so `$1` is already
literal. Reworded to name the four sequences that do corrupt.
Fixes#5663
* feat(models): define capability schema and readers
* fix(models): harden Google catalog probing
Restrict native catalog probing to the Gemini host, keep provider keys out of request URLs, filter non-chat model resources, and preserve the manual refresh default in the built-in Google add flow.
* docs: update static/js/MODULE_SUMMARY.md to reflect current ES6 frontend
Rewrite the stale module summary to match the current no-build,
ES6-module frontend architecture. Adds coverage of app.js orchestration,
the chat/SSE pipeline (chat.js, chatStream.js, chatRenderer.js,
streamingRenderer.js), new subsystems (research/, compare/, document
streaming, cookbook*, skills.js), and removes the obsolete <script> load
order assumptions.
* cleanup: remove dead MEMORY_DOC / memory_doc paths (closes#4411)
Removes the unused MEMORY_DOC constant and the matching DataConfig
memory_doc field / set_data_paths entry. No runtime code imports or
references these paths, so this is a no-behavior-change dead-code
cleanup under the storage-architecture tracker #4377.
Setting epSel.value triggered an async change event whose handler
called refreshModels('') — wiping the correct model selection that
refreshModels(settings.default_model) had just applied moments earlier.
The dropdown silently fell back to the alphabetically-first model
(deepseek-v4-flash instead of qwen-3.6-35B-A3B).
Moved the change listener registration to after the settings block
so the async change event fires before any listener exists. The
utility and teacher sections already followed this pattern.