kingkont 0.7.65 → 0.7.66

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/index.html CHANGED
@@ -457,6 +457,38 @@
457
457
  </div>
458
458
 
459
459
  <!-- ===== Полноэкранный просмотр (image/video) ===== -->
460
+ <!-- ===== Updates overlay (вместо отдельного BrowserWindow — на Sequoia
461
+ child-windows крашат V8 в ValueSerializer). ===== -->
462
+ <div class="modal hidden" id="updatesOverlay">
463
+ <div class="modal-card" style="min-width:480px; max-width:560px;">
464
+ <h3>Обновления KingKont</h3>
465
+ <div class="hint" style="margin-bottom:14px;">Источник: <code>registry.npmjs.org/kingkont</code></div>
466
+ <div style="display:flex; gap:24px; margin-bottom:14px;">
467
+ <div style="flex:1;">
468
+ <div style="color:#888; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:4px;">Установлено</div>
469
+ <div id="upCurrent" style="font-size:18px; font-family:ui-monospace,monospace;">—</div>
470
+ </div>
471
+ <div style="flex:1;">
472
+ <div style="color:#888; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:4px;">Доступно</div>
473
+ <div id="upLatest" style="font-size:18px; font-family:ui-monospace,monospace;">…</div>
474
+ </div>
475
+ </div>
476
+ <div id="upUpdateBlock" style="display:none;">
477
+ <div style="display:flex; gap:8px; align-items:center; margin-bottom:8px; flex-wrap:wrap;">
478
+ <button id="upInstallBtn" class="primary">⬇ Установить и перезапустить</button>
479
+ <button id="upRelaunchBtn" class="primary" style="display:none; background:#16a34a;">↻ Перезапустить сейчас</button>
480
+ </div>
481
+ <pre id="upInstallLog" style="display:none; max-height:200px; overflow-y:auto; margin-top:10px; font-family:ui-monospace,monospace; font-size:11px; line-height:1.4; background:#0e0e0e; border:1px solid #2a2a2a; border-radius:4px; padding:8px 10px; color:#aaa; white-space:pre-wrap; word-break:break-all;"></pre>
482
+ </div>
483
+ <div id="upToDate" style="display:none; color:#16a34a; font-size:12px;">✓ У вас последняя версия.</div>
484
+ <div id="upError" style="display:none; color:#ef4444; font-size:12px; margin-top:12px;"></div>
485
+ <div class="modal-actions">
486
+ <button id="upRecheck">Проверить ещё раз</button>
487
+ <button id="upClose" class="primary">Закрыть</button>
488
+ </div>
489
+ </div>
490
+ </div>
491
+
460
492
  <!-- ===== Дефолтные промпты сцены (multi, с тегами kind) ===== -->
461
493
  <div class="modal hidden" id="defaultPromptsModal">
462
494
  <div class="modal-card" style="min-width:600px; max-width:760px;">
package/main.js CHANGED
@@ -398,37 +398,20 @@ ipcMain.handle('settings-window:close', () => {
398
398
  });
399
399
  ipcMain.handle('settings-window:open', () => openSettingsWindow());
400
400
 
