clay-server 2.13.0-beta.4 → 2.13.0-beta.5

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 CHANGED
@@ -626,13 +626,12 @@ function createProjectContext(opts) {
626
626
  console.log("[loop-registry] Schedule triggered: " + record.name + " → linked task " + loopId);
627
627
  }
628
628
 
629
- // Verify the loop directory and files exist
629
+ // Verify the loop directory and PROMPT.md exist
630
630
  var recDir = path.join(cwd, ".claude", "loops", loopId);
631
631
  try {
632
632
  fs.accessSync(path.join(recDir, "PROMPT.md"));
633
- fs.accessSync(path.join(recDir, "JUDGE.md"));
634
633
  } catch (e) {
635
- console.error("[loop-registry] Loop files missing for " + loopId);
634
+ console.error("[loop-registry] PROMPT.md missing for " + loopId);
636
635
  return;
637
636
  }
638
637
  // Set the loopId and start
@@ -675,8 +674,7 @@ function createProjectContext(opts) {
675
674
  try {
676
675
  judgeText = fs.readFileSync(judgePath, "utf8");
677
676
  } catch (e) {
678
- send({ type: "loop_error", text: "Missing JUDGE.md in " + dir });
679
- return;
677
+ judgeText = null;
680
678
  }
681
679
 
682
680
  var baseCommit;
@@ -700,7 +698,7 @@ function createProjectContext(opts) {
700
698
  loopState.promptText = promptText;
701
699
  loopState.judgeText = judgeText;
702
700
  loopState.iteration = 0;
703
- loopState.maxIterations = loopConfig.maxIterations || loopOpts.maxIterations || 20;
701
+ loopState.maxIterations = judgeText ? (loopConfig.maxIterations || loopOpts.maxIterations || 20) : 1;
704
702
  loopState.baseCommit = baseCommit;
705
703
  loopState.currentSessionId = null;
706
704
  loopState.judgeSessionId = null;
@@ -778,7 +776,11 @@ function createProjectContext(opts) {
778
776
  setTimeout(function() { runNextIteration(); }, 2000);
779
777
  return;
780
778
  }
781
- runJudge();
779
+ if (loopState.judgeText) {
780
+ runJudge();
781
+ } else {
782
+ finishLoop("pass");
783
+ }
782
784
  };
783
785
 
784
786
  // Watchdog: if onQueryComplete hasn't fired after 10 minutes, force error and retry
@@ -2975,6 +2977,11 @@ function createProjectContext(opts) {
2975
2977
  var tmpJudge = judgePath + ".tmp";
2976
2978
  fs.writeFileSync(tmpJudge, wData.judgeText);
2977
2979
  fs.renameSync(tmpJudge, judgePath);
2980
+ } else {
2981
+ // No judge: force single iteration
2982
+ var singleJson = loopJsonPath + ".tmp2";
2983
+ fs.writeFileSync(singleJson, JSON.stringify({ maxIterations: 1 }, null, 2));
2984
+ fs.renameSync(singleJson, loopJsonPath);
2978
2985
  }
2979
2986
 
2980
2987
  // Go straight to approval (no crafting needed)
@@ -3190,9 +3197,8 @@ function createProjectContext(opts) {
3190
3197
  var rerunDir = path.join(cwd, ".claude", "loops", rerunRec.id);
3191
3198
  try {
3192
3199
  fs.accessSync(path.join(rerunDir, "PROMPT.md"));
3193
- fs.accessSync(path.join(rerunDir, "JUDGE.md"));
3194
3200
  } catch (e) {
3195
- sendTo(ws, { type: "loop_registry_error", text: "Loop files missing for " + rerunRec.id });
3201
+ sendTo(ws, { type: "loop_registry_error", text: "PROMPT.md missing for " + rerunRec.id });
3196
3202
  return;
3197
3203
  }
3198
3204
  loopState.loopId = rerunRec.id;
package/lib/public/app.js CHANGED
@@ -859,6 +859,10 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
859
859
  mateWs = null;
860
860
  }
861
861
  mateProjectSlug = null;
862
+ // If main WS was disconnected while in mate DM, reconnect now
863
+ if (ws && ws.readyState !== 1) {
864
+ connect();
865
+ }
862
866
  }
