This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/JS-DEPENDENCY-AUDIT.md
2026-03-14 12:30:57 +00:00

13 KiB
Raw Blame History

Frontend JS Dependency Audit

Version: v0.28.3 cs2 Date: 2026-03-13 Purpose: Map every global, cross-file dependency, and init sequence to prepare for module extraction.


Summary

Metric Value
JS files 47
Total lines 25,056
Total bytes 1,103,572 (~1.1 MB)
Top-level globals (original) 431
IIFE-wrapped files 47 (all)
Explicit window.* exports ~215
Functions privatized ~168
Implicit globals remaining 0
Vendor libs 3 (marked.min.js, purify.min.js, codemirror.bundle.js)
Inline onclick handlers (templates) ~50 unique functions
Dynamic onclick in JS (innerHTML) 143 total occurrences

Architecture: IIFE Modules (Post-Decomposition)

No module system (no ES modules, no bundler, no AMD). Every file is a <script> tag loaded in dependency order. All 47 files are now wrapped in IIFEs with explicit window.* exports:

(function() {
'use strict';
// ... all code ...
window.MyGlobal = MyGlobal;
})();

Phase 1 complete. Zero implicit globals remain. ~168 functions privatized. The next phase is onclick → addEventListener migration (143 dynamic handlers in JS innerHTML + ~50 in Go templates), which is the prerequisite for ES module conversion.

IIFE Files

File Clean? Leaks
admin-handlers.js None (all via inline onclick from globals)
admin-scaffold.js None
editor-surface.js None
knowledge-ui.js None
pages-splash.js None
task-admin.js window._loadAdminTasks
task-settings.js window._createFromTemplate, window._loadSettingsTasks
task-sidebar.js window.TaskSidebar
tools-toggle.js None
workflow-admin.js 5 functions (_loadAdminWorkflows, _wfCreate, _wfOpen, _wfEditStage, _wfDeleteStage)
workflow-api.js None (registers on App)
workflow-queue.js window.WorkflowQueue

Script Load Order

base.html (shared — every surface)

 1. app-state.js        → const App = { ... }
 2. api.js              → const API = { ... }
 3. (inline)            → window.__BASE__, auth bootstrap
 4. events.js           → const Events = { ... }
 5. ui-primitives.js    → const UI = { ... }
 6. vendor/marked.min.js
 7. vendor/purify.min.js
 8. ui-format.js        → formatMessage(), toggleCodeCollapse(), etc.
 9. ui-core.js          → renderChatList(), renderMessages(), etc.
10. pages.js            → const Pages = { ... }
11. user-menu.js        → const UserMenu = { ... }
12. model-selector.js   → const ModelSelector = { ... }
13. file-tree.js        → const FileTree = { ... }
14. code-editor.js      → const CodeEditor = { ... }
15. note-editor.js      → const NoteEditor = { ... }
16. drag-resize.js      → const DragResize = { ... }
17. pane-container.js   → const PaneContainer = { ... }
18. (inline)            → Theme.init()
19. surfaces/{surface}/js/main.js  → surface CSS + scaffold

chat.html (25 additional scripts + 1 vendor)

    vendor/codemirror/codemirror.bundle.js → window.CM (optional, onerror fallback)
20. extensions.js       → const Extensions = { ... }
21. panels.js           → const PanelRegistry = { ... }
22. ui-settings.js      → settings rendering (bare globals)
23. ui-admin.js         → admin rendering (bare globals)
24. tokens.js           → token counting (bare globals)
25. notes.js            → notes UI (bare globals)
26. note-graph.js       → graph visualization (bare globals)
27. files.js            → file upload/management (bare globals)
28. tools-toggle.js     → tool enable/disable (IIFE)
29. knowledge-ui.js     → KB picker (IIFE)
30. memory-ui.js        → memory panel (bare globals)
31. persona-kb.js       → persona KB bindings (bare globals)
32. projects-ui.js      → project management (bare globals, 78 top-level decls)
33. channel-models.js   → const ChannelModels = { ... }
34. notification-prefs.js → notification preferences (bare globals)
35. notifications.js    → const Notifications = { ... }
36. chat.js             → const ChatInput = { ... } + 29 top-level functions
37. settings-handlers.js → settings form handlers (bare globals, 24 decls)
38. admin-handlers.js   → admin form handlers (IIFE, 40 internal functions)
39. workflow-api.js     → workflow REST helpers (IIFE)
40. workflow-admin.js   → workflow admin UI (IIFE, 5 window.* leaks)
41. workflow-queue.js   → workflow queue sidebar (IIFE, window.WorkflowQueue)
42. task-sidebar.js     → task sidebar (IIFE, window.TaskSidebar)
43. app.js              → init(), startApp(), event listeners
44. debug.js            → debug console (bare globals)
45. repl.js             → REPL (bare globals)

