clideck 1.31.19 → 1.31.20

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clideck",
3
- "version": "1.31.19",
3
+ "version": "1.31.20",
4
4
  "description": "One screen for all your AI coding agents — run, monitor, and manage multiple CLI agents from a single browser tab",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -9,7 +9,9 @@
9
9
  "scripts": {
10
10
  "start": "node server.js",
11
11
  "build:css": "tailwindcss -i src/input.css -o public/tailwind.css --minify",
12
- "prepublishOnly": "npm run build:css"
12
+ "prepublishOnly": "npm run build:css",
13
+ "smoke:providers": "node tests/providers/run.js",
14
+ "smoke:menu": "node tests/providers/menu-detection.test.js"
13
15
  },
14
16
  "keywords": [
15
17
  "terminal",
@@ -4,6 +4,7 @@
4
4
  import { handleTerminalKey } from './prompts.js';
5
5
 
6
6
  const registry = new Map(); // normalized combo → { pluginId, callback }
7
+ const MAX_OSC52_BYTES = 512 * 1024;
7
8
 
8
9
  // Normalize a KeyboardEvent into a canonical combo string
9
10
  function normalizeEvent(e) {
@@ -84,10 +85,35 @@ export function unregisterAllForPlugin(pluginId) {
84
85
  }
85
86
  }
86
87
 
88
+ function decodeOsc52(data) {
89
+ const parts = String(data || '').split(';');
90
+ if (parts.length < 2) return '';
91
+ const encoded = parts.slice(1).join(';').trim();
92
+ if (!encoded || encoded === '?') return '';
93
+ if (encoded.length > MAX_OSC52_BYTES) return '';
94
+ try {
95
+ const binary = atob(encoded);
96
+ const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0));
97
+ return new TextDecoder().decode(bytes);
98
+ } catch {
99
+ return '';
100
+ }
101
+ }
102
+
103
+ function attachClipboardOscHandler(term) {
104
+ if (!term.parser?.registerOscHandler) return;
105
+ term.parser.registerOscHandler(52, (data) => {
106
+ const text = decodeOsc52(data);
107
+ if (!text || !navigator.clipboard?.writeText) return false;
108
+ return navigator.clipboard.writeText(text).then(() => true, () => false);
109
+ });
110
+ }
111
+
87
112
  // Attach to an xterm terminal instance — xterm's hidden textarea is an input,
88
113
  // so we bypass the isInput check and dispatch directly.
89
114
  // Prompt autocomplete (// trigger) runs first, then hotkey dispatch.
90
115
  export function attachToTerminal(term, presetId) {
116
+ attachClipboardOscHandler(term);
91
117
  term.attachCustomKeyEventHandler((e) => {
92
118
  if (e.type === 'keydown'
93
119
  && e.ctrlKey
@@ -781,7 +781,11 @@ export function select(id) {
781
781
  const dot = document.querySelector(`.group[data-id="${id}"] .unread-dot`);
782
782
  if (dot) dot.classList.add('hidden');
783
783
  updateUnreadBadge();
784
- if (state.filter.tab === 'unread') setTab('all');
784
+ if (state.filter.tab === 'unread') {
785
+ const hasMoreUnread = [...state.terms].some(([otherId, other]) => otherId !== id && other.unread);
786
+ if (hasMoreUnread) applyFilter();
787
+ else setTab('all');
788
+ }
785
789
  }
786
790
  entry.term.scrollToBottom();
787
791
  if (!document.querySelector('[contenteditable="true"]')) entry.term.focus();