| 2026-05-15 |
chore: remove test MCP servers from repo
...
project_health and time_toolkit were created for development testing
and should not be part of the committed codebase.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
feat: MCP server template, manual, and example servers
...
Add canonical scaffolding for MCP server development:
- manuals/write_mcp_server.md: full guide covering structure, validation,
smoke-testing, registration, and troubleshooting
- mcp-servers/_template/: annotated starter with annotated mcp_server.py
and pyproject.toml for FastMCP + pydantic
- mcp-servers/project_health/: example server with 3 tools
(get_project_summary, find_duplicate_files, get_project_dependencies)
- mcp-servers/time_toolkit/: example server with 4 tools
(get_current_time, convert_timezone, add_time, format_datetime)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
fix: wire test_mcp_tool into MCP manager startup injection
...
The startup loop in main.py assigns _mcp_manager only to tools that
have the attribute, but test_mcp_tool never declared it and mcp_status
used _manager instead of _mcp_manager — so both received None forever.
Changes:
- test_mcp_tool: add __init__(mcp_manager) with _mcp_manager, fallback
to module-level import if startup wiring skipped
- mcp_status: rename _manager → _mcp_manager, same fallback
- registry.py: register create_mcp_server and test_mcp_tool builtins
- main.py: include test_mcp_tool in startup wiring loop
- client.py: add 5s timeout to disconnect cleanup
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
fix: filesystem empty path validation and terminal timeout defaults
...
filesystem:
- Reject empty string paths in _check_path to prevent writing to cwd
- Clear error message when 'write' action uses 'destination' instead of 'path'
terminal:
- Reduce default timeout from 300s to 20s
- Clamp user-provided timeout between 1 and 300s
- Update parameter description to mention max and common use-cases
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
feat: add create_mcp_server and test_mcp_tool builtins
...
create_mcp_server:
- Scaffolds mcp-servers/<name>/ directory with venv, pyproject.toml,
app/__init__.py, and annotated mcp_server.py template
- Runs pip install -e . in isolated thread to avoid event-loop issues
- Validates template with python -m py_compile
test_mcp_tool:
- Execute a single MCP tool call for isolated testing
- Detailed diagnostics: not connected, empty response, timeout, crash
- Fallback to module-level _mcp_manager if startup wiring skipped
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
refactor: rewrite tool_developer profile for MCP server development
...
Complete migration from old-style user tools (tools/*.py) to MCP servers.
Profile changes:
- Replace write_tool, delete_tool, test_tool with create_mcp_server,
test_mcp_tool, mcp_status, reload_tools
- Update system_prompt.txt with 10-step MCP workflow
- Rewrite subagent_system_prompt.txt with canonical server format,
absolute rules, smoke-test procedures
- Remove mcp_servers mapping from config (no longer bound to
external servers)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
feat: admin API endpoints for individual MCP server CRUD
...
Add granular REST endpoints for managing single MCP servers:
- GET /admin/mcp/config/{server_name}
- PUT /admin/mcp/config/{server_name}
- DELETE /admin/mcp/config/{server_name}
Bulk endpoints remain for backward compatibility.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
refactor: migrate MCP config to directory-based mcp_servers.d
...
Replaces monolithic mcp_servers.json with per-server files in
mcp_servers.d/<name>.json. Filename stem becomes the server name.
- load_mcp_servers() reads directory globs, auto-migrates legacy file
- save_mcp_servers() writes per-server files, cleans up stale ones
- Update docstrings in manager.py and context_builder.py
Auto-migration: existing servers (gnexus-book, navi-3d, navi-web) plus
new ones (project_health, time_toolkit) now live in mcp_servers.d/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
| 2026-05-14 |
Rebuild dist for spinner overlay fix
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner overlay on magnifying-glass icon
...
- Replace opacity-based hiding with display:none on .input-group-addon > i.
Move spinner pseudo-element to nested &::after inside .input-group-addon
with display:block + margin:auto for reliable centering.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search bug fixes
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner overlay, scroller reset, highlight leak
...
- AppSidebar: use i.ph selector + !important for spinner overlay on
input-group-addon icon. Add transition for smooth fade.
- SessionList: simplify DynamicScroller :key to 'search'/'all' only,
removing sessions.length to prevent scroll reset on fetchMore.
- SessionList: pass empty searchQuery when searchActive is false,
preventing stale highlights in normal session list.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for final search UX polish
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Final search UX polish: focus, cache, spinner opacity, scroller key
...
- AppSidebar: auto-focus input when search opens via querySelector.
Spinner icon now hides via opacity:0 instead of visibility:hidden.
- SessionsStore: add searchCache ref + restoreSearch(). Cache stores last
search results (items, hasMore, nextOffset) so reopening search avoids
re-fetching when query hasn't changed.
- SessionList: add :key on DynamicScroller to force recreate when switching
between search/normal mode, fixes pinned item spacing bug.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search UX fixes
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner placement, msg-flash disappearance, results cleanup
...
- AppSidebar: spinner moved inside GnSearchField input-group-addon via CSS
(:deep .input-group-addon overlay). Removed spinner from sessions-label.
- AppSidebar: closeSearch and handleSelect now call sessionsStore.exitSearch()
and reload normal session list, so search results disappear after selection.
toggleSearch restores previous query and re-activates search on reopen.
- CSS msg-flash: removed animation-fill-mode:both and background-color:transparent
from keyframes, so message bubble keeps its original background after flash.
- SessionsStore: added exitSearch() method (preserves query, disables active flag).
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search flash and highlight fixes
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search flash for assistant messages, move spinner, hide highlights
...
- MessageList: pass isFlashing prop to UserMessage/AssistantMessage instead
of applying msg-flash on wrapper div. scrollToMessage now uses rawIndices
to map backend match_index to grouped message index.
- UserMessage: add isFlashing prop, apply msg-flash to msg-user-bubble
- AssistantMessage: add isFlashing prop, apply msg-flash to msg-assistant-content
- ChatStore: add rawIndices to built messages (user, summary, assistant)
- AppSidebar: move spinner into sessions-label, remove from search field
- SessionList: accept searchOpen prop, pass empty searchQuery when closed
so highlights disappear after selecting a session
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search UX polish
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Polish session search UX: GnSearchField, spinner, flash timing
...
- AppSidebar: use GnSearchField from gnexus-ui-kit, spinner during search,
search toggle button always visible in sessions-header, hide search on select
- MessageList: fix msg-flash timing — make content visible before scrolling,
extend flash duration to 2.5s with background + brightness
- CSS: enhance msg-flash keyframe animation
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for session search feature
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Add session search across messages with backend + frontend
...
Backend:
- GET /sessions now accepts `search` query param
- _session_summary computes match_indices and match_preview from messages
- pg_session_store: messages ILIKE added to search_list and count_all
- In-memory store: search_list also filters by message content
Frontend:
- AppSidebar: search toggle icon + debounced input, Ctrl+K shortcut
- SessionItem: highlight matching text, show match_preview from search
- SessionList: pass searchQuery to SessionItem
- SessionsStore: searchQuery/searchActive state, setSearch/clearSearch
- API layer: getSessions accepts search param
- MessageList: scroll to target message + brightness flash animation
- ChatStore: loadSession accepts targetMessageIndex, scrollToMessageIndex ref
- CSS: msg-flash keyframe animation in app.scss
- Tests updated for new getSessions signature
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for tool card UX improvements
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Compact and improve tool/thinking/plan card UX
...
- ToolCard: remove emoji header, collapse Arguments behind <details>,
render results with structured JSON (color-coded values) or markdown
detection for string outputs.
- SubagentStep: mirror ToolCard compact layout with same helpers.
- AssistantMessage: fold tool lists when >3 tools — show last 3 + summary
bar with count and toggle icon-button; TransitionGroup for smooth
expand/collapse animations.
- Plan card: switch accent color from info to secondary, compact sizing.
- Thinking card: compact sizing, remove bottom margin.
- app.scss: add details::details-content animation, fix nested chevron
rotation in subagent steps, adjust margins and input-bar padding.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Markdown images: adaptive 3-column grid, lightbox modal, and broken-image handling
...
- useMarkdown.js: custom marked renderer wraps images in clickable links with
inline onerror for broken-image detection
- app.scss: .msg-assistant-content becomes flex-wrap container; image paragraphs
sized to 3-per-row via calc((100% - 16px) / 3); images are square via
aspect-ratio: 1 / 1 and object-fit: cover
- ImageLightbox.vue: rewritten with proper gnexus-ui-kit .modal/.modal-dialog
DOM structure; broken images show error placeholder inside modal
- AssistantMessage.vue: attachImageLightbox() wired after v-html render
- Broken images: .is-broken class prevents lightbox click; CSS shows 🖼️ icon
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
| 2026-05-13 |
Persist uploaded files in messages, live file tree updates, and UI polish
...
Backend:
- Add `files` field to `Message` model so uploaded file metadata survives page refresh
- Pass `files` through websocket handler → `agent.run_stream` / `agent.run`
- `list_tools`: make `profile_id` required; return error instead of all-tools fallback
Webclient:
- Call `fetchFiles()` after successful file upload for immediate Files tab update
- Live refresh file tree on filesystem (write/edit/append/mkdir/rm/cp/mv), terminal, and code_exec tool calls
- Add manual refresh button (desktop) and pull-to-refresh (mobile) to Files tab
- Fix live link updates: move regex creation inside per-message loop to avoid lastIndex state leak
- Restore full profile name text next to avatar in ChatHeader; hide avatar in header
- Fix mobile ArtifactsPanel: collapse tab text labels so close button fits with 3 tabs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
Defensive image cleanup in Ollama backend to prevent 'unknown format' errors
...
- _clean_base64_image() strips data URI prefix and validates non-empty result
- _to_ollama_messages() filters out invalid/empty images before sending to Ollama
- Prevents 500 errors when models receive malformed or unsupported image data
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
Fix profile icon class in WelcomeScreen — prepend 'ph' prefix
...
GnAvatar's :icon prop expects the full Phosphor class (e.g. 'ph ph-briefcase'),
not just the icon name. profileIcon() now returns 'ph ${cls}'.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
Add session file directory listing endpoint and Files tab in ArtifactsPanel
...
Backend:
- New GET /sessions/{session_id}/files endpoint (recursive, max depth 10)
- Includes hidden files, returns {path, size, is_dir, modified_at}
- Path traversal protection via resolve() + relative_to(base)
- list_session_files() helper in session_files.py
Webclient:
- Third "Files" tab in ArtifactsPanel alongside Artifacts and Links
- Tree display with depth-based indentation
- File type icons by extension (image, video, code, etc.)
- Download and inline-open actions per file
- Fetch on session load/reload via chatStore.fetchFiles()
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
Fix GnAvatar usage: use props (src/icon/initials) instead of default slot
...
GnAvatar render function ignores default slot content; it only reads
src, icon, and initials props. Fixes broken user avatar image display.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|