admin.html (14 additional)

Loads: ui-settings, ui-admin, admin-handlers, settings-handlers, knowledge-ui, persona-kb, memory-ui, notifications, files, admin-scaffold, workflow-api, workflow-admin, task-admin, admin-surfaces.

notes.html (14 additional)

Loads: chat, files, channel-models, tokens, extensions, notes, note-graph, knowledge-ui, persona-kb, memory-ui, notifications, panels, projects-ui, app.

settings.html (9 additional)

Loads: ui-settings, settings-handlers, task-settings, knowledge-ui, persona-kb, memory-ui, notifications, notification-prefs, channel-models.

editor.html (4 additional + 1 vendor)

Loads: vendor/codemirror, chat-pane, editor-surface, app. Lightest surface — fewest dependencies.


Core Globals (Dependency Roots)

These are referenced by 10+ other files. They form the "root set" that must be extracted first.

Global Defined in Referenced by Role
App app-state.js 20 files State container (chats, models, user, settings, presence)
API api.js 36 files REST client (all HTTP calls)
UI ui-core.js 32 files DOM helpers (toast, confirm, modal, sidebar, theme)
Events events.js 9 files Pub/sub event bus (WebSocket bridge)

Secondary Globals (39 references)

Global Defined in Referenced by Role
Pages pages.js Templates + 3 files Page-level actions (login, admin forms)
ChannelModels channel-models.js 4 files Model roster per channel
ChatInput chat.js 3 files Message input state + send
Notifications notifications.js Templates + 2 files Bell dropdown, badge count
ChatPane chat-pane.js 3 files Embedded chat component (editor)
CM vendor/codemirror.bundle.js 5 files CodeMirror 6 editor (optional, graceful fallback)
PanelRegistry panels.js Templates + 1 file Side panel management

Leaf Globals (12 references, mostly self-contained)

ModelSelector, FileTree, CodeEditor, NoteEditor, DragResize, PaneContainer, UserMenu, WorkflowQueue, TaskSidebar, Extensions.


Inline Handler Problem

143 onclick= patterns in JS files (innerHTML-generated HTML) plus ~50 in Go templates. These reference bare globals that must remain on window or the handlers break. This is the primary blocker for ES module migration.

Top offenders (dynamic onclick in JS):

File Count Examples
ui-admin.js 28 Admin list row actions
projects-ui.js 26 Project CRUD, channel/KB/note associations
ui-core.js 25 Chat list, sidebar, context menus
ui-format.js 10 Code block copy/preview/download
ui-settings.js 8 Settings form toggles
notifications.js 8 Notification row actions

Template onclick (must remain global):

UI.toggleSidebar, UI.toggleSidebarSection, UI.switchTeamTab, Notifications.toggleDropdown, PanelRegistry.toggle, PanelRegistry.closeAll, Pages.doLogin, Pages.saveSettings, Pages.saveProvider, Pages.saveTeam, handleLogin, handleRegister, switchAuthTab, newChat, newFolder, newChannelOrDM, sendMessage, createProject, closeLightbox, toggleSidePanelFullscreen, plus ~15 more Pages.* admin form handlers.


Cross-File Call Graph (Simplified)

app-state.js (App)
  ↑ read/write by 20 files
  │
api.js (API)
  ↑ called by 36 files
  │
events.js (Events)
  ↑ subscribed by 9 files
  ├── chat.js (typing, message.created, presence)
  ├── notifications.js (notification.new/read)
  ├── extensions.js (tool.call/result)
  ├── repl.js (debug events)
  └── app.js (role.fallback banner)
  │