401
- // ===== Updates window + npm version check =====
402
- let updatesWin = null;
401
+ // ===== Updates: показываем как overlay внутри основного окна =====
402
+ // Раньше открывалось отдельное BrowserWindow. На macOS Sequoia 15.7 это
403
+ // крашило V8 в ValueSerializer при IPC (даже после bump'а до Electron 33).
404
+ // Решение — рендерить overlay внутри main window'а, child window не создаём.
403
405
  function openUpdatesWindow() {
404
- if (updatesWin && !updatesWin.isDestroyed()) {
405
- updatesWin.focus();
406
- return;
406
+ if (win && !win.isDestroyed()) {
407
+ win.show();
408
+ win.focus();
409
+ win.webContents.send('menu:open-updates');
407
410
  }
408
- // Не используем parent: win — на macOS Sequoia 15.7 + Electron 32 это
409
- // приводит к V8 CHECK-крашу `v8::BackingStore::MaxByteLength` при создании
410
- // child-window. Окно обновлений и так логически независимое.
411
- updatesWin = new BrowserWindow({
412
- width: 480,
413
- height: 380,
414
- title: 'Обновления',
415
- resizable: false,
416
- minimizable: false,
417
- maximizable: false,
418
- backgroundColor: '#1a1a1a',
419
- webPreferences: {
420
- contextIsolation: true,
421
- nodeIntegration: false,
422
- preload: path.join(__dirname, 'preload.js'),
423
- },
424
- });
425
- updatesWin.removeMenu();
426
- updatesWin.loadFile(path.join(__dirname, 'updates.html'));
427
- updatesWin.on('closed', () => { updatesWin = null; });
428
411
  }
429
- ipcMain.handle('updates-window:close', () => {
430
- if (updatesWin && !updatesWin.isDestroyed()) updatesWin.close();
431
- });
412
+ // Старый close-window IPC — оставлен no-op для backward-compat (если old
413
+ // updates.html ещё где-то остался). Renderer теперь сам закрывает overlay.
414
+ ipcMain.handle('updates-window:close', () => { /* no-op */ });
432
415
 
433
416
  // Простой semver-сравнитель: возвращает true если b > a (есть более свежая).
434
417
  // Поддерживает X.Y.Z и pre-release suffix через '-' (rc/beta пропускаем как not-newer).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.7.65",
3
+ "version": "0.7.66",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/preload.js CHANGED
@@ -18,7 +18,7 @@ contextBridge.exposeInMainWorld('appMenu', {
18
18
  on: (channel, cb) => {
19
19
  const allowed = ['open-film', 'new-episode', 'new-character', 'new-location',
20
20
  'undo', 'redo', 'toggle-timeline', 'close-project',
21
- 'close-window-or-project', 'open-settings'];
21
+ 'close-window-or-project', 'open-settings', 'open-updates'];
22
22
  if (!allowed.includes(channel)) return;
23
23
  ipcRenderer.on(`menu:${channel}`, (_e, payload) => cb(payload));
24
24
  },
package/renderer/board.js CHANGED
@@ -36,6 +36,7 @@ window.addEventListener('DOMContentLoaded', async () => {
36
36
  else window.appWindow?.minimize();
37
37
  });
38
38
  window.appMenu.on('open-settings', () => openSettings());
39
+ window.appMenu.on('open-updates', () => openUpdatesOverlay());
39
40
  }
40
41
  // Восстановить состояние панелей таймлайна/превью/реплик
41
42
  const tlOpen = localStorage.getItem('timelineOpen') === '1';
@@ -1315,6 +1316,91 @@ async function selectBoard(board) {
1315
1316
  startExternalWatcher();
1316
1317
  }
1317
1318
 
1319
+ // =============================================================================
1320
+ // Updates overlay — проверка/установка обновлений KingKont прямо в основном
1321
+ // окне (без создания child BrowserWindow, который на macOS Sequoia крашит
1322
+ // V8 в ValueSerializer при IPC).
1323
+ // =============================================================================
1324
+
1325
+ let _updatesUnsubLog = null;
1326
+
1327
+ async function openUpdatesOverlay() {
1328
+ const overlay = $('updatesOverlay');
1329
+ if (!overlay) return;
1330
+ overlay.classList.remove('hidden');
1331
+ // Сброс state.
1332
+ $('upError').style.display = 'none';
1333
+ $('upUpdateBlock').style.display = 'none';
1334
+ $('upToDate').style.display = 'none';
1335
+ $('upInstallLog').style.display = 'none';
1336
+ $('upRelaunchBtn').style.display = 'none';
1337
+ $('upInstallBtn').style.display = '';
1338
+ $('upInstallBtn').disabled = false;
1339
+ $('upInstallBtn').textContent = '⬇ Установить и перезапустить';
1340
+ $('upLatest').textContent = '…';
1341
+ await checkUpdates();
1342
+ }
1343
+
1344
+ async function checkUpdates() {
1345
+ $('upError').style.display = 'none';
1346
+ $('upUpdateBlock').style.display = 'none';
1347
+ $('upToDate').style.display = 'none';
1348
+ $('upLatest').textContent = '…';
1349
+ $('upRecheck').disabled = true;
1350
+ try {
1351
+ const r = await window.appUpdates.check();
1352
+ $('upCurrent').textContent = r.current;
1353
+ $('upLatest').textContent = r.latest;
1354
+ if (r.isNew) {
1355
+ $('upUpdateBlock').style.display = '';
1356
+ } else {
1357
+ $('upToDate').style.display = '';
1358
+ }
1359
+ $('upUpdateBlock').dataset.target = r.latest;
1360
+ } catch (e) {
1361
+ $('upLatest').textContent = '—';
1362
+ $('upError').style.display = '';
1363
+ $('upError').textContent = 'Не удалось проверить: ' + (e?.message || String(e));
1364
+ } finally {
1365
+ $('upRecheck').disabled = false;
1366
+ }
1367
+ }
1368
+
1369
+ document.getElementById('upClose')?.addEventListener('click', () => {
1370
+ $('updatesOverlay').classList.add('hidden');
1371
+ if (_updatesUnsubLog) { _updatesUnsubLog(); _updatesUnsubLog = null; }
1372
+ });
1373
+ document.getElementById('upRecheck')?.addEventListener('click', () => checkUpdates());
1374
+ document.getElementById('upInstallBtn')?.addEventListener('click', async () => {
1375
+ const btn = $('upInstallBtn');
1376
+ const log = $('upInstallLog');
1377
+ const target = $('upUpdateBlock').dataset.target || 'latest';
1378
+ btn.disabled = true;
1379
+ btn.textContent = 'Устанавливаю…';
1380
+ log.style.display = '';
1381
+ log.textContent = '';
1382
+ log.style.color = '#aaa';
1383
+ if (_updatesUnsubLog) _updatesUnsubLog();
1384
+ _updatesUnsubLog = window.appUpdates.onInstallOutput(({ stream, text }) => {
1385
+ log.textContent += text;
1386
+ log.scrollTop = log.scrollHeight;
1387
+ if (stream === 'stderr') log.style.color = '#f88';
1388
+ });
1389
+ try {
1390
+ await window.appUpdates.install(target);
1391
+ btn.style.display = 'none';
1392
+ $('upRelaunchBtn').style.display = '';
1393
+ } catch (e) {
1394
+ log.style.color = '#f88';
1395
+ log.textContent += `\n[error] ${e?.message || String(e)}`;
1396
+ btn.disabled = false;
1397
+ btn.textContent = '⬇ Попробовать снова';
1398
+ } finally {
1399
+ if (_updatesUnsubLog) { _updatesUnsubLog(); _updatesUnsubLog = null; }
1400
+ }
1401
+ });
1402
+ document.getElementById('upRelaunchBtn')?.addEventListener('click', () => window.appUpdates.relaunch());
1403
+
1318
1404
  // =============================================================================
1319
1405
  // External file watcher (FSAH polling).
1320
1406
  // FSAH не имеет нативного file-watch API — поллим scene.json's lastModified