cicy-desktop 2.1.252 → 2.1.254
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": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.254",
|
|
4
4
|
"description": "CiCy - AI-powered operating system browser",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -139,10 +139,10 @@
|
|
|
139
139
|
"//optionalDependencies": "(2026-06 回调): mac/linux 改回 native cicy-code(:8008,colima 在 16G mac 上压垮内存)→ 重新内置 cicy-code-<plat> / cicy-mihomo-<plat>,localbin.fromBundle 零网络 seed(npm 仅作更新通道,带 npmmirror→npmjs 回退)。这些由 scripts/sync-runtime-deps.cjs 在 tag-push 时同步到最新版。npm 的 os/cpu 字段保证每个平台只装自己那份。Windows 仍走 docker(WSL :8009),它那份 cicy-code-windows 用不到但 bundle 着无害。",
|
|
140
140
|
"optionalDependencies": {
|
|
141
141
|
"electron": "41.0.3",
|
|
142
|
-
"cicy-code-darwin-x64": "2.3.
|
|
143
|
-
"cicy-code-darwin-arm64": "2.3.
|
|
144
|
-
"cicy-code-linux-x64": "2.3.
|
|
145
|
-
"cicy-code-linux-arm64": "2.3.
|
|
142
|
+
"cicy-code-darwin-x64": "2.3.311",
|
|
143
|
+
"cicy-code-darwin-arm64": "2.3.311",
|
|
144
|
+
"cicy-code-linux-x64": "2.3.311",
|
|
145
|
+
"cicy-code-linux-arm64": "2.3.311",
|
|
146
146
|
"cicy-code-windows-x64": "2.3.193",
|
|
147
147
|
"cicy-mihomo-darwin-x64": "1.10.4",
|
|
148
148
|
"cicy-mihomo-darwin-arm64": "1.10.4",
|
|
@@ -98,7 +98,7 @@ class PanelCells {
|
|
|
98
98
|
},
|
|
99
99
|
});
|
|
100
100
|
const wc = view.webContents;
|
|
101
|
-
try { view.setBackgroundColor("#
|
|
101
|
+
try { view.setBackgroundColor("#ffffff"); } catch (e) {}
|
|
102
102
|
try { wc.cicyAccountIdx = profileIdx; } catch (e) {}
|
|
103
103
|
scrubUA(wc);
|
|
104
104
|
try { require("../utils/context-menu-options").attachContextMenu(wc); } catch (e) {}
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
.cbtn{flex:0 0 24px;width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:var(--muted);cursor:default}
|
|
64
64
|
.cbtn:hover{background:rgba(255,255,255,.10);color:#fff}
|
|
65
65
|
.cbtn.close:hover{background:rgba(249,112,102,.18);color:#f97066}
|
|
66
|
-
.cell__body{position:relative;flex:1;min-height:0;background:#
|
|
67
|
-
.cell__body webview{position:absolute;inset:0;width:100%;height:100
|
|
66
|
+
.cell__body{position:relative;flex:1;min-height:0;background:#fff}
|
|
67
|
+
.cell__body webview{position:absolute;inset:0;width:100%;height:100%;background:#fff}
|
|
68
68
|
/* while dragging a divider, a transparent shield stops webviews from
|
|
69
69
|
swallowing pointermove (webview = separate guest, events die inside it) */
|
|
70
70
|
.cell__body .shield{position:absolute;inset:0;display:none;z-index:5}
|
|
@@ -132,12 +132,24 @@
|
|
|
132
132
|
const emptyEl = document.getElementById('empty');
|
|
133
133
|
const fabEl = document.getElementById('fab');
|
|
134
134
|
let suspendVersion = 0;
|
|
135
|
+
const nextFrame = () => new Promise((resolve) => requestAnimationFrame(resolve));
|
|
135
136
|
async function suspendNativeViews() {
|
|
136
137
|
if (!NATIVE) return;
|
|
137
138
|
const version = ++suspendVersion;
|
|
138
139
|
try {
|
|
139
140
|
const shots = await window.panelAPI.snapshots();
|
|
140
141
|
if (version !== suspendVersion) return;
|
|
142
|
+
// Decode every data URL before detaching the BrowserViews. Setting a
|
|
143
|
+
// background-image and detaching in the same frame exposes the black cell
|
|
144
|
+
// background while Chromium is still decoding the snapshot.
|
|
145
|
+
await Promise.all((shots || []).map((shot) => new Promise((resolve) => {
|
|
146
|
+
if (!shot.dataUrl) return resolve();
|
|
147
|
+
const image = new Image();
|
|
148
|
+
image.onload = image.onerror = resolve;
|
|
149
|
+
image.src = shot.dataUrl;
|
|
150
|
+
if (image.complete) resolve();
|
|
151
|
+
})));
|
|
152
|
+
if (version !== suspendVersion) return;
|
|
141
153
|
for (const shot of shots || []) {
|
|
142
154
|
const cell = cells.get(Number(shot.id)) || cells.get(shot.id);
|
|
143
155
|
if (!cell || !shot.dataUrl) continue;
|
|
@@ -145,20 +157,32 @@
|
|
|
145
157
|
cell.body.style.backgroundSize = 'cover';
|
|
146
158
|
cell.body.style.backgroundPosition = 'center top';
|
|
147
159
|
}
|
|
160
|
+
// Let the decoded backgrounds paint before removing the native views.
|
|
161
|
+
await nextFrame();
|
|
162
|
+
await nextFrame();
|
|
163
|
+
if (version !== suspendVersion) return;
|
|
148
164
|
window.panelAPI.dragging(true);
|
|
149
165
|
} catch (e) {
|
|
150
|
-
|
|
166
|
+
if (version === suspendVersion) {
|
|
167
|
+
try { window.panelAPI.dragging(true); } catch (_) {}
|
|
168
|
+
}
|
|
151
169
|
}
|
|
152
170
|
}
|
|
153
171
|
function resumeNativeViews() {
|
|
154
172
|
if (!NATIVE) return;
|
|
155
|
-
suspendVersion
|
|
173
|
+
const version = ++suspendVersion;
|
|
156
174
|
try { window.panelAPI.dragging(false); } catch (e) {}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
// Keep the snapshot behind the reattached BrowserView for a couple frames;
|
|
176
|
+
// clearing synchronously can reveal black before its compositor surface is
|
|
177
|
+
// visible again.
|
|
178
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
179
|
+
if (version !== suspendVersion) return;
|
|
180
|
+
for (const cell of cells.values()) {
|
|
181
|
+
cell.body.style.backgroundImage = '';
|
|
182
|
+
cell.body.style.backgroundSize = '';
|
|
183
|
+
cell.body.style.backgroundPosition = '';
|
|
184
|
+
}
|
|
185
|
+
}));
|
|
162
186
|
}
|
|
163
187
|
|
|
164
188
|
const newLeaf = (url, profile = 1) => ({ type: 'leaf', id: seq++, url: url || '', profile: Number(profile) > 0 ? Number(profile) : 1 });
|
|
@@ -338,6 +362,9 @@
|
|
|
338
362
|
aistudio: '<img src="https://www.gstatic.com/images/branding/productlogos/ai_studio/v1/web-64dp/logo_ai_studio_color_1x_web_64dp.png" alt="">',
|
|
339
363
|
grok: '<img src="https://upload.wikimedia.org/wikipedia/commons/f/f4/Grok_logo_without_text.svg" alt="">',
|
|
340
364
|
chatgpt: '<img src="http://127.0.0.1:8008/openai.svg" alt="">',
|
|
365
|
+
myip: '<svg viewBox="0 0 24 24" fill="none" stroke="#60a5fa" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.4 2.5 3.6 5.5 3.6 9S14.4 18.5 12 21M12 3C9.6 5.5 8.4 8.5 8.4 12S9.6 18.5 12 21"/></svg>',
|
|
366
|
+
colab: '<img src="https://ssl.gstatic.com/colaboratory-static/common/52d6fb476890a764bd46064a9a454157/img/favicon.ico" alt="">',
|
|
367
|
+
drive: '<img src="https://ssl.gstatic.com/images/branding/product/2x/drive_2020q4_48dp.png" alt="">',
|
|
341
368
|
agent: '<svg viewBox="0 0 24 24" fill="none"><rect x="3" y="5" width="18" height="16" rx="5" fill="#2563eb"/><path d="M9 2h6M12 2v3M8 12h.01M16 12h.01M8 16c2.5 1.7 5.5 1.7 8 0" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>',
|
|
342
369
|
};
|
|
343
370
|
const AGENT_LOGOS = {
|
|
@@ -357,7 +384,25 @@
|
|
|
357
384
|
{ id: 'aistudio', name: 'Google AI Studio', meta: 'Google AI', url: 'https://aistudio.google.com/' },
|
|
358
385
|
{ id: 'grok', name: 'Grok', meta: 'xAI', url: 'https://grok.com/' },
|
|
359
386
|
{ id: 'chatgpt', name: 'ChatGPT', meta: 'OpenAI', url: 'https://chatgpt.com/' },
|
|
387
|
+
{ id: 'myip', name: 'My IP', meta: 'api.myip.com', url: 'https://api.myip.com/' },
|
|
388
|
+
{ id: 'colab', name: 'Google Colab', meta: 'Google Research', url: 'https://colab.research.google.com/' },
|
|
389
|
+
{ id: 'drive', name: 'Google Drive', meta: 'Google Workspace', url: 'https://drive.google.com/' },
|
|
360
390
|
];
|
|
391
|
+
const CUSTOM_SERVICES_KEY = 'cicy_panel_custom_services';
|
|
392
|
+
function readCustomServices() {
|
|
393
|
+
try {
|
|
394
|
+
const rows = JSON.parse(localStorage.getItem(CUSTOM_SERVICES_KEY) || '[]');
|
|
395
|
+
return Array.isArray(rows) ? rows.filter((x) => x && x.name && x.url).slice(0, 50) : [];
|
|
396
|
+
} catch (e) { return []; }
|
|
397
|
+
}
|
|
398
|
+
let customServices = readCustomServices();
|
|
399
|
+
function saveCustomService(url) {
|
|
400
|
+
let name = url;
|
|
401
|
+
try { name = new URL(url).hostname || url; } catch (e) {}
|
|
402
|
+
const old = customServices.find((x) => x.url === url);
|
|
403
|
+
if (!old) customServices.push({ name, url });
|
|
404
|
+
try { localStorage.setItem(CUSTOM_SERVICES_KEY, JSON.stringify(customServices)); } catch (e) {}
|
|
405
|
+
}
|
|
361
406
|
let agentList = [];
|
|
362
407
|
let agentsPromise = null;
|
|
363
408
|
function loadAgents() {
|
|
@@ -405,7 +450,17 @@
|
|
|
405
450
|
document.body.appendChild(picker);
|
|
406
451
|
const search = picker.querySelector('.service-search');
|
|
407
452
|
search.oninput = () => renderPicker(search.value);
|
|
408
|
-
search.onkeydown = (e) => {
|
|
453
|
+
search.onkeydown = (e) => {
|
|
454
|
+
if (e.key === 'Escape') closePicker();
|
|
455
|
+
if (e.key === 'Enter') {
|
|
456
|
+
const custom = customUrlFromQuery(search.value);
|
|
457
|
+
if (!custom || !pickerState) return;
|
|
458
|
+
e.preventDefault();
|
|
459
|
+
const id = pickerState.leafId;
|
|
460
|
+
closePicker();
|
|
461
|
+
setCellUrl(id, custom);
|
|
462
|
+
}
|
|
463
|
+
};
|
|
409
464
|
document.addEventListener('pointerdown', (e) => {
|
|
410
465
|
if (pickerState && !picker.contains(e.target) && !pickerState.trigger.contains(e.target)) closePicker();
|
|
411
466
|
});
|
|
@@ -426,13 +481,19 @@
|
|
|
426
481
|
list.innerHTML = '';
|
|
427
482
|
const q = String(query || '').trim().toLowerCase();
|
|
428
483
|
const current = selectedServiceValue(pickerState.url);
|
|
484
|
+
const custom = customUrlFromQuery(query);
|
|
429
485
|
const services = SERVICES.filter((s) => !q || `${s.name} ${s.meta}`.toLowerCase().includes(q));
|
|
486
|
+
const customs = customServices.filter((s) => !q || `${s.name} ${s.url}`.toLowerCase().includes(q));
|
|
430
487
|
const agents = agentList.filter((a) => !q || `${a.id} ${a.title} ${a.type}`.toLowerCase().includes(q));
|
|
431
488
|
const addSection = (label) => { const d = document.createElement('div'); d.className = 'service-section'; d.textContent = label; list.appendChild(d); };
|
|
432
489
|
if (services.length) {
|
|
433
490
|
addSection('应用');
|
|
434
491
|
for (const s of services) list.appendChild(pickerItem(ICONS[s.id], s.name, s.meta, s.url, current === s.url));
|
|
435
492
|
}
|
|
493
|
+
if (customs.length) {
|
|
494
|
+
addSection('自定义');
|
|
495
|
+
for (const s of customs) list.appendChild(pickerItem(ICONS.apps, s.name, s.url, s.url, pickerState.url === s.url));
|
|
496
|
+
}
|
|
436
497
|
if (agents.length) {
|
|
437
498
|
addSection('CiCy Code Agents');
|
|
438
499
|
for (const a of agents) {
|
|
@@ -440,14 +501,24 @@
|
|
|
440
501
|
list.appendChild(pickerItem(agentIcon(a.type), a.title || a.id, `${a.id} · ${a.type || 'agent'}`, url, current === url));
|
|
441
502
|
}
|
|
442
503
|
}
|
|
443
|
-
if (
|
|
504
|
+
if (custom) {
|
|
505
|
+
addSection('自定义 URL');
|
|
506
|
+
list.appendChild(pickerItem(ICONS.apps, query.trim(), custom, custom, pickerState.url === custom));
|
|
507
|
+
if (!customServices.some((x) => x.url === custom)) {
|
|
508
|
+
const add = pickerItem(ICONS.apps, '保存为自定义条目', custom, custom, false);
|
|
509
|
+
add.onclick = () => { saveCustomService(custom); renderPicker(query); };
|
|
510
|
+
list.appendChild(add);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!services.length && !customs.length && !agents.length && !custom) list.innerHTML = '<div class="service-empty">没有匹配结果</div>';
|
|
444
514
|
}
|
|
445
|
-
function openPicker(leafId, trigger, url) {
|
|
515
|
+
async function openPicker(leafId, trigger, url) {
|
|
446
516
|
if (pickerState) closePicker();
|
|
447
517
|
const pop = ensurePicker();
|
|
448
518
|
pickerState = { leafId, trigger, url: url || '' };
|
|
519
|
+
await suspendNativeViews();
|
|
520
|
+
if (!pickerState || pickerState.leafId !== leafId) return;
|
|
449
521
|
trigger.classList.add('open');
|
|
450
|
-
suspendNativeViews();
|
|
451
522
|
pop.classList.add('open');
|
|
452
523
|
const r = trigger.getBoundingClientRect();
|
|
453
524
|
const left = Math.max(8, Math.min(r.left, innerWidth - Math.min(340, innerWidth - 16) - 8));
|
|
@@ -491,6 +562,8 @@
|
|
|
491
562
|
if (!hit || isLocalCicyCode(hit.node.url)) return;
|
|
492
563
|
const profiles = await loadProfiles();
|
|
493
564
|
if (!findParent(root, leafId)) return;
|
|
565
|
+
await suspendNativeViews();
|
|
566
|
+
if (!findParent(root, leafId)) { resumeNativeViews(); return; }
|
|
494
567
|
const pop = document.createElement('div'); pop.className = 'profile-pop';
|
|
495
568
|
const rows = profiles.length ? profiles : [{ accountIdx: 1, name: '' }];
|
|
496
569
|
for (const p of rows) {
|
|
@@ -520,7 +593,6 @@
|
|
|
520
593
|
pop.style.top = Math.min(r.bottom + 6, innerHeight - Math.min(300, pop.offsetHeight) - 8) + 'px';
|
|
521
594
|
trigger.classList.add('open');
|
|
522
595
|
profilePop = { el: pop, trigger };
|
|
523
|
-
suspendNativeViews();
|
|
524
596
|
}
|
|
525
597
|
document.addEventListener('pointerdown', (e) => {
|
|
526
598
|
if (profilePop && !profilePop.el.contains(e.target) && !profilePop.trigger.contains(e.target)) closeProfilePicker();
|
|
@@ -538,6 +610,15 @@
|
|
|
538
610
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(v) || /^about:/i.test(v)) return v;
|
|
539
611
|
return (/\.\w/.test(v) && !/\s/.test(v)) ? 'https://' + v : 'https://www.google.com/search?q=' + encodeURIComponent(v);
|
|
540
612
|
}
|
|
613
|
+
function customUrlFromQuery(v) {
|
|
614
|
+
const raw = String(v || '').trim();
|
|
615
|
+
if (!raw || /\s/.test(raw)) return '';
|
|
616
|
+
const looksLikeUrl = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw)
|
|
617
|
+
|| /^localhost(?::\d+)?(?:\/|$)/i.test(raw)
|
|
618
|
+
|| /^(?:\d{1,3}\.){3}\d{1,3}(?::\d+)?(?:\/|$)/.test(raw)
|
|
619
|
+
|| /^[\w-]+(?:\.[\w-]+)+(?:\/|$)/.test(raw);
|
|
620
|
+
return looksLikeUrl ? normalizeUrl(raw) : '';
|
|
621
|
+
}
|
|
541
622
|
function mountCell(leaf) {
|
|
542
623
|
const el = document.createElement('div');
|
|
543
624
|
el.className = 'cell';
|