clay-server 3.4.0-beta.2 → 3.4.0-beta.21
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 +35 -7
- package/lib/project-debate.js +4 -0
- package/lib/project-mate-interaction.js +21 -1
- package/lib/project-memory.js +3 -0
- 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 +38 -80
- package/lib/public/antigravity-avatar.png +0 -0
- package/lib/public/app.js +29 -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 +56 -0
- package/lib/public/css/mates.css +6 -0
- package/lib/public/css/menus.css +38 -25
- package/lib/public/css/messages.css +9 -0
- package/lib/public/css/pane.css +16 -3
- package/lib/public/css/pwa-mobile.css +17 -0
- package/lib/public/css/session-actions.css +98 -0
- package/lib/public/css/title-bar.css +19 -0
- package/lib/public/grok-avatar.svg +4 -0
- package/lib/public/index.html +29 -7
- 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-header.js +4 -22
- package/lib/public/modules/app-messages.js +54 -11
- package/lib/public/modules/app-panels.js +36 -83
- package/lib/public/modules/app-projects.js +3 -1
- package/lib/public/modules/app-rendering.js +19 -4
- package/lib/public/modules/background-tasks-ui.js +55 -0
- package/lib/public/modules/mate-sidebar.js +11 -3
- package/lib/public/modules/model-picker.js +263 -0
- 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/session-actions.js +294 -0
- package/lib/public/modules/sidebar-mates.js +1 -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 +20 -6
- package/lib/public/modules/split-pair-ui.js +16 -77
- package/lib/public/modules/split-view.js +3 -0
- package/lib/public/modules/tools.js +6 -1
- package/lib/public/modules/vendor-priority.js +14 -0
- package/lib/public/modules/vendor-selection.js +20 -0
- 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 +4 -2
- package/lib/sdk-bridge.js +103 -56
- package/lib/sdk-message-processor.js +26 -4
- package/lib/session-handoff-context.js +110 -0
- package/lib/session-notes-mcp-server.js +8 -1
- 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 -14
- package/lib/yoke/adapters/antigravity.js +417 -0
- package/lib/yoke/adapters/claude.js +34 -0
- package/lib/yoke/adapters/codex.js +101 -5
- 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 +2 -2
- package/lib/yoke/adapters/qwen.js +7 -0
- package/lib/yoke/codex-app-server.js +25 -8
- package/lib/yoke/index.js +67 -28
- package/lib/yoke/instructions.js +3 -0
- package/lib/yoke/interface.js +12 -0
- package/lib/yoke/vendor-registry.js +61 -6
- package/package.json +1 -1
- package/lib/public/gemini-avatar.svg +0 -11
- package/lib/yoke/adapters/gemini.js +0 -7
package/lib/project.js
CHANGED
|
@@ -27,6 +27,7 @@ var { attachImage } = require("./project-image");
|
|
|
27
27
|
var { attachKnowledge } = require("./project-knowledge");
|
|
28
28
|
var { attachFilesystem } = require("./project-filesystem");
|
|
29
29
|
var { attachSessions } = require("./project-sessions");
|
|
30
|
+
var { attachModels } = require("./project-models");
|
|
30
31
|
var { attachUserMessage } = require("./project-user-message");
|
|
31
32
|
var { attachShellCommand } = require("./project-shell-command");
|
|
32
33
|
var { attachConnection } = require("./project-connection");
|
|
@@ -35,6 +36,7 @@ var { createLocalMcp } = require("./mcp-local");
|
|
|
35
36
|
var { attachEmail: attachEmailModule } = require("./project-email");
|
|
36
37
|
var { attachSessionSpawn } = require("./project-session-spawn");
|
|
37
38
|
var { attachSessionPair } = require("./project-session-pair");
|
|
39
|
+
var { attachSessionHandoff } = require("./project-session-handoff");
|
|
38
40
|
var { attachSessionNotes, composeSystemPrompts } = require("./project-session-notes");
|
|
39
41
|
var { attachSessionDocument } = require("./project-session-document");
|
|
40
42
|
var { attachSplitGroups } = require("./session-split-groups");
|
|
@@ -163,7 +165,7 @@ function createProjectContext(opts) {
|
|
|
163
165
|
var updateChannel = opts.updateChannel || "stable";
|
|
164
166
|
var osUsers = opts.osUsers || false;
|
|
165
167
|
var projectOwnerId = opts.projectOwnerId || null;
|
|
166
|
-
var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch,
|
|
168
|
+
var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch, external }
|
|
167
169
|
var isMate = opts.isMate || false;
|
|
168
170
|
var onCreateWorktree = opts.onCreateWorktree || null;
|
|
169
171
|
var serverPort = opts.port || 2633;
|
|
@@ -470,10 +472,9 @@ function createProjectContext(opts) {
|
|
|
470
472
|
|
|
471
473
|
var _projModel = typeof opts.onGetProjectDefaultModel === "function" ? opts.onGetProjectDefaultModel(slug) : null;
|
|
472
474
|
var _srvModel = typeof opts.onGetServerDefaultModel === "function" ? opts.onGetServerDefaultModel() : null;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (sm._savedDefaultModel) sm.currentModel = sm._savedDefaultModel;
|
|
475
|
+
var savedDefaultModel = (_projModel && _projModel.model) || (_srvModel && _srvModel.model) || null;
|
|
476
|
+
sm.defaultModelByVendor = sm.defaultModelByVendor || {};
|
|
477
|
+
if (savedDefaultModel) sm.defaultModelByVendor[sm.defaultVendor || "claude"] = savedDefaultModel;
|
|
477
478
|
|
|
478
479
|
// --- Local MCP (direct process management for localhost clients) ---
|
|
479
480
|
var _localMcp = createLocalMcp();
|
|
@@ -569,6 +570,18 @@ function createProjectContext(opts) {
|
|
|
569
570
|
getLinuxUserForSession: getLinuxUserForSession,
|
|
570
571
|
getPairToolDefs: function (boundSession) { return _sessionPair.getToolDefs(boundSession); },
|
|
571
572
|
});
|
|
573
|
+
var _sessionHandoff = attachSessionHandoff({
|
|
574
|
+
cwd: cwd,
|
|
575
|
+
sm: sm,
|
|
576
|
+
isMate: isMate,
|
|
577
|
+
splitStore: _splitGroups.store,
|
|
578
|
+
getSdk: function () { return sdk; },
|
|
579
|
+
sendTo: sendTo,
|
|
580
|
+
usersModule: usersModule,
|
|
581
|
+
adapters: adapters,
|
|
582
|
+
getLinuxUserForSession: getLinuxUserForSession,
|
|
583
|
+
onProcessingChanged: onProcessingChanged,
|
|
584
|
+
});
|
|
572
585
|
var _debate = null;
|
|
573
586
|
var _debateProposal = attachDebateProposal({
|
|
574
587
|
cwd: cwd,
|
|
@@ -835,6 +848,7 @@ function createProjectContext(opts) {
|
|
|
835
848
|
getNotificationsModule: function () { return _notifications; },
|
|
836
849
|
mateDisplayName: opts.mateDisplayName || "",
|
|
837
850
|
isMate: isMate,
|
|
851
|
+
osUsers: osUsers,
|
|
838
852
|
dangerouslySkipPermissions: dangerouslySkipPermissions,
|
|
839
853
|
mcpServers: getLocalMcpServers,
|
|
840
854
|
getRemoteMcpServers: function () { return _mcp.getMcpServers(); },
|
|
@@ -1052,78 +1066,6 @@ function createProjectContext(opts) {
|
|
|
1052
1066
|
return;
|
|
1053
1067
|
}
|
|
1054
1068
|
|
|
1055
|
-
// --- Vendor model switching ---
|
|
1056
|
-
if (msg.type === "get_vendor_models") {
|
|
1057
|
-
(async function() {
|
|
1058
|
-
if (msg.vendor) {
|
|
1059
|
-
try {
|
|
1060
|
-
var modelLinuxUser = getLinuxUserForWs(ws);
|
|
1061
|
-
var vendorAdapter = adapters[msg.vendor] || null;
|
|
1062
|
-
if (!vendorAdapter) {
|
|
1063
|
-
vendorAdapter = await yoke.lazyCreateAdapter(adapters, msg.vendor, {
|
|
1064
|
-
cwd: cwd,
|
|
1065
|
-
linuxUser: modelLinuxUser || undefined,
|
|
1066
|
-
clayPort: serverPort,
|
|
1067
|
-
clayTls: serverTls,
|
|
1068
|
-
clayAuthToken: serverAuthToken,
|
|
1069
|
-
slug: slug,
|
|
1070
|
-
});
|
|
1071
|
-
}
|
|
1072
|
-
var needsReadyMetadata = !sm.capabilitiesByVendor || !sm.capabilitiesByVendor[msg.vendor]
|
|
1073
|
-
|| !sm.modelsByVendor || !sm.modelsByVendor[msg.vendor];
|
|
1074
|
-
if (vendorAdapter && needsReadyMetadata && typeof vendorAdapter.init === "function") {
|
|
1075
|
-
// Init warms the adapter, but a slow/failed init must not block
|
|
1076
|
-
// model listing (e.g. Codex models are a fixed list). Keep going
|
|
1077
|
-
// to supportedModels() even if init throws.
|
|
1078
|
-
try {
|
|
1079
|
-
var readyResult = await vendorAdapter.init({
|
|
1080
|
-
cwd: cwd,
|
|
1081
|
-
clayPort: serverPort,
|
|
1082
|
-
clayTls: serverTls,
|
|
1083
|
-
clayAuthToken: serverAuthToken,
|
|
1084
|
-
slug: slug,
|
|
1085
|
-
});
|
|
1086
|
-
sm.capabilitiesByVendor = sm.capabilitiesByVendor || {};
|
|
1087
|
-
sm.capabilitiesByVendor[msg.vendor] = readyResult.capabilities || {};
|
|
1088
|
-
sm.modelsByVendor = sm.modelsByVendor || {};
|
|
1089
|
-
if (Array.isArray(readyResult.models)) sm.modelsByVendor[msg.vendor] = readyResult.models;
|
|
1090
|
-
} catch (e) {
|
|
1091
|
-
console.error("[project] " + msg.vendor + " init failed (continuing to model list):", e.message || e);
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
if (vendorAdapter) {
|
|
1095
|
-
sm.availableVendors = Object.keys(adapters);
|
|
1096
|
-
sm.modelsByVendor = sm.modelsByVendor || {};
|
|
1097
|
-
if (!sm.modelsByVendor[msg.vendor] && typeof vendorAdapter.supportedModels === "function") {
|
|
1098
|
-
sm.modelsByVendor[msg.vendor] = await vendorAdapter.supportedModels();
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
} catch (e) {
|
|
1102
|
-
console.error("[project] get_vendor_models lazy init failed for " + msg.vendor + ":", e.message || e);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
var vendorModels = (sm.modelsByVendor && sm.modelsByVendor[msg.vendor]) || [];
|
|
1106
|
-
var firstModel = vendorModels[0] || "";
|
|
1107
|
-
// model value can be string or {value, displayName} object
|
|
1108
|
-
var defaultModel = typeof firstModel === "string" ? firstModel : (firstModel.value || "");
|
|
1109
|
-
// Preserve the user's current model selection if it belongs to this
|
|
1110
|
-
// vendor, rather than always snapping back to the vendor's default.
|
|
1111
|
-
var modelToSend = defaultModel;
|
|
1112
|
-
if (sm.currentModel) {
|
|
1113
|
-
for (var mi = 0; mi < vendorModels.length; mi++) {
|
|
1114
|
-
var mv = typeof vendorModels[mi] === "string" ? vendorModels[mi] : (vendorModels[mi].value || "");
|
|
1115
|
-
if (mv === sm.currentModel) {
|
|
1116
|
-
modelToSend = sm.currentModel;
|
|
1117
|
-
break;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
var vendorCapabilities = (sm.capabilitiesByVendor && sm.capabilitiesByVendor[msg.vendor]) || {};
|
|
1122
|
-
sendTo(ws, { type: "model_info", model: modelToSend, models: vendorModels, vendor: msg.vendor, capabilities: vendorCapabilities, availableVendors: sm.availableVendors || [], installedVendors: sm.installedVendors || [] });
|
|
1123
|
-
})();
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
1069
|
// --- Debate ---
|
|
1128
1070
|
if (msg.type === "debate_start") {
|
|
1129
1071
|
handleDebateStart(ws, msg);
|
|
@@ -1171,7 +1113,9 @@ function createProjectContext(opts) {
|
|
|
1171
1113
|
|
|
1172
1114
|
// --- Sessions, config, project mgmt (delegated to project-sessions.js) ---
|
|
1173
1115
|
if (_sessionPair.handleMessage(ws, msg)) return;
|
|
1116
|
+
if (_sessionHandoff.handleMessage(ws, msg)) return;
|
|
1174
1117
|
if (_splitGroups.handleMessage(ws, msg)) return;
|
|
1118
|
+
if (_models.handleMessage(ws, msg)) return;
|
|
1175
1119
|
if (_sessions.handleSessionsMessage(ws, msg)) return;
|
|
1176
1120
|
|
|
1177
1121
|
// --- Filesystem, settings, env (delegated to project-filesystem.js) ---
|
|
@@ -1384,6 +1328,20 @@ function createProjectContext(opts) {
|
|
|
1384
1328
|
_notifications: _notifications,
|
|
1385
1329
|
});
|
|
1386
1330
|
|
|
1331
|
+
var _models = attachModels({
|
|
1332
|
+
cwd: cwd,
|
|
1333
|
+
slug: slug,
|
|
1334
|
+
sm: sm,
|
|
1335
|
+
sdk: sdk,
|
|
1336
|
+
adapters: adapters,
|
|
1337
|
+
sendTo: sendTo,
|
|
1338
|
+
getSessionForWs: getSessionForWs,
|
|
1339
|
+
getLinuxUserForWs: getLinuxUserForWs,
|
|
1340
|
+
serverPort: serverPort,
|
|
1341
|
+
serverTls: serverTls,
|
|
1342
|
+
serverAuthToken: serverAuthToken,
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1387
1345
|
// --- User message handler (delegated to project-user-message.js) ---
|
|
1388
1346
|
var _userMessage = attachUserMessage({
|
|
1389
1347
|
cwd: cwd,
|
|
@@ -1686,8 +1644,8 @@ function createProjectContext(opts) {
|
|
|
1686
1644
|
getProject: function () { return project; },
|
|
1687
1645
|
// Exposed so the first websocket connection can lazily warm up the
|
|
1688
1646
|
// adapters for this project (see project-connection handleConnection).
|
|
1689
|
-
warmup: function () {
|
|
1690
|
-
sdk.warmup();
|
|
1647
|
+
warmup: function (linuxUser) {
|
|
1648
|
+
sdk.warmup(osUsers ? linuxUser : null);
|
|
1691
1649
|
sdk.startIdleReaper();
|
|
1692
1650
|
if (!osUsers && !sessionTitleMigrationScheduled) {
|
|
1693
1651
|
sessionTitleMigrationScheduled = true;
|
|
@@ -1813,7 +1771,7 @@ function createProjectContext(opts) {
|
|
|
1813
1771
|
status.isWorktree = true;
|
|
1814
1772
|
status.parentSlug = worktreeMeta.parentSlug;
|
|
1815
1773
|
status.branch = worktreeMeta.branch;
|
|
1816
|
-
status.
|
|
1774
|
+
status.worktreeExternal = worktreeMeta.external === true;
|
|
1817
1775
|
}
|
|
1818
1776
|
if (usersModule.isMultiUser()) {
|
|
1819
1777
|
var seen = {};
|
|
Binary file
|
package/lib/public/app.js
CHANGED
|
@@ -60,10 +60,12 @@ import { initRateLimit, handleRateLimitEvent as _rlHandleRateLimitEvent, updateR
|
|
|
60
60
|
import { initCursors, handleRemoteCursorMove as _curHandleRemoteCursorMove, handleRemoteCursorLeave as _curHandleRemoteCursorLeave, handleRemoteSelection as _curHandleRemoteSelection, clearRemoteCursors as _curClearRemoteCursors, initCursorToggle } from './modules/app-cursors.js';
|
|
61
61
|
import { initFavicon, updateFavicon as _favUpdateFavicon, setSendBtnMode as _favSetSendBtnMode, blinkIO as _favBlinkIO, blinkSessionDot as _favBlinkSessionDot, updateCrossProjectBlink as _favUpdateCrossProjectBlink, startUrgentBlink as _favStartUrgentBlink, stopUrgentBlink as _favStopUrgentBlink, setActivity as _favSetActivity, drawFaviconAnimFrame as _favDrawFaviconAnimFrame } from './modules/app-favicon.js';
|
|
62
62
|
import { initHeader, closeSessionInfoPopover as _hdrCloseSessionInfoPopover, updateHistorySentinel as _hdrUpdateHistorySentinel, requestMoreHistory as _hdrRequestMoreHistory, prependOlderHistory as _hdrPrependOlderHistory } from './modules/app-header.js';
|
|
63
|
+
import { initSessionActions } from './modules/session-actions.js';
|
|
63
64
|
import { initMisc, flushPendingExtMessages, showImageModal as _miscShowImageModal, closeImageModal as _miscCloseImageModal, showPasteModal as _miscShowPasteModal, closePasteModal as _miscClosePasteModal, showConfirm as _miscShowConfirm, hideConfirm as _miscHideConfirm, showForceChangePinOverlay as _miscShowForceChangePinOverlay, sendExtensionCommand as _miscSendExtensionCommand, handleExtensionResult as _miscHandleExtensionResult } from './modules/app-misc.js';
|
|
64
65
|
import { initSkillInstall, requireSkills as _siRequireSkills, requireClayMateInterview as _siRequireClayMateInterview, handleSkillInstallWs as _siHandleSkillInstallWs } from './modules/app-skills-install.js';
|
|
65
66
|
import { initDebateUi, showDebateConcludeConfirm as _debShowDebateConcludeConfirm, exitDebateConcludeMode as _debExitDebateConcludeMode, handleDebateConcludeSend as _debHandleDebateConcludeSend, showDebateEndedMode as _debShowDebateEndedMode, exitDebateEndedMode as _debExitDebateEndedMode, showDebateUserFloor as _debShowDebateUserFloor, exitDebateFloorMode as _debExitDebateFloorMode, handleDebateFloorSend as _debHandleDebateFloorSend, renderDebateUserFloorDone as _debRenderDebateUserFloorDone, showDebateSticky as _debShowDebateSticky, showDebateBottomBar as _debShowDebateBottomBar, removeDebateBottomBar as _debRemoveDebateBottomBar, sendDebateStickyComment as _debSendDebateStickyComment, updateDebateRound as _debUpdateDebateRound } from './modules/app-debate-ui.js';
|
|
66
67
|
import { initLoopUi, updateLoopInputVisibility as _loopUpdateLoopInputVisibility, updateLoopButton as _loopUpdateLoopButton, showLoopBanner as _loopShowLoopBanner, updateLoopBanner as _loopUpdateLoopBanner, updateRalphBars as _loopUpdateRalphBars, showRalphCraftingBar as _loopShowRalphCraftingBar, showRalphApprovalBar as _loopShowRalphApprovalBar, updateRalphApprovalStatus as _loopUpdateRalphApprovalStatus, openRalphPreviewModal as _loopOpenRalphPreviewModal, showExecModal as _loopShowExecModal, closeExecModal as _loopCloseExecModal, updateExecModalStatus as _loopUpdateExecModalStatus } from './modules/app-loop-ui.js';
|
|
68
|
+
import { initBackgroundTasksUi } from './modules/background-tasks-ui.js';
|
|
67
69
|
import { initLoopWizard, openRalphWizard as _loopOpenRalphWizard, closeRalphWizard as _loopCloseRalphWizard, getWizardSource as _loopGetWizardSource } from './modules/app-loop-wizard.js';
|
|
68
70
|
import { initAppNotifications, handleNotificationsState as _notifHandleState, handleNotificationCreated as _notifHandleCreated, handleNotificationDismissed as _notifHandleDismissed, handleNotificationDismissedAll as _notifHandleDismissedAll } from './modules/app-notifications.js';
|
|
69
71
|
import { initWhatsNew, handleWhatsNewState as _wnHandleState, handleWhatsNewSeenResult as _wnHandleSeenResult } from './modules/whats-new.js';
|
|
@@ -295,6 +297,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
295
297
|
slashCommands: [],
|
|
296
298
|
processing: false,
|
|
297
299
|
activeSessionId: null,
|
|
300
|
+
activeBackgroundTasks: [],
|
|
301
|
+
sessionVendorBound: false,
|
|
298
302
|
cliSessionId: null,
|
|
299
303
|
isHeadlessMode: false,
|
|
300
304
|
savedMainSlug: null,
|
|
@@ -338,6 +342,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
338
342
|
markdownSlideLevelExplicit: false,
|
|
339
343
|
currentModel: "",
|
|
340
344
|
currentModels: [],
|
|
345
|
+
modelListVendor: "",
|
|
346
|
+
modelListStatus: "idle",
|
|
347
|
+
modelListError: "",
|
|
348
|
+
modelRequestId: "",
|
|
349
|
+
modelSelectionPending: null,
|
|
350
|
+
modelSelectionError: "",
|
|
341
351
|
// Project's last-used vendor; seeds the sidebar's "New session" button.
|
|
342
352
|
lastVendor: "",
|
|
343
353
|
// Static adapter metadata sent before any vendor is initialized.
|
|
@@ -556,6 +566,22 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
556
566
|
var newMsgBtnDefault = "\u2193 Latest";
|
|
557
567
|
var newMsgBtnActivity = "\u2193 New activity";
|
|
558
568
|
|
|
569
|
+
// The composer grows for mobile tabs, safe areas, multiline input, and the
|
|
570
|
+
// keyboard. Keep the jump button immediately above its real height instead
|
|
571
|
+
// of relying on one fixed bottom offset.
|
|
572
|
+
function positionNewMsgButton() {
|
|
573
|
+
var inputArea = $("input-area");
|
|
574
|
+
if (!inputArea) return;
|
|
575
|
+
newMsgBtn.style.bottom = (inputArea.offsetHeight + 12) + "px";
|
|
576
|
+
}
|
|
577
|
+
var inputAreaForNewMsgBtn = $("input-area");
|
|
578
|
+
if (inputAreaForNewMsgBtn && window.ResizeObserver) {
|
|
579
|
+
new ResizeObserver(positionNewMsgButton).observe(inputAreaForNewMsgBtn);
|
|
580
|
+
} else {
|
|
581
|
+
window.addEventListener("resize", positionNewMsgButton);
|
|
582
|
+
}
|
|
583
|
+
positionNewMsgButton();
|
|
584
|
+
|
|
559
585
|
messagesEl.addEventListener("scroll", function () {
|
|
560
586
|
// While sticky-bottom is armed (e.g. just after history_done or a "New
|
|
561
587
|
// activity" click), suppress "user scrolled up" detection. Growth-induced
|
|
@@ -616,6 +642,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
616
642
|
|
|
617
643
|
// --- Header module (rename, info popover, history) ---
|
|
618
644
|
initHeader();
|
|
645
|
+
initSessionActions();
|
|
619
646
|
|
|
620
647
|
// --- Skill Install module ---
|
|
621
648
|
initSkillInstall();
|
|
@@ -624,6 +651,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
624
651
|
initDebateUi();
|
|
625
652
|
|
|
626
653
|
initLoopUi();
|
|
654
|
+
initBackgroundTasksUi();
|
|
627
655
|
initLoopWizard();
|
|
628
656
|
|
|
629
657
|
// --- Notifications module ---
|
|
@@ -932,6 +960,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
932
960
|
messagesEl: messagesEl,
|
|
933
961
|
sessionListEl: sessionListEl,
|
|
934
962
|
scrollToBottom: scrollToBottom,
|
|
963
|
+
forceScrollToBottom: forceScrollToBottom,
|
|
935
964
|
basePath: basePath,
|
|
936
965
|
toggleUsagePanel: toggleUsagePanel,
|
|
937
966
|
toggleStatusPanel: toggleStatusPanel,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="GitHub Copilot CLI">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#24292f"/>
|
|
3
|
+
<path d="M15 25c0-8 7-14 17-14s17 6 17 14v15c0 8-7 13-17 13s-17-5-17-13zm8 1v13c0 4 4 7 9 7s9-3 9-7V26c0-4-4-7-9-7s-9 3-9 7z" fill="#fff"/>
|
|
4
|
+
<circle cx="27" cy="30" r="3" fill="#24292f"/><circle cx="37" cy="30" r="3" fill="#24292f"/>
|
|
5
|
+
</svg>
|
|
@@ -434,6 +434,7 @@
|
|
|
434
434
|
on hover/active, and a 4-direction drop-shadow + white glow on the
|
|
435
435
|
emoji img for readability on either background. */
|
|
436
436
|
.project-switcher-item .cmd-palette-item-icon {
|
|
437
|
+
position: relative;
|
|
437
438
|
width: 44px;
|
|
438
439
|
height: 44px;
|
|
439
440
|
font-size: 28px;
|
|
@@ -447,6 +448,26 @@
|
|
|
447
448
|
flex-shrink: 0;
|
|
448
449
|
transition: background 0.15s, color 0.15s;
|
|
449
450
|
}
|
|
451
|
+
.project-switcher-external-badge {
|
|
452
|
+
position: absolute;
|
|
453
|
+
right: -5px;
|
|
454
|
+
bottom: -5px;
|
|
455
|
+
width: 17px;
|
|
456
|
+
height: 17px;
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
justify-content: center;
|
|
460
|
+
border: 2px solid var(--bg);
|
|
461
|
+
border-radius: 50%;
|
|
462
|
+
background: var(--warning);
|
|
463
|
+
color: var(--bg);
|
|
464
|
+
pointer-events: none;
|
|
465
|
+
}
|
|
466
|
+
.project-switcher-item .cmd-palette-item-icon .project-switcher-external-badge .lucide {
|
|
467
|
+
width: 9px;
|
|
468
|
+
height: 9px;
|
|
469
|
+
stroke-width: 2.8;
|
|
470
|
+
}
|
|
450
471
|
.project-switcher-item .cmd-palette-item-icon .lucide {
|
|
451
472
|
width: 22px;
|
|
452
473
|
height: 22px;
|
|
@@ -515,8 +536,7 @@
|
|
|
515
536
|
letter-spacing: 0.5px;
|
|
516
537
|
}
|
|
517
538
|
|
|
518
|
-
/* Disabled
|
|
519
|
-
valid switch target, so skip highlight, skip click, visually dim. */
|
|
539
|
+
/* Disabled tiles are skipped by keyboard and pointer selection. */
|
|
520
540
|
.project-switcher-item.disabled {
|
|
521
541
|
opacity: 0.35;
|
|
522
542
|
cursor: not-allowed;
|
|
@@ -1257,20 +1257,27 @@
|
|
|
1257
1257
|
z-index: 1;
|
|
1258
1258
|
}
|
|
1259
1259
|
|
|
1260
|
-
/*
|
|
1261
|
-
.
|
|
1262
|
-
|
|
1263
|
-
cursor: not-allowed;
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
.icon-strip-wt-item.wt-disabled::after {
|
|
1267
|
-
content: "\1F6AB";
|
|
1260
|
+
/* Worktree registered outside the main project folder. It remains usable;
|
|
1261
|
+
the badge communicates location without treating it as an error. */
|
|
1262
|
+
.worktree-external-badge {
|
|
1268
1263
|
position: absolute;
|
|
1269
|
-
|
|
1264
|
+
right: 5px;
|
|
1265
|
+
bottom: 1px;
|
|
1266
|
+
width: 14px;
|
|
1267
|
+
height: 14px;
|
|
1268
|
+
display: flex;
|
|
1269
|
+
align-items: center;
|
|
1270
|
+
justify-content: center;
|
|
1271
|
+
border-radius: 50%;
|
|
1272
|
+
border: 2px solid var(--sidebar-bg);
|
|
1273
|
+
background: var(--warning);
|
|
1274
|
+
color: var(--bg);
|
|
1270
1275
|
z-index: 3;
|
|
1271
|
-
|
|
1276
|
+
pointer-events: none;
|
|
1272
1277
|
}
|
|
1273
1278
|
|
|
1279
|
+
.worktree-external-badge .lucide { width: 8px; height: 8px; stroke-width: 2.8; }
|
|
1280
|
+
|
|
1274
1281
|
/* Group add button */
|
|
1275
1282
|
.icon-strip-group-add {
|
|
1276
1283
|
width: 30px;
|
|
@@ -1420,11 +1427,20 @@ select.wt-modal-input {
|
|
|
1420
1427
|
opacity: 0.85;
|
|
1421
1428
|
}
|
|
1422
1429
|
|
|
1423
|
-
.mobile-
|
|
1424
|
-
|
|
1425
|
-
|
|
1430
|
+
.mobile-worktree-external-badge {
|
|
1431
|
+
width: 20px;
|
|
1432
|
+
height: 20px;
|
|
1433
|
+
display: inline-flex;
|
|
1434
|
+
align-items: center;
|
|
1435
|
+
justify-content: center;
|
|
1436
|
+
border-radius: 7px;
|
|
1437
|
+
background: color-mix(in srgb, var(--warning) 14%, transparent);
|
|
1438
|
+
color: var(--warning);
|
|
1439
|
+
flex-shrink: 0;
|
|
1426
1440
|
}
|
|
1427
1441
|
|
|
1442
|
+
.mobile-worktree-external-badge .lucide { width: 12px; height: 12px; stroke-width: 2.4; }
|
|
1443
|
+
|
|
1428
1444
|
.mobile-folder-chevron {
|
|
1429
1445
|
font-size: 8px;
|
|
1430
1446
|
color: var(--text-dimmer);
|
package/lib/public/css/input.css
CHANGED
|
@@ -667,6 +667,50 @@
|
|
|
667
667
|
position: relative;
|
|
668
668
|
}
|
|
669
669
|
|
|
670
|
+
.background-tasks-bar {
|
|
671
|
+
max-width: var(--content-width);
|
|
672
|
+
margin: 0 auto 8px;
|
|
673
|
+
border: 1px solid var(--border);
|
|
674
|
+
border-radius: 8px;
|
|
675
|
+
background: var(--input-bg);
|
|
676
|
+
overflow: hidden;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.background-tasks-toggle {
|
|
680
|
+
width: 100%;
|
|
681
|
+
display: flex;
|
|
682
|
+
align-items: center;
|
|
683
|
+
gap: 7px;
|
|
684
|
+
padding: 8px 10px;
|
|
685
|
+
border: 0;
|
|
686
|
+
background: transparent;
|
|
687
|
+
color: var(--text-secondary);
|
|
688
|
+
cursor: pointer;
|
|
689
|
+
font: inherit;
|
|
690
|
+
text-align: left;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.background-tasks-chip, .session-background-task-count {
|
|
694
|
+
display: inline-flex;
|
|
695
|
+
align-items: center;
|
|
696
|
+
justify-content: center;
|
|
697
|
+
min-width: 16px;
|
|
698
|
+
height: 16px;
|
|
699
|
+
padding: 0 4px;
|
|
700
|
+
border-radius: 8px;
|
|
701
|
+
background: var(--accent);
|
|
702
|
+
color: var(--bg);
|
|
703
|
+
font-size: 10px;
|
|
704
|
+
font-weight: 700;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.background-tasks-list { padding: 0 10px 8px; }
|
|
708
|
+
.background-task-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-top: 1px solid var(--border-subtle); }
|
|
709
|
+
.background-task-description { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
710
|
+
.background-task-type { padding: 2px 6px; border-radius: 5px; background: var(--code-bg); color: var(--text-muted); font-size: 11px; }
|
|
711
|
+
.background-task-stop { border: 1px solid var(--border); border-radius: 5px; padding: 3px 7px; background: transparent; color: var(--text-secondary); cursor: pointer; font: inherit; font-size: 12px; }
|
|
712
|
+
.background-task-stop:hover { color: var(--text); border-color: var(--text-muted); }
|
|
713
|
+
|
|
670
714
|
#input-row {
|
|
671
715
|
display: flex;
|
|
672
716
|
flex-direction: column;
|
|
@@ -790,6 +834,7 @@
|
|
|
790
834
|
opacity: 0.35;
|
|
791
835
|
cursor: default;
|
|
792
836
|
}
|
|
837
|
+
.vendor-toggle-btn.disabled:not(.active) { display: none; }
|
|
793
838
|
.vendor-toggle-icon {
|
|
794
839
|
width: 16px;
|
|
795
840
|
height: 16px;
|
|
@@ -799,6 +844,17 @@
|
|
|
799
844
|
.vendor-toggle-label {
|
|
800
845
|
pointer-events: none;
|
|
801
846
|
}
|
|
847
|
+
.vendor-toggle-btn.experimental::after,
|
|
848
|
+
.vendor-experimental-badge {
|
|
849
|
+
content: "🧪";
|
|
850
|
+
font-size: 10px;
|
|
851
|
+
line-height: 1;
|
|
852
|
+
font-weight: 400;
|
|
853
|
+
filter: saturate(0.85);
|
|
854
|
+
}
|
|
855
|
+
.vendor-experimental-badge {
|
|
856
|
+
margin-left: auto;
|
|
857
|
+
}
|
|
802
858
|
@media (min-width: 901px) {
|
|
803
859
|
.vendor-toggle-btn:not(.active) .vendor-toggle-label { display: none; }
|
|
804
860
|
.vendor-toggle-btn:not(.active) { padding: 0 8px; }
|
package/lib/public/css/mates.css
CHANGED
|
@@ -682,6 +682,12 @@
|
|
|
682
682
|
.mate-vendor-label {
|
|
683
683
|
pointer-events: none;
|
|
684
684
|
}
|
|
685
|
+
.mate-vendor-btn.experimental::after {
|
|
686
|
+
content: "🧪";
|
|
687
|
+
font-size: 9px;
|
|
688
|
+
line-height: 1;
|
|
689
|
+
font-weight: 400;
|
|
690
|
+
}
|
|
685
691
|
.mate-vendor-btn:not(.active) .mate-vendor-label { display: none; }
|
|
686
692
|
|
|
687
693
|
/* Collapse button inside mate header: white to match header style */
|
package/lib/public/css/menus.css
CHANGED
|
@@ -43,30 +43,9 @@
|
|
|
43
43
|
#header-rename-btn:hover { color: var(--text-secondary); background: rgba(var(--overlay-rgb),0.04); border-color: var(--border); }
|
|
44
44
|
#header-rename-btn .lucide { width: 13px; height: 13px; }
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
justify-content: center;
|
|
50
|
-
width: 24px;
|
|
51
|
-
height: 24px;
|
|
52
|
-
border: 1px solid transparent;
|
|
53
|
-
background: none;
|
|
54
|
-
color: var(--text-dimmer);
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
border-radius: 8px;
|
|
57
|
-
flex-shrink: 0;
|
|
58
|
-
padding: 0;
|
|
59
|
-
margin-left: 4px;
|
|
60
|
-
transition: color 0.15s, background 0.15s, border-color 0.15s;
|
|
61
|
-
}
|
|
62
|
-
#header-add-worker-btn:hover { color: var(--text-secondary); background: rgba(var(--overlay-rgb),0.04); border-color: var(--border); }
|
|
63
|
-
#header-add-worker-btn .lucide { width: 13px; height: 13px; }
|
|
64
|
-
#header-add-worker-btn.hidden { display: none; }
|
|
65
|
-
body.dm-mode #header-add-worker-btn { display: none; }
|
|
66
|
-
|
|
67
|
-
/* "Close terminal" button: sits just left of the rename pencil during a live
|
|
68
|
-
TUI session. Matches the rename button's chrome; reds out on hover since it
|
|
69
|
-
stops the running claude (the session stays resumable). */
|
|
46
|
+
/* "Close terminal" button for a live TUI session. Matches the session-control
|
|
47
|
+
chrome; reds out on hover since it stops the running agent while preserving
|
|
48
|
+
the resumable session. */
|
|
70
49
|
#header-tui-close-btn {
|
|
71
50
|
display: flex;
|
|
72
51
|
align-items: center;
|
|
@@ -667,6 +646,41 @@ body.dm-mode #header-add-worker-btn { display: none; }
|
|
|
667
646
|
color: var(--text-dimmer);
|
|
668
647
|
font-style: italic;
|
|
669
648
|
}
|
|
649
|
+
.config-model-state {
|
|
650
|
+
display: flex;
|
|
651
|
+
align-items: center;
|
|
652
|
+
gap: 10px;
|
|
653
|
+
min-width: 280px;
|
|
654
|
+
padding: 10px 14px;
|
|
655
|
+
color: var(--text-secondary);
|
|
656
|
+
font-size: 12px;
|
|
657
|
+
white-space: normal;
|
|
658
|
+
}
|
|
659
|
+
.config-model-state > div { flex: 1; min-width: 0; }
|
|
660
|
+
.config-model-state-title { color: var(--text); font-weight: 600; }
|
|
661
|
+
.config-model-state-detail { margin-top: 2px; color: var(--text-muted); line-height: 1.35; }
|
|
662
|
+
.config-model-spinner {
|
|
663
|
+
width: 14px;
|
|
664
|
+
height: 14px;
|
|
665
|
+
flex: 0 0 auto;
|
|
666
|
+
border: 2px solid var(--border);
|
|
667
|
+
border-top-color: var(--accent);
|
|
668
|
+
border-radius: 50%;
|
|
669
|
+
animation: config-model-spin 0.8s linear infinite;
|
|
670
|
+
}
|
|
671
|
+
@keyframes config-model-spin { to { transform: rotate(360deg); } }
|
|
672
|
+
.config-model-retry {
|
|
673
|
+
flex: 0 0 auto;
|
|
674
|
+
border: 1px solid var(--border);
|
|
675
|
+
border-radius: 5px;
|
|
676
|
+
padding: 4px 8px;
|
|
677
|
+
background: var(--surface-raised);
|
|
678
|
+
color: var(--text-secondary);
|
|
679
|
+
font: inherit;
|
|
680
|
+
cursor: pointer;
|
|
681
|
+
}
|
|
682
|
+
.config-model-retry:hover { color: var(--text); border-color: var(--text-muted); }
|
|
683
|
+
.config-radio-item.pending { color: var(--accent); opacity: 0.75; }
|
|
670
684
|
|
|
671
685
|
/* Segmented control for effort */
|
|
672
686
|
.config-segmented {
|
|
@@ -980,4 +994,3 @@ body.dm-mode #header-add-worker-btn { display: none; }
|
|
|
980
994
|
#config-chip .config-chip-icon { display: inline; width: 14px; height: 14px; }
|
|
981
995
|
#config-chip-label { display: none; }
|
|
982
996
|
}
|
|
983
|
-
|
|
@@ -5,12 +5,21 @@
|
|
|
5
5
|
#messages {
|
|
6
6
|
flex: 1;
|
|
7
7
|
overflow-y: auto;
|
|
8
|
+
overflow-x: hidden;
|
|
8
9
|
-webkit-overflow-scrolling: touch;
|
|
9
10
|
overscroll-behavior-y: contain;
|
|
10
11
|
padding: 20px 0 12px;
|
|
11
12
|
position: relative;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/* Rich message content can contain wide tables, diagrams, or generated HTML.
|
|
16
|
+
Keep that content inside the chat scroller; nested code blocks still own
|
|
17
|
+
their intentional horizontal scrolling. */
|
|
18
|
+
#messages > * {
|
|
19
|
+
min-width: 0;
|
|
20
|
+
max-width: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
/* --- Remote cursors (Figma-style) --- */
|
|
15
24
|
.remote-cursor {
|
|
16
25
|
pointer-events: none;
|
package/lib/public/css/pane.css
CHANGED
|
@@ -23,6 +23,10 @@ body.pane-mode #sticky-notes-container {
|
|
|
23
23
|
display: none !important;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
body.pane-mode .notif-banner-container {
|
|
27
|
+
display: none !important;
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
body.pane-mode #main-area {
|
|
27
31
|
border: 0;
|
|
28
32
|
border-radius: 0;
|
|
@@ -96,7 +100,8 @@ body.pane-mode #input-area {
|
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
.split-pane-title {
|
|
99
|
-
flex: 1;
|
|
103
|
+
flex: 0 1 auto;
|
|
104
|
+
max-width: 46%;
|
|
100
105
|
min-width: 0;
|
|
101
106
|
overflow: hidden;
|
|
102
107
|
text-overflow: ellipsis;
|
|
@@ -198,15 +203,18 @@ button.split-pair-role:hover { filter: brightness(1.25); }
|
|
|
198
203
|
max-width: var(--content-width);
|
|
199
204
|
margin: 0 auto;
|
|
200
205
|
padding: 4px 10px;
|
|
201
|
-
border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
|
|
202
|
-
border-bottom: 0;
|
|
203
206
|
border-radius: 8px 8px 0 0;
|
|
204
207
|
background: color-mix(in srgb, var(--accent) 8%, var(--bg));
|
|
205
208
|
color: var(--text-secondary);
|
|
206
209
|
font-size: 11px;
|
|
207
210
|
line-height: 1.4;
|
|
211
|
+
transition: box-shadow 0.2s;
|
|
208
212
|
}
|
|
209
213
|
.pane-delegation-notice.visible { display: flex; }
|
|
214
|
+
.pane-delegation-notice.visible:has(+ #input-wrapper #input-row:focus-within) {
|
|
215
|
+
box-shadow: 0 0 0 1px var(--border);
|
|
216
|
+
clip-path: inset(-1px -1px 0 -1px);
|
|
217
|
+
}
|
|
210
218
|
.pane-delegation-notice.visible + #input-wrapper #input-row {
|
|
211
219
|
border-radius: 0 0 8px 8px;
|
|
212
220
|
}
|
|
@@ -279,12 +287,17 @@ button.split-pair-role:hover { filter: brightness(1.25); }
|
|
|
279
287
|
color: var(--text-dimmer);
|
|
280
288
|
cursor: pointer;
|
|
281
289
|
flex-shrink: 0;
|
|
290
|
+
margin-left: auto;
|
|
282
291
|
}
|
|
283
292
|
|
|
284
293
|
.split-pane-context.has-data {
|
|
285
294
|
display: inline-flex;
|
|
286
295
|
}
|
|
287
296
|
|
|
297
|
+
.split-pane-context:not(.has-data) + .split-pane-close {
|
|
298
|
+
margin-left: auto;
|
|
299
|
+
}
|
|
300
|
+
|
|
288
301
|
.split-pane-context:hover {
|
|
289
302
|
background: var(--bg-alt);
|
|
290
303
|
color: var(--text);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* In an iOS Home Screen app, a 100%-tall root can be measured against the
|
|
2
|
+
shortened safe-area viewport. Use the physical viewport for the root while
|
|
3
|
+
retaining safe-area padding on controls inside the app. */
|
|
4
|
+
@media (max-width: 768px) {
|
|
5
|
+
html.pwa-standalone,
|
|
6
|
+
html.pwa-standalone body {
|
|
7
|
+
height: 100vh;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@media (max-width: 768px) and (display-mode: standalone),
|
|
12
|
+
(max-width: 768px) and (display-mode: fullscreen) {
|
|
13
|
+
html,
|
|
14
|
+
body {
|
|
15
|
+
height: 100vh;
|
|
16
|
+
}
|
|
17
|
+
}
|