clay-server 2.27.0-beta.8 → 2.27.0

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 (72) hide show
  1. package/README.md +10 -0
  2. package/lib/daemon-projects.js +164 -0
  3. package/lib/daemon.js +13 -126
  4. package/lib/mates-identity.js +132 -0
  5. package/lib/mates-knowledge.js +113 -0
  6. package/lib/mates-prompts.js +398 -0
  7. package/lib/mates.js +40 -599
  8. package/lib/project-connection.js +2 -0
  9. package/lib/project-debate.js +19 -12
  10. package/lib/project-http.js +4 -2
  11. package/lib/project-loop.js +110 -48
  12. package/lib/project-mate-interaction.js +4 -0
  13. package/lib/project-notifications.js +210 -0
  14. package/lib/project-sessions.js +5 -2
  15. package/lib/project-user-message.js +2 -1
  16. package/lib/project.js +26 -2
  17. package/lib/public/app.js +1193 -8521
  18. package/lib/public/css/command-palette.css +14 -0
  19. package/lib/public/css/loop.css +301 -0
  20. package/lib/public/css/notifications-center.css +190 -0
  21. package/lib/public/css/rewind.css +6 -0
  22. package/lib/public/index.html +89 -35
  23. package/lib/public/modules/app-connection.js +160 -0
  24. package/lib/public/modules/app-cursors.js +473 -0
  25. package/lib/public/modules/app-debate-ui.js +389 -0
  26. package/lib/public/modules/app-dm.js +627 -0
  27. package/lib/public/modules/app-favicon.js +212 -0
  28. package/lib/public/modules/app-header.js +229 -0
  29. package/lib/public/modules/app-home-hub.js +600 -0
  30. package/lib/public/modules/app-loop-ui.js +589 -0
  31. package/lib/public/modules/app-loop-wizard.js +439 -0
  32. package/lib/public/modules/app-messages.js +1560 -0
  33. package/lib/public/modules/app-misc.js +299 -0
  34. package/lib/public/modules/app-notifications.js +372 -0
  35. package/lib/public/modules/app-panels.js +888 -0
  36. package/lib/public/modules/app-projects.js +798 -0
  37. package/lib/public/modules/app-rate-limit.js +451 -0
  38. package/lib/public/modules/app-rendering.js +597 -0
  39. package/lib/public/modules/app-skills-install.js +234 -0
  40. package/lib/public/modules/command-palette.js +27 -4
  41. package/lib/public/modules/input.js +31 -20
  42. package/lib/public/modules/scheduler-config.js +1532 -0
  43. package/lib/public/modules/scheduler-history.js +79 -0
  44. package/lib/public/modules/scheduler.js +33 -1554
  45. package/lib/public/modules/session-search.js +13 -1
  46. package/lib/public/modules/sidebar-mates.js +812 -0
  47. package/lib/public/modules/sidebar-mobile.js +1269 -0
  48. package/lib/public/modules/sidebar-projects.js +1449 -0
  49. package/lib/public/modules/sidebar-sessions.js +986 -0
  50. package/lib/public/modules/sidebar.js +232 -4591
  51. package/lib/public/modules/store.js +27 -0
  52. package/lib/public/modules/ws-ref.js +7 -0
  53. package/lib/public/style.css +1 -0
  54. package/lib/sdk-bridge.js +96 -717
  55. package/lib/sdk-message-processor.js +587 -0
  56. package/lib/sdk-message-queue.js +42 -0
  57. package/lib/sdk-skill-discovery.js +131 -0
  58. package/lib/server-admin.js +712 -0
  59. package/lib/server-auth.js +737 -0
  60. package/lib/server-dm.js +221 -0
  61. package/lib/server-mates.js +281 -0
  62. package/lib/server-palette.js +110 -0
  63. package/lib/server-settings.js +479 -0
  64. package/lib/server-skills.js +280 -0
  65. package/lib/server.js +246 -2755
  66. package/lib/sessions.js +11 -4
  67. package/lib/users-auth.js +146 -0
  68. package/lib/users-permissions.js +118 -0
  69. package/lib/users-preferences.js +210 -0
  70. package/lib/users.js +48 -398
  71. package/lib/ws-schema.js +498 -0
  72. package/package.json +1 -1
