clay-server 5.2.0-beta.7 → 5.2.0-beta.9
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/pane-pending-interactions.js +20 -0
- package/lib/pane-session-activation.js +114 -0
- package/lib/pane-session-transport.js +26 -0
- package/lib/project-sessions.js +15 -5
- package/lib/project.js +11 -3
- package/lib/public/app.js +14 -0
- package/lib/public/css/contextual-clay.css +1 -1
- package/lib/public/css/input.css +6 -0
- package/lib/public/css/sticky-notes.css +37 -11
- package/lib/public/modules/app-connection.js +3 -0
- package/lib/public/modules/app-message-router.js +13 -0
- package/lib/public/modules/app-messages.js +25 -5
- package/lib/public/modules/app-misc.js +3 -1
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/clay-owner-navigation.js +0 -3
- package/lib/public/modules/clay-studio-render.js +3 -1
- package/lib/public/modules/command-palette.js +52 -14
- package/lib/public/modules/contextual-clay-workspace.js +14 -2
- package/lib/public/modules/contextual-clay.js +16 -3
- package/lib/public/modules/contextual-mate-context.js +6 -4
- package/lib/public/modules/elicitation-form.js +5 -0
- package/lib/public/modules/history-replay-batch.js +8 -0
- package/lib/public/modules/input.js +55 -11
- package/lib/public/modules/message-delivery.js +10 -2
- package/lib/public/modules/model-picker.js +2 -0
- package/lib/public/modules/pane-activation.js +214 -0
- package/lib/public/modules/pane-binding.js +82 -0
- package/lib/public/modules/pane-bridge.js +5 -2
- package/lib/public/modules/pane-browser-bridge.js +5 -3
- package/lib/public/modules/pane-file-bridge.js +4 -0
- package/lib/public/modules/pane-issue-bridge.js +4 -1
- package/lib/public/modules/rewind.js +5 -0
- package/lib/public/modules/session-actions.js +5 -2
- package/lib/public/modules/session-context-menu.js +5 -0
- package/lib/public/modules/session-rich-drafts.js +21 -0
- package/lib/public/modules/session-switch-defer.js +67 -0
- package/lib/public/modules/split-group-restore.js +68 -0
- package/lib/public/modules/split-pair-ui.js +1 -0
- package/lib/public/modules/split-pane-reconciler.js +15 -0
- package/lib/public/modules/split-pane-renderer.js +87 -6
- package/lib/public/modules/split-session-boundary.js +1 -1
- package/lib/public/modules/split-view.js +51 -52
- package/lib/public/modules/sticky-notes-checklist.js +51 -6
- package/lib/public/modules/stt-controller.js +4 -1
- package/lib/public/modules/stt-recording.js +1 -1
- package/lib/public/modules/stt.js +7 -2
- package/lib/public/modules/tools.js +18 -2
- package/lib/sessions.js +17 -10
- package/package.json +4 -3
|
@@ -9,6 +9,7 @@ import { openFile } from './filebrowser.js';
|
|
|
9
9
|
import { mateAvatarUrl } from './avatar.js';
|
|
10
10
|
import { getChatLayout } from './theme.js';
|
|
11
11
|
import { store } from './store.js';
|
|
12
|
+
import { currentPaneReview } from './pane-binding.js';
|
|
12
13
|
import { applyPermissionHints } from './permission-hints.js';
|
|
13
14
|
import { VENDOR_NAMES } from './app-rendering.js';
|
|
14
15
|
import { startThinkingSegment, appendThinkingText, stopThinkingSegment, resetThinkingTurn, clearThinkingState, saveThinkingState, restoreThinkingState, updateThinkingTokenEstimate } from './thinking-lifecycle.js';
|
|
@@ -394,12 +395,13 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
394
395
|
skipBtn.className = "ask-user-skip";
|
|
395
396
|
skipBtn.textContent = "Skip";
|
|
396
397
|
skipBtn.addEventListener("click", function () {
|
|
398
|
+
if (!currentPaneReview(container)) return;
|
|
397
399
|
if (container.classList.contains("answered")) return;
|
|
398
400
|
container.classList.add("answered");
|
|
399
401
|
markAskUserRequestAnswered(toolId);
|
|
400
402
|
enableMainInput();
|
|
401
403
|
if (ctx.ws && ctx.connected) {
|
|
402
|
-
ctx.ws.send(JSON.stringify({ type: "stop" }));
|
|
404
|
+
ctx.ws.send(JSON.stringify({ type: "stop", paneBinding: container.paneBinding || undefined }));
|
|
403
405
|
}
|
|
404
406
|
});
|
|
405
407
|
actions.appendChild(skipBtn);
|
|
@@ -419,6 +421,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
419
421
|
container.appendChild(mateContentWrap);
|
|
420
422
|
}
|
|
421
423
|
|
|
424
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
422
425
|
ctx.addToMessages(container);
|
|
423
426
|
disableMainInput();
|
|
424
427
|
ctx.setActivity(null);
|
|
@@ -436,6 +439,7 @@ export function enableMainInput() {
|
|
|
436
439
|
}
|
|
437
440
|
|
|
438
441
|
function submitAskUserAnswer(container, toolId, questions, answers, multiSelections) {
|
|
442
|
+
if (!currentPaneReview(container)) return;
|
|
439
443
|
if (container.classList.contains("answered") || container.dataset.askUserSubmitted === "true") return;
|
|
440
444
|
|
|
441
445
|
var result = {};
|
|
@@ -461,6 +465,7 @@ function submitAskUserAnswer(container, toolId, questions, answers, multiSelecti
|
|
|
461
465
|
if (ctx.ws && ctx.connected) {
|
|
462
466
|
ctx.ws.send(JSON.stringify({
|
|
463
467
|
type: "ask_user_response",
|
|
468
|
+
paneBinding: container.paneBinding || undefined,
|
|
464
469
|
toolId: toolId,
|
|
465
470
|
answers: result,
|
|
466
471
|
}));
|
|
@@ -655,6 +660,7 @@ function renderFormalPermission(requestId, toolName, toolInput, decisionReason)
|
|
|
655
660
|
container.appendChild(header);
|
|
656
661
|
container.appendChild(body);
|
|
657
662
|
container.appendChild(actions);
|
|
663
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
658
664
|
ctx.addToMessages(container);
|
|
659
665
|
|
|
660
666
|
pendingPermissions[requestId] = container;
|
|
@@ -762,6 +768,7 @@ function renderPlanPermission(requestId) {
|
|
|
762
768
|
container.appendChild(body);
|
|
763
769
|
container.appendChild(actions);
|
|
764
770
|
container.appendChild(feedbackRow);
|
|
771
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
765
772
|
ctx.addToMessages(container);
|
|
766
773
|
|
|
767
774
|
pendingPermissions[requestId] = container;
|
|
@@ -769,10 +776,11 @@ function renderPlanPermission(requestId) {
|
|
|
769
776
|
ctx.setActivity(null);
|
|
770
777
|
maybeScrollToBottom();
|
|
771
778
|
// Focus the feedback input after render
|
|
772
|
-
setTimeout(function () { feedbackInput.focus(); }, 50);
|
|
779
|
+
setTimeout(function () { if (currentPaneReview(container)) feedbackInput.focus(); }, 50);
|
|
773
780
|
}
|
|
774
781
|
|
|
775
782
|
function sendPlanResponse(container, requestId, decision, feedback) {
|
|
783
|
+
if (!currentPaneReview(container)) return;
|
|
776
784
|
if (container.classList.contains("resolved")) return;
|
|
777
785
|
container.classList.add("resolved");
|
|
778
786
|
if (ctx.stopUrgentBlink) ctx.stopUrgentBlink();
|
|
@@ -800,6 +808,7 @@ function sendPlanResponse(container, requestId, decision, feedback) {
|
|
|
800
808
|
if (ctx.ws && ctx.connected) {
|
|
801
809
|
var payload = {
|
|
802
810
|
type: "permission_response",
|
|
811
|
+
paneBinding: container.paneBinding || undefined,
|
|
803
812
|
requestId: requestId,
|
|
804
813
|
decision: decision,
|
|
805
814
|
};
|
|
@@ -954,6 +963,7 @@ function renderConversationalPermission(requestId, toolName, toolInput, mateId,
|
|
|
954
963
|
|
|
955
964
|
container.appendChild(content);
|
|
956
965
|
|
|
966
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
957
967
|
ctx.addToMessages(container);
|
|
958
968
|
pendingPermissions[requestId] = container;
|
|
959
969
|
refreshIcons();
|
|
@@ -962,6 +972,7 @@ function renderConversationalPermission(requestId, toolName, toolInput, mateId,
|
|
|
962
972
|
}
|
|
963
973
|
|
|
964
974
|
function sendPermissionResponse(container, requestId, decision) {
|
|
975
|
+
if (!currentPaneReview(container)) return;
|
|
965
976
|
if (container.classList.contains("resolved")) return;
|
|
966
977
|
container.classList.add("resolved");
|
|
967
978
|
if (ctx.stopUrgentBlink) ctx.stopUrgentBlink();
|
|
@@ -979,6 +990,7 @@ function sendPermissionResponse(container, requestId, decision) {
|
|
|
979
990
|
if (ctx.ws && ctx.connected) {
|
|
980
991
|
ctx.ws.send(JSON.stringify({
|
|
981
992
|
type: "permission_response",
|
|
993
|
+
paneBinding: container.paneBinding || undefined,
|
|
982
994
|
requestId: requestId,
|
|
983
995
|
decision: decision,
|
|
984
996
|
}));
|
|
@@ -1053,6 +1065,7 @@ export function renderElicitationRequest(msg) {
|
|
|
1053
1065
|
var container = buildElicitationCard(msg, function () {
|
|
1054
1066
|
if (ctx.stopUrgentBlink) ctx.stopUrgentBlink();
|
|
1055
1067
|
});
|
|
1068
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
1056
1069
|
ctx.addToMessages(container);
|
|
1057
1070
|
pendingElicitations[msg.requestId] = container;
|
|
1058
1071
|
refreshIcons();
|
|
@@ -1079,6 +1092,7 @@ export function markElicitationError(requestId, error, expired) {
|
|
|
1079
1092
|
var pendingUserDialogs = {};
|
|
1080
1093
|
|
|
1081
1094
|
function sendUserDialogResponse(container, requestId, behavior, result) {
|
|
1095
|
+
if (!currentPaneReview(container)) return;
|
|
1082
1096
|
if (container.classList.contains("resolved")) return;
|
|
1083
1097
|
container.classList.add("resolved");
|
|
1084
1098
|
if (ctx.stopUrgentBlink) ctx.stopUrgentBlink();
|
|
@@ -1094,6 +1108,7 @@ function sendUserDialogResponse(container, requestId, behavior, result) {
|
|
|
1094
1108
|
if (ctx.ws && ctx.connected) {
|
|
1095
1109
|
var msg = {
|
|
1096
1110
|
type: "user_dialog_response",
|
|
1111
|
+
paneBinding: container.paneBinding || undefined,
|
|
1097
1112
|
requestId: requestId,
|
|
1098
1113
|
behavior: isCancel ? "cancelled" : "completed",
|
|
1099
1114
|
};
|
|
@@ -1185,6 +1200,7 @@ export function renderUserDialogRequest(msg) {
|
|
|
1185
1200
|
container.appendChild(header);
|
|
1186
1201
|
container.appendChild(body);
|
|
1187
1202
|
container.appendChild(actions);
|
|
1203
|
+
container.paneBinding = store.get("panePendingBinding") || store.get("paneCommittedBinding") || null;
|
|
1188
1204
|
ctx.addToMessages(container);
|
|
1189
1205
|
|
|
1190
1206
|
pendingUserDialogs[msg.requestId] = container;
|
package/lib/sessions.js
CHANGED
|
@@ -778,8 +778,8 @@ function createSessionManager(opts) {
|
|
|
778
778
|
}
|
|
779
779
|
|
|
780
780
|
// History entries include tool activity and streamed output, so opening a
|
|
781
|
-
// conversation
|
|
782
|
-
var INITIAL_HISTORY_SIZE =
|
|
781
|
+
// conversation starts with a 300-entry target, aligned to a complete user turn.
|
|
782
|
+
var INITIAL_HISTORY_SIZE = 300;
|
|
783
783
|
var HISTORY_PAGE_SIZE = 100;
|
|
784
784
|
|
|
785
785
|
function findTurnBoundary(history, targetIndex) {
|
|
@@ -789,8 +789,9 @@ function createSessionManager(opts) {
|
|
|
789
789
|
return 0;
|
|
790
790
|
}
|
|
791
791
|
|
|
792
|
-
function replayHistory(session, fromIndex, targetWs, transform) {
|
|
793
|
-
var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
|
|
792
|
+
function replayHistory(session, fromIndex, targetWs, transform, snapshotSend) {
|
|
793
|
+
var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
|
|
794
|
+
var sendHistory = snapshotSend && snapshotSend.history || _send;
|
|
794
795
|
var total = session.history.length;
|
|
795
796
|
if (typeof fromIndex !== "number") {
|
|
796
797
|
if (total <= INITIAL_HISTORY_SIZE) {
|
|
@@ -800,7 +801,7 @@ function createSessionManager(opts) {
|
|
|
800
801
|
}
|
|
801
802
|
}
|
|
802
803
|
|
|
803
|
-
|
|
804
|
+
sendHistory({ type: "history_meta", total: total, from: fromIndex });
|
|
804
805
|
|
|
805
806
|
for (var i = fromIndex; i < total; i++) {
|
|
806
807
|
var _item = session.history[i];
|
|
@@ -812,7 +813,7 @@ function createSessionManager(opts) {
|
|
|
812
813
|
var normalizedItem = require("./yoke/usage").clientEvent(_item, session.vendor || "claude");
|
|
813
814
|
var replayItem = transform ? transform(normalizedItem) : normalizedItem;
|
|
814
815
|
if (replayItem && typeof replayItem === "object") replayItem = Object.assign({}, replayItem, { _historyIndex: i });
|
|
815
|
-
|
|
816
|
+
sendHistory(replayItem);
|
|
816
817
|
}
|
|
817
818
|
|
|
818
819
|
// Find the last result message in the full history for accurate context data
|
|
@@ -833,16 +834,17 @@ function createSessionManager(opts) {
|
|
|
833
834
|
}
|
|
834
835
|
}
|
|
835
836
|
|
|
836
|
-
|
|
837
|
+
sendHistory({ type: "history_done", controlHistoryRevision: require("./clay-control-target-projection").digest(session.history || []), sessionId: session.localId, sessionOriginId: session.sessionOriginId || null, lastUsage: lastUsage, lastModelUsage: lastModelUsage, lastCost: lastCost, lastStreamInputTokens: lastStreamInputTokens, context: lastContext, contextUsage: require("./yoke/usage").context(session.lastContextUsage, session.vendor || "claude") });
|
|
837
838
|
for (var vi = 0; vi < sessionViewedListeners.length; vi++) {
|
|
838
839
|
try { sessionViewedListeners[vi](session, targetWs, _send); } catch (e) {}
|
|
839
840
|
}
|
|
840
841
|
}
|
|
841
842
|
|
|
842
|
-
function switchSession(localId, targetWs, transform) {
|
|
843
|
+
function switchSession(localId, targetWs, transform, snapshotSend, snapshotGuard) {
|
|
843
844
|
var session = sessions.get(localId);
|
|
844
845
|
if (!session) return;
|
|
845
846
|
if (typeof onSessionHydrate === "function") onSessionHydrate(session);
|
|
847
|
+
if (snapshotGuard && !snapshotGuard()) return;
|
|
846
848
|
|
|
847
849
|
// Pane sockets (split-view iframes) pin their session via switch_session
|
|
848
850
|
// but must not move the project-global active pointer: reloads and
|
|
@@ -863,7 +865,7 @@ function createSessionManager(opts) {
|
|
|
863
865
|
singleUserUnread[localId] = 0;
|
|
864
866
|
|
|
865
867
|
// In multi-user mode with a specific client, only send to that client
|
|
866
|
-
var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
|
|
868
|
+
var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
|
|
867
869
|
|
|
868
870
|
var _capsByVendor = capabilitiesByVendor || {};
|
|
869
871
|
var _sessionVendor = session.vendor || defaultVendor || "claude";
|
|
@@ -876,7 +878,7 @@ function createSessionManager(opts) {
|
|
|
876
878
|
|| [];
|
|
877
879
|
_send({ type: "slash_commands", commands: _vendorCmds, vendor: _sessionVendor });
|
|
878
880
|
broadcastSessionList();
|
|
879
|
-
replayHistory(session, undefined, targetWs, transform);
|
|
881
|
+
replayHistory(session, undefined, targetWs, transform, snapshotSend);
|
|
880
882
|
|
|
881
883
|
if (session.isProcessing) {
|
|
882
884
|
_send({ type: "status", status: "processing" });
|
|
@@ -894,10 +896,15 @@ function createSessionManager(opts) {
|
|
|
894
896
|
toolInput: p.toolInput,
|
|
895
897
|
toolUseId: p.toolUseId,
|
|
896
898
|
decisionReason: p.decisionReason,
|
|
899
|
+
defaultToNo: p.defaultToNo,
|
|
900
|
+
suppressAlwaysAllowRule: p.suppressAlwaysAllowRule,
|
|
901
|
+
mateId: p.mateId || undefined,
|
|
902
|
+
vendor: p.vendor || session.vendor || undefined,
|
|
897
903
|
});
|
|
898
904
|
}
|
|
899
905
|
|
|
900
906
|
// Re-send active mention indicator so returning clients restore the mate avatar state
|
|
907
|
+
if (snapshotSend) require('./pane-pending-interactions').send(session, _send);
|
|
901
908
|
if (session._mentionInProgress && session._mentionActiveMateId) {
|
|
902
909
|
_send({ type: "mention_processing", mateId: session._mentionActiveMateId, active: true });
|
|
903
910
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clay-server",
|
|
3
|
-
"version": "5.2.0-beta.
|
|
3
|
+
"version": "5.2.0-beta.9",
|
|
4
4
|
"description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"clay-server": "./bin/cli.js"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "node bin/cli.js --dev",
|
|
10
|
-
"test": "node --test --test-force-exit test/*.test.js",
|
|
11
|
-
"semantic-release": "semantic-release"
|
|
10
|
+
"test": "node --test --test-force-exit --test-skip-pattern=\"^real sidebar (normal|long-turn):\" test/*.test.js",
|
|
11
|
+
"semantic-release": "semantic-release",
|
|
12
|
+
"test:pane-performance": "node --test --test-force-exit test/pane-reuse-browser.test.js"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"bin/",
|