clay-server 5.3.0-beta.5 → 5.3.0-beta.7

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 (185) hide show
  1. package/lib/clay-product-control-tools.js +2 -2
  2. package/lib/clay-product-control.js +1 -1
  3. package/lib/clay-screen-controls.js +1 -0
  4. package/lib/clay-split-view-awareness.js +5 -2
  5. package/lib/clay-split-view-controls.js +14 -7
  6. package/lib/clay-split-view-input.js +5 -4
  7. package/lib/clay-split-view-render-proof.js +14 -4
  8. package/lib/clay-view-workspace-input.js +71 -0
  9. package/lib/project-admin-overview.js +22 -11
  10. package/lib/project-background-tasks.js +76 -0
  11. package/lib/project-connection.js +1 -1
  12. package/lib/project-file-history.js +11 -9
  13. package/lib/project-file-watch.js +26 -7
  14. package/lib/project-filesystem.js +5 -4
  15. package/lib/project-sessions.js +12 -5
  16. package/lib/project-shared-browser.js +7 -3
  17. package/lib/project-split-view-document.js +16 -2
  18. package/lib/project-split-views.js +27 -297
  19. package/lib/project-user-message.js +4 -3
  20. package/lib/project-vendor-login.js +2 -2
  21. package/lib/project-view-input.js +11 -0
  22. package/lib/project-view-pair.js +26 -0
  23. package/lib/project-view-store.js +348 -0
  24. package/lib/project-view-terminal-binding.js +16 -0
  25. package/lib/project-view-workspace.js +126 -0
  26. package/lib/project-worker-conversation.js +5 -0
  27. package/lib/project.js +1 -0
  28. package/lib/public/app.js +9 -0
  29. package/lib/public/css/contextual-clay.css +2 -1
  30. package/lib/public/css/issues.css +3 -0
  31. package/lib/public/css/mate-conversation.css +1 -1
  32. package/lib/public/css/pane.css +5 -1
  33. package/lib/public/css/pending-message-queue.css +24 -19
  34. package/lib/public/css/project-admin-overview.css +42 -13
  35. package/lib/public/css/right-workbench.css +0 -1
  36. package/lib/public/css/scheduled-tasks.css +7 -0
  37. package/lib/public/css/shared-browser.css +31 -8
  38. package/lib/public/css/split-view-layout.css +129 -10
  39. package/lib/public/css/tool-pane.css +124 -0
  40. package/lib/public/index.html +6 -6
  41. package/lib/public/modules/agent-message-bubbles.js +96 -0
  42. package/lib/public/modules/app-header.js +6 -0
  43. package/lib/public/modules/app-messages.js +26 -9
  44. package/lib/public/modules/background-task-previews.js +8 -0
  45. package/lib/public/modules/background-task-viewer.js +97 -0
  46. package/lib/public/modules/background-tasks-ui.js +34 -125
  47. package/lib/public/modules/chat-bubble-renderer.js +11 -5
  48. package/lib/public/modules/clay-file-links.js +2 -1
  49. package/lib/public/modules/clay-split-view-screen.js +6 -3
  50. package/lib/public/modules/clay-tool-pane-screen.js +35 -0
  51. package/lib/public/modules/contextual-clay-geometry.js +7 -3
  52. package/lib/public/modules/file-history-snapshot.js +12 -0
  53. package/lib/public/modules/file-pane-entrypoints.js +55 -0
  54. package/lib/public/modules/file-pane-history.js +78 -0
  55. package/lib/public/modules/file-pane-instances.js +140 -0
  56. package/lib/public/modules/file-pane-links.js +41 -0
  57. package/lib/public/modules/file-pane-render.js +48 -0
  58. package/lib/public/modules/file-pane-review.js +26 -0
  59. package/lib/public/modules/file-pane-toolbar.js +54 -0
  60. package/lib/public/modules/file-viewer-source.js +70 -0
  61. package/lib/public/modules/filebrowser.js +43 -82
  62. package/lib/public/modules/git-panel.js +5 -0
  63. package/lib/public/modules/issues.js +3 -4
  64. package/lib/public/modules/linear-panel.js +2 -2
  65. package/lib/public/modules/mate-knowledge-workbench.js +10 -6
  66. package/lib/public/modules/notifications.js +4 -1
  67. package/lib/public/modules/pane-activation.js +7 -3
  68. package/lib/public/modules/pane-binding.js +5 -1
  69. package/lib/public/modules/pane-browser-bridge.js +6 -2
  70. package/lib/public/modules/pane-browser-transport.js +110 -0
  71. package/lib/public/modules/pane-header-tooltips.js +32 -0
  72. package/lib/public/modules/pending-message-queue-drag.js +69 -0
  73. package/lib/public/modules/pending-message-queue.js +3 -33
  74. package/lib/public/modules/permission-control.js +6 -5
  75. package/lib/public/modules/plantuml-preview.js +12 -12
  76. package/lib/public/modules/project-admin-overview.js +125 -10
  77. package/lib/public/modules/project-grouping.js +9 -0
  78. package/lib/public/modules/right-workbench.js +34 -15
  79. package/lib/public/modules/scheduled-tasks.js +7 -6
  80. package/lib/public/modules/server-settings-controls.js +33 -4
  81. package/lib/public/modules/session-folder-toolbar.js +1 -1
  82. package/lib/public/modules/session-tool-item.js +86 -0
  83. package/lib/public/modules/settings-select.js +2 -1
  84. package/lib/public/modules/shared-browser-tabs.js +37 -21
  85. package/lib/public/modules/shared-browser.js +69 -9
  86. package/lib/public/modules/sidebar-projects.js +1 -10
  87. package/lib/public/modules/split-pane-renderer.js +1 -0
  88. package/lib/public/modules/split-session-empty-pane.js +47 -0
  89. package/lib/public/modules/split-view-create-menu.js +74 -65
  90. package/lib/public/modules/split-view-drag-preview.js +90 -0
  91. package/lib/public/modules/split-view-layout-client.js +1 -1
  92. package/lib/public/modules/split-view-layout-scope.js +4 -0
  93. package/lib/public/modules/split-view-picker-actions.js +71 -0
  94. package/lib/public/modules/split-view-picker-render.js +81 -0
  95. package/lib/public/modules/split-view-presentation-drag.js +36 -13
  96. package/lib/public/modules/split-view-presentation-drop.js +21 -18
  97. package/lib/public/modules/split-view-presentation-renderer.js +22 -17
  98. package/lib/public/modules/split-view-presentations.js +25 -33
  99. package/lib/public/modules/split-view-worker-activity.js +2 -2
  100. package/lib/public/modules/split-view-worker-transcript.js +70 -33
  101. package/lib/public/modules/split-view-workers.js +6 -4
  102. package/lib/public/modules/split-view.js +9 -2
  103. package/lib/public/modules/sticky-notes-browser.js +2 -2
  104. package/lib/public/modules/terminal-viewport.js +14 -0
  105. package/lib/public/modules/terminal.js +49 -23
  106. package/lib/public/modules/theme-palette.js +177 -0
  107. package/lib/public/modules/theme.js +2 -180
  108. package/lib/public/modules/tool-pane-chrome.js +88 -0
  109. package/lib/public/modules/tool-pane-drag.js +134 -0
  110. package/lib/public/modules/tool-pane-layout.js +95 -0
  111. package/lib/public/modules/tool-pane-legacy.js +60 -0
  112. package/lib/public/modules/tool-pane-tree.js +51 -0
  113. package/lib/public/modules/tools.js +5 -89
  114. package/lib/public/modules/tooltip.js +32 -6
  115. package/lib/public/modules/view-legacy-coordinates.js +16 -0
  116. package/lib/public/modules/view-mutations.js +24 -0
  117. package/lib/public/modules/view-pair-presentation.js +74 -0
  118. package/lib/public/modules/view-pair-validation.js +12 -0
  119. package/lib/public/modules/view-presentation-state.js +37 -0
  120. package/lib/public/modules/view-workspace-controller.js +210 -0
  121. package/lib/public/modules/view-workspace-state.js +103 -0
  122. package/lib/public/modules/view-workspace-validation.js +47 -0
  123. package/lib/public/modules/wireframe-workbench.js +13 -2
  124. package/lib/public/modules/workbench-layout-preference.js +12 -5
  125. package/lib/public/modules/workbench-panels.js +21 -0
  126. package/lib/public/modules/worker-message-previews.js +39 -0
  127. package/lib/public/pane-assets/app-5W6KJXK5.js +1 -0
  128. package/lib/public/pane-assets/chunk-2IJUTAB6.js +2 -0
  129. package/lib/public/pane-assets/chunk-6QFLYOVY.js +1 -0
  130. package/lib/public/pane-assets/chunk-7OVNC5HT.js +1 -0
  131. package/lib/public/pane-assets/chunk-BQN7B62H.js +3 -0
  132. package/lib/public/pane-assets/chunk-EMLN2Y7L.js +1 -0
  133. package/lib/public/pane-assets/chunk-ENPAHXLB.js +1 -0
  134. package/lib/public/pane-assets/chunk-EPBGGZRT.js +1 -0
  135. package/lib/public/pane-assets/chunk-EYTE56IA.js +1 -0
  136. package/lib/public/pane-assets/chunk-FQTNR4ZS.js +1 -0
  137. package/lib/public/pane-assets/chunk-JIV7O5GN.js +1 -0
  138. package/lib/public/pane-assets/chunk-L6LSA5WI.js +1 -0
  139. package/lib/public/pane-assets/chunk-M57UIGZV.js +1 -0
  140. package/lib/public/pane-assets/chunk-MGTFTEJP.js +1 -0
  141. package/lib/public/pane-assets/chunk-MMG6MYCN.js +1 -0
  142. package/lib/public/pane-assets/chunk-MZLMEXMW.js +1 -0
  143. package/lib/public/pane-assets/chunk-OG3E5SVA.js +166 -0
  144. package/lib/public/pane-assets/chunk-R7QVVFUG.js +1 -0
  145. package/lib/public/pane-assets/chunk-RGAFZ3T2.js +1 -0
  146. package/lib/public/pane-assets/chunk-RNDRURMF.js +1 -0
  147. package/lib/public/pane-assets/chunk-SJOT74VW.js +2 -0
  148. package/lib/public/pane-assets/chunk-SJTGHIN5.js +1 -0
  149. package/lib/public/pane-assets/chunk-SLMAFKI2.js +1 -0
  150. package/lib/public/pane-assets/chunk-U3I5KY3B.js +1 -0
  151. package/lib/public/pane-assets/chunk-UPXU2IPC.js +1 -0
  152. package/lib/public/pane-assets/chunk-VEBYD7TL.js +1 -0
  153. package/lib/public/pane-assets/chunk-VZ2OKDAO.js +1 -0
  154. package/lib/public/pane-assets/chunk-XBHYNXXT.js +1 -0
  155. package/lib/public/pane-assets/manifest.json +438 -381
  156. package/lib/public/pane-assets/style-BSKKK54Q.css +1 -0
  157. package/lib/public/style.css +1 -0
  158. package/lib/sdk-message-processor.js +5 -2
  159. package/lib/server-storage.js +27 -3
  160. package/lib/server-workbench-layout-settings.js +3 -3
  161. package/lib/server.js +4 -2
  162. package/lib/sessions.js +1 -1
  163. package/lib/split-view-layout.js +11 -7
  164. package/lib/storage-usage.js +29 -7
  165. package/lib/terminal-manager.js +2 -2
  166. package/lib/users-workbench-layout-preferences.js +14 -4
  167. package/lib/workbench-window-layout.js +30 -0
  168. package/lib/worker-message-previews.js +50 -0
  169. package/lib/ws-schema.js +1 -1
  170. package/lib/yoke/adapters/claude-worker.js +8 -0
  171. package/lib/yoke/adapters/claude.js +17 -2
  172. package/lib/yoke/claude-task-reader.js +94 -0
  173. package/lib/yoke/interface.js +1 -0
  174. package/package.json +1 -1
  175. package/lib/public/pane-assets/app-6H5S2Y3Z.js +0 -1
  176. package/lib/public/pane-assets/chunk-3QV5SDC4.js +0 -1
  177. package/lib/public/pane-assets/chunk-4FM3U3DW.js +0 -1
  178. package/lib/public/pane-assets/chunk-7GZH3FZY.js +0 -1
  179. package/lib/public/pane-assets/chunk-AGJTF5WQ.js +0 -1
  180. package/lib/public/pane-assets/chunk-DGOFGEUK.js +0 -1
  181. package/lib/public/pane-assets/chunk-I57URYSL.js +0 -1
  182. package/lib/public/pane-assets/chunk-NPKRTUNG.js +0 -2
  183. package/lib/public/pane-assets/chunk-VGA2Y3D2.js +0 -2
  184. package/lib/public/pane-assets/chunk-WKO3T75E.js +0 -167
  185. package/lib/public/pane-assets/style-TSRDU54Z.css +0 -1
