Ship 0.15.0: installable persona packs and slimmer bundled set.

Load Assistent/extensions packs between bundled and overlay, keep neutral/aggressive/dreamer, drop cinema/lewd/private shelves, and make horny slash commands schema-driven.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-23 08:28:31 +03:00
co-authored by Cursor
parent e2d48b4bf9
commit 47d352a7af
42 changed files with 353 additions and 429 deletions
+30 -25
View File
@@ -5320,9 +5320,9 @@
return {
id,
title: (known && known.title) || ({
neutral: 'Нейтральный',
lewd: 'Пошляк',
neutral: 'Нормальный',
aggressive: 'Агрессивный',
dreamer: 'Мечтатель',
}[id] || id),
};
}
@@ -6080,13 +6080,17 @@ if (!(meta && meta.historical)) {
syncPersonaDeleteButton(data.persona_source || data.personas?.find((p) => p.id === (data.persona || $('sa_persona')?.value))?.source);
}
function isDeletablePersonaSource(source) {
const src = String(source || '');
return src === 'overlay' || src === 'overlay+bundled' || src === 'overlay+pack';
}
function syncPersonaDeleteButton(source) {
const btn = $('sa_persona_delete');
if (!btn) {
return;
}
const src = String(source || '');
const canDelete = src === 'overlay' || src === 'overlay+bundled';
const canDelete = isDeletablePersonaSource(source);
btn.hidden = !canDelete;
btn.disabled = !canDelete;
}
@@ -6212,17 +6216,12 @@ if (!(meta && meta.historical)) {
}
function coolDownHorny() {
const persona = $('sa_persona')?.value || '';
if (persona !== 'leonid') {
setStatus('/остынь только для Leonid');
const schema = state.config?.controls || {};
if (!schema.horny) {
setStatus('/остынь: у этой личности нет слайдера Хорни');
return;
}
state.lastUserControlIntent = true;
const schema = state.config?.controls || {};
if (!schema.horny) {
setStatus('У этой личности нет слайдера Хорни');
return;
}
const min = Number(schema.horny.min ?? 0);
const max = Number(schema.horny.max ?? 100);
const cur = getControlValue('horny', Number(schema.horny.default ?? 35));
@@ -6244,12 +6243,12 @@ if (!(meta && meta.historical)) {
}
async function startHornyGame() {
const persona = $('sa_persona')?.value || '';
if (persona !== 'leonid') {
setStatus('/horny-game только для Leonid');
const schema = state.config?.controls || {};
if (!schema.horny) {
setStatus('/horny-game: у этой личности нет слайдера Хорни');
return;
}
const cur = getControlValue('horny', 35);
const cur = getControlValue('horny', Number(schema.horny.default ?? 35));
state.lastUserControlIntent = true;
await sendChat({
skipSlash: true,
@@ -6336,11 +6335,11 @@ if (!(meta && meta.historical)) {
const meta = (state.personas || []).find((p) => p.id === id);
const title = meta?.title || id;
const src = meta?.source || state.config?.persona_source || '';
if (src !== 'overlay' && src !== 'overlay+bundled') {
setStatus('Bundled personas cannot be deleted');
if (src !== 'overlay' && src !== 'overlay+bundled' && src !== 'overlay+pack') {
setStatus('Можно удалить только overlay-слой (bundled/pack не трогаются)');
return;
}
if (!window.confirm(`Удалить «${title}»?\nПоставка (bundled) не трогается.`)) {
if (!window.confirm(`Удалить «${title}»?\nПоставка (bundled/pack) не трогается.`)) {
return;
}
await new Promise((resolve) => {
@@ -7021,6 +7020,12 @@ if (!(meta && meta.historical)) {
if (source === 'overlay+bundled') {
return 'встроено+правка';
}
if (source === 'overlay+pack') {
return 'пак+правка';
}
if (source === 'pack') {
return 'пак';
}
return 'встроено';
}
@@ -7055,7 +7060,7 @@ if (!(meta && meta.historical)) {
function syncPersonaPanelActions() {
const id = state.settingsPersonaId;
const p = (state.personas || []).find((x) => x.id === id);
const canDelete = p && (p.source === 'overlay' || p.source === 'overlay+bundled');
const canDelete = p && isDeletablePersonaSource(p.source);
const del = $('sa_btn_persona_delete_panel');
if (del) {
del.disabled = !canDelete;
@@ -7125,8 +7130,8 @@ if (!(meta && meta.historical)) {
return;
}
let newId = pack?.id || '';
if ((state.personas || []).some((p) => p.id === newId && (p.source === 'bundled' || p.source === 'overlay+bundled'))) {
newId = window.prompt('Id занят bundled — новый id:', `${newId}_import`) || '';
if ((state.personas || []).some((p) => p.id === newId && (p.source === 'bundled' || p.source === 'pack' || p.source === 'overlay+bundled' || p.source === 'overlay+pack'))) {
newId = window.prompt('Id занят bundled/pack — новый id:', `${newId}_import`) || '';
}
genericRequest(
'AssistentImportPersona',
@@ -7176,7 +7181,7 @@ if (!(meta && meta.historical)) {
function deleteSelectedOverlayPersona() {
const id = state.settingsPersonaId;
const p = (state.personas || []).find((x) => x.id === id);
if (!p || (p.source !== 'overlay' && p.source !== 'overlay+bundled')) {
if (!p || !isDeletablePersonaSource(p.source)) {
setStatus('Можно удалить только overlay');
return;
}
@@ -7905,8 +7910,8 @@ if (!(meta && meta.historical)) {
why.push('session_exact пуст — params из Exact + профиль чекпоинта');
}
why.push(`профиль чекпоинта: ${profile} (имя/title → turbo|raw)`);
if (persona === 'cinema' || state.exact?.generation?.aspect) {
why.push(`persona/exact aspect: ${state.exact?.generation?.aspect || exactGen.aspect || '—'}`);
if (state.exact?.generation?.aspect) {
why.push(`persona/exact aspect: ${state.exact.generation.aspect || exactGen.aspect || '—'}`);
}
if (state.lastPatch) {
const keys = Object.keys(state.lastPatch).filter((k) => state.lastPatch[k] != null && k !== 'notes');