shadok-ai 0.2.75 → 0.3.77
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 +1 -1
- package/public/index.html +43 -12
- package/public/profile-card.js +13 -0
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -1655,6 +1655,7 @@
|
|
|
1655
1655
|
<button id="profSwitchClose" title="Close">✕</button>
|
|
1656
1656
|
</div>
|
|
1657
1657
|
<p class="sec-note">Applying re-spawns the agent in place. Its history is kept and the conversation continues.</p>
|
|
1658
|
+
<p class="sec-note warn" id="profSwitchManaged" hidden></p>
|
|
1658
1659
|
<div id="profSwitchGrid" role="radiogroup" aria-label="Agent profile"></div>
|
|
1659
1660
|
</div>
|
|
1660
1661
|
</div>
|
|
@@ -1904,8 +1905,7 @@
|
|
|
1904
1905
|
profileBadges,
|
|
1905
1906
|
defaultAgentName,
|
|
1906
1907
|
hasReadonlyPreset,
|
|
1907
|
-
applyReadonlyPreset,
|
|
1908
|
-
} from "/profile-card.js";
|
|
1908
|
+
applyReadonlyPreset, isManagedProfile } from "/profile-card.js";
|
|
1909
1909
|
import { notifyState, BLINK_MS } from "/notify.js";
|
|
1910
1910
|
import { echoAuthor } from "/echo-author.js";
|
|
1911
1911
|
import { dialPos, dialColor, arcSegments, dialTitle, SWEEP_DEG } from "/gauge-dial.js";
|
|
@@ -1918,6 +1918,7 @@
|
|
|
1918
1918
|
window.profileBlurb = profileBlurb;
|
|
1919
1919
|
window.profileBadges = profileBadges;
|
|
1920
1920
|
window.defaultAgentName = defaultAgentName;
|
|
1921
|
+
window.isManagedProfile = isManagedProfile;
|
|
1921
1922
|
window.hasReadonlyPreset = hasReadonlyPreset;
|
|
1922
1923
|
window.applyReadonlyPreset = applyReadonlyPreset;
|
|
1923
1924
|
window.echoAuthor = echoAuthor;
|
|
@@ -2294,12 +2295,18 @@
|
|
|
2294
2295
|
profSwitchTab = tab;
|
|
2295
2296
|
$("profSwitchWho").textContent = tab.nameEl ? tab.nameEl.textContent : "agent";
|
|
2296
2297
|
await loadProfilesInto(); // la liste a pu changer depuis le dernier passage
|
|
2298
|
+
const onManaged = managedProfile(tab.profile);
|
|
2297
2299
|
renderProfileCards(
|
|
2298
2300
|
$("profSwitchGrid"),
|
|
2299
|
-
tab.profile || "",
|
|
2301
|
+
onManaged ? null : tab.profile || "", // null : aucune carte ne ment
|
|
2300
2302
|
(name) => askProfileSwitch(tab, name),
|
|
2301
2303
|
false,
|
|
2302
2304
|
);
|
|
2305
|
+
// Un agent qui TOURNE sous un rôle managé n'a plus de carte : sans ce mot,
|
|
2306
|
+
// rien n'indiquerait ce qui tourne réellement.
|
|
2307
|
+
const note = $("profSwitchManaged");
|
|
2308
|
+
note.hidden = !onManaged;
|
|
2309
|
+
if (onManaged) note.textContent = "Currently running " + tab.profile + " — a managed role, not offered as a choice. Picking another one replaces it.";
|
|
2303
2310
|
$("profSwitchOverlay").hidden = false;
|
|
2304
2311
|
}
|
|
2305
2312
|
|
|
@@ -5284,13 +5291,18 @@
|
|
|
5284
5291
|
// carte ici serait une deuxième porte, subtilement différente, vers le même
|
|
5285
5292
|
// agent. Il reste listé dans le panneau Profils, pour qu'on puisse tout de
|
|
5286
5293
|
// même lui attacher un secret ou un modèle.
|
|
5287
|
-
renderProfileCards(grid, selectedProfile, (n) => selectProfile(n, true), failed
|
|
5294
|
+
renderProfileCards(grid, selectedProfile, (n) => selectProfile(n, true), failed);
|
|
5288
5295
|
}
|
|
5289
5296
|
|
|
5297
|
+
/** Garde alignée sur invariant 10 : le pont ESM s'exécute après le parsing.
|
|
5298
|
+
* S'il n'est pas encore là, on ne filtre pas — un rôle de trop est moins
|
|
5299
|
+
* grave qu'une exception qui viderait la liste en silence. */
|
|
5300
|
+
const managedProfile = (name) => (window.isManagedProfile ? window.isManagedProfile(name) : false);
|
|
5301
|
+
|
|
5290
5302
|
/** Peint les cartes de profil dans `container`. Générique : la box de création
|
|
5291
5303
|
* ET le sélecteur du menu d'onglet s'en servent — la logique de carte (blurb,
|
|
5292
5304
|
* badges, crayon, clavier) ne vit qu'ici, en un seul exemplaire. */
|
|
5293
|
-
function renderProfileCards(container, selected, onPick, failed
|
|
5305
|
+
function renderProfileCards(container, selected, onPick, failed) {
|
|
5294
5306
|
container.innerHTML = "";
|
|
5295
5307
|
if (failed) {
|
|
5296
5308
|
const note = document.createElement("div");
|
|
@@ -5298,11 +5310,13 @@
|
|
|
5298
5310
|
note.textContent = "couldn't load profiles";
|
|
5299
5311
|
container.appendChild(note);
|
|
5300
5312
|
}
|
|
5301
|
-
//
|
|
5302
|
-
//
|
|
5303
|
-
//
|
|
5304
|
-
//
|
|
5305
|
-
|
|
5313
|
+
// Les rôles pilotés par le serveur ne sont JAMAIS un choix : leur prompt est
|
|
5314
|
+
// réécrit à chaque boot, les proposer promet une personnalisation qui
|
|
5315
|
+
// s'effacera. Filtré ici pour toutes les listes, plutôt que par un paramètre
|
|
5316
|
+
// qu'un futur appelant oublierait — c'est ce qui était arrivé au sélecteur
|
|
5317
|
+
// du menu d'onglet. L'agent qui TOURNE sous un tel rôle est annoncé à part
|
|
5318
|
+
// (voir openProfileSwitcher), sinon la grille mentirait sur ce qui tourne.
|
|
5319
|
+
const list = profileCache.filter((p) => p && !managedProfile(p.name));
|
|
5306
5320
|
// Zéro profil : on montre la porte d'entrée plutôt qu'un « (none) » muet.
|
|
5307
5321
|
// Pas de role="radio" → ignorée par la sélection et par les flèches.
|
|
5308
5322
|
if (!failed && !list.length) {
|
|
@@ -5383,6 +5397,19 @@
|
|
|
5383
5397
|
* nom réellement retenu — "" si le profil visé n'existe plus. */
|
|
5384
5398
|
function markProfileSelection(container, selected) {
|
|
5385
5399
|
const cards = [...container.querySelectorAll('.profile-card[role="radio"]')];
|
|
5400
|
+
// `null` = ne rien cocher, délibérément. Un agent qui tourne sous un rôle
|
|
5401
|
+
// managé n'a pas de carte : retomber sur "" cocherait « No profile » et la
|
|
5402
|
+
// grille affirmerait qu'il tourne sans profil. Une chaîne, elle, garde le
|
|
5403
|
+
// repli sur « No profile » — c'est le défaut légitime de la box.
|
|
5404
|
+
if (selected === null) {
|
|
5405
|
+
for (const c of cards) {
|
|
5406
|
+
c.classList.remove("selected");
|
|
5407
|
+
c.setAttribute("aria-checked", "false");
|
|
5408
|
+
c.tabIndex = -1;
|
|
5409
|
+
}
|
|
5410
|
+
if (cards.length) cards[0].tabIndex = 0; // le groupe reste atteignable au clavier
|
|
5411
|
+
return null;
|
|
5412
|
+
}
|
|
5386
5413
|
let on = selected || "";
|
|
5387
5414
|
if (!cards.some((c) => c.dataset.profile === on)) on = "";
|
|
5388
5415
|
for (const c of cards) {
|
|
@@ -5441,8 +5468,12 @@
|
|
|
5441
5468
|
function renderProfilesList() {
|
|
5442
5469
|
const ul = $("profilesList");
|
|
5443
5470
|
ul.innerHTML = "";
|
|
5444
|
-
|
|
5445
|
-
|
|
5471
|
+
// Masqués ici aussi : leur prompt est repris du dépôt à chaque boot, donc
|
|
5472
|
+
// « edit » y perdrait la saisie sans un mot, et « delete » ne tiendrait pas
|
|
5473
|
+
// le redémarrage.
|
|
5474
|
+
const listed = profileCache.filter((p) => p && !managedProfile(p.name));
|
|
5475
|
+
if (!listed.length) ul.innerHTML = '<li><span style="opacity:.6">no profiles yet</span></li>';
|
|
5476
|
+
for (const p of listed) {
|
|
5446
5477
|
const li = document.createElement("li");
|
|
5447
5478
|
const meta = document.createElement("div");
|
|
5448
5479
|
// Nom et modèle en textContent : un profil peut être créé par un agent
|
package/public/profile-card.js
CHANGED
|
@@ -107,3 +107,16 @@ export function applyReadonlyPreset(deny, on, preset) {
|
|
|
107
107
|
for (const x of p) if (!have.has(x)) list.push(x);
|
|
108
108
|
return list;
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Rôles pilotés par le SERVEUR, qui n'ont rien à faire dans une liste où l'on
|
|
113
|
+
* choisit un profil. `Shadok-Tweak` reprend son prompt de
|
|
114
|
+
* `context/tweak-prompt.md` à chaque boot et possède son propre CTA : l'offrir
|
|
115
|
+
* comme un rôle ordinaire promet une personnalisation que le prochain
|
|
116
|
+
* redémarrage effacera.
|
|
117
|
+
*/
|
|
118
|
+
export const MANAGED_PROFILES = ["Shadok-Tweak"];
|
|
119
|
+
|
|
120
|
+
export function isManagedProfile(name) {
|
|
121
|
+
return MANAGED_PROFILES.includes(String(name ?? "").trim());
|
|
122
|
+
}
|