kingkont 0.14.3 → 0.14.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/renderer/chat.js CHANGED
@@ -209,6 +209,17 @@
209
209
  },
210
210
  },
211
211
 
212
+ take_snapshot: {
213
+ description: 'Сделать снимок проекта ДО серьёзного изменения (удаление, массовое редактирование промптов, очистка таймлайна, перезапуск генерации). Юзер потом может откатить через UI tool-блока в чате. Label — короткое описание что собираешься делать («перед удалением 3 нод», «перед очисткой timeline»). НЕ делай snapshot перед read-only действиями (read_scene, list_scenes) — только перед destructive.',
214
+ params: '{"label":"<короткое описание что будет сделано>"}',
215
+ async handler({ label }) {
216
+ const snap = await takeSnapshot(label || 'без метки');
217
+ if (!snap) throw new Error('не удалось сделать snapshot (нет filmHandle?)');
218
+ const idx = snapshots.indexOf(snap);
219
+ return { ok: true, snapshotIdx: idx, label: snap.label, ts: snap.ts };
220
+ },
221
+ },
222
+
212
223
  delete_node: {
213
224
  description: 'Удалить ноду. Файл (если есть) переедет в _deleted/.',
214
225
  params: '{"id":"<node-id>"}',
@@ -421,6 +432,13 @@
421
432
  lines.push('- Не выдумывай имена сцен — сначала list_scenes.');
422
433
  lines.push('- Для генерации сразу после add_node — ВОЗЬМИ id из result.id ПРЕДЫДУЩЕГО вызова и передай в generate_node.');
423
434
  lines.push('- Когда нужно создать несколько нод сразу — выдавай add_node + generate_node чередуя, или сначала все add_node, потом все generate_node (используя id из их result-ов).');
435
+ lines.push('');
436
+ lines.push('SNAPSHOT для отката (важно):');
437
+ lines.push('- Перед DESTRUCTIVE действиями (delete_node, update_node_prompt, generate_node на ноду которая уже сгенерирована, clear_timeline, remove_clip_from_timeline) — позови take_snapshot ПЕРВЫМ tool в этом турне.');
438
+ lines.push('- Label snapshot\'a — короткое описание того что сейчас делаешь («перед удалением 3 нод», «перед перегенерацией картинки Закат», «перед очисткой таймлайна»).');
439
+ lines.push('- НЕ зови take_snapshot для read-only действий (read_scene, list_scenes, list_timeline) и для безопасных операций добавления (add_node без перетирания, add_clip_to_timeline).');
440
+ lines.push('- Если в одном турне НЕСКОЛЬКО destructive-вызовов — одного take_snapshot в начале достаточно.');
441
+ lines.push('');
424
442
  lines.push('- Отвечай по-русски, кратко. Объясняй что делаешь, без лишней воды.');
425
443
  lines.push('');
426
444
  lines.push('ВАЖНО: НИКОГДА не пиши <tool_result>...</tool_result> сам — это формат который Я');
@@ -703,8 +721,13 @@
703
721
  }
704
722
 
705
723
  function renderSnapshotBar() {
724
+ // Snapshot-bar отключён — откаты теперь inline в chat tool-блоке.
725
+ // (Кнопка ↩ Откатить «label» под каждым take_snapshot tool'ом.)
706
726
  const bar = $('chatSnapshotBar');
707
727
  if (!bar) return;
728
+ bar.style.display = 'none';
729
+ return;
730
+ // -- legacy code below, не выполняется --
708
731
  bar.innerHTML = '';
709
732
  if (!snapshots.length) { bar.style.display = 'none'; return; }
710
733
  bar.style.display = '';
@@ -1089,10 +1112,8 @@
1089
1112
  if (!userText.trim()) return;
1090
1113
  const key = sessionKey();
1091
1114
  if (!key) { alert('Сначала открой проект'); return; }
1092
- // Snapshot ДО мутацииклиентский (для отката чат-действий).
1093
- try {
1094
- await takeSnapshot(userText.length > 60 ? userText.slice(0, 60) + '…' : userText);
1095
- } catch (e) { console.warn('snapshot failed:', e?.message); }
1115
+ // Snapshot НЕ берём автоматически теперь это явный tool take_snapshot,
1116
+ // который Claude вызывает перед destructive-действиями. См. system-prompt.
1096
1117
  // Контекст + system-prompt: формируем тут (на клиенте) и отдаём серверу.
1097
1118
  const ctxSnap = buildContextSnapshot();
1098
1119
  const system = buildSystemPrompt() + '\n\n' + buildContextBlock(ctxSnap);
@@ -1190,6 +1211,30 @@
1190
1211
  const pre = document.createElement('pre');
1191
1212
  pre.textContent = JSON.stringify(dumpAll, null, 2);
1192
1213
  t.appendChild(pre);
1214
+ // Если среди tools есть take_snapshot — добавляем кнопки отката.
1215
+ // Pattern: одна кнопка ↩ на каждый snapshot tool-call. snapshotIdx
1216
+ // приходит из result handler'а (см. take_snapshot tool).
1217
+ for (const tc of m.tools) {
1218
+ if (tc.name !== 'take_snapshot' || !tc._ok || tc._error) continue;
1219
+ const idx = tc.result?.snapshotIdx;
1220
+ const lbl = tc.result?.label || tc.args?.label || '';
1221
+ if (typeof idx !== 'number') continue;
1222
+ const rb = document.createElement('button');
1223
+ rb.className = 'chat-snapshot-rollback';
1224
+ rb.textContent = `↩ Откатить «${lbl}»`;
1225
+ rb.title = `Откат до snapshot'а #${idx}`;
1226
+ rb.addEventListener('click', () => {
1227
+ // snapshots могли уже измениться (новые добавились) — find by ts.
1228
+ const realIdx = snapshots.findIndex(s => s.ts === tc.result?.ts);
1229
+ if (realIdx < 0) {
1230
+ alert('Snapshot потерялся (возможно вы переключили проект).');
1231
+ return;
1232
+ }
1233
+ if (!confirm(`Откатить до «${lbl}»?`)) return;
1234
+ rollbackToSnapshot(realIdx);
1235
+ });
1236
+ div.appendChild(rb);
1237
+ }
1193
1238
  div.appendChild(t);
1194
1239
  }
1195
1240
  list.appendChild(div);
@@ -300,6 +300,17 @@
300
300
  border-radius: 4px; padding: 2px 8px; cursor: pointer; font-size: 12px;
301
301
  }
302
302
  .chat-header button:hover { background: #2a2a2a; color: #fff; }
303
+ /* Кнопка отката снепшота прямо в чат-сообщении (под take_snapshot tool). */
304
+ .chat-snapshot-rollback {
305
+ margin-top: 4px; align-self: flex-start;
306
+ background: #232a36; border: 1px solid #3a4a5a; color: #aac;
307
+ font-size: 11px; padding: 3px 8px; border-radius: 999px;
308
+ cursor: pointer; opacity: 0.85;
309
+ }
310
+ .chat-snapshot-rollback:hover {
311
+ background: #2a3548; border-color: #4a6a8a; color: #cde; opacity: 1;
312
+ }
313
+
303
314
  .chat-snapshot-bar {
304
315
  padding: 6px 10px; background: #1f1f1f; border-bottom: 1px solid #2a2a2a;
305
316
  display: flex; align-items: center; gap: 6px; flex-shrink: 0;