Changeset 0.25.1 (#161)

This commit is contained in:
2026-03-08 18:54:53 +00:00
parent 2b01d540d6
commit b3f8b747dd
48 changed files with 531 additions and 888 deletions

View File

@@ -393,50 +393,101 @@ Vanilla JavaScript, no framework. The frontend ships as static files served by n
```
src/
├── index.html # Single-page app shell
├── sw.js # Service worker (offline cache)
├── index.html # Redirect stub → server-rendered surfaces
├── sw.js # Service worker (offline cache, BUILD_HASH)
├── manifest.json # PWA manifest
├── css/
│ ├── styles.css # Core styles (CSS variables, light/dark themes)
── memory.css # Memory settings + admin review panel styles
│ ├── variables.css # Theme vars, reset, base styles
── layout.css # App shell, workspace, sidebar, responsive
│ ├── primitives.css # Buttons, forms, toasts, toggles, badges, icon-btn
│ ├── modals.css # Modal system, debug, command palette, confirm
│ ├── chat.css # Chat area, markdown, input, files, lightbox
│ ├── panels.css # Side panel, preview, notes, graph
│ ├── surfaces.css # Admin, settings, editor, projects, notes layouts
│ ├── splash.css # Auth splash, PWA banner
│ ├── chat-pane.css # ChatPane component styles
│ ├── pane-container.css # PaneContainer resize/tab styles
│ ├── user-menu.css # UserMenu flyout styles
│ ├── editor-surface.css # Editor surface 3-pane layout
│ ├── channel-models.css # @mention autocomplete, model roster
│ ├── memory.css # Memory settings + admin review
│ ├── notifications.css # Notification dropdown + list
│ ├── notification-prefs.css # SMTP config, notification pref table
│ ├── persona-kb.css # Persona KB picker panel
│ ├── admin-surfaces.css # Admin surface management
│ └── tool-grants.css # Persona tool grants checkbox list
├── js/
│ ├── ── Primitives (base.html, all surfaces) ──
│ ├── app-state.js # Global state (App, API refs)
│ ├── api.js # HTTP client with token refresh
│ ├── app.js # Application state machine, startup, routing
│ ├── chat.js # Chat input abstraction, message send/receive
│ ├── channel-models.js # @mention autocomplete, channel model roster
│ ├── events.js # Labeled event bus + WebSocket bridge
│ ├── debug.js # Debug panel, diagnostics, state export
├── ui-core.js # DOM rendering, sidebar, modals, panels
├── ui-format.js # Markdown rendering, @mention pills, code blocks
├── ui-settings.js # Settings tabs, theme, appearance, teams
├── ui-admin.js # Admin panel rendering
│ ├── admin-handlers.js # Admin CRUD operations + extension editors
│ ├── ui-primitives.js # esc(), componentMixin, Providers, Roles,
# renderCapBadges, renderProviderForm/List,
│ # renderRoleConfig, renderUsageDashboard,
│ # showConfirm, showPrompt, openModal/closeModal,
│ # Theme, mountAvatarUpload
│ ├── ui-format.js # Markdown rendering, code blocks, time formatting
│ ├── ui-core.js # DOM rendering, sidebar, navigation, toast
│ ├── pages.js # Page routing, splash, login
│ │
│ ├── ── Components (base.html, all surfaces) ──
│ ├── user-menu.js # UserMenu template+factory component
│ ├── model-selector.js # ModelSelector template+factory component
│ ├── file-tree.js # FileTree template+factory component
│ ├── code-editor.js # CodeEditor template+factory component (CM6)
│ ├── note-editor.js # NoteEditor template+factory component
│ ├── chat-pane.js # ChatPane template+factory component
│ ├── pane-container.js # PaneContainer (resizable multi-pane layout)
│ ├── debug.js # Debug panel + diagnostics
│ ├── repl.js # Browser REPL console
│ │
│ ├── ── Surface: Chat ──
│ ├── app.js # Chat surface boot, auth, WebSocket
│ ├── chat.js # Chat message send/receive, stream
│ ├── extensions.js # Extension framework + sandbox
│ ├── panels.js # Side panel registry
│ ├── ui-settings.js # Settings modal tabs (chat surface)
│ ├── ui-admin.js # Admin navigation + section routing
│ ├── admin-handlers.js # Admin CRUD + extension editors
│ ├── admin-scaffold.js # Admin section HTML scaffolding
│ ├── settings-handlers.js # User settings CRUD, command palette
│ ├── tokens.js # Input token counting + context budget
│ ├── attachments.js # File upload, paste-to-file, lightbox
│ ├── files.js # File upload, paste-to-file, lightbox
│ ├── notes.js # Notes panel CRUD + graph + daily notes
│ ├── note-graph.js # Canvas force-directed graph visualization
│ ├── projects-ui.js # Project sidebar, context menu, drag-and-drop
│ ├── knowledge.js # Knowledge base UI
│ ├── memory-ui.js # Memory settings tab + admin review panel
│ ├── projects-ui.js # Project sidebar, context menu, DnD
│ ├── channel-models.js # Channel model roster + @mention AC
│ ├── tools-toggle.js # Tool enable/disable popup
│ ├── knowledge-ui.js # Knowledge base picker + management
│ ├── persona-kb.js # Persona KB assignment panel
│ ├── memory-ui.js # Memory settings + admin review
│ ├── notifications.js # Notification bell + dropdown
│ ├── notification-prefs.js # SMTP config + notification prefs
│ │
│ ├── ── Surface: Editor ──
│ ├── editor-surface.js # Editor 3-pane boot, workspace management
│ │
│ ├── ── Surface: Admin ──
│ ├── admin-surfaces.js # Surface management (admin only)
│ │
│ ├── ── Surface: Login ──
│ ├── pages-splash.js # Login/register splash page
│ │
│ └── __tests__/ # Node.js test suite (node --test)
├── editor/ # CM6 source (compiled at build time)
│ ├── package.json # CM6 + language mode dependencies
│ ├── package-lock.json # Lockfile for npm ci
│ ├── build.mjs # esbuild script → IIFE bundle
│ ├── index.mjs # Bundle entrypoint (window.CM)
│ ├── chat-input.mjs # Chat input factory (markdown, code blocks)
│ ├── code-editor.mjs # Code editor factory (syntax, keybindings)
│ ├── note-editor.mjs # Note editor factory (markdown + wikilinks)
│ ├── wikilink.mjs # CM6 wikilink extension (parse, decorate, autocomplete)
│ └── theme.mjs # Switchboard + chat input + note editor themes
└── vendor/ # Vendored libraries (local + CDN fallback)
├── marked/ # Markdown renderer
├── purify/ # DOMPurify (XSS protection)
── mermaid/ # Diagram renderer
├── katex/ # Math renderer
└── codemirror/ # CM6 bundle (built by Docker)
└── codemirror.bundle.js # ~295KB min, ~90KB gzip
│ ├── wikilink.mjs # CM6 wikilink extension
│ └── theme.mjs # CM6 themes (dark/light)
└── vendor/ # Vendored libraries (loaded in base.html)
├── marked.min.js # Markdown renderer
├── purify.min.js # DOMPurify (XSS protection)
── codemirror/
└── codemirror.bundle.js # CM6 bundle (~295KB min, ~90KB gzip)
```
### CM6 Integration

View File

@@ -1,8 +1,8 @@
# DESIGN — Surface & Extension Architecture
**Status:** Accepted
**Status:** Accepted (Phases 12 implemented in v0.25.1)
**Scope:** Primitives, Components, Surfaces, Extension hooks, Themes
**Depends on:** v0.22.5 (Go template engine), v0.22.7 (ChatPane)
**Depends on:** v0.22.5 (Go template engine), v0.22.7 (ChatPane), v0.25.1 (audit)
**Informs:** v0.22.8+, EXTENSIONS.md rewrite, ARCHITECTURE.md update, ICD-API, ICD-SURFACE
---
@@ -159,7 +159,9 @@ Primitives.menu({ anchor: el, items: [...], onSelect: fn })
Primitives.dialog({ title: 'Confirm', body: el, onConfirm: fn })
```
Current locations: `ui-primitives.js`, `ui-primitives-additions.js`,
Current locations: `ui-primitives.js` (factory functions, `esc()`,
`createComponentRegistry()`, `componentMixin()`, `showConfirm()`,
`showPrompt()`, `Theme`, `mountAvatarUpload()`)
and Go template components (`model-select.html`, `team-select.html`,
`file-upload.html`). These converge into one coherent set.
@@ -202,23 +204,42 @@ to interact with.
### Instance Pattern
Components use the factory pattern established by ChatPane:
Components use `createComponentRegistry()` and `componentMixin()` from
`ui-primitives.js` for shared lifecycle (instance tracking, event
listener cleanup, destroy):
```js
const pane = ChatPane.create({
messagesEl: document.getElementById('editorChatMessages'),
inputEl: document.getElementById('editorChatInput'),
sendBtnEl: document.getElementById('editorSendBtn'),
channelId: workspaceChatId,
standalone: true,
});
const ChatPane = {
...createComponentRegistry('ChatPane'),
// Lifecycle
pane.renderMessages(msgs);
pane.streamResponse(resp, msgs);
pane.destroy();
create(opts) {
const instance = componentMixin({
id: opts.id || 'pane-' + Date.now(),
messagesEl: opts.messagesEl,
inputEl: opts.inputEl,
channelId: opts.channelId || null,
// ... domain-specific state
// Component-specific teardown (called by mixin's destroy())
_cleanup() {
if (this._cmView) { this._cmView.destroy(); this._cmView = null; }
},
}, ChatPane);
ChatPane._register(instance.id, instance);
return instance;
},
// Custom queries beyond .get(id)
forChannel(channelId) { /* ... */ },
};
```
The mixin provides `_on(el, event, handler)` for tracked event binding
and `destroy()` which calls `_cleanup()` then removes all listeners and
unregisters from the registry. Components that need extra teardown define
`_cleanup()`.
Components can be instantiated multiple times on the same page (editor
has a ChatPane, notes has a ChatPane — independent instances).
@@ -567,7 +588,7 @@ accommodates it without redesign.
b. Register hooks (pre-completion, post-render, etc.)
c. Register surface injections for current surface
d. Initialize tool bridges
5. Surface-specific JS runs (app.js for chat, editor-mode.js, etc.)
5. Surface-specific JS runs (app.js for chat, editor-surface.js, etc.)
```
`Extensions.boot()` replaces the current chat-specific
@@ -672,8 +693,8 @@ post-render hooks use to discover display content from any extension.
| Current State | Target State |
|---------------|-------------|
| `ui-primitives.js` + `ui-primitives-additions.js` | Primitive catalog with stable factory API |
| `ChatPane.create()` (v0.22.7) | Component catalog with shared instance pattern |
| `ui-primitives.js` (merged, with `esc()`, `createComponentRegistry()`, `componentMixin()`) | ✅ Done (v0.25.1) |
| `ChatPane.create()` + 5 other components using shared mixin | ✅ Done (v0.25.1) |
| 5 Go template routes | Surface registry (hardcoded core, manifest-driven extensions) |
| `ctx.ui.replace()` / `ctx.ui.inject()` | Hook 6: Surface Injection with declared mount points |
| `ctx.surfaces.register()` | Manifest `surfaces` field → page engine route registration |
@@ -688,17 +709,22 @@ post-render hooks use to discover display content from any extension.
This does not prescribe version numbers. It describes dependency order.
**Phase 1: Primitive consolidation**
- Audit `ui-primitives.js`, `ui-primitives-additions.js`, and Go
template components
- Define the primitive catalog and factory API
- Define the CSS custom property contract (theme API)
- Migrate existing callers to the consolidated API
**Phase 1: Primitive consolidation** ✅ (v0.25.1)
- `ui-primitives-additions.js` deleted, survivors merged into
`ui-primitives.js`
- `esc()` centralized (13 private copies eliminated)
- Badge system unified (24 scattered classes → grouped in primitives.css)
- CSS variable names normalized, duplicate selectors resolved
- `showConfirm()` is the sole confirm pattern (bare `confirm()` purged)
**Phase 2: Component formalization**
- ChatPane already exists (v0.22.7). Formalize the instance pattern.
- Extract NoteEditor, FileTree, ModelSelector as components
- Each component gets a Go template partial + JS hydration
**Phase 2: Component formalization** ✅ (v0.25.1)
- `createComponentRegistry()` + `componentMixin()` extracted
- 6 components (ChatPane, ModelSelector, UserMenu, CodeEditor, FileTree,
NoteEditor) use the shared mixin. ~100 lines of boilerplate eliminated.
- Each component has a Go template partial + JS hydration
- `surface-nav.js` deleted; navigation is native in `ui-core.js`
- Vendor scripts (`marked.min.js`, `purify.min.js`) and `ui-format.js`
moved to `base.html` (loaded once, available to all surfaces)
**Phase 3: Extension hooks**
- `Extensions.boot()` on every surface (v0.22.8)

View File

@@ -1,6 +1,6 @@
# Surface Development Guide
**Version:** 0.25.0
**Version:** 0.25.1
**Audience:** Anyone with admin access to a Chat Switchboard instance
---