clay-server 2.31.0 → 2.32.0-beta.2

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 (74) hide show
  1. package/lib/browser-mcp-server.js +32 -44
  2. package/lib/debate-mcp-server.js +14 -31
  3. package/lib/mcp-local.js +31 -1
  4. package/lib/project-connection.js +4 -2
  5. package/lib/project-filesystem.js +47 -1
  6. package/lib/project-http.js +75 -8
  7. package/lib/project-mcp.js +4 -0
  8. package/lib/project-sessions.js +88 -51
  9. package/lib/project-user-message.js +12 -7
  10. package/lib/project.js +204 -90
  11. package/lib/public/app.js +123 -448
  12. package/lib/public/codex-avatar.png +0 -0
  13. package/lib/public/css/debate.css +3 -2
  14. package/lib/public/css/filebrowser.css +91 -1
  15. package/lib/public/css/icon-strip.css +21 -5
  16. package/lib/public/css/input.css +181 -100
  17. package/lib/public/css/mates.css +43 -0
  18. package/lib/public/css/mention.css +48 -4
  19. package/lib/public/css/menus.css +1 -1
  20. package/lib/public/css/messages.css +2 -0
  21. package/lib/public/css/notifications-center.css +19 -0
  22. package/lib/public/index.html +46 -24
  23. package/lib/public/modules/app-connection.js +138 -37
  24. package/lib/public/modules/app-cursors.js +18 -17
  25. package/lib/public/modules/app-debate-ui.js +9 -9
  26. package/lib/public/modules/app-dm.js +170 -131
  27. package/lib/public/modules/app-favicon.js +28 -26
  28. package/lib/public/modules/app-header.js +79 -68
  29. package/lib/public/modules/app-home-hub.js +55 -47
  30. package/lib/public/modules/app-loop-ui.js +34 -18
  31. package/lib/public/modules/app-loop-wizard.js +6 -6
  32. package/lib/public/modules/app-messages.js +195 -152
  33. package/lib/public/modules/app-misc.js +23 -12
  34. package/lib/public/modules/app-notifications.js +97 -3
  35. package/lib/public/modules/app-panels.js +203 -49
  36. package/lib/public/modules/app-projects.js +159 -150
  37. package/lib/public/modules/app-rate-limit.js +5 -4
  38. package/lib/public/modules/app-rendering.js +149 -101
  39. package/lib/public/modules/app-skills-install.js +4 -4
  40. package/lib/public/modules/context-sources.js +12 -41
  41. package/lib/public/modules/dom-refs.js +21 -0
  42. package/lib/public/modules/filebrowser.js +173 -2
  43. package/lib/public/modules/input.js +86 -0
  44. package/lib/public/modules/mate-sidebar.js +38 -0
  45. package/lib/public/modules/mention.js +24 -6
  46. package/lib/public/modules/scheduler.js +1 -1
  47. package/lib/public/modules/sidebar-mates.js +66 -34
  48. package/lib/public/modules/sidebar-mobile.js +34 -30
  49. package/lib/public/modules/sidebar-projects.js +60 -57
  50. package/lib/public/modules/sidebar-sessions.js +75 -69
  51. package/lib/public/modules/sidebar.js +12 -20
  52. package/lib/public/modules/skills.js +8 -9
  53. package/lib/public/modules/sticky-notes.js +1 -2
  54. package/lib/public/modules/store.js +9 -2
  55. package/lib/public/modules/stt.js +4 -1
  56. package/lib/public/modules/tools.js +14 -9
  57. package/lib/sdk-bridge.js +511 -1113
  58. package/lib/sdk-message-processor.js +123 -134
  59. package/lib/sdk-worker.js +4 -0
  60. package/lib/server-dm.js +1 -0
  61. package/lib/server.js +86 -1
  62. package/lib/sessions.js +47 -36
  63. package/lib/ws-schema.js +2 -0
  64. package/lib/yoke/adapters/claude-worker.js +559 -0
  65. package/lib/yoke/adapters/claude.js +1418 -0
  66. package/lib/yoke/adapters/codex.js +968 -0
  67. package/lib/yoke/adapters/gemini.js +668 -0
  68. package/lib/yoke/codex-app-server.js +307 -0
  69. package/lib/yoke/index.js +199 -0
  70. package/lib/yoke/instructions.js +62 -0
  71. package/lib/yoke/interface.js +92 -0
  72. package/lib/yoke/mcp-bridge-server.js +294 -0
  73. package/lib/yoke/package.json +7 -0
  74. package/package.json +3 -1
