Changeset 0.28.3 (#187)

This commit is contained in:
2026-03-14 12:30:57 +00:00
parent b2c03be001
commit f68a58b073
46 changed files with 1589 additions and 107 deletions

View File

@@ -4,6 +4,9 @@
// Admin actions: user management, roles, model visibility,
// personas, team management, global providers.
(function() {
'use strict';
// ── Admin Actions ────────────────────────────
function _adminScroll() { return document.getElementById('adminMain'); }
@@ -883,3 +886,36 @@ async function saveAdminExtension(id) {
UI.toast(e.message, 'error');
}
}
// ── Exports ─────────────────────────────────
window._adminPersonaForm = _adminPersonaForm;
window._initAdminListeners = _initAdminListeners;
window.adminResetUserPassword = adminResetUserPassword;
window.bulkSetUserModelVisibility = bulkSetUserModelVisibility;
window.cycleModelVisibility = cycleModelVisibility;
window.deleteAdminExtension = deleteAdminExtension;
window.deleteAdminPersona = deleteAdminPersona;
window.deleteGroup = deleteGroup;
window.deleteTeam = deleteTeam;
window.deleteUser = deleteUser;
window.deleteUserPersona = deleteUserPersona;
window.editAdminExtension = editAdminExtension;
window.editAdminPersona = editAdminPersona;
window.ensureAdminPersonaForm = ensureAdminPersonaForm;
window.removeGroupMember = removeGroupMember;
window.removeTeamMember = removeTeamMember;
window.saveGrant = saveGrant;
window.settingsDeleteTeamPersona = settingsDeleteTeamPersona;
window.settingsRemoveTeamMember = settingsRemoveTeamMember;
window.settingsUpdateTeamMember = settingsUpdateTeamMember;
window.showApproveForm = showApproveForm;
window.toggleAdminExtension = toggleAdminExtension;
window.toggleAdminPersona = toggleAdminPersona;
window.toggleTeamActive = toggleTeamActive;
window.toggleUserActive = toggleUserActive;
window.toggleUserModelVisibility = toggleUserModelVisibility;
window.toggleUserRole = toggleUserRole;
window.updateTeamMember = updateTeamMember;
window._closeExtEditForm = _closeExtEditForm;
window.saveAdminExtension = saveAdminExtension;
})();

View File

@@ -3,6 +3,11 @@
// ==========================================
// v0.25.0: Surface lifecycle management.
// Renders in the "Surfaces" admin section via ADMIN_LOADERS.
//
// Exports: window._loadAdminSurfaces
(function() {
'use strict';
async function _loadAdminSurfaces() {
const container = document.getElementById('adminSurfacesContent');
@@ -191,3 +196,7 @@ async function _loadSurfaceList() {
}
}
// ── Exports ─────────────────────────────────
window._loadAdminSurfaces = _loadAdminSurfaces;
})();

View File

@@ -7,8 +7,13 @@
// BASE_PATH: injected via index.html <script>
// at container startup. All API paths are
// prefixed automatically.
//
// Exports: window.API
// ==========================================
(function() {
'use strict';
const BASE = window.__BASE__ || '';
const _storageKey = BASE ? `sb_auth_${BASE.replace(/\//g, '')}` : 'sb_auth';
@@ -987,3 +992,6 @@ const API = {
return this._parseJSON(resp, path);
}
};
window.API = API;
})();

View File

@@ -4,6 +4,12 @@
// Loaded by base.html for ALL surfaces. Contains the App state
// object and universal data-loading functions (models, settings).
// Surface-specific logic lives in app.js (chat), admin-scaffold.js, etc.
//
// Exports: window.App, window.fetchModels
// ==========================================
(function() {
'use strict';
const App = {
chats: [],
@@ -130,3 +136,7 @@ async function fetchModels() {
console.log(`📋 Loaded ${App.models.length} models (${App.models.filter(m => m.isPersona).length} personas, ${App.models.filter(m => m.hidden).length} hidden)`);
} catch (e) { console.warn('Model fetch failed:', e.message); }
}
window.App = App;
window.fetchModels = fetchModels;
})();

