47e248d9ac
- README.md: reduced to overview + quick start + links to docs/ - docs/architecture.md: stack, design decisions, data models, key services - docs/configuration.md: all env vars, docker-compose setup, production + security - docs/development.md: dev workflow, CI/CD, migrations, release process - docs/features.md: detailed feature breakdown + keyboard shortcuts - docs/api-keys-and-mcp.md: API key management + Fable MCP install guide - docs/sso-oauth.md: OAuth/OIDC setup (replaces docs/oauth-setup.md) - docs/changelog.md: development history from summary.md - Remove summary.md (content distributed across docs/) - Remove docs/oauth-setup.md (superseded by docs/sso-oauth.md) - .gitignore: add .mcp.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
151 lines
10 KiB
Markdown
151 lines
10 KiB
Markdown
# Changelog
|
||
|
||
Development history — most recent first.
|
||
|
||
---
|
||
|
||
## 2026-03-24 — fable-mcp serve, admin log tool, Settings MCP install UI
|
||
|
||
- **Dockerfile** — builds `fable-mcp` wheel into `/app/dist/` at image build time
|
||
- **`routes/fable_mcp_dist.py`** — `GET /api/fable-mcp/info` (availability check) and `GET /api/fable-mcp/download` (wheel download)
|
||
- **`fable_mcp/tools/admin.py`** — `get_app_logs()` calling `/api/admin/logs`
|
||
- **`fable_mcp/server.py`** — `fable_get_app_logs` MCP tool
|
||
- **SettingsView** — "Fable MCP" section in API Keys tab: wheel download button and install instructions
|
||
- **ci.yml** — `fable-mcp/**` added to trigger paths
|
||
|
||
## 2026-03-23 — fable-mcp scaffold + all tools
|
||
|
||
- `fable-mcp/` Python package scaffolded (`pyproject.toml`, `hatchling` build)
|
||
- `FableClient` — async httpx wrapper with `FABLE_URL` + `FABLE_API_KEY` auth
|
||
- Tool modules: `notes`, `tasks`, `projects`, `milestones`, `search`, `chat`, `admin`
|
||
- `server.py` — FastMCP stdio transport; all tools registered
|
||
- Settings UI — API Keys tab with create/revoke, `.env` download, Claude config download
|
||
- `routes/api_keys.py` — `POST /api/api-keys`, `GET /api/api-keys`, `DELETE /api/api-keys/:id`
|
||
|
||
## 2026-03-23 — Model management UI, RSS category/refresh, weather city search
|
||
|
||
- **SettingsView** — Model Management section: list installed models (size, loaded state), pull by name (SSE progress), delete unused
|
||
- **`routes/chat.py` `list_models_route`** — also hits `/api/ps` in parallel; returns `loaded: bool` and `modified_at` per model
|
||
- **RSS feeds** — category badge, last-fetched age, manual refresh button, category input on add
|
||
- **`routes/briefing.py`** — `POST /api/briefing/feeds/refresh` triggers immediate re-fetch
|
||
- **`get_weather` tool** — now accepts any city name (geocodes via Nominatim + fetches Open-Meteo); not limited to pre-configured locations
|
||
|
||
## 2026-03-22 — Briefing scheduler fix, quick capture fix, task back navigation
|
||
|
||
- **Briefing scheduler** — fixed deadlock: `start_briefing_scheduler` made async; replaced `run_coroutine_threadsafe(...).result()` with `await` (was blocking the event loop thread)
|
||
- **Briefing pipeline** — added early return when both LLM synthesis lanes produce empty strings (was always prepending "Good morning" on failure)
|
||
- **Quick capture** — fixed: was always creating notes. Two causes fixed: (1) now uses user's `default_model` setting instead of `Config.OLLAMA_MODEL`; (2) removed `create_project` from classifier prompt (tool not offered, causing fallback to note)
|
||
- **TaskViewerView** — back button navigates to task's project when `project_id` is set; Esc handler registered in capture phase to prevent conflict with App.vue global handler
|
||
|
||
## 2026-03-21 — Briefing RSS + project kanban advance buttons
|
||
|
||
- **ProjectView kanban** — status-advance buttons on task cards (→ todo→in_progress, ✓ in_progress→done), hidden until hover
|
||
- **Briefing UI** — RSS feeds section: add URL + category, list feeds with last-fetched age badge, delete, manual refresh
|
||
|
||
## 2026-03-16 — Fuzzy project resolution, create_project guard, task embedding fix
|
||
|
||
- `services/tools.py` — `_resolve_project` rewritten with 4-step lookup: (1) exact DB match, (2) `query in title` substring, (3) `title in query` reverse substring, (4) SequenceMatcher ≥ 0.55. Partial names now reliably resolve without creating duplicates.
|
||
- `services/tools.py` — `create_project` handler: similar-project checks (threshold 0.55) run **before** the `confirmed` gate, so `confirmed=true` cannot bypass them.
|
||
- `routes/tasks.py` — fire-and-forget `upsert_note_embedding` added to create and update routes (tasks weren't getting embeddings via REST API).
|
||
- `services/briefing_pipeline.py` — `await is_caldav_configured()` fix (was called without await — latent bug since the function became async).
|
||
- `services/notes.py` — removed erroneous duplicate `count_query.where(Note.parent_id == parent_id)` that was applied inside the `no_project` branch.
|
||
|
||
## 2026-03-12 — CI release process update
|
||
|
||
- `.forgejo/workflows/ci.yml` — removed `main` from `branches` push trigger. CI fires only on `dev` pushes, `v*` tags. Production release: create release via Forgejo UI on `main` with a `v*` tag → tag push fires CI → build job pushes `:latest` + `:<version>`.
|
||
|
||
## 2026-03-11 — Daily Briefing (full feature)
|
||
|
||
Backend:
|
||
- Migration `0026_add_briefing_tables.py`: `rss_feeds`, `rss_items`, `weather_cache`; added `conversation_type` and `briefing_date` to `conversations`.
|
||
- `services/weather.py`: geocoding via Nominatim, forecast via Open-Meteo, per-user DB cache.
|
||
- `services/rss.py`: feedparser-based fetch, per-feed DB cache prune-to-100.
|
||
- `services/briefing_pipeline.py`: two-lane parallel gather (weather, RSS, tasks, calendar) → LLM synthesis → GenerationBuffer SSE stream.
|
||
- `services/briefing_scheduler.py` (APScheduler): slots morning/midday/evening/night with catch-up logic.
|
||
- `routes/briefing.py`: RSS CRUD at `/api/briefing/feeds`, weather config, briefing config, `POST /api/briefing/trigger`.
|
||
|
||
Frontend:
|
||
- `BriefingView.vue`: primary briefing page; digest card + conversation thread + reply bar.
|
||
- `BriefingSetupWizard.vue`: 4-step setup wizard shown on first visit.
|
||
- SettingsView: Briefing tab (enable toggle, location geocoding, office days, time slot toggles, RSS CRUD).
|
||
- AppHeader: "Briefing" nav link added.
|
||
|
||
## 2026-03-11 — Version footer, task history, note version retention
|
||
|
||
- CalVer build-time version tracking: `Dockerfile` injects `BUILD_VERSION` ARG; displayed in Settings footer.
|
||
- Task history moved to collapsible right sidebar (previously modal overlay).
|
||
- Note version retention: configurable max versions per note (default 20) enforced at write time.
|
||
- Content deduplication in `build_context()` — same note cannot appear in multiple context blocks.
|
||
|
||
## 2026-03-11 — Multi-user sharing, notifications, groups, backup rewrite
|
||
|
||
- Migration `0025_add_sharing_and_notifications.py`: `groups`, `group_memberships`, `project_shares`, `note_shares`, `notifications`.
|
||
- `services/access.py`: `PERMISSION_RANK` dict; `get_project_permission` / `get_note_permission` — check ownership, direct share, group-based share, note→project inheritance.
|
||
- Share dialog (`ShareDialog.vue`): user tab (search + permission select), group tab, current shares list with inline change/remove.
|
||
- `SharedWithMeView.vue`: `/shared` route — shared projects and notes.
|
||
- In-app notification bell with 60s polling; push generated on share/group events.
|
||
- Backup rewrite (version 2): includes all tables; `restore_full_backup` builds ID maps, two-pass note restore for `parent_id` patching.
|
||
|
||
## 2026-03-10 — Project Workspace, Graph View, settings tabs, message queue persistence
|
||
|
||
- `WorkspaceView.vue`: 3-panel layout (tasks/chat/notes), collapse toggles, SSE watcher auto-loads notes and refreshes tasks.
|
||
- `WorkspaceTaskPanel.vue`: milestone-grouped task list, detail slide-over with status cycle + log.
|
||
- `WorkspaceNoteEditor.vue`: list ↔ TipTap editor, autosave.
|
||
- `GraphView.vue`: D3 force-directed graph, tag nodes, project hub nodes, physics panel, peek panel.
|
||
- SettingsView fully rewritten with tabbed layout (General, Account, Notifications, Integrations, Data, Admin).
|
||
- Message queue: persisted to localStorage; queued bubbles shown in chat with opacity + "QUEUED" label.
|
||
- ToolCallCard: confirm/deny inline; "Create anyway" posts directly to API (no LLM round-trip).
|
||
- Duplicate detection: scoped to same `is_task` type; semantic threshold raised 0.87 → 0.90.
|
||
|
||
## 2026-03-10 — "Illuminated Transcript" design language
|
||
|
||
- Fraunces font for headings; assistant bubbles elevated with left indigo accent + shadow; user bubbles ghosted (transparent bg, muted text).
|
||
- Dark palette shifted to slate-indigo (`#111113`). `--radius-lg` 12→18px.
|
||
- Cards: shadow depth replaces borders. Send buttons: indigo gradient + glow.
|
||
|
||
## 2026-03-10 — CI/CD infrastructure
|
||
|
||
- `infra/Dockerfile.runner-base`: Ubuntu 24.04 + Python 3.12 + Node 22 LTS custom runner image.
|
||
- All CI jobs use `py3.12-node22` runner; pip caching added; Node bumped to 22.
|
||
|
||
## 2026-03-06 — Session invalidation on credential change
|
||
|
||
- `users.session_version` column; incremented on password change/reset; checked in `_check_auth`; mismatch evicts all other sessions.
|
||
|
||
## 2026-03-06 — DRY refactoring (backend + frontend)
|
||
|
||
- `models/base.py`: `TimestampMixin` + `CreatedAtMixin` applied to all models (~60 lines removed).
|
||
- `routes/utils.py`: `not_found()` + `parse_iso_date()` helpers.
|
||
- Frontend composables: `useAutoSave`, `useEditorGuards`, `useTagSuggestions`, `useFloatingAssist`, `useListKeyboardNavigation`.
|
||
- Shared CSS: `editor-shared.css`, `viewer-shared.css`. Net: −634 lines, +237 lines.
|
||
|
||
## 2026-03-06 — Project-aware writing assist, link suggestions, project-scoped RAG
|
||
|
||
- Writing assist: `context_notes` param injects project notes; `definition`-tagged notes prioritised.
|
||
- Link suggestions: detects note titles as plain text in body; one-click wikilink conversion.
|
||
- Project-scoped RAG: `rag_project_id` param restricts semantic + keyword search to a project.
|
||
- `search_notes` tool: upgraded to hybrid semantic + keyword; `relevance` field in results.
|
||
- SSRF protection: `_is_private_url()` blocks private/loopback addresses; `follow_redirects=False`.
|
||
- Config validation: `Config.validate()` at startup.
|
||
|
||
## 2026-03-05 — Note editor sidebar, full-document writing assist, drafts, version history
|
||
|
||
- NoteEditorView: two-column layout; writing assistant always visible in sidebar.
|
||
- `whole_doc` mode: assistant outputs complete revised document (not just selected section).
|
||
- `DiffView.vue`: standalone diff component with equal-line collapsing (git-style context).
|
||
- Persistent drafts: `note_drafts` table; draft auto-saved after assist generation; restored on load.
|
||
- `note_versions` table: auto-snapshot on body change; version browser with diff + restore.
|
||
|
||
## 2026-03-05 — Task work log, task editor overhaul
|
||
|
||
- `task_logs` table; `TaskLogSection.vue` with timestamps, duration badges, inline edit.
|
||
- TaskEditorView: two-column layout with collapsible sidebar; sub-tasks section.
|
||
- `log_work` LLM tool added to `_CORE_TOOLS`.
|
||
|
||
## 2026-03-04 — Per-conversation streaming, SSE reconnection, keyboard navigation
|
||
|
||
- Per-conversation streaming state; auto-new chat on open.
|
||
- SSE reconnection: chat `reconnectIfGenerating()` on mount + navigation; assist retry loop with `Last-Event-ID`.
|
||
- Model load timeout raised 90s → 180s.
|
||
- Writing assist retry loop (3 attempts, exponential backoff).
|