clay-server 3.3.2-beta.3 → 3.4.0-beta.10
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 +1 -1
- package/lib/project-connection.js +20 -5
- package/lib/project-debate.js +4 -0
- package/lib/project-file-watch.js +77 -16
- package/lib/project-mate-interaction.js +21 -1
- package/lib/project-memory.js +3 -0
- package/lib/project-shell-command.js +160 -0
- package/lib/project-user-message.js +10 -0
- package/lib/project.js +19 -4
- package/lib/public/antigravity-avatar.png +0 -0
- package/lib/public/app.js +28 -0
- package/lib/public/copilot-avatar.svg +5 -0
- package/lib/public/css/command-palette.css +22 -2
- package/lib/public/css/icon-strip.css +29 -13
- package/lib/public/css/input.css +79 -0
- package/lib/public/css/mates.css +7 -0
- package/lib/public/css/menus.css +48 -14
- package/lib/public/css/messages.css +9 -0
- package/lib/public/css/pane.css +4 -0
- package/lib/public/css/pwa-mobile.css +17 -0
- package/lib/public/css/title-bar.css +19 -0
- package/lib/public/grok-avatar.svg +4 -0
- package/lib/public/index.html +43 -4
- package/lib/public/junie-avatar.svg +11 -0
- package/lib/public/kimi-avatar.svg +4 -0
- package/lib/public/modules/app-header.js +4 -0
- package/lib/public/modules/app-messages.js +28 -5
- package/lib/public/modules/app-panels.js +37 -5
- package/lib/public/modules/app-projects.js +3 -1
- package/lib/public/modules/app-rendering.js +22 -1
- package/lib/public/modules/input.js +58 -28
- package/lib/public/modules/mate-sidebar.js +17 -3
- package/lib/public/modules/notifications.js +7 -1
- package/lib/public/modules/pane-bridge.js +11 -0
- package/lib/public/modules/pane-links.js +23 -0
- package/lib/public/modules/project-switcher.js +7 -6
- package/lib/public/modules/shell-command.js +148 -0
- package/lib/public/modules/sidebar-mates.js +7 -1
- 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 +6 -6
- package/lib/public/modules/split-pair-ui.js +3 -2
- package/lib/public/modules/tools.js +12 -1
- package/lib/public/modules/vendor-priority.js +14 -0
- package/lib/public/modules/vendor-selection.js +20 -0
- package/lib/public/modules/worktree-location.js +17 -0
- package/lib/public/opencode-avatar.svg +4 -0
- package/lib/public/qwen-avatar.svg +4 -0
- package/lib/public/style.css +3 -2
- package/lib/sdk-bridge.js +59 -19
- package/lib/sdk-message-processor.js +10 -1
- package/lib/session-notes-mcp-server.js +7 -1
- package/lib/worktree.js +9 -4
- package/lib/ws-schema.js +3 -0
- package/lib/yoke/acp-agent-profiles.js +238 -0
- package/lib/yoke/acp-driver-runtime.js +50 -0
- package/lib/yoke/acp-event-normalizer.js +179 -0
- package/lib/yoke/acp-process-manager.js +264 -0
- package/lib/yoke/acp-query-handle.js +487 -0
- package/lib/yoke/adapters/acp.js +317 -0
- package/lib/yoke/adapters/antigravity.js +417 -0
- package/lib/yoke/adapters/codex.js +98 -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 -4
- package/lib/yoke/adapters/opencode.js +7 -0
- package/lib/yoke/adapters/qwen.js +7 -0
- package/lib/yoke/codex-app-server.js +25 -8
- package/lib/yoke/index.js +81 -13
- package/lib/yoke/instructions.js +3 -0
- package/lib/yoke/interface.js +2 -0
- package/lib/yoke/kiro-acp-server.js +30 -276
- package/lib/yoke/vendor-registry.js +77 -0
- package/package.json +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
4
|
+
import { showToast } from './utils.js';
|
|
5
|
+
|
|
6
|
+
var defaultPlaceholder = "";
|
|
7
|
+
|
|
8
|
+
function getInput() {
|
|
9
|
+
return document.getElementById("input");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function appendToMessages(element) {
|
|
13
|
+
var messages = document.getElementById("messages");
|
|
14
|
+
if (!messages) return;
|
|
15
|
+
messages.appendChild(element);
|
|
16
|
+
requestAnimationFrame(function () { messages.scrollTop = messages.scrollHeight; });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function setMode(active) {
|
|
20
|
+
var input = getInput();
|
|
21
|
+
var button = document.getElementById("shell-command-btn");
|
|
22
|
+
var row = document.getElementById("input-row");
|
|
23
|
+
store.set({ shellCommandMode: active });
|
|
24
|
+
if (button) {
|
|
25
|
+
button.classList.toggle("active", active);
|
|
26
|
+
button.setAttribute("aria-pressed", active ? "true" : "false");
|
|
27
|
+
}
|
|
28
|
+
if (row) row.classList.toggle("shell-command-mode", active);
|
|
29
|
+
if (input) {
|
|
30
|
+
if (!defaultPlaceholder) defaultPlaceholder = input.placeholder;
|
|
31
|
+
input.placeholder = active ? "Run a shell command in this project…" : defaultPlaceholder;
|
|
32
|
+
input.focus();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isShellCommandMode() {
|
|
37
|
+
return !!store.get("shellCommandMode");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function toggleShellCommandMode() {
|
|
41
|
+
if (store.get("shellCommandRunning")) return;
|
|
42
|
+
var target = store.get("dmTargetUser");
|
|
43
|
+
if (store.get("dmMode") && target && !target.isMate) {
|
|
44
|
+
showToast("Shell commands are available in agent sessions, not user DMs.", "error");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setMode(!isShellCommandMode());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function renderPendingCommand(requestId, command) {
|
|
51
|
+
var card = document.createElement("div");
|
|
52
|
+
card.className = "shell-command-card running";
|
|
53
|
+
card.dataset.requestId = requestId;
|
|
54
|
+
card.innerHTML =
|
|
55
|
+
'<div class="shell-command-header">' +
|
|
56
|
+
'<span class="shell-command-icon">' + iconHtml("square-terminal") + '</span>' +
|
|
57
|
+
'<code></code><span class="shell-command-status">Running…</span>' +
|
|
58
|
+
'</div>' +
|
|
59
|
+
'<pre class="shell-command-output">Waiting for output…</pre>';
|
|
60
|
+
card.querySelector("code").textContent = "$ " + command;
|
|
61
|
+
appendToMessages(card);
|
|
62
|
+
refreshIcons();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function submitShellCommand(command) {
|
|
66
|
+
command = String(command || "").trim();
|
|
67
|
+
if (!command || store.get("shellCommandRunning")) return false;
|
|
68
|
+
var ws = getWs();
|
|
69
|
+
if (!ws || ws.readyState !== 1) {
|
|
70
|
+
showToast("Not connected — command not run.", "error");
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var requestId = "shell_" + Date.now() + "_" + Math.random().toString(36).slice(2, 9);
|
|
75
|
+
store.set({ shellCommandRunning: true, pendingShellCommandId: requestId });
|
|
76
|
+
var input = getInput();
|
|
77
|
+
if (input) {
|
|
78
|
+
input.disabled = true;
|
|
79
|
+
input.placeholder = "Running command…";
|
|
80
|
+
}
|
|
81
|
+
renderPendingCommand(requestId, command);
|
|
82
|
+
ws.send(JSON.stringify({ type: "shell_command", requestId: requestId, command: command }));
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function handleShellCommandResult(msg) {
|
|
87
|
+
var cards = document.querySelectorAll(".shell-command-card[data-request-id]");
|
|
88
|
+
var card = null;
|
|
89
|
+
for (var i = 0; i < cards.length; i++) {
|
|
90
|
+
if (cards[i].dataset.requestId === (msg.requestId || "")) {
|
|
91
|
+
card = cards[i];
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (card) {
|
|
96
|
+
var status = card.querySelector(".shell-command-status");
|
|
97
|
+
var output = card.querySelector(".shell-command-output");
|
|
98
|
+
card.classList.remove("running");
|
|
99
|
+
if (msg.error) {
|
|
100
|
+
card.classList.add("error");
|
|
101
|
+
if (status) status.textContent = "Failed";
|
|
102
|
+
if (output) output.textContent = msg.error;
|
|
103
|
+
} else {
|
|
104
|
+
card.classList.toggle("error", msg.exitCode !== 0);
|
|
105
|
+
if (status) status.textContent = msg.timedOut ? "Timed out" : "Exit " + (msg.exitCode == null ? "—" : msg.exitCode);
|
|
106
|
+
if (output) output.textContent = msg.output || "(no output)";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
store.set({ shellCommandRunning: false, pendingShellCommandId: null });
|
|
111
|
+
var input = getInput();
|
|
112
|
+
if (input) input.disabled = false;
|
|
113
|
+
if (msg.error) {
|
|
114
|
+
setMode(true);
|
|
115
|
+
} else {
|
|
116
|
+
setMode(false);
|
|
117
|
+
}
|
|
118
|
+
var messages = document.getElementById("messages");
|
|
119
|
+
if (messages) requestAnimationFrame(function () { messages.scrollTop = messages.scrollHeight; });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function initShellCommand() {
|
|
123
|
+
var button = document.getElementById("shell-command-btn");
|
|
124
|
+
var mobileButton = document.getElementById("input-more-shell");
|
|
125
|
+
if (button) button.addEventListener("click", toggleShellCommandMode);
|
|
126
|
+
if (mobileButton) {
|
|
127
|
+
mobileButton.addEventListener("click", function () {
|
|
128
|
+
var sheet = document.getElementById("input-more-sheet");
|
|
129
|
+
if (sheet) {
|
|
130
|
+
sheet.classList.remove("open");
|
|
131
|
+
setTimeout(function () { sheet.classList.add("hidden"); }, 250);
|
|
132
|
+
}
|
|
133
|
+
toggleShellCommandMode();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
store.subscribe(function (state, previous) {
|
|
137
|
+
if (previous.connected && !state.connected && state.shellCommandRunning) {
|
|
138
|
+
resetShellCommand();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function resetShellCommand() {
|
|
144
|
+
store.set({ shellCommandMode: false, shellCommandRunning: false, pendingShellCommandId: null });
|
|
145
|
+
var input = getInput();
|
|
146
|
+
if (input) input.disabled = false;
|
|
147
|
+
setMode(false);
|
|
148
|
+
}
|
|
@@ -457,7 +457,13 @@ export function renderUserStrip(allUsers, onlineUserIds, myUserId, dmFavorites,
|
|
|
457
457
|
// Tooltip
|
|
458
458
|
var displayName = mp.displayName || mate.name || "New Mate";
|
|
459
459
|
var mateVendor = mate.vendor || "claude";
|
|
460
|
-
var vendorLabels = {
|
|
460
|
+
var vendorLabels = {
|
|
461
|
+
claude: "Claude Code",
|
|
462
|
+
codex: "OpenAI Codex",
|
|
463
|
+
antigravity: "Antigravity CLI",
|
|
464
|
+
opencode: "OpenCode",
|
|
465
|
+
kiro: "Kiro CLI",
|
|
466
|
+
};
|
|
461
467
|
el.addEventListener("mouseenter", function () {
|
|
462
468
|
var html = '<div style="font-weight:600">' + escapeHtml(displayName);
|
|
463
469
|
if (mate.primary) {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
resolveDefaultVendor,
|
|
16
16
|
startNewSession
|
|
17
17
|
} from './sidebar-sessions.js';
|
|
18
|
-
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, VENDOR_HOMEPAGES } from './app-rendering.js';
|
|
18
|
+
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, VENDOR_HOMEPAGES, isExperimentalVendor } from './app-rendering.js';
|
|
19
19
|
import {
|
|
20
20
|
getCachedProjectList,
|
|
21
21
|
getCachedCurrentSlug,
|
|
@@ -754,6 +754,7 @@ function renderMobileSessionsInto(container) {
|
|
|
754
754
|
if (vendor === mobileDefaultVendor) vBtn.classList.add("active");
|
|
755
755
|
vBtn.innerHTML = '<img src="' + VENDOR_AVATARS[vendor] + '" class="mobile-session-new-icon" alt="">' +
|
|
756
756
|
'<span>' + name + '</span>' +
|
|
757
|
+
(isExperimentalVendor(vendor) ? '<span class="vendor-experimental-badge" aria-label="Experimental integration" title="Experimental integration; not yet validated through direct use testing">🧪</span>' : '') +
|
|
757
758
|
(isInstalled ? "" : '<span class="mobile-vendor-note">Not installed</span>');
|
|
758
759
|
vBtn.addEventListener("click", function () {
|
|
759
760
|
if (!isInstalled) {
|
|
@@ -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';
|
|
@@ -299,13 +299,10 @@ function appendSessionCloseButton(el, session) {
|
|
|
299
299
|
el.appendChild(closeBtn);
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
// Resolve the vendor the "New session" button should launch
|
|
303
|
-
//
|
|
304
|
-
// vendor, else Claude (so the button always has a sane label to render).
|
|
302
|
+
// Resolve the vendor the "New session" button should launch from the stable
|
|
303
|
+
// installed-vendor priority (Claude, then Codex, then the remaining vendors).
|
|
305
304
|
export function resolveDefaultVendor() {
|
|
306
305
|
var installed = store.get('installedVendors') || [];
|
|
307
|
-
var last = store.get('lastVendor') || "";
|
|
308
|
-
if (last && installed.indexOf(last) !== -1) return last;
|
|
309
306
|
for (var i = 0; i < VENDOR_ORDER.length; i++) {
|
|
310
307
|
if (installed.indexOf(VENDOR_ORDER[i]) !== -1) return VENDOR_ORDER[i];
|
|
311
308
|
}
|
|
@@ -330,6 +327,7 @@ export function startNewSession(vendor, extra) {
|
|
|
330
327
|
currentModel: "",
|
|
331
328
|
currentModels: [],
|
|
332
329
|
vendorSelectionLocked: true,
|
|
330
|
+
sessionVendorBound: true,
|
|
333
331
|
});
|
|
334
332
|
}
|
|
335
333
|
|
|
@@ -396,10 +394,12 @@ function showNewSessionMenu(anchorBtn, defaultVendor) {
|
|
|
396
394
|
item.type = "button";
|
|
397
395
|
item.innerHTML = '<img src="' + VENDOR_AVATARS[vendor] + '" class="session-top-action-icon" alt="">' +
|
|
398
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>' : '') +
|
|
399
398
|
(isInstalled ? "" : '<span class="session-new-vendor-note">Not installed</span>' + iconHtml("external-link"));
|
|
400
399
|
item.title = isInstalled
|
|
401
400
|
? "New " + name + " session"
|
|
402
401
|
: name + " is not installed - open " + VENDOR_HOMEPAGES[vendor];
|
|
402
|
+
if (isExperimentalVendor(vendor)) item.title += " · Experimental integration; not yet validated through direct use testing";
|
|
403
403
|
item.addEventListener("click", function (e) {
|
|
404
404
|
e.stopPropagation();
|
|
405
405
|
closeSessionCtxMenu();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
2
|
import { getWs } from './ws-ref.js';
|
|
3
|
-
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER } from './app-rendering.js';
|
|
3
|
+
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, isExperimentalVendor } from './app-rendering.js';
|
|
4
4
|
import { effortLevelsFor, effortDisplayName } from './app-panels.js';
|
|
5
5
|
import { showToast } from './utils.js';
|
|
6
6
|
|
|
@@ -46,7 +46,8 @@ function buildVendorSelect(installed, preferred) {
|
|
|
46
46
|
if (installed.indexOf(VENDOR_ORDER[i]) === -1) continue;
|
|
47
47
|
var option = document.createElement("option");
|
|
48
48
|
option.value = VENDOR_ORDER[i];
|
|
49
|
-
option.textContent = VENDOR_NAMES[VENDOR_ORDER[i]] || VENDOR_ORDER[i];
|
|
49
|
+
option.textContent = (isExperimentalVendor(VENDOR_ORDER[i]) ? "🧪 " : "") + (VENDOR_NAMES[VENDOR_ORDER[i]] || VENDOR_ORDER[i]);
|
|
50
|
+
if (isExperimentalVendor(VENDOR_ORDER[i])) option.title = "Experimental integration; not yet validated through direct use testing";
|
|
50
51
|
select.appendChild(option);
|
|
51
52
|
}
|
|
52
53
|
if (preferred && installed.indexOf(preferred) !== -1) select.value = preferred;
|
|
@@ -814,7 +814,18 @@ function resolvePermissionIdentity(mateId, vendor) {
|
|
|
814
814
|
}
|
|
815
815
|
}
|
|
816
816
|
// Project chat: use vendor name and avatar
|
|
817
|
-
var vendorAvatars = {
|
|
817
|
+
var vendorAvatars = {
|
|
818
|
+
claude: "/claude-code-avatar.png",
|
|
819
|
+
codex: "/codex-avatar.png",
|
|
820
|
+
antigravity: "/antigravity-avatar.png",
|
|
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",
|
|
827
|
+
kiro: "/kiro-avatar.svg",
|
|
828
|
+
};
|
|
818
829
|
var vendorName = (vendor && VENDOR_NAMES[vendor]) || VENDOR_NAMES.claude;
|
|
819
830
|
return {
|
|
820
831
|
name: vendorName,
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
}
|
|
7
|
+
|
|
8
|
+
export function firstInstalledVendor(installedVendors) {
|
|
9
|
+
var installed = Array.isArray(installedVendors) ? installedVendors : [];
|
|
10
|
+
for (var i = 0; i < VENDOR_ORDER.length; i++) {
|
|
11
|
+
if (installed.indexOf(VENDOR_ORDER[i]) !== -1) return VENDOR_ORDER[i];
|
|
12
|
+
}
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { firstInstalledVendor } from './vendor-priority.js';
|
|
3
|
+
|
|
4
|
+
export function selectDefaultVendorForBlankSession() {
|
|
5
|
+
var state = store.snap();
|
|
6
|
+
if (!state.activeSessionId || state.sessionHasHistory || state.sessionVendorBound || state.dmMode) return "";
|
|
7
|
+
var vendor = firstInstalledVendor(state.installedVendors);
|
|
8
|
+
if (!vendor) return "";
|
|
9
|
+
if (vendor === state.currentVendor) {
|
|
10
|
+
if (state.vendorSelectionLocked) store.set({ vendorSelectionLocked: false });
|
|
11
|
+
return vendor;
|
|
12
|
+
}
|
|
13
|
+
store.set({
|
|
14
|
+
currentVendor: vendor,
|
|
15
|
+
currentModel: "",
|
|
16
|
+
currentModels: [],
|
|
17
|
+
vendorSelectionLocked: false,
|
|
18
|
+
});
|
|
19
|
+
return vendor;
|
|
20
|
+
}
|
|
@@ -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="OpenCode">
|
|
2
|
+
<rect width="64" height="64" rx="16" fill="#111814"/>
|
|
3
|
+
<path d="m26 19-13 13 13 13M38 19l13 13-13 13" fill="none" stroke="#78e08f" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
</svg>
|
|
@@ -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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
@import url("css/base.css");
|
|
2
2
|
@import url("css/icon-strip.css");
|
|
3
|
-
@import url("css/title-bar.css");
|
|
3
|
+
@import url("css/title-bar.css?v=20260824");
|
|
4
4
|
@import url("css/pane.css");
|
|
5
5
|
@import url("css/worker-proposal.css");
|
|
6
6
|
@import url("css/sidebar.css");
|
|
7
7
|
@import url("css/overlays.css");
|
|
8
8
|
@import url("css/menus.css");
|
|
9
|
-
@import url("css/messages.css?v=
|
|
9
|
+
@import url("css/messages.css?v=20260824");
|
|
10
10
|
@import url("css/rewind.css");
|
|
11
11
|
@import url("css/input.css");
|
|
12
12
|
@import url("css/filebrowser.css");
|
|
@@ -35,3 +35,4 @@
|
|
|
35
35
|
@import url("css/debate.css");
|
|
36
36
|
@import url("css/notifications-center.css");
|
|
37
37
|
@import url("css/tui-attention.css");
|
|
38
|
+
@import url("css/pwa-mobile.css?v=20260824f");
|