kingkont 0.7.39 → 0.7.41

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.
@@ -0,0 +1,70 @@
1
+ // Загрузка настроек KingKont — общая для server.js, main.js (Electron) и
2
+ // bin/kingkont.js (CLI). Источник правды — userData/settings.json,
3
+ // который пишется главным процессом Electron.
4
+ //
5
+ // Структура settings.json:
6
+ // {
7
+ // // Провайдеры — какие включены (use* checkbox в UI):
8
+ // useChatium: bool,
9
+ // useOpenrouter: bool,
10
+ // useElevenlabs: bool,
11
+ // useKie: bool,
12
+ // // Прямые ключи (если юзер подключил провайдеров напрямую):
13
+ // kieKey: '...',
14
+ // elevenKey: '...',
15
+ // openrouterKey: '...',
16
+ // // Chatium-сессия (логин по token-flow):
17
+ // chatium: { token: '...', base: 'https://kingkont.ru', userId, appName }
18
+ // }
19
+
20
+ 'use strict';
21
+
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+ const path = require('node:path');
25
+
26
+ /**
27
+ * Кросс-платформенный путь к userData/settings.json.
28
+ * macOS: ~/Library/Application Support/KingKont/settings.json
29
+ * Linux: ~/.config/KingKont/settings.json
30
+ * Windows: %APPDATA%\KingKont\settings.json
31
+ */
32
+ function defaultSettingsPath() {
33
+ if (process.platform === 'darwin') {
34
+ return path.join(os.homedir(), 'Library', 'Application Support', 'KingKont', 'settings.json');
35
+ }
36
+ if (process.platform === 'win32') {
37
+ const appData = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
38
+ return path.join(appData, 'KingKont', 'settings.json');
39
+ }
40
+ return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'KingKont', 'settings.json');
41
+ }
42
+
43
+ /** Прочитать settings.json. Если нет — вернёт {} (не падаем). */
44
+ function loadSettings(p = defaultSettingsPath()) {
45
+ try {
46
+ if (!fs.existsSync(p)) return {};
47
+ return JSON.parse(fs.readFileSync(p, 'utf-8'));
48
+ } catch {
49
+ return {};
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Прокидывает прямые API-ключи в process.env, если они есть.
55
+ * server.js / lib/providers ожидают KIE_API_KEY / ELEVENLABS_API_KEY /
56
+ * OPENROUTER_API_KEY в env (исторически, для совместимости с .env).
57
+ * Безопасно вызывать многократно.
58
+ */
59
+ function applySettingsToEnv(s) {
60
+ if (!s) return;
61
+ if (s.kieKey) process.env.KIE_API_KEY = s.kieKey;
62
+ if (s.elevenKey) process.env.ELEVENLABS_API_KEY = s.elevenKey;
63
+ if (s.openrouterKey) process.env.OPENROUTER_API_KEY = s.openrouterKey;
64
+ }
65
+
66
+ module.exports = {
67
+ defaultSettingsPath,
68
+ loadSettings,
69
+ applySettingsToEnv,
70
+ };
package/main.js CHANGED
@@ -9,6 +9,7 @@ app.setName('KingKont');
9
9
  const { spawn } = require('node:child_process');
10
10
  const path = require('node:path');
11
11
  const fs = require('node:fs');
12
+ const os = require('node:os');
12
13
  const { start } = require('./server');
13
14
 
14
15
  let win = null;
@@ -153,6 +154,31 @@ ipcMain.handle('claudeMd:template', () => {
153
154
  catch { return ''; }
154
155
  });
155
156
 
157
+ // Установить kingkont skill в ~/.claude/skills/kingkont/SKILL.md
158
+ // (на Windows: %USERPROFILE%\.claude\skills\kingkont\SKILL.md).
159
+ // То же самое что `kingkont install-skill` в CLI — для юзеров которые
160
+ // никогда не запускали bin/kingkont напрямую (только Electron-приложение).
161
+ //
162
+ // Read+write, не copyFileSync — source может лежать внутри app.asar в
163
+ // bundled-сборке (.dmg/.exe), там copy с asar→disk периодически глючит.
164
+ ipcMain.handle('claudeMd:installSkill', () => {
165
+ try {
166
+ const src = path.join(__dirname, 'skill', 'SKILL.md');
167
+ let buf;
168
+ try { buf = fs.readFileSync(src); }
169
+ catch (e) {
170
+ return { ok: false, error: 'Шаблон skill/SKILL.md не найден в пакете: ' + e.message };
171
+ }
172
+ const dest = path.join(os.homedir(), '.claude', 'skills', 'kingkont');
173
+ fs.mkdirSync(dest, { recursive: true });
174
+ const destFile = path.join(dest, 'SKILL.md');
175
+ fs.writeFileSync(destFile, buf);
176
+ return { ok: true, path: destFile };
177
+ } catch (e) {
178
+ return { ok: false, error: e?.message || String(e) };
179
+ }
180
+ });
181
+
156
182
  ipcMain.handle('settings:get', () => readSettings());
157
183
  ipcMain.handle('settings:save', (_e, partial) => {
158
184
  const cur = readSettings();
@@ -476,6 +502,8 @@ ipcMain.handle('updates:install', async (e, target = 'latest') => {
476
502
  });
477
503
  });
478
504
 
505
+ ipcMain.handle('app:version', () => app.getVersion());
506
+
479
507
  ipcMain.handle('app:relaunch', () => {
480
508
  // app.relaunch() запускает ТЕКУЩИЙ execPath. Если юзер обновился через
481
509
  // `npm i -g`, новая kingkont лежит в global-bin, а не в npx-кэше где сидит
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.7.39",
3
+ "version": "0.7.41",
4
4
  "description": "KingKont \u00b7 Chatium \u2014 \u043d\u043e\u0434-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0441\u0446\u0435\u043d \u0441 AI-\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 (\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438/\u0432\u0438\u0434\u0435\u043e/\u0433\u043e\u043b\u043e\u0441/SFX/\u043c\u0443\u0437\u044b\u043a\u0430/\u0442\u0435\u043a\u0441\u0442)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -14,6 +14,8 @@
14
14
  "settings.html",
15
15
  "assets/**/*",
16
16
  "bin/**/*",
17
+ "lib/**/*",
18
+ "renderer/**/*",
17
19
  "scripts/**/*",
18
20
  "skill/**/*",
19
21
  "README.md",
@@ -59,6 +61,9 @@
59
61
  "index.html",
60
62
  "settings.html",
61
63
  "assets/**/*",
64
+ "lib/**/*",
65
+ "renderer/**/*",
66
+ "skill/**/*",
62
67
  "package.json",
63
68
  "updates.html"
64
69
  ],
package/preload.js CHANGED
@@ -29,6 +29,12 @@ contextBridge.exposeInMainWorld('appWindow', {
29
29
  minimize: () => ipcRenderer.invoke('window:minimize'),
30
30
  });
31
31
 
32
+ // Версия приложения — пробрасываем app.getVersion() из main, чтобы рендер
33
+ // показывал актуальный номер на welcome-экране и в шапке.
34
+ contextBridge.exposeInMainWorld('appInfo', {
35
+ version: () => ipcRenderer.invoke('app:version'),
36
+ });
37
+
32
38
  contextBridge.exposeInMainWorld('appProject', {
33
39
  notifyState: (isOpen) => ipcRenderer.send('project:state', !!isOpen),
34
40
  });
@@ -76,4 +82,5 @@ contextBridge.exposeInMainWorld('appChatium', {
76
82
 
77
83
  contextBridge.exposeInMainWorld('claudeMd', {
78
84
  template: () => ipcRenderer.invoke('claudeMd:template'),
85
+ installSkill: () => ipcRenderer.invoke('claudeMd:installSkill'),
79
86
  });