kingkont 0.7.40 → 0.7.42
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/bin/kingkont.js +6 -1
- package/main.js +42 -14
- package/package.json +2 -1
- package/settings.html +12 -2
package/bin/kingkont.js
CHANGED
|
@@ -106,7 +106,12 @@ if (cmd && NODE_COMMANDS[cmd]) {
|
|
|
106
106
|
process.env.PORT = String(port);
|
|
107
107
|
const targetPath = args[1] && !args[1].startsWith('--') ? path.resolve(args[1]) : null;
|
|
108
108
|
const { start } = require(path.join(root, 'server.js'));
|
|
109
|
-
|
|
109
|
+
// Live-чтение settings.json на каждый запрос — так же как в Electron-режиме
|
|
110
|
+
// (main.js). Без этого use*-флаги и chatium.token не доходят до server.js,
|
|
111
|
+
// и провайдеры (chatium / openrouter / kie / elevenlabs) висят выключенными,
|
|
112
|
+
// даже если юзер залогинен через UI приложения.
|
|
113
|
+
const startOpts = { getSettings: () => settingsLib.loadSettings() };
|
|
114
|
+
start(port, startOpts).then(actualPort => {
|
|
110
115
|
const url = `http://localhost:${actualPort}/`;
|
|
111
116
|
console.log(`\n▶ KingKont готов: ${url}`);
|
|
112
117
|
if (targetPath) console.log(` подразумеваемый проект: ${targetPath}`);
|
package/main.js
CHANGED
|
@@ -154,19 +154,25 @@ ipcMain.handle('claudeMd:template', () => {
|
|
|
154
154
|
catch { return ''; }
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
// Установить kingkont skill в ~/.claude/skills/kingkont/SKILL.md
|
|
157
|
+
// Установить kingkont skill в ~/.claude/skills/kingkont/SKILL.md
|
|
158
|
+
// (на Windows: %USERPROFILE%\.claude\skills\kingkont\SKILL.md).
|
|
158
159
|
// То же самое что `kingkont install-skill` в CLI — для юзеров которые
|
|
159
160
|
// никогда не запускали bin/kingkont напрямую (только Electron-приложение).
|
|
161
|
+
//
|
|
162
|
+
// Read+write, не copyFileSync — source может лежать внутри app.asar в
|
|
163
|
+
// bundled-сборке (.dmg/.exe), там copy с asar→disk периодически глючит.
|
|
160
164
|
ipcMain.handle('claudeMd:installSkill', () => {
|
|
161
165
|
try {
|
|
162
166
|
const src = path.join(__dirname, 'skill', 'SKILL.md');
|
|
163
|
-
|
|
164
|
-
|
|
167
|
+
let buf;
|
|
168
|
+
try { buf = fs.readFileSync(src); }
|
|
169
|
+
catch (e) {
|
|
170
|
+
return { ok: false, error: 'Шаблон skill/SKILL.md не найден в пакете: ' + e.message };
|
|
165
171
|
}
|
|
166
172
|
const dest = path.join(os.homedir(), '.claude', 'skills', 'kingkont');
|
|
167
173
|
fs.mkdirSync(dest, { recursive: true });
|
|
168
174
|
const destFile = path.join(dest, 'SKILL.md');
|
|
169
|
-
fs.
|
|
175
|
+
fs.writeFileSync(destFile, buf);
|
|
170
176
|
return { ok: true, path: destFile };
|
|
171
177
|
} catch (e) {
|
|
172
178
|
return { ok: false, error: e?.message || String(e) };
|
|
@@ -758,19 +764,41 @@ app.whenReady().then(async () => {
|
|
|
758
764
|
|
|
759
765
|
// Фиксированный порт нужен потому что Chromium хранит IndexedDB и FSAH-handle
|
|
760
766
|
// per-origin (http://localhost:PORT). Со случайным портом каждый запуск
|
|
761
|
-
// получал бы новую пустую IDB
|
|
762
|
-
//
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
// на
|
|
767
|
+
// получал бы новую пустую IDB и юзер должен заново указывать папки в recents.
|
|
768
|
+
//
|
|
769
|
+
// RETRY на 17893: при relaunch'е старый instance отпускает singleton-lock
|
|
770
|
+
// быстрее, чем macOS освобождает TCP-сокет (TIME_WAIT). Без retry сразу
|
|
771
|
+
// падаем на random и теряем handle. 8×500мс = 4 сек обычно хватает.
|
|
772
|
+
// server.js на каждый запрос читает live-настройки через getSettings —
|
|
773
|
+
// settings.json на диске единственный источник правды.
|
|
766
774
|
const startOpts = { getSettings: () => readSettings() };
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
775
|
+
const PRIMARY_PORT = 17893;
|
|
776
|
+
const RETRIES = 8;
|
|
777
|
+
let lastErr;
|
|
778
|
+
for (let i = 0; i < RETRIES; i++) {
|
|
779
|
+
try { port = await start(PRIMARY_PORT, startOpts); break; }
|
|
780
|
+
catch (e) {
|
|
781
|
+
lastErr = e;
|
|
782
|
+
if (e.code !== 'EADDRINUSE') break; // не race — нет смысла ретраить
|
|
783
|
+
console.warn(`port ${PRIMARY_PORT} busy (attempt ${i + 1}/${RETRIES}), waiting…`);
|
|
784
|
+
await new Promise(r => setTimeout(r, 500));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
if (!port) {
|
|
788
|
+
// Сначала попробуем фиксированные fallback'и (17894/17895/...) —
|
|
789
|
+
// это сохранит хотя бы часть recents (origin будет стабильным от
|
|
790
|
+
// запуска к запуску при условии что 17893 хронически занят).
|
|
791
|
+
for (const p of [17894, 17895, 17896, 17897, 17898, 17899]) {
|
|
792
|
+
try { port = await start(p, startOpts); console.warn(`fell back to port ${p}`); break; }
|
|
793
|
+
catch { /* try next */ }
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (!port) {
|
|
797
|
+
// Последний резерв — случайный порт (потеряем handle).
|
|
798
|
+
console.warn('all stable ports busy, falling back to random (recents-handle will be lost)');
|
|
771
799
|
try { port = await start(0, startOpts); }
|
|
772
800
|
catch (e) {
|
|
773
|
-
console.error('Server failed to start:', e);
|
|
801
|
+
console.error('Server failed to start:', e || lastErr);
|
|
774
802
|
app.quit();
|
|
775
803
|
return;
|
|
776
804
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.42",
|
|
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": {
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"assets/**/*",
|
|
64
64
|
"lib/**/*",
|
|
65
65
|
"renderer/**/*",
|
|
66
|
+
"skill/**/*",
|
|
66
67
|
"package.json",
|
|
67
68
|
"updates.html"
|
|
68
69
|
],
|
package/settings.html
CHANGED
|
@@ -175,7 +175,9 @@
|
|
|
175
175
|
Скилл <code>kingkont</code> для Claude Code
|
|
176
176
|
</div>
|
|
177
177
|
<div class="hint" style="margin-top:0; margin-bottom:12px;">
|
|
178
|
-
Положит <code
|
|
178
|
+
Положит <code>SKILL.md</code> в папку настроек Claude Code в твоём
|
|
179
|
+
домашнем каталоге (macOS/Linux: <code>~/.claude/skills/kingkont/</code>;
|
|
180
|
+
Windows: <code>%USERPROFILE%\.claude\skills\kingkont\</code>). Claude
|
|
179
181
|
сможет управлять проектами KingKont (создавать ноды, запускать
|
|
180
182
|
генерации) без открытия приложения. После установки нужен
|
|
181
183
|
<code>/reload</code> в Claude Code.
|
|
@@ -184,6 +186,7 @@
|
|
|
184
186
|
<button id="installSkill" class="secondary">Установить skill для Claude</button>
|
|
185
187
|
<span class="saved" id="skillSaved" style="margin-left:auto;">Установлено ✓</span>
|
|
186
188
|
</div>
|
|
189
|
+
<div class="hint" id="skillPath" style="display:none; margin-top:8px; word-break:break-all; font-family:ui-monospace,monospace; color:var(--ok);"></div>
|
|
187
190
|
<div class="error" id="skillError" style="display:none;"></div>
|
|
188
191
|
</div>
|
|
189
192
|
|
|
@@ -328,12 +331,15 @@ function escapeHtml(s) {
|
|
|
328
331
|
}
|
|
329
332
|
|
|
330
333
|
// Кнопка «Установить skill для Claude» — копирует skill/SKILL.md в
|
|
331
|
-
// ~/.claude/skills/kingkont/
|
|
334
|
+
// ~/.claude/skills/kingkont/ (или %USERPROFILE%\.claude\skills\kingkont\
|
|
335
|
+
// на Windows) через main-process IPC. После успеха показывает реальный путь.
|
|
332
336
|
$('installSkill').addEventListener('click', async () => {
|
|
333
337
|
const btn = $('installSkill');
|
|
334
338
|
const ok = $('skillSaved');
|
|
335
339
|
const err = $('skillError');
|
|
340
|
+
const pathEl = $('skillPath');
|
|
336
341
|
err.style.display = 'none';
|
|
342
|
+
pathEl.style.display = 'none';
|
|
337
343
|
ok.classList.remove('show');
|
|
338
344
|
btn.disabled = true;
|
|
339
345
|
btn.textContent = 'Устанавливаю…';
|
|
@@ -343,6 +349,10 @@ $('installSkill').addEventListener('click', async () => {
|
|
|
343
349
|
btn.textContent = 'Переустановить skill для Claude';
|
|
344
350
|
ok.classList.add('show');
|
|
345
351
|
setTimeout(() => ok.classList.remove('show'), 2500);
|
|
352
|
+
if (res.path) {
|
|
353
|
+
pathEl.style.display = '';
|
|
354
|
+
pathEl.textContent = '✓ ' + res.path;
|
|
355
|
+
}
|
|
346
356
|
} else {
|
|
347
357
|
throw new Error(res?.error || 'Не удалось установить');
|
|
348
358
|
}
|