From 2b01d540d62b4f16e2b192bfda4a8af5a793ca3f Mon Sep 17 00:00:00 2001 From: xcaliber Date: Sun, 8 Mar 2026 16:54:17 +0000 Subject: [PATCH] Changeset 0.25.0 (#160) --- VERSION | 2 +- docs/ROADMAP.md | 1288 ++++------------- docs/SURFACES.md | 350 +++++ server/database/migrations/022_surfaces.sql | 17 + server/handlers/completion.go | 81 +- server/handlers/messages.go | 19 +- server/handlers/personas.go | 45 + server/handlers/surfaces.go | 297 ++++ server/main.go | 73 +- server/pages/loaders.go | 17 +- server/pages/pages.go | 251 +++- server/pages/pages_surfaces.go | 70 + server/pages/templates/base.html | 13 + .../pages/templates/components/chat-pane.html | 17 +- .../templates/components/code-editor.html | 30 + .../pages/templates/components/file-tree.html | 20 + .../templates/components/model-selector.html | 19 + .../templates/components/note-editor.html | 86 ++ .../pages/templates/components/user-menu.html | 40 + server/pages/templates/surfaces/admin.html | 3 +- server/pages/templates/surfaces/chat.html | 46 +- server/pages/templates/surfaces/editor.html | 159 +- server/store/interfaces.go | 1 + server/store/postgres/stores.go | 1 + server/store/postgres/surface_registry.go | 117 ++ server/store/surface_registry_iface.go | 36 + server/tools/calculator.go | 2 +- server/tools/conversation_search.go | 1 + server/tools/datetime.go | 2 +- server/tools/file_recall.go | 1 + server/tools/git.go | 33 +- server/tools/kbsearch.go | 1 + server/tools/memory.go | 2 + server/tools/notes.go | 5 +- server/tools/predicates.go | 85 ++ server/tools/predicates_test.go | 376 +++++ server/tools/registry.go | 25 +- server/tools/types.go | 46 +- server/tools/urlfetch.go | 2 +- server/tools/websearch.go | 2 +- server/tools/workspace.go | 16 +- server/tools/workspace_search.go | 1 + src/css/admin-surfaces.css | 153 ++ src/css/chat-pane.css | 412 ++++++ src/css/editor-mode.css | 288 ---- src/css/editor-surface.css | 535 +++++++ src/css/pane-container.css | 167 +++ src/css/tool-grants.css | 41 + src/css/user-menu.css | 162 +++ src/js/admin-scaffold.js | 35 +- src/js/admin-surfaces.js | 198 +++ src/js/app.js | 84 +- src/js/code-editor.js | 341 +++++ src/js/editor-mode.js | 1157 --------------- src/js/editor-surface.js | 662 +++++++++ src/js/file-tree.js | 278 ++++ src/js/model-selector.js | 191 +++ src/js/note-editor.js | 450 ++++++ src/js/pane-container.js | 554 +++++++ src/js/ui-admin.js | 5 +- src/js/ui-core.js | 136 +- src/js/ui-settings.js | 14 +- src/js/user-menu.js | 154 ++ 63 files changed, 6942 insertions(+), 2773 deletions(-) create mode 100644 docs/SURFACES.md create mode 100644 server/database/migrations/022_surfaces.sql create mode 100644 server/handlers/surfaces.go create mode 100644 server/pages/pages_surfaces.go create mode 100644 server/pages/templates/components/code-editor.html create mode 100644 server/pages/templates/components/file-tree.html create mode 100644 server/pages/templates/components/model-selector.html create mode 100644 server/pages/templates/components/note-editor.html create mode 100644 server/pages/templates/components/user-menu.html create mode 100644 server/store/postgres/surface_registry.go create mode 100644 server/store/surface_registry_iface.go create mode 100644 server/tools/predicates.go create mode 100644 server/tools/predicates_test.go create mode 100644 src/css/admin-surfaces.css create mode 100644 src/css/chat-pane.css delete mode 100644 src/css/editor-mode.css create mode 100644 src/css/editor-surface.css create mode 100644 src/css/pane-container.css create mode 100644 src/css/tool-grants.css create mode 100644 src/css/user-menu.css create mode 100644 src/js/admin-surfaces.js create mode 100644 src/js/code-editor.js delete mode 100644 src/js/editor-mode.js create mode 100644 src/js/editor-surface.js create mode 100644 src/js/file-tree.js create mode 100644 src/js/model-selector.js create mode 100644 src/js/note-editor.js create mode 100644 src/js/pane-container.js create mode 100644 src/js/user-menu.js diff --git a/VERSION b/VERSION index fef426c..d21d277 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.24.3 \ No newline at end of file +0.25.0 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 6c04bf5..f8139ab 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -127,13 +127,19 @@ v0.24.0 Auth Abstraction + User Identity ✅ │ └── v0.24.2 Fine-Grained Permissions (parallel) ✅ │ - ┌───────┴──────────────┐ - │ │ -v0.25.0 Workflow v0.26.0 Tasks / - Engine Autonomous Agents - (team-owned, (service channels, - staged processes, scheduler, unattended - human + AI collab) execution) +v0.25.0 Dynamic Surfaces + Context-Aware Tools + (pane system, manifest-driven surfaces, + editor rebuild, tool predicates, + persona tool grants) + │ +v0.26.0 Workflow Engine + (team-owned staged processes, + human + AI collab, visitor + intake, assignment queue) + │ +v0.27.0 Tasks / Autonomous Agents + (service channels, scheduler, + unattended execution) ``` --- @@ -230,985 +236,142 @@ Groups (global/team-scoped ACLs) decoupled from team membership. Three-way resource grants (team_only/global/groups) for Personas and KBs. Grant picker UI. Schema consolidation: 9 migrations → single `001_v016_schema.sql`. ---- -## v0.17.0 — Persona-KB Binding + Enterprise KB Mode + QOL ✅ +### ✅ v0.17.0 — Persona-KB Binding + Enterprise KB Mode + QOL +Personas as KB gateways. `persona_knowledge_bases` binding, auto-search +mode, enterprise KB discoverability controls. Team admin workflow. +`HandleFromName()` auto-generation. Store layer sole DB interface. -Personas become **gateways** to knowledge. In enterprise deployments, -users don't interact with KBs directly — they talk to Personas that -have KBs attached. Plus quality-of-life improvements: chat rename, -token display, state persistence, utility model auto-naming. +### ✅ v0.17.1 — SQLite Backend +Dual-database support (Postgres + SQLite). `database/compat.go` dialect +abstraction, `database.Q()` query rewriting, SQLite-specific migration +set. Single-user / dev deployment mode. +See [v0171-sqlite-backend.md](v0171-sqlite-backend.md). -Depends on: knowledge bases (v0.14.0), user groups (v0.16.0). +### ✅ v0.17.2 — CodeMirror 6 Integration +CM6 replaces textarea: `codeEditor()` + `chatInput()` + `noteEditor()` +factories. 20+ languages bundled, Vim/Emacs keybindings, `[[wikilink]]` +autocomplete. esbuild bundle. See [DESIGN-CM6.md](DESIGN-CM6.md). -**Persona-KB Binding** -- [x] `persona_knowledge_bases` table: `persona_id`, `kb_id`, `auto_search` (bool — always search vs tool-only) -- [x] When a channel uses a Persona with bound KBs, `kb_search` is auto-scoped to those KBs -- [x] No user toggle needed — Persona carries its own KB context -- [x] Channel KB toggle becomes "additional KBs" on top of Persona-provided ones -- [x] Persona system prompt auto-includes KB listing hint (reuses `BuildKBHint` pattern) -- [x] Admin/team admin UI: KB picker on Persona create/edit form +### ✅ v0.17.3 — Notes Graph + Wikilinks +`[[wikilink]]` bi-directional linking, `note_links` junction table, +Canvas force-directed graph visualization. Daily notes, folder tree, +markdown preview. See [DESIGN-0.17.3.md](archive/DESIGN-0.17.3.md). -**Enterprise KB Mode** -- [x] `discoverable` flag on knowledge_bases: `true` (default — appears in user's KB popup) or `false` (hidden, only accessible through Persona binding) -- [x] Hidden KBs don't appear in `GET /api/v1/knowledge-bases-discoverable` for non-admins -- [x] Hidden KBs still searchable by `kb_search` tool when accessed through a Persona -- [x] Admin panel: toggle discoverability per KB -- [x] Platform policy: `kb_direct_access` — when `false`, disables channel KB popup entirely (strict enterprise mode) +### ✅ v0.18.0 — Memory (User + Persona Scopes) +User + persona memory extraction pipeline. Background summarization via +utility role. Memory injection into system prompt. Admin review panel. +`memories` + `persona_memories` tables. -**Access Control Integration** -- [x] Persona grants (v0.16.0 groups) control who can *use* a Persona -- [x] KB grants control who can *manage* a KB (upload/delete docs) -- [x] Persona-KB binding grants implicit *search* access through the Persona -- [x] Users who can use a Persona can search its KBs, even if they can't see those KBs directly +### ✅ v0.18.1 — Side Panel Architecture +Single-slot panel system. Panel registry with independent open/close. +Dual-view mode (two panels side-by-side). `ctx.ui.openPreview()`, +keyboard shortcuts. Extension UI participation. Mobile swipe. -**Team Admin Workflow** -- [x] Team admin creates KB → uploads documents → marks non-discoverable -- [x] Team admin creates Persona → binds KBs → sets access to Team Only or specific Groups -- [x] Team members see the Persona in their preset list, use it, get KB-powered answers -- [x] Team members never see or manage the underlying KBs +### ✅ v0.19.0 — Projects / Workspaces +Project container: channels, KBs, personas, system prompt, team scope. +`projects` + `project_channels` tables. Drag-drop sidebar. -**Technical Debt (carried forward)** -- [x] **Security**: KB create handler authorization — team/global scope verified -- [x] **Test hygiene**: stripped DIAG diagnostics from `TestGroupBasedPersonaAccess` -- [x] **Architecture**: `KnowledgeBaseStore.UpdateDocumentStorageKey()` — moved to store layer -- [x] **UX**: Embedding dropdown fix — tolerant type filter, manual model ID fallback, auto-switch on empty _(already implemented in `ui-primitives.js`)_ -- [x] **Minor**: Paste-to-file character threshold — synced from backend `PublicSettings` (`storage.paste_to_file_chars`), admin-configurable, default 2000 +### ✅ v0.19.1 — Active Project + System Prompt + Detail Panel +Active project context in chat. Project system prompt prepend. Detail +panel (info, members, KBs, channels). Channel-project binding UI. -**Role Fallback Alerts** ([#69](https://git.gobha.me/xcaliber/chat-switchboard/issues/69)) -- [x] Audit log entry on fallback fire: `action = "role.fallback"` with primary/fallback model IDs and error string -- [x] `role.fallback` WebSocket event via EventBus (`PublishAsync`, zero latency impact on completion path) -- [x] In-memory cooldown on `Resolver` (per-role, 5-minute TTL) to deduplicate repeated fallback alerts -- [x] Admin UI: persistent alert banner on `role.fallback` event (persists until dismissed) -- [x] Wire `*events.Bus` into `roles.NewResolver` via `.WithBus()` builder +### ✅ v0.19.2 — Project Persona Default + Archive + Reorder +Project-level default persona. Archive/unarchive. Drag-to-reorder +sidebar items. Project settings persistence. -**QOL / UX Wins** -- [x] **Chat rename**: inline edit on sidebar item — dblclick title → input → blur/Enter saves via `API.updateChannel(id, { title })` -- [x] **Chat token count**: display `Tokens.estimateConversation()` in model bar, update on `selectChat` and after each message -- [x] **State restore on refresh**: persist `App.currentChatId` to `sessionStorage` on select, restore on load -- [x] **Utility model auto-naming**: after first assistant response, background utility role request → `POST /channels/:id/generate-title` → re-render sidebar. Fallback to truncation when no utility model configured. Debounced via `_autoNamePending` set -- [x] **SW extension cache fix**: exclude `/extensions/` from service worker fetch handler -- [x] **Mermaid renderer**: promoted enhanced version (v2.0 — pan/zoom, SVG/PNG export, source copy) to `extensions/builtin/mermaid-renderer/` +### ✅ v0.20.0 — Notifications + @mention Routing + Multi-model +Bell dropdown notifications. `@mention` resolves to persona handles and +model IDs. Multi-model chat. `notifications` table, WebSocket push, +`channel_participants` table. AI-to-AI chaining, context poisoning +prevention (Anthropic rewrite, OpenAI Name field). + +### ✅ v0.21.x — Workspace Platform + Extension Surfaces +Seven-release series. v0.21.0: workspace storage primitive. v0.21.1: +workspace tools + channel/project binding. v0.21.2: workspace indexing + +semantic search. v0.21.3: surface infrastructure + REPL. v0.21.4: git +integration (clone/push/pull/commit, credential management). v0.21.5: +editor surface (IDE-like: file tree + CM6 + chat pane). v0.21.6: article +surface + document output pipeline + hash router. v0.21.7: scanJSON +driver buffer aliasing bugfix. See [DESIGN-0.21.0.md](archive/DESIGN-0.21.0.md). + +### ✅ v0.22.0 — Provider Health + Capability Overrides +`provider_health` accumulator (5-min windows, 1h retention). Health +badges. `capability_overrides` table. Two-tier capability resolution +(catalog sync → heuristic → optional admin override). Provider-scoped +capabilities. + +### ✅ v0.22.1 — Provider Extensions (Declarative Config) +YAML-based provider type registration. Settings schema per provider type. +Venice.ai provider. Provider-specific parameter pass-through. Extended +thinking support (Anthropic). + +### ✅ v0.22.2 — Routing Policies + Fallback Chains +`routing_policies` table. Three policy types: `model_preference`, +`provider_failover`, `cost_optimize`. Channel-bindable. Failover +execution in completion handler. Health-aware skip. + +### ✅ v0.22.3 — Provider Admin UI + Deferred Polish +Provider health dashboard, capability override editor, routing policy +builder. Model catalog sync trigger. Dynamic provider config form. + +### ✅ v0.22.4 — Provider Health UX + Project Files + Export +Health dots in model selector. Project files tab (channel file +aggregation). Conversation export (JSON, Markdown). Bulk file download. + +### ✅ v0.22.5 — Surfaces + Go Templates + Admin Bug Fixes +Go `html/template` engine with `//go:embed`. Six surfaces (chat, editor, +notes, settings, admin, login). Reusable components (model-select, +team-select, file-upload). `AuthOrRedirect` middleware. CSP nonces. + +### ✅ v0.22.6 — Split Deployment Fix + CI Timeout + Code Pruning +`BACKEND_URL` fail-fast, ~2,430 lines OBE code removed (router.js, +surfaces.js, SPA shell). Extension surfaces intentionally broken pending +pane refactor (→ v0.25.0). Service worker BUILD_HASH cache key. + +### ✅ v0.22.7 — Surface Prototypes (Theme + ChatPane + Splash) +`theme.css` with CSS custom properties. `ChatPane.create()` factory +pattern. Login/splash redesign. Toast stack, badges, icon buttons, +avatar upload, confirm dialog. Settings feature gates (BYOK, Personas). + +### ✅ v0.22.8 — Surface Integration (Wire into Existing JS) +`ChatPane.primary` bridge from server-rendered mount points. Theme wired +to settings appearance. Admin hybrid section loaders. Naming cleanup: +preset → persona, APIConfigID → ProviderConfigID. --- -## v0.17.1 — SQLite Backend ✅ - -Dual-database support. Every subsequent schema change is developed -against both Postgres and SQLite from day one — no retrofit. SQLite -enables single-binary deployment for dev, demo, edge, and single-user. - -Depends on: v0.17.0 DB debt cleanup (store layer is sole DB interface). - -**Store Layer** -- [x] 19 SQLite store implementations covering all domain interfaces -- [x] `DB_DRIVER` env var: `postgres` (default) | `sqlite` -- [x] Separate migration files per driver (`migrations/sqlite/`) -- [x] WAL mode + single-writer connection pooling for SQLite concurrency -- [x] CI matrix: full handler integration tests against both Postgres and SQLite - -**Vector Search** -- [x] App-level cosine similarity in Go (pure Go, no CGO/sqlite-vec required) -- [x] Embeddings stored as JSON text in `kb_chunks.embedding` column -- [x] Full feature parity with pgvector: `SimilaritySearch`, `InsertChunks` -- [x] Graceful: adequate performance for SQLite-scale deployments (single-user, not millions of chunks) - -**Schema Compatibility** -- [x] UUID generation: application-side `store.NewID()` (Go `uuid.New()`) -- [x] JSONB → JSON text columns with `ToJSON()`/`ScanJSON()` helpers -- [x] `UUID[]` arrays → JSON arrays with `ToJSONArray()`/`ScanJSONArray()` -- [x] `TIMESTAMPTZ` → SQLite `TEXT` with `datetime('now')` -- [x] `ON CONFLICT excluded.*` pattern (works in both dialects) -- [x] `INSERT RETURNING id` → separate query pattern for SQLite - -**Test Infrastructure** -- [x] `dialectSQL()` converts `$N` → `?` and strips `::jsonb` at runtime -- [x] `database.PH(n)` returns dialect-appropriate placeholder -- [x] `database.TruncateAll()` dialect-aware (DELETE + PRAGMA vs TRUNCATE CASCADE) -- [x] Generic provider config: `PROVIDER`/`PROVIDER_KEY`/`PROVIDER_URL` (replaces `VENICE_API_KEY`) -- [x] Model selection prefers non-reasoning models in live tests - -**What SQLite mode skips** (feature-gated, not broken): -- [x] `LISTEN/NOTIFY` — WebSocket event fan-out uses in-process EventBus (already works) -- [x] Full-text search `tsvector` — conversation_search uses LIKE fallback - ---- - -## v0.17.2 — CodeMirror 6 Integration ✅ - -Rich editor infrastructure for the frontend. CM6 is ESM-native; the build -step runs in Docker (esbuild → single IIFE bundle). No change to dev -experience for non-editor code — the rest of `src/js/` stays vanilla. - -Depends on: nothing (frontend-only). Prerequisite for: extension surfaces -(v0.21.5 editor surface). See [DESIGN-CM6.md](DESIGN-CM6.md) for full spec. - -**Build Pipeline** -- [x] `src/editor/` directory: `package.json`, `build.mjs`, `index.mjs`, language/theme modules -- [x] `scripts/build-editor.sh`: shared build script for both Dockerfiles and local dev -- [x] New Docker stage (`cm6-build`): `npm ci` + `node build.mjs` → `vendor/codemirror/` -- [x] Both `Dockerfile.frontend` and `Dockerfile` (unified) use the shared build script -- [x] Bundle output: `codemirror.bundle.js` (~295KB min, ~90KB gzip) -- [x] Graceful degradation: all integration points check `window.CM` — falls back to ` + + + + {{/* Read mode */}} + + + {{/* Backlinks */}} + + + + {{/* ── Graph View ──────────────────────── */}} + + +{{end}} diff --git a/server/pages/templates/components/user-menu.html b/server/pages/templates/components/user-menu.html new file mode 100644 index 0000000..f06261f --- /dev/null +++ b/server/pages/templates/components/user-menu.html @@ -0,0 +1,40 @@ +{{/* + User Menu Component — reusable user avatar + flyout dropdown. + Usage: {{template "user-menu" dict "ID" ""}} + With empty ID, generates existing IDs: userMenuBtn, userAvatar, etc. + With prefix: {{template "user-menu" dict "ID" "editor"}} → editorUserMenuBtn, etc. + UserMenu.create() in user-menu.js binds to these IDs. +*/}} +{{define "user-menu"}} +
+ +
+ + + + +
+ +
+
+{{end}} diff --git a/server/pages/templates/surfaces/admin.html b/server/pages/templates/surfaces/admin.html index 0534dd5..d3f65da 100644 --- a/server/pages/templates/surfaces/admin.html +++ b/server/pages/templates/surfaces/admin.html @@ -32,7 +32,7 @@ Routing - + System @@ -241,4 +241,5 @@ + {{end}} diff --git a/server/pages/templates/surfaces/chat.html b/server/pages/templates/surfaces/chat.html index 616bc65..5281a64 100644 --- a/server/pages/templates/surfaces/chat.html +++ b/server/pages/templates/surfaces/chat.html @@ -177,45 +177,20 @@ window.addEventListener('unhandledrejection', function(e) { {{/* User / bottom */}} @@ -233,16 +208,7 @@ window.addEventListener('unhandledrejection', function(e) { {{/* Chat header: model selector + caps + tokens + panel + notif */}}
-
- -
- {{/* Populated by UI.updateModelSelector() */}} -
-
- + {{template "model-selector" dict "ID" ""}}
diff --git a/server/pages/templates/surfaces/editor.html b/server/pages/templates/surfaces/editor.html index 6c1e1e7..e6c72df 100644 --- a/server/pages/templates/surfaces/editor.html +++ b/server/pages/templates/surfaces/editor.html @@ -1,127 +1,104 @@ {{/* - Editor surface — matches switchboard-prototype-editor.jsx. - IDE-like layout: topbar + file tree + tabs + code + chat pane. - editor-mode.js builds CodeMirror, file tree, etc. + Editor surface — v0.25.0 rebuild. + Three-pane layout: files | code-editor | + Uses PaneContainer for resizable splits and tabbed right pane. + + Components are SERVER-RENDERED via Go template partials into hidden + containers (#editorComponents). The boot script moves them into + pane slots created by PaneContainer. This ensures full DOM parity + with the chat surface — same buttons, same features, same behavior. */}} {{define "surface-editor"}} -
+
- {{/* Top Bar */}} -
- + {{/* ── Top Bar ─────────────────────────── */}} +
+ Back -
+
- - {{if .Data}}{{.Data.WorkspaceName}}{{else}}Editor{{end}} - -
- - main -
-
- - - -
- - -
- {{/* Body: tree + editor + chat */}} -
- {{/* File Tree */}} -
-
- - Files - +
+
+ {{/* Populated by JS */}} +
+
+
-
- {{/* Populated by editor-mode.js */}} -
- {{/* Main Editor Area */}} -
- {{/* Tabs */}} -
- {{/* Populated by editor-mode.js */}} -
- - {{/* Code Content */}} -
-
-
- -

Open a file to start editing

-

Select from the file tree or Ctrl+P

-
-
-
- - {{/* Status Bar */}} -
- Ready -
+ +
+ + {{template "user-menu" dict "ID" ""}} +
- {{/* Chat Pane (resizable) */}} - -