web: newchat.js — restore the three bare references the extraction dropped (#973)
isAdmin() (now via verbs — the audit was fooled by a same-named local const in another function's scope), the ENABLE_BOTS/ENABLE_APPS gates (joined shellstate with gateMeta + ENABLE_AI), and ICON_WRENCH (icons.js import). Paul hit the empty new-chat sheet on the canary; the boot smoke now opens the picker and fails on an empty sheet.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
3 files changed,
+10
−8
web/static/newchat.js+3 −2web/static/shell.js+2 −6web/static/shellstate.js+5 −0
diff --git a/web/static/newchat.js b/web/static/newchat.js| index c834857..5f6ae9f 100644 |
| --- a/web/static/newchat.js |
| +++ b/web/static/newchat.js |
| @@ -2,7 +2,8 @@ |
| // Discover, and the apps catalogue, plus thread creation itself. Extracted |
| // verbatim from shell.js; behaviours ride the verbs seam, state shellstate. |
| import { verbs } from "/static/shellverbs.js"; |
| -import { session, roster, myUserId, threads, threadKeys, activeId, nicknames, threadName, threadKeyB64, hidden, dmClosed, embed, setActiveId } from "/static/shellstate.js"; |
| +import { ICON_WRENCH } from "/static/icons.js"; |
| +import { session, roster, myUserId, threads, threadKeys, activeId, nicknames, threadName, threadKeyB64, hidden, dmClosed, embed, setActiveId, ENABLE_BOTS, ENABLE_APPS } from "/static/shellstate.js"; |
| import { avatarFor, avatarEl, paintAvatar } from "/static/avatars.js"; |
| import { decrypt, encrypt, generateKey, importKey, wrapThreadKey } from "/static/crypto.js"; |
| import { appGlyphInto, personalApps } from "/static/apps.js"; |
| @@ -102,7 +103,7 @@ export function showNewChat(startMode) { |
| // admins get its row in the Apps section all the same — the discoverable way |
| // in, beyond the /admin command. Null for everyone else. Deliberately exempt |
| // from the apps gate: Admin is how an admin switches apps back on. |
| - const adminApp = isAdmin() ? { name: "admin", title: "Admin", glyph: "🛠️", logo: ICON_WRENCH } : null; |
| + const adminApp = verbs.isAdmin() ? { name: "admin", title: "Admin", glyph: "🛠️", logo: ICON_WRENCH } : null; |
| const adminMatches = (q) => !!adminApp && adminApp.title.toLowerCase().includes(q); |
| const addAppRow = (listEl, app) => { |
| const b = document.createElement("button"); |
diff --git a/web/static/shell.js b/web/static/shell.js| index 6956fcd..9dd13df 100644 |
| --- a/web/static/shell.js |
| +++ b/web/static/shell.js |
| @@ -144,7 +144,7 @@ import { verbs } from "/static/shellverbs.js"; // the behaviour seam (docs/shell |
| import { scheduleMessageSearch, wireSearch, searchIdx } from "/static/searchui.js"; // message search over the local store (#586) |
| import { loadMemberApps, setMemberSeeder, setSurfaceRefresh, setMemberAdmin, recentLocalDeploy, pushTheme } from "/static/sandbox.js"; // member-built apps, run sandboxed (docs/member-apps.md) |
| import { THEME_META, THEME_ORDER, currentTheme, currentAppearance, setTheme, setAppearance, currentTextSize, setTextSize, onThemeApplied } from "/static/theme.js"; // applies the saved theme/text-size on import |
| -import { session, roster, myUserId, threads, threadKeys, activeId, ws, setSession, setRoster, setMyUserId, setThreads, setActiveId, setWs, nicknames, setNicknames, threadName, instanceKey, instanceKeyB64, setInstanceKey, threadKeyB64, unread, hidden, dmClosed, embed } from "/static/shellstate.js"; // the shared shell state (docs/shell-modules.md) |
| +import { session, roster, myUserId, threads, threadKeys, activeId, ws, setSession, setRoster, setMyUserId, setThreads, setActiveId, setWs, nicknames, setNicknames, threadName, instanceKey, instanceKeyB64, setInstanceKey, threadKeyB64, unread, hidden, dmClosed, embed, ENABLE_AI, ENABLE_BOTS, ENABLE_APPS } from "/static/shellstate.js"; // the shared shell state (docs/shell-modules.md) |
| import { openLightbox } from "/static/lightbox.js"; |
| import { mutedPeople, blockedPeople, loadModPrefs, setPersonMuted, openReportSheet, loadBlocks, setPersonBlocked, onModerationChange } from "/static/moderation.js"; |
| @@ -194,7 +194,7 @@ Object.assign(verbs, { |
| resolveRename, showList, paintHeaderAvatar, |
| loadTiers, setNickname, syncThreadKeysToSW, |
| inviteSomeone, resolveAppThread, billingDate, levelPrice, inviteAllowed, |
| - decryptRosterLabels, openThreadById, seedAppState, welcomePending, |
| + decryptRosterLabels, openThreadById, seedAppState, welcomePending, isAdmin, |
| }); |
| onThemeApplied(pushTheme); // live-retint mounted sandbox frames on theme change |
| @@ -2238,10 +2238,6 @@ const USER_INVITES = ((document.querySelector('meta[name="user-invites"]') || {} |
| // they only hide entry points; the server enforces each gate. ENABLE_AI has no |
| // web entry point to hide (the sidecar enforces it), but rides along so copy |
| // can consult it. |
| -const gateMeta = (name) => ((document.querySelector(`meta[name="${name}"]`) || {}).content || "") !== "0"; |
| -const ENABLE_AI = gateMeta("enable-ai"); |
| -const ENABLE_BOTS = gateMeta("enable-bots"); |
| -const ENABLE_APPS = gateMeta("enable-apps"); |
| // Whether THIS member may invite: the toggle governs ordinary members, but an |
| // admin always can — otherwise the person who just set the space up couldn't |
diff --git a/web/static/shellstate.js b/web/static/shellstate.js| index bb6e8f5..724abb3 100644 |
| --- a/web/static/shellstate.js |
| +++ b/web/static/shellstate.js |
| @@ -7,6 +7,11 @@ |
| // here; helpers keep moving into their own modules. |
| export const embed = window.__lchatEmbed || null; // native-webview embed config, or null in a browser |
| +// Feature gates the server stamps into the page as meta tags ("0" = off). |
| +const gateMeta = (name) => ((document.querySelector(`meta[name="${name}"]`) || {}).content || "") !== "0"; |
| +export const ENABLE_AI = gateMeta("enable-ai"); |
| +export const ENABLE_BOTS = gateMeta("enable-bots"); |
| +export const ENABLE_APPS = gateMeta("enable-apps"); |
| export let session = null; // { token, name } — set at boot (embed or localStorage) |
| export let roster = []; // [{user_id, label, public_key}] |
| export let myUserId = ""; |