clay-server 2.31.0 → 2.32.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/lib/browser-mcp-server.js +32 -44
  2. package/lib/debate-mcp-server.js +14 -31
  3. package/lib/mcp-local.js +31 -1
  4. package/lib/project-connection.js +4 -2
  5. package/lib/project-filesystem.js +47 -1
  6. package/lib/project-http.js +75 -8
  7. package/lib/project-mcp.js +4 -0
  8. package/lib/project-sessions.js +88 -51
  9. package/lib/project-user-message.js +12 -7
  10. package/lib/project.js +204 -90
  11. package/lib/public/app.js +123 -448
  12. package/lib/public/codex-avatar.png +0 -0
  13. package/lib/public/css/debate.css +3 -2
  14. package/lib/public/css/filebrowser.css +91 -1
  15. package/lib/public/css/icon-strip.css +21 -5
  16. package/lib/public/css/input.css +181 -100
  17. package/lib/public/css/mates.css +43 -0
  18. package/lib/public/css/mention.css +48 -4
  19. package/lib/public/css/menus.css +1 -1
  20. package/lib/public/css/messages.css +2 -0
  21. package/lib/public/css/notifications-center.css +19 -0
  22. package/lib/public/index.html +46 -24
  23. package/lib/public/modules/app-connection.js +138 -37
  24. package/lib/public/modules/app-cursors.js +18 -17
  25. package/lib/public/modules/app-debate-ui.js +9 -9
  26. package/lib/public/modules/app-dm.js +170 -131
  27. package/lib/public/modules/app-favicon.js +28 -26
  28. package/lib/public/modules/app-header.js +79 -68
  29. package/lib/public/modules/app-home-hub.js +55 -47
  30. package/lib/public/modules/app-loop-ui.js +34 -18
  31. package/lib/public/modules/app-loop-wizard.js +6 -6
  32. package/lib/public/modules/app-messages.js +195 -152
  33. package/lib/public/modules/app-misc.js +23 -12
  34. package/lib/public/modules/app-notifications.js +97 -3
  35. package/lib/public/modules/app-panels.js +203 -49
  36. package/lib/public/modules/app-projects.js +159 -150
  37. package/lib/public/modules/app-rate-limit.js +5 -4
  38. package/lib/public/modules/app-rendering.js +149 -101
  39. package/lib/public/modules/app-skills-install.js +4 -4
  40. package/lib/public/modules/context-sources.js +12 -41
  41. package/lib/public/modules/dom-refs.js +21 -0
  42. package/lib/public/modules/filebrowser.js +173 -2
  43. package/lib/public/modules/input.js +86 -0
  44. package/lib/public/modules/mate-sidebar.js +38 -0
  45. package/lib/public/modules/mention.js +24 -6
  46. package/lib/public/modules/scheduler.js +1 -1
  47. package/lib/public/modules/sidebar-mates.js +66 -34
  48. package/lib/public/modules/sidebar-mobile.js +34 -30
  49. package/lib/public/modules/sidebar-projects.js +60 -57
  50. package/lib/public/modules/sidebar-sessions.js +75 -69
  51. package/lib/public/modules/sidebar.js +12 -20
  52. package/lib/public/modules/skills.js +8 -9
  53. package/lib/public/modules/sticky-notes.js +1 -2
  54. package/lib/public/modules/store.js +9 -2
  55. package/lib/public/modules/stt.js +4 -1
  56. package/lib/public/modules/tools.js +14 -9
  57. package/lib/sdk-bridge.js +511 -1113
  58. package/lib/sdk-message-processor.js +123 -134
  59. package/lib/sdk-worker.js +4 -0
  60. package/lib/server-dm.js +1 -0
  61. package/lib/server.js +86 -1
  62. package/lib/sessions.js +47 -36
  63. package/lib/ws-schema.js +2 -0
  64. package/lib/yoke/adapters/claude-worker.js +559 -0
  65. package/lib/yoke/adapters/claude.js +1418 -0
  66. package/lib/yoke/adapters/codex.js +968 -0
  67. package/lib/yoke/adapters/gemini.js +668 -0
  68. package/lib/yoke/codex-app-server.js +307 -0
  69. package/lib/yoke/index.js +199 -0
  70. package/lib/yoke/instructions.js +62 -0
  71. package/lib/yoke/interface.js +92 -0
  72. package/lib/yoke/mcp-bridge-server.js +294 -0
  73. package/lib/yoke/package.json +7 -0
  74. package/package.json +3 -1
package/lib/public/app.js CHANGED
@@ -48,7 +48,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
48
48
  import { initLongPress } from './modules/longpress.js';
49
49
  import { initConnection, connect as _connConnect, setStatus as _connSetStatus, scheduleReconnect as _connScheduleReconnect, cancelReconnect as _connCancelReconnect } from './modules/app-connection.js';
50
50
  import { processMessage as _msgProcessMessage } from './modules/app-messages.js';
51
- import { setWs as _setWsRef } from './modules/ws-ref.js';
51
+ import { getWs as _getWsRef, setWs as _setWsRef } from './modules/ws-ref.js';
52
52
  import { initHomeHub, showHomeHub as _hubShowHomeHub, hideHomeHub as _hubHideHomeHub, handleHubSchedules as _hubHandleHubSchedules, renderHomeHub as _hubRenderHomeHub, isHomeHubVisible } from './modules/app-home-hub.js';
53
53
  import { initRateLimit, handleRateLimitEvent as _rlHandleRateLimitEvent, updateRateLimitUsage as _rlUpdateRateLimitUsage, addScheduledMessageBubble as _rlAddScheduledMessageBubble, removeScheduledMessageBubble as _rlRemoveScheduledMessageBubble, handleFastModeState as _rlHandleFastModeState, getScheduledMsgEl, resetRateLimitState } from './modules/app-rate-limit.js';
54
54
  import { initCursors, handleRemoteCursorMove as _curHandleRemoteCursorMove, handleRemoteCursorLeave as _curHandleRemoteCursorLeave, handleRemoteSelection as _curHandleRemoteSelection, clearRemoteCursors as _curClearRemoteCursors, initCursorToggle } from './modules/app-cursors.js';
