clay-server 3.4.0-beta.8 → 3.4.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/daemon-projects.js +3 -3
- package/lib/daemon.js +59 -59
- package/lib/project-connection.js +19 -6
- package/lib/project-models.js +220 -0
- package/lib/project-session-handoff.js +162 -0
- package/lib/project-session-pair.js +14 -7
- package/lib/project-session-spawn.js +1 -1
- package/lib/project-sessions.js +13 -45
- package/lib/project-worker-proposal.js +51 -14
- package/lib/project.js +35 -79
- package/lib/public/app.js +11 -0
- package/lib/public/copilot-avatar.svg +5 -0
- package/lib/public/css/command-palette.css +22 -2
- package/lib/public/css/filebrowser.css +6 -1
- package/lib/public/css/icon-strip.css +29 -13
- package/lib/public/css/input.css +56 -0
- package/lib/public/css/mates.css +6 -0
- package/lib/public/css/menus.css +35 -56
- package/lib/public/css/pane.css +18 -3
- package/lib/public/css/session-actions.css +98 -0
- package/lib/public/grok-avatar.svg +4 -0
- package/lib/public/index.html +26 -9
- package/lib/public/junie-avatar.svg +11 -0
- package/lib/public/kimi-avatar.svg +4 -0
- package/lib/public/modules/agent-config-selects.js +69 -0
- package/lib/public/modules/app-connection.js +6 -0
- package/lib/public/modules/app-header.js +0 -22
- package/lib/public/modules/app-messages.js +48 -9
- package/lib/public/modules/app-panels.js +33 -82
- package/lib/public/modules/app-projects.js +3 -1
- package/lib/public/modules/app-rendering.js +16 -1
- package/lib/public/modules/background-tasks-ui.js +55 -0
- package/lib/public/modules/filebrowser-tabs.js +65 -0
- package/lib/public/modules/filebrowser.js +23 -3
- package/lib/public/modules/mate-sidebar.js +10 -2
- package/lib/public/modules/model-picker.js +263 -0
- package/lib/public/modules/pane-bridge.js +6 -0
- package/lib/public/modules/project-switcher.js +7 -6
- package/lib/public/modules/session-actions.js +294 -0
- package/lib/public/modules/sidebar-mobile.js +2 -1
- package/lib/public/modules/sidebar-projects.js +34 -43
- package/lib/public/modules/sidebar-sessions.js +17 -1
- package/lib/public/modules/split-pair-ui.js +16 -77
- package/lib/public/modules/split-view.js +11 -1
- package/lib/public/modules/tools.js +5 -0
- package/lib/public/modules/vendor-priority.js +6 -1
- package/lib/public/modules/worker-proposal.js +6 -1
- package/lib/public/modules/worktree-location.js +17 -0
- package/lib/public/qwen-avatar.svg +4 -0
- package/lib/public/style.css +1 -0
- package/lib/sdk-bridge.js +57 -34
- package/lib/sdk-message-processor.js +26 -4
- package/lib/session-handoff-context.js +110 -0
- package/lib/session-notes-mcp-server.js +1 -0
- package/lib/sessions.js +4 -0
- package/lib/worktree.js +9 -4
- package/lib/ws-schema.js +9 -1
- package/lib/yoke/acp-agent-profiles.js +64 -0
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/claude.js +34 -0
- package/lib/yoke/adapters/codex.js +38 -3
- package/lib/yoke/adapters/copilot.js +7 -0
- package/lib/yoke/adapters/grok.js +7 -0
- package/lib/yoke/adapters/junie.js +7 -0
- package/lib/yoke/adapters/kimi.js +7 -0
- package/lib/yoke/adapters/kiro.js +4 -3
- package/lib/yoke/adapters/qwen.js +7 -0
- package/lib/yoke/codex-background-tasks.js +84 -0
- package/lib/yoke/index.js +43 -14
- package/lib/yoke/instructions.js +3 -0
- package/lib/yoke/interface.js +21 -0
- package/lib/yoke/vendor-registry.js +55 -0
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ import { showIconTooltip, hideIconTooltip, closeUserCtxMenu, getCurrentDmUserId
|
|
|
13
13
|
import { switchProject, openAddProjectModal, getCachedProjects } from './app-projects.js';
|
|
14
14
|
import { showHomeHub } from './app-home-hub.js';
|
|
15
15
|
import { getPendingTuiAttention } from './app-notifications.js';
|
|
16
|
+
import { isExternalWorktree, externalWorktreeTooltip, appendExternalWorktreeBadge } from './worktree-location.js';
|
|
16
17
|
|
|
17
18
|
// --- Project state ---
|
|
18
19
|
var cachedProjectList = [];
|
|
@@ -489,7 +490,7 @@ export function closeProjectCtxMenu() {
|
|
|
489
490
|
}
|
|
490
491
|
}
|
|
491
492
|
|
|
492
|
-
function showIconCtxMenu(anchorEl, slug, name) {
|
|
493
|
+
function showIconCtxMenu(anchorEl, slug, name, options) {
|
|
493
494
|
closeProjectCtxMenu();
|
|
494
495
|
if (closeUserCtxMenu) closeUserCtxMenu();
|
|
495
496
|
closeEmojiPicker();
|
|
@@ -510,17 +511,19 @@ function showIconCtxMenu(anchorEl, slug, name) {
|
|
|
510
511
|
menu.appendChild(iconItem);
|
|
511
512
|
|
|
512
513
|
if (isWorktree) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
getWs().
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
514
|
+
if (!options || options.canRemoveWorktree !== false) {
|
|
515
|
+
var removeWtItem = document.createElement("button");
|
|
516
|
+
removeWtItem.className = "project-ctx-item project-ctx-delete";
|
|
517
|
+
removeWtItem.innerHTML = iconHtml("trash-2") + " <span>Remove Worktree</span>";
|
|
518
|
+
removeWtItem.addEventListener("click", function (e) {
|
|
519
|
+
e.stopPropagation();
|
|
520
|
+
closeProjectCtxMenu();
|
|
521
|
+
if (getWs() && store.get('connected')) {
|
|
522
|
+
getWs().send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name || slug }));
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
menu.appendChild(removeWtItem);
|
|
526
|
+
}
|
|
524
527
|
} else {
|
|
525
528
|
var wtItem = document.createElement("button");
|
|
526
529
|
wtItem.className = "project-ctx-item";
|
|
@@ -1253,8 +1256,8 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1253
1256
|
(function (wt) {
|
|
1254
1257
|
var wtEl = document.createElement("a");
|
|
1255
1258
|
var isWtActive = wt.slug === currentSlug && !currentDmUserId;
|
|
1256
|
-
var
|
|
1257
|
-
wtEl.className = "icon-strip-wt-item" + (isWtActive ? " active" : "") + (
|
|
1259
|
+
var isExternal = isExternalWorktree(wt);
|
|
1260
|
+
wtEl.className = "icon-strip-wt-item" + (isWtActive ? " active" : "") + (isExternal ? " wt-external" : "");
|
|
1258
1261
|
wtEl.href = "/p/" + wt.slug + "/";
|
|
1259
1262
|
wtEl.dataset.slug = wt.slug;
|
|
1260
1263
|
|
|
@@ -1276,42 +1279,28 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1276
1279
|
if (wt.isProcessing) wtStatus.classList.add("processing");
|
|
1277
1280
|
wtEl.appendChild(wtStatus);
|
|
1278
1281
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1282
|
+
if (isExternal) appendExternalWorktreeBadge(wtEl, "worktree-external-badge");
|
|
1283
|
+
|
|
1284
|
+
var tooltipText = isExternal ? externalWorktreeTooltip(wt.name) : wt.name;
|
|
1283
1285
|
(function (text, elem) {
|
|
1284
1286
|
elem.addEventListener("mouseenter", function () { showIconTooltip(elem, text); });
|
|
1285
1287
|
elem.addEventListener("mouseleave", hideIconTooltip);
|
|
1286
1288
|
})(tooltipText, wtEl);
|
|
1287
1289
|
|
|
1288
|
-
|
|
1289
|
-
(function (slug) {
|
|
1290
|
-
wtEl.addEventListener("click", function (e) {
|
|
1291
|
-
e.preventDefault();
|
|
1292
|
-
if (switchProject) switchProject(slug);
|
|
1293
|
-
});
|
|
1294
|
-
})(wt.slug);
|
|
1295
|
-
} else {
|
|
1290
|
+
(function (slug) {
|
|
1296
1291
|
wtEl.addEventListener("click", function (e) {
|
|
1297
1292
|
e.preventDefault();
|
|
1293
|
+
if (switchProject) switchProject(slug);
|
|
1298
1294
|
});
|
|
1299
|
-
}
|
|
1295
|
+
})(wt.slug);
|
|
1300
1296
|
|
|
1301
|
-
|
|
1302
|
-
(function (
|
|
1303
|
-
elem.addEventListener("contextmenu", function (e) {
|
|
1304
|
-
e.preventDefault();
|
|
1305
|
-
e.stopPropagation();
|
|
1306
|
-
showIconCtxMenu(elem, slug, name);
|
|
1307
|
-
});
|
|
1308
|
-
})(wt.slug, wt.name, wtEl);
|
|
1309
|
-
} else {
|
|
1310
|
-
wtEl.addEventListener("contextmenu", function (e) {
|
|
1297
|
+
(function (slug, name, elem, external) {
|
|
1298
|
+
elem.addEventListener("contextmenu", function (e) {
|
|
1311
1299
|
e.preventDefault();
|
|
1312
1300
|
e.stopPropagation();
|
|
1301
|
+
showIconCtxMenu(elem, slug, name, { canRemoveWorktree: !external });
|
|
1313
1302
|
});
|
|
1314
|
-
}
|
|
1303
|
+
})(wt.slug, wt.name, wtEl, isExternal);
|
|
1315
1304
|
|
|
1316
1305
|
if (!isWtActive && (wt.pendingPermissions > 0 || getPendingTuiAttention(wt.slug) > 0)) {
|
|
1317
1306
|
wtEl.classList.add("has-pending-perm");
|
|
@@ -1360,7 +1349,10 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1360
1349
|
|
|
1361
1350
|
renderProjectList(projects, currentSlug);
|
|
1362
1351
|
|
|
1363
|
-
|
|
1352
|
+
var iconNodes = [container];
|
|
1353
|
+
var mobileProjectList = document.getElementById("project-list");
|
|
1354
|
+
if (mobileProjectList) iconNodes.push(mobileProjectList);
|
|
1355
|
+
try { lucide.createIcons({ nodes: iconNodes }); } catch (e) {}
|
|
1364
1356
|
}
|
|
1365
1357
|
|
|
1366
1358
|
function renderProjectList(projects, currentSlug) {
|
|
@@ -1401,11 +1393,10 @@ function renderProjectList(projects, currentSlug) {
|
|
|
1401
1393
|
var wtList = document.createElement("div");
|
|
1402
1394
|
wtList.className = "mobile-folder-items";
|
|
1403
1395
|
for (var wi = 0; wi < worktrees.length; wi++) {
|
|
1404
|
-
var isAccessible = worktrees[wi].worktreeAccessible !== false;
|
|
1405
1396
|
var wtItem = createMobileProjectItem(worktrees[wi], currentSlug, true);
|
|
1406
|
-
if (
|
|
1407
|
-
|
|
1408
|
-
wtItem
|
|
1397
|
+
if (isExternalWorktree(worktrees[wi])) {
|
|
1398
|
+
wtItem.classList.add("wt-external");
|
|
1399
|
+
appendExternalWorktreeBadge(wtItem, "mobile-worktree-external-badge");
|
|
1409
1400
|
}
|
|
1410
1401
|
wtList.appendChild(wtItem);
|
|
1411
1402
|
}
|
|
@@ -12,7 +12,7 @@ import { dismissOverlayPanels, closeSidebar, updatePageTitle, spawnDustParticles
|
|
|
12
12
|
import { showConfirm } from './app-misc.js';
|
|
13
13
|
import { getUpcomingSchedules } from './scheduler.js';
|
|
14
14
|
import { refreshMobileChatSheet } from './sidebar-mobile.js';
|
|
15
|
-
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, VENDOR_HOMEPAGES } from './app-rendering.js';
|
|
15
|
+
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, VENDOR_HOMEPAGES, isExperimentalVendor } from './app-rendering.js';
|
|
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';
|
|
@@ -394,10 +394,12 @@ function showNewSessionMenu(anchorBtn, defaultVendor) {
|
|
|
394
394
|
item.type = "button";
|
|
395
395
|
item.innerHTML = '<img src="' + VENDOR_AVATARS[vendor] + '" class="session-top-action-icon" alt="">' +
|
|
396
396
|
'<span class="session-new-vendor-name">' + name + '</span>' +
|
|
397
|
+
(isExperimentalVendor(vendor) ? '<span class="vendor-experimental-badge" aria-label="Experimental integration" title="Experimental integration; not yet validated through direct use testing">🧪</span>' : '') +
|
|
397
398
|
(isInstalled ? "" : '<span class="session-new-vendor-note">Not installed</span>' + iconHtml("external-link"));
|
|
398
399
|
item.title = isInstalled
|
|
399
400
|
? "New " + name + " session"
|
|
400
401
|
: name + " is not installed - open " + VENDOR_HOMEPAGES[vendor];
|
|
402
|
+
if (isExperimentalVendor(vendor)) item.title += " · Experimental integration; not yet validated through direct use testing";
|
|
401
403
|
item.addEventListener("click", function (e) {
|
|
402
404
|
e.stopPropagation();
|
|
403
405
|
closeSessionCtxMenu();
|
|
@@ -975,6 +977,9 @@ function renderLoopChild(s) {
|
|
|
975
977
|
if (s.isProcessing) {
|
|
976
978
|
textHtml += '<span class="session-processing"></span>';
|
|
977
979
|
}
|
|
980
|
+
if (s.backgroundTaskCount) {
|
|
981
|
+
textHtml += '<span class="session-background-task-count">' + s.backgroundTaskCount + '</span>';
|
|
982
|
+
}
|
|
978
983
|
if (s.loop) {
|
|
979
984
|
var isRalphChild = s.loop.source === "ralph";
|
|
980
985
|
var roleName = s.loop.role === "crafting" ? "Crafting" : s.loop.role === "judge" ? "Judge" : (isRalphChild ? "Coder" : "Run");
|
|
@@ -1094,6 +1099,9 @@ function renderLoopGroup(loopId, children, groupKey) {
|
|
|
1094
1099
|
if (anyProcessing) {
|
|
1095
1100
|
textHtml += '<span class="session-processing"></span>';
|
|
1096
1101
|
}
|
|
1102
|
+
var groupBackgroundTaskCount = 0;
|
|
1103
|
+
for (var bi = 0; bi < children.length; bi++) groupBackgroundTaskCount += children[bi].backgroundTaskCount || 0;
|
|
1104
|
+
if (groupBackgroundTaskCount) textHtml += '<span class="session-background-task-count">' + groupBackgroundTaskCount + '</span>';
|
|
1097
1105
|
var groupIcon = isDebate ? "mic" : (isRalph ? "repeat" : "calendar-clock");
|
|
1098
1106
|
var iconClass = isDebate ? " debate" : (isRalph ? "" : " scheduled");
|
|
1099
1107
|
textHtml += '<span class="session-loop-icon' + iconClass + '">' + iconHtml(groupIcon) + '</span>';
|
|
@@ -1203,6 +1211,9 @@ function renderLoopRun(parentGk, startedAtKey, sessions, isRalph) {
|
|
|
1203
1211
|
if (anyProcessing) {
|
|
1204
1212
|
textHtml += '<span class="session-processing"></span>';
|
|
1205
1213
|
}
|
|
1214
|
+
var runBackgroundTaskCount = 0;
|
|
1215
|
+
for (var bi = 0; bi < sessions.length; bi++) runBackgroundTaskCount += sessions[bi].backgroundTaskCount || 0;
|
|
1216
|
+
if (runBackgroundTaskCount) textHtml += '<span class="session-background-task-count">' + runBackgroundTaskCount + '</span>';
|
|
1206
1217
|
textHtml += '<span class="session-loop-run-time">' + escapeHtml(timeLabel) + '</span>';
|
|
1207
1218
|
textHtml += '<span class="session-loop-count' + (isRalph ? "" : " scheduled") + '">' + sessions.length + '</span>';
|
|
1208
1219
|
textSpan.innerHTML = textHtml;
|
|
@@ -1252,6 +1263,9 @@ function renderSessionItem(s) {
|
|
|
1252
1263
|
if (s.isProcessing) {
|
|
1253
1264
|
textHtml += '<span class="session-processing"></span>';
|
|
1254
1265
|
}
|
|
1266
|
+
if (s.backgroundTaskCount) {
|
|
1267
|
+
textHtml += '<span class="session-background-task-count">' + s.backgroundTaskCount + '</span>';
|
|
1268
|
+
}
|
|
1255
1269
|
if (s.loop && s.loop.source === "debate") {
|
|
1256
1270
|
textHtml += '<span class="session-debate-icon" title="Debate">' + iconHtml("mic") + '</span>';
|
|
1257
1271
|
}
|
|
@@ -1320,6 +1334,8 @@ function renderSplitGroupItem(group, members) {
|
|
|
1320
1334
|
}
|
|
1321
1335
|
html += "</span>";
|
|
1322
1336
|
if (members[0].isProcessing || members[1].isProcessing) html += '<span class="session-processing"></span>';
|
|
1337
|
+
var splitBackgroundTaskCount = (members[0].backgroundTaskCount || 0) + (members[1].backgroundTaskCount || 0);
|
|
1338
|
+
if (splitBackgroundTaskCount) html += '<span class="session-background-task-count">' + splitBackgroundTaskCount + '</span>';
|
|
1323
1339
|
html += '<span class="split-group-name">' + highlightMatch(group.name || "Split", searchQuery) + "</span>";
|
|
1324
1340
|
text.innerHTML = html;
|
|
1325
1341
|
el.appendChild(text);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
2
|
import { getWs } from './ws-ref.js';
|
|
3
|
-
import { VENDOR_AVATARS
|
|
4
|
-
import {
|
|
3
|
+
import { VENDOR_AVATARS } from './app-rendering.js';
|
|
4
|
+
import { buildAgentVendorSelect, fillAgentModels, buildAgentEffortSelect, fillAgentEffort } from './agent-config-selects.js';
|
|
5
5
|
import { showToast } from './utils.js';
|
|
6
6
|
|
|
7
7
|
var pairDialog = null;
|
|
@@ -9,77 +9,14 @@ var pairDialog = null;
|
|
|
9
9
|
// that session becomes the Driver and the dialog only configures the Worker.
|
|
10
10
|
var pendingDriver = null;
|
|
11
11
|
|
|
12
|
-
function optionValue(entry) {
|
|
13
|
-
if (typeof entry === "string") return entry;
|
|
14
|
-
return entry && (entry.value || entry.id) || "";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function optionLabel(entry) {
|
|
18
|
-
if (typeof entry === "string") return entry;
|
|
19
|
-
return entry && (entry.displayName || entry.name || entry.value || entry.id) || "";
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function fillModels(select, vendor, options) {
|
|
23
|
-
var models = (options.modelsByVendor && options.modelsByVendor[vendor]) || [];
|
|
24
|
-
select.innerHTML = "";
|
|
25
|
-
var automatic = document.createElement("option");
|
|
26
|
-
automatic.value = "";
|
|
27
|
-
automatic.textContent = "Automatic";
|
|
28
|
-
select.appendChild(automatic);
|
|
29
|
-
for (var i = 0; i < models.length; i++) {
|
|
30
|
-
var option = document.createElement("option");
|
|
31
|
-
option.value = optionValue(models[i]);
|
|
32
|
-
option.textContent = optionLabel(models[i]);
|
|
33
|
-
select.appendChild(option);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
12
|
function closePairDialog() {
|
|
38
13
|
if (pairDialog) pairDialog.remove();
|
|
39
14
|
pairDialog = null;
|
|
40
15
|
}
|
|
41
16
|
|
|
42
|
-
function buildVendorSelect(installed, preferred) {
|
|
43
|
-
var select = document.createElement("select");
|
|
44
|
-
select.className = "wt-modal-input";
|
|
45
|
-
for (var i = 0; i < VENDOR_ORDER.length; i++) {
|
|
46
|
-
if (installed.indexOf(VENDOR_ORDER[i]) === -1) continue;
|
|
47
|
-
var option = document.createElement("option");
|
|
48
|
-
option.value = VENDOR_ORDER[i];
|
|
49
|
-
option.textContent = VENDOR_NAMES[VENDOR_ORDER[i]] || VENDOR_ORDER[i];
|
|
50
|
-
select.appendChild(option);
|
|
51
|
-
}
|
|
52
|
-
if (preferred && installed.indexOf(preferred) !== -1) select.value = preferred;
|
|
53
|
-
return select;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
17
|
// Effort levels are vendor- and model-specific (codex: minimal..xhigh,
|
|
57
18
|
// claude/kiro: low..max, plus per-model supportedEffortLevels overrides), so
|
|
58
19
|
// options are rebuilt whenever the role's vendor or model changes.
|
|
59
|
-
function fillEffortOptions(select, vendor, options, modelValue) {
|
|
60
|
-
var previous = select.value;
|
|
61
|
-
var models = (options.modelsByVendor && options.modelsByVendor[vendor]) || [];
|
|
62
|
-
var levels = effortLevelsFor(vendor, models, modelValue);
|
|
63
|
-
select.innerHTML = "";
|
|
64
|
-
var automatic = document.createElement("option");
|
|
65
|
-
automatic.value = "";
|
|
66
|
-
automatic.textContent = "Default";
|
|
67
|
-
select.appendChild(automatic);
|
|
68
|
-
for (var i = 0; i < levels.length; i++) {
|
|
69
|
-
var option = document.createElement("option");
|
|
70
|
-
option.value = levels[i];
|
|
71
|
-
option.textContent = effortDisplayName(levels[i]);
|
|
72
|
-
select.appendChild(option);
|
|
73
|
-
}
|
|
74
|
-
select.value = levels.indexOf(previous) !== -1 ? previous : "";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function buildEffortSelect() {
|
|
78
|
-
var select = document.createElement("select");
|
|
79
|
-
select.className = "wt-modal-input";
|
|
80
|
-
return select;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
20
|
function fieldLabel(text, control) {
|
|
84
21
|
var label = document.createElement("label");
|
|
85
22
|
label.className = "wt-modal-label";
|
|
@@ -154,25 +91,25 @@ export function showPairDialog(options) {
|
|
|
154
91
|
: "One Driver plans and directs a visible Worker session.";
|
|
155
92
|
modal.appendChild(desc);
|
|
156
93
|
|
|
157
|
-
var driverVendor =
|
|
94
|
+
var driverVendor = buildAgentVendorSelect(installed, installed.indexOf("claude") !== -1 ? "claude" : installed[0]);
|
|
158
95
|
var workerDefault = options.lastVendor && options.lastVendor !== driverVendor.value ? options.lastVendor : (installed.indexOf("codex") !== -1 ? "codex" : installed[0]);
|
|
159
|
-
var workerVendor =
|
|
96
|
+
var workerVendor = buildAgentVendorSelect(installed, workerDefault);
|
|
160
97
|
var driverModel = document.createElement("select");
|
|
161
98
|
driverModel.className = "wt-modal-input";
|
|
162
99
|
var workerModel = document.createElement("select");
|
|
163
100
|
workerModel.className = "wt-modal-input";
|
|
164
|
-
var driverEffort =
|
|
165
|
-
var workerEffort =
|
|
166
|
-
function refreshDriverEffort() {
|
|
167
|
-
function refreshWorkerEffort() {
|
|
168
|
-
|
|
169
|
-
|
|
101
|
+
var driverEffort = buildAgentEffortSelect();
|
|
102
|
+
var workerEffort = buildAgentEffortSelect();
|
|
103
|
+
function refreshDriverEffort() { fillAgentEffort(driverEffort, driverVendor.value, options, driverModel.value); }
|
|
104
|
+
function refreshWorkerEffort() { fillAgentEffort(workerEffort, workerVendor.value, options, workerModel.value); }
|
|
105
|
+
fillAgentModels(driverModel, driverVendor.value, options);
|
|
106
|
+
fillAgentModels(workerModel, workerVendor.value, options);
|
|
170
107
|
refreshDriverEffort();
|
|
171
108
|
refreshWorkerEffort();
|
|
172
109
|
workerEffort.value = "medium";
|
|
173
110
|
if (workerEffort.value !== "medium") workerEffort.value = "";
|
|
174
|
-
driverVendor.addEventListener("change", function () {
|
|
175
|
-
workerVendor.addEventListener("change", function () {
|
|
111
|
+
driverVendor.addEventListener("change", function () { fillAgentModels(driverModel, driverVendor.value, options); refreshDriverEffort(); });
|
|
112
|
+
workerVendor.addEventListener("change", function () { fillAgentModels(workerModel, workerVendor.value, options); refreshWorkerEffort(); });
|
|
176
113
|
driverModel.addEventListener("change", refreshDriverEffort);
|
|
177
114
|
workerModel.addEventListener("change", refreshWorkerEffort);
|
|
178
115
|
|
|
@@ -318,7 +255,8 @@ export function syncPairChrome(host, split) {
|
|
|
318
255
|
setBtn.title = "Make this session the Driver; the other pane becomes its Worker";
|
|
319
256
|
setBtn.addEventListener("click", function () { sendSetPair(group.id, paneSessionId); });
|
|
320
257
|
var titleEl = header.querySelector(".split-pane-title");
|
|
321
|
-
|
|
258
|
+
var accessEl = header.querySelector(".split-pane-full-access");
|
|
259
|
+
header.insertBefore(setBtn, accessEl ? accessEl.nextSibling : (titleEl ? titleEl.nextSibling : null));
|
|
322
260
|
})(split.panes[ai].sessionId, headers[ai]);
|
|
323
261
|
}
|
|
324
262
|
return;
|
|
@@ -338,7 +276,8 @@ export function syncPairChrome(host, split) {
|
|
|
338
276
|
sendSetPair(group.id, isDriver ? null : sessionId);
|
|
339
277
|
});
|
|
340
278
|
var title = header.querySelector(".split-pane-title");
|
|
341
|
-
|
|
279
|
+
var access = header.querySelector(".split-pane-full-access");
|
|
280
|
+
header.insertBefore(badge, access ? access.nextSibling : (title ? title.nextSibling : null));
|
|
342
281
|
})(split.panes[pi].sessionId, headers[pi]);
|
|
343
282
|
}
|
|
344
283
|
var active = (store.get('splitDelegations') || {})[group.id];
|
|
@@ -10,6 +10,7 @@ import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
|
10
10
|
import { groupedSessionIds, findSplitGroup } from './split-group-helpers.js';
|
|
11
11
|
import { showConfirm } from './app-misc.js';
|
|
12
12
|
import { syncPairChrome } from './split-pair-ui.js';
|
|
13
|
+
import { presentMarkdownEdit } from './filebrowser.js';
|
|
13
14
|
|
|
14
15
|
var host = null;
|
|
15
16
|
var nativeApp = null;
|
|
@@ -231,6 +232,9 @@ function createPane(pane, index) {
|
|
|
231
232
|
}, "Skip Permissions", true);
|
|
232
233
|
});
|
|
233
234
|
header.appendChild(fullAccess);
|
|
235
|
+
// Permission state belongs to the session identity on the left. Keep it
|
|
236
|
+
// immediately after the title instead of grouping it with usage and close.
|
|
237
|
+
header.insertBefore(fullAccess, ctxChip);
|
|
234
238
|
|
|
235
239
|
var close = document.createElement("button");
|
|
236
240
|
close.type = "button";
|
|
@@ -266,7 +270,13 @@ function updatePaneContextChip(paneEl, msg) {
|
|
|
266
270
|
function handlePaneMessage(event) {
|
|
267
271
|
if (event.origin !== window.location.origin) return;
|
|
268
272
|
var msg = event.data;
|
|
269
|
-
if (!msg ||
|
|
273
|
+
if (!msg || !host) return;
|
|
274
|
+
if (msg.type === "clay-pane-present-markdown") {
|
|
275
|
+
var present = msg.message;
|
|
276
|
+
if (present) presentMarkdownEdit(present);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (msg.type !== "clay-pane-context") return;
|
|
270
280
|
var frames = host.querySelectorAll(".split-pane-frame");
|
|
271
281
|
for (var i = 0; i < frames.length; i++) {
|
|
272
282
|
if (frames[i].contentWindow === event.source) {
|
|
@@ -819,6 +819,11 @@ function resolvePermissionIdentity(mateId, vendor) {
|
|
|
819
819
|
codex: "/codex-avatar.png",
|
|
820
820
|
antigravity: "/antigravity-avatar.png",
|
|
821
821
|
opencode: "/opencode-avatar.svg",
|
|
822
|
+
kimi: "/kimi-avatar.svg",
|
|
823
|
+
grok: "/grok-avatar.svg",
|
|
824
|
+
copilot: "/copilot-avatar.svg",
|
|
825
|
+
qwen: "/qwen-avatar.svg",
|
|
826
|
+
junie: "/junie-avatar.svg",
|
|
822
827
|
kiro: "/kiro-avatar.svg",
|
|
823
828
|
};
|
|
824
829
|
var vendorName = (vendor && VENDOR_NAMES[vendor]) || VENDOR_NAMES.claude;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export var VENDOR_ORDER = ["claude", "codex", "antigravity", "opencode", "kiro"];
|
|
1
|
+
export var VENDOR_ORDER = ["claude", "codex", "grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode", "kiro"];
|
|
2
|
+
export var EXPERIMENTAL_VENDORS = ["grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode"];
|
|
3
|
+
|
|
4
|
+
export function isExperimentalVendor(vendor) {
|
|
5
|
+
return EXPERIMENTAL_VENDORS.indexOf(vendor) !== -1;
|
|
6
|
+
}
|
|
2
7
|
|
|
3
8
|
export function firstInstalledVendor(installedVendors) {
|
|
4
9
|
var installed = Array.isArray(installedVendors) ? installedVendors : [];
|
|
@@ -95,6 +95,7 @@ function statusLabel(status) {
|
|
|
95
95
|
if (status === "starting") return "Starting Worker";
|
|
96
96
|
if (status === "running") return "Worker running";
|
|
97
97
|
if (status === "completed") return "Completed";
|
|
98
|
+
if (status === "interrupted") return "Interrupted";
|
|
98
99
|
if (status === "declined") return "Continuing here";
|
|
99
100
|
if (status === "error") return "Needs attention";
|
|
100
101
|
return "Suggested by Fable";
|
|
@@ -103,8 +104,10 @@ function statusLabel(status) {
|
|
|
103
104
|
function applyState(card, msg) {
|
|
104
105
|
var status = msg.status || "pending";
|
|
105
106
|
card.dataset.status = status;
|
|
107
|
+
if (msg.autoApproved) card.dataset.autoApproved = "true";
|
|
108
|
+
var autoApproved = card.dataset.autoApproved === "true";
|
|
106
109
|
var badge = card.querySelector(".worker-proposal-status");
|
|
107
|
-
if (badge) badge.textContent = statusLabel(status);
|
|
110
|
+
if (badge) badge.textContent = statusLabel(status) + (autoApproved ? " · auto-approved" : "");
|
|
108
111
|
var error = card.querySelector(".worker-proposal-error");
|
|
109
112
|
if (error) {
|
|
110
113
|
error.textContent = msg.error || "";
|
|
@@ -116,6 +119,8 @@ function applyState(card, msg) {
|
|
|
116
119
|
preview.classList.remove("hidden");
|
|
117
120
|
}
|
|
118
121
|
setControlsDisabled(card, status !== "pending");
|
|
122
|
+
var actions = card.querySelector(".worker-proposal-actions");
|
|
123
|
+
if (actions) actions.classList.toggle("hidden", autoApproved);
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
function sendDecision(card, accepted) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function isExternalWorktree(project) {
|
|
2
|
+
return !!(project && project.isWorktree && project.worktreeExternal === true);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function externalWorktreeTooltip(name) {
|
|
6
|
+
return name + " — outside the main project folder";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function appendExternalWorktreeBadge(container, className) {
|
|
10
|
+
var badge = document.createElement("span");
|
|
11
|
+
badge.className = className;
|
|
12
|
+
badge.setAttribute("role", "img");
|
|
13
|
+
badge.setAttribute("aria-label", "Outside the main project folder");
|
|
14
|
+
badge.innerHTML = '<i data-lucide="external-link"></i>';
|
|
15
|
+
container.appendChild(badge);
|
|
16
|
+
return badge;
|
|
17
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Qwen Code">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#6b4eff"/>
|
|
3
|
+
<path d="M32 12a20 20 0 1 0 12 36l7 5-3-11a20 20 0 0 0-16-30zm0 9a11 11 0 1 1-7.8 18.8A11 11 0 0 1 32 21z" fill="#fff"/>
|
|
4
|
+
</svg>
|
package/lib/public/style.css
CHANGED