clay-server 4.0.0-beta.13 → 4.0.0-beta.15
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/capsule-display-floor.js +51 -0
- package/lib/capsule-frame-server.js +229 -0
- package/lib/capsule-pig-logic.js +268 -0
- package/lib/capsule-server-runtimes.js +41 -0
- package/lib/capsule-tictactoe-logic.js +260 -0
- package/lib/capsules/pig/display.js +190 -0
- package/lib/capsules/pig/manifest.json +9 -0
- package/lib/capsules/pig/ui.json +46 -0
- package/lib/capsules/tictactoe/manifest.json +9 -0
- package/lib/capsules/tictactoe/ui.json +203 -0
- package/lib/project-capsule-catalog.js +9 -1
- package/lib/project-connection.js +1 -1
- package/lib/project-log-feedback-delivery.js +76 -0
- package/lib/project-logs.js +4 -0
- package/lib/project-pair-lifecycle.js +7 -12
- package/lib/project-session-pair.js +29 -39
- package/lib/project-worker-proposal.js +203 -72
- package/lib/project.js +13 -0
- package/lib/public/css/capsule-ui.css +18 -0
- package/lib/public/css/home-session-actions.css +66 -0
- package/lib/public/css/home-sidebar.css +66 -0
- package/lib/public/css/mobile-nav.css +80 -0
- package/lib/public/css/sidebar.css +92 -0
- package/lib/public/css/worker-proposal.css +34 -1
- package/lib/public/modules/app-messages.js +14 -1
- package/lib/public/modules/home-conversations-sheet.js +102 -48
- package/lib/public/modules/home-session-actions.js +6 -0
- package/lib/public/modules/home-sidebar-chat-list.js +101 -41
- package/lib/public/modules/home-tool-frame.js +165 -0
- package/lib/public/modules/home-tools.js +129 -1
- package/lib/public/modules/session-hierarchy.js +54 -0
- package/lib/public/modules/sidebar-mobile.js +35 -6
- package/lib/public/modules/sidebar-session-hierarchy.js +206 -0
- package/lib/public/modules/sidebar-sessions.js +49 -7
- package/lib/public/modules/worker-proposal-state.js +16 -0
- package/lib/public/modules/worker-proposal.js +49 -12
- package/lib/sdk-bridge.js +16 -8
- package/lib/sdk-message-processor.js +34 -4
- package/lib/server-home-chat.js +12 -1
- package/lib/server-tools.js +97 -9
- package/lib/server.js +3 -0
- package/lib/session-driver-eligibility.js +20 -165
- package/lib/session-pair-factory.js +31 -28
- package/lib/session-pair-mcp-server.js +5 -9
- package/lib/session-pair-prompts.js +15 -15
- package/lib/session-provenance.js +119 -0
- package/lib/session-spawn-mcp-server.js +1 -1
- package/lib/sessions.js +40 -2
- package/lib/tools-registry.js +44 -10
- package/lib/ws-schema.js +8 -3
- package/lib/yoke/adapters/claude.js +12 -0
- package/package.json +1 -1
|
@@ -612,6 +612,86 @@
|
|
|
612
612
|
font-weight: 600;
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
+
.mobile-driver-header {
|
|
616
|
+
display: flex;
|
|
617
|
+
align-items: center;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.mobile-driver-header > .mobile-session-item {
|
|
621
|
+
min-width: 0;
|
|
622
|
+
flex: 1;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.mobile-driver-toggle {
|
|
626
|
+
width: 32px;
|
|
627
|
+
height: 44px;
|
|
628
|
+
padding: 0;
|
|
629
|
+
border: 0;
|
|
630
|
+
border-radius: 8px;
|
|
631
|
+
display: inline-flex;
|
|
632
|
+
align-items: center;
|
|
633
|
+
justify-content: center;
|
|
634
|
+
color: var(--text-dimmer);
|
|
635
|
+
background: transparent;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.mobile-driver-toggle .lucide,
|
|
639
|
+
.mobile-orphan-toggle .lucide {
|
|
640
|
+
width: 15px;
|
|
641
|
+
height: 15px;
|
|
642
|
+
transition: transform 0.15s ease;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.mobile-driver-toggle[aria-expanded="true"] .lucide,
|
|
646
|
+
.mobile-orphan-toggle[aria-expanded="true"] .lucide {
|
|
647
|
+
transform: rotate(90deg);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.mobile-worker-children {
|
|
651
|
+
margin-left: 16px;
|
|
652
|
+
padding-left: 12px;
|
|
653
|
+
border-left: 1px solid color-mix(in srgb, var(--text-dimmer) 24%, transparent);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.mobile-worker-item {
|
|
657
|
+
min-height: 43px;
|
|
658
|
+
padding-block: 9px;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.mobile-worker-generation {
|
|
662
|
+
flex-shrink: 0;
|
|
663
|
+
padding: 2px 6px;
|
|
664
|
+
border-radius: 999px;
|
|
665
|
+
color: var(--text-dimmer);
|
|
666
|
+
background: rgba(var(--overlay-rgb), 0.04);
|
|
667
|
+
font-size: 10px;
|
|
668
|
+
font-weight: 650;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.mobile-worker-generation.current {
|
|
672
|
+
color: var(--success);
|
|
673
|
+
background: color-mix(in srgb, var(--success) 10%, transparent);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.mobile-orphan-toggle {
|
|
677
|
+
width: 100%;
|
|
678
|
+
min-height: 42px;
|
|
679
|
+
padding: 8px 12px;
|
|
680
|
+
border: 0;
|
|
681
|
+
border-radius: 9px;
|
|
682
|
+
display: flex;
|
|
683
|
+
align-items: center;
|
|
684
|
+
gap: 9px;
|
|
685
|
+
color: var(--text-dimmer);
|
|
686
|
+
background: transparent;
|
|
687
|
+
font: inherit;
|
|
688
|
+
text-align: left;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.mobile-orphan-toggle span:first-of-type {
|
|
692
|
+
flex: 1;
|
|
693
|
+
}
|
|
694
|
+
|
|
615
695
|
.mobile-session-title {
|
|
616
696
|
flex: 1;
|
|
617
697
|
display: inline-flex;
|
|
@@ -926,6 +926,98 @@
|
|
|
926
926
|
transition: opacity 0.15s;
|
|
927
927
|
}
|
|
928
928
|
|
|
929
|
+
.session-driver-hierarchy {
|
|
930
|
+
position: relative;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
.session-driver-toggle {
|
|
934
|
+
width: 18px;
|
|
935
|
+
height: 24px;
|
|
936
|
+
padding: 0;
|
|
937
|
+
border: 0;
|
|
938
|
+
border-radius: 5px;
|
|
939
|
+
display: inline-flex;
|
|
940
|
+
align-items: center;
|
|
941
|
+
justify-content: center;
|
|
942
|
+
flex-shrink: 0;
|
|
943
|
+
color: var(--text-dimmer);
|
|
944
|
+
background: transparent;
|
|
945
|
+
cursor: pointer;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
.session-driver-toggle:hover,
|
|
949
|
+
.session-driver-toggle:focus-visible,
|
|
950
|
+
.session-orphan-toggle:hover,
|
|
951
|
+
.session-orphan-toggle:focus-visible {
|
|
952
|
+
color: var(--text);
|
|
953
|
+
background: rgba(var(--overlay-rgb), 0.05);
|
|
954
|
+
outline: none;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.session-driver-toggle .lucide,
|
|
958
|
+
.session-orphan-toggle .lucide {
|
|
959
|
+
width: 13px;
|
|
960
|
+
height: 13px;
|
|
961
|
+
transition: transform 0.15s ease;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
.session-driver-toggle[aria-expanded="true"] .lucide,
|
|
965
|
+
.session-orphan-toggle[aria-expanded="true"] .lucide {
|
|
966
|
+
transform: rotate(90deg);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.session-worker-children {
|
|
970
|
+
margin-left: 17px;
|
|
971
|
+
padding-left: 8px;
|
|
972
|
+
border-left: 1px solid color-mix(in srgb, var(--text-dimmer) 22%, transparent);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.session-worker-item {
|
|
976
|
+
height: 33px;
|
|
977
|
+
border-radius: 7px;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
.session-worker-generation,
|
|
981
|
+
.session-worker-count {
|
|
982
|
+
flex-shrink: 0;
|
|
983
|
+
padding: 1px 5px;
|
|
984
|
+
border-radius: 999px;
|
|
985
|
+
color: var(--text-dimmer);
|
|
986
|
+
background: rgba(var(--overlay-rgb), 0.04);
|
|
987
|
+
font-size: 9px;
|
|
988
|
+
font-weight: 650;
|
|
989
|
+
letter-spacing: 0.02em;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.session-worker-generation.current {
|
|
993
|
+
color: var(--success);
|
|
994
|
+
background: color-mix(in srgb, var(--success) 10%, transparent);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.session-orphan-toggle {
|
|
998
|
+
width: 100%;
|
|
999
|
+
height: 32px;
|
|
1000
|
+
padding: 0 9px 0 4px;
|
|
1001
|
+
border: 0;
|
|
1002
|
+
border-radius: 8px;
|
|
1003
|
+
display: flex;
|
|
1004
|
+
align-items: center;
|
|
1005
|
+
gap: 7px;
|
|
1006
|
+
color: var(--text-dimmer);
|
|
1007
|
+
background: transparent;
|
|
1008
|
+
cursor: pointer;
|
|
1009
|
+
font: inherit;
|
|
1010
|
+
text-align: left;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
.session-orphan-title {
|
|
1014
|
+
flex: 1;
|
|
1015
|
+
overflow: hidden;
|
|
1016
|
+
text-overflow: ellipsis;
|
|
1017
|
+
white-space: nowrap;
|
|
1018
|
+
font-size: 12px;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
929
1021
|
.split-group-text {
|
|
930
1022
|
display: flex;
|
|
931
1023
|
align-items: center;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Inline approval surface for
|
|
1
|
+
/* Inline approval surface for user-controlled Split Worker configuration. */
|
|
2
2
|
|
|
3
3
|
.worker-proposal-card {
|
|
4
4
|
width: min(var(--content-width), calc(100% - 40px));
|
|
@@ -67,6 +67,30 @@
|
|
|
67
67
|
|
|
68
68
|
.worker-proposal-plan li::marker { color: var(--accent2); font-weight: 700; }
|
|
69
69
|
|
|
70
|
+
.worker-proposal-rationale {
|
|
71
|
+
display: grid;
|
|
72
|
+
gap: 4px;
|
|
73
|
+
margin: 0 0 14px;
|
|
74
|
+
padding: 10px 12px;
|
|
75
|
+
border-left: 2px solid color-mix(in srgb, var(--accent2) 62%, var(--border));
|
|
76
|
+
background: color-mix(in srgb, var(--accent2) 5%, transparent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.worker-proposal-rationale > span {
|
|
80
|
+
color: var(--accent2);
|
|
81
|
+
font-size: 9px;
|
|
82
|
+
font-weight: 750;
|
|
83
|
+
letter-spacing: 0.06em;
|
|
84
|
+
text-transform: uppercase;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.worker-proposal-rationale p {
|
|
88
|
+
margin: 0;
|
|
89
|
+
color: var(--text-secondary);
|
|
90
|
+
font-size: 11px;
|
|
91
|
+
line-height: 1.45;
|
|
92
|
+
}
|
|
93
|
+
|
|
70
94
|
.worker-proposal-config {
|
|
71
95
|
display: grid;
|
|
72
96
|
grid-template-columns: minmax(120px, 0.8fr) minmax(160px, 1.2fr) minmax(190px, auto);
|
|
@@ -100,6 +124,15 @@
|
|
|
100
124
|
.worker-proposal-effort-btn:hover { color: var(--text); }
|
|
101
125
|
.worker-proposal-effort-btn.active { background: color-mix(in srgb, var(--accent2) 18%, var(--bg)); color: var(--accent2); }
|
|
102
126
|
|
|
127
|
+
.worker-proposal-decision {
|
|
128
|
+
margin-top: 9px;
|
|
129
|
+
color: var(--text-dimmer);
|
|
130
|
+
font-size: 9px;
|
|
131
|
+
line-height: 1.35;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.worker-proposal-decision.automatic { color: var(--accent2); }
|
|
135
|
+
|
|
103
136
|
.worker-proposal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
|
|
104
137
|
.worker-proposal-action { min-height: 34px; padding: 0 13px; border-radius: 9px; font: inherit; font-size: 11px; font-weight: 700; cursor: pointer; }
|
|
105
138
|
.worker-proposal-action.secondary { border: 1px solid var(--border); background: transparent; color: var(--text-muted); }
|
|
@@ -65,8 +65,9 @@ import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateCont
|
|
|
65
65
|
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
66
66
|
import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
|
|
67
67
|
import { hideHomeHub, showHomeHub } from './app-home-hub.js';
|
|
68
|
-
import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest } from './home-tools.js';
|
|
68
|
+
import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest, handleToolServerState, handleToolServerEvent } from './home-tools.js';
|
|
69
69
|
import { handleHomeDockState } from './home-dock.js';
|
|
70
|
+
import { handleToolFrameUrlState } from './home-tool-frame.js';
|
|
70
71
|
import { enterDmMode, exitDmMode, handleMateCreatedInApp, updateMateIconStatus, appendDmMessage, showDmTypingIndicator, buildMateInterviewPrompt } from './app-dm.js';
|
|
71
72
|
import { handleRateLimitEvent, updateRateLimitUsage, addScheduledMessageBubble, removeScheduledMessageBubble, handleFastModeState } from './app-rate-limit.js';
|
|
72
73
|
import { handleRemoteCursorMove, handleRemoteCursorLeave, handleRemoteSelection, clearRemoteCursors } from './app-cursors.js';
|
|
@@ -627,6 +628,18 @@ export function processMessage(msg) {
|
|
|
627
628
|
handleToolControlRequest(msg);
|
|
628
629
|
break;
|
|
629
630
|
|
|
631
|
+
case "tool_server_state":
|
|
632
|
+
handleToolServerState(msg);
|
|
633
|
+
break;
|
|
634
|
+
|
|
635
|
+
case "tool_server_event":
|
|
636
|
+
handleToolServerEvent(msg);
|
|
637
|
+
break;
|
|
638
|
+
|
|
639
|
+
case "tool_frame_url_state":
|
|
640
|
+
handleToolFrameUrlState(msg);
|
|
641
|
+
break;
|
|
642
|
+
|
|
630
643
|
case "input_sync":
|
|
631
644
|
if (!store.get('dmMode')) handleInputSync(msg.text);
|
|
632
645
|
break;
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
import { store } from './store.js';
|
|
4
4
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
5
5
|
import { getHomeSessionConversations, createHomeSessionActionsTrigger, disposeHomeSessionActionsMenu } from './home-session-actions.js';
|
|
6
|
+
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
6
7
|
|
|
7
8
|
var overlay = null;
|
|
8
9
|
var searchInput = null;
|
|
9
10
|
var listEl = null;
|
|
10
11
|
var sheetOpener = null;
|
|
11
12
|
var selectConversation = null;
|
|
13
|
+
var hierarchyExpansion = new Map();
|
|
12
14
|
|
|
13
15
|
function closeSheet(restoreFocus) {
|
|
14
16
|
if (!overlay) return;
|
|
@@ -54,66 +56,118 @@ function handleKeydown(event) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
function conversationMatches(conversation, query) {
|
|
60
|
+
if (!query) return true;
|
|
61
|
+
return conversation.title.toLowerCase().indexOf(query) !== -1 || conversation.mateName.toLowerCase().indexOf(query) !== -1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createSheetItem(conversation, worker) {
|
|
65
|
+
var item = document.createElement("div");
|
|
66
|
+
item.className = "home-conversations-sheet-item" + (worker ? " home-conversations-worker-item" : "");
|
|
67
|
+
var row = document.createElement("button");
|
|
68
|
+
row.type = "button";
|
|
69
|
+
row.className = "home-conversations-sheet-row";
|
|
70
|
+
var copy = document.createElement("span");
|
|
71
|
+
copy.className = "home-conversations-sheet-copy";
|
|
72
|
+
var title = document.createElement("span");
|
|
73
|
+
title.className = "home-conversations-sheet-row-title";
|
|
74
|
+
title.textContent = conversation.title;
|
|
75
|
+
copy.appendChild(title);
|
|
76
|
+
var mate = document.createElement("span");
|
|
77
|
+
mate.className = "home-conversations-sheet-row-mate";
|
|
78
|
+
mate.textContent = worker && conversation.workerGeneration ? conversation.mateName + " · Worker generation " + conversation.workerGeneration : conversation.mateName;
|
|
79
|
+
copy.appendChild(mate);
|
|
80
|
+
row.appendChild(copy);
|
|
81
|
+
if (conversation.isProcessing) {
|
|
82
|
+
var activity = document.createElement("span");
|
|
83
|
+
activity.className = "home-sidebar-processing";
|
|
84
|
+
activity.setAttribute("aria-label", "Processing");
|
|
85
|
+
row.appendChild(activity);
|
|
86
|
+
}
|
|
87
|
+
row.addEventListener("click", function () {
|
|
88
|
+
var onSelect = selectConversation;
|
|
89
|
+
closeSheet();
|
|
90
|
+
if (onSelect) onSelect(conversation.mateId, conversation.sessionId);
|
|
91
|
+
});
|
|
92
|
+
var active = conversation.mateId === store.get('homeChatMateId') && conversation.sessionId === store.get('homeChatSessionId');
|
|
93
|
+
if (active) {
|
|
94
|
+
item.classList.add("is-active");
|
|
95
|
+
row.setAttribute("aria-current", "page");
|
|
96
|
+
}
|
|
97
|
+
var detailsReturn = sheetOpener;
|
|
98
|
+
var actions = createHomeSessionActionsTrigger(conversation, {
|
|
99
|
+
detailsOpener: detailsReturn,
|
|
100
|
+
beforeOpenDetails: function () { closeSheet(false); },
|
|
101
|
+
});
|
|
102
|
+
item.appendChild(row);
|
|
103
|
+
item.appendChild(actions);
|
|
104
|
+
return item;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function createSheetHierarchy(root, query) {
|
|
108
|
+
if (!root.workers.length) return createSheetItem(root.driver, false);
|
|
109
|
+
var key = root.driver.hierarchyId;
|
|
110
|
+
var expanded = hierarchyExpansion.has(key) ? hierarchyExpansion.get(key) : !!query;
|
|
111
|
+
for (var ai = 0; ai < root.workers.length; ai++) {
|
|
112
|
+
if (root.workers[ai].mateId === store.get('homeChatMateId') && root.workers[ai].sessionId === store.get('homeChatSessionId')) expanded = true;
|
|
113
|
+
}
|
|
114
|
+
var wrapper = document.createElement("div");
|
|
115
|
+
wrapper.className = "home-conversations-driver-hierarchy";
|
|
116
|
+
var header = document.createElement("div");
|
|
117
|
+
header.className = "home-conversations-driver-header";
|
|
118
|
+
var toggle = document.createElement("button");
|
|
119
|
+
toggle.type = "button";
|
|
120
|
+
toggle.className = "home-conversations-driver-toggle";
|
|
121
|
+
var childrenId = "home-sheet-workers-" + String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
122
|
+
toggle.setAttribute("aria-expanded", String(expanded));
|
|
123
|
+
toggle.setAttribute("aria-controls", childrenId);
|
|
124
|
+
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
125
|
+
toggle.innerHTML = iconHtml("chevron-right");
|
|
126
|
+
if (!root.driver.sessionId) toggle.insertAdjacentHTML("beforeend", "<span>Unavailable Driver</span><span>" + root.workers.length + "</span>");
|
|
127
|
+
toggle.addEventListener("click", function () {
|
|
128
|
+
hierarchyExpansion.set(key, !expanded);
|
|
129
|
+
renderRows();
|
|
130
|
+
});
|
|
131
|
+
header.appendChild(toggle);
|
|
132
|
+
if (root.driver.sessionId) header.appendChild(createSheetItem(root.driver, false));
|
|
133
|
+
wrapper.appendChild(header);
|
|
134
|
+
var children = document.createElement("div");
|
|
135
|
+
children.id = childrenId;
|
|
136
|
+
children.className = "home-conversations-worker-children";
|
|
137
|
+
children.setAttribute("role", "group");
|
|
138
|
+
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
139
|
+
children.hidden = !expanded;
|
|
140
|
+
var driverMatched = root.driver.sessionId && conversationMatches(root.driver, query);
|
|
141
|
+
for (var i = 0; i < root.workers.length; i++) {
|
|
142
|
+
if (!query || driverMatched || conversationMatches(root.workers[i], query)) children.appendChild(createSheetItem(root.workers[i], true));
|
|
143
|
+
}
|
|
144
|
+
wrapper.appendChild(children);
|
|
145
|
+
return wrapper;
|
|
146
|
+
}
|
|
147
|
+
|
|
57
148
|
function renderRows() {
|
|
58
149
|
if (!listEl) return;
|
|
59
150
|
var query = searchInput ? searchInput.value.trim().toLowerCase() : "";
|
|
60
|
-
var
|
|
61
|
-
|
|
62
|
-
|
|
151
|
+
var hierarchy = buildSessionHierarchy(getHomeSessionConversations());
|
|
152
|
+
var roots = hierarchy.roots.filter(function (root) {
|
|
153
|
+
if (conversationMatches(root.driver, query)) return true;
|
|
154
|
+
for (var i = 0; i < root.workers.length; i++) if (conversationMatches(root.workers[i], query)) return true;
|
|
155
|
+
return false;
|
|
63
156
|
});
|
|
157
|
+
var orphans = hierarchy.orphans.filter(function (worker) { return conversationMatches(worker, query); });
|
|
64
158
|
disposeHomeSessionActionsMenu();
|
|
65
159
|
listEl.innerHTML = "";
|
|
66
|
-
if (!
|
|
160
|
+
if (!roots.length && !orphans.length) {
|
|
67
161
|
var empty = document.createElement("div");
|
|
68
162
|
empty.className = "home-conversations-sheet-empty";
|
|
69
163
|
empty.textContent = query ? "No chats match your search." : "No chats yet.";
|
|
70
164
|
listEl.appendChild(empty);
|
|
71
165
|
return;
|
|
72
166
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
var row = document.createElement("button");
|
|
78
|
-
row.type = "button";
|
|
79
|
-
row.className = "home-conversations-sheet-row";
|
|
80
|
-
var copy = document.createElement("span");
|
|
81
|
-
copy.className = "home-conversations-sheet-copy";
|
|
82
|
-
var title = document.createElement("span");
|
|
83
|
-
title.className = "home-conversations-sheet-row-title";
|
|
84
|
-
title.textContent = conversation.title;
|
|
85
|
-
copy.appendChild(title);
|
|
86
|
-
var mate = document.createElement("span");
|
|
87
|
-
mate.className = "home-conversations-sheet-row-mate";
|
|
88
|
-
mate.textContent = conversation.mateName;
|
|
89
|
-
copy.appendChild(mate);
|
|
90
|
-
row.appendChild(copy);
|
|
91
|
-
if (conversation.isProcessing) {
|
|
92
|
-
var activity = document.createElement("span");
|
|
93
|
-
activity.className = "home-sidebar-processing";
|
|
94
|
-
activity.setAttribute("aria-label", "Processing");
|
|
95
|
-
row.appendChild(activity);
|
|
96
|
-
}
|
|
97
|
-
row.addEventListener("click", function () {
|
|
98
|
-
var onSelect = selectConversation;
|
|
99
|
-
closeSheet();
|
|
100
|
-
if (onSelect) onSelect(conversation.mateId, conversation.sessionId);
|
|
101
|
-
});
|
|
102
|
-
var active = conversation.mateId === store.get('homeChatMateId') && conversation.sessionId === store.get('homeChatSessionId');
|
|
103
|
-
if (active) {
|
|
104
|
-
item.classList.add("is-active");
|
|
105
|
-
row.setAttribute("aria-current", "page");
|
|
106
|
-
}
|
|
107
|
-
var detailsReturn = sheetOpener;
|
|
108
|
-
var actions = createHomeSessionActionsTrigger(conversation, {
|
|
109
|
-
detailsOpener: detailsReturn,
|
|
110
|
-
beforeOpenDetails: function () { closeSheet(false); },
|
|
111
|
-
});
|
|
112
|
-
item.appendChild(row);
|
|
113
|
-
item.appendChild(actions);
|
|
114
|
-
listEl.appendChild(item);
|
|
115
|
-
})(all[i]);
|
|
116
|
-
}
|
|
167
|
+
roots.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
168
|
+
for (var i = 0; i < roots.length; i++) listEl.appendChild(createSheetHierarchy(roots[i], query));
|
|
169
|
+
if (orphans.length) listEl.appendChild(createSheetHierarchy({ driver: { hierarchyId: "orphan-sheet", title: "Unavailable Driver" }, workers: orphans }, query));
|
|
170
|
+
refreshIcons();
|
|
117
171
|
}
|
|
118
172
|
|
|
119
173
|
export function openHomeConversationsSheet(onSelect, opener) {
|
|
@@ -53,6 +53,12 @@ export function getHomeSessionConversations() {
|
|
|
53
53
|
createdAt: typeof sessions[j].createdAt === "number" ? sessions[j].createdAt : 0,
|
|
54
54
|
lastActivity: typeof sessions[j].lastActivity === "number" ? sessions[j].lastActivity : 0,
|
|
55
55
|
isProcessing: sessions[j].isProcessing === true,
|
|
56
|
+
sessionRole: sessions[j].sessionRole === "worker" ? "worker" : "driver",
|
|
57
|
+
parentSessionId: safeText(sessions[j].parentSessionId, null),
|
|
58
|
+
parentAvailable: sessions[j].parentAvailable === true,
|
|
59
|
+
workerGeneration: typeof sessions[j].workerGeneration === "number" ? sessions[j].workerGeneration : null,
|
|
60
|
+
hierarchyId: mateIds[i] + ":" + sessions[j].id,
|
|
61
|
+
parentHierarchyId: sessions[j].parentSessionId ? mateIds[i] + ":" + sessions[j].parentSessionId : null,
|
|
56
62
|
});
|
|
57
63
|
}
|
|
58
64
|
}
|
|
@@ -1,7 +1,98 @@
|
|
|
1
|
-
// Complete
|
|
1
|
+
// Complete Home chat archive rendered as provenance-preserving session trees.
|
|
2
2
|
|
|
3
3
|
import { store } from './store.js';
|
|
4
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
4
5
|
import { getHomeSessionConversations, createHomeSessionActionsTrigger, disposeHomeSessionActionsMenu } from './home-session-actions.js';
|
|
6
|
+
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
7
|
+
|
|
8
|
+
var expansion = new Map();
|
|
9
|
+
|
|
10
|
+
function isExpanded(key, workers) {
|
|
11
|
+
if (expansion.has(key)) return expansion.get(key);
|
|
12
|
+
for (var i = 0; i < workers.length; i++) {
|
|
13
|
+
if (workers[i].mateId === store.get('homeChatMateId') && workers[i].sessionId === store.get('homeChatSessionId')) return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createChatItem(chat, openConversation, worker) {
|
|
19
|
+
var item = document.createElement("div");
|
|
20
|
+
item.className = "home-sidebar-recent-item" + (worker ? " home-sidebar-worker-item" : "");
|
|
21
|
+
var row = document.createElement("button");
|
|
22
|
+
row.type = "button";
|
|
23
|
+
row.className = "home-sidebar-recent-row";
|
|
24
|
+
row.setAttribute("aria-label", chat.title + ", with " + chat.mateName);
|
|
25
|
+
if (chat.mateId === store.get('homeChatMateId') && chat.sessionId === store.get('homeChatSessionId')) {
|
|
26
|
+
item.classList.add("is-active");
|
|
27
|
+
row.setAttribute("aria-current", "page");
|
|
28
|
+
}
|
|
29
|
+
var copy = document.createElement("span");
|
|
30
|
+
copy.className = "home-sidebar-recent-copy";
|
|
31
|
+
var title = document.createElement("span");
|
|
32
|
+
title.className = "home-sidebar-recent-title";
|
|
33
|
+
title.textContent = chat.title;
|
|
34
|
+
var mate = document.createElement("span");
|
|
35
|
+
mate.className = "home-sidebar-recent-mate";
|
|
36
|
+
mate.textContent = worker && chat.workerGeneration ? chat.mateName + " · Worker generation " + chat.workerGeneration : chat.mateName;
|
|
37
|
+
copy.appendChild(title);
|
|
38
|
+
copy.appendChild(mate);
|
|
39
|
+
row.appendChild(copy);
|
|
40
|
+
if (chat.isProcessing) {
|
|
41
|
+
var activity = document.createElement("span");
|
|
42
|
+
activity.className = "home-sidebar-processing";
|
|
43
|
+
activity.setAttribute("aria-label", "Processing");
|
|
44
|
+
row.appendChild(activity);
|
|
45
|
+
}
|
|
46
|
+
row.addEventListener("click", function () {
|
|
47
|
+
if (typeof openConversation === "function") openConversation(chat.mateId, chat.sessionId);
|
|
48
|
+
});
|
|
49
|
+
item.appendChild(row);
|
|
50
|
+
item.appendChild(createHomeSessionActionsTrigger(chat));
|
|
51
|
+
return item;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createHierarchy(root, openConversation) {
|
|
55
|
+
if (!root.workers.length) return createChatItem(root.driver, openConversation, false);
|
|
56
|
+
var wrapper = document.createElement("div");
|
|
57
|
+
wrapper.className = "home-sidebar-driver-hierarchy";
|
|
58
|
+
var key = root.driver.hierarchyId;
|
|
59
|
+
var expanded = isExpanded(key, root.workers);
|
|
60
|
+
var childrenId = "home-sidebar-workers-" + String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
61
|
+
var header = document.createElement("div");
|
|
62
|
+
header.className = "home-sidebar-driver-header";
|
|
63
|
+
var toggle = document.createElement("button");
|
|
64
|
+
toggle.type = "button";
|
|
65
|
+
toggle.className = "home-sidebar-driver-toggle";
|
|
66
|
+
toggle.setAttribute("aria-expanded", String(expanded));
|
|
67
|
+
toggle.setAttribute("aria-controls", childrenId);
|
|
68
|
+
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
69
|
+
toggle.innerHTML = iconHtml("chevron-right");
|
|
70
|
+
toggle.addEventListener("click", function () {
|
|
71
|
+
expansion.set(key, !expanded);
|
|
72
|
+
renderHomeSidebarChats(openConversation);
|
|
73
|
+
});
|
|
74
|
+
header.appendChild(toggle);
|
|
75
|
+
if (root.driver.sessionId) header.appendChild(createChatItem(root.driver, openConversation, false));
|
|
76
|
+
wrapper.appendChild(header);
|
|
77
|
+
var children = document.createElement("div");
|
|
78
|
+
children.id = childrenId;
|
|
79
|
+
children.className = "home-sidebar-worker-children";
|
|
80
|
+
children.setAttribute("role", "group");
|
|
81
|
+
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
82
|
+
children.hidden = !expanded;
|
|
83
|
+
for (var i = 0; i < root.workers.length; i++) children.appendChild(createChatItem(root.workers[i], openConversation, true));
|
|
84
|
+
wrapper.appendChild(children);
|
|
85
|
+
return wrapper;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function createOrphans(workers, openConversation) {
|
|
89
|
+
var wrapper = createHierarchy({ driver: { hierarchyId: "orphan-home", title: "Unavailable Driver" }, workers: workers }, openConversation);
|
|
90
|
+
var toggle = wrapper.querySelector(".home-sidebar-driver-toggle");
|
|
91
|
+
toggle.classList.add("home-sidebar-orphan-toggle");
|
|
92
|
+
toggle.setAttribute("aria-label", "Toggle Workers whose Driver is unavailable");
|
|
93
|
+
toggle.insertAdjacentHTML("beforeend", "<span>Unavailable Driver</span><span>" + workers.length + "</span>");
|
|
94
|
+
return wrapper;
|
|
95
|
+
}
|
|
5
96
|
|
|
6
97
|
export function renderHomeSidebarChats(openConversation) {
|
|
7
98
|
var list = document.getElementById("home-sidebar-recent-list");
|
|
@@ -11,9 +102,7 @@ export function renderHomeSidebarChats(openConversation) {
|
|
|
11
102
|
var chats = getHomeSessionConversations();
|
|
12
103
|
var scope = store.get('homeChatScope') === "current" ? "current" : "all";
|
|
13
104
|
var activeMateId = store.get('homeChatMateId');
|
|
14
|
-
if (scope === "current") {
|
|
15
|
-
chats = chats.filter(function (chat) { return chat.mateId === activeMateId; });
|
|
16
|
-
}
|
|
105
|
+
if (scope === "current") chats = chats.filter(function (chat) { return chat.mateId === activeMateId; });
|
|
17
106
|
if (!chats.length) {
|
|
18
107
|
var empty = document.createElement("div");
|
|
19
108
|
empty.className = "home-sidebar-recent-empty";
|
|
@@ -21,43 +110,14 @@ export function renderHomeSidebarChats(openConversation) {
|
|
|
21
110
|
list.appendChild(empty);
|
|
22
111
|
return 0;
|
|
23
112
|
}
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
row.type = "button";
|
|
31
|
-
row.className = "home-sidebar-recent-row";
|
|
32
|
-
row.setAttribute("aria-label", chat.title + ", with " + chat.mateName);
|
|
33
|
-
if (chat.mateId === activeMateId && chat.sessionId === activeSessionId) {
|
|
34
|
-
item.classList.add("is-active");
|
|
35
|
-
row.setAttribute("aria-current", "page");
|
|
36
|
-
}
|
|
37
|
-
var copy = document.createElement("span");
|
|
38
|
-
copy.className = "home-sidebar-recent-copy";
|
|
39
|
-
var title = document.createElement("span");
|
|
40
|
-
title.className = "home-sidebar-recent-title";
|
|
41
|
-
title.textContent = chat.title;
|
|
42
|
-
var mate = document.createElement("span");
|
|
43
|
-
mate.className = "home-sidebar-recent-mate";
|
|
44
|
-
mate.textContent = chat.mateName;
|
|
45
|
-
copy.appendChild(title);
|
|
46
|
-
copy.appendChild(mate);
|
|
47
|
-
row.appendChild(copy);
|
|
48
|
-
if (chat.isProcessing) {
|
|
49
|
-
var activity = document.createElement("span");
|
|
50
|
-
activity.className = "home-sidebar-processing";
|
|
51
|
-
activity.setAttribute("aria-label", "Processing");
|
|
52
|
-
row.appendChild(activity);
|
|
53
|
-
}
|
|
54
|
-
row.addEventListener("click", function () {
|
|
55
|
-
if (typeof openConversation === "function") openConversation(chat.mateId, chat.sessionId);
|
|
56
|
-
});
|
|
57
|
-
item.appendChild(row);
|
|
58
|
-
item.appendChild(createHomeSessionActionsTrigger(chat));
|
|
59
|
-
list.appendChild(item);
|
|
60
|
-
})(chats[i]);
|
|
113
|
+
var hierarchy = buildSessionHierarchy(chats);
|
|
114
|
+
var hasHierarchy = hierarchy.orphans.length > 0;
|
|
115
|
+
hierarchy.roots.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
116
|
+
for (var i = 0; i < hierarchy.roots.length; i++) {
|
|
117
|
+
if (hierarchy.roots[i].workers.length) hasHierarchy = true;
|
|
118
|
+
list.appendChild(createHierarchy(hierarchy.roots[i], openConversation));
|
|
61
119
|
}
|
|
120
|
+
if (hierarchy.orphans.length) list.appendChild(createOrphans(hierarchy.orphans, openConversation));
|
|
121
|
+
if (hasHierarchy) refreshIcons();
|
|
62
122
|
return chats.length;
|
|
63
123
|
}
|