@@ -63,7 +63,7 @@ import { initAppNotifications, handleNotificationsState as _notifHandleState, ha
63
63
  import { createStore, store } from './modules/store.js';
64
64
  import { initPanels, updateConfigChip as _panUpdateConfigChip, getModelEffortLevels as _panGetModelEffortLevels, accumulateUsage as _panAccumulateUsage, updateUsagePanel as _panUpdateUsagePanel, resetUsage as _panResetUsage, toggleUsagePanel as _panToggleUsagePanel, formatTokens as _panFormatTokens, updateStatusPanel as _panUpdateStatusPanel, requestProcessStats as _panRequestProcessStats, toggleStatusPanel as _panToggleStatusPanel, accumulateContext as _panAccumulateContext, updateContextPanel as _panUpdateContextPanel, resetContext as _panResetContext, resetContextData as _panResetContextData, minimizeContext as _panMinimizeContext, expandContext as _panExpandContext, toggleContextPanel as _panToggleContextPanel, getContextView as _panGetContextView, renderCtxPopover as _panRenderCtxPopover, hideCtxPopover as _panHideCtxPopover, formatBytes as _panFormatBytes, formatUptime as _panFormatUptime, getModelSupportsEffort as _panGetModelSupportsEffort, getSessionUsage, setSessionUsage, getContextData, setContextData, setContextView as _panSetContextView, applyContextView as _panApplyContextView } from './modules/app-panels.js';
65
65
  import { initProjects, updateProjectList as _projUpdateProjectList, renderProjectList as _projRenderProjectList, renderTopbarPresence as _projRenderTopbarPresence, switchProject as _projSwitchProject, resetClientState as _projResetClientState, confirmRemoveProject as _projConfirmRemoveProject, handleRemoveProjectCheckResult as _projHandleRemoveProjectCheckResult, handleRemoveProjectResult as _projHandleRemoveProjectResult, openAddProjectModal as _projOpenAddProjectModal, closeAddProjectModal as _projCloseAddProjectModal, handleBrowseDirResult as _projHandleBrowseDirResult, handleAddProjectResult as _projHandleAddProjectResult, handleCloneProgress as _projHandleCloneProgress, showUpdateAvailable as _projShowUpdateAvailable, getCachedProjects, setCachedProjects, getCachedProjectCount, getCachedRemovedProjects, setCachedRemovedProjects } from './modules/app-projects.js';
66
- import { initRendering, addToMessages as _renAddToMessages, scrollToBottom as _renScrollToBottom, forceScrollToBottom as _renForceScrollToBottom, addUserMessage as _renAddUserMessage, getMsgTime as _renGetMsgTime, shouldGroupMessage as _renShouldGroupMessage, ensureAssistantBlock as _renEnsureAssistantBlock, addCopyHandler as _renAddCopyHandler, appendDelta as _renAppendDelta, flushStreamBuffer as _renFlushStreamBuffer, finalizeAssistantBlock as _renFinalizeAssistantBlock, addSystemMessage as _renAddSystemMessage, addConflictMessage as _renAddConflictMessage, addContextOverflowMessage as _renAddContextOverflowMessage, addAuthRequiredMessage as _renAddAuthRequiredMessage, showClaudePreThinking as _renShowClaudePreThinking, showMatePreThinking as _renShowMatePreThinking, removeMatePreThinking as _renRemoveMatePreThinking, showSuggestionChips as _renShowSuggestionChips, hideSuggestionChips as _renHideSuggestionChips, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp } from './modules/app-rendering.js';
66
+ import { initRendering, addToMessages as _renAddToMessages, scrollToBottom as _renScrollToBottom, forceScrollToBottom as _renForceScrollToBottom, addUserMessage as _renAddUserMessage, getMsgTime as _renGetMsgTime, shouldGroupMessage as _renShouldGroupMessage, ensureAssistantBlock as _renEnsureAssistantBlock, addCopyHandler as _renAddCopyHandler, appendDelta as _renAppendDelta, flushStreamBuffer as _renFlushStreamBuffer, finalizeAssistantBlock as _renFinalizeAssistantBlock, addSystemMessage as _renAddSystemMessage, addConflictMessage as _renAddConflictMessage, addContextOverflowMessage as _renAddContextOverflowMessage, addAuthRequiredMessage as _renAddAuthRequiredMessage, showClaudePreThinking as _renShowClaudePreThinking, showMatePreThinking as _renShowMatePreThinking, removeMatePreThinking as _renRemoveMatePreThinking, showSuggestionChips as _renShowSuggestionChips, hideSuggestionChips as _renHideSuggestionChips, getGhostSuggestion as _renGetGhostSuggestion, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp } from './modules/app-rendering.js';
67
67
  import { initDm, openDm as _dmOpenDm, enterDmMode as _dmEnterDmMode, exitDmMode as _dmExitDmMode, handleMateCreatedInApp as _dmHandleMateCreatedInApp, renderAvailableBuiltins as _dmRenderAvailableBuiltins, buildMateInterviewPrompt as _dmBuildMateInterviewPrompt, updateMateIconStatus as _dmUpdateMateIconStatus, connectMateProject as _dmConnectMateProject, disconnectMateProject as _dmDisconnectMateProject, appendDmMessage as _dmAppendDmMessage, showDmTypingIndicator as _dmShowDmTypingIndicator, handleDmSend as _dmHandleDmSend } from './modules/app-dm.js';
68
68
  import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
69
69
  import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState, exportDebateAsPdf, renderMcpDebateProposal } from './modules/debate.js';
@@ -166,12 +166,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
166
166
 
167
167
  document.addEventListener("keydown", function (e) {
168
168
  if (e.key === "Escape") {
169
- if (isHomeHubVisible() && store.getState().currentSlug) {
169
+ if (isHomeHubVisible() && store.get('currentSlug')) {
170
170
  hideHomeHub();
171
171
  if (document.documentElement.classList.contains("pwa-standalone")) {
172
- history.replaceState(null, "", "/p/" + store.getState().currentSlug + "/");
172
+ history.replaceState(null, "", "/p/" + store.get('currentSlug') + "/");
173
173
  } else {
174
- history.pushState(null, "", "/p/" + store.getState().currentSlug + "/");
174
+ history.pushState(null, "", "/p/" + store.get('currentSlug') + "/");
175
175
  }
176
176
  var homeIcon = document.querySelector(".icon-strip-home");
177
177
  if (homeIcon) homeIcon.classList.remove("active");
@@ -210,7 +210,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
210
210
  function closeImageModal() { _miscCloseImageModal(); }
211
211
 
212
212
  // --- State ---
213
- var ws = null;
214
213
  // connected, processing, activeSessionId, sessionDrafts -> store
215
214
  // loopActive, loopAvailable, loopIteration, loopMaxIterations, loopBannerName,
216
215
  // ralphPhase, ralphCraftingSessionId, ralphCraftingSource, ralphFilesReady, ralphPreviewContent -> modules/app-loop-ui.js
@@ -240,7 +239,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
240
239
  } catch (e) {}
241
240
  // messageUuidMap, historyFrom, historyTotal -> store
242
241
  // prependAnchor, replayingHistory, isUserScrolledUp, scrollThreshold -> modules/app-rendering.js
243
- var loadingMore = false;
242
+ // loadingMore -> moved to store
244
243
  // historySentinelObserver -> modules/app-header.js
245
244
 
246
245
  // builtinCommands -> modules/input.js
@@ -261,6 +260,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
261
260
  wsPath: wsPath,
262
261
  dmMode: false,
263
262
  historyFrom: 0,
263
+ loadingMore: false,
264
264
  historyTotal: 0,
265
265
  replayingHistory: false,
266
266
  projectName: projectName,
@@ -330,6 +330,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
330
330
  debateEndedMode: false,
331
331
  // skills
332
332
  knownInstalledSkills: {},
333
+ // permissions (RBAC)
334
+ permissions: null,
333
335
  // loop wizard
334
336
  wizardData: { name: "", task: "", maxIterations: null, cron: null }
335
337
  });
@@ -337,9 +339,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
337
339
  // --- Rewind (module) ---
338
340
  initRewind({
339
341
  $: $,
340
- get ws() { return ws; },
341
- get connected() { return store.getState().connected; },
342
- get processing() { return store.getState().processing; },
342
+ get ws() { return _getWsRef(); },
343
+ get connected() { return store.get('connected'); },
344
+ get processing() { return store.get('processing'); },
343
345
  messagesEl: messagesEl,
344
346
  addSystemMessage: addSystemMessage,
345
347
  });
@@ -356,9 +358,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
356
358
  // --- Sidebar (module) ---
357
359
  var sidebarCtx = {
358
360
  $: $,
359
- get ws() { return ws; },
360
- get connected() { return store.getState().connected; },
361
- get projectName() { return store.getState().projectName; },
361
+ get ws() { return _getWsRef(); },
362
+ get connected() { return store.get('connected'); },
363
+ get projectName() { return store.get('projectName'); },
362
364
  messagesEl: messagesEl,
363
365
  sessionListEl: sessionListEl,
364
366
  sidebar: sidebar,
@@ -377,22 +379,22 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
377
379
  showHomeHub: function () { showHomeHub(); },
378
380
  openRalphWizard: function (source) { openRalphWizard(source); },
379
381
  getUpcomingSchedules: getUpcomingSchedules,
380
- get multiUser() { return store.getState().isMultiUserMode; },
381
- get myUserId() { return store.getState().myUserId; },
382
- get projectOwnerId() { return store.getState().currentProjectOwnerId; },
383
- get ownerLocked() { return store.getState().ownerLocked; },
382
+ get multiUser() { return store.get('isMultiUserMode'); },
383
+ get myUserId() { return store.get('myUserId'); },
384
+ get projectOwnerId() { return store.get('currentProjectOwnerId'); },
385
+ get ownerLocked() { return store.get('ownerLocked'); },
384
386
  openDm: function (userId) { openDm(userId); },
385
387
  openMateWizard: function () { requireClayMateInterview(function () { openMateWizard(); }); },
386
388
  openAddProjectModal: function () { openAddProjectModal(); },
387
389
  sendWs: function (msg) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(msg)); },
388
- onDmRemoveUser: function (userId) { var dr = Object.assign({}, store.getState().dmRemovedUsers); dr[userId] = true; store.setState({ dmRemovedUsers: dr }); },
389
- getHistoryFrom: function () { return store.getState().historyFrom; },
390
- get permissions() { return myPermissions; },
390
+ onDmRemoveUser: function (userId) { var dr = Object.assign({}, store.get('dmRemovedUsers')); dr[userId] = true; store.set({ dmRemovedUsers: dr }); },
391
+ getHistoryFrom: function () { return store.get('historyFrom'); },
392
+ get permissions() { return store.get('permissions'); },
391
393
  get projectList() { return getCachedProjects() || []; },
392
- availableBuiltins: function () { return store.getState().cachedAvailableBuiltins || []; },
394
+ availableBuiltins: function () { return store.get('cachedAvailableBuiltins') || []; },
393
395
  };
