# Changelog ## [0.37.14.23] — 2026-03-23 ### Summary Extension surface user menu fix + roadmap workflow integration. The ICD Runner (and all extension surfaces) now mount the Preact UserMenu via `sw.userMenu()` instead of relying on the dead Go template hydration. ### Fixed - **Extension surface "? User" label:** extension template included static `{{template "user-menu"}}` which rendered placeholder HTML ("? User") since the legacy hydration script was removed in v0.37.13. Removed the dead template inclusion. (`server/pages/templates/surfaces/extension.html`) - **Extension surface user menu click does nothing:** ICD Runner never called `sw.userMenu()` to mount the Preact UserMenu component. Added topbar with `sw.userMenu(topbar, { flyout: 'down' })` in `renderShell`. Also uses `sw.auth.user` instead of dead `window.__USER__` for header display. (`packages/icd-test-runner/js/ui.js`, `packages/icd-test-runner/js/main.js`) ### Changed - **Roadmap:** added v0.37.15 reference to `DESIGN-0.37.15.md` workflow design doc, added v0.38.x Workflow Product Maturity section referencing `ROADMAP-0.38.md`. Trimmed completed version descriptions. --- ## [0.37.14.22] — 2026-03-23 ### Summary Thinking tags persistence + deleteMessage endpoint. Two features that close out the v0.37.14 pane audit. Also fixes an S9 latent bug (messages paginated response not unwrapped) and a SQLite NULL scan crash in GetByID. ### Added - **deleteMessage server endpoint** — `DELETE /channels/:id/messages/:msgId` with soft-delete, channel access check, and `message.deleted` WS broadcast to other participants. (`server/handlers/messages.go`, `server/main.go`) - **`message.deleted` event type** — registered as `DirToClient` for cross-tab message removal. (`server/events/types.go`) - **`deleteMessage` SDK method** — `rc.del(...)` in channels namespace. (`src/js/sw/sdk/api-domains.js`) - **`message.deleted` WS handler** — filters by active channel, removes message from state. (`src/js/sw/components/chat-pane/use-chat.js`) - **`onDelete` wired in ChatPane** — delete button now visible on all messages. (`src/js/sw/components/chat-pane/index.js`) - **`extractThinking` / `hydrateThinking` helpers** — parse `` blocks from message content on the load path (switchChannel, loadMore, WS message.created). (`src/js/sw/components/chat-pane/use-chat.js`) ### Fixed - **Thinking tags lost on refresh:** `` content rendered correctly during streaming (via SSE `reasoning_content`) but spilled as raw text after page reload. Now extracted on the load path and rendered in the collapsible `
` block. Frontend-only fix, no DB migration. - **S9 messages unwrap bug:** messages endpoint returns paginated response with 5 sibling keys, so `_unwrap` preserves the full object. `resp || []` produced an object, not an array. Changed to `resp.data || resp || []`. - **SQLite NULL scan crash:** `GetByID` fails on user messages where `model` and `tokens_used` are NULL (struct uses `string`/`int`, not pointers). Delete handler now uses a direct `EXISTS` query instead. --- ## [0.37.14.21] — 2026-03-23 ### Summary Double-unwrap cleanup + API envelope normalization. Eliminated 93 defensive `resp.data || resp || []` patterns across the frontend by fixing `_unwrap` to preserve sibling fields and normalizing all Go handlers to use `{data: [...]}` standard envelopes. Three latent bugs fixed (roles, provider types, audit). ### Changed - `src/js/sw/sdk/rest-client.js` — `_unwrap` now only strips `{data: [...]}` when `data` is the sole key (`Object.keys(json).length === 1`). Responses with siblings (e.g. `{data: [...], total: N}`) pass through intact. - **15 Go handlers** normalized from named keys (`users`, `configs`, `models`, `channels`, `participants`, `tools`, `folders`, `messages`, `values`, `packages`) to standard `{data: [...]}` envelope: - `server/handlers/admin.go` — ListUsers, ListGlobalConfigs, ListModelConfigs, ListArchivedChannels - `server/handlers/apiconfigs.go` — ListConfigs, ListModels - `server/handlers/channel_models.go` — List, Add, Update, Delete - `server/handlers/participants.go` — List, Add, Update, Remove - `server/handlers/presence.go` — SearchUsers - `server/handlers/completion.go` — ListTools - `server/handlers/folders.go` — List - `server/handlers/notes.go` — ListFolders - `server/handlers/messages.go` — GetActivePath, SetCursor - `server/handlers/teams.go` — ListAvailableModels - `server/handlers/team_providers.go` — ListTeamProviderModels - `server/handlers/packages.go` — UpdatePackageSettings - `server/handlers/package_registry.go` — BrowseRegistry - `server/handlers/roles.go` — ListRoles (bare map → wrapped in `{data: map}`) - **~45 frontend files** — simplified all double-unwrap patterns: - Sole-key endpoints (unwrapped): `resp || []` - Sibling endpoints (not unwrapped): `resp.data || []`, `resp.total || 0` - Roles map: `r.data || {}` + `Object.entries()` for iteration - Go integration + live provider tests updated for new envelope keys - Frontend contract + policy-gating tests updated ### Fixed - **Admin → Roles always empty:** `ListRoles` returned a raw map; `r.roles` was undefined on it. Now wrapped in `{data: map}`, frontend iterates via `Object.entries(roles)`. - **Admin → Provider Types dropdown always empty:** `GetProviderTypes` returned `{data: types}`, `_unwrap` stripped it to bare array, `t.types` was undefined. Now correctly uses `t || []`. - **Admin → Audit entries always empty:** `_unwrap` stripped `{data, total}` to just the array, losing `total`. Now preserved because of sibling-aware `_unwrap`. ### Design Notes - **Envelope contract:** All list endpoints now return `{data: [...]}` or `{data: [...], ...metadata}`. No more `{users: [...]}`, `{models: [...]}`, etc. - **`_unwrap` contract:** sole-key `{data: [...]}` → bare array; sibling keys present → full object (frontend accesses `.data` and siblings). - **Editor package skipped:** `packages/editor/js/main.js` uses `API._get` which bypasses `_unwrap`; defensive patterns intentionally preserved. --- ## [0.37.14] — 2026-03-22 ### Summary Scorched Earth IV + Pane Audit — fourth dead-code purge. 4 files deleted (~−1,672 lines). The old global layer (`sb.js`, `events.js`, `switchboard-sdk.js`, `workflow-surfaces.js`) is fully removed. Two survivors (`debug.js`, `repl.js`) cleaned of all old-layer dependencies and now stand alone with direct `window.*` exports. ### Removed - `src/js/sb.js` (133 LOC) — global action registry (`window.sb`); onclick handlers in base.html rewritten to direct function calls - `src/js/events.js` (361 LOC) — event bus + WebSocket bridge (`window.Events`); WebSocket auth called deleted `API` global; new SDK (`sw/sdk/events.js`) is the sole event system - `src/js/switchboard-sdk.js` (~697 LOC) — composition layer (`window.Switchboard`); `window.sw` was immediately overwritten by Preact SDK `boot()`; most methods referenced deleted globals (`API`, `UI`) - `src/js/workflow-surfaces.js` (481 LOC) — workflow stage surface registry; loaded deleted `ui-primitives.js` as dependency (already broken at runtime since v0.37.13) - `base.html`: removed 3 script tags, removed `Switchboard.init()` block (including dead `handleLogout` referencing deleted `Events`/`API`) ### Changed - `src/js/debug.js` — replaced `sb.ns()`/`sb.register()` with direct `window.*` exports; replaced dead `API`/`App`/`Events`/`Extensions` state snapshot with Preact SDK `window.sw` introspection; diagnostics use `sw.auth.token` and `sw.events.connected`; fixed `copyDebugLog` referencing deleted `UI.toast` - `src/js/repl.js` — replaced `sb.ns()` with `window.REPL`; admin gate uses `window.sw.auth.user.role` instead of deleted `API.user.role`; injected globals reduced to `sw` + `DebugLog`; removed dead event label tab-completion - `server/pages/templates/base.html` — 11 `sb.call()` onclick handlers rewritten to direct function calls - `server/pages/templates/workflow.html` — broken custom surface loader replaced with graceful error message - `src/sw.js` — removed 3 entries from SHELL_FILES (sb.js, events.js, switchboard-sdk.js) - `packages/icd-test-runner/js/tier-sdk.js` — boot tests updated from `Switchboard.init()` to Preact SDK `boot()`; identity tests use `sw.auth.user`; theme test uses `sw.emit()`; removed extension compat shim test - `src/js/sw/sdk/index.js` — SDK version marker updated to 0.37.14 ### Design Notes - **2 old JS files survive:** `debug.js` (debug modal + diagnostics) and `repl.js` (admin REPL console). Both are standalone with zero old-layer dependencies. Scheduled for Preact rewrite at v0.37.17. - **Cumulative scorched earth:** 53 files deleted, ~−19,382 lines across four passes (v0.37.10, v0.37.12, v0.37.13, v0.37.14). --- ## [0.37.13] — 2026-03-22 ### Summary Scorched Earth III — third dead-code purge. 5 files deleted (−2,269 net lines). The massive `ui-primitives.js` (1,133 LOC) is gone; its few remaining consumers (`debug.js`, `switchboard-sdk.js`) received inlined replacements. Theme management migrated from the global `Theme` object to the Preact SDK's `createTheme` module. SDK slimmed by removing 6 dead factory wrappers. ### Removed - `src/js/ui-primitives.js` (1,133 LOC) — `esc()`, `createComponentRegistry()`, `componentMixin()`, `Providers`, `Roles`, `showConfirm()`, `showPrompt()`, `openModal()`, `closeModal()`, `Theme`, render helpers. All consumers deleted or inlined. - `src/js/code-editor.js` (362 LOC) — tabbed CodeMirror 6 editor, zero consumers - `src/js/file-tree.js` (290 LOC) — workspace file browser widget, zero consumers - `src/js/user-menu.js` (206 LOC) — vanilla flyout menu; all surfaces use Preact `sw/shell/user-menu.js` - `src/js/app-state.js` (139 LOC) — global `window.App` state; Preact surfaces use local state hooks; `debug.js` state snapshot already guards with `typeof` ### Changed - `src/js/debug.js` — inlined `openModal()`, `closeModal()`, `showConfirm()`, `_escHtml()` (~44 LOC) to replace dependency on deleted `ui-primitives.js` - `src/js/switchboard-sdk.js` — removed 6 dead factory wrappers (`sw.notes()`, `sw.panels()`, `sw.fileTree()`, `sw.codeEditor()`, `sw.layout()`, `sw.userMenu()` + `_hydrateUserMenu()`); replaced global `Theme` with `import { createTheme } from './sw/sdk/theme.js'`; inlined `esc()` and `openModal`/`closeModal` helpers; net −213 LOC - `server/pages/templates/base.html` — removed 5 script tags (`app-state.js`, `ui-primitives.js`, `user-menu.js`, `file-tree.js`, `code-editor.js`); consolidated removal comments - `src/sw.js` — removed 5 entries from `SHELL_FILES` cache manifest ### Design Notes - **6 old JS files survive:** `sb.js` (debug modal onclick handlers), `events.js` (extension bridge), `switchboard-sdk.js` (extension compatibility), `debug.js` + `repl.js` (active tooling), `workflow-surfaces.js` (deferred to Preact rewrite). Targeted for removal as extensions migrate. - **`user-menu.css` kept:** extension surface template still renders server-side user-menu HTML; CSS provides styling for the placeholder. - **Cumulative scorched earth:** 49 files deleted, ~−17,710 lines across three passes (v0.37.10, v0.37.12, v0.37.13). --- ## [0.37.12] — 2026-03-22 ### Summary Scorched Earth II — second dead-code purge. 23 files deleted (~2,600 lines). All six core surfaces are confirmed Preact-only; old vanilla JS, CSS, and admin templates removed. Service worker cache manifest overhauled. ### Removed - `src/js/ui-format.js` — old markdown renderer (replaced by `sw/components/chat-pane/markdown.js`) - `src/js/virtual-scroll.js` — only consumer was deleted `chat.js` - `src/js/model-selector.js` — Preact ChatPane has its own `ModelSelector` - `src/js/drag-resize.js` — only consumer was deleted `PaneContainer` - `src/js/pages-splash.js` — login is Preact since v0.37.5 - `src/js/task-sidebar.js` — no template loads this - `src/js/workflow-api.js` — new SDK has `sw.api.workflows.*` - `src/js/workflow-queue.js` — references deleted `App.chats` - `src/js/workflow-monitor.js` — ES module export, never imported - `src/css/splash.css` — replaced by `sw-login.css` - `src/css/styles.css` — 13-line decomposition comment from v0.22.9 - `src/css/persona-kb.css` — old admin/settings UI - `src/css/notification-prefs.css` — old settings UI - `src/css/memory.css` — old admin/settings UI - `src/css/channel-models.css` — old chat autocomplete - `server/pages/templates/admin/` — 8 dead templates (overview, users, models, providers, settings, teams, roles, routing); admin is Preact since v0.37.6 ### Changed - `server/pages/templates/base.html` — removed 7 script/link tags: `splash.css`, `marked.min.js`, `purify.min.js`, `ui-format.js`, `virtual-scroll.js`, `model-selector.js`, `drag-resize.js`. `marked`/`purify` now loaded only by surfaces that need them (chat, notes). - `src/sw.js` — replaced entire `SHELL_FILES` array; removed 17 stale entries referencing files deleted in v0.37.10, added all `sw-*.css` files - `server/pages/pages.go` — removed `templates/admin/*.html` from `//go:embed` directive and `ParseFS` call ### Design Notes - **11 old JS files survive:** `sb.js`, `app-state.js`, `events.js`, `ui-primitives.js`, `user-menu.js`, `file-tree.js`, `code-editor.js`, `switchboard-sdk.js`, `debug.js`, `repl.js`, `workflow-surfaces.js`. These provide globals consumed by extension surfaces (`Events.on()`, `Theme.resolved()`, `sw.fileTree()`) and the debug modal (`sb.call()`). Targeted for removal when extensions migrate to Preact SDK. - **`workflow-surfaces.js` deferred:** still loaded by `workflow.html` standalone page; removed when workflow surfaces rebuilt (v0.37.13). --- ## [0.37.11] — 2026-03-22 ### Summary Notes surface built as full Preact surface, replacing the v0.37.9 template mount. Sidebar with folder tree, tag cloud, search, and UserMenu. NotesPane runs `standalone=false` — the surface sidebar owns filter controls. Cross-surface fixes: Menu primitive CSS was never loaded (now added to base.html), Avatar initials fixed for single-word names. ### New - `src/js/sw/surfaces/notes/index.js` — NotesSurface root, self-mounts at `#notes-mount` - `src/js/sw/surfaces/notes/use-workspace.js` — sidebar toggle + active note (sessionStorage) - `src/js/sw/surfaces/notes/use-sidebar.js` — folders, tags, search, WS live updates - `src/js/sw/surfaces/notes/sidebar.js` — search input, folder/tag sections, UserMenu footer - `src/js/sw/surfaces/notes/sidebar-folders.js` — collapsible folder tree with counts - `src/js/sw/surfaces/notes/sidebar-tags.js` — collapsible tag cloud with active state - `src/js/sw/surfaces/notes/notes-workspace.js` — workspace header + NotesPane - `src/css/sw-notes-surface.css` — surface layout (sidebar + workspace + mobile responsive) ### Changed - `src/js/sw/components/notes-pane/index.js` — handleRef expanded with `setFolder`, `setTagFilter`, `setSearchQuery`, `getFolder`, `getTagFilter`; threads `standalone` prop to NoteList - `src/js/sw/components/notes-pane/note-list.js` — `standalone=false` hides search row, folder dropdown, tag cloud (surface sidebar owns these) - `src/js/sw/primitives/avatar.js` — single-word names show first letter only ("admin" → "A" not "AD"); multi-word unchanged ("John Doe" → "JD") - `server/pages/templates/surfaces/notes.html` — full rewrite: crash catcher + `#notes-mount` + Preact boot (mirrors chat.html pattern) - `server/pages/templates/base.html` — added `sw-primitives.css` link (Menu primitive was unstyled on all surfaces); added `css-notes` conditional - `src/css/surfaces.css` — deleted `.surface-notes*` rules (9 lines, replaced by `sw-notes-surface.css`) ### Design Notes - **Sidebar ↔ NotesPane coordination:** write-only via handleRef. Sidebar sets folder/tag/search on the kit; kit reloads its own list. No bidirectional sync needed because `standalone=false` hides the kit's own filter controls. - **Menu primitive bug:** `sw-primitives.css` was never loaded in `base.html`. The Menu component (`sw-menu__item`) had no hover, no cursor, no background. Chat surface masked this by using its own `.sw-chat-surface__context-menu` styles. Fixed globally — all surfaces now get proper Menu styles. - **Kit enhancements deferred:** markdown toolbar, wikilink hover preview, breadcrumbs, split view, templates, slash commands, graph minimap all moved to v0.37.14 pane audit. ### Cumulative Layer Status | Layer | Version | Status | |-------|---------|--------| | Preact+htm vendor | v0.37.2 | ✅ | | Layer 0: Primitives | v0.37.11 | ✅ (Menu CSS fix, Avatar fix) | | Layer 1: SDK | v0.37.10 | ✅ (8 modules) | | Layer 1.5: ChatPane | v0.37.10 | ✅ (13 files) | | Layer 1.5: NotesPane | v0.37.11 | ✅ (10 files, standalone prop) | | Layer 2: Shell | v0.37.4 | ✅ (5 components) | | Surface: Login | v0.37.5 | ✅ | | Surface: Settings | v0.37.7 | ✅ | | Surface: Admin | v0.37.6 | ✅ | | Surface: Team Admin | v0.37.7 | ✅ | | Surface: Chat | v0.37.10 | ✅ | | Surface: Notes | v0.37.11 | ✅ | ## [0.37.10] — 2026-03-21 ### Summary Scorched earth rebuild of the Chat surface. The old 16-file imperative SPA (~11,500 lines of `app.js`, `chat.js`, `ui-core.js`, `projects-ui.js`, etc.) is replaced by a focused Preact surface (8 files) composing the ChatPane kit. ChatPane kit upgraded with error display, stop generation, regenerate, code block copy, markdown toolbar, emoji picker, and message pagination. Features that don't belong on the chat surface (projects, KB management, extensions, notifications) are deferred — each earns its way back as its own surface or shell-level feature. 32 files changed. +774 / −13,615. **Net: −12,841 lines.** ### New - **Chat Surface** (`src/js/sw/surfaces/chat/`) — 8 files: - `ChatSurface` root — sidebar + workspace + ToastContainer + DialogStack - `useWorkspace` — active conversation coordinator, sessionStorage restore - `useSidebar` — channels, chats, folders data; search filter; WS live updates; CRUD (rename, delete, move-to-folder, create folder) - `Sidebar` — search bar, "New Chat" button, collapsible Channels section, collapsible Chats section with folder grouping, context menus, desktop collapse toggle - `SidebarChannels` — DMs + named channels, unread badges - `SidebarChats` — personal AI chats, folder grouping, context menus (rename, delete, move to folder) - `ChatWorkspace` — workspace header (sidebar toggle, tools button) + ChatPane in `standalone=false` mode (surface manages navigation) - `ToolsPopup` — scrollable category-based tool toggles with persistence, `useTools` hook loads from API - **ChatPane Kit enhancements** (4 new components in `chat-pane/`): - `CodeBlock` — language badge + copy button, code block extraction from rendered markdown HTML - `MessageActions` — per-message toolbar: regenerate, copy text, delete. Appears on hover/focus - `MarkdownToolbar` — bold, italic, code, code block, link, bullet list, numbered list, heading, blockquote. Wraps selection with markdown syntax. Keyboard shortcuts: Ctrl+B, Ctrl+I, Ctrl+E - `EmojiPicker` — categorized grid (7 categories), search, recently used (localStorage). Inserts at cursor position - **ChatPane Kit upgrades** (6 modified files): - `index.js` — error banner rendered from `error` state, stop button wiring, new kit re-exports - `use-chat.js` — `regenerate(msgId)`, `deleteMessage(msgId)`, `loadMore()` pagination, `hasMore`/`loadingMore` state - `message-list.js` — "Load older messages" pagination button, scroll position preservation on prepend, ARIA `role="log"`, regenerate/delete wiring per message - `message-bubble.js` — CodeBlock rendering with copy+language badge, MessageActions toolbar (regenerate/copy/delete), relative timestamps - `message-input.js` — MarkdownToolbar, EmojiPicker, stop button (replaces send during streaming), ARIA labels, keyboard format shortcuts - `markdown.js` — `marked.setOptions()` with GFM+breaks, task list checkbox rendering via custom renderer - **UserMenu auto-surface-filtering** — reads `body[data-surface]`, auto- includes links to all other surfaces (Notes, extensions), filters out the current surface. Default `handleSelect` navigates via `location.href`. Every surface gets the same menu minus itself. - **`sw-chat-surface.css`** — sidebar + workspace flex layout, responsive mobile overlay, sidebar collapse, tools popup, context menus (~600 lines) ### Deleted **16 JS files (~11,500 lines):** - `src/js/app.js` (589) — SPA bootstrap, sidebar, init - `src/js/api.js` (995) — REST client, auth, token management - `src/js/chat.js` (1,344) — message rendering, streaming, CM6 input - `src/js/chat-pane.js` (160) — legacy ChatPane wrapper - `src/js/channel-models.js` (437) — channel model management UI - `src/js/extensions.js` (506) — extension panel, package management - `src/js/files.js` (857) — file upload/staging UI - `src/js/knowledge-ui.js` (556) — knowledge base toggle popup - `src/js/notifications.js` (431) — notification bell + dropdown - `src/js/pages.js` (349) — admin page rendering - `src/js/pane-container.js` (589) — split pane resize manager - `src/js/panels.js` (454) — side panel registration + lifecycle - `src/js/projects-ui.js` (2,090) — project sidebar section - `src/js/tokens.js` (167) — token count display - `src/js/tools-toggle.js` (245) — tools toggle popup - `src/js/ui-core.js` (1,699) — core UI: sidebar, messages, context menus **5 CSS files (~1,650 lines):** - `src/css/chat.css` (648) — old chat area, sidebar, workspace, input - `src/css/chat-pane.css` — legacy chat pane styles - `src/css/panels.css` — side panel styles - `src/css/pane-container.css` — split pane layout - `src/css/notifications.css` — notification bell + dropdown ### Changed - `chat.html` — rewritten from ~387-line SPA scaffold to ~50-line Preact boot (same pattern as settings/admin/team-admin surfaces) - `base.html` — removed `