clay-server 2.6.0 → 2.7.1

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.
Files changed (38) hide show
  1. package/bin/cli.js +53 -4
  2. package/lib/config.js +15 -6
  3. package/lib/daemon.js +47 -5
  4. package/lib/ipc.js +12 -0
  5. package/lib/notes.js +2 -2
  6. package/lib/project.js +883 -2
  7. package/lib/public/app.js +862 -14
  8. package/lib/public/css/diff.css +12 -0
  9. package/lib/public/css/filebrowser.css +1 -1
  10. package/lib/public/css/loop.css +841 -0
  11. package/lib/public/css/menus.css +5 -0
  12. package/lib/public/css/mobile-nav.css +15 -15
  13. package/lib/public/css/rewind.css +23 -0
  14. package/lib/public/css/scheduler-modal.css +546 -0
  15. package/lib/public/css/scheduler.css +944 -0
  16. package/lib/public/css/sidebar.css +1 -0
  17. package/lib/public/css/skills.css +59 -0
  18. package/lib/public/css/sticky-notes.css +486 -0
  19. package/lib/public/css/title-bar.css +83 -3
  20. package/lib/public/index.html +181 -3
  21. package/lib/public/modules/diff.js +3 -3
  22. package/lib/public/modules/filebrowser.js +169 -45
  23. package/lib/public/modules/input.js +17 -3
  24. package/lib/public/modules/markdown.js +10 -0
  25. package/lib/public/modules/qrcode.js +23 -26
  26. package/lib/public/modules/scheduler.js +1240 -0
  27. package/lib/public/modules/server-settings.js +40 -0
  28. package/lib/public/modules/sidebar.js +12 -0
  29. package/lib/public/modules/skills.js +84 -0
  30. package/lib/public/modules/sticky-notes.js +617 -52
  31. package/lib/public/modules/theme.js +9 -19
  32. package/lib/public/modules/tools.js +16 -2
  33. package/lib/public/style.css +3 -0
  34. package/lib/scheduler.js +362 -0
  35. package/lib/sdk-bridge.js +36 -0
  36. package/lib/sessions.js +9 -5
  37. package/lib/utils.js +49 -3
  38. package/package.json +1 -1
@@ -179,6 +179,19 @@ export function initServerSettings(appCtx) {
179
179
  });
180
180
  }
181
181
 
182
+ // Restart server
183
+ var restartBtn = document.getElementById("settings-restart-btn");
184
+ if (restartBtn) {
185
+ restartBtn.addEventListener("click", function () {
186
+ var ws = ctx.ws;
187
+ if (ws && ws.readyState === 1) {
188
+ restartBtn.disabled = true;
189
+ restartBtn.textContent = "Restarting...";
190
+ ws.send(JSON.stringify({ type: "restart_server" }));
191
+ }
192
+ });
193
+ }
194
+
182
195
  // Shutdown server
183
196
  var shutdownInput = document.getElementById("settings-shutdown-input");
184
197
  var shutdownBtn = document.getElementById("settings-shutdown-btn");