@@ -1,11 +1,14 @@
1
+ import { recordToolExpansion } from './view-presentation-state.js';
2
+ import { workspaceChanged } from './view-workspace-state.js';
1
3
  import { store } from './store.js';
2
4
  import { iconHtml, refreshIcons } from './icons.js';
3
5
  import { closeSidebar } from './sidebar.js';
4
6
  import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench } from './right-workbench.js';
5
7
  import { copyToClipboard } from './utils.js';
6
- import { getTerminalTheme, getDockedTerminalTheme } from './theme.js';
8
+ import { getTerminalTheme } from './theme.js';
7
9
  import { getTerminalFontFamily, getTerminalFontSize, onTerminalFontChange } from './terminal-prefs.js';
8
10
  import { createKeyToolbar } from './terminal-toolbar.js';
11
+ import { applyTerminalSize, hasTerminalViewport } from './terminal-viewport.js';
9
12
 
10
13
  var ctx;
11
14
  var tabs = new Map(); // termId -> { id, title, exited, xterm, fitAddon, bodyEl }
@@ -145,13 +148,8 @@ export function initTerminal(_ctx) {
145
148
 
146
149
  // Fullscreen toggle
147
150
  document.getElementById("terminal-fullscreen").addEventListener("click", function () {
148
- var isFs = ctx.terminalContainerEl.classList.toggle("panel-fullscreen");
149
- var icon = this.querySelector("[data-lucide]");
150
- if (icon) {
151
- icon.setAttribute("data-lucide", isFs ? "minimize-2" : "maximize-2");
152
- refreshIcons();
153
- }
154
- fitTerminal();
151
+ setTerminalExpanded(!ctx.terminalContainerEl.classList.contains('panel-fullscreen'));
152
+ recordToolExpansion('terminal', ctx.terminalContainerEl.classList.contains('panel-fullscreen'));
155
153
  });
156
154
 
157
155
  // Header toggle button
@@ -224,6 +222,7 @@ export function openTerminal() {
224
222
 
225
223
  // --- Close terminal panel (hide, detach, but keep PTYs alive) ---
226
224
  export function closeTerminal() {
225
+ recordToolExpansion('terminal', false);
227
226
  releaseRightWorkbench("terminal");
228
227
  var container = ctx.terminalContainerEl;
229
228
  container.classList.remove("panel-fullscreen");
@@ -279,7 +278,7 @@ function closeTab(termId) {
279
278
  }
280
279
 
281
280
  // --- Activate a tab (show xterm, attach) ---
282
- function activateTab(termId) {
281
+ function activateTab(termId, savedBinding) {
283
282
  var tab = tabs.get(termId);
284
283
  if (!tab) return;
285
284
 
@@ -294,6 +293,10 @@ function activateTab(termId) {
294
293
  }
295
294
 
296
295
  activeTabId = termId;
296
+ var binding = (store.get("clayControlTerminalViews") || []).find(function (item) { return item.id === termId; });
297
+ if (binding) store.set({ savedViewTerminalResource: { id: binding.id, identity: binding.identity, runtimeId: binding.runtimeId } });
298
+ var unavailable = document.getElementById("terminal-saved-unavailable"); if (unavailable) unavailable.remove();
299
+ workspaceChanged();
297
300
 
298
301
  // Lazy-create xterm instance
299
302
  if (!tab.xterm) {
@@ -305,7 +308,7 @@ function activateTab(termId) {
305
308
 
306
309
  // Attach to server
307
310
  if (ctx.ws && ctx.connected) {
308
- ctx.ws.send(JSON.stringify({ type: "term_attach", id: termId }));
311
+ ctx.ws.send(JSON.stringify({ type: "term_attach", id: termId, savedBinding: savedBinding }));
309
312
  }
310
313
 
311
314
  // Fit and focus
@@ -358,7 +361,7 @@ function createXtermForTab(tab) {
358
361
  cursorBlink: true,
359
362
  fontSize: getTerminalFontSize(),
360
363
  fontFamily: getTerminalFontFamily(),
361
- theme: (store.get('rightWorkbenchDockedOwners') || []).indexOf('terminal') !== -1 ? getDockedTerminalTheme() : getTerminalTheme(),
364
+ theme: getTerminalTheme(),
362
365
  });
363
366
 
364
367
  var fitAddon = null;
@@ -480,7 +483,7 @@ function fitTerminal() {
480
483
  fitRafId = null;
481
484
  if (!activeTabId) return;
482
485
  var tab = tabs.get(activeTabId);
483
- if (!tab || !tab.fitAddon || !tab.xterm) return;
486
+ if (!isOpen || !tab || !tab.fitAddon || !tab.xterm || !hasTerminalViewport(tab)) return;
484
487
 
485
488
  try {
486
489
  tab.fitAddon.fit();
@@ -557,11 +560,13 @@ function renderTabBar() {
557
560
 
558
561
  var moreBtn = document.createElement("button");
559
562
  moreBtn.className = "terminal-tab-more";
560
- moreBtn.innerHTML = '<i data-lucide="ellipsis" style="width:12px;height:12px"></i>';
563
+ moreBtn.innerHTML = iconHtml('x');
564
+ moreBtn.setAttribute('aria-label', 'Close terminal tab ' + t.title);
561
565
  moreBtn.addEventListener("click", function (e) {
562
566
  e.stopPropagation();
563
- showTabContextMenu(e, t, label);
567
+ closeTab(t.id);
564
568
  });
569
+ el.addEventListener('contextmenu', function (event) { event.preventDefault(); showTabContextMenu(event, t, label); });
565
570
  el.appendChild(moreBtn);
566
571
 
567
572
  el.addEventListener("click", function () {
@@ -699,7 +704,7 @@ function updateTerminalBadge() {
699
704
  // --- Handle server messages ---
700
705
 
701
706
  export function handleTermList(msg) {
702
- store.set({ clayControlTerminalViews: (msg.terminals || []).map(function (item) { return { id: item.id, identity: item.controlIdentity, revision: item.controlRevision, runtimeId: store.get('controlRuntimeId') }; }) });
707
+ store.set({ clayControlTerminalViews: (msg.terminals || []).map(function (item) { return { id: item.id, identity: item.controlIdentity, revision: item.controlRevision, exited: item.exited, runtimeId: store.get('controlRuntimeId') }; }) });
703
708
  // TUI session terminals are owned by session-tui-view.js and must not
704
709
  // appear in the bottom terminal panel. Filter them out before any tab
705
710
  // bookkeeping so the panel never tries to render or auto-attach them.
@@ -744,6 +749,7 @@ export function handleTermList(msg) {
744
749
  }
745
750
 
746
751
  renderTabBar();
752
+ store.set({ savedViewTerminalListReady: true });
747
753
 
748
754
  // If panel is open and we have tabs, re-attach
749
755
  if (isOpen && tabs.size > 0) {
@@ -782,9 +788,7 @@ export function handleTermResized(msg) {
782
788
  handleTerminalProjection(msg);
783
789
  if (!msg.id) return;
784
790
  var tab = tabs.get(msg.id);
785
- if (tab && tab.xterm && msg.cols > 0 && msg.rows > 0) {
786
- tab.xterm.resize(msg.cols, msg.rows);
787
- }
791
+ applyTerminalSize(tab, msg, isOpen && msg.id === activeTabId, fitTerminal);
788
792
  }
789
793
 
790
794
  export function handleTermExited(msg) {
@@ -825,6 +829,7 @@ export function handleTermClosed(msg) {
825
829
 
826
830
  // --- Reset on reconnect ---
827
831
  export function resetTerminals() {
832
+ store.set({ savedViewTerminalListReady: false, savedViewTerminalResource: null });
828
833
  // Dispose all xterm instances (server state survives, client re-syncs via term_list)
829
834
  for (var tab of tabs.values()) {
830
835
  disposeTab(tab);
@@ -842,8 +847,8 @@ export function sendTerminalCommand(command) {
842
847
  }
843
848
  }
844
849
 
845
- export function setTerminalTheme(xtermTheme) {
846
- if ((store.get('rightWorkbenchDockedOwners') || []).indexOf('terminal') !== -1) xtermTheme = getDockedTerminalTheme();
850
+ export function setTerminalTheme() {
851
+ var xtermTheme = getTerminalTheme();
847
852
  for (var tab of tabs.values()) {
848
853
  if (tab.xterm) {
849
854
  tab.xterm.options.theme = xtermTheme;
@@ -851,9 +856,6 @@ export function setTerminalTheme(xtermTheme) {
851
856
  }
852
857
  }
853
858
 
854
- store.subscribe(function (state, previous) {
855
- if ((state.rightWorkbenchDockedOwners || []).includes('terminal') !== (previous.rightWorkbenchDockedOwners || []).includes('terminal')) setTerminalTheme(getTerminalTheme());
856
- });
857
859
 
858
860
  // Live font update: applies family/size to every open shell terminal
859
861
  // and refits each (cell dimensions change with font size, so cols/rows
@@ -983,3 +985,27 @@ function showTermCtxMenu(e, tab) {
983
985
  document.addEventListener("click", closeTermCtxMenu, { once: true });
984
986
  }, 0);
985
987
  }
988
+
989
+ // Restoration must never enter openTerminal's create-new branch.
990
+ export function restoreExistingTerminal(resource) {
991
+ if (!store.get('connected') || !store.get('controlRuntimeId')) return 'pending';
992
+ if (!store.get('savedViewTerminalListReady')) return 'pending';
993
+ var live = (store.get('clayControlTerminalViews') || []).find(function (item) { return item.id === resource.id && item.identity === resource.identity && item.runtimeId === resource.runtimeId && !item.exited; });
994
+ claimRightWorkbench('terminal');
995
+ var container = document.getElementById('terminal-container'); container.classList.remove('hidden');
996
+ if (live && tabs.has(resource.id)) { isOpen = true; activateTab(resource.id, resource); return 'restored'; }
997
+ isOpen = false;
998
+ tabs.forEach(function (tab) { if (tab.bodyEl) tab.bodyEl.style.display = 'none'; });
999
+ var notice = document.getElementById('terminal-saved-unavailable');
1000
+ if (!notice) { notice = document.createElement('p'); notice.id = 'terminal-saved-unavailable'; notice.className = 'saved-view-unavailable'; notice.setAttribute('role', 'status'); document.getElementById('terminal-body').appendChild(notice); }
1001
+ notice.textContent = 'This saved terminal is unavailable. Close this pane and open Terminal to choose an available shell.';
1002
+ return 'unavailable';
1003
+ }
1004
+
1005
+ export function setTerminalExpanded(enabled) {
1006
+ var panel = document.getElementById('terminal-container'); if (!panel) return;
1007
+ panel.classList.toggle('panel-fullscreen', !!enabled);
1008
+ var icon = panel.querySelector('#terminal-fullscreen [data-lucide]');
1009
+ if (icon) { icon.setAttribute('data-lucide', enabled ? 'minimize-2' : 'maximize-2'); refreshIcons(); }
1010
+ if (!panel.classList.contains('hidden')) fitTerminal();
1011
+ }
@@ -0,0 +1,177 @@
1
+ // --- Color utilities ---
2
+
3
+ function hexToRgb(hex) {
4
+ var h = hex.replace("#", "");
5
+ return {
6
+ r: parseInt(h.substring(0, 2), 16),
7
+ g: parseInt(h.substring(2, 4), 16),
8
+ b: parseInt(h.substring(4, 6), 16)
9
+ };
10
+ }
11
+
12
+ function rgbToHex(r, g, b) {
13
+ return "#" + [r, g, b].map(function (v) {
14
+ var c = Math.max(0, Math.min(255, Math.round(v)));
15
+ return c.toString(16).padStart(2, "0");
16
+ }).join("");
17
+ }
18
+
19
+ function darken(hex, amount) {
20
+ var c = hexToRgb(hex);
21
+ var f = 1 - amount;
22
+ return rgbToHex(c.r * f, c.g * f, c.b * f);
23
+ }
24
+
25
+ function lighten(hex, amount) {
26
+ var c = hexToRgb(hex);
27
+ return rgbToHex(
28
+ c.r + (255 - c.r) * amount,
29
+ c.g + (255 - c.g) * amount,
30
+ c.b + (255 - c.b) * amount
31
+ );
32
+ }
33
+
34
+ function mixColors(hex1, hex2, weight) {
35
+ var c1 = hexToRgb(hex1);
36
+ var c2 = hexToRgb(hex2);
37
+ var w = weight;
38
+ return rgbToHex(
39
+ c1.r * w + c2.r * (1 - w),
40
+ c1.g * w + c2.g * (1 - w),
41
+ c1.b * w + c2.b * (1 - w)
42
+ );
43
+ }
44
+
45
+ function hexToRgba(hex, alpha) {
46
+ var c = hexToRgb(hex);
47
+ return "rgba(" + c.r + ", " + c.g + ", " + c.b + ", " + alpha + ")";
48
+ }
49
+
50
+ function luminance(hex) {
51
+ var c = hexToRgb(hex);
52
+ return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b) / 255;
53
+ }
54
+
55
+ var DEFAULT_DARK_THEME_ID = "clay-dark";
56
+ var DEFAULT_LIGHT_THEME_ID = "clay-light";
57
+
58
+ // Embedded defaults keep the first render branded before /api/themes loads.
59
+ var defaultDarkFallback = {
60
+ name: "Clay Studio Dark", variant: "dark",
61
+ base00: "171715", base01: "20201D", base02: "393934", base03: "686861",
62
+ base04: "A0A098", base05: "D1D1CA", base06: "E8E8E2", base07: "FAFAF5",
63
+ base08: "FF7479", base09: "7776FF", base0A: "E0B45B", base0B: "07E5A3",
64
+ base0C: "5FD2C0", base0D: "8AA7FF", base0E: "C39AF3", base0F: "D69A7D",
65
+ accent2: "07E5A3", link: "7F7EC8"
66
+ };
67
+
68
+ var defaultLightFallback = {
69
+ name: "Clay Studio Light", variant: "light",
70
+ base00: "F7F7F3", base01: "EEEEEA", base02: "D7D7D0", base03: "A2A29B",
71
+ base04: "73736C", base05: "44443F", base06: "252522", base07: "151513",
72
+ base08: "C84B50", base09: "5857FC", base0A: "956A19", base0B: "087B59",
73
+ base0C: "187A7C", base0D: "3F62B4", base0E: "7A52A8", base0F: "9A5A46",
74
+ accent2: "07E5A3", link: "4948B8"
75
+ };
76
+
77
+ // --- Compute CSS variables from a base16 palette ---
78
+ function computeVars(theme) {
79
+ var b = {};
80
+ var keys = ["base00","base01","base02","base03","base04","base05","base06","base07",
81
+ "base08","base09","base0A","base0B","base0C","base0D","base0E","base0F"];
82
+ for (var i = 0; i < keys.length; i++) {
83
+ b[keys[i]] = "#" + theme[keys[i]];
84
+ }
85
+
86
+ var isLight = theme.variant === "light";
87
+ var accent2 = theme.accent2 ? "#" + theme.accent2 : b.base0D;
88
+ var link = theme.link ? "#" + theme.link : b.base0D;
89
+
90
+ return {
91
+ "--bg": b.base00,
92
+ "--bg-alt": b.base01,
93
+ "--text": b.base06,
94
+ "--text-secondary": b.base05,
95
+ "--text-muted": b.base04,
96
+ "--text-dimmer": b.base03,
97
+ "--accent": b.base09,
98
+ "--accent-hover": isLight ? darken(b.base09, 0.12) : lighten(b.base09, 0.12),
99
+ "--accent-bg": hexToRgba(b.base09, 0.12),
100
+ "--link": link,
101
+ "--link-hover": isLight ? darken(link, 0.10) : lighten(link, 0.10),
102
+ "--code-bg": isLight ? darken(b.base00, 0.03) : darken(b.base00, 0.15),
103
+ "--border": b.base02,
104
+ "--border-subtle": mixColors(b.base00, b.base02, 0.6),
105
+ "--input-bg": isLight ? darken(b.base00, 0.04) : mixColors(b.base01, b.base02, 0.5),
106
+ "--ask-mate-bg": isLight ? mixColors("#ffffff", darken(b.base00, 0.04), 0.6) : mixColors(b.base00, mixColors(b.base01, b.base02, 0.5), 0.6),
107
+ "--user-bubble": isLight ? darken(b.base01, 0.03) : mixColors(b.base01, b.base02, 0.3),
108
+ "--error": b.base08,
109
+ "--success": b.base0B,
110
+ "--warning": b.base0A,
111
+ "--sidebar-bg": isLight ? darken(b.base00, 0.02) : darken(b.base00, 0.10),
112
+ "--sidebar-hover": isLight ? darken(b.base00, 0.06) : mixColors(b.base00, b.base01, 0.5),
113
+ "--sidebar-active": isLight ? darken(b.base01, 0.05) : mixColors(b.base01, b.base02, 0.5),
114
+ "--filebrowser-bg": isLight ? lighten(b.base00, 0.03) : lighten(b.base00, 0.04),
115
+ "--filebrowser-border": isLight ? darken(b.base00, 0.08) : mixColors(b.base02, b.base00, 0.5),
116
+ "--accent-8": hexToRgba(b.base09, 0.08),
117
+ "--accent-12": hexToRgba(b.base09, 0.12),
118
+ "--accent-15": hexToRgba(b.base09, 0.15),
119
+ "--accent-20": hexToRgba(b.base09, 0.20),
120
+ "--accent-25": hexToRgba(b.base09, 0.25),
121
+ "--accent-30": hexToRgba(b.base09, 0.30),
122
+ "--accent2": accent2,
123
+ "--accent2-hover": isLight ? darken(accent2, 0.12) : lighten(accent2, 0.12),
124
+ "--accent2-bg": hexToRgba(accent2, 0.12),
125
+ "--accent2-8": hexToRgba(accent2, 0.08),
126
+ "--accent2-12": hexToRgba(accent2, 0.12),
127
+ "--accent2-15": hexToRgba(accent2, 0.15),
128
+ "--accent2-20": hexToRgba(accent2, 0.20),
129
+ "--accent2-25": hexToRgba(accent2, 0.25),
130
+ "--accent2-30": hexToRgba(accent2, 0.30),
131
+ "--error-8": hexToRgba(b.base08, 0.08),
132
+ "--error-12": hexToRgba(b.base08, 0.12),
133
+ "--error-15": hexToRgba(b.base08, 0.15),
134
+ "--error-25": hexToRgba(b.base08, 0.25),
135
+ "--success-8": hexToRgba(b.base0B, 0.08),
136
+ "--success-12": hexToRgba(b.base0B, 0.12),
137
+ "--success-15": hexToRgba(b.base0B, 0.15),
138
+ "--success-25": hexToRgba(b.base0B, 0.25),
139
+ "--warning-bg": hexToRgba(b.base0A, 0.12),
140
+ "--overlay-rgb": isLight ? "0,0,0" : "255,255,255",
141
+ "--shadow-rgb": "0,0,0",
142
+ "--hl-comment": b.base03,
143
+ "--hl-keyword": b.base0E,
144
+ "--hl-string": b.base0B,
145
+ "--hl-number": b.base09,
146
+ "--hl-function": b.base0D,
147
+ "--hl-variable": b.base08,
148
+ "--hl-type": b.base0A,
149
+ "--hl-constant": b.base09,
150
+ "--hl-tag": b.base08,
151
+ "--hl-attr": b.base0D,
152
+ "--hl-regexp": b.base0C,
153
+ "--hl-meta": b.base0F,
154
+ "--hl-builtin": b.base09,
155
+ "--hl-symbol": b.base0F,
156
+ "--hl-addition": b.base0B,
157
+ "--hl-deletion": b.base08
158
+ };
159
+ }
160
+
161
+ function validateTheme(t) {
162
+ if (!t || typeof t !== "object") return false;
163
+ if (!t.name || typeof t.name !== "string") return false;
164
+ var keys = ["base00","base01","base02","base03","base04","base05","base06","base07",
165
+ "base08","base09","base0A","base0B","base0C","base0D","base0E","base0F"];
166
+ for (var i = 0; i < keys.length; i++) {
167
+ if (!t[keys[i]] || !/^[0-9a-fA-F]{6}$/.test(t[keys[i]])) return false;
168
+ }
169
+ if (t.variant && t.variant !== "dark" && t.variant !== "light") return false;
170
+ if (!t.variant) {
171
+ t.variant = luminance("#" + t.base00) > 0.5 ? "light" : "dark";
172
+ }
173
+ return true;
174
+ }
175
+
176
+
177
+ export { hexToRgb, rgbToHex, darken, lighten, mixColors, hexToRgba, luminance, computeVars, validateTheme, defaultDarkFallback, defaultLightFallback, DEFAULT_DARK_THEME_ID, DEFAULT_LIGHT_THEME_ID };
@@ -5,165 +5,7 @@ import { setTuiSessionTheme } from './session-tui-view.js';
5
5
  import { setTuiAttentionTheme } from './tui-attention.js';
6
6
  import { updateMermaidTheme } from './markdown.js';
7
7
 
8
- // --- Color utilities ---
9
-
10
- function hexToRgb(hex) {
11
- var h = hex.replace("#", "");
12
- return {
13
- r: parseInt(h.substring(0, 2), 16),
14
- g: parseInt(h.substring(2, 4), 16),
15
- b: parseInt(h.substring(4, 6), 16)
16
- };
17
- }
18
-
19
- function rgbToHex(r, g, b) {
20
- return "#" + [r, g, b].map(function (v) {
21
- var c = Math.max(0, Math.min(255, Math.round(v)));
22
- return c.toString(16).padStart(2, "0");
23
- }).join("");
24
- }
25
-
26
- function darken(hex, amount) {
27
- var c = hexToRgb(hex);
28
- var f = 1 - amount;
29
- return rgbToHex(c.r * f, c.g * f, c.b * f);
30
- }
31
-
32
- function lighten(hex, amount) {
33
- var c = hexToRgb(hex);
34
- return rgbToHex(
35
- c.r + (255 - c.r) * amount,
36
- c.g + (255 - c.g) * amount,
37
- c.b + (255 - c.b) * amount
38
- );
39
- }
40
-
41
- function mixColors(hex1, hex2, weight) {
42
- var c1 = hexToRgb(hex1);
43
- var c2 = hexToRgb(hex2);
44
- var w = weight;
45
- return rgbToHex(
46
- c1.r * w + c2.r * (1 - w),
47
- c1.g * w + c2.g * (1 - w),
48
- c1.b * w + c2.b * (1 - w)
49
- );
50
- }
51
-
52
- function hexToRgba(hex, alpha) {
53
- var c = hexToRgb(hex);
54
- return "rgba(" + c.r + ", " + c.g + ", " + c.b + ", " + alpha + ")";
55
- }
56
-
57
- function luminance(hex) {
58
- var c = hexToRgb(hex);
59
- return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b) / 255;
60
- }
61
-
62
- var DEFAULT_DARK_THEME_ID = "clay-dark";
63
- var DEFAULT_LIGHT_THEME_ID = "clay-light";
64
-
65
- // Embedded defaults keep the first render branded before /api/themes loads.
66
- var defaultDarkFallback = {
67
- name: "Clay Studio Dark", variant: "dark",
68
- base00: "171715", base01: "20201D", base02: "393934", base03: "686861",
69
- base04: "A0A098", base05: "D1D1CA", base06: "E8E8E2", base07: "FAFAF5",
70
- base08: "FF7479", base09: "7776FF", base0A: "E0B45B", base0B: "07E5A3",
71
- base0C: "5FD2C0", base0D: "8AA7FF", base0E: "C39AF3", base0F: "D69A7D",
72
- accent2: "07E5A3", link: "7F7EC8"
73
- };
74
-
75
- var defaultLightFallback = {
76
- name: "Clay Studio Light", variant: "light",
77
- base00: "F7F7F3", base01: "EEEEEA", base02: "D7D7D0", base03: "A2A29B",
78
- base04: "73736C", base05: "44443F", base06: "252522", base07: "151513",
79
- base08: "C84B50", base09: "5857FC", base0A: "956A19", base0B: "087B59",
80
- base0C: "187A7C", base0D: "3F62B4", base0E: "7A52A8", base0F: "9A5A46",
81
- accent2: "07E5A3", link: "4948B8"
82
- };
83
-
84
- // --- Compute CSS variables from a base16 palette ---
85
- function computeVars(theme) {
86
- var b = {};
87
- var keys = ["base00","base01","base02","base03","base04","base05","base06","base07",
88
- "base08","base09","base0A","base0B","base0C","base0D","base0E","base0F"];
89
- for (var i = 0; i < keys.length; i++) {
90
- b[keys[i]] = "#" + theme[keys[i]];
91
- }
92
-
93
- var isLight = theme.variant === "light";
94
- var accent2 = theme.accent2 ? "#" + theme.accent2 : b.base0D;
95
- var link = theme.link ? "#" + theme.link : b.base0D;
96
-
97
- return {
98
- "--bg": b.base00,
99
- "--bg-alt": b.base01,
100
- "--text": b.base06,
101
- "--text-secondary": b.base05,
102
- "--text-muted": b.base04,
103
- "--text-dimmer": b.base03,
104
- "--accent": b.base09,
105
- "--accent-hover": isLight ? darken(b.base09, 0.12) : lighten(b.base09, 0.12),
106
- "--accent-bg": hexToRgba(b.base09, 0.12),
107
- "--link": link,
108
- "--link-hover": isLight ? darken(link, 0.10) : lighten(link, 0.10),
109
- "--code-bg": isLight ? darken(b.base00, 0.03) : darken(b.base00, 0.15),
110
- "--border": b.base02,
111
- "--border-subtle": mixColors(b.base00, b.base02, 0.6),
112
- "--input-bg": isLight ? darken(b.base00, 0.04) : mixColors(b.base01, b.base02, 0.5),
113
- "--ask-mate-bg": isLight ? mixColors("#ffffff", darken(b.base00, 0.04), 0.6) : mixColors(b.base00, mixColors(b.base01, b.base02, 0.5), 0.6),
114
- "--user-bubble": isLight ? darken(b.base01, 0.03) : mixColors(b.base01, b.base02, 0.3),
115
- "--error": b.base08,
116
- "--success": b.base0B,
117
- "--warning": b.base0A,
118
- "--sidebar-bg": isLight ? darken(b.base00, 0.02) : darken(b.base00, 0.10),
119
- "--sidebar-hover": isLight ? darken(b.base00, 0.06) : mixColors(b.base00, b.base01, 0.5),
120
- "--sidebar-active": isLight ? darken(b.base01, 0.05) : mixColors(b.base01, b.base02, 0.5),
121
- "--filebrowser-bg": isLight ? lighten(b.base00, 0.03) : lighten(b.base00, 0.04),
122
- "--filebrowser-border": isLight ? darken(b.base00, 0.08) : mixColors(b.base02, b.base00, 0.5),
123
- "--accent-8": hexToRgba(b.base09, 0.08),
124
- "--accent-12": hexToRgba(b.base09, 0.12),
125
- "--accent-15": hexToRgba(b.base09, 0.15),
126
- "--accent-20": hexToRgba(b.base09, 0.20),
127
- "--accent-25": hexToRgba(b.base09, 0.25),
128
- "--accent-30": hexToRgba(b.base09, 0.30),
129
- "--accent2": accent2,
130
- "--accent2-hover": isLight ? darken(accent2, 0.12) : lighten(accent2, 0.12),
131
- "--accent2-bg": hexToRgba(accent2, 0.12),
132
- "--accent2-8": hexToRgba(accent2, 0.08),
133
- "--accent2-12": hexToRgba(accent2, 0.12),
134
- "--accent2-15": hexToRgba(accent2, 0.15),
135
- "--accent2-20": hexToRgba(accent2, 0.20),
136
- "--accent2-25": hexToRgba(accent2, 0.25),
137
- "--accent2-30": hexToRgba(accent2, 0.30),
138
- "--error-8": hexToRgba(b.base08, 0.08),
139
- "--error-12": hexToRgba(b.base08, 0.12),
140
- "--error-15": hexToRgba(b.base08, 0.15),
141
- "--error-25": hexToRgba(b.base08, 0.25),
142
- "--success-8": hexToRgba(b.base0B, 0.08),
143
- "--success-12": hexToRgba(b.base0B, 0.12),
144
- "--success-15": hexToRgba(b.base0B, 0.15),
145
- "--success-25": hexToRgba(b.base0B, 0.25),
146
- "--warning-bg": hexToRgba(b.base0A, 0.12),
147
- "--overlay-rgb": isLight ? "0,0,0" : "255,255,255",
148
- "--shadow-rgb": "0,0,0",
149
- "--hl-comment": b.base03,
150
- "--hl-keyword": b.base0E,
151
- "--hl-string": b.base0B,
152
- "--hl-number": b.base09,
153
- "--hl-function": b.base0D,
154
- "--hl-variable": b.base08,
155
- "--hl-type": b.base0A,
156
- "--hl-constant": b.base09,
157
- "--hl-tag": b.base08,
158
- "--hl-attr": b.base0D,
159
- "--hl-regexp": b.base0C,
160
- "--hl-meta": b.base0F,
161
- "--hl-builtin": b.base09,
162
- "--hl-symbol": b.base0F,
163
- "--hl-addition": b.base0B,
164
- "--hl-deletion": b.base08
165
- };
166
- }
8
+ import { hexToRgb, rgbToHex, darken, lighten, mixColors, hexToRgba, luminance, computeVars, validateTheme, defaultDarkFallback, defaultLightFallback, DEFAULT_DARK_THEME_ID, DEFAULT_LIGHT_THEME_ID } from './theme-palette.js';
167
9
 
168
10
  var defaultExactVars = computeVars(defaultDarkFallback);
169
11
 
@@ -267,11 +109,6 @@ export function getTerminalTheme() {
267
109
  return computeTerminalTheme(getTheme(DEFAULT_DARK_THEME_ID) || defaultDarkFallback);
268
110
  }
269
111
 
270
- export function getDockedTerminalTheme() {
271
- var theme = getCurrentTheme();
272
- return Object.assign({}, computeTerminalTheme(theme), { background: '#' + theme.base00 });
273
- }
274
-
275
112
  export function getMermaidThemeVars() {
276
113
  return computeMermaidVars(getCurrentTheme());
277
114
  }
@@ -332,7 +169,7 @@ export function applyTheme(themeId, fromPicker) {
332
169
  // Terminals deliberately keep Clay Studio Dark for predictable ANSI
333
170
  // contrast, even while the surrounding workspace uses a light theme.
334
171
  var termTheme = getTerminalTheme();
335
- try { setTerminalTheme(termTheme); } catch (e) {}
172
+ try { setTerminalTheme(); } catch (e) {}
336
173
  try { setTuiSessionTheme(termTheme); } catch (e) {}
337
174
  try { setTuiAttentionTheme(termTheme); } catch (e) {}
338
175
 
@@ -401,21 +238,6 @@ function loadThemes() {
401
238
  });
402
239
  }
403
240
 
404
- function validateTheme(t) {
405
- if (!t || typeof t !== "object") return false;
406
- if (!t.name || typeof t.name !== "string") return false;
407
- var keys = ["base00","base01","base02","base03","base04","base05","base06","base07",
408
- "base08","base09","base0A","base0B","base0C","base0D","base0E","base0F"];
409
- for (var i = 0; i < keys.length; i++) {
410
- if (!t[keys[i]] || !/^[0-9a-fA-F]{6}$/.test(t[keys[i]])) return false;
411
- }
412
- if (t.variant && t.variant !== "dark" && t.variant !== "light") return false;
413
- if (!t.variant) {
414
- t.variant = luminance("#" + t.base00) > 0.5 ? "light" : "dark";
415
- }
416
- return true;
417
- }
418
-
419
241
  // --- Light / Dark mode toggle ---
420
242
 
421
243
  // Returns the system preferred mode
@@ -0,0 +1,88 @@
1
+ import { WORKBENCH_PANELS } from './workbench-panels.js';
2
+ import { recordToolExpansion } from './view-presentation-state.js';
3
+ import { store } from './store.js';
4
+ import { iconHtml, refreshIcons } from './icons.js';
5
+ import { TOOL_PANES } from './tool-pane-tree.js';
6
+
7
+ function titleFor(panel, name) {
8
+ if (name === 'terminal') {
9
+ var state = store.snap(), project = (state.projectsHubList || []).find(function (item) { return item && item.slug === state.currentSlug; });
10
+ var projectName = project && (project.title || project.project || project.name) || state.projectName || state.currentSlug;
11
+ return projectName ? projectName + ' · Terminal' : 'Terminal';
12
+ }
13
+ if (name === 'file-viewer') { var tab = panel.querySelector('.file-viewer-tab.active .file-viewer-tab-label'); return tab && tab.textContent || 'Files'; }
14
+ var browser = store.get('sharedBrowser');
15
+ try { return browser && browser.url ? new URL(browser.url).hostname : 'Browser'; } catch (error) { return 'Browser'; }
16
+ }
17
+ export function renderToolPaneChrome(panel, name) {
18
+ if (panel.dataset.fileInstance) return;
19
+ if (WORKBENCH_PANELS[name]) { renderWorkbenchChrome(panel, name); return; }
20
+ var definition = TOOL_PANES[name];
21
+ if (!definition) return;
22
+ var header = panel.querySelector(':scope > .tool-pane-header');
23
+ if (!header) {
24
+ var original = panel.querySelector(name === 'terminal' ? '.terminal-header' : name === 'browser' ? '.shared-browser-header' : '.file-viewer-tabbar');
25
+ if (!original) return;
26
+ header = document.createElement('header'); header.className = 'tool-pane-header split-pane-header'; header.dataset.toolPane = name;
27
+ var kind = document.createElement('span'); kind.className = 'tool-pane-kind' + (name === 'terminal' ? '' : ' split-view-runtime');
28
+ kind.innerHTML = iconHtml(definition.icon) + (name === 'terminal' ? '' : '<span class="split-view-model">' + definition.label + '</span>');
29
+ var title = document.createElement('span'); title.className = 'tool-pane-title split-pane-title';
30
+ var space = document.createElement('span'); space.className = 'split-pane-drag-space'; space.title = 'Drag to rearrange panes'; space.setAttribute('aria-hidden', 'true');
31
+ var actions = original.querySelector('.terminal-header-actions, .shared-browser-window, .file-viewer-window-actions');
32
+ header.append(kind, title, space); if (actions) header.appendChild(actions);
33
+ panel.insertBefore(header, panel.firstChild);
34
+ if (name === 'browser') {
35
+ header.classList.add('browser-pane-header');
36
+ var tabs = panel.querySelector('.shared-browser-tabs');
37
+ if (tabs) header.insertBefore(tabs, space);
38
+ kind.setAttribute('aria-label', 'Browser'); kind.setAttribute('data-tip', 'Browser');
39
+ original.hidden = true; var close = header.querySelector('[data-action="hide"]'); if (close) { close.title = 'Close browser pane'; close.setAttribute('aria-label', 'Close browser pane'); }
40
+ }
41
+ else original.classList.add('tool-pane-tab-row');
42
+ var observer = new MutationObserver(function () { update(); });
43
+ observer.observe(panel, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['aria-selected'] });
44
+ panel.addEventListener('clay-tool-pane-dispose', function () { observer.disconnect(); }, { once: true });
45
+ refreshIcons();
46
+ }
47
+ function update() {
48
+ var label = titleFor(panel, name), title = header.querySelector('.tool-pane-title');
49
+ if (title.textContent !== label) { title.textContent = label; title.title = label; }
50
+ }
51
+ update();
52
+ }
53
+
54
+ store.subscribe(function (state, previous) {
55
+ if (state.projectName === previous.projectName && state.projectsHubList === previous.projectsHubList && state.currentSlug === previous.currentSlug) return;
56
+ var panel = document.getElementById('terminal-container');
57
+ if (panel && panel.querySelector(':scope > .tool-pane-header')) renderToolPaneChrome(panel, 'terminal');
58
+ });
59
+
60
+ function renderWorkbenchChrome(panel, name) {
61
+ panel.classList.add('workbench-pane-shell');
62
+ var header = panel.querySelector(':scope > header');
63
+ if (!header || header.dataset.toolPane === name) return;
64
+ header.dataset.toolPane = name;
65
+ header.classList.add('tool-pane-header', 'split-pane-header');
66
+ var actions = header.querySelector('[class*="window-actions"], :scope > div:last-child');
67
+ if (!actions) {
68
+ actions = document.createElement('div');
69
+ Array.from(header.querySelectorAll(':scope > button')).forEach(function (button) {
70
+ var label = button.getAttribute('aria-label') || '';
71
+ if (/^(Widen|Close)|fullscreen/i.test(label)) actions.appendChild(button);
72
+ });
73
+ header.appendChild(actions);
74
+ }
75
+ actions.classList.add('workbench-pane-actions');
76
+ var title = header.querySelector('strong, [class$="-title"]');
77
+ if (title) title.classList.add('tool-pane-title');
78
+ var space = document.createElement('span'); space.className = 'split-pane-drag-space';
79
+ space.title = 'Drag to rearrange panes'; space.setAttribute('aria-hidden', 'true');
80
+ header.insertBefore(space, actions);
81
+ var expanded = panel.classList.contains('panel-fullscreen');
82
+ var observer = new MutationObserver(function () {
83
+ var next = panel.classList.contains('panel-fullscreen');
84
+ if (next !== expanded) { expanded = next; recordToolExpansion(name, next); }
85
+ });
86
+ observer.observe(panel, { attributes: true, attributeFilter: ['class'] });
87
+ panel.addEventListener('clay-tool-pane-dispose', function () { observer.disconnect(); }, { once: true });
88
+ }