clay-server 2.27.0-beta.11 → 2.27.0-beta.13
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/lib/project.js +5 -1
- package/lib/public/app.js +1485 -8511
- package/lib/public/modules/app-connection.js +160 -0
- package/lib/public/modules/app-cursors.js +473 -0
- package/lib/public/modules/app-debate-ui.js +399 -0
- package/lib/public/modules/app-dm.js +627 -0
- package/lib/public/modules/app-favicon.js +212 -0
- package/lib/public/modules/app-header.js +229 -0
- package/lib/public/modules/app-home-hub.js +600 -0
- package/lib/public/modules/app-loop-ui.js +865 -0
- package/lib/public/modules/app-messages.js +1478 -0
- package/lib/public/modules/app-misc.js +301 -0
- package/lib/public/modules/app-panels.js +907 -0
- package/lib/public/modules/app-projects.js +782 -0
- package/lib/public/modules/app-rate-limit.js +448 -0
- package/lib/public/modules/app-rendering.js +597 -0
- package/lib/public/modules/app-skills-install.js +240 -0
- package/lib/public/modules/sidebar-mates.js +801 -0
- package/lib/public/modules/sidebar-mobile.js +1259 -0
- package/lib/public/modules/sidebar-projects.js +1449 -0
- package/lib/public/modules/sidebar-sessions.js +986 -0
- package/lib/public/modules/sidebar.js +232 -4591
- package/lib/sdk-bridge.js +54 -0
- package/package.json +1 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// app-skills-install.js - Skill install dialog, requireSkills, requireClayMateInterview
|
|
2
|
+
// Extracted from app.js (PR-33)
|
|
3
|
+
|
|
4
|
+
import { refreshIcons, iconHtml } from './icons.js';
|
|
5
|
+
import { escapeHtml } from './utils.js';
|
|
6
|
+
|
|
7
|
+
var _ctx = null;
|
|
8
|
+
|
|
9
|
+
// --- Module-owned state ---
|
|
10
|
+
var skillInstallModal = null;
|
|
11
|
+
var skillInstallTitle = null;
|
|
12
|
+
var skillInstallReason = null;
|
|
13
|
+
var skillInstallList = null;
|
|
14
|
+
var skillInstallOk = null;
|
|
15
|
+
var skillInstallCancel = null;
|
|
16
|
+
var skillInstallStatus = null;
|
|
17
|
+
|
|
18
|
+
var pendingSkillInstalls = [];
|
|
19
|
+
var skillInstallCallback = null;
|
|
20
|
+
var skillInstalling = false;
|
|
21
|
+
var skillInstallDone = false;
|
|
22
|
+
var knownInstalledSkills = {};
|
|
23
|
+
|
|
24
|
+
export function initSkillInstall(ctx) {
|
|
25
|
+
_ctx = ctx;
|
|
26
|
+
|
|
27
|
+
skillInstallModal = document.getElementById("skill-install-modal");
|
|
28
|
+
skillInstallTitle = document.getElementById("skill-install-title");
|
|
29
|
+
skillInstallReason = document.getElementById("skill-install-reason");
|
|
30
|
+
skillInstallList = document.getElementById("skill-install-list");
|
|
31
|
+
skillInstallOk = document.getElementById("skill-install-ok");
|
|
32
|
+
skillInstallCancel = document.getElementById("skill-install-cancel");
|
|
33
|
+
skillInstallStatus = document.getElementById("skill-install-status");
|
|
34
|
+
|
|
35
|
+
skillInstallCancel.addEventListener("click", hideSkillInstallModal);
|
|
36
|
+
skillInstallModal.querySelector(".confirm-backdrop").addEventListener("click", hideSkillInstallModal);
|
|
37
|
+
|
|
38
|
+
skillInstallOk.addEventListener("click", function () {
|
|
39
|
+
if (skillInstallDone) {
|
|
40
|
+
var proceedCb = skillInstallCallback;
|
|
41
|
+
skillInstallCallback = null;
|
|
42
|
+
hideSkillInstallModal();
|
|
43
|
+
if (proceedCb) proceedCb();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (skillInstalling) return;
|
|
47
|
+
skillInstalling = true;
|
|
48
|
+
skillInstallOk.disabled = true;
|
|
49
|
+
skillInstallOk.textContent = "Installing...";
|
|
50
|
+
|
|
51
|
+
var total = 0;
|
|
52
|
+
for (var i = 0; i < pendingSkillInstalls.length; i++) {
|
|
53
|
+
if (!pendingSkillInstalls[i].installed) total++;
|
|
54
|
+
}
|
|
55
|
+
skillInstallStatus.classList.remove("hidden");
|
|
56
|
+
updateSkillInstallProgress(0, total);
|
|
57
|
+
|
|
58
|
+
for (var j = 0; j < pendingSkillInstalls.length; j++) {
|
|
59
|
+
var s = pendingSkillInstalls[j];
|
|
60
|
+
if (s.installed) continue;
|
|
61
|
+
fetch(_ctx.basePath + "api/install-skill", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: { "Content-Type": "application/json" },
|
|
64
|
+
body: JSON.stringify({ url: s.url, skill: s.name, scope: s.scope || "global" }),
|
|
65
|
+
}).catch(function () {});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// --- State accessors ---
|
|
71
|
+
export function getKnownInstalledSkills() { return knownInstalledSkills; }
|
|
72
|
+
export function setKnownInstalledSkills(v) { knownInstalledSkills = v; }
|
|
73
|
+
|
|
74
|
+
// --- Functions ---
|
|
75
|
+
|
|
76
|
+
function renderSkillInstallDialog(opts, missing) {
|
|
77
|
+
var hasOutdated = false;
|
|
78
|
+
var hasMissing = false;
|
|
79
|
+
for (var c = 0; c < missing.length; c++) {
|
|
80
|
+
if (missing[c].status === "outdated") hasOutdated = true;
|
|
81
|
+
else hasMissing = true;
|
|
82
|
+
}
|
|
83
|
+
var defaultTitle = hasMissing ? "Skill Installation Required" : "Skill Update Available";
|
|
84
|
+
var defaultReason = hasMissing
|
|
85
|
+
? "This feature requires the following skill(s) to be installed."
|
|
86
|
+
: "Newer versions of the following skill(s) are available.";
|
|
87
|
+
if (hasMissing && hasOutdated) {
|
|
88
|
+
defaultTitle = "Skill Installation / Update Required";
|
|
89
|
+
defaultReason = "Some skills need to be installed or updated.";
|
|
90
|
+
}
|
|
91
|
+
skillInstallTitle.textContent = opts.title || defaultTitle;
|
|
92
|
+
skillInstallReason.textContent = opts.reason || defaultReason;
|
|
93
|
+
skillInstallList.innerHTML = "";
|
|
94
|
+
for (var i = 0; i < missing.length; i++) {
|
|
95
|
+
var s = missing[i];
|
|
96
|
+
var badge = s.status === "outdated"
|
|
97
|
+
? '<span class="skill-badge skill-badge-update">Update ' + escapeHtml(s.installedVersion || "") + ' \u2192 ' + escapeHtml(s.remoteVersion || "") + '</span>'
|
|
98
|
+
: '<span class="skill-badge skill-badge-new">New</span>';
|
|
99
|
+
var item = document.createElement("div");
|
|
100
|
+
item.className = "skill-install-item";
|
|
101
|
+
item.setAttribute("data-skill", s.name);
|
|
102
|
+
item.innerHTML = '<span class="skill-icon">🧩</span>' +
|
|
103
|
+
'<div class="skill-info">' +
|
|
104
|
+
'<span class="skill-name">' + escapeHtml(s.name) + '</span>' +
|
|
105
|
+
badge +
|
|
106
|
+
'</div>' +
|
|
107
|
+
'<span class="skill-status"></span>';
|
|
108
|
+
skillInstallList.appendChild(item);
|
|
109
|
+
}
|
|
110
|
+
skillInstallStatus.classList.add("hidden");
|
|
111
|
+
skillInstallStatus.innerHTML = "";
|
|
112
|
+
skillInstallOk.disabled = false;
|
|
113
|
+
var btnLabel = hasMissing ? "Install" : "Update";
|
|
114
|
+
if (hasMissing && hasOutdated) btnLabel = "Install / Update";
|
|
115
|
+
skillInstallOk.textContent = btnLabel;
|
|
116
|
+
skillInstallOk.className = "confirm-btn confirm-delete";
|
|
117
|
+
skillInstallModal.classList.remove("hidden");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function hideSkillInstallModal() {
|
|
121
|
+
skillInstallModal.classList.add("hidden");
|
|
122
|
+
skillInstallCallback = null;
|
|
123
|
+
pendingSkillInstalls = [];
|
|
124
|
+
skillInstalling = false;
|
|
125
|
+
skillInstallDone = false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function updateSkillInstallProgress(done, total) {
|
|
129
|
+
var hasUpdates = false;
|
|
130
|
+
for (var u = 0; u < pendingSkillInstalls.length; u++) {
|
|
131
|
+
if (pendingSkillInstalls[u].status === "outdated") { hasUpdates = true; break; }
|
|
132
|
+
}
|
|
133
|
+
var label = hasUpdates ? "Updating" : "Installing";
|
|
134
|
+
skillInstallStatus.innerHTML = '<div class="skills-spinner small"></div> ' + label + ' skills... (' + done + '/' + total + ')';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function updateSkillListItems() {
|
|
138
|
+
var items = skillInstallList.querySelectorAll(".skill-install-item");
|
|
139
|
+
for (var i = 0; i < items.length; i++) {
|
|
140
|
+
var name = items[i].getAttribute("data-skill");
|
|
141
|
+
for (var j = 0; j < pendingSkillInstalls.length; j++) {
|
|
142
|
+
if (pendingSkillInstalls[j].name === name) {
|
|
143
|
+
var statusEl = items[i].querySelector(".skill-status");
|
|
144
|
+
if (pendingSkillInstalls[j].installed) {
|
|
145
|
+
if (statusEl) {
|
|
146
|
+
statusEl.innerHTML = '<span class="skill-status-ok">' + iconHtml("circle-check") + '</span>';
|
|
147
|
+
refreshIcons();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function handleSkillInstallWs(msg) {
|
|
157
|
+
if (!skillInstalling || pendingSkillInstalls.length === 0) return;
|
|
158
|
+
for (var i = 0; i < pendingSkillInstalls.length; i++) {
|
|
159
|
+
if (pendingSkillInstalls[i].name === msg.skill) {
|
|
160
|
+
if (msg.success) {
|
|
161
|
+
pendingSkillInstalls[i].installed = true;
|
|
162
|
+
knownInstalledSkills[msg.skill] = true;
|
|
163
|
+
} else {
|
|
164
|
+
skillInstalling = false;
|
|
165
|
+
skillInstallOk.disabled = false;
|
|
166
|
+
skillInstallOk.textContent = "Install";
|
|
167
|
+
skillInstallStatus.innerHTML = "Failed to install " + escapeHtml(msg.skill) + ". Try again.";
|
|
168
|
+
updateSkillListItems();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
var doneCount = 0;
|
|
175
|
+
var totalCount = pendingSkillInstalls.length;
|
|
176
|
+
for (var k = 0; k < pendingSkillInstalls.length; k++) {
|
|
177
|
+
if (pendingSkillInstalls[k].installed) doneCount++;
|
|
178
|
+
}
|
|
179
|
+
updateSkillListItems();
|
|
180
|
+
updateSkillInstallProgress(doneCount, totalCount);
|
|
181
|
+
|
|
182
|
+
if (doneCount === totalCount) {
|
|
183
|
+
skillInstallDone = true;
|
|
184
|
+
var hasUpdates = false;
|
|
185
|
+
for (var u = 0; u < pendingSkillInstalls.length; u++) {
|
|
186
|
+
if (pendingSkillInstalls[u].status === "outdated") { hasUpdates = true; break; }
|
|
187
|
+
}
|
|
188
|
+
var doneMsg = hasUpdates ? "All skills updated successfully." : "All skills installed successfully.";
|
|
189
|
+
skillInstallStatus.innerHTML = '<span class="skill-status-ok">' + iconHtml("circle-check") + '</span> ' + doneMsg;
|
|
190
|
+
refreshIcons();
|
|
191
|
+
skillInstallOk.disabled = false;
|
|
192
|
+
skillInstallOk.textContent = "Proceed";
|
|
193
|
+
skillInstallOk.className = "confirm-btn confirm-proceed";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function requireSkills(opts, cb) {
|
|
198
|
+
fetch(_ctx.basePath + "api/check-skill-updates", {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: { "Content-Type": "application/json" },
|
|
201
|
+
body: JSON.stringify({ skills: opts.skills }),
|
|
202
|
+
})
|
|
203
|
+
.then(function (res) { return res.json(); })
|
|
204
|
+
.then(function (data) {
|
|
205
|
+
var results = data.results || [];
|
|
206
|
+
var actionable = [];
|
|
207
|
+
for (var i = 0; i < results.length; i++) {
|
|
208
|
+
var r = results[i];
|
|
209
|
+
if (r.status === "missing" || r.status === "outdated") {
|
|
210
|
+
var orig = null;
|
|
211
|
+
for (var j = 0; j < opts.skills.length; j++) {
|
|
212
|
+
if (opts.skills[j].name === r.name) { orig = opts.skills[j]; break; }
|
|
213
|
+
}
|
|
214
|
+
if (!orig) continue;
|
|
215
|
+
actionable.push({
|
|
216
|
+
name: r.name,
|
|
217
|
+
url: orig.url,
|
|
218
|
+
scope: orig.scope || "global",
|
|
219
|
+
installed: false,
|
|
220
|
+
status: r.status,
|
|
221
|
+
installedVersion: r.installedVersion,
|
|
222
|
+
remoteVersion: r.remoteVersion,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (actionable.length === 0) { cb(); return; }
|
|
227
|
+
pendingSkillInstalls = actionable;
|
|
228
|
+
skillInstallCallback = cb;
|
|
229
|
+
renderSkillInstallDialog(opts, actionable);
|
|
230
|
+
})
|
|
231
|
+
.catch(function () { cb(); });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function requireClayMateInterview(cb) {
|
|
235
|
+
requireSkills({
|
|
236
|
+
title: "Skill Installation Required",
|
|
237
|
+
reason: "The Mate Interview skill is required to create a new Mate.",
|
|
238
|
+
skills: [{ name: "clay-mate-interview", url: "https://github.com/chadbyte/clay-mate-interview", scope: "global" }]
|
|
239
|
+
}, cb);
|
|
240
|
+
}
|