@@ -235,6 +248,7 @@ function openSettings() {
235
248
  refreshIcons(settingsEl);
236
249
  populateSettings();
237
250
  requestDaemonConfig();
251
+ resetRestartButton();
238
252
  resetShutdownForm();
239
253
 
240
254
  // Start periodic stats refresh
@@ -242,6 +256,13 @@ function openSettings() {
242
256
  statsTimer = setInterval(requestStats, 5000);
243
257
  }
244
258
 
259
+ function resetRestartButton() {
260
+ var btn = document.getElementById("settings-restart-btn");
261
+ var errorEl = document.getElementById("settings-restart-error");
262
+ if (btn) { btn.disabled = false; btn.innerHTML = '<i data-lucide="refresh-cw" style="width:14px;height:14px;vertical-align:-2px;margin-right:4px;"></i>Restart Server'; }
263
+ if (errorEl) errorEl.classList.add("hidden");
264
+ }
265
+
245
266
  function resetShutdownForm() {
246
267
  var input = document.getElementById("settings-shutdown-input");
247
268
  var btn = document.getElementById("settings-shutdown-btn");
@@ -580,6 +601,25 @@ export function handleKeepAwakeChanged(msg) {
580
601
  if (keepAwakeToggle) keepAwakeToggle.checked = !!msg.keepAwake;
581
602
  }
582
603
 
604
+ export function handleRestartResult(msg) {
605
+ var restartBtn = document.getElementById("settings-restart-btn");
606
+ var errorEl = document.getElementById("settings-restart-error");
607
+
608
+ if (msg.ok) {
609
+ if (restartBtn) restartBtn.textContent = "Server restarting...";
610
+ showToast("Server is restarting...");
611
+ } else {
612
+ if (restartBtn) {
613
+ restartBtn.textContent = "Restart Server";
614
+ restartBtn.disabled = false;
615
+ }
616
+ if (errorEl) {
617
+ errorEl.textContent = msg.error || "Restart failed";
618
+ errorEl.classList.remove("hidden");
619
+ }
620
+ }
621
+ }
622
+
583
623
  export function handleShutdownResult(msg) {
584
624
  var shutdownInput = document.getElementById("settings-shutdown-input");
585
625
  var shutdownBtn = document.getElementById("settings-shutdown-btn");
@@ -1,6 +1,7 @@
1
1
  import { escapeHtml, copyToClipboard } from './utils.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { openProjectSettings } from './project-settings.js';
4
+ import { triggerShare } from './qrcode.js';
4
5
 
5
6
  var ctx;
6
7
 
@@ -1225,6 +1226,17 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
1225
1226
  });
1226
1227
  menu.appendChild(settingsItem);
1227
1228
 
1229
+ // --- Share ---
1230
+ var shareItem = document.createElement("button");
1231
+ shareItem.className = "project-ctx-item";
1232
+ shareItem.innerHTML = iconHtml("share") + " <span>Share</span>";
1233
+ shareItem.addEventListener("click", function (e) {
1234
+ e.stopPropagation();
1235
+ closeProjectCtxMenu();
1236
+ triggerShare();
1237
+ });
1238
+ menu.appendChild(shareItem);
1239
+
1228
1240
  // --- Separator ---
1229
1241
  var sep = document.createElement("div");
1230
1242
  sep.className = "project-ctx-separator";
@@ -196,6 +196,12 @@ function loadSkills(tab) {
196
196
  var searchEl = document.getElementById("skills-search");
197
197
  if (searchEl) searchEl.style.display = "";
198
198
 
199
+ // Installed tab — uses local data, not skills.sh
200
+ if (tab === "installed") {
201
+ loadInstalledSkills();
202
+ return;
203
+ }
204
+
199
205
  // Check cache
200
206
  if (skillsData[tab]) {
201
207
  renderList(skillsData[tab], tab);
@@ -216,6 +222,74 @@ function loadSkills(tab) {
216
222
  });
217
223
  }
218
224
 
225
+ function loadInstalledSkills() {
226
+ contentEl.innerHTML = '<div class="skills-loading"><div class="skills-spinner"></div> Loading installed skills...</div>';
227
+
228
+ fetch(basePath + "api/installed-skills")
229
+ .then(function (res) { return res.json(); })
230
+ .then(function (data) {
231
+ installedSkills = data.installed || {};
232
+ renderInstalledList(installedSkills);
233
+ })
234
+ .catch(function () {
235
+ contentEl.innerHTML = '<div class="skills-empty">Failed to load installed skills</div>';
236
+ });
237
+ }
238
+
239
+ function renderInstalledList(installed) {
240
+ var names = Object.keys(installed);
241
+ if (!names.length) {
242
+ contentEl.innerHTML = '<div class="skills-empty">No skills installed<div class="skills-empty-hint">Browse the other tabs to discover and install skills</div></div>';
243
+ return;
244
+ }
245
+
246
+ var html = '<div class="skills-list">';
247
+
248
+ for (var i = 0; i < names.length; i++) {
249
+ var name = names[i];
250
+ var info = installed[name];
251
+ var desc = info.description || "";
252
+
253
+ html += '<div class="skills-installed-item">' +
254
+ '<div class="skills-installed-item-info">' +
255
+ '<div class="skills-installed-item-header">' +
256
+ '<span class="skills-installed-item-name">' + escapeHtml(name) + '</span>' +
257
+ '<span class="skills-installed-badge">' + iconHtml("check") + ' ' + scopeLabel(info.scope) + '</span>' +
258
+ '</div>' +
259
+ (desc ? '<div class="skills-installed-item-desc">' + escapeHtml(desc) + '</div>' : '') +
260
+ '</div>' +
261
+ '<div class="skills-installed-item-actions">' +
262
+ buildUninstallButtons(name, info.scope) +
263
+ '</div>' +
264
+ '</div>';
265
+ }
266
+
267
+ html += '</div>';
268
+ contentEl.innerHTML = html;
269
+ refreshIcons(contentEl);
270
+
271
+ // Attach uninstall handlers
272
+ var unBtns = contentEl.querySelectorAll(".skills-uninstall-btn");
273
+ for (var j = 0; j < unBtns.length; j++) {
274
+ (function (btn) {
275
+ btn.addEventListener("click", function () {
276
+ uninstallSkill(btn.dataset.skill, btn.dataset.scope);
277
+ });
278
+ })(unBtns[j]);
279
+ }
280
+ }
281
+
282
+ function buildUninstallButtons(skillName, scope) {
283
+ var html = '';
284
+ if (scope === "both") {
285
+ html += '<button class="skills-uninstall-btn" data-skill="' + escapeHtml(skillName) + '" data-scope="project" title="Uninstall (Project)">' + iconHtml("x") + '</button>';
286
+ html += '<button class="skills-uninstall-btn" data-skill="' + escapeHtml(skillName) + '" data-scope="global" title="Uninstall (Global)">' + iconHtml("x") + '</button>';
287
+ } else {
288
+ html += '<button class="skills-uninstall-btn" data-skill="' + escapeHtml(skillName) + '" data-scope="' + escapeHtml(scope) + '" title="Uninstall">' + iconHtml("x") + '</button>';
289
+ }
290
+ return html;
291
+ }
292
+
219
293
  function loadSearchResults(q) {
220
294
  // Stale check — if query changed since this was scheduled, skip
221
295
  if (q !== searchQuery) return;
@@ -529,6 +603,11 @@ export function handleSkillInstalled(msg) {
529
603
  updateDetailInstallButtons(skill);
530
604
  }
531
605
  }
606
+
607
+ // If we're on the installed tab, refresh it
608
+ if (activeTab === "installed" && currentView === "list") {
609
+ loadInstalledSkills();
610
+ }
532
611
  } else {
533
612
  // Show error toast
534
613
  showToast("Failed to install " + skill + (msg.error ? ": " + msg.error : ""), "error");
@@ -593,6 +672,11 @@ export function handleSkillUninstalled(msg) {
593
672
  updateDetailInstallButtons(skill);
594
673
  }
595
674
  }
675
+
676
+ // If we're on the installed tab, refresh it
677
+ if (activeTab === "installed" && currentView === "list") {
678
+ loadInstalledSkills();
679
+ }
596
680
  } else {
597
681
  showToast("Failed to uninstall " + skill + (msg.error ? ": " + msg.error : ""), "error");
598
682
  // Re-enable the uninstall button