863
867
 
864
868
  function appendDmMessage(msg) {
@@ -3122,9 +3126,9 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3122
3126
  ws = new WebSocket(protocol + "//" + location.host + wsPath);
3123
3127
 
3124
3128
 
3125
- // If not connected within 3s, force retry
3129
+ // If not connected within 3s, force retry (skip if stashed during mate DM)
3126
3130
  connectTimeoutId = setTimeout(function () {
3127
- if (!connected) {
3131
+ if (!connected && !savedMainWs) {
3128
3132
  ws.onclose = null;
3129
3133
  ws.onerror = null;
3130
3134
  ws.close();
@@ -3183,6 +3187,9 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3183
3187
  };
3184
3188
 
3185
3189
  ws.onclose = function (e) {
3190
+ // If this WS is stashed while in mate DM, ignore close events
3191
+ if (savedMainWs === this) return;
3192
+
3186
3193
  if (connectTimeoutId) { clearTimeout(connectTimeoutId); connectTimeoutId = null; }
3187
3194
  setStatus("disconnected");
3188
3195
  processing = false;
@@ -3208,9 +3215,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3208
3215
  };
3209
3216
 
3210
3217
  ws.onerror = function () {
3218
+ // If this WS is stashed while in mate DM, ignore error events
3219
+ if (savedMainWs === this) return;
3211
3220
  };
3212
3221
 
3213
3222
  ws.onmessage = function (event) {
3223
+ // If this WS is stashed while in mate DM, ignore its messages
3224
+ if (savedMainWs === this) return;
3225
+
3214
3226
  // Backup: if we're receiving messages, we're connected
3215
3227
  if (!connected) {
3216
3228
  setStatus("connected");
@@ -4372,6 +4384,8 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
4372
4384
 
4373
4385
  function scheduleReconnect() {
4374
4386
  if (reconnectTimer) return;
4387
+ // Don't reconnect main WS while in mate DM
4388
+ if (savedMainWs) return;
4375
4389
  reconnectTimer = setTimeout(function () {
4376
4390
  reconnectTimer = null;
4377
4391
  // Check if auth is still valid before reconnecting
@@ -242,9 +242,6 @@ export function renderAskUserQuestion(toolId, input) {
242
242
  answers[qIdx] = opt.label;
243
243
  var otherInput = qDiv.querySelector(".ask-user-other input");
244
244
  if (otherInput) otherInput.value = "";
245
- if (questions.length === 1) {
246
- submitAskUserAnswer(container, toolId, questions, answers, multiSelections);
247
- }
248
245
  }
249
246
  });
250
247
 
@@ -280,17 +277,14 @@ export function renderAskUserQuestion(toolId, input) {
280
277
  container.appendChild(qDiv);
281
278
  });
282
279
 
283
- // Submit button: show for multi-question or any multi-select question
284
- var hasMultiSelect = questions.some(function (q) { return q.multiSelect; });
285
- if (questions.length > 1 || hasMultiSelect) {
286
- var submitBtn = document.createElement("button");
287
- submitBtn.className = "ask-user-submit";
288
- submitBtn.textContent = "Submit";
289
- submitBtn.addEventListener("click", function () {
290
- submitAskUserAnswer(container, toolId, questions, answers, multiSelections);
291
- });
292
- container.appendChild(submitBtn);
293
- }
280
+ // Submit button: always show
281
+ var submitBtn = document.createElement("button");
282
+ submitBtn.className = "ask-user-submit";
283
+ submitBtn.textContent = "Submit";
284
+ submitBtn.addEventListener("click", function () {
285
+ submitAskUserAnswer(container, toolId, questions, answers, multiSelections);
286
+ });
287
+ container.appendChild(submitBtn);
294
288
 
295
289
  // Skip button
296
290
  var skipBtn = document.createElement("button");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.13.0-beta.4",
3
+ "version": "2.13.0-beta.5",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",