shadok-ai 0.8.14 → 0.8.16

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": "shadok-ai",
3
- "version": "0.8.14",
3
+ "version": "0.8.16",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts context/*/test/*.test.mjs",
package/public/index.html CHANGED
@@ -365,7 +365,7 @@
365
365
 
366
366
  /* ── Channels (left column) ──────────────────────────── */
367
367
  #tabbar {
368
- width: 220px;
368
+ width: 264px; /* the agents column, 20% wider than the former 220px */
369
369
  flex: none;
370
370
  display: flex;
371
371
  flex-direction: column;
@@ -677,6 +677,9 @@
677
677
  /* Un prompt suivi se lit mais ne s'édite pas : le griser dit pourquoi. */
678
678
  #profRole.tracked { opacity: .75; border-style: dashed; }
679
679
  .prof-drift { margin-left: 8px; font-size: 11px; color: var(--amber); }
680
+ /* À qui ce secret est injecté. Discret : c'est une information de contexte,
681
+ pas une alerte — contrairement à sec-orphan juste en dessous. */
682
+ .sec-users { margin-left: 8px; font-size: 11px; color: var(--text-dim); }
680
683
  .sec-orphan { margin-left: 8px; font-size: 11px; color: var(--amber); font-family: var(--sans, inherit); }
681
684
  /* Profile picker for a running agent (the tab's context menu). */
682
685
  #profSwitchGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; padding: 0 18px 18px; }
@@ -1955,7 +1958,7 @@
1955
1958
  profileBadges,
1956
1959
  defaultAgentName,
1957
1960
  hasReadonlyPreset,
1958
- applyReadonlyPreset, isManagedProfile, profileSaveBody } from "/profile-card.js";
1961
+ applyReadonlyPreset, isManagedProfile, profileSaveBody, secretUsers } from "/profile-card.js";
1959
1962
  import { notifyState, BLINK_MS } from "/notify.js";
1960
1963
  import { echoAuthor } from "/echo-author.js";
1961
1964
  import { dialPos, dialColor, arcSegments, dialTitle, SWEEP_DEG } from "/gauge-dial.js";
@@ -1969,6 +1972,7 @@
1969
1972
  window.profileBlurb = profileBlurb;
1970
1973
  window.profileBadges = profileBadges;
1971
1974
  window.defaultAgentName = defaultAgentName;
1975
+ window.secretUsers = secretUsers;
1972
1976
  window.profileSaveBody = profileSaveBody;
1973
1977
  window.isManagedProfile = isManagedProfile;
1974
1978
  window.hasReadonlyPreset = hasReadonlyPreset;
@@ -5262,19 +5266,28 @@
5262
5266
  const ul = $("secretsList");
5263
5267
  ul.innerHTML = "";
5264
5268
  if (!vaultNames.length) ul.innerHTML = '<li><span style="opacity:.6">the vault is empty</span></li>';
5265
- // How many profiles reference each secret. A blurb is read once; a secret
5266
- // marked "unused" shows the problem where the problem is.
5267
- const usage = {};
5268
- for (const p of profileCache) for (const n of p.secrets || []) usage[n] = (usage[n] || 0) + 1;
5269
5269
  for (const k of vaultNames) {
5270
5270
  const li = document.createElement("li");
5271
5271
  const code = document.createElement("code"); code.textContent = k;
5272
- if (!usage[k]) {
5273
- const warn = document.createElement("span");
5274
- warn.className = "sec-orphan";
5275
- warn.textContent = "⚠ no profile uses it";
5276
- warn.title = "No agent will ever receive this secret until a profile references it";
5277
- code.appendChild(warn);
5272
+ // Qui reçoit ce secret. Le panneau disait déjà « personne » ; il ne disait
5273
+ // pas À QUI il sert quand il sert, ce qui obligeait à ouvrir les profils
5274
+ // un par un. Garde du pont ESM (invariant 10) : pas de module, pas de
5275
+ // mention, plutôt qu'une exception qui viderait la liste.
5276
+ const users = window.secretUsers ? window.secretUsers(profileCache, k) : null;
5277
+ if (users) {
5278
+ const tag = document.createElement("span");
5279
+ if (users.length) {
5280
+ tag.className = "sec-users";
5281
+ tag.textContent = "→ " + users.join(", ");
5282
+ tag.title = users.length === 1
5283
+ ? "Injected as an environment variable into agents running " + users[0]
5284
+ : "Injected as an environment variable into agents running any of: " + users.join(", ");
5285
+ } else {
5286
+ tag.className = "sec-orphan";
5287
+ tag.textContent = "⚠ no profile uses it";
5288
+ tag.title = "No agent will ever receive this secret until a profile references it";
5289
+ }
5290
+ code.appendChild(tag);
5278
5291
  }
5279
5292
  const del = document.createElement("button");
5280
5293
  del.textContent = "✕"; del.title = "Remove from vault";
@@ -143,3 +143,20 @@ export function profileSaveBody(form, state) {
143
143
  if (!state.tracked || state.forked) body.systemPrompt = form.prompt ?? "";
144
144
  return body;
145
145
  }
146
+
147
+ /**
148
+ * Les profils qui injectent ce secret, triés par nom.
149
+ *
150
+ * Un secret ne sert à rien tant qu'aucun profil ne le référence — le panneau le
151
+ * disait déjà, mais sans dire À QUI il sert quand il sert, ce qui obligeait à
152
+ * ouvrir les profils un par un pour le savoir.
153
+ *
154
+ * Compte AUSSI les rôles que le panneau des profils masque (Shadok-Tweak) : ils
155
+ * reçoivent bel et bien le secret, et les annoncer « inutilisés » serait faux.
156
+ */
157
+ export function secretUsers(profiles, name) {
158
+ return (Array.isArray(profiles) ? profiles : [])
159
+ .filter((p) => p && typeof p.name === "string" && (p.secrets || []).includes(name))
160
+ .map((p) => p.name)
161
+ .sort();
162
+ }