@@ -0,0 +1,439 @@
1
+ // app-loop-wizard.js - Ralph Loop wizard: step navigation, data collection, repeat picker
2
+ // Extracted from app-loop-ui.js
3
+
4
+ import { refreshIcons } from './icons.js';
5
+ import { store } from './store.js';
6
+ import { getWs } from './ws-ref.js';
7
+ import { requireSkills } from './app-skills-install.js';
8
+
9
+ // --- Module-owned state (not in store) ---
10
+ var wizardStep = 1;
11
+ var wizardSource = "ralph"; // "ralph" or "task"
12
+ var wizardMode = "draft"; // "draft" or "own"
13
+ var loopModeChoice = "judge"; // "simple" | "judge"
14
+ var promptAuthor = "clay"; // "clay" | "me"
15
+ var judgeAuthor = "clay"; // "clay" | "me"
16
+
17
+ // --- Module-local state accessors ---
18
+ export function getWizardSource() { return wizardSource; }
19
+
20
+ // --- DOM refs for repeat picker (captured in init) ---
21
+ var repeatSelect = null;
22
+ var repeatTimeRow = null;
23
+ var repeatCustom = null;
24
+ var repeatUnitSelect = null;
25
+ var repeatDowRow = null;
26
+ var cronPreview = null;
27
+
28
+ // ========================================================
29
+ // Init
30
+ // ========================================================
31
+ export function initLoopWizard() {
32
+ // Repeat picker DOM refs
33
+ repeatSelect = document.getElementById("ralph-repeat");
34
+ repeatTimeRow = document.getElementById("ralph-time-row");
35
+ repeatCustom = document.getElementById("ralph-custom-repeat");
36
+ repeatUnitSelect = document.getElementById("ralph-repeat-unit");
37
+ repeatDowRow = document.getElementById("ralph-custom-dow-row");
38
+ cronPreview = document.getElementById("ralph-cron-preview");
39
+
40
+ // --- Wizard button listeners ---
41
+ var wizardCloseBtn = document.getElementById("ralph-wizard-close");
42
+ var wizardBackdrop = document.querySelector(".ralph-wizard-backdrop");
43
+ var wizardBackBtn = document.getElementById("ralph-wizard-back");
44
+ var wizardSkipBtn = document.getElementById("ralph-wizard-skip");
45
+ var wizardNextBtn = document.getElementById("ralph-wizard-next");
46
+
47
+ if (wizardCloseBtn) wizardCloseBtn.addEventListener("click", closeRalphWizard);
48
+ if (wizardBackdrop) wizardBackdrop.addEventListener("click", closeRalphWizard);
49
+ if (wizardBackBtn) wizardBackBtn.addEventListener("click", wizardBack);
50
+ if (wizardSkipBtn) wizardSkipBtn.addEventListener("click", wizardSkip);
51
+ if (wizardNextBtn) wizardNextBtn.addEventListener("click", wizardNext);
52
+
53
+ // --- Mode cards (step 1: loop mode) ---
54
+ var modeCards = document.querySelectorAll(".ralph-mode-card");
55
+ for (var mc = 0; mc < modeCards.length; mc++) {
56
+ modeCards[mc].addEventListener("click", function () {
57
+ loopModeChoice = this.getAttribute("data-loop-mode");
58
+ var all = document.querySelectorAll(".ralph-mode-card");
59
+ for (var i = 0; i < all.length; i++) all[i].classList.remove("active");
60
+ this.classList.add("active");
61
+ updateModePreview();
62
+ });
63
+ }
64
+
65
+ // --- Authorship toggles (step 3) ---
66
+ var authorBtns = document.querySelectorAll(".ralph-authorship-toggle .config-segment-btn");
67
+ for (var ab = 0; ab < authorBtns.length; ab++) {
68
+ authorBtns[ab].addEventListener("click", function () {
69
+ var toggle = this.parentElement;
70
+ var file = toggle.getAttribute("data-file");
71
+ var author = this.getAttribute("data-author");
72
+ var siblings = toggle.querySelectorAll(".config-segment-btn");
73
+ for (var s = 0; s < siblings.length; s++) siblings[s].classList.remove("active");
74
+ this.classList.add("active");
75
+ if (file === "prompt") promptAuthor = author;
76
+ if (file === "judge") judgeAuthor = author;
77
+ });
78
+ }
79
+
80
+ // --- Repeat picker handlers ---
81
+ if (repeatSelect) {
82
+ repeatSelect.addEventListener("change", updateRepeatUI);
83
+ }
84
+ if (repeatUnitSelect) {
85
+ repeatUnitSelect.addEventListener("change", function () {
86
+ if (repeatDowRow) repeatDowRow.style.display = this.value === "week" ? "" : "none";
87
+ updateRepeatUI();
88
+ });
89
+ }
90
+
91
+ var timeInput = document.getElementById("ralph-time");
92
+ if (timeInput) timeInput.addEventListener("change", updateRepeatUI);
93
+
94
+ // DOW buttons in custom repeat
95
+ var customDowBtns = document.querySelectorAll("#ralph-custom-repeat .sched-dow-btn");
96
+ for (var di = 0; di < customDowBtns.length; di++) {
97
+ customDowBtns[di].addEventListener("click", function () {
98
+ this.classList.toggle("active");
99
+ updateRepeatUI();
100
+ });
101
+ }
102
+ }
103
+
104
+ // ========================================================
105
+ // Mode preview toggle
106
+ // ========================================================
107
+
108
+ function updateModePreview() {
109
+ var judgePreview = document.querySelector(".ralph-mode-preview-judge");
110
+ var simplePreview = document.querySelector(".ralph-mode-preview-simple");
111
+ if (judgePreview) judgePreview.style.display = loopModeChoice === "judge" ? "" : "none";
112
+ if (simplePreview) simplePreview.style.display = loopModeChoice === "simple" ? "" : "none";
113
+ }
114
+
115
+ // ========================================================
116
+ // requireClayRalph
117
+ // ========================================================
118
+
119
+ function requireClayRalph(cb) {
120
+ requireSkills({
121
+ title: "Skill Installation Required",
122
+ reason: "This feature requires the following skill to be installed.",
123
+ skills: [{ name: "clay-ralph", url: "https://github.com/chadbyte/clay-ralph", scope: "global" }]
124
+ }, cb);
125
+ }
126
+
127
+ // ========================================================
128
+ // Ralph Wizard (exported: openRalphWizard, closeRalphWizard)
129
+ // ========================================================
130
+
131
+ export function openRalphWizard(source) {
132
+ requireClayRalph(function () {
133
+ wizardSource = source || "ralph";
134
+ store.setState({ wizardData: { name: "", task: "", maxIterations: null } });
135
+ loopModeChoice = "judge";
136
+ promptAuthor = "clay";
137
+ judgeAuthor = "clay";
138
+
139
+ var el = document.getElementById("ralph-wizard");
140
+ if (!el) return;
141
+
142
+ // Reset inputs
143
+ var taskEl = document.getElementById("ralph-task");
144
+ if (taskEl) taskEl.value = "";
145
+ var promptInput = document.getElementById("ralph-prompt-input");
146
+ if (promptInput) promptInput.value = "";
147
+ var judgeInput = document.getElementById("ralph-judge-input");
148
+ if (judgeInput) judgeInput.value = "";
149
+
150
+ // Reset mode cards
151
+ var modeCards = document.querySelectorAll(".ralph-mode-card");
152
+ for (var mc = 0; mc < modeCards.length; mc++) {
153
+ if (modeCards[mc].getAttribute("data-loop-mode") === "judge") {
154
+ modeCards[mc].classList.add("active");
155
+ } else {
156
+ modeCards[mc].classList.remove("active");
157
+ }
158
+ }
159
+
160
+ // Reset authorship toggles
161
+ var authorToggles = document.querySelectorAll(".ralph-authorship-toggle");
162
+ for (var at = 0; at < authorToggles.length; at++) {
163
+ var btns = authorToggles[at].querySelectorAll(".config-segment-btn");
164
+ for (var b = 0; b < btns.length; b++) {
165
+ if (btns[b].getAttribute("data-author") === "clay") {
166
+ btns[b].classList.add("active");
167
+ } else {
168
+ btns[b].classList.remove("active");
169
+ }
170
+ }
171
+ }
172
+
173
+ // Update text based on source
174
+ var isTask = wizardSource === "task";
175
+ var headerSpan = el.querySelector(".ralph-wizard-header > span");
176
+ if (headerSpan) headerSpan.textContent = isTask ? "New Task" : "New Loop";
177
+
178
+ if (wizardSource === "task") {
179
+ // Tasks skip step 1 (loop mode), go to step 2
180
+ wizardStep = 2;
181
+ } else {
182
+ wizardStep = 1;
183
+ }
184
+ el.classList.remove("hidden");
185
+ var statusEl = document.getElementById("ralph-install-status");
186
+ if (statusEl) { statusEl.classList.add("hidden"); statusEl.innerHTML = ""; }
187
+
188
+ // Reset exec modal flag
189
+ store.setState({ execModalShown: false });
190
+
191
+ updateModePreview();
192
+ updateWizardStep();
193
+ });
194
+ }
195
+
196
+ export function closeRalphWizard() {
197
+ var el = document.getElementById("ralph-wizard");
198
+ if (el) el.classList.add("hidden");
199
+ }
200
+
201
+ // --- Internal wizard helpers ---
202
+
203
+ function updateWizardStep() {
204
+ var steps = document.querySelectorAll(".ralph-step");
205
+ for (var i = 0; i < steps.length; i++) {
206
+ var stepNum = parseInt(steps[i].getAttribute("data-step"), 10);
207
+ if (stepNum === wizardStep) {
208
+ steps[i].classList.add("active");
209
+ } else {
210
+ steps[i].classList.remove("active");
211
+ }
212
+ }
213
+ var dots = document.querySelectorAll(".ralph-dot");
214
+ for (var j = 0; j < dots.length; j++) {
215
+ var dotStep = parseInt(dots[j].getAttribute("data-step"), 10);
216
+ dots[j].classList.remove("active", "done");
217
+ if (dotStep === wizardStep) dots[j].classList.add("active");
218
+ else if (dotStep < wizardStep) dots[j].classList.add("done");
219
+ }
220
+
221
+ // Show/hide JUDGE authorship row based on loop mode
222
+ var judgeRow = document.getElementById("ralph-judge-authorship-row");
223
+ if (judgeRow) judgeRow.style.display = loopModeChoice === "simple" ? "none" : "";
224
+
225
+ // Update step 3 input visibility
226
+ if (wizardStep === 3) updateInputVisibility();
227
+
228
+ var backBtn = document.getElementById("ralph-wizard-back");
229
+ var skipBtn = document.getElementById("ralph-wizard-skip");
230
+ var nextBtn = document.getElementById("ralph-wizard-next");
231
+ if (backBtn) {
232
+ var firstStep = (wizardSource === "task") ? 2 : 1;
233
+ backBtn.style.visibility = (wizardStep === firstStep) ? "hidden" : "visible";
234
+ backBtn.textContent = (wizardSource === "task" && wizardStep <= 2) ? "Cancel" : "Back";
235
+ }
236
+ if (skipBtn) skipBtn.style.display = "none";
237
+ if (nextBtn) {
238
+ if (wizardStep === 3) nextBtn.textContent = "Launch";
239
+ else nextBtn.textContent = "Next";
240
+ }
241
+ }
242
+
243
+ function updateInputVisibility() {
244
+ var taskSection = document.getElementById("ralph-input-task-section");
245
+ var promptSection = document.getElementById("ralph-input-prompt-section");
246
+ var judgeSection = document.getElementById("ralph-input-judge-section");
247
+
248
+ var needsTask = (promptAuthor === "clay");
249
+ var needsPrompt = (promptAuthor === "me");
250
+ var needsJudge = (loopModeChoice === "judge" && judgeAuthor === "me");
251
+
252
+ if (taskSection) {
253
+ if (needsTask) taskSection.classList.remove("hidden");
254
+ else taskSection.classList.add("hidden");
255
+ }
256
+ if (promptSection) {
257
+ if (needsPrompt) promptSection.classList.remove("hidden");
258
+ else promptSection.classList.add("hidden");
259
+ }
260
+ if (judgeSection) {
261
+ if (needsJudge) judgeSection.classList.remove("hidden");
262
+ else judgeSection.classList.add("hidden");
263
+ }
264
+
265
+ var heading = document.querySelector('.ralph-step[data-step="3"] h3');
266
+ if (heading) {
267
+ if (needsTask && !needsJudge) heading.textContent = "Describe your task";
268
+ else if (needsPrompt && !needsJudge) heading.textContent = "Provide your prompt";
269
+ else if (needsPrompt && needsJudge) heading.textContent = "Provide your files";
270
+ else if (needsTask && needsJudge) heading.textContent = "Provide details";
271
+ else heading.textContent = "Provide details";
272
+ }
273
+ }
274
+
275
+ function collectWizardData() {
276
+ var wd = {
277
+ name: "",
278
+ maxIterations: null,
279
+ cron: buildWizardCron(),
280
+ loopMode: loopModeChoice,
281
+ promptAuthor: promptAuthor,
282
+ judgeAuthor: (loopModeChoice === "judge") ? judgeAuthor : null,
283
+ mode: (promptAuthor === "me") ? "own" : "draft"
284
+ };
285
+
286
+ if (promptAuthor === "clay") {
287
+ var taskEl = document.getElementById("ralph-task");
288
+ wd.task = taskEl ? taskEl.value.trim() : "";
289
+ wd.promptText = null;
290
+ } else {
291
+ var promptInput = document.getElementById("ralph-prompt-input");
292
+ wd.task = "";
293
+ wd.promptText = promptInput ? promptInput.value.trim() : "";
294
+ }
295
+
296
+ if (loopModeChoice === "judge" && judgeAuthor === "me") {
297
+ var judgeInput = document.getElementById("ralph-judge-input");
298
+ wd.judgeText = judgeInput ? judgeInput.value.trim() : "";
299
+ } else {
300
+ wd.judgeText = null;
301
+ }
302
+
303
+ store.setState({ wizardData: wd });
304
+ }
305
+
306
+ function buildWizardCron() {
307
+ if (!repeatSelect) return null;
308
+ var preset = repeatSelect.value;
309
+ if (preset === "none") return null;
310
+
311
+ var timeEl = document.getElementById("ralph-time");
312
+ var timeVal = timeEl ? timeEl.value : "09:00";
313
+ var timeParts = timeVal.split(":");
314
+ var hour = parseInt(timeParts[0], 10) || 9;
315
+ var minute = parseInt(timeParts[1], 10) || 0;
316
+
317
+ if (preset === "daily") return minute + " " + hour + " * * *";
318
+ if (preset === "weekdays") return minute + " " + hour + " * * 1-5";
319
+ if (preset === "weekly") return minute + " " + hour + " * * " + new Date().getDay();
320
+ if (preset === "monthly") return minute + " " + hour + " " + new Date().getDate() + " * *";
321
+
322
+ if (preset === "custom") {
323
+ var unitEl = document.getElementById("ralph-repeat-unit");
324
+ var unit = unitEl ? unitEl.value : "day";
325
+ if (unit === "day") return minute + " " + hour + " * * *";
326
+ if (unit === "month") return minute + " " + hour + " " + new Date().getDate() + " * *";
327
+ // week: collect selected days
328
+ var dowBtns = document.querySelectorAll("#ralph-custom-repeat .sched-dow-btn.active");
329
+ var days = [];
330
+ for (var i = 0; i < dowBtns.length; i++) {
331
+ days.push(dowBtns[i].dataset.dow);
332
+ }
333
+ if (days.length === 0) days.push(String(new Date().getDay()));
334
+ return minute + " " + hour + " * * " + days.join(",");
335
+ }
336
+ return null;
337
+ }
338
+
339
+ function cronToHumanText(cron) {
340
+ if (!cron) return "";
341
+ var parts = cron.trim().split(/\s+/);
342
+ if (parts.length !== 5) return cron;
343
+ var m = parts[0], h = parts[1], dom = parts[2], dow = parts[4];
344
+ var pad = function(n) { return (parseInt(n,10) < 10 ? "0" : "") + parseInt(n,10); };
345
+ var t = pad(h) + ":" + pad(m);
346
+ var dayNames = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
347
+ if (dow === "*" && dom === "*") return "Every day at " + t;
348
+ if (dow === "1-5" && dom === "*") return "Weekdays at " + t;
349
+ if (dom !== "*" && dow === "*") return "Monthly on day " + dom + " at " + t;
350
+ if (dow !== "*" && dom === "*") {
351
+ var ds = dow.split(",").map(function(d) { return dayNames[parseInt(d,10)] || d; });
352
+ return "Every " + ds.join(", ") + " at " + t;
353
+ }
354
+ return cron;
355
+ }
356
+
357
+ var LAST_STEP = 3;
358
+
359
+ function validateLastStep() {
360
+ var wd = store.getState().wizardData;
361
+ if (promptAuthor === "clay") {
362
+ var taskEl = document.getElementById("ralph-task");
363
+ if (!wd.task) {
364
+ if (taskEl) { taskEl.focus(); taskEl.style.borderColor = "#e74c3c"; setTimeout(function() { taskEl.style.borderColor = ""; }, 2000); }
365
+ return false;
366
+ }
367
+ } else {
368
+ var promptInput = document.getElementById("ralph-prompt-input");
369
+ if (!wd.promptText) {
370
+ if (promptInput) { promptInput.focus(); promptInput.style.borderColor = "#e74c3c"; setTimeout(function() { promptInput.style.borderColor = ""; }, 2000); }
371
+ return false;
372
+ }
373
+ }
374
+ if (loopModeChoice === "judge" && judgeAuthor === "me") {
375
+ var judgeInput = document.getElementById("ralph-judge-input");
376
+ if (!wd.judgeText) {
377
+ if (judgeInput) { judgeInput.focus(); judgeInput.style.borderColor = "#e74c3c"; setTimeout(function() { judgeInput.style.borderColor = ""; }, 2000); }
378
+ return false;
379
+ }
380
+ }
381
+ return true;
382
+ }
383
+
384
+ function wizardNext() {
385
+ collectWizardData();
386
+ if (wizardStep < LAST_STEP) {
387
+ wizardStep++;
388
+ updateWizardStep();
389
+ return;
390
+ }
391
+ if (validateLastStep()) wizardSubmit();
392
+ }
393
+
394
+ function wizardBack() {
395
+ if (wizardSource === "task" && wizardStep <= 2) {
396
+ closeRalphWizard();
397
+ return;
398
+ }
399
+ if (wizardStep > 1) {
400
+ collectWizardData();
401
+ wizardStep--;
402
+ updateWizardStep();
403
+ }
404
+ }
405
+
406
+ function wizardSkip() {
407
+ if (wizardStep < 3) {
408
+ wizardStep++;
409
+ updateWizardStep();
410
+ }
411
+ }
412
+
413
+ function wizardSubmit() {
414
+ collectWizardData();
415
+ var wd = Object.assign({}, store.getState().wizardData);
416
+ wd.source = wizardSource === "task" ? "task" : undefined;
417
+ store.setState({ wizardData: wd });
418
+ closeRalphWizard();
419
+ var ws = getWs();
420
+ if (ws && ws.readyState === 1) {
421
+ ws.send(JSON.stringify({ type: "ralph_wizard_complete", data: wd }));
422
+ }
423
+ }
424
+
425
+ function updateRepeatUI() {
426
+ if (!repeatSelect) return;
427
+ var val = repeatSelect.value;
428
+ var isScheduled = val !== "none";
429
+ if (repeatTimeRow) repeatTimeRow.style.display = isScheduled ? "" : "none";
430
+ if (repeatCustom) repeatCustom.style.display = val === "custom" ? "" : "none";
431
+ if (cronPreview) cronPreview.style.display = isScheduled ? "" : "none";
432
+ if (isScheduled) {
433
+ var cron = buildWizardCron();
434
+ var humanEl = document.getElementById("ralph-cron-human");
435
+ var cronEl = document.getElementById("ralph-cron-expr");
436
+ if (humanEl) humanEl.textContent = cronToHumanText(cron);
437
+ if (cronEl) cronEl.textContent = cron || "";
438
+ }
439
+ }