diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26a9e0b..9474f3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5317 +1,57 @@
# Changelog
-## [0.38.5.0] — 2026-03-25
+All notable changes to Switchboard Core are documented here.
-### Summary
+## [Unreleased] — v0.1.0
-Git-board rewrite — library composition capstone. Rewrites git-board from
-a self-contained monolith into a library consumer of gitea-client, proving
-the full extension architecture end-to-end: lib.require(), connections,
-dependencies, multi-file Starlark, and connection type discovery. Includes
-5 platform bug fixes found during composition testing.
-
-### Changed
-
-- **git-board v0.2.0:** Rewrote Starlark backend to delegate all Gitea API
- work to gitea-client library via `lib.require("gitea-client")`. Removed
- `api.http` permission, platform abstraction, and per-user token settings.
- Added `connections.read` permission and `gitea-client >= 1.0.0` dependency.
- Surface JS: replaced TokenSetup with ConnectionSetup screen.
- (~130 lines, down from ~329)
-- **gitea-client v1.0.1:** Added missing fields to `get_issues()` (created_at,
- updated_at, html_url) and `get_prs()` (created_at, html_url, mergeable).
- Re-exported loaded sub-module functions via explicit global assignment for
- lib.require() compatibility.
-
-### Fixed (platform bugs)
-
-- **ext_api.go:** Route handler no longer requires `api.http` for all packages
- with API routes. Consumer packages that delegate HTTP to libraries don't
- need `api.http` themselves.
-- **packages.go:** `InstallPackage` handler now calls `SyncManifestPermissions`
- so permission rows are created on package install (was only in the legacy
- `AdminInstallExtension` handler).
-- **runner.go:** Package loader for `load()` sub-modules now injects the `json`
- module into predeclared scope, matching ExecWithLoader behavior.
-- **connection_resolver.go:** Added panic recovery around `vault.Decrypt` to
- prevent goroutine crashes from invalid nonce lengths after vault key rotation.
-
-### Added
-
-- **SDK test runner:** `git-board.js` domain (14 tests) — validates multi-file
- library install, connection type registration, consumer dependency, tool
- registration, consumers list, uninstall protection, connection CRUD, full
- cleanup cycle.
-
-## [0.38.2.0] — 2026-03-25
-
-### Summary
-
-Library Packages. Reusable Starlark libraries that extensions can declare
-as dependencies and load at runtime via `lib.require()`. Libraries export
-functions, run with their own permission context, and are protected from
-uninstall while active consumers exist. Includes a `test-tool` admin
-endpoint for invoking extension tool calls without the AI chat loop.
-
-### Added
-
-- **Schema:** `ext_dependencies` table with `(consumer_id, library_id)`
- composite PK, `version_spec` and `resolved_ver` columns. SQLite
- migration also rebuilds `packages` table to add `'library'` to the
- type CHECK constraint (SQLite cannot ALTER constraints).
- (`server/database/migrations/023_ext_dependencies.sql`,
- `server/database/migrations/sqlite/023_ext_dependencies.sql`)
-- **Model:** `ExtDependency` struct with `ConsumerID`, `LibraryID`,
- `VersionSpec`, `ResolvedVer`.
- (`server/models/ext_dependency.go`)
-- **Store:** `DependencyStore` interface — `Create`, `DeleteByConsumer`,
- `ListByConsumer`, `ListByLibrary`, `ListAll`. Postgres and SQLite
- implementations.
- (`server/store/interfaces.go`, `postgres/ext_dependency.go`,
- `sqlite/ext_dependency.go`)
-- **Handlers:** Dependency admin endpoints:
- - `GET /admin/packages/:id/dependencies` — list consumer's deps
- - `GET /admin/packages/:id/consumers` — list library's consumers
- - `GET /admin/dependencies` — full dependency graph
- (`server/handlers/dependencies.go`)
-- **Test-tool endpoint:** `POST /admin/packages/:id/test-tool` — invokes
- a starlark extension's `on_tool_call` entry point directly for testing.
- (`server/handlers/packages.go`)
-- **Starlark module:** `lib.require(id)` — loads a declared library
- dependency, executes its script with library-scoped permissions,
- extracts manifest exports, freezes into a cached struct. Per-invocation
- cache and cycle detection.
- (`server/sandbox/lib_module.go`)
-- **Install validation:** Library packages require `exports` array,
- must not have `tools`, `pipes`, or `route`. Consumer `dependencies`
- map validated against installed active libraries. Dependency records
- created on install, cleaned up on consumer uninstall. Libraries with
- active consumers return 409 on delete.
- (`server/handlers/packages.go`)
-- **SDK:** `sw.api.admin.packages.dependencies(id)`,
- `sw.api.admin.packages.consumers(id)` domain methods.
- (`src/js/sw/sdk/api-domains.js`)
-- **ICD:** Extension dependencies section with all endpoint specs.
- (`docs/ICD/extensions.md`)
-- **OpenAPI:** Dependency endpoint schemas and `test-tool` endpoint.
- (`server/static/openapi.yaml`)
-- **SDK test runner:** `dependencies` domain — 8 tests covering library
- install, dependency creation, consumer listing, uninstall protection,
- cleanup, and library deletion.
- (`packages/sdk-test-runner/js/domains/dependencies.js`)
-
-### Changed
-
-- **Runner:** `ExecPackage` creates a `libContext` per invocation and
- passes it through `buildModulesWithLibCtx`. The `lib` module is always
- injected (no permission required). Multi-file `packageLoader` reused
- for library scripts.
- (`server/sandbox/runner.go`)
-- **Packages handler:** Install flow extended with dependency resolution
- and `ext_dependencies` record creation. Delete flow checks for active
- consumers before allowing library removal.
- (`server/handlers/packages.go`)
-
-### Design Notes
-
-- `lib.require()` was originally `lib.load()` but `load` is a reserved
- keyword in Starlark (used for `load("module.star", "symbol")`). Renamed
- to `require` to avoid parser conflicts.
-- Libraries run with their **own** permission context, not the consumer's.
- A consumer without `api.http` can still call a library that uses
- `http.get()` — the library's permissions are evaluated independently.
-- The `test-tool` endpoint enables E2E testing of Starlark extensions
- without a configured LLM provider.
-
-### Files
-
-- **8 created:** `lib_module.go`, `dependencies.go`, `ext_dependency.go`
- (model), `ext_dependency.go` (pg), `ext_dependency.go` (sqlite),
- `023_ext_dependencies.sql` (×2), `dependencies.js` (SDK runner)
-- **11 modified:** `packages.go`, `runner.go`, `main.go`, `interfaces.go`,
- `stores.go` (×2), `api-domains.js`, `openapi.yaml`, `extensions.md`,
- `packages.js`, `main.js` (SDK runner)
-- **+1,141 lines** (737 new files + 404 modified)
-
-## [0.38.1.0] — 2026-03-25
-
-### Summary
-
-Extension Connections. Scoped credential management for extensions that
-integrate with external services. Same scope/resolution pattern as LLM
-providers (personal → team → global), sharable across packages.
-
-### Added
-
-- **Schema:** `ext_connections` table with `(type, scope, owner_id, name)`
- unique constraint. Secret fields encrypted at rest using vault pattern.
- (`server/database/migrations/022_ext_connections.sql`)
-- **Store:** `ConnectionStore` interface with CRUD, scoped queries, and
- resolution chain (personal → team → global).
- (`server/store/interfaces.go`, `postgres/ext_connection.go`, `sqlite/ext_connection.go`)
-- **Handlers:** Three scope tiers of REST endpoints:
- - Personal: `GET/POST /connections`, `GET/PUT/DELETE /connections/:id`, `GET /connections/resolve`
- - Team: `GET/POST /teams/:teamId/connections`, `PUT/DELETE /teams/:teamId/connections/:id`
- - Admin: `GET/POST /admin/connections`, `PUT/DELETE /admin/connections/:id`
- (`server/handlers/connections.go`, `team_connections.go`, `admin_connections.go`)
-- **Starlark module:** `connections.get(type)`, `connections.get(type, name=)`,
- `connections.list(type)` — gated by `connections.read` permission.
- (`server/sandbox/connections_module.go`)
-- **UI:** Connection management sections in Admin, Team Admin, and Settings
- surfaces with dynamic form rendering from manifest field schemas.
- (`src/js/sw/surfaces/admin/connections.js`, `team-admin/connections.js`, `settings/connections.js`)
-- **SDK:** `sw.api.connections.*`, `sw.api.teams.{create,update,delete}Connection()`,
- `sw.api.admin.connections.*` domain methods.
- (`src/js/sw/sdk/api-domains.js`)
-- **ICD:** Extension connections section with all endpoint specs.
- (`docs/ICD/extensions.md`)
-- **OpenAPI:** Connection endpoint schemas (personal, team, admin, resolve).
- (`server/static/openapi.yaml`)
-- **SDK test runner:** `connections` domain — CRUD + resolve chain tests.
- (`packages/sdk-test-runner/js/domains/connections.js`)
-
-## [0.38.0.0] — 2026-03-25
-
-### Summary
-
-Multi-file Starlark packages. Promotes Starlark scripts from a single
-inline blob in the DB manifest to a proper file tree with `load()` support.
-Prerequisite for library packages (v0.38.2) and large extensions.
-
-### Changed
-
-- **Extraction:** `extractableRelPath()` now extracts `star/` directories
- and bare `*.star` files alongside `js/`, `css/`, `assets/`. Starlark
- scripts land on disk at install time instead of being serialized into
- the manifest JSONB.
- (`server/handlers/packages.go`)
-- **Sandbox:** New `ExecWithLoader()` accepts an optional `LoadFunc` for
- resolving `load()` statements. `Exec()` is now a thin wrapper that
- passes a nil loader (backward compatible).
- (`server/sandbox/sandbox.go`)
-- **Runner:** Disk-first script loading via `loadScript()` — reads from
- `{packagesDir}/{pkgID}/script.star` (or custom `entry_point`), falls
- back to legacy `_starlark_script` manifest field. Package-scoped
- `packageLoader()` enables `load()` within a package's directory with
- path traversal protection, `.star`-only enforcement, and circular
- dependency detection.
- (`server/sandbox/runner.go`)
-- **Wiring:** `SetPackagesDir()` called at startup with
- `cfg.StoragePath + "/packages"`. Build script includes `star/` in
- archives.
- (`server/main.go`, `packages/build.sh`)
-
-### Added
-
-- **Entry point validation:** Starlark-tier packages must include
- `script.star` (or the manifest's `entry_point` value) in the archive.
- Returns 400 if missing.
-- **`entry_point` manifest field:** Optional override for the default
- entry script name (`script.star`).
-- **SDK test runner:** New `packages` domain with 6 tests covering
- install validation (missing entry point, with star/, custom entry_point,
- browser-tier bypass).
- (`packages/sdk-test-runner/js/domains/packages.js`)
+Forked from chat-switchboard v0.38.5. Gutted to a pure extension platform.
### Removed
-- **`_starlark_script` injection:** The installer no longer reads
- `script.star` from the archive and stuffs it into the manifest JSON.
- Scripts are loaded from disk at runtime. Existing packages with
- `_starlark_script` in their DB row continue to work (legacy fallback).
-
-### Documentation
-
-- **ICD:** Multi-file Starlark section added to `extensions.md` with
- archive structure, `load()` constraints, and error codes.
-- **OpenAPI:** Install endpoint description updated with entry point
- validation and `star/` directory extraction.
-- **Surfaces ICD:** Archive format updated to include `script.star` and
- `star/` entries.
-
----
-
-## [0.37.19.0] — 2026-03-24
-
-### Summary
-
-Tag release — "UI Complete." Closes all remaining code review items from
-FE-REWRITE-REVIEW-0.37.14.md. Adds client-side RBAC gates (`sw.can()`) to
-surface action buttons, migrates settings policy reads from `__PAGE_DATA__`
-to `sw.auth.policies`, removes dead `__USER__` / `__PAGE_DATA__` template
-injections, and moves shell-coupled `_getScale()` into the SDK. Light mode
-CSS audit and dead code sweep confirm no outstanding issues.
-
-### Changed
-
-- **sw.can() RBAC gates (CR P2-1):** Channel/group creation buttons in chat
- dashboard and sidebar gated behind `sw.can('channel.create')`. Persona
- create/edit/delete gated behind `sw.can('persona.create')` /
- `sw.can('persona.manage')`. Knowledge base create/upload/delete gated
- behind `sw.can('kb.create')` / `sw.can('kb.write')`.
- (`chat-workspace.js`, `sidebar.js`, `personas.js`, `knowledge.js`)
-- **Settings → sw.auth.policies (CR P2-4):** Settings surface reads BYOK and
- persona policies from `sw.auth.policies` (populated at SDK boot via
- `/api/v1/profile/permissions`) instead of `window.__PAGE_DATA__`. Listens
- for `auth.permissions.changed` event to react to policy updates.
- (`settings/index.js`)
-- **_getScale → sw.shell.getScale() (CR P3-3):** Scale detection for CSS zoom
- compensation moved from sidebar-chats.js local function into SDK shell
- namespace. Explicit coupling replaces implicit `#surfaceInner` DOM reach.
- (`sdk/index.js`, `sidebar-chats.js`)
-- **SDK version:** `sw._sdk` updated to `'0.37.19'`.
-
-### Removed
-
-- **__USER__ / __PAGE_DATA__ injection (CR P2-4):** Removed `window.__USER__`
- and `window.__PAGE_DATA__` global injections from `base.html`. SDK boot
- populates `sw.auth.user` and `sw.auth.policies` from API. Extension packages
- updated to use SDK (`editor`, `hello-dashboard`, `icd-test-runner`).
- (`base.html`, `loaders.go`, `EXTENSION-SURFACES.md`)
-- **SettingsPageData policy fields:** `BYOKEnabled` and `UserPersonasEnabled`
- removed from Go struct (no longer injected via template). (`loaders.go`)
-
-### Documentation
-
-- **CR P3-17:** Added comment documenting intentional raw DOM usage in notes
- markdown wikilink processing (`markdown.js`).
-- **CR P3-19:** Added comment documenting keyboard shortcut DOM presence check
- pattern with future guidance (`use-notes.js`).
-- **EXTENSION-SURFACES.md:** Updated `__USER__` references to `sw.auth.user`.
-
----
-
-## [0.37.18.0] — 2026-03-24
-
-### Summary
-
-Debug/Model surface rebuild + workspace bridge. Debug modal converted from
-673 lines of imperative DOM JS to a Preact component tree (CR P2-5). User
-default workspace auto-created on first access. Tool outputs auto-save file
-refs linked to assistant messages. "Save to workspace" action on chat code
-blocks. Model selector shows provider health dots. Provider "Test Connection"
-buttons added to both BYOK and admin UIs.
-
-### Added
-
-- **Debug modal Preact rebuild:** Engine singleton (`debugEngine`) with
- subscribe() pattern for reactive updates. Component tree: ConsoleTab,
- NetworkTab, StateTab, ReplTab, DebugBadge. `sw-debug.css` extracted from
- `modals.css`. `debug.js` reduced from 673 to ~40 lines (thin bootstrap).
- `repl.js` absorbed into `repl-tab.js`. (`src/js/sw/components/debug/`)
-- **Default user workspace:** `GET /workspaces/default` auto-creates a
- "My Files" workspace per user on first access. Idempotent. Route wired
- before `:id` param. SDK: `sw.api.workspaces.getDefault()`.
- (`server/handlers/workspaces.go`, `server/main.go`)
-- **tool_output auto-save:** When `workspace_write` or `workspace_patch`
- tools succeed during completion, a file ref with `origin=tool_output` is
- recorded in the `files` table, linked to the assistant message via
- `message_id`. (`server/handlers/tool_loop.go`, `completion.go`)
-- **Origin filter on channel files:** `GET /channels/:id/files?origin=`
- query param. SDK: `sw.api.channels.files(id, {origin})`.
- (`server/handlers/files.go`)
-- **Save-to-Workspace bridge:** Save button on assistant messages with code
- blocks. Saves to user's default workspace with auto-generated filenames.
- `guessExtension()` utility (37 language mappings). (`message-actions.js`,
- `message-bubble.js`, `code-block.js`)
-- **Model selector health dots:** Provider health status (green/yellow/red)
- shown next to model names in chat selector. Admin-only, graceful degrade
- for non-admin. (`model-selector.js`)
-- **Provider test buttons:** "Test Connection" in Settings BYOK and "Test"
- in Admin providers. Calls `fetchModels()` and shows success/failure toast.
- (`settings/providers.js`, `admin/providers.js`)
-
-### Changed
-
-- `modals.css`: Debug-specific rules moved to `sw-debug.css` (~22 rules).
-- `base.html`: 46-line debug modal HTML block replaced by `
`.
-- `sw.js`: Service worker cache list updated (repl.js removed, sw-debug.css added).
-- `LoopResult` struct: new `FileRefs` field for tool file output tracking.
-- `channels.files` SDK method: now accepts optional opts for query params.
-
-### Removed
-
-- `src/js/repl.js` (527 lines) — absorbed into Preact `repl-tab.js`.
-
-### ICD / OpenAPI / SDK Test Runner
-
-- ICD: `GET /workspaces/default` documented; tool_output creation behavior updated.
-- OpenAPI: `/api/v1/workspaces/default` endpoint added.
-- SDK runner: 2 workspace tests (getDefault + idempotent), 1 channel files origin filter test.
-
-## [0.37.17.0] — 2026-03-24
-
-### Summary
-
-Workspaces — workspace-first file storage for projects. Project files route
-through the workspace FS subsystem (auto-created on first upload) instead of
-the flat objStore path. Tree browser UI with nested folders, archive support
-(zip/tar.gz upload and download), file actions (download, delete, mkdir), and
-upload improvements (progress counter, archive detection, quota errors).
-
-Architecture decision: `files` table + objStore = ephemeral message attachments;
-Workspace FS = persistent file collections (tree, dirs, archive, quota, indexing).
-"Save to workspace" bridge from chat files deferred to v0.37.18.
-
-Also: extension track continuation scheduled as v0.39.x in roadmap, two new
-design docs committed (multi-file Starlark, extension connections & libraries).
-
-### Added
-
-- **Workspace-backed project files:** `ensureProjectWorkspace()` auto-creates a
- workspace (`owner_type=project`) on first file upload, sets `project.workspace_id`.
- All project file operations route through workspace FS instead of objStore.
- (`server/handlers/files.go`)
-- **File download:** `GET /projects/:id/files/download?path=` streams raw file
- content with `Content-Disposition: attachment`. (`server/handlers/files.go`)
-- **File delete:** `DELETE /projects/:id/files?path=` with optional `recursive`
- param for directories. (`server/handlers/files.go`)
-- **Create directory:** `POST /projects/:id/files/mkdir` accepts path via JSON
- body or query param. (`server/handlers/files.go`)
-- **Archive upload:** `POST /projects/:id/archive/upload` extracts .zip/.tar.gz
- into project workspace. Returns `files_extracted` count.
- (`server/handlers/files.go`)
-- **Archive download:** `GET /projects/:id/archive/download?format=zip` bundles
- all project files into a zip/tar.gz. (`server/handlers/files.go`)
-- **File browser UI:** Tree browser with nested folders (expand/collapse),
- type icons, size display, on-hover delete button. Replaces the flat file list
- from v0.37.16. (`src/js/sw/surfaces/projects/detail.js`)
-- **File action bar:** "New folder" and "Download all" buttons above the file
- tree when files exist. (`detail.js`)
-- **Upload improvements:** Progress counter ("Uploading 3 of 7…"), archive
- detection (`.zip`/`.tar.gz` → confirm extract dialog), specific error
- messages (413 = quota exceeded). (`detail.js`)
-- **SDK methods:** `deleteFile`, `mkdir`, `uploadArchive` added to
- `sw.api.projects` domain. `files()` and `uploadFile()` updated to support
- path param. (`src/js/sw/sdk/api-domains.js`)
-- **File browser CSS:** 120 lines — file-row, file-chevron, file-icon,
- file-name, file-meta, file-delete, dropzone, file-actions-bar.
- (`src/css/sw-projects-surface.css`)
-- **DESIGN-EXT-CONNECTIONS-LIBRARIES.md:** Extension connections (scoped
- credentials) and library packages (shared code + data via `lib.load()`).
- Three implementation phases. (`docs/`)
-- **Extension track v0.39.x:** Roadmap updated — v0.39.0 multi-file Starlark,
- v0.39.1 connections, v0.39.2 libraries, v0.39.3 full composition.
- (`docs/ROADMAP.md`)
-
-### Changed
-
-- **Project file list response:** Now returns `WorkspaceFile` objects (with
- `path`, `is_directory`, `content_type`, `size_bytes`) instead of `File` model
- objects. `GET /projects/:id/files` supports `?path=` and `?recursive=` params.
-- **FileHandler constructor:** Gains `SetWorkspaceFS()` method for workspace
- injection. Project file routes use dedicated `projFileH` instance with wfs
- attached. (`server/main.go`)
-- **ICD updated:** `docs/ICD/projects.md` — expanded Project Files section with
- all 7 endpoints, request/response schemas, error codes.
-- **OpenAPI updated:** `server/static/openapi.yaml` — 5 new paths for project
- file operations (download, delete, mkdir, archive upload/download).
-
-### Known Limitations
-
-- **User default workspace:** Not yet implemented. Personal "My Files" deferred
- to v0.37.18.
-- **Tool output persistence:** `origin=tool_output` auto-save for LLM-generated
- artifacts deferred to v0.37.18.
-- **Save to workspace bridge:** "Save" action to promote ephemeral chat files
- to workspace storage deferred to v0.37.18.
-- **Workspace unique constraint:** Race guard on concurrent workspace creation
- relies on DB error handling (re-read on duplicate key). Migration 014 for
- explicit `UNIQUE(owner_type, owner_id)` not yet added.
-
----
-
-## [0.37.16.0] — 2026-03-24
-
-### Summary
-
-Projects Surface. Card-grid list + two-column detail view with inline ChatPane,
-context menu (color/archive/delete), sidebar sections (description, instructions,
-KBs, notes, files), star toggle, deep-linking, and search/sort. UserMenu in header
-on both views. Backend was already complete (16 protected + 2 admin endpoints,
-18 SDK methods); this changeset delivers the full Preact frontend.
-
-### Added
-
-- **Projects list view:** Card grid with search filter, activity/name sort,
- "+ New project" via `sw.prompt` dialog, UserMenu in header left-of-title.
- (`src/js/sw/surfaces/projects/list.js`, `src/css/sw-projects-surface.css`)
-- **Projects detail view:** Two-column layout — left panel for conversations
- (inline ChatPane, "+ New" channel creation, channel list with back nav),
- right sidebar for description/instructions textareas with save, collapsible
- Knowledge Bases/Notes/Files sections with "+" picker dropdowns.
- (`src/js/sw/surfaces/projects/detail.js`)
-- **Context menu:** "..." button opens dropdown with Rename, 8 color swatches,
- Archive/Unarchive toggle, Delete with confirm dialog. All actions persist
- via `PUT /api/v1/projects/:id`. (`detail.js`)
-- **Star toggle:** Optimistic ☆↔★ toggle, persists in `settings.starred`.
- (`detail.js`)
-- **Deep-linking:** `/projects/:id` loads detail view directly via
- `window.__PROJECT_ID__` template injection. Invalid IDs gracefully fall
- back to list view. (`src/js/sw/surfaces/projects/index.js`,
- `server/pages/loaders.go`, `server/pages/templates/surfaces/projects.html`)
-- **Surface registration:** `/projects` route with `:id` param, nginx proxy,
- docker-entrypoint FE route, conditional CSS/JS loading in `base.html`.
- (`server/pages/pages.go`, `nginx.conf`, `docker-entrypoint-fe.sh`,
- `server/pages/templates/base.html`)
-
-### Fixed
-
-- **Picker section expand:** `openPicker()` now auto-expands the collapsed
- section when "+" is clicked, so the picker dropdown is visible without
- manually toggling the chevron first. (`detail.js`)
-
-### Changed
-
-- **UserMenu in header (list view):** Moved from bottom footer to header row,
- left of "Projects" title. Consistent with detail view placement. Removed
- `.sw-projects__list-footer` CSS class. (`list.js`, `sw-projects-surface.css`)
-
-### Known Limitations
-
-- **File upload:** UI is wired (dropzone + click handler) but backend returns
- "failed to save file metadata" — requires workspace storage layer. File
- upload (archive upload/download) is required for MVP; deferred to v0.37.17
- (Workspaces). Git integration is optional/post-MVP.
-- **Conversation names:** Channel list shows raw UUID instead of friendly name
- (channels created as type `direct` have no name field).
-
----
-
-## [0.37.15.0] — 2026-03-23
-
-### Summary
-
-Workflow Ownership & Lifecycle (CS1–CS5). Adds instance cancel with assignment
-cascade, assignment unclaim/reassign/cancel operations, full FE API domain
-wiring for stage CRUD and assignments, team-admin workflows rewrite with
-tabbed layout (Workflows + Stage Editor | Assignments Queue | Instance Monitor),
-and settings assignments view replacing the read-only workflow list.
-
-### Added
-
-- **Instance cancel:** `POST /channels/:id/workflow/cancel` sets
- `workflow_status='cancelled'` and cascades to all open assignments. Auth:
- instance owner, team admin, or global admin. Team-scoped variant at
- `POST /teams/:teamId/workflows/monitor/instances/:channelId/cancel`.
- (`server/handlers/workflow_instances.go`, `server/store/*/channel.go`)
-- **Assignment unclaim:** `POST /workflow-assignments/:id/unclaim` returns
- claimed assignment to unassigned. Auth: claimer or team admin.
- (`server/handlers/workflow_assignments.go`, `server/store/*/workflows.go`)
-- **Assignment reassign:** `POST /workflow-assignments/:id/reassign` changes
- `assigned_to` on claimed assignment. Auth: team admin.
- (`server/handlers/workflow_assignments.go`, `server/store/*/workflows.go`)
-- **Assignment cancel:** `POST /workflow-assignments/:id/cancel` cancels a
- single assignment. Auth: team admin.
- (`server/handlers/workflow_assignments.go`, `server/store/*/workflows.go`)
-- **FE API domains:** `workflowAssignments` domain (mine, claim, unclaim,
- complete, reassign, cancel, comment). Team domain additions: assignments,
- workflowInstances, cancelWorkflowInstance, stage CRUD (workflowStages,
- createWorkflowStage, updateWorkflowStage, deleteWorkflowStage,
- reorderWorkflowStages). (`src/js/sw/sdk/api-domains.js`)
-- **Team-admin workflows tabs:** Tabbed layout (Workflows | Assignments |
- Monitor). Workflows tab includes inline stage editor with add/edit/delete.
- Assignments tab shows claimed + available queue with claim/release/complete
- actions and WS live updates. Monitor tab shows active instances with cancel.
- (`src/js/sw/surfaces/team-admin/workflows.js`)
-- **Settings assignments:** Replaces read-only workflow list with personal
- assignment queue across all teams. Shows claimed and available assignments
- with claim/release/open/complete actions.
- (`src/js/sw/surfaces/settings/workflows.js`)
-
-### Changed
-
-- Settings sidebar label "Workflows" → "Assignments".
- (`src/js/sw/surfaces/settings/index.js`)
-
----
-
-## [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 `
-```
-
-Application files continue to load as `
-
-
-
- ... platform scripts ...
- ← YOUR SCRIPT
-