ui-primitives.js (UI)
  ↑ called by 32 files
  ├── toast(), confirm(), modal()
  ├── toggleSidebar(), toggleSidebarSection()
  └── theme, kbd shortcuts
  │
ui-format.js (formatMessage, etc.)
  ↑ called by ui-core.js, chat.js, notes.js, projects-ui.js
  ├── depends on: marked.min.js, purify.min.js
  │
ui-core.js (renderChatList, renderMessages, etc.)
  ↑ called by chat.js, app.js, projects-ui.js
  ├── depends on: App, API, UI, ui-format
  │
chat.js (ChatInput, sendMessage, selectChat, loadChats)
  ↑ called by app.js, templates
  ├── depends on: App, API, Events, UI, ui-core, ui-format,
  │               ChannelModels, tokens, files
  │
app.js (init, startApp)
  ↑ entry point — called by inline <script> in base.html
  ├── depends on: everything above + surface-specific modules

Decomposition Strategy

Phase 1: Extract Core Four (no bundler required)

Move App, API, Events, UI to a pattern where they're defined as proper singletons with explicit exports. No ES modules yet — just clean up the global registration so each file has a single window.X export with a documented interface.

Why no bundler yet: 143 dynamic onclick handlers + 50 template onclick handlers require globals on window. A bundler would need either (a) a global shim layer or (b) converting all handlers to addEventListener. Option (b) is the right answer but it's ~200 call sites across 16 files + 10 templates — too much churn for one changeset.

Phase 2: onclick → addEventListener migration

Convert dynamic HTML generation from:

`<button onclick="deleteItem('${id}')">Delete</button>`

to:

const btn = document.createElement('button');
btn.textContent = 'Delete';
btn.addEventListener('click', () => deleteItem(id));

This eliminates the global requirement. Target the top 6 files first (ui-admin, projects-ui, ui-core, ui-format, ui-settings, notifications) which account for 105 of 143 occurrences.

Template onclick handlers stay — Go templates can't do addEventListener. These become the only remaining reason for window.* exports.

Phase 3: ES Module conversion

Once onclick handlers are gone from JS, files can become ES modules:

<script type="module" src="js/app.js"></script>

Import graph follows the dependency order already established by <script> tag ordering. Vendor libs (marked, purify, codemirror) stay as classic scripts since they self-register on window.

Phase 4: Template handler shim

Create a thin window.handlers = {} object that ES modules register into. Template onclick handlers call handlers.doLogin() etc. This is the final bridge — once templates move to client-side rendering (extension surface SDK), this shim disappears.


Files by Decomposition Priority

Tier 1 — Core (extract first, most dependents)

File Lines Globals Dependents Notes
app-state.js 96 3 20 Clean singleton, easy extract
api.js 1,159 3 36 Large but self-contained
events.js 261 1 9 Clean singleton
ui-primitives.js 1,316 18 32 Large, many utility functions

Tier 2 — Rendering (depends on Tier 1)

File Lines Globals Dependents Notes
ui-format.js 573 20 4 Markdown + code blocks
ui-core.js 1,644 6 3 Chat list, messages, sidebar
pages.js 382 8 Templates Page-level orchestration

Tier 3 — Feature modules (leaf nodes, mostly self-contained)

File Lines Notes
channel-models.js 425 Clean object literal
chat-pane.js 143 Clean object literal
notifications.js 390 Clean singleton, IIFE candidate
model-selector.js 191 Clean object literal
file-tree.js 295 Clean object literal
tokens.js 143 4 globals, minimal deps

Tier 4 — Heavy pages (most onclick handlers, refactor last)

File Lines onclick Notes
ui-admin.js 1,922 28 Admin rendering, deeply coupled
projects-ui.js 1,794 26 78 top-level globals (!), biggest mess
ui-core.js 1,644 25 Already in Tier 2, but onclick heavy
ui-settings.js 1,011 8 Settings rendering
settings-handlers.js 1,064 0 But 24 globals called by ui-settings
admin-handlers.js 952 2 IIFE but 40 internal functions