clay-server 4.0.0-beta.8 → 4.0.0
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 +255 -0
- package/lib/capsule-mate-turn.js +105 -0
- package/lib/capsule-pig-logic.js +300 -0
- package/lib/capsule-server-runtimes.js +39 -0
- package/lib/capsules/pig/display.js +198 -0
- package/lib/capsules/pig/manifest.json +9 -0
- package/lib/capsules/pig/ui.json +84 -0
- package/lib/config.js +25 -1
- package/lib/daemon-projects.js +13 -8
- package/lib/daemon.js +127 -14
- package/lib/git-cli.js +95 -1
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +240 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/migrate-single-user.js +2 -0
- package/lib/notes-lifecycle.js +149 -0
- package/lib/notes.js +60 -3
- package/lib/os-users.js +3 -1
- package/lib/project-capsule-catalog.js +9 -1
- package/lib/project-capsule-turn.js +96 -0
- package/lib/project-connection.js +15 -1
- package/lib/project-file-history.js +223 -0
- package/lib/project-file-watch.js +77 -49
- package/lib/project-filesystem.js +31 -220
- package/lib/project-http.js +15 -1
- package/lib/project-knowledge.js +22 -0
- package/lib/project-log-context.js +172 -0
- package/lib/project-log-feedback-delivery.js +118 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-context-state.js +42 -0
- package/lib/project-logs-mcp-server.js +328 -0
- package/lib/project-logs-query.js +185 -0
- package/lib/project-logs-root.js +75 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +463 -0
- package/lib/project-logs-snapshot.js +205 -0
- package/lib/project-logs-store.js +495 -0
- package/lib/project-logs-versioning.js +132 -0
- package/lib/project-logs.js +400 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +22 -0
- package/lib/project-message-delivery.js +70 -0
- package/lib/project-pair-lifecycle.js +460 -0
- package/lib/project-request-access.js +66 -0
- package/lib/project-session-handoff.js +1 -1
- package/lib/project-session-notes.js +64 -13
- package/lib/project-session-pair.js +159 -146
- package/lib/project-session-spawn.js +1 -1
- package/lib/project-sessions.js +58 -13
- package/lib/project-user-message.js +53 -4
- package/lib/project-worker-permission.js +430 -0
- package/lib/project-worker-proposal.js +208 -62
- package/lib/project.js +185 -6
- package/lib/public/app.js +63 -35
- package/lib/public/css/admin.css +2 -2
- package/lib/public/css/capsule-ui.css +38 -0
- package/lib/public/css/command-palette.css +19 -9
- package/lib/public/css/git-placard.css +154 -0
- package/lib/public/css/home-hub.css +4 -0
- package/lib/public/css/home-session-actions.css +66 -0
- package/lib/public/css/home-sidebar.css +66 -0
- package/lib/public/css/input.css +84 -3
- package/lib/public/css/messages.css +40 -1
- package/lib/public/css/mobile-nav.css +80 -0
- package/lib/public/css/notifications-center.css +67 -0
- package/lib/public/css/pane.css +97 -10
- package/lib/public/css/project-logs.css +198 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/session-actions.css +16 -101
- package/lib/public/css/sidebar.css +103 -0
- package/lib/public/css/sticky-notes.css +237 -229
- package/lib/public/css/worker-proposal.css +36 -3
- package/lib/public/index.html +43 -11
- package/lib/public/modules/admin.js +8 -8
- package/lib/public/modules/app-connection.js +124 -6
- package/lib/public/modules/app-home-hub.js +12 -8
- package/lib/public/modules/app-message-cards.js +2 -1
- package/lib/public/modules/app-messages.js +92 -11
- package/lib/public/modules/app-misc.js +2 -14
- package/lib/public/modules/app-notifications.js +11 -7
- package/lib/public/modules/app-panels.js +3 -2
- package/lib/public/modules/app-projects.js +56 -18
- package/lib/public/modules/app-rendering.js +1 -0
- package/lib/public/modules/capsule-preference.js +44 -0
- package/lib/public/modules/chat-bubble-renderer.js +1 -1
- package/lib/public/modules/clay-log-links.js +70 -0
- package/lib/public/modules/command-palette.js +52 -15
- package/lib/public/modules/context-sources.js +0 -3
- package/lib/public/modules/git-agent-sessions.js +85 -0
- package/lib/public/modules/git-panel.js +111 -84
- package/lib/public/modules/git-placard.js +161 -0
- package/lib/public/modules/home-chat-empty-state.js +39 -0
- package/lib/public/modules/home-chat-identity.js +9 -0
- package/lib/public/modules/home-conversations-sheet.js +102 -48
- package/lib/public/modules/home-mate-chat.js +15 -35
- 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-sidebar.js +7 -0
- package/lib/public/modules/home-surface-boot.js +7 -3
- package/lib/public/modules/home-tool-frame.js +182 -0
- package/lib/public/modules/home-tools.js +138 -1
- package/lib/public/modules/input.js +38 -7
- package/lib/public/modules/markdown.js +2 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/message-delivery.js +97 -0
- package/lib/public/modules/paste-modal.js +84 -0
- package/lib/public/modules/project-activation.js +45 -0
- package/lib/public/modules/project-logs-render.js +405 -0
- package/lib/public/modules/project-logs.js +461 -0
- package/lib/public/modules/project-removal-target.js +26 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/session-actions.js +29 -105
- package/lib/public/modules/session-hierarchy.js +54 -0
- package/lib/public/modules/sidebar-mobile.js +40 -15
- package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
- package/lib/public/modules/sidebar-sessions.js +77 -11
- package/lib/public/modules/sidebar.js +17 -5
- package/lib/public/modules/split-group-helpers.js +8 -0
- package/lib/public/modules/split-pair-ui.js +15 -4
- package/lib/public/modules/split-view.js +5 -2
- package/lib/public/modules/split-worker-runtime.js +24 -0
- package/lib/public/modules/sticky-note-markdown.js +5 -0
- package/lib/public/modules/sticky-notes-browser.js +326 -0
- package/lib/public/modules/sticky-notes-card.js +360 -0
- package/lib/public/modules/sticky-notes-editor.js +291 -0
- package/lib/public/modules/sticky-notes-shared.js +90 -0
- package/lib/public/modules/sticky-notes.js +170 -946
- package/lib/public/modules/thinking-lifecycle.js +175 -0
- package/lib/public/modules/thinking-summary.js +28 -0
- package/lib/public/modules/thinking-view.js +75 -0
- package/lib/public/modules/tool-palette-order.js +143 -0
- package/lib/public/modules/tool-palette-overlays.js +159 -0
- package/lib/public/modules/tool-palette.js +21 -188
- package/lib/public/modules/tools.js +31 -123
- package/lib/public/modules/update-snooze.js +169 -0
- package/lib/public/modules/user-settings.js +4 -0
- package/lib/public/modules/worker-pane-lock.js +176 -0
- package/lib/public/modules/worker-proposal-state.js +16 -0
- package/lib/public/modules/worker-proposal.js +49 -20
- package/lib/public/style.css +3 -1
- package/lib/sdk-bridge.js +135 -46
- package/lib/sdk-message-processor.js +36 -19
- package/lib/server-experimental-settings.js +49 -0
- package/lib/server-global-ws.js +11 -0
- package/lib/server-home-chat-events.js +31 -1
- package/lib/server-home-chat.js +27 -4
- package/lib/server-home-clay-entry.js +1 -1
- package/lib/server-home-clay-session-links.js +34 -5
- package/lib/server-settings.js +5 -0
- package/lib/server-tools.js +127 -9
- package/lib/server.js +137 -22
- package/lib/session-driver-eligibility.js +38 -0
- package/lib/session-driver-orchestration.js +31 -0
- package/lib/session-hygiene.js +3 -0
- package/lib/session-notes-mcp-server.js +25 -5
- package/lib/session-pair-factory.js +247 -0
- package/lib/session-pair-mcp-server.js +46 -8
- package/lib/session-pair-prompts.js +79 -0
- package/lib/session-pair-turn-control.js +153 -0
- package/lib/session-provenance.js +119 -0
- package/lib/session-spawn-mcp-server.js +1 -1
- package/lib/session-split-groups.js +4 -1
- package/lib/session-title-policy.js +60 -0
- package/lib/session-visibility.js +41 -0
- package/lib/sessions.js +57 -10
- package/lib/tools-registry.js +89 -10
- package/lib/update-snooze.js +437 -0
- package/lib/users-experimental-preferences.js +30 -0
- package/lib/users-permissions.js +6 -6
- package/lib/users.js +22 -16
- package/lib/workspace-query-access.js +102 -0
- package/lib/workspace-query-service.js +24 -17
- package/lib/worktree.js +25 -38
- package/lib/ws-schema.js +38 -7
- package/lib/yoke/adapters/claude-worker.js +16 -6
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex.js +24 -14
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +2 -2
|
@@ -16,6 +16,12 @@ import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, VENDOR_HOMEPAGES, isExperim
|
|
|
16
16
|
import { openGroup, separateGroup } from './split-view.js';
|
|
17
17
|
import { groupedSessionIds } from './split-group-helpers.js';
|
|
18
18
|
import { openPairDialog } from './split-pair-ui.js';
|
|
19
|
+
import {
|
|
20
|
+
hierarchyItemMatches,
|
|
21
|
+
prepareSidebarHierarchy,
|
|
22
|
+
renderDesktopDriverHierarchy,
|
|
23
|
+
renderDesktopOrphanHierarchy
|
|
24
|
+
} from './sidebar-session-hierarchy.js';
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
// --- Session state ---
|
|
@@ -49,8 +55,8 @@ function sendSessionBookmark(sessionId, bookmarked) {
|
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
function compareSessionListItems(a, b) {
|
|
52
|
-
var aData = a && a.type === "session" ? a.data : a;
|
|
53
|
-
var bData = b && b.type === "session" ? b.data : b;
|
|
58
|
+
var aData = a && (a.type === "session" || a.type === "driver-hierarchy") ? a.data : a;
|
|
59
|
+
var bData = b && (b.type === "session" || b.type === "driver-hierarchy") ? b.data : b;
|
|
54
60
|
var aBookmarked = !!(aData && aData.bookmarked);
|
|
55
61
|
var bBookmarked = !!(bData && bData.bookmarked);
|
|
56
62
|
if (aBookmarked !== bBookmarked) return aBookmarked ? -1 : 1;
|
|
@@ -236,6 +242,14 @@ function collectItemSessionIds(item) {
|
|
|
236
242
|
if (item.type === "split-group" && Array.isArray(item.members)) {
|
|
237
243
|
return item.members.map(function (session) { return session.id; });
|
|
238
244
|
}
|
|
245
|
+
if (item.type === "driver-hierarchy" && item.root) {
|
|
246
|
+
var hierarchyIds = [item.root.driver.id];
|
|
247
|
+
for (var j = 0; j < item.root.workers.length; j++) hierarchyIds.push(item.root.workers[j].id);
|
|
248
|
+
return hierarchyIds;
|
|
249
|
+
}
|
|
250
|
+
if (item.type === "orphan-workers" && Array.isArray(item.workers)) {
|
|
251
|
+
return item.workers.map(function (session) { return session.id; });
|
|
252
|
+
}
|
|
239
253
|
return [];
|
|
240
254
|
}
|
|
241
255
|
|
|
@@ -683,7 +697,7 @@ function showSessionCtxMenu(anchorBtn, sessionId, title, cliSid, sessionData) {
|
|
|
683
697
|
|
|
684
698
|
// Session visibility toggle (only the session owner can change)
|
|
685
699
|
if (store.get('isMultiUserMode') && sessionData && sessionData.ownerId && sessionData.ownerId === store.get('myUserId')) {
|
|
686
|
-
var currentVis = (sessionData && sessionData.sessionVisibility) || "
|
|
700
|
+
var currentVis = (sessionData && sessionData.sessionVisibility) || "private";
|
|
687
701
|
var isPrivate = currentVis === "private";
|
|
688
702
|
var visItem = document.createElement("button");
|
|
689
703
|
visItem.className = "session-ctx-item";
|
|
@@ -1246,10 +1260,12 @@ function renderLoopRun(parentGk, startedAtKey, sessions, isRalph) {
|
|
|
1246
1260
|
|
|
1247
1261
|
// --- Session item rendering ---
|
|
1248
1262
|
|
|
1249
|
-
function renderSessionItem(s) {
|
|
1263
|
+
function renderSessionItem(s, options) {
|
|
1264
|
+
var itemOptions = options || {};
|
|
1250
1265
|
var el = document.createElement("div");
|
|
1251
1266
|
var isMatch = searchMatchIds !== null && searchMatchIds.has(s.id);
|
|
1252
1267
|
el.className = "session-item" + (s.active ? " active" : "") + (isMatch ? " search-match" : "");
|
|
1268
|
+
if (itemOptions.worker) el.classList.add("session-worker-item");
|
|
1253
1269
|
el.dataset.sessionId = s.id;
|
|
1254
1270
|
|
|
1255
1271
|
// Keep agent identity separate from the title so each row has a stable
|
|
@@ -1274,13 +1290,20 @@ function renderSessionItem(s) {
|
|
|
1274
1290
|
if (s.loop && s.loop.source === "debate") {
|
|
1275
1291
|
textHtml += '<span class="session-debate-icon" title="Debate">' + iconHtml("mic") + '</span>';
|
|
1276
1292
|
}
|
|
1277
|
-
if (store.get('isMultiUserMode') && s.sessionVisibility === "
|
|
1278
|
-
textHtml += '<span class="session-
|
|
1293
|
+
if (store.get('isMultiUserMode') && s.sessionVisibility === "shared") {
|
|
1294
|
+
textHtml += '<span class="session-shared-icon" title="Shared session" aria-label="Shared session">' + iconHtml("users") + '</span>';
|
|
1279
1295
|
}
|
|
1280
1296
|
textHtml += highlightMatch(s.title || "New Session", searchQuery);
|
|
1281
1297
|
textSpan.innerHTML = textHtml;
|
|
1282
1298
|
el.appendChild(textSpan);
|
|
1283
1299
|
|
|
1300
|
+
if (itemOptions.worker) {
|
|
1301
|
+
var workerLabel = document.createElement("span");
|
|
1302
|
+
workerLabel.className = "session-worker-generation" + (itemOptions.current ? " current" : "");
|
|
1303
|
+
workerLabel.textContent = itemOptions.current ? "Current" : (s.workerGeneration ? "Gen " + s.workerGeneration : "Worker");
|
|
1304
|
+
el.appendChild(workerLabel);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1284
1307
|
var ageText = relativeTime(s.lastActivity || 0);
|
|
1285
1308
|
if (ageText) {
|
|
1286
1309
|
var age = document.createElement("span");
|
|
@@ -1325,7 +1348,7 @@ function renderSessionItem(s) {
|
|
|
1325
1348
|
|
|
1326
1349
|
// Presence avatars (multi-user)
|
|
1327
1350
|
renderPresenceAvatars(el, String(s.id));
|
|
1328
|
-
setupSessionDragHandlers(el, s);
|
|
1351
|
+
if (!itemOptions.worker) setupSessionDragHandlers(el, s);
|
|
1329
1352
|
|
|
1330
1353
|
return el;
|
|
1331
1354
|
}
|
|
@@ -1376,8 +1399,29 @@ function renderSplitGroupItem(group, members) {
|
|
|
1376
1399
|
|
|
1377
1400
|
// --- Main session list ---
|
|
1378
1401
|
|
|
1402
|
+
// Fingerprint of the last completed render: the whole session payload plus the
|
|
1403
|
+
// two store values this render also reads. Nothing is cherry-picked, so the
|
|
1404
|
+
// guard can only skip a frame that is byte-identical to what is already on
|
|
1405
|
+
// screen. A re-render triggered by other state (sessions === null) always
|
|
1406
|
+
// runs and resets the fingerprint afterwards.
|
|
1407
|
+
var lastRenderFingerprint = null;
|
|
1408
|
+
|
|
1409
|
+
function sessionRenderFingerprint(sessions) {
|
|
1410
|
+
try {
|
|
1411
|
+
return JSON.stringify([sessions, store.get('splitGroups') || [], store.get('splitPanes') || null]);
|
|
1412
|
+
} catch (e) {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1379
1417
|
export function renderSessionList(sessions) {
|
|
1380
|
-
if (sessions)
|
|
1418
|
+
if (sessions) {
|
|
1419
|
+
// A reconnect and a streaming turn both re-send this list unchanged;
|
|
1420
|
+
// rebuilding the sidebar for an identical frame is what made it flicker.
|
|
1421
|
+
var incoming = sessionRenderFingerprint(sessions);
|
|
1422
|
+
if (incoming !== null && incoming === lastRenderFingerprint) return;
|
|
1423
|
+
cachedSessions = sessions;
|
|
1424
|
+
}
|
|
1381
1425
|
|
|
1382
1426
|
// If mobile chat sheet is open, refresh it
|
|
1383
1427
|
if (refreshMobileChatSheet) refreshMobileChatSheet();
|
|
@@ -1388,12 +1432,17 @@ export function renderSessionList(sessions) {
|
|
|
1388
1432
|
// Group by loopId + date so all runs of the same task on the same day are merged
|
|
1389
1433
|
var splitGroups = store.get('splitGroups') || [];
|
|
1390
1434
|
var groupedIds = groupedSessionIds(splitGroups);
|
|
1435
|
+
var hierarchy = prepareSidebarHierarchy(cachedSessions);
|
|
1436
|
+
var hierarchyByDriver = hierarchy.byDriver;
|
|
1437
|
+
var hierarchySessionIds = hierarchy.sessionIds;
|
|
1438
|
+
hierarchySessionIds.forEach(function (id) { groupedIds.delete(id); });
|
|
1391
1439
|
var sessionsById = new Map();
|
|
1392
1440
|
for (var si = 0; si < cachedSessions.length; si++) sessionsById.set(cachedSessions[si].id, cachedSessions[si]);
|
|
1393
1441
|
var loopGroups = {}; // groupKey -> [sessions]
|
|
1394
1442
|
var normalSessions = [];
|
|
1395
1443
|
for (var i = 0; i < cachedSessions.length; i++) {
|
|
1396
1444
|
var s = cachedSessions[i];
|
|
1445
|
+
if (s.sessionRole === "worker") continue;
|
|
1397
1446
|
if (groupedIds.has(s.id)) continue;
|
|
1398
1447
|
if (s.loop && s.loop.loopId && s.loop.role === "crafting" && s.loop.source !== "ralph" && s.loop.source !== "debate") {
|
|
1399
1448
|
// Task crafting sessions live in the scheduler calendar, not the main list (except debate)
|
|
@@ -1412,13 +1461,21 @@ export function renderSessionList(sessions) {
|
|
|
1412
1461
|
// Build virtual items: normal sessions + one entry per loop group (using latest child's lastActivity)
|
|
1413
1462
|
var items = [];
|
|
1414
1463
|
for (var j = 0; j < normalSessions.length; j++) {
|
|
1415
|
-
|
|
1464
|
+
var driverRoot = hierarchyByDriver.get(normalSessions[j].id);
|
|
1465
|
+
if (driverRoot) items.push({ type: "driver-hierarchy", root: driverRoot, data: driverRoot.driver, lastActivity: driverRoot.lastActivity });
|
|
1466
|
+
else items.push({ type: "session", data: normalSessions[j], lastActivity: normalSessions[j].lastActivity || 0 });
|
|
1467
|
+
}
|
|
1468
|
+
if (hierarchy.orphans.length) {
|
|
1469
|
+
var orphanActivity = 0;
|
|
1470
|
+
for (var oi = 0; oi < hierarchy.orphans.length; oi++) orphanActivity = Math.max(orphanActivity, hierarchy.orphans[oi].lastActivity || 0);
|
|
1471
|
+
items.push({ type: "orphan-workers", workers: hierarchy.orphans, lastActivity: orphanActivity });
|
|
1416
1472
|
}
|
|
1417
1473
|
for (var sg = 0; sg < splitGroups.length; sg++) {
|
|
1418
1474
|
var splitGroup = splitGroups[sg];
|
|
1419
1475
|
var leftMember = sessionsById.get(splitGroup.members[0]);
|
|
1420
1476
|
var rightMember = sessionsById.get(splitGroup.members[1]);
|
|
1421
1477
|
if (!leftMember || !rightMember) continue;
|
|
1478
|
+
if (hierarchySessionIds.has(leftMember.id) || hierarchySessionIds.has(rightMember.id)) continue;
|
|
1422
1479
|
items.push({
|
|
1423
1480
|
type: "split-group",
|
|
1424
1481
|
group: splitGroup,
|
|
@@ -1449,9 +1506,10 @@ export function renderSessionList(sessions) {
|
|
|
1449
1506
|
if (item.type === "session" && item.data && !isSessionVisibleBySearch(item.data.id)) {
|
|
1450
1507
|
continue;
|
|
1451
1508
|
}
|
|
1509
|
+
if ((item.type === "driver-hierarchy" || item.type === "orphan-workers") && !hierarchyItemMatches(item, searchMatchIds)) continue;
|
|
1452
1510
|
if (item.type === "split-group" && searchMatchIds !== null &&
|
|
1453
1511
|
!searchMatchIds.has(item.members[0].id) && !searchMatchIds.has(item.members[1].id)) continue;
|
|
1454
|
-
if (item.type === "session" && item.data && item.data.bookmarked) {
|
|
1512
|
+
if ((item.type === "session" || item.type === "driver-hierarchy") && item.data && item.data.bookmarked) {
|
|
1455
1513
|
bookmarkedItems.push(item);
|
|
1456
1514
|
} else {
|
|
1457
1515
|
regularItems.push(item);
|
|
@@ -1468,7 +1526,8 @@ export function renderSessionList(sessions) {
|
|
|
1468
1526
|
favoritesContainer.appendChild(emptyHint);
|
|
1469
1527
|
}
|
|
1470
1528
|
for (var bi = 0; bi < bookmarkedItems.length; bi++) {
|
|
1471
|
-
favoritesContainer.appendChild(
|
|
1529
|
+
if (bookmarkedItems[bi].type === "driver-hierarchy") favoritesContainer.appendChild(renderDesktopDriverHierarchy(bookmarkedItems[bi].root, renderSessionItem, function () { renderSessionList(null); }, searchMatchIds));
|
|
1530
|
+
else favoritesContainer.appendChild(renderSessionItem(bookmarkedItems[bi].data));
|
|
1472
1531
|
}
|
|
1473
1532
|
|
|
1474
1533
|
var divider = document.createElement("div");
|
|
@@ -1508,6 +1567,10 @@ export function renderSessionList(sessions) {
|
|
|
1508
1567
|
}
|
|
1509
1568
|
} else if (item.type === "split-group") {
|
|
1510
1569
|
regularContainer.appendChild(renderSplitGroupItem(item.group, item.members));
|
|
1570
|
+
} else if (item.type === "driver-hierarchy") {
|
|
1571
|
+
regularContainer.appendChild(renderDesktopDriverHierarchy(item.root, renderSessionItem, function () { renderSessionList(null); }, searchMatchIds));
|
|
1572
|
+
} else if (item.type === "orphan-workers") {
|
|
1573
|
+
regularContainer.appendChild(renderDesktopOrphanHierarchy(item.workers, renderSessionItem, function () { renderSessionList(null); }, searchMatchIds));
|
|
1511
1574
|
} else {
|
|
1512
1575
|
regularContainer.appendChild(renderSessionItem(item.data));
|
|
1513
1576
|
}
|
|
@@ -1516,6 +1579,9 @@ export function renderSessionList(sessions) {
|
|
|
1516
1579
|
refreshIcons();
|
|
1517
1580
|
if (updatePageTitle) updatePageTitle();
|
|
1518
1581
|
syncHeaderSearchUi();
|
|
1582
|
+
// Recorded from the sessions actually rendered, so a null-argument re-render
|
|
1583
|
+
// driven by other state refreshes the fingerprint rather than stranding it.
|
|
1584
|
+
lastRenderFingerprint = sessionRenderFingerprint(cachedSessions);
|
|
1519
1585
|
}
|
|
1520
1586
|
|
|
1521
1587
|
// --- Search results ---
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closeNotesBrowser } from './sticky-notes-browser.js';
|
|
2
2
|
import { closeScheduler } from './scheduler.js';
|
|
3
3
|
import { initSidebarSessions } from './sidebar-sessions.js';
|
|
4
4
|
import { focusFileTree } from './filebrowser.js';
|
|
@@ -23,7 +23,7 @@ export function syncResizeHandles() {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function dismissOverlayPanels() {
|
|
26
|
-
|
|
26
|
+
closeNotesBrowser();
|
|
27
27
|
closeScheduler();
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -119,7 +119,10 @@ export function initSidebar(_ctx) {
|
|
|
119
119
|
|
|
120
120
|
// --- Panel switch (sessions / files / projects) ---
|
|
121
121
|
var fileBrowserBtn = ctx.$("file-browser-btn");
|
|
122
|
-
|
|
122
|
+
// Git has no tool-palette tile. The repository placard's More control is
|
|
123
|
+
// the entry point into the same panel, with the same lifecycle.
|
|
124
|
+
var gitPlacard = ctx.$("git-placard");
|
|
125
|
+
var gitPlacardMore = ctx.$("git-placard-more");
|
|
123
126
|
var projectsPanel = ctx.$("sidebar-panel-projects");
|
|
124
127
|
var sessionsPanel = ctx.$("sidebar-panel-sessions");
|
|
125
128
|
var filesPanel = ctx.$("sidebar-panel-files");
|
|
@@ -216,14 +219,23 @@ export function initSidebar(_ctx) {
|
|
|
216
219
|
});
|
|
217
220
|
});
|
|
218
221
|
}
|
|
219
|
-
if (
|
|
220
|
-
|
|
222
|
+
if (gitPlacardMore) {
|
|
223
|
+
gitPlacardMore.addEventListener("click", function () {
|
|
221
224
|
if (gitPanel && !gitPanel.classList.contains("hidden")) {
|
|
222
225
|
hideGitPanel(function () { showSessionsPanel(); });
|
|
223
226
|
}
|
|
224
227
|
else showGitPanel();
|
|
225
228
|
});
|
|
226
229
|
}
|
|
230
|
+
if (gitPlacard && gitPlacardMore) {
|
|
231
|
+
// Clicking the block itself is a pointer convenience only; it forwards to
|
|
232
|
+
// the More control so every listener bound there runs exactly once, and
|
|
233
|
+
// the keyboard path stays the single focusable button.
|
|
234
|
+
gitPlacard.addEventListener("click", function (event) {
|
|
235
|
+
if (event.target.closest("#git-placard-more")) return;
|
|
236
|
+
gitPlacardMore.click();
|
|
237
|
+
});
|
|
238
|
+
}
|
|
227
239
|
if (gitPanelClose) {
|
|
228
240
|
gitPanelClose.addEventListener("click", function () {
|
|
229
241
|
hideGitPanel(function () { showSessionsPanel(); });
|
|
@@ -16,3 +16,11 @@ export function findSplitGroup(groups, memberIds) {
|
|
|
16
16
|
}
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
export function isConfiguredWorker(groups, sessionId) {
|
|
21
|
+
var list = groups || [];
|
|
22
|
+
for (var i = 0; i < list.length; i++) {
|
|
23
|
+
if (list[i].pair && list[i].pair.workerId === sessionId) return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
@@ -3,6 +3,8 @@ import { getWs } from './ws-ref.js';
|
|
|
3
3
|
import { VENDOR_AVATARS } from './app-rendering.js';
|
|
4
4
|
import { buildAgentVendorSelect, fillAgentModels, buildAgentEffortSelect, fillAgentEffort } from './agent-config-selects.js';
|
|
5
5
|
import { showToast } from './utils.js';
|
|
6
|
+
import { getCachedSessions } from './sidebar-sessions.js';
|
|
7
|
+
import { appendWorkerRuntime } from './split-worker-runtime.js';
|
|
6
8
|
|
|
7
9
|
var pairDialog = null;
|
|
8
10
|
// Set when the dialog was opened via "Add Split Worker" on an existing session:
|
|
@@ -190,8 +192,7 @@ export function handlePairCreated(msg) {
|
|
|
190
192
|
|
|
191
193
|
// --- Worker-pane composer notice -------------------------------------
|
|
192
194
|
// Shown inside a pane iframe while ITS session is processing a delegated
|
|
193
|
-
// turn
|
|
194
|
-
// makes it visible that a new message joins the Driver's turn.
|
|
195
|
+
// turn. Identifies the Driver responsible for the current task.
|
|
195
196
|
var workerNoticeEl = null;
|
|
196
197
|
|
|
197
198
|
export function showWorkerDelegationNotice(driverTitle) {
|
|
@@ -205,7 +206,7 @@ export function showWorkerDelegationNotice(driverTitle) {
|
|
|
205
206
|
inputArea.insertBefore(workerNoticeEl, inputWrapper);
|
|
206
207
|
}
|
|
207
208
|
var who = driverTitle ? "“" + driverTitle + "”" : "the Driver";
|
|
208
|
-
workerNoticeEl.textContent = "
|
|
209
|
+
workerNoticeEl.textContent = "Working on a task from " + who + ".";
|
|
209
210
|
workerNoticeEl.classList.add("visible");
|
|
210
211
|
}
|
|
211
212
|
|
|
@@ -239,8 +240,10 @@ export function syncPairChrome(host, split) {
|
|
|
239
240
|
for (var i = 0; i < groups.length; i++) {
|
|
240
241
|
if (groups[i].id === split.groupId) { group = groups[i]; break; }
|
|
241
242
|
}
|
|
242
|
-
var oldBadges = host.querySelectorAll(".split-pair-role, .split-pair-live, .split-pair-set-driver");
|
|
243
|
+
var oldBadges = host.querySelectorAll(".split-pair-role, .split-pair-live, .split-pair-set-driver, .split-worker-runtime");
|
|
243
244
|
for (var bi = 0; bi < oldBadges.length; bi++) oldBadges[bi].remove();
|
|
245
|
+
var runtimeHeaders = host.querySelectorAll(".has-worker-runtime");
|
|
246
|
+
for (var ri = 0; ri < runtimeHeaders.length; ri++) runtimeHeaders[ri].classList.remove("has-worker-runtime");
|
|
244
247
|
host.classList.remove("split-delegating", "split-direction-right", "split-direction-left");
|
|
245
248
|
if (!group) return;
|
|
246
249
|
var headers = host.querySelectorAll(".split-pane-header");
|
|
@@ -272,6 +275,14 @@ export function syncPairChrome(host, split) {
|
|
|
272
275
|
var title = header.querySelector(".split-pane-title");
|
|
273
276
|
var access = header.querySelector(".split-pane-full-access");
|
|
274
277
|
header.insertBefore(badge, access ? access.nextSibling : (title ? title.nextSibling : null));
|
|
278
|
+
if (!isDriver) {
|
|
279
|
+
var sessions = getCachedSessions() || [];
|
|
280
|
+
var workerSession = null;
|
|
281
|
+
for (var wi = 0; wi < sessions.length; wi++) {
|
|
282
|
+
if (sessions[wi].id === sessionId) { workerSession = sessions[wi]; break; }
|
|
283
|
+
}
|
|
284
|
+
appendWorkerRuntime(header, workerSession);
|
|
285
|
+
}
|
|
275
286
|
})(split.panes[pi].sessionId, headers[pi]);
|
|
276
287
|
}
|
|
277
288
|
var active = (store.get('splitDelegations') || {})[group.id];
|
|
@@ -7,7 +7,7 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
7
7
|
import { detachTuiView } from './session-tui-view.js';
|
|
8
8
|
import { formatTokens } from './app-panels.js';
|
|
9
9
|
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
10
|
-
import { groupedSessionIds, findSplitGroup } from './split-group-helpers.js';
|
|
10
|
+
import { groupedSessionIds, findSplitGroup, isConfiguredWorker } from './split-group-helpers.js';
|
|
11
11
|
import { showConfirm } from './app-misc.js';
|
|
12
12
|
import { syncPairChrome } from './split-pair-ui.js';
|
|
13
13
|
import { presentMarkdownEdit } from './filebrowser.js';
|
|
@@ -159,7 +159,10 @@ export function syncPaneTitles() {
|
|
|
159
159
|
function updatePaneFullAccessButton(button, session) {
|
|
160
160
|
if (!button) return;
|
|
161
161
|
var mode = session && (session.runtimeMode || session.mode || "gui");
|
|
162
|
-
var
|
|
162
|
+
var worker = !!session && isConfiguredWorker(store.get('splitGroups'), session.id);
|
|
163
|
+
// Permission policy belongs to the Driver. A configured Worker inherits it
|
|
164
|
+
// server-side and must not present a second, misleading control.
|
|
165
|
+
var visible = !!session && !worker && !store.get('skipPermsEnabled') && mode === "gui";
|
|
163
166
|
var enabled = visible && session.permissionMode === "bypassPermissions";
|
|
164
167
|
button.classList.toggle("hidden", !visible);
|
|
165
168
|
button.classList.toggle("active", enabled);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Read the Worker's own session metadata, never the active Driver's settings.
|
|
2
|
+
export function workerRuntimeLabels(session) {
|
|
3
|
+
var model = session && typeof session.model === "string" ? session.model : "";
|
|
4
|
+
var effort = session && typeof session.effort === "string" ? session.effort : "";
|
|
5
|
+
var level = effort === "xhigh" ? "X-High" : (effort ? effort.charAt(0).toUpperCase() + effort.slice(1) : "Default");
|
|
6
|
+
return { model: model || "Default model", thinking: "Thinking: " + level };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function appendWorkerRuntime(header, session) {
|
|
10
|
+
var labels = workerRuntimeLabels(session);
|
|
11
|
+
var runtime = document.createElement("div");
|
|
12
|
+
runtime.className = "split-worker-runtime";
|
|
13
|
+
var model = document.createElement("span");
|
|
14
|
+
model.className = "split-worker-runtime-model";
|
|
15
|
+
model.textContent = labels.model;
|
|
16
|
+
model.title = "Model: " + labels.model;
|
|
17
|
+
var thinking = document.createElement("span");
|
|
18
|
+
thinking.className = "split-worker-runtime-thinking";
|
|
19
|
+
thinking.textContent = labels.thinking;
|
|
20
|
+
runtime.appendChild(model);
|
|
21
|
+
runtime.appendChild(thinking);
|
|
22
|
+
header.classList.add("has-worker-runtime");
|
|
23
|
+
header.appendChild(runtime);
|
|
24
|
+
}
|
|
@@ -58,6 +58,11 @@ function nodeToMarkdown(node) {
|
|
|
58
58
|
return "\n" + inner;
|
|
59
59
|
case "P": return "\n" + inner;
|
|
60
60
|
case "A": return node.getAttribute("href") || inner;
|
|
61
|
+
case "BUTTON":
|
|
62
|
+
if (node.classList.contains("clayos-log-link") && node.dataset && node.dataset.logRef) {
|
|
63
|
+
return "`" + node.dataset.logRef + "`";
|
|
64
|
+
}
|
|
65
|
+
return inner;
|
|
61
66
|
case "SPAN":
|
|
62
67
|
if (node.classList.contains("sn-check")) {
|
|
63
68
|
return node.classList.contains("checked") ? "- [x]" : "- [ ]";
|