kingkont 0.4.0 → 0.6.0

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/main.js CHANGED
@@ -185,8 +185,30 @@ function buildMenu() {
185
185
  const sendToRenderer = (channel) => {
186
186
  if (win && !win.isDestroyed()) win.webContents.send(channel);
187
187
  };
188
+ // На macOS первый пункт menubar строится явно — чтобы:
189
+ // 1) показать «KingKont» (а не «Electron» из бандла, если кэш macOS
190
+ // не подхватил CFBundleName);
191
+ // 2) положить «Настройки…» сюда (стандартное место Preferences для macOS),
192
+ // убрав его из «Файл».
193
+ const appMenu = isMac ? [{
194
+ label: 'KingKont',
195
+ submenu: [
196
+ { label: 'О программе KingKont', role: 'about' },
197
+ { type: 'separator' },
198
+ { label: 'Настройки…', accelerator: 'Cmd+,', click: () => sendToRenderer('menu:open-settings') },
199
+ { type: 'separator' },
200
+ { role: 'services' },
201
+ { type: 'separator' },
202
+ { label: 'Скрыть KingKont', accelerator: 'Cmd+H', role: 'hide' },
203
+ { role: 'hideOthers' },
204
+ { role: 'unhide' },
205
+ { type: 'separator' },
206
+ { label: 'Завершить KingKont', accelerator: 'Cmd+Q', role: 'quit' },
207
+ ],
208
+ }] : [];
209
+
188
210
  const template = [
189
- ...(isMac ? [{ role: 'appMenu' }] : []),
211
+ ...appMenu,
190
212
  {
191
213
  label: 'Файл',
192
214
  submenu: [
@@ -209,21 +231,20 @@ function buildMenu() {
209
231
  click: () => trigger('#newLocation'),
210
232
  },
211
233
  { type: 'separator' },
212
- {
213
- label: 'Настройки…',
214
- accelerator: 'CmdOrCtrl+,',
215
- click: () => sendToRenderer('menu:open-settings'),
216
- },
217
- { type: 'separator' },
218
234
  {
219
235
  label: 'Закрыть',
220
236
  accelerator: 'CmdOrCtrl+W',
221
237
  // Cmd+W: если проект открыт → закрывает проект (renderer решает),
222
- // если проект уже закрыт → закрывает окно (на macOS приложение
223
- // остаётся в Dock; на Windows/Linux окно — последнее, app.quit).
238
+ // если проект уже закрыт → закрывает окно.
224
239
  click: () => sendToRenderer('menu:close-window-or-project'),
225
240
  },
226
- ...(isMac ? [] : [{ type: 'separator' }, { role: 'quit' }]),
241
+ // На Windows/Linux нужен явный «Настройки» и «Quit», т.к. App-меню нет.
242
+ ...(isMac ? [] : [
243
+ { type: 'separator' },
244
+ { label: 'Настройки…', accelerator: 'CmdOrCtrl+,', click: () => sendToRenderer('menu:open-settings') },
245
+ { type: 'separator' },
246
+ { role: 'quit' },
247
+ ]),
227
248
  ],
228
249
  },
229
250
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "server": "node server.js",
29
29
  "pack": "electron-builder --dir",
30
30
  "dist": "electron-builder",
31
- "postinstall": "if [ \"$(uname)\" = \"Darwin\" ] && [ -d node_modules/electron ]; then bash scripts/patch-electron-name.sh || true; fi"
31
+ "postinstall": "node scripts/patch-electron-name.js"
32
32
  },
33
33
  "dependencies": {
34
34
  "electron": "^32.2.0"
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ // Переименовывает dev-Electron бандл в «KingKont» — в menubar macOS,
3
+ // Activity Monitor, Dock-tooltip и пр. Запускается через postinstall.
4
+ // Идемпотентно. Молча выходит если что-то не так — это не критическая
5
+ // часть установки.
6
+ 'use strict';
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+ const { execFileSync } = require('node:child_process');
10
+
11
+ if (process.platform !== 'darwin') process.exit(0);
12
+
13
+ let electronExe;
14
+ try { electronExe = require('electron'); }
15
+ catch (e) {
16
+ console.warn('[kingkont postinstall] electron not found, skip rename:', e.message);
17
+ process.exit(0);
18
+ }
19
+ // require('electron') возвращает путь к бинарю. На macOS это:
20
+ // node_modules/electron/dist/Electron.app/Contents/MacOS/Electron
21
+ // Если уже переименовано — KingKont.app/Contents/MacOS/KingKont
22
+ const macOsDir = path.dirname(electronExe); // .../MacOS
23
+ const contentsDir = path.dirname(macOsDir); // .../Contents
24
+ const appBundle = path.dirname(contentsDir); // .../Electron.app или KingKont.app
25
+ const dist = path.dirname(appBundle); // .../dist
26
+ const electronPkg = path.dirname(dist); // .../electron
27
+
28
+ const oldApp = path.join(dist, 'Electron.app');
29
+ const newApp = path.join(dist, 'KingKont.app');
30
+
31
+ // Уже переименовано?
32
+ if (fs.existsSync(newApp) && !fs.existsSync(oldApp)) {
33
+ // Убедимся что иконка из нашего пакета актуальна (на случай обновления).
34
+ ensureIcon(newApp);
35
+ process.exit(0);
36
+ }
37
+ if (!fs.existsSync(oldApp)) {
38
+ console.warn('[kingkont postinstall] Electron.app not found at', oldApp);
39
+ process.exit(0);
40
+ }
41
+
42
+ console.log('[kingkont postinstall] Electron → KingKont…');
43
+
44
+ // 1) main bundle + бинарь
45
+ fs.renameSync(oldApp, newApp);
46
+ fs.renameSync(path.join(newApp, 'Contents', 'MacOS', 'Electron'),
47
+ path.join(newApp, 'Contents', 'MacOS', 'KingKont'));
48
+
49
+ // 2) Helpers
50
+ const fwDir = path.join(newApp, 'Contents', 'Frameworks');
51
+ const helpers = [
52
+ ['Electron Helper.app', 'KingKont Helper.app'],
53
+ ['Electron Helper (GPU).app', 'KingKont Helper (GPU).app'],
54
+ ['Electron Helper (Plugin).app', 'KingKont Helper (Plugin).app'],
55
+ ['Electron Helper (Renderer).app','KingKont Helper (Renderer).app'],
56
+ ];
57
+ for (const [oldH, newH] of helpers) {
58
+ const o = path.join(fwDir, oldH);
59
+ const n = path.join(fwDir, newH);
60
+ if (!fs.existsSync(o)) continue;
61
+ fs.renameSync(o, n);
62
+ const oldBin = oldH.replace(/\.app$/, '');
63
+ const newBin = newH.replace(/\.app$/, '');
64
+ fs.renameSync(path.join(n, 'Contents', 'MacOS', oldBin),
65
+ path.join(n, 'Contents', 'MacOS', newBin));
66
+ patchPlist(path.join(n, 'Contents', 'Info.plist'), {
67
+ CFBundleExecutable: newBin,
68
+ CFBundleName: newBin,
69
+ CFBundleDisplayName: newBin,
70
+ });
71
+ }
72
+
73
+ // 3) Info.plist главного app
74
+ patchPlist(path.join(newApp, 'Contents', 'Info.plist'), {
75
+ CFBundleExecutable: 'KingKont',
76
+ CFBundleName: 'KingKont',
77
+ CFBundleDisplayName: 'KingKont',
78
+ });
79
+
80
+ // 4) electron/path.txt — npm-обёртка читает его при require('electron')
81
+ fs.writeFileSync(path.join(electronPkg, 'path.txt'),
82
+ 'KingKont.app/Contents/MacOS/KingKont');
83
+
84
+ // 5) Иконка
85
+ ensureIcon(newApp);
86
+
87
+ // 6) Ad-hoc resign — без неё macOS Sequoia может убить процесс при старте.
88
+ try {
89
+ execFileSync('codesign', ['--force', '--deep', '--sign', '-', newApp], { stdio: 'ignore' });
90
+ } catch {}
91
+
92
+ // 7) Refresh LaunchServices
93
+ try {
94
+ execFileSync('/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister',
95
+ ['-f', newApp], { stdio: 'ignore' });
96
+ } catch {}
97
+
98
+ console.log('[kingkont postinstall] ✓ KingKont готов');
99
+
100
+ // === helpers ===
101
+
102
+ function patchPlist(plistPath, fields) {
103
+ if (!fs.existsSync(plistPath)) return;
104
+ for (const [k, v] of Object.entries(fields)) {
105
+ // Сначала Set; если ключа нет — Add.
106
+ try {
107
+ execFileSync('/usr/libexec/PlistBuddy', ['-c', `Set :${k} ${v}`, plistPath], { stdio: 'ignore' });
108
+ } catch {
109
+ try {
110
+ execFileSync('/usr/libexec/PlistBuddy', ['-c', `Add :${k} string ${v}`, plistPath], { stdio: 'ignore' });
111
+ } catch {}
112
+ }
113
+ }
114
+ }
115
+
116
+ function ensureIcon(bundle) {
117
+ // Этот скрипт лежит в <pkg>/scripts/, иконка в <pkg>/assets/logo.icns.
118
+ const src = path.join(__dirname, '..', 'assets', 'logo.icns');
119
+ const dst = path.join(bundle, 'Contents', 'Resources', 'electron.icns');
120
+ if (!fs.existsSync(src)) return;
121
+ try {
122
+ fs.copyFileSync(src, dst);
123
+ } catch {}
124
+ }