View File

@@ -6,6 +6,12 @@
// (loaded by base.html for all surfaces).
// Domain logic lives in chat.js, notes.js, settings-handlers.js,
// admin-handlers.js. UI rendering in ui-*.js files.
//
// Exports: handleLogin, handleRegister, handleLogout, switchAuthTab,
// startApp, initBanners
(function() {
'use strict';
async function init() {
console.log('🔀 Chat Switchboard initializing...');
@@ -574,3 +580,12 @@ async function initBanners() {
// ── Boot ─────────────────────────────────────
document.addEventListener('DOMContentLoaded', init);
// ── Exports ─────────────────────────────────
window.handleLogin = handleLogin;
window.handleRegister = handleRegister;
window.handleLogout = handleLogout;
window.switchAuthTab = switchAuthTab;
window.startApp = startApp;
window.initBanners = initBanners;
})();

View File

@@ -6,6 +6,11 @@
// - @mention autocomplete in chat input
// - Model attribution on assistant messages
// ==========================================
//
// Exports: window.ChannelModels
(function() {
'use strict';
const ChannelModels = {
@@ -429,3 +434,7 @@ function _shortName(fullName) {
.trim()
.replace(/\s+/g, '-'); // spaces → hyphens
}
// ── Exports ─────────────────────────────────
window.ChannelModels = ChannelModels;
})();

View File

@@ -4,6 +4,11 @@
// v0.22.7: Mountable, self-contained chat pane instances.
// Replaces the hardcoded singleton pattern.
// ChatPane.primary is the backward-compat bridge.
//
// Exports: window.ChatPane
(function() {
'use strict';
const ChatPane = {
...createComponentRegistry('ChatPane'),
@@ -145,3 +150,7 @@ const ChatPane = {
active() { return this.primary; },
};
// ── Exports ─────────────────────────────────
window.ChatPane = ChatPane;
})();

View File

@@ -3,6 +3,16 @@
// ==========================================
// Chat management, send, stream, regenerate, edit, branch,
// summarize, per-chat model persistence.
//
// Exports: ChatInput, loadChats, selectChat, newChat, newGroupChat,
// deleteChat, startRenameChat, sendMessage, stopGeneration,
// reloadActivePath, regenerateMessage, regenerate, editMessage,
// submitEdit, cancelEdit, switchSibling, advanceWorkflowStage,
// rejectWorkflowStage, _initChatListeners,
// summarizeAndContinue, toggleChannelAutoCompact
(function() {
'use strict';
// ── Chat Input Abstraction ──────────────────
// Wraps CM6 editor (when available) or fallback textarea.
@@ -1246,3 +1256,27 @@ async function rejectWorkflowStage() {
UI.toast('Reject failed: ' + (e.message || e), 'error');
}
}
// ── Exports ─────────────────────────────────
window.ChatInput = ChatInput;
window.loadChats = loadChats;
window.selectChat = selectChat;
window.newChat = newChat;
window.newGroupChat = newGroupChat;
window.deleteChat = deleteChat;
window.startRenameChat = startRenameChat;
window.sendMessage = sendMessage;
window.stopGeneration = stopGeneration;
window.reloadActivePath = reloadActivePath;
window.regenerateMessage = regenerateMessage;
window.regenerate = regenerate;
window.editMessage = editMessage;
window.submitEdit = submitEdit;
window.cancelEdit = cancelEdit;
window.switchSibling = switchSibling;
window.advanceWorkflowStage = advanceWorkflowStage;
window.rejectWorkflowStage = rejectWorkflowStage;
window._initChatListeners = _initChatListeners;
window.summarizeAndContinue = summarizeAndContinue;
window.toggleChannelAutoCompact = toggleChannelAutoCompact;
})();

View File

@@ -17,6 +17,11 @@
// editor.isModified('src/main.go'); // → false
// await editor.saveAll();
// editor.destroy();
//
// Exports: window.CodeEditor
(function() {
'use strict';
const CodeEditor = {
...createComponentRegistry('CodeEditor'),
@@ -324,3 +329,7 @@ function _ceDetectLanguage(path) {
};
return map[ext] || 'text';
}
// ── Exports ─────────────────────────────────
window.CodeEditor = CodeEditor;
})();

View File

@@ -7,6 +7,11 @@
//
// Activate: Ctrl+K → "debug" or tap the 🐛 badge (appears after init)
// ==========================================
//
// Exports: window.DebugLog,window.openDebugModal,window.switchDebugTab,window.clearDebugLog,window.copyDebugLog,window.exportDebugLog,window.runDebugDiagnostics,window.purgeCache
(function() {
'use strict';
const DebugLog = {
entries: [],
@@ -661,3 +666,14 @@ async function purgeCache() {
// Initialize ASAP — before app.js init() so we capture everything
DebugLog.init();
// ── Exports ─────────────────────────────────
window.DebugLog = DebugLog;
window.openDebugModal = openDebugModal;
window.switchDebugTab = switchDebugTab;
window.clearDebugLog = clearDebugLog;
window.copyDebugLog = copyDebugLog;
window.exportDebugLog = exportDebugLog;
window.runDebugDiagnostics = runDebugDiagnostics;
window.purgeCache = purgeCache;
})();

View File

@@ -18,6 +18,11 @@
// onMove(delta, ctx), // delta = px from start (signed)
// onEnd(ctx), // cleanup / persist
// });
//
// Exports: window.initDragResize
(function() {
'use strict';
/**
* Attach drag-resize behavior to a handle element.
@@ -92,3 +97,7 @@ function _clientPos(e, isHoriz) {
}
return isHoriz ? e.clientX : e.clientY;
}
// ── Exports ─────────────────────────────────
window.initDragResize = initDragResize;
})();

View File

@@ -9,8 +9,13 @@
// Events.on('chat.message.*', (payload, meta) => { ... });
// Events.emit('chat.typing.abc123', { user: 'jeff' });
// Events.connect('/ws');
//
// Exports: window.Events
// ==========================================
(function() {
'use strict';
const Events = {
_handlers: new Map(), // label → Set<{fn, once}>
@@ -191,9 +196,9 @@ const Events = {
}
// Add auth token as query param (WebSocket doesn't support headers)
const tokens = JSON.parse(localStorage.getItem(typeof _storageKey !== 'undefined' ? _storageKey : 'sb_auth') || '{}');
if (tokens.accessToken) {
url += (url.includes('?') ? '&' : '?') + `token=${encodeURIComponent(tokens.accessToken)}`;
const token = (typeof API !== 'undefined' && API.accessToken) ? API.accessToken : null;
if (token) {
url += (url.includes('?') ? '&' : '?') + `token=${encodeURIComponent(token)}`;
} else {
console.warn('[EventBus] No auth token — skipping WebSocket');
return;
@@ -325,3 +330,6 @@ const Events = {
return subs;
}
};
window.Events = Events;
})();

View File

@@ -14,6 +14,11 @@
//
// Load order: events.js → extensions.js → [ext scripts] → api.js → app.js
// ==========================================
//
// Exports: window.Extensions
(function() {
'use strict';
const Extensions = {
@@ -481,3 +486,7 @@ const Extensions = {
return { extensions: exts, rendererCount: this._renderers.length };
},
};
// ── Exports ─────────────────────────────────
window.Extensions = Extensions;
})();

View File

@@ -16,6 +16,11 @@
// await tree.refresh();
// tree.setActiveFile('src/main.go');
// tree.destroy();
//
// Exports: window.FileTree
(function() {
'use strict';
const FileTree = {
...createComponentRegistry('FileTree'),
@@ -261,3 +266,7 @@ function _ftFileIcon(name) {
};
return icons[ext] || '📄';
}
// ── Exports ─────────────────────────────────
window.FileTree = FileTree;
})();

View File

@@ -9,6 +9,9 @@
// Consumed by: chat.js (send flow), ui-core.js (message rendering),
// ui-admin.js (storage tab)
(function() {
'use strict';
// ── Constants ───────────────────────────────
const FILE_POLL_INTERVAL = 2000; // ms between extraction status checks
@@ -834,3 +837,24 @@ function _hasDragFiles(e) {
if (!e.dataTransfer?.types) return false;
return e.dataTransfer.types.includes('Files');
}
// ── Exports ─────────────────────────────────
window._initFileListeners = _initFileListeners;
window._pollTimers = _pollTimers;
window._startPolling = _startPolling;
window._stopPolling = _stopPolling;
window.clearStaged = clearStaged;
window.closeLightbox = closeLightbox;
window.consumeStaged = consumeStaged;
window.getStagedFileIds = getStagedFileIds;
window.hasStagedFiles = hasStagedFiles;
window.initFiles = initFiles;
window.isSendBlocked = isSendBlocked;
window.loadAdminStorage = loadAdminStorage;
window.loadAuthImages = loadAuthImages;
window.loadChannelFiles = loadChannelFiles;
window.renderMessageFiles = renderMessageFiles;
window.unstageFile = unstageFile;
window.openLightbox = openLightbox;
window.downloadFile = downloadFile;
})();

View File

@@ -4,6 +4,11 @@
// User-facing memory management in Settings,
// admin memory review in Admin Panel,
// and persona memory config in persona forms.
//
// Exports: window.MemoryUI
(function() {
'use strict';
const MemoryUI = {
@@ -362,3 +367,7 @@ function _debounce(fn, ms) {
timer = setTimeout(() => fn.apply(this, args), ms);
};
}
// ── Exports ─────────────────────────────────
window.MemoryUI = MemoryUI;
})();

View File

@@ -11,6 +11,11 @@
// sel.select(modelId);
// sel.getSelected(); // → current model ID
// sel.destroy();
//
// Exports: window.ModelSelector
(function() {
'use strict';
const ModelSelector = {
...createComponentRegistry('ModelSelector'),
@@ -167,3 +172,7 @@ const ModelSelector = {
return instance;
},
};
// ── Exports ─────────────────────────────────
window.ModelSelector = ModelSelector;
})();

View File

@@ -18,6 +18,11 @@
// The existing notes.js + PanelRegistry integration continues to
// work on the chat surface. This component is for NEW mount points
// (editor pane, future notes-studio layout).
//
// Exports: window.NoteEditor
(function() {
'use strict';
const NoteEditor = {
...createComponentRegistry('NoteEditor'),
@@ -433,3 +438,7 @@ const NoteEditor = {
},
};
// ── Exports ─────────────────────────────────
window.NoteEditor = NoteEditor;
})();

View File

@@ -5,6 +5,11 @@
// connections. Lazy-loaded — initializes only
// when the graph view is opened.
// ==========================================
//
// Exports: window.openNoteGraph,window.closeNoteGraph,window._render,window._graphResetZoom,window._graphToggleOrphans,window.invalidateNoteGraph
(function() {
'use strict';
var _graphData = null; // cached { nodes, edges, unresolved }
var _graphState = null; // { panX, panY, zoom, animId, canvas, ctx }
@@ -488,3 +493,12 @@ function invalidateNoteGraph() {
_graphDirty = true;
_folderColorMap = {};
}
// ── Exports ─────────────────────────────────
window.openNoteGraph = openNoteGraph;
window.closeNoteGraph = closeNoteGraph;
window._render = _render;
window._graphResetZoom = _graphResetZoom;
window._graphToggleOrphans = _graphToggleOrphans;
window.invalidateNoteGraph = invalidateNoteGraph;
})();

View File

@@ -3,6 +3,9 @@
// ==========================================
// Notes panel: editor, multi-select, folders, CRUD.
(function() {
'use strict';
var _editingNoteId = null;
var _notesSelectMode = false;
var _selectedNoteIds = new Set();
@@ -940,3 +943,18 @@ function _initNotesListeners() {
// No-op: kept for backward compatibility with app.js calling sequence.
// All wiring moved into _registerNotesPanel().
}
// ── Exports ─────────────────────────────────
window._currentNote = _currentNote;
window._editingNoteId = _editingNoteId;
window._initNotesListeners = _initNotesListeners;
window._registerNotesPanel = _registerNotesPanel;
window.deleteNote = deleteNote;
window.openNoteEditor = openNoteEditor;
window.openNotes = openNotes;
window.saveMessageToNote = saveMessageToNote;
window.saveNote = saveNote;
window._toggleNoteSelect = _toggleNoteSelect;
window._navigateToLinkedNote = _navigateToLinkedNote;
window.toggleBacklinks = toggleBacklinks;
})();

View File

@@ -4,6 +4,11 @@
───────────────────────────────────────────── */
// eslint-disable-next-line no-unused-vars
//
// Exports: window.NotifPrefs
(function() {
'use strict';
const NotifPrefs = {
_loaded: false,
_prefs: [],
@@ -161,3 +166,7 @@ NotifPrefs._getAdminSmtp = function() {
if (pw) config.smtp_password = pw;
return config;
};
// ── Exports ─────────────────────────────────
window.NotifPrefs = NotifPrefs;
})();

View File

@@ -6,6 +6,11 @@
//
// Dependencies: API, Events, PanelRegistry, UI
// ==========================================
//
// Exports: window.Notifications
(function() {
'use strict';
const Notifications = {
@@ -423,3 +428,7 @@ function _timeAgo(isoStr) {
if (sec < 604800) return `${Math.floor(sec / 86400)}d ago`;
return d.toLocaleDateString();
}
// ── Exports ─────────────────────────────────
window.Notifications = Notifications;
})();

View File

@@ -9,8 +9,13 @@
// - Cascading model select (provider change → filter models)
// - Admin save operations (roles, routing, providers, teams, users, settings)
// - Table filtering
//
// Exports: window.Pages, window._val (used by pages-splash.js)
// ==========================================
(function() {
'use strict';
const Pages = {
// ── Model Select Cascading ───────────────
@@ -340,3 +345,8 @@ async function _api(method, path, body) {
return false;
}
}
// ── Exports ─────────────────────────────────
window.Pages = Pages;
window._val = _val; // used by pages-splash.js
})();

View File

@@ -18,6 +18,11 @@
// const fileTree = layout.getPane('files');
// layout.resize('files', 250);
// layout.destroy();
//
// Exports: window.PaneContainer
(function() {
'use strict';
const PaneContainer = {
_presets: {},
@@ -581,3 +586,7 @@ PaneContainer.registerPreset('split', {
{ type: 'leaf', id: 'secondary', component: null },
],
});
// ── Exports ─────────────────────────────────
window.PaneContainer = PaneContainer;
})();

View File

@@ -14,6 +14,11 @@
// .workspace-primary ← main content (chat / notes / editor)
// .workspace-handle ← drag-resize between panes
// .workspace-secondary ← panel pages (preview / notes / project)
//
// Exports: window.PanelRegistry,window.toggleSidePanelFullscreen,window._initWorkspaceResize,window._initPanelSwipe,window._initPanelResponsive,window._initPanelOverlay
(function() {
'use strict';
// ── Panel Registry ──────────────────────────
@@ -441,3 +446,12 @@ function closeSidePanel() {
function switchSidePanelTab(tab) {
PanelRegistry.open(tab);
}
// ── Exports ─────────────────────────────────
window.PanelRegistry = PanelRegistry;
window.toggleSidePanelFullscreen = toggleSidePanelFullscreen;
window._initWorkspaceResize = _initWorkspaceResize;
window._initPanelSwipe = _initPanelSwipe;
window._initPanelResponsive = _initPanelResponsive;
window._initPanelOverlay = _initPanelOverlay;
})();

View File

@@ -3,6 +3,11 @@
// Provides renderPersonaKBPicker(container, opts) which renders a multi-select
// KB picker with auto_search toggles for use in persona create/edit forms.
// Pattern: (container, options) → control object with getValues/setValues/clear.
//
// Exports: window.renderPersonaKBPicker,window.loadPersonaKBs,window.savePersonaKBs
(function() {
'use strict';
'use strict';
@@ -175,3 +180,9 @@ async function savePersonaKBs(personaId, kbPicker, apiPrefix) {
console.warn('Failed to save persona KBs:', e.message);
}
}
// ── Exports ─────────────────────────────────
window.renderPersonaKBPicker = renderPersonaKBPicker;
window.loadPersonaKBs = loadPersonaKBs;
window.savePersonaKBs = savePersonaKBs;
})();

View File

@@ -6,6 +6,9 @@
// and drag-and-drop.
// ==========================================
(function() {
'use strict';
async function loadProjects() {
try {
const resp = await API.listProjects();
@@ -2003,3 +2006,54 @@ async function _removeParticipant(channelId, recordId) {
UI.toast('Failed to remove: ' + e.message, 'error');
}
}
// ── Exports ─────────────────────────────────
window._registerProjectPanel = _registerProjectPanel;
window.createProject = createProject;
window.cycleChannelAiMode = cycleChannelAiMode;
window.deleteChannel = deleteChannel;
window.deleteFolder = deleteFolder;
window.deleteProject = deleteProject;
window.loadChannels = loadChannels;
window.loadFolders = loadFolders;
window.loadProjectChannelPositions = loadProjectChannelPositions;
window.loadProjects = loadProjects;
window.loadUsers = loadUsers;
window.newChannelOrDM = newChannelOrDM;
window.newFolder = newFolder;
window.onChatDragEnd = onChatDragEnd;
window.onChatDragStart = onChatDragStart;
window.onChatSectionDrop = onChatSectionDrop;
window.onFolderDrop = onFolderDrop;
window.onProjectDragLeave = onProjectDragLeave;
window.onProjectDragOver = onProjectDragOver;
window.onProjectDrop = onProjectDrop;
window.onUnfiledDrop = onUnfiledDrop;
window.openParticipantsPanel = openParticipantsPanel;
window.openProjectPanel = openProjectPanel;
window.selectChannel = selectChannel;
window.showChannelContextMenu = showChannelContextMenu;
window.showChatContextMenu = showChatContextMenu;
window.showFolderMenu = showFolderMenu;
window.showProjectMenu = showProjectMenu;
window.toggleProjectCollapse = toggleProjectCollapse;
window.renameProject = renameProject;
window.setProjectColor = setProjectColor;
window.toggleActiveProject = toggleActiveProject;
window.moveChatToProject = moveChatToProject;
window.dismissChatContextMenu = dismissChatContextMenu;
window.createProjectAndMove = createProjectAndMove;
window.moveChatToFolder = moveChatToFolder;
window._removeProjectKB = _removeProjectKB;
window._addProjectKB = _addProjectKB;
window._removeProjectNote = _removeProjectNote;
window.showWorkspacePicker = showWorkspacePicker;
window._moveChatInProject = _moveChatInProject;
window.renameChannel = renameChannel;
window.editChannelTopic = editChannelTopic;
window.archiveChannel = archiveChannel;
window.renameFolder = renameFolder;
window._showAddParticipantSearch = _showAddParticipantSearch;
window._addParticipant = _addParticipant;
window._removeParticipant = _removeParticipant;
})();

View File

@@ -15,6 +15,11 @@
// - Multi-line: Shift+Enter for newline, Enter to run
// - Admin-gated OR ?debug=1 URL param
// ==========================================
//
// Exports: window.REPL
(function() {
'use strict';
const REPL = {
@@ -549,3 +554,7 @@ const REPL = {
// Initialized from app.js startApp() after auth is confirmed,
// ensuring API.user.role is available for admin gate check.
// ── Exports ─────────────────────────────────
window.REPL = REPL;
})();

View File

@@ -3,6 +3,13 @@
// ==========================================
// Settings save, provider CRUD, avatar, command palette,
// user model roles.
//
// Exports: window.loadSettings,window.saveSettings,window.updateAvatarPreview,window._userProvForm,window._userProvList,window.handleSaveAdminSettings,window._userRoleConfig,window.toggleCmdPalette,window.closeCmdPalette,window._initSettingsListeners,window._initAdminSettingsToggles
// (also: window.toggleUserModelVisibility, window.bulkSetUserModelVisibility,
// window.deleteUserPersona, window.loadTeamWorkflows — self-assigned)
(function() {
'use strict';
// ── Settings ─────────────────────────────────
@@ -892,3 +899,17 @@ window.loadTeamWorkflows = async function() {
el.innerHTML = '<div class="settings-placeholder">Failed to load workflows: ' + esc(e.message) + '</div>';
}
};
// ── Exports ─────────────────────────────────
window.loadSettings = loadSettings;
window.saveSettings = saveSettings;
window.updateAvatarPreview = updateAvatarPreview;
window._userProvForm = _userProvForm;
window._userProvList = _userProvList;
window.handleSaveAdminSettings = handleSaveAdminSettings;
window._userRoleConfig = _userRoleConfig;
window.toggleCmdPalette = toggleCmdPalette;
window.closeCmdPalette = closeCmdPalette;
window._initSettingsListeners = _initSettingsListeners;
window._initAdminSettingsToggles = _initAdminSettingsToggles;
})();

View File

@@ -2,6 +2,11 @@
// Chat Switchboard Token Estimation
// ==========================================
// Context tracking, token estimation, and context warning.
//
// Exports: window.Tokens,window.updateInputTokens,window.updateContextWarning
(function() {
'use strict';
// ── Token Estimation + Context Tracking ─────
@@ -157,3 +162,9 @@ function dismissContextWarning() {
const el = document.getElementById('contextWarning');
if (el) el.style.display = 'none';
}
// ── Exports ─────────────────────────────────
window.Tokens = Tokens;
window.updateInputTokens = updateInputTokens;
window.updateContextWarning = updateContextWarning;
})();

View File

@@ -4,6 +4,9 @@
// Fullscreen admin panel with category + section navigation.
// All loadAdmin*() functions unchanged — same endpoints, same DOM IDs.
(function() {
'use strict';
// ── Category → Section mapping ────────────
const ADMIN_SECTIONS = {
people: ['users', 'teams', 'groups'],
@@ -1565,3 +1568,9 @@ Object.assign(UI, {
},
});
// ── Exports ─────────────────────────────────
window.ADMIN_SECTIONS = ADMIN_SECTIONS;
window.ADMIN_LABELS = ADMIN_LABELS;
window.ADMIN_LOADERS = ADMIN_LOADERS;
})();

View File

@@ -5,6 +5,13 @@
// model selector, capability badges, user, generating state, toast,
// settings modal dispatcher, export, message actions, scroll.
// Extended by ui-settings.js and ui-admin.js via Object.assign.
//
// Exports: window.UI, window.renderPersonaForm,
// window.toggleSummarizedHistory (onclick handler)
// ==========================================
(function() {
'use strict';
// ── Avatar Helper ────────────────────────────
// Returns HTML for a message avatar: <img> if data URI available, emoji fallback.
@@ -1596,3 +1603,10 @@ const UI = {
} catch (_) { /* corrupt localStorage — ignore */ }
}
};
// ── Exports ─────────────────────────────────
window.UI = UI;
window.renderPersonaForm = renderPersonaForm;
// onclick handler (called from innerHTML)
window.toggleSummarizedHistory = toggleSummarizedHistory;
})();

View File

@@ -3,6 +3,16 @@
// ==========================================
// Markdown rendering, code blocks, preview panel, time formatting.
// esc() is in ui-primitives.js (loaded globally in base.html).
//
// Exports: formatMessage, clearPreview, runExtensionPostRender,
// _livePreviewUpdate, _relativeTime, _renderToolCallsHTML,
// _registerPreviewPanel,
// toggleCodeCollapse, toggleHTMLPreview, downloadCode,
// popOutExtBlock (onclick handlers)
// ==========================================
(function() {
'use strict';
// ── Message Formatting ──────────────────────
@@ -573,3 +583,19 @@ function runExtensionPostRender(container) {
Extensions.runPostRenderers(container);
}
}
// ── Exports ─────────────────────────────────
// Cross-file function calls
window.formatMessage = formatMessage;
window.clearPreview = clearPreview;
window.runExtensionPostRender = runExtensionPostRender;
window._livePreviewUpdate = _livePreviewUpdate;
window._relativeTime = _relativeTime;
window._renderToolCallsHTML = _renderToolCallsHTML;
window._registerPreviewPanel = _registerPreviewPanel;
// onclick handlers (called from innerHTML)
window.toggleCodeCollapse = toggleCodeCollapse;
window.toggleHTMLPreview = toggleHTMLPreview;
window.downloadCode = downloadCode;
window.popOutExtBlock = popOutExtBlock;
})();

View File

@@ -4,8 +4,14 @@
// Follows the renderPersonaForm() pattern: (container, options) → control object.
// Designed for extension hooks: registries are open for .add(), primitives
// accept options for customization, and return handles for programmatic control.
//
// Exports: esc, createComponentRegistry, componentMixin, Providers, Roles,
// renderCapBadges, renderProviderForm, renderProviderList,
// renderRoleConfig, renderUsageDashboard, showConfirm, showPrompt,
// openModal, closeModal, checkTabsOverflow, Theme, mountAvatarUpload
// ─────────────────────────────────────────────────────────────────────────────
(function() {
'use strict';
// ══════════════════════════════════════════════════════════════════════════════
@@ -1108,3 +1114,23 @@ function mountAvatarUpload(containerEl, opts = {}) {
return { setImage: render };
}
// ── Exports ─────────────────────────────────
window.esc = esc;
window.createComponentRegistry = createComponentRegistry;
window.componentMixin = componentMixin;
window.Providers = Providers;
window.Roles = Roles;
window.renderCapBadges = renderCapBadges;
window.renderProviderForm = renderProviderForm;
window.renderProviderList = renderProviderList;
window.renderRoleConfig = renderRoleConfig;
window.renderUsageDashboard = renderUsageDashboard;
window.showConfirm = showConfirm;
window.showPrompt = showPrompt;
window.openModal = openModal;
window.closeModal = closeModal;
window.checkTabsOverflow = checkTabsOverflow;
window.Theme = Theme;
window.mountAvatarUpload = mountAvatarUpload;
})();

View File

@@ -3,6 +3,11 @@
// ==========================================
// Extends UI with settings modal tabs, team management,
// providers, usage, model roles, and user preferences.
//
// Exports: none (extends window.UI via Object.assign)
(function() {
'use strict';
Object.assign(UI, {
// ── General Settings (Settings Surface) ──
@@ -861,3 +866,5 @@ Object.assign(UI, {
},
});
})();

View File

@@ -10,6 +10,11 @@
// menu.setUser({ display_name: 'Jeff', username: 'jeff', avatar: null });
// menu.showAdmin(true);
// menu.destroy();
//
// Exports: window.UserMenu
(function() {
'use strict';
const UserMenu = {
...createComponentRegistry('UserMenu'),
@@ -131,3 +136,7 @@ const UserMenu = {
return instance;
},
};
// ── Exports ─────────────────────────────────
window.UserMenu = UserMenu;
})();