kingkont 0.7.39 → 0.7.40

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,25 @@ ipcMain.handle('claudeMd:template', () => {
153
154
  catch { return ''; }
154
155
  });
155
156
 
157
+ // Установить kingkont skill в ~/.claude/skills/kingkont/SKILL.md.
158
+ // То же самое что `kingkont install-skill` в CLI — для юзеров которые
159
+ // никогда не запускали bin/kingkont напрямую (только Electron-приложение).
160
+ ipcMain.handle('claudeMd:installSkill', () => {
161
+ try {
162
+ const src = path.join(__dirname, 'skill', 'SKILL.md');
163
+ if (!fs.existsSync(src)) {
164
+ return { ok: false, error: 'Шаблон skill/SKILL.md не найден в пакете' };
165
+ }
166
+ const dest = path.join(os.homedir(), '.claude', 'skills', 'kingkont');
167
+ fs.mkdirSync(dest, { recursive: true });
168
+ const destFile = path.join(dest, 'SKILL.md');
169
+ fs.copyFileSync(src, destFile);
170
+ return { ok: true, path: destFile };
171
+ } catch (e) {
172
+ return { ok: false, error: e?.message || String(e) };
173
+ }
174
+ });
175
+
156
176
  ipcMain.handle('settings:get', () => readSettings());
157
177
  ipcMain.handle('settings:save', (_e, partial) => {
158
178
  const cur = readSettings();
@@ -476,6 +496,8 @@ ipcMain.handle('updates:install', async (e, target = 'latest') => {
476
496
  });
477
497
  });
478
498
 
499
+ ipcMain.handle('app:version', () => app.getVersion());
500
+
479
501
  ipcMain.handle('app:relaunch', () => {
480
502
  // app.relaunch() запускает ТЕКУЩИЙ execPath. Если юзер обновился через
481
503
  // `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.40",
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,8 @@
59
61
  "index.html",
60
62
  "settings.html",
61
63
  "assets/**/*",
64
+ "lib/**/*",
65
+ "renderer/**/*",
62
66
  "package.json",
63
67
  "updates.html"
64
68
  ],
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
  });