clay-server 4.7.0-beta.3 → 4.7.0-beta.4
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.
|
@@ -387,6 +387,7 @@ function attachPairResultOutbox(options) {
|
|
|
387
387
|
markRestartUncertain: markRestartUncertain,
|
|
388
388
|
authorizeHumanTurn: authorizeHumanTurn,
|
|
389
389
|
grantManualRetry: grantManualRetry,
|
|
390
|
+
dismissNotice: function (key, revision) { return transition(key, { dismissedNoticeRevision: revision }); },
|
|
390
391
|
status: status,
|
|
391
392
|
list: function () { return Object.keys(records).map(function (key) { return copy(records[key]); }); },
|
|
392
393
|
get: function (key) { return records[key] ? copy(records[key]) : null; },
|
|
@@ -146,6 +146,11 @@ function attachPairResultRecovery(ctx) {
|
|
|
146
146
|
confirmDuplicate: completed && state === "uncertain",
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
|
+
function noticeItem(record) {
|
|
150
|
+
var item = publicItem(record);
|
|
151
|
+
item.revision = opaqueId(JSON.stringify(item));
|
|
152
|
+
return item;
|
|
153
|
+
}
|
|
149
154
|
function canRead(ws, session) {
|
|
150
155
|
if (!ws || !session || ws._clayActiveSession !== session.localId) return false;
|
|
151
156
|
if (ownerId(session)) return !!(ws._clayUser && String(ws._clayUser.id) === String(ownerId(session)));
|
|
@@ -153,7 +158,9 @@ function attachPairResultRecovery(ctx) {
|
|
|
153
158
|
}
|
|
154
159
|
function sendState(session, ws, sendFn) {
|
|
155
160
|
if (!canRead(ws, session)) return false;
|
|
156
|
-
var items = recordsFor(session).
|
|
161
|
+
var items = recordsFor(session).filter(function (record) {
|
|
162
|
+
return record.dismissedNoticeRevision !== noticeItem(record).revision;
|
|
163
|
+
}).map(noticeItem);
|
|
157
164
|
(sendFn || ctx.sendTo.bind(null, ws))({ type: "pair_result_status", sessionId: session.localId, items: items });
|
|
158
165
|
return true;
|
|
159
166
|
}
|
|
@@ -204,7 +211,7 @@ function attachPairResultRecovery(ctx) {
|
|
|
204
211
|
changed(session);
|
|
205
212
|
}
|
|
206
213
|
function handleMessage(ws, msg) {
|
|
207
|
-
if (!msg || (msg.type !== "pair_result_state_request" && msg.type !== "pair_result_retry")) return false;
|
|
214
|
+
if (!msg || (msg.type !== "pair_result_state_request" && msg.type !== "pair_result_retry" && msg.type !== "pair_result_dismiss")) return false;
|
|
208
215
|
var session = ctx.sm.sessions.get(ws._clayActiveSession);
|
|
209
216
|
if (!canRead(ws, session)) return true;
|
|
210
217
|
if (msg.sessionId != null && msg.sessionId !== session.localId) return true;
|
|
@@ -213,6 +220,12 @@ function attachPairResultRecovery(ctx) {
|
|
|
213
220
|
var records = recordsFor(session), record = null;
|
|
214
221
|
for (var i = 0; i < records.length; i++) if (opaqueId(records[i].key) === msg.id) record = records[i];
|
|
215
222
|
if (!record) { sendState(session, ws); return true; }
|
|
223
|
+
if (msg.type === "pair_result_dismiss") {
|
|
224
|
+
if (msg.revision === noticeItem(record).revision) ctx.outbox.dismissNotice(record.key, msg.revision);
|
|
225
|
+
changed(session);
|
|
226
|
+
sendState(session, ws);
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
216
229
|
if (record.deliveryState === "uncertain" && msg.confirmDuplicate !== true) { sendState(session, ws); return true; }
|
|
217
230
|
var granted = ctx.outbox.grantManualRetry(record.key);
|
|
218
231
|
if (granted.ok) schedule(record.key);
|
|
@@ -1387,17 +1387,24 @@ pre.mermaid-error {
|
|
|
1387
1387
|
.plan-banner.plan-exit { color: var(--success); }
|
|
1388
1388
|
.plan-banner.plan-exit .plan-banner-icon { color: var(--success); }
|
|
1389
1389
|
|
|
1390
|
-
|
|
1391
|
-
.pair-result-status
|
|
1390
|
+
/* Recovery notices use the same quiet surface as session work references. */
|
|
1391
|
+
.pair-result-status { flex: 0 0 auto; margin: 8px 16px 0; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt); color: var(--text-muted); font-size: 12px; line-height: 1.5; max-height: 35vh; overflow-y: auto; }
|
|
1392
|
+
.pair-result-status-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--text-secondary); }
|
|
1393
|
+
.pair-result-status button { font: inherit; color: var(--text-secondary); background: transparent; border: 1px solid var(--border); border-radius: 5px; cursor: pointer; }
|
|
1394
|
+
.pair-result-status .pair-result-status-dismiss { display: grid; place-items: center; flex: 0 0 28px; width: 28px; height: 28px; padding: 0; border: 0; font-size: 20px; line-height: 1; }
|
|
1395
|
+
.pair-result-status button:hover { background: var(--input-bg); color: var(--text); }
|
|
1396
|
+
.pair-result-status button:focus-visible, .pair-result-status summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1397
|
+
.pair-result-status-details > summary { cursor: pointer; width: fit-content; }
|
|
1398
|
+
.pair-result-status-card { padding: 10px 0; border-top: 1px solid var(--border); margin-top: 8px; }
|
|
1392
1399
|
.pair-result-status-card > strong, .pair-result-status-card > span { display: block; }
|
|
1393
|
-
.pair-result-status-card > strong { color: var(--text); margin-bottom: 3px; }
|
|
1400
|
+
.pair-result-status-card > strong { color: var(--text-secondary); font-weight: 500; margin-bottom: 3px; }
|
|
1394
1401
|
.pair-result-status-card details { margin-top: 7px; }
|
|
1395
|
-
.pair-result-status-card summary { cursor: pointer;
|
|
1396
|
-
.pair-result-status-card pre { max-height: 180px; overflow: auto; white-space: pre-wrap; font: inherit; }
|
|
1397
|
-
.pair-result-status-
|
|
1398
|
-
.pair-result-status-retry:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1402
|
+
.pair-result-status-card summary { cursor: pointer; }
|
|
1403
|
+
.pair-result-status-card pre { max-height: 180px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; }
|
|
1404
|
+
.pair-result-status-retry { margin-top: 8px; padding: 4px 8px; }
|
|
1399
1405
|
.pair-result-status-retry:disabled { cursor: not-allowed; opacity: 0.55; }
|
|
1400
|
-
.pair-result-status-
|
|
1406
|
+
@media (max-width: 600px) { .pair-result-status { margin: 6px 8px 0; } .pair-result-status .pair-result-status-dismiss { min-width: 36px; height: 36px; } }
|
|
1407
|
+
|
|
1401
1408
|
|
|
1402
1409
|
/* --- Plan card --- */
|
|
1403
1410
|
.plan-card {
|
|
@@ -33,6 +33,16 @@ function retry(item) {
|
|
|
33
33
|
sendRetry(source, false);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function dismiss(items) {
|
|
37
|
+
var ws = getWs();
|
|
38
|
+
if (!ws || ws.readyState !== 1) return;
|
|
39
|
+
items.forEach(function (item) {
|
|
40
|
+
ws.send(JSON.stringify({ type: "pair_result_dismiss", id: item.id, revision: item.revision,
|
|
41
|
+
sessionId: store.get("activeSessionId"),
|
|
42
|
+
projectSlug: store.get("currentSlug") || store.get("activeProjectSlug") || null }));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
function renderPairResultStatus() {
|
|
37
47
|
var existing = document.getElementById("pair-result-status");
|
|
38
48
|
if (existing) existing.remove();
|
|
@@ -44,6 +54,21 @@ function renderPairResultStatus() {
|
|
|
44
54
|
section.id = "pair-result-status";
|
|
45
55
|
section.className = "pair-result-status";
|
|
46
56
|
section.setAttribute("role", "status");
|
|
57
|
+
var header = document.createElement("div");
|
|
58
|
+
header.className = "pair-result-status-header";
|
|
59
|
+
var heading = document.createElement("span");
|
|
60
|
+
heading.textContent = items.length === 1 ? "Worker update needs attention" : items.length + " Worker updates need attention";
|
|
61
|
+
var close = document.createElement("button");
|
|
62
|
+
close.type = "button"; close.className = "pair-result-status-dismiss";
|
|
63
|
+
close.textContent = "×";
|
|
64
|
+
close.setAttribute("aria-label", "Dismiss Worker notices");
|
|
65
|
+
close.title = "Dismiss notices. Retained tasks and results are kept.";
|
|
66
|
+
close.addEventListener("click", dismiss.bind(null, items));
|
|
67
|
+
header.appendChild(heading); header.appendChild(close); section.appendChild(header);
|
|
68
|
+
var content = document.createElement("details"), toggle = document.createElement("summary");
|
|
69
|
+
content.className = "pair-result-status-details";
|
|
70
|
+
toggle.textContent = "Review updates";
|
|
71
|
+
content.appendChild(toggle); section.appendChild(content);
|
|
47
72
|
for (var i = 0; i < items.length; i++) {
|
|
48
73
|
var item = items[i], card = document.createElement("div");
|
|
49
74
|
card.className = "pair-result-status-card pair-result-status-" + item.state;
|
|
@@ -61,11 +86,11 @@ function renderPairResultStatus() {
|
|
|
61
86
|
}
|
|
62
87
|
if (item.canRetry) {
|
|
63
88
|
var button = document.createElement("button");
|
|
64
|
-
button.type = "button"; button.className = "
|
|
89
|
+
button.type = "button"; button.className = "pair-result-status-retry"; button.textContent = "Retry delivery";
|
|
65
90
|
button.addEventListener("click", retry.bind(null, item));
|
|
66
91
|
card.appendChild(button);
|
|
67
92
|
}
|
|
68
|
-
|
|
93
|
+
content.appendChild(card);
|
|
69
94
|
}
|
|
70
95
|
messages.parentElement.insertBefore(section, messages);
|
|
71
96
|
}
|
package/package.json
CHANGED