@@ -1,7 +1,16 @@
1
1
  // app-home-hub.js - Home hub rendering, weather, tips
2
2
  // Extracted from app.js (PR-25)
3
3
 
4
- var _ctx = null;
4
+ import { store } from './store.js';
5
+ import { getWs } from './ws-ref.js';
6
+ import { escapeHtml } from './utils.js';
7
+ import { switchProject, getCachedProjects, renderProjectList } from './app-projects.js';
8
+ import { openSchedulerToTab } from './scheduler.js';
9
+ import { getPlaybooks, openPlaybook, getPlaybookForTip } from './playbook.js';
10
+ import { mateAvatarUrl } from './avatar.js';
11
+ import { openDm, exitDmMode } from './app-dm.js';
12
+
13
+ function $hub(id) { return document.getElementById(id); }
5
14
 
6
15
  var homeHub = null;
7
16
  var homeHubVisible = false;
@@ -75,24 +84,23 @@ var weatherSlotPlayed = false;
75
84
 
76
85
  var hubCloseBtn = null;
77
86
 
78
- export function initHomeHub(ctx) {
79
- _ctx = ctx;
87
+ export function initHomeHub() {
80
88
  homeHub = document.getElementById("home-hub");
81
89
  hubCloseBtn = document.getElementById("home-hub-close");
82
90
 
83
91
  if (hubCloseBtn) {
84
92
  hubCloseBtn.addEventListener("click", function () {
85
93
  hideHomeHub();
86
- if (_ctx.currentSlug) {
94
+ if (store.get('currentSlug')) {
87
95
  if (document.documentElement.classList.contains("pwa-standalone")) {
88
- history.replaceState(null, "", "/p/" + _ctx.currentSlug + "/");
96
+ history.replaceState(null, "", "/p/" + store.get('currentSlug') + "/");
89
97
  } else {
90
- history.pushState(null, "", "/p/" + _ctx.currentSlug + "/");
98
+ history.pushState(null, "", "/p/" + store.get('currentSlug') + "/");
91
99
  }
92
100
  // Restore icon strip active state
93
101
  var homeIcon = document.querySelector(".icon-strip-home");
94
102
  if (homeIcon) homeIcon.classList.remove("active");
95
- _ctx.renderProjectList();
103
+ renderProjectList();
96
104
  }
97
105
  });
98
106
  }
@@ -152,7 +160,7 @@ function fetchWeather() {
152
160
  }
153
161
 
154
162
  function updateGreetingWeather() {
155
- var greetEl = _ctx.$("hub-greeting-text");
163
+ var greetEl = $hub("hub-greeting-text");
156
164
  if (!greetEl) return;
157
165
  // If we have real weather and haven't played the slot yet, do the reel
158
166
  if (weatherEmoji && !weatherSlotPlayed && homeHubVisible) {
@@ -254,12 +262,12 @@ export function renderHomeHub(projects) {
254
262
  updateGreetingWeather();
255
263
 
256
264
  // Date
257
- var dateEl = _ctx.$("hub-greeting-date");
265
+ var dateEl = $hub("hub-greeting-date");
258
266
  if (dateEl) dateEl.textContent = getFormattedDate();
259
267
 
260
268
  // --- Upcoming tasks ---
261
- var upcomingList = _ctx.$("hub-upcoming-list");
262
- var upcomingCount = _ctx.$("hub-upcoming-count");
269
+ var upcomingList = $hub("hub-upcoming-list");
270
+ var upcomingCount = $hub("hub-upcoming-count");
263
271
  if (upcomingList) {
264
272
  var now = Date.now();
265
273
  var upcoming = hubSchedules.filter(function (s) {
@@ -290,7 +298,7 @@ export function renderHomeHub(projects) {
290
298
  if (ctaBtn) {
291
299
  ctaBtn.addEventListener("click", function () {
292
300
  hideHomeHub();
293
- _ctx.openSchedulerToTab("calendar");
301
+ openSchedulerToTab("calendar");
294
302
  });
295
303
  }
296
304
  } else {
@@ -303,13 +311,13 @@ export function renderHomeHub(projects) {
303
311
  var dotColor = sched.color || "";
304
312
  item.innerHTML = '<span class="hub-upcoming-dot"' + (dotColor ? ' style="background:' + dotColor + '"' : '') + '></span>' +
305
313
  '<span class="hub-upcoming-time">' + formatScheduleTime(sched.nextRunAt) + '</span>' +
306
- '<span class="hub-upcoming-name">' + _ctx.escapeHtml(sched.name || "Untitled") + '</span>' +
307
- '<span class="hub-upcoming-project">' + _ctx.escapeHtml(sched.projectTitle || "") + '</span>';
314
+ '<span class="hub-upcoming-name">' + escapeHtml(sched.name || "Untitled") + '</span>' +
315
+ '<span class="hub-upcoming-project">' + escapeHtml(sched.projectTitle || "") + '</span>';
308
316
  item.addEventListener("click", function () {
309
317
  if (sched.projectSlug) {
310
- _ctx.switchProject(sched.projectSlug);
318
+ switchProject(sched.projectSlug);
311
319
  setTimeout(function () {
312
- _ctx.openSchedulerToTab("library");
320
+ openSchedulerToTab("library");
313
321
  }, 300);
314
322
  }
315
323
  });
@@ -326,7 +334,7 @@ export function renderHomeHub(projects) {
326
334
  }
327
335
 
328
336
  // --- Projects summary (exclude mate projects) ---
329
- var projectsList = _ctx.$("hub-projects-list");
337
+ var projectsList = $hub("hub-projects-list");
330
338
  if (projectsList && projects) {
331
339
  projectsList.innerHTML = "";
332
340
  var hubProjects = projects.filter(function (p) { return !p.isMate; });
@@ -339,10 +347,10 @@ export function renderHomeHub(projects) {
339
347
  var sessionsLabel = typeof proj.sessions === "number" ? proj.sessions : "";
340
348
  item.innerHTML = '<span class="' + dotClass + '"></span>' +
341
349
  iconHtml +
342
- '<span class="hub-project-name">' + _ctx.escapeHtml(proj.title || proj.project || proj.slug) + '</span>' +
350
+ '<span class="hub-project-name">' + escapeHtml(proj.title || proj.project || proj.slug) + '</span>' +
343
351
  (sessionsLabel !== "" ? '<span class="hub-project-sessions">' + sessionsLabel + '</span>' : '');
344
352
  item.addEventListener("click", function () {
345
- _ctx.switchProject(proj.slug);
353
+ switchProject(proj.slug);
346
354
  });
347
355
  projectsList.appendChild(item);
348
356
  })(hubProjects[p]);
@@ -352,7 +360,7 @@ export function renderHomeHub(projects) {
352
360
  }
353
361
 
354
362
  // --- Week strip ---
355
- var weekStrip = _ctx.$("hub-week-strip");
363
+ var weekStrip = $hub("hub-week-strip");
356
364
  if (weekStrip) {
357
365
  weekStrip.innerHTML = "";
358
366
  var today = new Date();
@@ -405,10 +413,10 @@ export function renderHomeHub(projects) {
405
413
  }
406
414
 
407
415
  // --- Playbooks ---
408
- var pbGrid = _ctx.$("hub-playbooks-grid");
409
- var pbSection = _ctx.$("hub-playbooks");
416
+ var pbGrid = $hub("hub-playbooks-grid");
417
+ var pbSection = $hub("hub-playbooks");
410
418
  if (pbGrid) {
411
- var pbs = _ctx.getPlaybooks();
419
+ var pbs = getPlaybooks();
412
420
  if (pbs.length === 0) {
413
421
  if (pbSection) pbSection.style.display = "none";
414
422
  } else {
@@ -420,14 +428,14 @@ export function renderHomeHub(projects) {
420
428
  card.className = "hub-playbook-card" + (pb.completed ? " completed" : "");
421
429
  card.innerHTML = '<span class="hub-playbook-card-icon">' + pb.icon + '</span>' +
422
430
  '<div class="hub-playbook-card-body">' +
423
- '<div class="hub-playbook-card-title">' + _ctx.escapeHtml(pb.title) + '</div>' +
424
- '<div class="hub-playbook-card-desc">' + _ctx.escapeHtml(pb.description) + '</div>' +
431
+ '<div class="hub-playbook-card-title">' + escapeHtml(pb.title) + '</div>' +
432
+ '<div class="hub-playbook-card-desc">' + escapeHtml(pb.description) + '</div>' +
425
433
  '</div>' +
426
434
  (pb.completed ? '<span class="hub-playbook-card-check">✓</span>' : '');
427
435
  card.addEventListener("click", function () {
428
- _ctx.openPlaybook(pb.id, function () {
436
+ openPlaybook(pb.id, function () {
429
437
  // Re-render hub after playbook closes to update completion state
430
- renderHomeHub(_ctx.cachedProjects);
438
+ renderHomeHub(getCachedProjects());
431
439
  });
432
440
  });
433
441
  pbGrid.appendChild(card);
@@ -440,41 +448,41 @@ export function renderHomeHub(projects) {
440
448
 
441
449
  // --- Tip ---
442
450
  var currentTip = hubTips[hubTipIndex % hubTips.length];
443
- var tipEl = _ctx.$("hub-tip-text");
451
+ var tipEl = $hub("hub-tip-text");
444
452
  if (tipEl) tipEl.textContent = currentTip;
445
453
 
446
454
  // "Try it" button if tip has a linked playbook
447
455
  var existingTry = homeHub.querySelector(".hub-tip-try");
448
456
  if (existingTry) existingTry.remove();
449
- var linkedPb = _ctx.getPlaybookForTip(currentTip);
457
+ var linkedPb = getPlaybookForTip(currentTip);
450
458
  if (linkedPb && tipEl) {
451
459
  var tryBtn = document.createElement("button");
452
460
  tryBtn.className = "hub-tip-try";
453
461
  tryBtn.textContent = "Try it →";
454
462
  tryBtn.addEventListener("click", function () {
455
- _ctx.openPlaybook(linkedPb, function () {
456
- renderHomeHub(_ctx.cachedProjects);
463
+ openPlaybook(linkedPb, function () {
464
+ renderHomeHub(getCachedProjects());
457
465
  });
458
466
  });
459
467
  tipEl.appendChild(tryBtn);
460
468
  }
461
469
 
462
470
  // Tip prev/next buttons
463
- var prevBtn = _ctx.$("hub-tip-prev");
471
+ var prevBtn = $hub("hub-tip-prev");
464
472
  if (prevBtn && !prevBtn._hubWired) {
465
473
  prevBtn._hubWired = true;
466
474
  prevBtn.addEventListener("click", function () {
467
475
  hubTipIndex = (hubTipIndex - 1 + hubTips.length) % hubTips.length;
468
- renderHomeHub(_ctx.cachedProjects);
476
+ renderHomeHub(getCachedProjects());
469
477
  startTipRotation();
470
478
  });
471
479
  }
472
- var nextBtn = _ctx.$("hub-tip-next");
480
+ var nextBtn = $hub("hub-tip-next");
473
481
  if (nextBtn && !nextBtn._hubWired) {
474
482
  nextBtn._hubWired = true;
475
483
  nextBtn.addEventListener("click", function () {
476
484
  hubTipIndex = (hubTipIndex + 1) % hubTips.length;
477
- renderHomeHub(_ctx.cachedProjects);
485
+ renderHomeHub(getCachedProjects());
478
486
  startTipRotation();
479
487
  });
480
488
  }
@@ -486,7 +494,7 @@ export function renderHomeHub(projects) {
486
494
  export function handleHubSchedules(msg) {
487
495
  if (msg.schedules) {
488
496
  hubSchedules = msg.schedules;
489
- if (homeHubVisible) renderHomeHub(_ctx.cachedProjects);
497
+ if (homeHubVisible) renderHomeHub(getCachedProjects());
490
498
  }
491
499
  }
492
500
 
@@ -494,7 +502,7 @@ function startTipRotation() {
494
502
  stopTipRotation();
495
503
  hubTipTimer = setInterval(function () {
496
504
  hubTipIndex = (hubTipIndex + 1) % hubTips.length;
497
- renderHomeHub(_ctx.cachedProjects);
505
+ renderHomeHub(getCachedProjects());
498
506
  }, 15000);
499
507
  }
500
508
 
@@ -509,12 +517,12 @@ function renderHomeHubMates() {
509
517
  var container = document.getElementById("home-hub-mates");
510
518
  if (!container) return;
511
519
  container.innerHTML = "";
512
- if (!_ctx.cachedMatesList || _ctx.cachedMatesList.length === 0) {
520
+ if (!store.get('cachedMatesList') || store.get('cachedMatesList').length === 0) {
513
521
  container.classList.add("hidden");
514
522
  return;
515
523
  }
516
524
  container.classList.remove("hidden");
517
- for (var i = 0; i < _ctx.cachedMatesList.length; i++) {
525
+ for (var i = 0; i < store.get('cachedMatesList').length; i++) {
518
526
  (function (mate) {
519
527
  var item = document.createElement("div");
520
528
  item.className = "home-hub-mate-item" + (mate.primary ? " home-hub-mate-primary" : "");
@@ -523,7 +531,7 @@ function renderHomeHubMates() {
523
531
  avatarWrap.className = "home-hub-mate-avatar-wrap";
524
532
 
525
533
  var mp = mate.profile || {};
526
- var mateAvUrl = _ctx.mateAvatarUrl(mate, 48);
534
+ var mateAvUrl = mateAvatarUrl(mate, 48);
527
535
  var avatar = document.createElement("img");
528
536
  avatar.className = "home-hub-mate-avatar";
529
537
  avatar.src = mateAvUrl;
@@ -549,30 +557,30 @@ function renderHomeHubMates() {
549
557
  item.appendChild(nameEl);
550
558
 
551
559
  item.addEventListener("click", function () {
552
- _ctx.openDm(mate.id);
560
+ openDm(mate.id);
553
561
  });
554
562
 
555
563
  container.appendChild(item);
556
- })(_ctx.cachedMatesList[i]);
564
+ })(store.get('cachedMatesList')[i]);
557
565
  }
558
566
  }
559
567
 
560
568
  export function showHomeHub() {
561
- if (_ctx.dmMode) _ctx.exitDmMode();
569
+ if (store.get('dmMode')) exitDmMode();
562
570
  homeHubVisible = true;
563
571
  homeHub.classList.remove("hidden");
564
572
  // Show close button only if there's a project to return to
565
573
  if (hubCloseBtn) {
566
- if (_ctx.currentSlug) hubCloseBtn.classList.remove("hidden");
574
+ if (store.get('currentSlug')) hubCloseBtn.classList.remove("hidden");
567
575
  else hubCloseBtn.classList.add("hidden");
568
576
  }
569
577
  // Fetch weather silently (once)
570
578
  fetchWeather();
571
579
  // Request cross-project schedules
572
- if (_ctx.ws && _ctx.ws.readyState === 1) {
573
- _ctx.ws.send(JSON.stringify({ type: "hub_schedules_list" }));
580
+ if (getWs() && getWs().readyState === 1) {
581
+ getWs().send(JSON.stringify({ type: "hub_schedules_list" }));
574
582
  }
575
- renderHomeHub(_ctx.cachedProjects);
583
+ renderHomeHub(getCachedProjects());
576
584
  renderHomeHubMates();
577
585
  startTipRotation();
578
586
  if (document.documentElement.classList.contains("pwa-standalone")) {
@@ -19,6 +19,22 @@ var pendingIterations = 20;
19
19
  // ========================================================
20
20
  export function initLoopUi() {
21
21
 
22
+ // --- Reactive UI sync for loop state ---
23
+ store.subscribe(function (state, prev) {
24
+ if (state.loopActive !== prev.loopActive ||
25
+ state.ralphPhase !== prev.ralphPhase ||
26
+ state.loopIteration !== prev.loopIteration ||
27
+ state.loopMaxIterations !== prev.loopMaxIterations) {
28
+ updateLoopButton();
29
+ }
30
+ if (state.ralphPhase !== prev.ralphPhase ||
31
+ state.ralphCraftingSessionId !== prev.ralphCraftingSessionId ||
32
+ state.ralphCraftingSource !== prev.ralphCraftingSource ||
33
+ state.activeSessionId !== prev.activeSessionId) {
34
+ updateRalphBars();
35
+ }
36
+ });
37
+
22
38
  // --- Preview modal listeners ---
23
39
  // Backdrop click intentionally does NOT close the modal (no way to reopen it)
24
40
 
@@ -75,7 +91,7 @@ export function initLoopUi() {
75
91
  // ========================================================
76
92
 
77
93
  function syncIterationsUi() {
78
- var wizData = store.getState().wizardData || {};
94
+ var wizData = store.get('wizardData') || {};
79
95
  var isSimple = wizData.loopMode === "simple";
80
96
  var label = isSimple ? ("Run x" + pendingIterations) : ("Start (max " + pendingIterations + ")");
81
97
 
@@ -101,7 +117,7 @@ function syncIterationsUi() {
101
117
  // ========================================================
102
118
 
103
119
  function startLoopFromUi() {
104
- var basePath = store.getState().basePath;
120
+ var basePath = store.get('basePath');
105
121
  var stickyEl = document.getElementById("ralph-sticky");
106
122
 
107
123
  fetch(basePath + "api/git-dirty")
@@ -155,7 +171,7 @@ export function updateLoopButton() {
155
171
  var section = document.getElementById("ralph-loop-section");
156
172
  if (!section) return;
157
173
 
158
- var s = store.getState();
174
+ var s = store.snap();
159
175
  var busy = s.loopActive || s.ralphPhase === "executing";
160
176
  var phase = busy ? "executing" : s.ralphPhase;
161
177
 
@@ -233,7 +249,7 @@ export function showLoopBanner(show) {
233
249
  return;
234
250
  }
235
251
 
236
- var bannerLabel = store.getState().loopBannerName || "Loop";
252
+ var bannerLabel = store.get('loopBannerName') || "Loop";
237
253
  stickyEl.innerHTML =
238
254
  '<div class="ralph-sticky-inner">' +
239
255
  '<div class="ralph-sticky-header">' +
@@ -275,7 +291,7 @@ export function updateLoopBanner(iteration, maxIterations, phase) {
275
291
 
276
292
  export function updateRalphBars() {
277
293
  // Task source uses the scheduler panel, not the sticky bar
278
- var s = store.getState();
294
+ var s = store.snap();
279
295
  var isTaskSource = s.ralphCraftingSource !== "ralph";
280
296
  var onCraftingSession = s.ralphCraftingSessionId && s.activeSessionId === s.ralphCraftingSessionId;
281
297
  // If approval phase but no craftingSessionId (recovered after server restart), show bar anyway
@@ -299,7 +315,7 @@ export function updateRalphBars() {
299
315
  }
300
316
 
301
317
  // Restore debate sticky on session switch
302
- var debateStickyState = store.getState().debateStickyState;
318
+ var debateStickyState = store.get('debateStickyState');
303
319
  if (debateStickyState && debateStickyState.phase) {
304
320
  showDebateSticky(debateStickyState.phase, debateStickyState.msg);
305
321
  } else {
@@ -318,10 +334,10 @@ function toggleLoopPopover() {
318
334
  return;
319
335
  }
320
336
 
321
- var wizData = store.getState().wizardData || {};
337
+ var wizData = store.get('wizardData') || {};
322
338
  var taskPreview = wizData.task || "\u2014";
323
339
  if (taskPreview.length > 120) taskPreview = taskPreview.substring(0, 120) + "\u2026";
324
- var _s = store.getState();
340
+ var _s = store.snap();
325
341
  var statusText = "Iteration #" + _s.loopIteration + " / " + _s.loopMaxIterations;
326
342
 
327
343
  var modal = document.createElement("div");
@@ -361,7 +377,7 @@ function toggleLoopPopover() {
361
377
  modal.querySelector(".loop-status-dialog-stop").addEventListener("click", function(e) {
362
378
  e.stopPropagation();
363
379
  closeModal();
364
- showConfirm("Stop the running " + (store.getState().loopBannerName || "loop") + "?", function() {
380
+ showConfirm("Stop the running " + (store.get('loopBannerName') || "loop") + "?", function() {
365
381
  var w = getWs();
366
382
  if (w && w.readyState === 1) {
367
383
  w.send(JSON.stringify({ type: "loop_stop" }));
@@ -413,14 +429,14 @@ export function showRalphApprovalBar(show) {
413
429
  if (!stickyEl) return;
414
430
  if (!show) {
415
431
  // Only clear if we're in approval mode (don't clobber crafting)
416
- if (store.getState().ralphPhase !== "crafting") {
432
+ if (store.get('ralphPhase') !== "crafting") {
417
433
  stickyEl.classList.add("hidden");
418
434
  stickyEl.innerHTML = "";
419
435
  }
420
436
  return;
421
437
  }
422
438
 
423
- var wizData = store.getState().wizardData || {};
439
+ var wizData = store.get('wizardData') || {};
424
440
  var isSimple = wizData.loopMode === "simple";
425
441
  var defaultIter = isSimple ? 5 : 20;
426
442
  pendingIterations = defaultIter;
@@ -486,9 +502,9 @@ export function updateRalphApprovalStatus() {
486
502
  var startBtn = document.querySelector(".ralph-sticky-start");
487
503
  if (!statusEl) return;
488
504
 
489
- var wizData = store.getState().wizardData || {};
505
+ var wizData = store.get('wizardData') || {};
490
506
  var isSimple = wizData.loopMode === "simple";
491
- var _rf = store.getState().ralphFilesReady;
507
+ var _rf = store.get('ralphFilesReady');
492
508
  var ready = isSimple ? _rf.promptReady : _rf.bothReady;
493
509
 
494
510
  if (ready) {
@@ -513,7 +529,7 @@ export function updateRalphApprovalStatus() {
513
529
  // ========================================================
514
530
 
515
531
  export function showExecModal() {
516
- store.setState({ execModalShown: true });
532
+ store.set({ execModalShown: true });
517
533
  // Open the preview modal immediately, then request file content to fill in
518
534
  openRalphPreviewModal();
519
535
  var ws = getWs();
@@ -532,7 +548,7 @@ export function updateExecModalStatus() {
532
548
 
533
549
  export function openRalphPreviewModal() {
534
550
  // Only show for loop (ralph) source, not scheduled tasks
535
- var st = store.getState();
551
+ var st = store.snap();
536
552
  if (st.ralphCraftingSource !== "ralph") return;
537
553
 
538
554
  var modal = document.getElementById("ralph-preview-modal");
@@ -564,7 +580,7 @@ export function openRalphPreviewModal() {
564
580
  if (comboLabel) comboLabel.textContent = isSimple ? "Run x" : "Start max";
565
581
 
566
582
  var runBtn = document.getElementById("ralph-preview-run");
567
- if (runBtn) runBtn.disabled = !store.getState().ralphFilesReady.bothReady;
583
+ if (runBtn) runBtn.disabled = !store.get('ralphFilesReady').bothReady;
568
584
 
569
585
  _previewLoopSettings = {};
570
586
  showRalphPreviewTab("prompt");
@@ -600,7 +616,7 @@ function showRalphPreviewTab(tab) {
600
616
  return;
601
617
  }
602
618
 
603
- var _rpc = store.getState().ralphPreviewContent;
619
+ var _rpc = store.get('ralphPreviewContent');
604
620
  var content = tab === "prompt" ? _rpc.prompt : _rpc.judge;
605
621
  if (typeof marked !== "undefined" && marked.parse) {
606
622
  body.innerHTML = '<div class="md-content">' + DOMPurify.sanitize(marked.parse(content)) + '</div>';
@@ -610,7 +626,7 @@ function showRalphPreviewTab(tab) {
610
626
  }
611
627
 
612
628
  function renderPreviewModelTab(bodyEl) {
613
- var s = store.getState();
629
+ var s = store.snap();
614
630
 
615
631
  bodyEl.innerHTML =
616
632
  '<div class="scheduler-model-settings">' +
@@ -131,7 +131,7 @@ function requireClayRalph(cb) {
131
131
  export function openRalphWizard(source) {
132
132
  requireClayRalph(function () {
133
133
  wizardSource = source || "ralph";
134
- store.setState({ wizardData: { name: "", task: "", maxIterations: null } });
134
+ store.set({ wizardData: { name: "", task: "", maxIterations: null } });
135
135
  loopModeChoice = "judge";
136
136
  promptAuthor = "clay";
137
137
  judgeAuthor = "clay";
@@ -186,7 +186,7 @@ export function openRalphWizard(source) {
186
186
  if (statusEl) { statusEl.classList.add("hidden"); statusEl.innerHTML = ""; }
187
187
 
188
188
  // Reset exec modal flag
189
- store.setState({ execModalShown: false });
189
+ store.set({ execModalShown: false });
190
190
 
191
191
  updateModePreview();
192
192
  updateWizardStep();
@@ -300,7 +300,7 @@ function collectWizardData() {
300
300
  wd.judgeText = null;
301
301
  }
302
302
 
303
- store.setState({ wizardData: wd });
303
+ store.set({ wizardData: wd });
304
304
  }
305
305
 
306
306
  function buildWizardCron() {
@@ -357,7 +357,7 @@ function cronToHumanText(cron) {
357
357
  var LAST_STEP = 3;
358
358
 
359
359
  function validateLastStep() {
360
- var wd = store.getState().wizardData;
360
+ var wd = store.get('wizardData');
361
361
  if (promptAuthor === "clay") {
362
362
  var taskEl = document.getElementById("ralph-task");
363
363
  if (!wd.task) {
@@ -412,9 +412,9 @@ function wizardSkip() {
412
412
 
413
413
  function wizardSubmit() {
414
414
  collectWizardData();
415
- var wd = Object.assign({}, store.getState().wizardData);
415
+ var wd = Object.assign({}, store.get('wizardData'));
416
416
  wd.source = wizardSource === "task" ? "task" : undefined;
417
- store.setState({ wizardData: wd });
417
+ store.set({ wizardData: wd });
418
418
  closeRalphWizard();
419
419
  var ws = getWs();
420
420
  if (ws && ws.readyState === 1) {