394
396
  initSidebar(sidebarCtx);
395
- var wsGetter = function () { return ws; };
397
+ var wsGetter = function () { return _getWsRef(); };
396
398
  initMateSidebar(wsGetter);
397
399
  initMateKnowledge(wsGetter);
398
400
  initMateMemory(wsGetter, { onShow: function () { hideKnowledge(); hideNotes(); } });
@@ -403,13 +405,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
403
405
 
404
406
  initCommandPalette({
405
407
  switchProject: function (slug) { switchProject(slug); },
406
- currentSlug: function () { return store.getState().currentSlug; },
408
+ currentSlug: function () { return store.get('currentSlug'); },
407
409
  projectList: function () { return getCachedProjects() || []; },
408
- matesList: function () { return store.getState().cachedMatesList || []; },
409
- availableBuiltins: function () { return store.getState().cachedAvailableBuiltins || []; },
410
- allUsers: function () { return store.getState().cachedAllUsers || []; },
411
- dmConversations: function () { return store.getState().cachedDmConversations || []; },
412
- myUserId: function () { return store.getState().myUserId; },
410
+ matesList: function () { return store.get('cachedMatesList') || []; },
411
+ availableBuiltins: function () { return store.get('cachedAvailableBuiltins') || []; },
412
+ allUsers: function () { return store.get('cachedAllUsers') || []; },
413
+ dmConversations: function () { return store.get('cachedDmConversations') || []; },
414
+ myUserId: function () { return store.get('myUserId'); },
413
415
  selectSession: function (id) {
414
416
  // Close any open panels before switching
415
417
  if (isSchedulerOpen()) closeScheduler();
@@ -524,8 +526,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
524
526
  if (!msgEl || !msgEl.dataset.uuid) return;
525
527
  var forkUuid = msgEl.dataset.uuid;
526
528
  showConfirm("Fork session from this message?", function() {
527
- if (ws && ws.readyState === 1) {
528
- ws.send(JSON.stringify({ type: "fork_session", uuid: forkUuid }));
529
+ var _ws = _getWsRef();
530
+ if (_ws && _ws.readyState === 1) {
531
+ _ws.send(JSON.stringify({ type: "fork_session", uuid: forkUuid }));
529
532
  }
530
533
  }, "Fork", false);
531
534
  });
@@ -537,53 +540,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
537
540
  initMisc();
538
541
 
539
542
  // --- Favicon module ---
540
- initFavicon({
541
- sendBtn: sendBtn,
542
- get basePath() { return basePath; },
543
- onThemeChange: onThemeChange,
544
- getStatusDot: getStatusDot,
545
- addToMessages: addToMessages,
546
- scrollToBottom: scrollToBottom,
547
- getActivityEl: getActivityEl,
548
- setActivityEl: setActivityEl,
549
- get connected() { return store.getState().connected; },
550
- get dmMode() { return store.getState().dmMode; },
551
- get dmTargetUser() { return store.getState().dmTargetUser; },
552
- get currentSlug() { return store.getState().currentSlug; },
553
- });
543
+ initFavicon();
554
544
 
555
545
  // --- Header module (rename, info popover, history) ---
556
- initHeader({
557
- $: $,
558
- messagesEl: messagesEl,
559
- headerTitleEl: headerTitleEl,
560
- headerRenameBtn: headerRenameBtn,
561
- headerInfoBtn: $("header-info-btn"),
562
- getWs: function () { return ws; },
563
- get connected() { return store.getState().connected; },
564
- get activeSessionId() { return store.getState().activeSessionId; },
565
- get cliSessionId() { return store.getState().cliSessionId; },
566
- get historyFrom() { return store.getState().historyFrom; },
567
- set historyFrom(v) { store.setState({ historyFrom: v }); },
568
- get loadingMore() { return loadingMore; },
569
- set loadingMore(v) { loadingMore = v; },
570
- // Rendering state accessors for prependOlderHistory
571
- getCurrentMsgEl: function () { return store.getState().currentMsgEl; },
572
- setCurrentMsgEl: function (v) { store.setState({ currentMsgEl: v }); },
573
- getActivityEl: getActivityEl, setActivityEl: setActivityEl,
574
- getCurrentFullText: function () { return store.getState().currentFullText; },
575
- setCurrentFullText: function (v) { store.setState({ currentFullText: v }); },
576
- getTurnCounter: getTurnCounter, setTurnCounter: setTurnCounter,
577
- saveToolState: saveToolState, resetToolState: resetToolState, restoreToolState: restoreToolState,
578
- getContextData: getContextData, setContextData: setContextData,
579
- getSessionUsage: getSessionUsage, setSessionUsage: setSessionUsage,
580
- setPrependAnchor: setPrependAnchor, getPrependAnchor: getPrependAnchor,
581
- processMessage: processMessage,
582
- finalizeAssistantBlock: finalizeAssistantBlock,
583
- updateContextPanel: updateContextPanel,
584
- updateUsagePanel: updateUsagePanel,
585
- onSessionSearchHistoryPrepended: onSessionSearchHistoryPrepended,
586
- });
546
+ initHeader();
587
547
 
588
548
  // --- Skill Install module ---
589
549
  initSkillInstall();
@@ -601,44 +561,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
601
561
  initPanels();
602
562
 
603
563
  // --- Rendering module ---
604
- initRendering({
605
- messagesEl: messagesEl,
606
- inputEl: inputEl,
607
- sendBtn: sendBtn,
608
- suggestionChipsEl: suggestionChipsEl,
609
- newMsgBtn: newMsgBtn,
610
- newMsgBtnDefault: newMsgBtnDefault,
611
- newMsgBtnActivity: newMsgBtnActivity,
612
- CLAUDE_CODE_AVATAR: CLAUDE_CODE_AVATAR,
613
- // Functions
614
- getScheduledMsgEl: getScheduledMsgEl,
615
- renderMarkdown: renderMarkdown,
616
- highlightCodeBlocks: highlightCodeBlocks,
617
- renderMermaidBlocks: renderMermaidBlocks,
618
- closeToolGroup: closeToolGroup,
619
- copyToClipboard: copyToClipboard,
620
- escapeHtml: escapeHtml,
621
- iconHtml: iconHtml,
622
- refreshIcons: refreshIcons,
623
- showImageModal: showImageModal,
624
- showPasteModal: showPasteModal,
625
- userAvatarUrl: userAvatarUrl,
626
- sendMessage: sendMessage,
627
- openTerminal: function () { openTerminal(); },
628
- getChatLayout: getChatLayout,
629
- getWs: function () { return ws; },
630
- getDmTargetUser: function () { return store.getState().dmTargetUser; },
631
- setPendingTermCommand: function (v) { store.setState({ pendingTermCommand: v }); },
632
- getProcessing: function () { return store.getState().processing; },
633
- get myUserId() { return store.getState().myUserId; },
634
- get cachedAllUsers() { return store.getState().cachedAllUsers; },
635
- });
564
+ initRendering();
636
565
 
637
566
  // --- Tools module ---
638
567
  initTools({
639
568
  $: $,
640
- get ws() { return ws; },
641
- get connected() { return store.getState().connected; },
569
+ get ws() { return _getWsRef(); },
570
+ get connected() { return store.get('connected'); },
642
571
  get turnCounter() { return getTurnCounter(); },
643
572
  messagesEl: messagesEl,
644
573
  inputEl: inputEl,
@@ -652,12 +581,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
652
581
  var cd = getContextData();
653
582
  return cd.contextWindow > 0 ? Math.round((cd.input / cd.contextWindow) * 100) : 0;
654
583
  },
655
- isMateDm: function () { return store.getState().dmMode && store.getState().dmTargetUser && store.getState().dmTargetUser.isMate; },
656
- getMateName: function () { return store.getState().dmTargetUser ? (store.getState().dmTargetUser.displayName || "Mate") : "Mate"; },
584
+ isMateDm: function () { return store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate; },
585
+ getMateName: function () { return store.get('dmTargetUser') ? (store.get('dmTargetUser').displayName || "Mate") : "Mate"; },
657
586
  getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
658
587
  getClaudeAvatar: function () { return CLAUDE_CODE_AVATAR; },
659
588
  getMateById: function (id) {
660
- var ml = store.getState().cachedMatesList;
589
+ var ml = store.get('cachedMatesList');
661
590
  if (!id || !ml) return null;
662
591
  for (var i = 0; i < ml.length; i++) {
663
592
  if (ml[i].id === id) return ml[i];
@@ -708,15 +637,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
708
637
  window.addEventListener("popstate", function () {
709
638
  var m = location.pathname.match(/^\/p\/([a-z0-9_-]+)/);
710
639
  var newSlug = m ? m[1] : null;
711
- if (newSlug && newSlug !== store.getState().currentSlug) {
640
+ if (newSlug && newSlug !== store.get('currentSlug')) {
712
641
  resetFileBrowser();
713
642
  closeArchive();
714
643
  if (isSchedulerOpen()) closeScheduler();
715
644
  resetScheduler(newSlug);
716
- store.setState({ currentSlug: newSlug });
645
+ store.set({ currentSlug: newSlug });
717
646
  basePath = "/p/" + newSlug + "/";
718
647
  wsPath = "/p/" + newSlug + "/ws";
719
- store.setState({ basePath: basePath, wsPath: wsPath });
648
+ store.set({ basePath: basePath, wsPath: wsPath });
720
649
  resetClientState();
721
650
  connect();
722
651
  }
@@ -740,17 +669,17 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
740
669
 
741
670
  // --- Input module (sendMessage, autoResize, paste/image, slash menu, input handlers) ---
742
671
  initInput({
743
- get ws() { return ws; },
744
- get connected() { return store.getState().connected; },
745
- get processing() { return store.getState().processing; },
672
+ get ws() { return _getWsRef(); },
673
+ get connected() { return store.get('connected'); },
674
+ get processing() { return store.get('processing'); },
746
675
  get basePath() { return basePath; },
747
676
  inputEl: inputEl,
748
677
  sendBtn: sendBtn,
749
678
  slashMenu: slashMenu,
750
679
  messagesEl: messagesEl,
751
680
  imagePreviewBar: imagePreviewBar,
752
- slashCommands: function() { return store.getState().slashCommands; },
753
- messageUuidMap: function() { return store.getState().messageUuidMap; },
681
+ slashCommands: function() { return store.get('slashCommands'); },
682
+ messageUuidMap: function() { return store.get('messageUuidMap'); },
754
683
  addUserMessage: addUserMessage,
755
684
  addSystemMessage: addSystemMessage,
756
685
  toggleUsagePanel: toggleUsagePanel,
@@ -759,19 +688,20 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
759
688
  resetContextData: resetContextData,
760
689
  showImageModal: showImageModal,
761
690
  hideSuggestionChips: hideSuggestionChips,
691
+ getGhostSuggestion: function () { return _renGetGhostSuggestion(); },
762
692
  setSendBtnMode: setSendBtnMode,
763
- isDmMode: function () { return store.getState().dmMode && !(store.getState().dmTargetUser && store.getState().dmTargetUser.isMate); },
764
- getDmKey: function () { return store.getState().dmKey; },
693
+ isDmMode: function () { return store.get('dmMode') && !(store.get('dmTargetUser') && store.get('dmTargetUser').isMate); },
694
+ getDmKey: function () { return store.get('dmKey'); },
765
695
  handleDmSend: function () { handleDmSend(); },
766
- isDebateEndedMode: function () { return store.getState().debateEndedMode; },
696
+ isDebateEndedMode: function () { return store.get('debateEndedMode'); },
767
697
  handleDebateEndedSend: function () { handleDebateEndedSend(); },
768
- isDebateConcludeMode: function () { return store.getState().debateConcludeMode; },
698
+ isDebateConcludeMode: function () { return store.get('debateConcludeMode'); },
769
699
  handleDebateConcludeSend: function () { handleDebateConcludeSend(); },
770
- isDebateFloorMode: function () { return store.getState().debateFloorMode; },
700
+ isDebateFloorMode: function () { return store.get('debateFloorMode'); },
771
701
  handleDebateFloorSend: function () { handleDebateFloorSend(); },
772
- isMateDm: function () { return store.getState().dmMode && store.getState().dmTargetUser && store.getState().dmTargetUser.isMate; },
773
- getDmMateId: function () { return (store.getState().dmMode && store.getState().dmTargetUser && store.getState().dmTargetUser.isMate) ? dmTargetUser.id : null; },
774
- getMateName: function () { return store.getState().dmTargetUser ? (store.getState().dmTargetUser.displayName || "Mate") : "Mate"; },
702
+ isMateDm: function () { return store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate; },
703
+ getDmMateId: function () { return (store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate) ? dmTargetUser.id : null; },
704
+ getMateName: function () { return store.get('dmTargetUser') ? (store.get('dmTargetUser').displayName || "Mate") : "Mate"; },
775
705
  getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
776
706
  showMatePreThinking: function () { showMatePreThinking(); },
777
707
  showClaudePreThinking: function () { showClaudePreThinking(); },
@@ -779,12 +709,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
779
709
 
780
710
  // --- @Mention module ---
781
711
  initMention({
782
- get ws() { return ws; },
783
- get connected() { return store.getState().connected; },
712
+ get ws() { return _getWsRef(); },
713
+ get connected() { return store.get('connected'); },
784
714
  inputEl: inputEl,
785
715
  messagesEl: messagesEl,
786
- matesList: function () { return store.getState().cachedMatesList || []; },
787
- availableBuiltins: function () { return store.getState().cachedAvailableBuiltins || []; },
716
+ matesList: function () { return store.get('cachedMatesList') || []; },
717
+ availableBuiltins: function () { return store.get('cachedAvailableBuiltins') || []; },
788
718
  scrollToBottom: scrollToBottom,
789
719
  addUserMessage: addUserMessage,
790
720
  addCopyHandler: addCopyHandler,
@@ -795,15 +725,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
795
725
 
796
726
  // --- Debate module ---
797
727
  initDebate({
798
- get ws() { return ws; },
728
+ get ws() { return _getWsRef(); },
799
729
  sendWs: function (obj) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(obj)); },
800
730
  messagesEl: messagesEl,
801
731
  addToMessages: function (el) { addToMessages(el); },
802
732
  scrollToBottom: scrollToBottom,
803
733
  addCopyHandler: addCopyHandler,
804
- matesList: function () { return store.getState().cachedMatesList || []; },
805
- availableBuiltins: function () { return store.getState().cachedAvailableBuiltins || []; },
806
- currentMateId: function () { return (store.getState().dmTargetUser && store.getState().dmTargetUser.isMate) ? store.getState().dmTargetUser.id : null; },
734
+ matesList: function () { return store.get('cachedMatesList') || []; },
735
+ availableBuiltins: function () { return store.get('cachedAvailableBuiltins') || []; },
736
+ currentMateId: function () { return (store.get('dmTargetUser') && store.get('dmTargetUser').isMate) ? store.get('dmTargetUser').id : null; },
807
737
  requireSkills: requireSkills,
808
738
  showDebateEndedMode: function (msg) { showDebateEndedMode(msg); },
809
739
  });
@@ -833,14 +763,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
833
763
  initAdmin({
834
764
  get projectList() { return getCachedProjects(); },
835
765
  });
836
- var myPermissions = null; // null = single-user, all allowed
837
766
  fetch("/api/me").then(function (r) { return r.json(); }).then(function (d) {
838
- if (d.multiUser) { store.setState({ isMultiUserMode: true }); }
839
- if (d.user && d.user.id) { store.setState({ myUserId: d.user.id }); }
840
- if (d.permissions) myPermissions = d.permissions;
767
+ if (d.multiUser) { store.set({ isMultiUserMode: true }); }
768
+ if (d.user && d.user.id) { store.set({ myUserId: d.user.id }); }
769
+ if (d.permissions) store.set({ permissions: d.permissions });
841
770
  if (d.mustChangePin) showForceChangePinOverlay();
842
771
  // Single-user mode: clear user strip skeletons immediately (no presence message will arrive)
843
- if (!store.getState().isMultiUserMode) {
772
+ if (!store.get('isMultiUserMode')) {
844
773
  var usersContainer = document.getElementById("icon-strip-users");
845
774
  if (usersContainer) {
846
775
  usersContainer.innerHTML = "";
@@ -849,28 +778,29 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
849
778
  }
850
779
  initCursorToggle();
851
780
  // Apply RBAC UI gating
852
- if (myPermissions) {
853
- if (!myPermissions.terminal) {
781
+ var _perms = store.get('permissions');
782
+ if (_perms) {
783
+ if (!_perms.terminal) {
854
784
  var termSideBtn = document.getElementById("terminal-sidebar-btn");
855
785
  if (termSideBtn) termSideBtn.style.display = "none";
856
786
  }
857
- if (!myPermissions.fileBrowser) {
787
+ if (!_perms.fileBrowser) {
858
788
  var fbBtn = document.getElementById("file-browser-btn");
859
789
  if (fbBtn) fbBtn.style.display = "none";
860
790
  }
861
- if (!myPermissions.skills) {
791
+ if (!_perms.skills) {
862
792
  var sBtn = document.getElementById("skills-btn");
863
793
  if (sBtn) sBtn.style.display = "none";
864
794
  var msBtn = document.getElementById("mate-skills-btn");
865
795
  if (msBtn) msBtn.style.display = "none";
866
796
  }
867
- if (!myPermissions.scheduledTasks) {
797
+ if (!_perms.scheduledTasks) {
868
798
  var schBtn = document.getElementById("scheduler-btn");
869
799
  if (schBtn) schBtn.style.display = "none";
870
800
  var mateSchBtn = document.getElementById("mate-scheduler-btn");
871
801
  if (mateSchBtn) mateSchBtn.style.display = "none";
872
802
  }
873
- if (!myPermissions.createProject) {
803
+ if (!_perms.createProject) {
874
804
  var addProjBtn = document.getElementById("icon-strip-add");
875
805
  if (addProjBtn) addProjBtn.style.display = "none";
876
806
  }
@@ -878,7 +808,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
878
808
  }).catch(function () {});
879
809
  // Hide server settings and update controls for non-admin users in multi-user mode
880
810
  checkAdminAccess().then(function (isAdmin) {
881
- if (store.getState().isMultiUserMode && !isAdmin) {
811
+ if (store.get('isMultiUserMode') && !isAdmin) {
882
812
  var settingsBtn = document.getElementById("server-settings-btn");
883
813
  if (settingsBtn) settingsBtn.style.display = "none";
884
814
  var updatePill = document.getElementById("update-pill-wrap");
@@ -889,8 +819,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
889
819
  // --- Notifications module (viewport, banners, notifications, debug, service worker) ---
890
820
  initNotifications({
891
821
  $: $,
892
- get ws() { return ws; },
893
- get connected() { return store.getState().connected; },
822
+ get ws() { return _getWsRef(); },
823
+ get connected() { return store.get('connected'); },
894
824
  messagesEl: messagesEl,
895
825
  sessionListEl: sessionListEl,
896
826
  scrollToBottom: scrollToBottom,
@@ -901,33 +831,33 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
901
831
 
902
832
  // --- Server Settings ---
903
833
  initServerSettings({
904
- get ws() { return ws; },
905
- get projectName() { return store.getState().projectName; },
906
- get currentSlug() { return store.getState().currentSlug; },
834
+ get ws() { return _getWsRef(); },
835
+ get projectName() { return store.get('projectName'); },
836
+ get currentSlug() { return store.get('currentSlug'); },
907
837
  wsPath: wsPath,
908
- get currentModels() { return store.getState().currentModels; },
909
- set currentModels(v) { store.setState({ currentModels: v }); updateConfigChip(); },
910
- get currentModel() { return store.getState().currentModel; },
911
- get currentMode() { return store.getState().currentMode; },
912
- get currentEffort() { return store.getState().currentEffort; },
913
- get currentBetas() { return store.getState().currentBetas; },
914
- get currentThinking() { return store.getState().currentThinking; },
915
- get currentThinkingBudget() { return store.getState().currentThinkingBudget; },
838
+ get currentModels() { return store.get('currentModels'); },
839
+ set currentModels(v) { store.set({ currentModels: v }); },
840
+ get currentModel() { return store.get('currentModel'); },
841
+ get currentMode() { return store.get('currentMode'); },
842
+ get currentEffort() { return store.get('currentEffort'); },
843
+ get currentBetas() { return store.get('currentBetas'); },
844
+ get currentThinking() { return store.get('currentThinking'); },
845
+ get currentThinkingBudget() { return store.get('currentThinkingBudget'); },
916
846
  setContextView: function (v) { _panSetContextView(v); },
917
847
  applyContextView: function (v) { _panApplyContextView(v); },
918
848
  });
919
849
 
920
850
  // --- Project Settings ---
921
851
  initProjectSettings({
922
- get ws() { return ws; },
923
- get connected() { return store.getState().connected; },
924
- get currentModels() { return store.getState().currentModels; },
925
- get currentModel() { return store.getState().currentModel; },
926
- get currentMode() { return store.getState().currentMode; },
927
- get currentEffort() { return store.getState().currentEffort; },
928
- get currentBetas() { return store.getState().currentBetas; },
929
- get currentThinking() { return store.getState().currentThinking; },
930
- get currentThinkingBudget() { return store.getState().currentThinkingBudget; },
852
+ get ws() { return _getWsRef(); },
853
+ get connected() { return store.get('connected'); },
854
+ get currentModels() { return store.get('currentModels'); },
855
+ get currentModel() { return store.get('currentModel'); },
856
+ get currentMode() { return store.get('currentMode'); },
857
+ get currentEffort() { return store.get('currentEffort'); },
858
+ get currentBetas() { return store.get('currentBetas'); },
859
+ get currentThinking() { return store.get('currentThinking'); },
860
+ get currentThinkingBudget() { return store.get('currentThinkingBudget'); },
931
861
  }, getEmojiCategories());
932
862
 
933
863
  // --- QR code ---
@@ -937,10 +867,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
937
867
 
938
868
  // --- File browser ---
939
869
  initFileBrowser({
940
- get ws() { return ws; },
941
- get connected() { return store.getState().connected; },
942
- get activeSessionId() { return store.getState().activeSessionId; },
943
- get cwd() { return store.getState().cwd; },
870
+ get ws() { return _getWsRef(); },
871
+ get connected() { return store.get('connected'); },
872
+ get activeSessionId() { return store.get('activeSessionId'); },
873
+ get cwd() { return store.get('cwd'); },
944
874
  messagesEl: messagesEl,
945
875
  fileTreeEl: $("file-tree"),
946
876
  fileViewerEl: $("file-viewer"),
@@ -948,8 +878,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
948
878
 
949
879
  // --- Terminal ---
950
880
  initTerminal({
951
- get ws() { return ws; },
952
- get connected() { return store.getState().connected; },
881
+ get ws() { return _getWsRef(); },
882
+ get connected() { return store.get('connected'); },
953
883
  terminalContainerEl: $("terminal-container"),
954
884
  terminalBodyEl: $("terminal-body"),
955
885
  fileViewerEl: $("file-viewer"),
@@ -957,8 +887,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
957
887
 
958
888
  // --- Context Sources ---
959
889
  initContextSources({
960
- get ws() { return ws; },
961
- get connected() { return store.getState().connected; },
890
+ get ws() { return _getWsRef(); },
891
+ get connected() { return store.get('connected'); },
962
892
  });
963
893
 
964
894
  // --- Chrome Extension Bridge -> modules/app-misc.js
@@ -986,8 +916,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
986
916
  // --- In-session search (Cmd+F / Ctrl+F) ---
987
917
  initSessionSearch({
988
918
  messagesEl: messagesEl,
989
- get ws() { return ws; },
990
- getHistoryFrom: function () { return store.getState().historyFrom; },
919
+ get ws() { return _getWsRef(); },
920
+ getHistoryFrom: function () { return store.get('historyFrom'); },
991
921
  });
992
922
  var findInSessionBtn = $("find-in-session-btn");
993
923
  if (findInSessionBtn) {
@@ -998,8 +928,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
998
928
 
999
929
  // --- Sticky Notes ---
1000
930
  initStickyNotes({
1001
- get ws() { return ws; },
1002
- get connected() { return store.getState().connected; },
931
+ get ws() { return _getWsRef(); },
932
+ get connected() { return store.get('connected'); },
1003
933
  });
1004
934
 
1005
935
  // --- Sticky Notes sidebar button (create new note) ---
@@ -1065,7 +995,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1065
995
  if (debateBtn) {
1066
996
  debateBtn.addEventListener("click", function () {
1067
997
  var contextMessages = dmMessageCache.map(function (m) {
1068
- return { text: m.text, isMate: m.from !== store.getState().myUserId };
998
+ return { text: m.text, isMate: m.from !== store.get('myUserId') };
1069
999
  });
1070
1000
  openDebateModal({ dmContext: contextMessages });
1071
1001
  });
@@ -1099,19 +1029,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1099
1029
  initEmailDefaultsModal();
1100
1030
 
1101
1031
  // --- Skills ---
1102
- initSkills({
1103
- get ws() { return ws; },
1104
- get connected() { return store.getState().connected; },
1105
- basePath: basePath,
1106
- openTerminal: function () { openTerminal(); },
1107
- sendTerminalCommand: function (cmd) { sendTerminalCommand(cmd); },
1108
- });
1032
+ initSkills();
1109
1033
 
1110
1034
  // --- Scheduler ---
1111
1035
  initScheduler({
1112
- get ws() { return ws; },
1113
- get connected() { return store.getState().connected; },
1114
- get activeSessionId() { return store.getState().activeSessionId; },
1036
+ get ws() { return _getWsRef(); },
1037
+ get connected() { return store.get('connected'); },
1038
+ get activeSessionId() { return store.get('activeSessionId'); },
1115
1039
  basePath: basePath,
1116
1040
  currentSlug: currentSlug, // init-time snapshot, scheduler uses for initial setup
1117
1041
  openRalphWizard: function (source) { openRalphWizard(source); },
@@ -1145,278 +1069,29 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1145
1069
  function clearRemoteCursors() { _curClearRemoteCursors(); }
1146
1070
 
1147
1071
  // --- Cursors module ---
1148
- initCursors({
1149
- messagesEl: messagesEl,
1150
- registerTooltip: registerTooltip,
1151
- get ws() { return ws; },
1152
- get isMultiUserMode() { return store.getState().isMultiUserMode; },
1153
- });
1072
+ initCursors();
1154
1073
 
1155
1074
  // --- Rate Limit module ---
1156
1075
  initRateLimit();
1157
1076
 
1158
1077
  // --- Projects module ---
1159
- initProjects({
1160
- $: $,
1161
- messagesEl: messagesEl,
1162
- newMsgBtn: newMsgBtn,
1163
- connectOverlay: connectOverlay,
1164
- userAvatarUrl: userAvatarUrl,
1165
- checkAdminAccess: checkAdminAccess,
1166
- renderUserStrip: renderUserStrip,
1167
- renderIconStrip: renderIconStrip,
1168
- updateCrossProjectBlink: updateCrossProjectBlink,
1169
- showConfirm: showConfirm,
1170
- showToast: showToast,
1171
- showHomeHub: showHomeHub,
1172
- hideHomeHub: hideHomeHub,
1173
- isHomeHubVisible: isHomeHubVisible,
1174
- spawnDustParticles: spawnDustParticles,
1175
- getStatusDot: getStatusDot,
1176
- // Rendering state accessors
1177
- setCurrentMsgEl: function (v) { store.setState({ currentMsgEl: v }); },
1178
- setCurrentFullText: function (v) { store.setState({ currentFullText: v }); },
1179
- setTurnCounter: setTurnCounter,
1180
- setPrependAnchor: setPrependAnchor,
1181
- setActivityEl: setActivityEl,
1182
- setIsUserScrolledUp: setIsUserScrolledUp,
1183
- // Reset helpers
1184
- closeSearch: function () { if (isSearchOpen()) closeSearch(); },
1185
- resetToolState: resetToolState,
1186
- clearPendingImages: clearPendingImages,
1187
- setRewindMode: function (v) { setRewindMode(v); },
1188
- setActivity: setActivity,
1189
- setStatus: setStatus,
1190
- enableMainInput: enableMainInput,
1191
- resetUsage: resetUsage,
1192
- resetTurnMetaCost: resetTurnMetaCost,
1193
- resetContext: resetContext,
1194
- resetRateLimitState: resetRateLimitState,
1195
- hideSuggestionChips: hideSuggestionChips,
1196
- closeSessionInfoPopover: closeSessionInfoPopover,
1197
- stopUrgentBlink: stopUrgentBlink,
1198
- resetDebateState: resetDebateState,
1199
- removeDebateBottomBar: removeDebateBottomBar,
1200
- // Project switching helpers
1201
- exitDmMode: exitDmMode,
1202
- resetFileBrowser: resetFileBrowser,
1203
- closeArchive: closeArchive,
1204
- hideMemory: hideMemory,
1205
- isSchedulerOpen: isSchedulerOpen,
1206
- closeScheduler: closeScheduler,
1207
- resetScheduler: resetScheduler,
1208
- connect: function () { connect(); },
1209
- cancelReconnect: function () { _connCancelReconnect(); },
1210
- getWs: function () { return ws; },
1211
- setWs: function (v) { ws = v; _setWsRef(v); },
1212
- setConnected: function (v) { store.setState({ connected: v }); },
1213
- setProcessing: function (v) { store.setState({ processing: v }); },
1214
- setCurrentSlug: function (v) { store.setState({ currentSlug: v }); },
1215
- setBasePath: function (v) { basePath = v; },
1216
- setWsPath: function (v) { wsPath = v; },
1217
- setMessageUuidMap: function (v) { store.setState({ messageUuidMap: v }); },
1218
- setHistoryFrom: function (v) { store.setState({ historyFrom: v }); },
1219
- setHistoryTotal: function (v) { store.setState({ historyTotal: v }); },
1220
- setLoadingMore: function (v) { loadingMore = v; },
1221
- getHeaderContextEl: function () { return store.getState().headerContextEl; },
1222
- setHeaderContextEl: function (v) { store.setState({ headerContextEl: v }); },
1223
- setDebateStickyState: function (v) { store.setState({ debateStickyState: v }); },
1224
- setCachedOnlineIds: function (v) { store.setState({ cachedOnlineIds: v }); },
1225
- setCachedAllUsers: function (v) { store.setState({ cachedAllUsers: v }); },
1226
- setCachedDmFavorites: function (v) { store.setState({ cachedDmFavorites: v }); },
1227
- setCachedDmConversations: function (v) { store.setState({ cachedDmConversations: v }); },
1228
- get currentSlug() { return store.getState().currentSlug; },
1229
- get connected() { return store.getState().connected; },
1230
- get processing() { return store.getState().processing; },
1231
- get loopActive() { return store.getState().loopActive; },
1232
- get dmMode() { return store.getState().dmMode; },
1233
- get dmTargetUser() { return store.getState().dmTargetUser; },
1234
- get activeSessionId() { return store.getState().activeSessionId; },
1235
- get isHeadlessMode() { return store.getState().isHeadlessMode; },
1236
- get isOsUsers() { return store.getState().isOsUsers; },
1237
- get mateProjectSlug() { return store.getState().mateProjectSlug; },
1238
- get savedMainSlug() { return store.getState().savedMainSlug; },
1239
- get myUserId() { return store.getState().myUserId; },
1240
- get cachedAllUsers() { return store.getState().cachedAllUsers; },
1241
- get cachedOnlineIds() { return store.getState().cachedOnlineIds; },
1242
- get cachedDmFavorites() { return store.getState().cachedDmFavorites; },
1243
- get cachedDmConversations() { return store.getState().cachedDmConversations; },
1244
- get dmUnread() { return store.getState().dmUnread; },
1245
- get dmRemovedUsers() { return store.getState().dmRemovedUsers; },
1246
- get cachedMatesList() { return store.getState().cachedMatesList; },
1247
- });
1078
+ initProjects();
1248
1079
 
1249
1080
  // --- Home Hub module ---
1250
- initHomeHub({
1251
- $: $,
1252
- exitDmMode: exitDmMode,
1253
- openDm: openDm,
1254
- mateAvatarUrl: mateAvatarUrl,
1255
- escapeHtml: escapeHtml,
1256
- switchProject: switchProject,
1257
- openSchedulerToTab: openSchedulerToTab,
1258
- getPlaybooks: getPlaybooks,
1259
- openPlaybook: openPlaybook,
1260
- getPlaybookForTip: getPlaybookForTip,
1261
- renderProjectList: renderProjectList,
1262
- get dmMode() { return store.getState().dmMode; },
1263
- get ws() { return ws; },
1264
- get currentSlug() { return store.getState().currentSlug; },
1265
- get cachedProjects() { return getCachedProjects(); },
1266
- get cachedMatesList() { return store.getState().cachedMatesList; },
1267
- });
1081
+ initHomeHub();
1268
1082
 
1269
1083
  // --- DM module ---
1270
- var _dmCtx = {
1271
- // Functions
1272
- connect: connect,
1273
- resetClientState: resetClientState,
1274
- scrollToBottom: scrollToBottom,
1275
- autoResize: autoResize,
1276
- showDebateSticky: showDebateSticky,
1277
- updateDmBadge: updateDmBadge,
1278
- setCurrentDmUser: setCurrentDmUser,
1279
- renderProjectList: renderProjectList,
1280
- hideHomeHub: hideHomeHub,
1281
- hideNotes: hideNotes,
1282
- showMateSidebar: showMateSidebar,
1283
- hideMateSidebar: hideMateSidebar,
1284
- hideKnowledge: hideKnowledge,
1285
- hideMemory: hideMemory,
1286
- closeFileViewer: closeFileViewer,
1287
- closeTerminal: closeTerminal,
1288
- mateAvatarUrl: mateAvatarUrl,
1289
- userAvatarUrl: userAvatarUrl,
1290
- renderUserStrip: renderUserStrip,
1291
- openMobileSheet: openMobileSheet,
1292
- setMobileSheetMateData: setMobileSheetMateData,
1293
- closeDmUserPicker: closeDmUserPicker,
1294
- getProfileLang: getProfileLang,
1295
- isSchedulerOpen: isSchedulerOpen,
1296
- closeScheduler: closeScheduler,
1297
- requireClayMateInterview: requireClayMateInterview,
1298
- // DOM refs
1299
- messagesEl: messagesEl,
1300
- inputEl: inputEl,
1301
- };
1302
- // Mutable state for DM module (store-backed)
1303
- Object.defineProperties(_dmCtx, {
1304
- ws: { get: function() { return ws; }, enumerable: true },
1305
- dmMode: { get: function() { return store.getState().dmMode; }, set: function(v) { store.setState({ dmMode: v }); }, enumerable: true },
1306
- dmKey: { get: function() { return store.getState().dmKey; }, set: function(v) { store.setState({ dmKey: v }); }, enumerable: true },
1307
- dmTargetUser: { get: function() { return store.getState().dmTargetUser; }, set: function(v) { store.setState({ dmTargetUser: v }); }, enumerable: true },
1308
- dmMessageCache: { get: function() { return dmMessageCache; }, set: function(v) { dmMessageCache = v; }, enumerable: true },
1309
- dmUnread: { get: function() { return store.getState().dmUnread; }, enumerable: true },
1310
- dmRemovedUsers: { get: function() { return store.getState().dmRemovedUsers; }, enumerable: true },
1311
- cachedAllUsers: { get: function() { return store.getState().cachedAllUsers; }, enumerable: true },
1312
- cachedOnlineIds: { get: function() { return store.getState().cachedOnlineIds; }, enumerable: true },
1313
- cachedDmFavorites: { get: function() { return store.getState().cachedDmFavorites; }, set: function(v) { store.setState({ cachedDmFavorites: v }); }, enumerable: true },
1314
- cachedDmConversations: { get: function() { return store.getState().cachedDmConversations; }, enumerable: true },
1315
- cachedMatesList: { get: function() { return store.getState().cachedMatesList; }, enumerable: true },
1316
- cachedAvailableBuiltins: { get: function() { return store.getState().cachedAvailableBuiltins; }, set: function(v) { store.setState({ cachedAvailableBuiltins: v }); }, enumerable: true },
1317
- cachedProjects: { get: function() { return getCachedProjects(); }, enumerable: true },
1318
- mateProjectSlug: { get: function() { return store.getState().mateProjectSlug; }, set: function(v) { store.setState({ mateProjectSlug: v }); }, enumerable: true },
1319
- savedMainSlug: { get: function() { return store.getState().savedMainSlug; }, set: function(v) { store.setState({ savedMainSlug: v }); }, enumerable: true },
1320
- returningFromMateDm: { get: function() { return store.getState().returningFromMateDm; }, set: function(v) { store.setState({ returningFromMateDm: v }); }, enumerable: true },
1321
- pendingMateInterview: { get: function() { return store.getState().pendingMateInterview; }, set: function(v) { store.setState({ pendingMateInterview: v }); }, enumerable: true },
1322
- currentSlug: { get: function() { return store.getState().currentSlug; }, set: function(v) { store.setState({ currentSlug: v }); }, enumerable: true },
1323
- wsPath: { get: function() { return wsPath; }, set: function(v) { wsPath = v; }, enumerable: true },
1324
- basePath: { get: function() { return basePath; }, set: function(v) { basePath = v; }, enumerable: true },
1325
- activeSessionId: { get: function() { return store.getState().activeSessionId; }, enumerable: true },
1326
- myUserId: { get: function() { return store.getState().myUserId; }, enumerable: true },
1327
- });
1328
- initDm(_dmCtx);
1084
+ initDm();
1329
1085
 
1330
1086
  // --- Messages module (uses direct imports, no ctx injection needed) ---
1331
1087
 
1332
1088
  // --- Connection module ---
1333
- initConnection({
1334
- getWs: function () { return ws; },
1335
- setWs: function (v) { ws = v; _setWsRef(v); },
1336
- isConnected: function () { return store.getState().connected; },
1337
- setConnected: function (v) { store.setState({ connected: v }); },
1338
- setProcessing: function (v) { store.setState({ processing: v }); },
1339
- getWsPath: function () { return wsPath; },
1340
- getStatusDot: getStatusDot,
1341
- sendBtn: sendBtn,
1342
- connectOverlay: connectOverlay,
1343
- setSendBtnMode: setSendBtnMode,
1344
- hasSendableContent: hasSendableContent,
1345
- startVerbCycle: startVerbCycle,
1346
- stopVerbCycle: stopVerbCycle,
1347
- blinkIO: blinkIO,
1348
- isNotifAlertEnabled: isNotifAlertEnabled,
1349
- closeDmUserPicker: closeDmUserPicker,
1350
- setActivity: setActivity,
1351
- processMessage: processMessage,
1352
- onConnected: function () {
1353
- // Flush any extension messages that arrived before WS was ready
1354
- flushPendingExtMessages();
1355
-
1356
- // Reset terminal xterm instances (server will send fresh term_list)
1357
- resetTerminals();
1358
-
1359
- // Re-send push subscription on reconnect
1360
- if (window._pushSubscription) {
1361
- try {
1362
- ws.send(JSON.stringify({
1363
- type: "push_subscribe",
1364
- subscription: window._pushSubscription.toJSON(),
1365
- }));
1366
- } catch(e) {}
1367
- }
1368
-
1369
- // Request mates list
1370
- try {
1371
- ws.send(JSON.stringify({ type: "mate_list" }));
1372
- } catch(e) {}
1373
-
1374
- // If connecting to a mate project, request knowledge list for badge
1375
- if (store.getState().mateProjectSlug) {
1376
- try { ws.send(JSON.stringify({ type: "knowledge_list" })); } catch(e) {}
1377
- }
1378
-
1379
- // Session restore is now server-driven (user-presence.json).
1380
- // Mate DM restore is also server-driven via "restore_mate_dm" message.
1381
- // Fallback: if server doesn't restore DM within 2s, try localStorage
1382
- var savedDm = null;
1383
- try { savedDm = localStorage.getItem("clay-active-dm"); } catch (e) {}
1384
- if (savedDm && !store.getState().dmMode && !store.getState().mateProjectSlug) {
1385
- var dmFallbackTimer = setTimeout(function () {
1386
- if (!store.getState().dmMode && savedDm) {
1387
- console.log("[dm-restore] Server did not restore DM, using localStorage fallback:", savedDm);
1388
- openDm(savedDm);
1389
- }
1390
- }, 2000);
1391
- // Cancel fallback if server restores DM first
1392
- var patchedOnce = false;
1393
- var checkRestore = function (evt) {
1394
- try {
1395
- var d = JSON.parse(evt.data);
1396
- if (d.type === "restore_mate_dm" && !patchedOnce) {
1397
- patchedOnce = true;
1398
- clearTimeout(dmFallbackTimer);
1399
- }
1400
- } catch (e) {}
1401
- };
1402
- ws.addEventListener("message", checkRestore);
1403
- setTimeout(function () { ws.removeEventListener("message", checkRestore); }, 3000);
1404
- }
1405
- // Safety: clear returningFromMateDm after initial messages settle
1406
- if (store.getState().returningFromMateDm) {
1407
- setTimeout(function () {
1408
- if (store.getState().returningFromMateDm) {
1409
- store.setState({ returningFromMateDm: false });
1410
- }
1411
- }, 2000);
1412
- }
1413
- },
1414
- });
1089
+ initConnection();
1415
1090
 
1416
1091
  // --- Init ---
1417
1092
  lucide.createIcons();
1418
1093
  connect();
1419
- if (!store.getState().currentSlug) {
1094
+ if (!store.get('currentSlug')) {
1420
1095
  showHomeHub();
1421
1096
  } else if (location.hash === "#scheduler") {
1422
1097
  // Restore scheduler view after refresh