clay-server 2.34.1-beta.3 → 2.34.1-beta.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.
|
@@ -356,6 +356,16 @@ export function processMessage(msg) {
|
|
|
356
356
|
break;
|
|
357
357
|
|
|
358
358
|
case "model_info": {
|
|
359
|
+
// Drop stale model_info from a vendor that doesn't match the active
|
|
360
|
+
// session's vendor. On high-latency connections, the server's default-
|
|
361
|
+
// adapter model_info can arrive after session_switched has already
|
|
362
|
+
// bound the session to a different vendor. Applying it would replace
|
|
363
|
+
// currentModels with the wrong vendor's list and trigger app-panels
|
|
364
|
+
// to request models for the "wrong" vendor, which feeds back into a
|
|
365
|
+
// ping-pong loop of vendor flapping. See issue #336.
|
|
366
|
+
var _curV = store.get('currentVendor');
|
|
367
|
+
if (msg.vendor && _curV && msg.vendor !== _curV) break;
|
|
368
|
+
|
|
359
369
|
var _modelVal = msg.model;
|
|
360
370
|
if (_modelVal && typeof _modelVal === "object") _modelVal = _modelVal.value || _modelVal.displayName || "";
|
|
361
371
|
var _miUpdate = { currentModels: msg.models || [] };
|
|
@@ -530,8 +540,12 @@ export function processMessage(msg) {
|
|
|
530
540
|
if (!store.get('vendorSelectionLocked') || msg.hasHistory) {
|
|
531
541
|
store.set({ currentVendor: msg.vendor });
|
|
532
542
|
}
|
|
543
|
+
// Sessions with history have their vendor structurally bound to
|
|
544
|
+
// the session: lock so a late-arriving default-adapter model_info
|
|
545
|
+
// can't flip the UI back. Previously this branch unlocked, which
|
|
546
|
+
// is what allowed the feedback loop in issue #336.
|
|
533
547
|
if (msg.hasHistory) {
|
|
534
|
-
store.set({ vendorSelectionLocked:
|
|
548
|
+
store.set({ vendorSelectionLocked: true });
|
|
535
549
|
}
|
|
536
550
|
} else if (msg.hasHistory) {
|
|
537
551
|
// Existing session without explicit vendor: reset to claude
|
|
@@ -18,6 +18,11 @@ var pendingSkillInstalls = [];
|
|
|
18
18
|
var skillInstallCallback = null;
|
|
19
19
|
var skillInstalling = false;
|
|
20
20
|
var skillInstallDone = false;
|
|
21
|
+
// True when the modal contains only "outdated" skills (no "missing"). In that
|
|
22
|
+
// case the user is allowed to skip the update and continue with the original
|
|
23
|
+
// action; the dismissal is remembered for the rest of the browser session so
|
|
24
|
+
// we don't re-prompt on every reconnect / DM open.
|
|
25
|
+
var skillInstallSkippable = false;
|
|
21
26
|
|
|
22
27
|
export function initSkillInstall() {
|
|
23
28
|
skillInstallModal = document.getElementById("skill-install-modal");
|
|
@@ -28,8 +33,8 @@ export function initSkillInstall() {
|
|
|
28
33
|
skillInstallCancel = document.getElementById("skill-install-cancel");
|
|
29
34
|
skillInstallStatus = document.getElementById("skill-install-status");
|
|
30
35
|
|
|
31
|
-
skillInstallCancel.addEventListener("click",
|
|
32
|
-
skillInstallModal.querySelector(".confirm-backdrop").addEventListener("click",
|
|
36
|
+
skillInstallCancel.addEventListener("click", onSkillInstallDismiss);
|
|
37
|
+
skillInstallModal.querySelector(".confirm-backdrop").addEventListener("click", onSkillInstallDismiss);
|
|
33
38
|
|
|
34
39
|
skillInstallOk.addEventListener("click", function () {
|
|
35
40
|
if (skillInstallDone) {
|
|
@@ -106,6 +111,11 @@ function renderSkillInstallDialog(opts, missing) {
|
|
|
106
111
|
if (hasMissing && hasOutdated) btnLabel = "Install / Update";
|
|
107
112
|
skillInstallOk.textContent = btnLabel;
|
|
108
113
|
skillInstallOk.className = "confirm-btn confirm-delete";
|
|
114
|
+
// When only outdated skills are pending, the feature still works on the
|
|
115
|
+
// current version. Let the user skip and continue; surface that as a
|
|
116
|
+
// distinct cancel label so it's clear this won't abort the action.
|
|
117
|
+
skillInstallSkippable = hasOutdated && !hasMissing;
|
|
118
|
+
skillInstallCancel.textContent = skillInstallSkippable ? "Skip" : "Cancel";
|
|
109
119
|
skillInstallModal.classList.remove("hidden");
|
|
110
120
|
}
|
|
111
121
|
|
|
@@ -115,6 +125,45 @@ function hideSkillInstallModal() {
|
|
|
115
125
|
pendingSkillInstalls = [];
|
|
116
126
|
skillInstalling = false;
|
|
117
127
|
skillInstallDone = false;
|
|
128
|
+
skillInstallSkippable = false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Cancel/backdrop click handler. For "missing" skills the feature genuinely
|
|
132
|
+
// cannot run without them, so dismiss = drop the callback (existing behavior).
|
|
133
|
+
// For "outdated"-only prompts the feature still works on the old version, so
|
|
134
|
+
// dismiss = remember the choice for this browser session and proceed with cb.
|
|
135
|
+
function onSkillInstallDismiss() {
|
|
136
|
+
if (skillInstallSkippable) {
|
|
137
|
+
rememberOutdatedDismissal(pendingSkillInstalls);
|
|
138
|
+
var proceedCb = skillInstallCallback;
|
|
139
|
+
skillInstallCallback = null;
|
|
140
|
+
hideSkillInstallModal();
|
|
141
|
+
if (proceedCb) proceedCb();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
hideSkillInstallModal();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function dismissalKey(name, remoteVersion) {
|
|
148
|
+
return "clay-skill-update-dismissed:" + name + ":" + (remoteVersion || "");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function rememberOutdatedDismissal(items) {
|
|
152
|
+
try {
|
|
153
|
+
for (var i = 0; i < items.length; i++) {
|
|
154
|
+
var it = items[i];
|
|
155
|
+
if (it.status !== "outdated") continue;
|
|
156
|
+
sessionStorage.setItem(dismissalKey(it.name, it.remoteVersion), "1");
|
|
157
|
+
}
|
|
158
|
+
} catch (e) {}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function isOutdatedDismissed(name, remoteVersion) {
|
|
162
|
+
try {
|
|
163
|
+
return sessionStorage.getItem(dismissalKey(name, remoteVersion)) === "1";
|
|
164
|
+
} catch (e) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
118
167
|
}
|
|
119
168
|
|
|
120
169
|
function updateSkillInstallProgress(done, total) {
|
|
@@ -197,29 +246,31 @@ export function requireSkills(opts, cb) {
|
|
|
197
246
|
.then(function (res) { return res.json(); })
|
|
198
247
|
.then(function (data) {
|
|
199
248
|
var results = data.results || [];
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
249
|
+
// "missing" skills hard-block: the feature cannot run without them.
|
|
250
|
+
// "outdated" skills are surfaced too because skills look like a single
|
|
251
|
+
// user-facing feature but call vendor-specific tools (codex vs claude)
|
|
252
|
+
// internally — version drift breaks that consistency. The modal is
|
|
253
|
+
// skippable for outdated-only cases, and a session-scoped dismissal
|
|
254
|
+
// suppresses re-prompts so reconnect/refresh doesn't re-fire it.
|
|
204
255
|
var actionable = [];
|
|
205
256
|
for (var i = 0; i < results.length; i++) {
|
|
206
257
|
var r = results[i];
|
|
207
|
-
if (r.status
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
if (!orig) continue;
|
|
213
|
-
actionable.push({
|
|
214
|
-
name: r.name,
|
|
215
|
-
url: orig.url,
|
|
216
|
-
scope: orig.scope || "global",
|
|
217
|
-
installed: false,
|
|
218
|
-
status: r.status,
|
|
219
|
-
installedVersion: r.installedVersion,
|
|
220
|
-
remoteVersion: r.remoteVersion,
|
|
221
|
-
});
|
|
258
|
+
if (r.status !== "missing" && r.status !== "outdated") continue;
|
|
259
|
+
if (r.status === "outdated" && isOutdatedDismissed(r.name, r.remoteVersion)) continue;
|
|
260
|
+
var orig = null;
|
|
261
|
+
for (var j = 0; j < opts.skills.length; j++) {
|
|
262
|
+
if (opts.skills[j].name === r.name) { orig = opts.skills[j]; break; }
|
|
222
263
|
}
|
|
264
|
+
if (!orig) continue;
|
|
265
|
+
actionable.push({
|
|
266
|
+
name: r.name,
|
|
267
|
+
url: orig.url,
|
|
268
|
+
scope: orig.scope || "global",
|
|
269
|
+
installed: false,
|
|
270
|
+
status: r.status,
|
|
271
|
+
installedVersion: r.installedVersion,
|
|
272
|
+
remoteVersion: r.remoteVersion,
|
|
273
|
+
});
|
|
223
274
|
}
|
|
224
275
|
if (actionable.length === 0) { cb(); return; }
|
|
225
276
|
pendingSkillInstalls = actionable;
|