clay-server 5.1.0-beta.2 → 5.1.0-beta.3
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/bin/cli.js +9 -91
- package/lib/builtin-mates.js +7 -7
- package/lib/daemon-settings.js +11 -0
- package/lib/daemon.js +8 -37
- package/lib/linear-store.js +35 -8
- package/lib/mate-identity-file.js +39 -0
- package/lib/mate-knowledge-sync.js +1 -1
- package/lib/mate-ready-creation.js +2 -1
- package/lib/mates-identity.js +4 -4
- package/lib/mates-prompts.js +4 -3
- package/lib/mates.js +12 -11
- package/lib/os-users.js +5 -16
- package/lib/project-connection.js +0 -7
- package/lib/project-debate.js +3 -2
- package/lib/project-filesystem.js +21 -39
- package/lib/project-mate-interaction.js +7 -6
- package/lib/project-server-settings.js +31 -0
- package/lib/project-sessions.js +57 -184
- package/lib/project.js +3 -3
- package/lib/public/app.js +6 -37
- package/lib/public/css/input.css +3 -1
- package/lib/public/css/menus.css +3 -0
- package/lib/public/css/overlays.css +7 -0
- package/lib/public/css/project-settings-modal.css +56 -0
- package/lib/public/css/server-settings-system.css +125 -0
- package/lib/public/css/session-github.css +25 -16
- package/lib/public/css/settings-ui.css +247 -22
- package/lib/public/css/shared-browser.css +7 -3
- package/lib/public/css/title-bar.css +5 -1
- package/lib/public/index.html +173 -447
- package/lib/public/modules/account-island.js +9 -7
- package/lib/public/modules/admin-settings-email.js +197 -0
- package/lib/public/modules/admin-settings-invitations.js +183 -0
- package/lib/public/modules/admin-settings-projects.js +198 -0
- package/lib/public/modules/admin-settings-ui.js +100 -0
- package/lib/public/modules/admin-settings-users.js +331 -0
- package/lib/public/modules/admin.js +19 -949
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-messages.js +13 -52
- package/lib/public/modules/app-rate-limit.js +70 -12
- package/lib/public/modules/avatar.js +6 -1
- package/lib/public/modules/context-sources.js +27 -18
- package/lib/public/modules/default-ai.js +14 -7
- package/lib/public/modules/header-tui-font.js +10 -20
- package/lib/public/modules/home-mate-avatar-editor.js +2 -2
- package/lib/public/modules/linear-settings.js +3 -2
- package/lib/public/modules/markdown.js +5 -6
- package/lib/public/modules/notification-settings.js +81 -0
- package/lib/public/modules/notifications.js +44 -28
- package/lib/public/modules/personal-settings-dialog.js +51 -0
- package/lib/public/modules/profile.js +15 -6
- package/lib/public/modules/project-settings-environment.js +106 -0
- package/lib/public/modules/project-settings.js +72 -628
- package/lib/public/modules/server-settings-controls.js +316 -0
- package/lib/public/modules/server-settings-environment.js +194 -0
- package/lib/public/modules/server-settings-navigation.js +39 -0
- package/lib/public/modules/server-settings-state.js +54 -0
- package/lib/public/modules/server-settings.js +116 -788
- package/lib/public/modules/server-storage-settings.js +84 -0
- package/lib/public/modules/session-github.js +2 -1
- package/lib/public/modules/session-presence-ui.js +1 -1
- package/lib/public/modules/settings-env-values.js +34 -0
- package/lib/public/modules/settings-select.js +121 -0
- package/lib/public/modules/shared-browser.js +22 -12
- package/lib/public/modules/stt-picker.js +14 -5
- package/lib/public/modules/terminal-prefs.js +22 -0
- package/lib/public/modules/theme.js +88 -52
- package/lib/public/modules/user-settings-account.js +318 -0
- package/lib/public/modules/user-settings-appearance.js +55 -0
- package/lib/public/modules/user-settings-editors.js +24 -0
- package/lib/public/modules/user-settings-integrations.js +104 -0
- package/lib/public/modules/user-settings-layout.js +80 -0
- package/lib/public/modules/user-settings-preferences.js +48 -0
- package/lib/public/modules/user-settings-profile.js +53 -0
- package/lib/public/modules/user-settings-themes.js +38 -0
- package/lib/public/modules/user-settings-voice.js +75 -0
- package/lib/public/modules/user-settings.js +53 -480
- package/lib/public/style.css +4 -0
- package/lib/sdk-message-processor.js +16 -4
- package/lib/sdk-quota-snapshot.js +37 -0
- package/lib/server-appearance-settings.js +71 -0
- package/lib/server-linear.js +14 -8
- package/lib/server-mate-instructions.js +2 -2
- package/lib/server-mates.js +2 -1
- package/lib/server-notification-settings.js +67 -0
- package/lib/server-settings.js +4 -0
- package/lib/server-storage.js +57 -0
- package/lib/server.js +10 -2
- package/lib/sessions.js +3 -4
- package/lib/startup-projects.js +40 -0
- package/lib/storage-native-walk.js +85 -0
- package/lib/storage-usage.js +144 -0
- package/lib/users-preferences.js +0 -74
- package/lib/users.js +0 -4
- package/lib/ws-schema.js +2 -4
- package/lib/yoke/acp-process-manager.js +2 -2
- package/lib/yoke/adapters/codex.js +12 -52
- package/lib/yoke/codex-app-server.js +2 -2
- package/lib/yoke/codex-model-catalog.js +52 -0
- package/lib/yoke/codex-rate-limits.js +26 -0
- package/package.json +3 -3
|
@@ -80,7 +80,6 @@ export function openDm(targetUserId, opts) {
|
|
|
80
80
|
if (mates[i] && mates[i].id === targetUserId) isMateTarget = true;
|
|
81
81
|
}
|
|
82
82
|
if (isMateTarget) {
|
|
83
|
-
if (store.get('projectMateDmsEnabled') === false) return;
|
|
84
83
|
showHomeHub();
|
|
85
84
|
openHomeChat(targetUserId);
|
|
86
85
|
return;
|
|
@@ -152,7 +151,6 @@ function showMateOnboarding(callback) {
|
|
|
152
151
|
export function enterDmMode(key, targetUser, messages) {
|
|
153
152
|
console.log("[DEBUG enterDmMode] key=" + key, "isMate=" + (targetUser && targetUser.isMate), "messages=" + (messages ? messages.length : 0));
|
|
154
153
|
if (targetUser && targetUser.isMate) {
|
|
155
|
-
if (store.get('projectMateDmsEnabled') === false) return;
|
|
156
154
|
showHomeHub();
|
|
157
155
|
openHomeChat(targetUser.id);
|
|
158
156
|
return;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { handlePersonalSettingsMessage } from './user-settings-preferences.js';
|
|
2
|
+
import { handleServerUpdate } from './server-settings-controls.js';
|
|
1
3
|
import { handleYouMessage } from './you.js';
|
|
2
4
|
import { handleYouActivity } from './you-activity.js';
|
|
3
5
|
import { handleProjectDebateMessage } from './project-debate-workspace.js';
|
|
@@ -53,9 +55,10 @@ import { showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundE
|
|
|
53
55
|
import { handleFsList, handleFsRead, handleFileChanged, handleDirChanged, handleFileHistory, handleGitDiff, handleFileAt, refreshIfOpen, getPendingNavigate, handleFsSearch, presentMarkdownEdit } from './filebrowser.js';
|
|
54
56
|
import { beginMarkdownTurn, finishMarkdownTurn, markdownPathFromToolInput } from './markdown-live-edit.js';
|
|
55
57
|
import { forwardPaneMarkdownPresentation } from './pane-bridge.js';
|
|
56
|
-
import {
|
|
58
|
+
import { handleProjectOwnerChanged } from './project-settings.js';
|
|
59
|
+
import { handleProjectEnv, handleProjectEnvSaved } from './project-settings-environment.js';
|
|
57
60
|
import { handleProjectSessionVisibilityDefault, refreshProjectSessionVisibilitySettings } from './project-session-visibility-settings.js';
|
|
58
|
-
import { updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged,
|
|
61
|
+
import { updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleServerSettingResult } from './server-settings.js';
|
|
59
62
|
import { handleTermList, handleTermCreated, sendTerminalCommand, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed } from './terminal.js';
|
|
60
63
|
import { attachTuiView, detachTuiView, setTuiSuspendedView, tuiHandleTermOutput, tuiHandleTermResized, tuiHandleTermExited, tuiHandleTermClosed } from './session-tui-view.js';
|
|
61
64
|
import { handleTuiTranscriptState } from './tui-grab.js';
|
|
@@ -115,6 +118,8 @@ var connectOverlay = document.getElementById("connect-overlay");
|
|
|
115
118
|
initMessageDeliveryUi();
|
|
116
119
|
|
|
117
120
|
export function processMessage(msg) {
|
|
121
|
+
if (["update_available", "up_to_date", "update_started", "update_check_failed"].indexOf(msg.type) !== -1) handleServerUpdate(msg);
|
|
122
|
+
if (/^(set_pin|set_keep_awake|set_inherit_groups|set_image_retention|set_update_channel|restart_server|shutdown_server)_result$/.test(msg.type)) handleServerSettingResult(msg);
|
|
118
123
|
if (handleProjectDebateMessage(msg)) return;
|
|
119
124
|
if (handleMcpConnectionMessage(msg)) return;
|
|
120
125
|
if (handleSharedBrowserMessage(msg)) return;
|
|
@@ -881,11 +886,8 @@ export function processMessage(msg) {
|
|
|
881
886
|
} else if (_prevSid) {
|
|
882
887
|
delete store.get('sessionDrafts')[_prevSid];
|
|
883
888
|
}
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
// to existing sessions too (born-GUI viewed under TUI pref runs
|
|
887
|
-
// claude --resume in xterm; born-TUI viewed under GUI pref was
|
|
888
|
-
// in-place converted to GUI by the server before this message).
|
|
889
|
+
// Live legacy terminals keep their runtime presentation. Idle legacy
|
|
890
|
+
// sessions are hydrated into chat by the server before this message.
|
|
889
891
|
var _effectiveMode = msg.runtimeMode || msg.mode || "gui";
|
|
890
892
|
var _effectiveTerminalId = (typeof msg.runtimeTerminalId === "number")
|
|
891
893
|
? msg.runtimeTerminalId
|
|
@@ -1572,15 +1574,10 @@ export function processMessage(msg) {
|
|
|
1572
1574
|
break;
|
|
1573
1575
|
|
|
1574
1576
|
case "fs_read_result":
|
|
1575
|
-
|
|
1576
|
-
handleInstructionsRead(msg);
|
|
1577
|
-
} else {
|
|
1578
|
-
handleFsRead(msg);
|
|
1579
|
-
}
|
|
1577
|
+
handleFsRead(msg);
|
|
1580
1578
|
break;
|
|
1581
1579
|
|
|
1582
1580
|
case "fs_write_result":
|
|
1583
|
-
handleInstructionsWrite(msg);
|
|
1584
1581
|
break;
|
|
1585
1582
|
|
|
1586
1583
|
case "project_env_result":
|
|
@@ -1591,22 +1588,12 @@ export function processMessage(msg) {
|
|
|
1591
1588
|
handleProjectEnvSaved(msg);
|
|
1592
1589
|
break;
|
|
1593
1590
|
|
|
1594
|
-
case "global_claude_md_result":
|
|
1595
|
-
handleGlobalClaudeMdRead(msg);
|
|
1596
|
-
break;
|
|
1597
|
-
|
|
1598
|
-
case "write_global_claude_md_result":
|
|
1599
|
-
handleGlobalClaudeMdWrite(msg);
|
|
1600
|
-
break;
|
|
1601
|
-
|
|
1602
1591
|
case "shared_env_result":
|
|
1603
1592
|
handleSharedEnv(msg);
|
|
1604
|
-
handleProjectSharedEnv(msg);
|
|
1605
1593
|
break;
|
|
1606
1594
|
|
|
1607
1595
|
case "set_shared_env_result":
|
|
1608
1596
|
handleSharedEnvSaved(msg);
|
|
1609
|
-
handleProjectSharedEnvSaved(msg);
|
|
1610
1597
|
break;
|
|
1611
1598
|
|
|
1612
1599
|
case "fs_file_changed":
|
|
@@ -2187,30 +2174,16 @@ export function processMessage(msg) {
|
|
|
2187
2174
|
handleKeepAwakeChanged(msg);
|
|
2188
2175
|
break;
|
|
2189
2176
|
|
|
2190
|
-
case "set_inherit_groups_result":
|
|
2191
|
-
case "inherit_groups_changed":
|
|
2192
|
-
handleInheritGroupsChanged(msg);
|
|
2193
|
-
break;
|
|
2194
|
-
|
|
2195
2177
|
case "set_auto_continue_result":
|
|
2196
2178
|
case "auto_continue_changed":
|
|
2197
2179
|
handleAutoContinueChanged(msg);
|
|
2198
2180
|
break;
|
|
2199
2181
|
|
|
2200
|
-
case "set_claude_open_mode_result":
|
|
2201
|
-
case "claude_open_mode_changed":
|
|
2202
|
-
if (msg.claudeOpenMode === "tui" || msg.claudeOpenMode === "gui") {
|
|
2203
|
-
store.set({ claudeOpenMode: msg.claudeOpenMode });
|
|
2204
|
-
// Reflect into the user-settings toggle if it's already in the DOM.
|
|
2205
|
-
var _comToggle = document.getElementById("us-claude-open-mode");
|
|
2206
|
-
if (_comToggle) _comToggle.checked = msg.claudeOpenMode === "tui";
|
|
2207
|
-
}
|
|
2208
|
-
break;
|
|
2209
|
-
|
|
2210
2182
|
case "claude_allow_list":
|
|
2183
|
+
handlePersonalSettingsMessage(msg);
|
|
2211
2184
|
// Initial state for the user-settings allow-list editor.
|
|
2212
2185
|
var _alTa = document.getElementById("us-claude-allow-list");
|
|
2213
|
-
if (_alTa && Array.isArray(msg.user)) {
|
|
2186
|
+
if (_alTa && Array.isArray(msg.user) && !store.get("userAllowDirty")) {
|
|
2214
2187
|
_alTa.value = msg.user.join("\n");
|
|
2215
2188
|
}
|
|
2216
2189
|
var _alManaged = document.getElementById("us-claude-allow-managed");
|
|
@@ -2226,19 +2199,7 @@ export function processMessage(msg) {
|
|
|
2226
2199
|
break;
|
|
2227
2200
|
|
|
2228
2201
|
case "set_claude_user_allow_list_result":
|
|
2229
|
-
|
|
2230
|
-
if (_alStatus) {
|
|
2231
|
-
if (msg.ok) {
|
|
2232
|
-
_alStatus.textContent = "Saved (applies on next claude invocation)";
|
|
2233
|
-
_alStatus.classList.remove("error");
|
|
2234
|
-
setTimeout(function () {
|
|
2235
|
-
if (_alStatus.textContent.indexOf("Saved") === 0) _alStatus.textContent = "";
|
|
2236
|
-
}, 4000);
|
|
2237
|
-
} else {
|
|
2238
|
-
_alStatus.textContent = "Save failed: " + (msg.error || "unknown");
|
|
2239
|
-
_alStatus.classList.add("error");
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
2202
|
+
handlePersonalSettingsMessage(msg);
|
|
2242
2203
|
break;
|
|
2243
2204
|
|
|
2244
2205
|
case "restart_server_result":
|
|
@@ -83,6 +83,22 @@ function setActiveRateLimitState(next) {
|
|
|
83
83
|
rateLimitResetState = next;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
function extraUsageDescription(msg) {
|
|
87
|
+
if (msg.vendor && msg.vendor !== "claude") return "";
|
|
88
|
+
var reason = msg.overageDisabledReason;
|
|
89
|
+
if (reason === "out_of_credits") return "Extra usage has no credits remaining";
|
|
90
|
+
if (reason === "fetch_error") return "Extra usage availability could not be checked";
|
|
91
|
+
if (reason && reason !== "unknown") return "Extra usage is unavailable for this account";
|
|
92
|
+
if (msg.overageStatus === "rejected") {
|
|
93
|
+
var reset = formatResetTime(msg.overageResetsAt);
|
|
94
|
+
return "Extra usage limit reached" + (reset ? "; resets in " + reset : "");
|
|
95
|
+
}
|
|
96
|
+
if (msg.isUsingOverage) return "Extra usage is currently being used";
|
|
97
|
+
if (msg.overageEnabled === false) return "Extra usage is turned off";
|
|
98
|
+
if (msg.overageEnabled === true) return "Extra usage is enabled";
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
function rateLimitTypeLabel(type) {
|
|
87
103
|
if (!type) return "Usage";
|
|
88
104
|
var labels = {
|
|
@@ -90,7 +106,8 @@ function rateLimitTypeLabel(type) {
|
|
|
90
106
|
"seven_day": "7-day",
|
|
91
107
|
"seven_day_opus": "7-day Opus",
|
|
92
108
|
"seven_day_sonnet": "7-day Sonnet",
|
|
93
|
-
"overage": "
|
|
109
|
+
"overage": "Extra usage",
|
|
110
|
+
"seven_day_overage_included": "7-day included extra usage",
|
|
94
111
|
};
|
|
95
112
|
return labels[type] || type;
|
|
96
113
|
}
|
|
@@ -163,6 +180,12 @@ function showRateLimitPopover(text, isRejected) {
|
|
|
163
180
|
pop.className = "rate-limit-popover" + (isRejected ? " rejected" : "");
|
|
164
181
|
pop.textContent = text;
|
|
165
182
|
rateLimitIndicatorEl.appendChild(pop);
|
|
183
|
+
if (typeof pop.getBoundingClientRect === "function") {
|
|
184
|
+
var bounds = pop.getBoundingClientRect();
|
|
185
|
+
var viewportWidth = document.documentElement.clientWidth;
|
|
186
|
+
var shift = bounds.left < 16 ? 16 - bounds.left : Math.min(0, viewportWidth - 16 - bounds.right);
|
|
187
|
+
pop.style.marginLeft = shift + "px";
|
|
188
|
+
}
|
|
166
189
|
|
|
167
190
|
// Auto-dismiss after 5s
|
|
168
191
|
var fadeTimer = setTimeout(function () {
|
|
@@ -182,9 +205,7 @@ function clearRateLimitIndicator() {
|
|
|
182
205
|
|
|
183
206
|
function formatResetTime(resetsAt) {
|
|
184
207
|
if (!resetsAt) return "";
|
|
185
|
-
var
|
|
186
|
-
var now = new Date();
|
|
187
|
-
var diff = resetsAt - now.getTime();
|
|
208
|
+
var diff = resetsAt - Date.now();
|
|
188
209
|
if (diff <= 0) return "";
|
|
189
210
|
var hrs = Math.floor(diff / 3600000);
|
|
190
211
|
var mins = Math.floor((diff % 3600000) / 60000);
|
|
@@ -200,10 +221,31 @@ function rateLimitTypeShortLabel(type) {
|
|
|
200
221
|
return type || "";
|
|
201
222
|
}
|
|
202
223
|
|
|
224
|
+
function quotaWindowLabel(entry) {
|
|
225
|
+
var mins = entry.windowDurationMins;
|
|
226
|
+
if (!Number.isFinite(mins) || mins <= 0) return "Usage";
|
|
227
|
+
if (mins % 1440 === 0) return (mins / 1440) + "d";
|
|
228
|
+
if (mins % 60 === 0) return (mins / 60) + "h";
|
|
229
|
+
return mins + "m";
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function applyQuotaSnapshot(msg) {
|
|
233
|
+
var next = Object.assign({}, getActiveRateLimitState());
|
|
234
|
+
Object.keys(next).forEach(function (key) {
|
|
235
|
+
// Retire the old inferred Codex windows as soon as real metadata arrives.
|
|
236
|
+
if (!next[key].source || next[key].limitId === msg.limitId) delete next[key];
|
|
237
|
+
});
|
|
238
|
+
msg.quotaWindows.forEach(function (window) {
|
|
239
|
+
if (window.resetsAt && window.resetsAt <= Date.now()) return;
|
|
240
|
+
var key = JSON.stringify([msg.limitId, window.key]);
|
|
241
|
+
next[key] = Object.assign({}, window, { source: "account_snapshot", limitId: msg.limitId });
|
|
242
|
+
});
|
|
243
|
+
setActiveRateLimitState(next);
|
|
244
|
+
}
|
|
245
|
+
|
|
203
246
|
function tickRateLimitUsage() {
|
|
204
247
|
if (!rateLimitUsageEl) return;
|
|
205
|
-
var
|
|
206
|
-
var types = ["five_hour", "seven_day", "seven_day_opus", "seven_day_sonnet"];
|
|
248
|
+
var types = Object.keys(rateLimitResetState);
|
|
207
249
|
var nextState = Object.assign({}, rateLimitResetState);
|
|
208
250
|
var changed = false;
|
|
209
251
|
for (var i = 0; i < types.length; i++) {
|
|
@@ -211,13 +253,8 @@ function tickRateLimitUsage() {
|
|
|
211
253
|
if (!entry || !entry.resetsAt) continue;
|
|
212
254
|
var timeStr = formatResetTime(entry.resetsAt);
|
|
213
255
|
if (!timeStr) { delete nextState[types[i]]; changed = true; continue; }
|
|
214
|
-
parts.push(rateLimitTypeShortLabel(types[i]) + " resets " + timeStr);
|
|
215
256
|
}
|
|
216
257
|
if (changed) setActiveRateLimitState(nextState);
|
|
217
|
-
if (parts.length === 0) {
|
|
218
|
-
renderRateLimitUsage();
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
258
|
renderRateLimitUsage();
|
|
222
259
|
}
|
|
223
260
|
|
|
@@ -247,9 +284,19 @@ function renderRateLimitUsage() {
|
|
|
247
284
|
rateLimitUsageEl.style.display = "";
|
|
248
285
|
|
|
249
286
|
var parts = [];
|
|
250
|
-
var types =
|
|
287
|
+
var types = Object.keys(rateLimitResetState);
|
|
288
|
+
var hasWarning = false;
|
|
251
289
|
for (var i = 0; i < types.length; i++) {
|
|
252
290
|
var entry = rateLimitResetState[types[i]];
|
|
291
|
+
if (entry && entry.source === "account_snapshot") {
|
|
292
|
+
if (entry.resetsAt && entry.resetsAt <= Date.now()) continue;
|
|
293
|
+
var quotaText = quotaWindowLabel(entry);
|
|
294
|
+
if (Number.isFinite(entry.usedPercent)) quotaText += " " + Math.round(entry.usedPercent) + "% used";
|
|
295
|
+
if (entry.resetsAt) quotaText += " · resets " + formatResetTime(entry.resetsAt);
|
|
296
|
+
if (entry.usedPercent >= 80) hasWarning = true;
|
|
297
|
+
parts.push(quotaText);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
253
300
|
if (!entry || !entry.resetsAt) continue;
|
|
254
301
|
var timeStr = formatResetTime(entry.resetsAt);
|
|
255
302
|
if (!timeStr) continue;
|
|
@@ -257,6 +304,7 @@ function renderRateLimitUsage() {
|
|
|
257
304
|
}
|
|
258
305
|
|
|
259
306
|
var label = parts.length > 0 ? parts.join(" · ") : "Check usage";
|
|
307
|
+
rateLimitUsageEl.className = "top-bar-pill usage-check-link " + (hasWarning ? "pill-warning" : "pill-dim");
|
|
260
308
|
var meta = getVendorUsageMeta(activeVendor);
|
|
261
309
|
if (meta) {
|
|
262
310
|
rateLimitUsageEl.href = meta.href;
|
|
@@ -301,6 +349,8 @@ export function initRateLimit() {
|
|
|
301
349
|
|
|
302
350
|
export function handleRateLimitEvent(msg) {
|
|
303
351
|
if (!rateLimitEventAppliesToPane(msg, store.snap())) return;
|
|
352
|
+
// Old Codex history contains quota snapshots misrecorded as rejections.
|
|
353
|
+
if (msg.vendor === "codex" && !msg.source) return;
|
|
304
354
|
if (msg.resetsAt && msg.resetsAt <= Date.now()) {
|
|
305
355
|
var expiredState = Object.assign({}, getActiveRateLimitState());
|
|
306
356
|
if (msg.rateLimitType) delete expiredState[msg.rateLimitType];
|
|
@@ -351,11 +401,19 @@ export function handleRateLimitEvent(msg) {
|
|
|
351
401
|
updateRateLimitIndicator(msg);
|
|
352
402
|
}
|
|
353
403
|
|
|
404
|
+
var extraUsage = extraUsageDescription(msg);
|
|
405
|
+
if (extraUsage) popoverText += ". " + extraUsage;
|
|
354
406
|
showRateLimitPopover(popoverText, isRejected);
|
|
355
407
|
}
|
|
356
408
|
|
|
357
409
|
export function updateRateLimitUsage(msg) {
|
|
358
410
|
if (!rateLimitEventAppliesToPane(msg, store.snap())) return;
|
|
411
|
+
if (msg.vendor === "codex" && msg.source === "account_snapshot" && Array.isArray(msg.quotaWindows)) {
|
|
412
|
+
applyQuotaSnapshot(msg);
|
|
413
|
+
renderRateLimitUsage();
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (msg.vendor === "codex" && !msg.source) return;
|
|
359
417
|
var activeVendor = store.get('currentVendor') || "claude";
|
|
360
418
|
if (!vendorTracksRateLimits(activeVendor)) {
|
|
361
419
|
renderRateLimitUsage();
|
|
@@ -15,6 +15,11 @@ export var MATE_AVATAR_STYLES = [
|
|
|
15
15
|
];
|
|
16
16
|
|
|
17
17
|
export function avatarUrl(style, seed, size) {
|
|
18
|
+
// Legacy user styles remain part of the seed identity, never the artwork.
|
|
19
|
+
return imprintDataUrl({ style: style || 'imprint', seed: seed || 'anonymous', size: size || 64 });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function mateStyleAvatarUrl(style, seed, size) {
|
|
18
23
|
var normalizedStyle = style || 'imprint';
|
|
19
24
|
var normalizedSeed = seed || 'anonymous';
|
|
20
25
|
var normalizedSize = size || 64;
|
|
@@ -60,7 +65,7 @@ export function mateAvatarUrl(mate, size) {
|
|
|
60
65
|
var identity = p.displayName || mate.name || mate.displayName || 'Mate';
|
|
61
66
|
var style = p.avatarStyle || mate.avatarStyle || 'imprint';
|
|
62
67
|
if (style !== 'imprint' && style !== 'initial') {
|
|
63
|
-
return
|
|
68
|
+
return mateStyleAvatarUrl(style, p.avatarSeed || mate.avatarSeed || mate.id || identity, size);
|
|
64
69
|
}
|
|
65
70
|
return mateMarkUrl(identity, size);
|
|
66
71
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { showToast } from './utils.js';
|
|
2
|
+
import { preparePersonalConnectionDialog } from './personal-settings-dialog.js';
|
|
1
3
|
// Context Sources — attach terminal output, browser tabs, and email accounts as context for Claude
|
|
2
4
|
|
|
3
5
|
var ctx = null;
|
|
@@ -433,25 +435,32 @@ export function getEmailAccountListCache() {
|
|
|
433
435
|
return emailAccountList;
|
|
434
436
|
}
|
|
435
437
|
|
|
436
|
-
export function showEmailSetupModal() {
|
|
438
|
+
export function showEmailSetupModal(provider, host) {
|
|
439
|
+
var providerNames = { gmail: "Gmail", outlook: "Outlook Mail", yahoo: "Yahoo Mail", custom: "Custom email" };
|
|
440
|
+
if (!Object.hasOwn(providerNames, provider)) provider = null;
|
|
437
441
|
// Remove any existing modal
|
|
438
442
|
var existing = document.getElementById("email-setup-modal");
|
|
439
|
-
if (existing) existing.
|
|
443
|
+
if (existing) {existing.querySelector("input:not([type=hidden]),button").focus();return;}
|
|
440
444
|
|
|
441
445
|
var overlay = document.createElement("div");
|
|
442
446
|
overlay.id = "email-setup-modal";
|
|
443
|
-
overlay.className = "email-setup-overlay";
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
+
overlay.className = host ? "email-setup-inline" : "email-setup-overlay";
|
|
448
|
+
|
|
449
|
+
if (!provider) {
|
|
450
|
+
var picker = document.createElement('div'); picker.className = 'email-setup-dialog';
|
|
451
|
+
picker.innerHTML = '<h3>Choose an email provider</h3><div class="us-integration-tiles"></div><button id="email-setup-cancel" type="button" class="email-setup-btn">Cancel</button>';
|
|
452
|
+
Object.keys(providerNames).forEach(function (id) {
|
|
453
|
+
var button = document.createElement('button'); button.type = 'button'; button.className = 'email-setup-btn'; button.textContent = providerNames[id];
|
|
454
|
+
button.onclick = function () { closePicker(); showEmailSetupModal(id, host); };
|
|
455
|
+
picker.querySelector('.us-integration-tiles').appendChild(button);
|
|
456
|
+
});
|
|
457
|
+
overlay.appendChild(picker); (host || document.body).appendChild(overlay); var closePicker = preparePersonalConnectionDialog(overlay, !!host); return;
|
|
458
|
+
}
|
|
447
459
|
var modal = document.createElement("div");
|
|
448
460
|
modal.className = "email-setup-dialog";
|
|
449
461
|
modal.innerHTML =
|
|
450
|
-
'<h3 class="email-setup-title">Add
|
|
451
|
-
'<
|
|
452
|
-
'<label class="email-setup-label">Provider</label>' +
|
|
453
|
-
'<select id="email-setup-provider" class="email-setup-input">' + providerOptions + '</select>' +
|
|
454
|
-
'</div>' +
|
|
462
|
+
'<h3 class="email-setup-title">Add ' + providerNames[provider] + ' account</h3>' +
|
|
463
|
+
'<input type="hidden" id="email-setup-provider" value="' + provider + '">' +
|
|
455
464
|
'<div class="email-setup-field">' +
|
|
456
465
|
'<label class="email-setup-label">Email Address</label>' +
|
|
457
466
|
'<input id="email-setup-address" type="email" placeholder="you@example.com" class="email-setup-input" />' +
|
|
@@ -488,11 +497,12 @@ export function showEmailSetupModal() {
|
|
|
488
497
|
'</div>';
|
|
489
498
|
|
|
490
499
|
overlay.appendChild(modal);
|
|
491
|
-
document.body.appendChild(overlay);
|
|
500
|
+
(host || document.body).appendChild(overlay);
|
|
501
|
+
preparePersonalConnectionDialog(overlay, !!host);
|
|
492
502
|
|
|
493
503
|
// Event: close on overlay click
|
|
494
504
|
overlay.addEventListener("click", function (e) {
|
|
495
|
-
if (e.target === overlay) overlay.remove();
|
|
505
|
+
if (!host && e.target === overlay) overlay.remove();
|
|
496
506
|
});
|
|
497
507
|
|
|
498
508
|
// Event: cancel button
|
|
@@ -547,9 +557,7 @@ export function showEmailSetupModal() {
|
|
|
547
557
|
}
|
|
548
558
|
}
|
|
549
559
|
|
|
550
|
-
|
|
551
|
-
applyProviderMeta(providerSelect.value);
|
|
552
|
-
});
|
|
560
|
+
applyProviderMeta(provider);
|
|
553
561
|
|
|
554
562
|
// Reset test state
|
|
555
563
|
_emailTestPassed = false;
|
|
@@ -564,7 +572,7 @@ export function showEmailSetupModal() {
|
|
|
564
572
|
}
|
|
565
573
|
document.getElementById("email-setup-address").addEventListener("input", onInputChange);
|
|
566
574
|
document.getElementById("email-setup-password").addEventListener("input", onInputChange);
|
|
567
|
-
|
|
575
|
+
|
|
568
576
|
|
|
569
577
|
function runTest() {
|
|
570
578
|
var statusEl = document.getElementById("email-setup-status");
|
|
@@ -701,7 +709,8 @@ export function handleEmailAddResult(msg) {
|
|
|
701
709
|
|
|
702
710
|
// Handle email_account_remove_result from server
|
|
703
711
|
export function handleEmailRemoveResult(msg) {
|
|
704
|
-
|
|
712
|
+
showToast(msg.ok ? 'Personal mailbox disconnected.' : msg.error || 'Could not disconnect mailbox. Retry from Email settings.');
|
|
713
|
+
// The acknowledged list arrives separately through email_accounts_list.
|
|
705
714
|
}
|
|
706
715
|
|
|
707
716
|
function getSourceLabel(id) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { confirmSettingsAction } from './server-settings-state.js';
|
|
2
|
+
import { enhanceSettingsSelects } from './settings-select.js';
|
|
1
3
|
// User-island Default AI picker. Canonical state and the unsaved draft are separate.
|
|
2
4
|
|
|
3
5
|
import { store } from './store.js';
|
|
@@ -135,6 +137,7 @@ function renderInlineSummary() {
|
|
|
135
137
|
summary.appendChild(icon);
|
|
136
138
|
popover.appendChild(summary);
|
|
137
139
|
summary.addEventListener('click', function () { store.set({ defaultAiInlineEditing: true }); });
|
|
140
|
+
if(state.error)addStatus(state.error,true);
|
|
138
141
|
refreshIcons();
|
|
139
142
|
}
|
|
140
143
|
|
|
@@ -157,6 +160,16 @@ function render() {
|
|
|
157
160
|
} else {
|
|
158
161
|
popover.innerHTML = '<div class="default-ai-title">Default AI</div><div class="default-ai-copy">Used for new Clay interviews and built-in AI assistance.</div>';
|
|
159
162
|
}
|
|
163
|
+
if (inlineTarget) {
|
|
164
|
+
var cancel = popover.querySelector(".default-ai-cancel");
|
|
165
|
+
cancel.addEventListener("click", function () {
|
|
166
|
+
function discard() {
|
|
167
|
+
var canonical = inlineCurrentSelection(store.get("defaultAiState") || {}, store.get("defaultAiDraft") || {});
|
|
168
|
+
store.set({ defaultAiDraft: Object.assign({}, canonical), defaultAiDraftDirty: false, defaultAiInlineEditing: false });
|
|
169
|
+
}
|
|
170
|
+
if(store.get("defaultAiDraftDirty"))confirmSettingsAction("Discard unsaved AI defaults?", "Discard", discard);else discard();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
160
173
|
if (state.loading && !vendors.length) {
|
|
161
174
|
addStatus("Loading available AI providers…", false);
|
|
162
175
|
position();
|
|
@@ -228,14 +241,8 @@ function render() {
|
|
|
228
241
|
}
|
|
229
242
|
render();
|
|
230
243
|
});
|
|
231
|
-
if (inlineTarget) {
|
|
232
|
-
var cancel = popover.querySelector(".default-ai-cancel");
|
|
233
|
-
cancel.addEventListener("click", function () {
|
|
234
|
-
var canonical = inlineCurrentSelection(store.get("defaultAiState") || {}, store.get("defaultAiDraft") || {});
|
|
235
|
-
store.set({ defaultAiDraft: Object.assign({}, canonical), defaultAiDraftDirty: false, defaultAiInlineEditing: false });
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
244
|
popover.appendChild(save);
|
|
245
|
+
enhanceSettingsSelects(popover);
|
|
239
246
|
if (state.error) addStatus(state.error, true);
|
|
240
247
|
position();
|
|
241
248
|
refreshIcons();
|
|
@@ -7,23 +7,14 @@
|
|
|
7
7
|
// PUT /api/user/terminal-font.
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
saveTerminalFont,
|
|
11
|
+
TERMINAL_FONT_OPTIONS,
|
|
11
12
|
getTerminalFontFamily,
|
|
12
13
|
getTerminalFontSize,
|
|
13
14
|
onTerminalFontChange,
|
|
14
15
|
} from './terminal-prefs.js';
|
|
15
16
|
|
|
16
|
-
var FONT_OPTIONS =
|
|
17
|
-
{ label: "SF Mono", family: "'SF Mono', Menlo, Monaco, 'Courier New', monospace" },
|
|
18
|
-
{ label: "JetBrains Mono", family: "'JetBrains Mono', 'SF Mono', Menlo, monospace" },
|
|
19
|
-
{ label: "Fira Code", family: "'Fira Code', 'SF Mono', Menlo, monospace" },
|
|
20
|
-
{ label: "Cascadia Code", family: "'Cascadia Code', 'SF Mono', Menlo, monospace" },
|
|
21
|
-
{ label: "IBM Plex Mono", family: "'IBM Plex Mono', 'SF Mono', Menlo, monospace" },
|
|
22
|
-
{ label: "Source Code Pro", family: "'Source Code Pro', 'SF Mono', Menlo, monospace" },
|
|
23
|
-
{ label: "Roboto Mono", family: "'Roboto Mono', 'SF Mono', Menlo, monospace" },
|
|
24
|
-
{ label: "D2 Coding", family: "'D2 coding', 'D2Coding', 'SF Mono', Menlo, monospace" },
|
|
25
|
-
{ label: "System mono", family: "ui-monospace, monospace" },
|
|
26
|
-
];
|
|
17
|
+
var FONT_OPTIONS = TERMINAL_FONT_OPTIONS;
|
|
27
18
|
|
|
28
19
|
var MIN_SIZE = 9;
|
|
29
20
|
var MAX_SIZE = 32;
|
|
@@ -48,11 +39,12 @@ function escapeHtml(s) {
|
|
|
48
39
|
}
|
|
49
40
|
|
|
50
41
|
function persistTermFont(family, size) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
var status = popoverEl.querySelector('[role=status]');
|
|
43
|
+
status.textContent = 'Saving…';
|
|
44
|
+
popoverEl.querySelectorAll('button').forEach(function (button) {button.disabled = true;});
|
|
45
|
+
saveTerminalFont(family, size).then(function () {status.textContent = 'Saved.';})
|
|
46
|
+
.catch(function (error) {status.textContent = error.message;})
|
|
47
|
+
.finally(function () {popoverEl.querySelectorAll('button').forEach(function (button) {button.disabled = false;});syncSize();});
|
|
56
48
|
}
|
|
57
49
|
|
|
58
50
|
function syncSize() {
|
|
@@ -96,7 +88,6 @@ function buildPopover() {
|
|
|
96
88
|
(function (family) {
|
|
97
89
|
item.addEventListener('click', function (e) {
|
|
98
90
|
e.stopPropagation();
|
|
99
|
-
applyTerminalFont(family, undefined);
|
|
100
91
|
persistTermFont(family, undefined);
|
|
101
92
|
});
|
|
102
93
|
})(opt.family);
|
|
@@ -127,16 +118,15 @@ function buildPopover() {
|
|
|
127
118
|
sizeDecEl.addEventListener('click', function (e) {
|
|
128
119
|
e.stopPropagation();
|
|
129
120
|
var next = Math.max(MIN_SIZE, getTerminalFontSize() - 1);
|
|
130
|
-
applyTerminalFont(undefined, next);
|
|
131
121
|
persistTermFont(undefined, next);
|
|
132
122
|
});
|
|
133
123
|
sizeIncEl.addEventListener('click', function (e) {
|
|
134
124
|
e.stopPropagation();
|
|
135
125
|
var next = Math.min(MAX_SIZE, getTerminalFontSize() + 1);
|
|
136
|
-
applyTerminalFont(undefined, next);
|
|
137
126
|
persistTermFont(undefined, next);
|
|
138
127
|
});
|
|
139
128
|
|
|
129
|
+
var status = document.createElement('p');status.setAttribute('role','status');status.className='settings-status';popoverEl.appendChild(status);
|
|
140
130
|
document.body.appendChild(popoverEl);
|
|
141
131
|
return popoverEl;
|
|
142
132
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Mate avatar choices hosted inside the current settings dialog.
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { mateStyleAvatarUrl, mateAvatarUrl, MATE_AVATAR_STYLES } from './avatar.js';
|
|
4
4
|
import { showAvatarPositioner } from './profile.js';
|
|
5
5
|
import { getWs } from './ws-ref.js';
|
|
6
6
|
import { store } from './store.js';
|
|
@@ -168,7 +168,7 @@ export function renderHomeMateAvatarEditor(body, mate, rerender) {
|
|
|
168
168
|
choices.setAttribute('aria-label', 'Avatar for ' + name);
|
|
169
169
|
for (var i = 0; i < MATE_AVATAR_STYLES.length; i++) {
|
|
170
170
|
(function (entry) {
|
|
171
|
-
var choice = createChoice(entry.name,
|
|
171
|
+
var choice = createChoice(entry.name, mateStyleAvatarUrl(entry.id, seed, 48), !profile.avatarCustom && style === entry.id);
|
|
172
172
|
choice.addEventListener('click', function () { selectStyle(mate, entry.id, seed, rerender); });
|
|
173
173
|
choices.appendChild(choice);
|
|
174
174
|
})(MATE_AVATAR_STYLES[i]);
|
|
@@ -40,13 +40,14 @@ export function initLinearSettings() {
|
|
|
40
40
|
try {
|
|
41
41
|
var response = await fetch('/api/linear/connection', { method: disconnect ? 'DELETE' : 'PUT',
|
|
42
42
|
headers: { 'Content-Type': 'application/json' }, body: disconnect ? undefined : JSON.stringify({ key: input.value }) });
|
|
43
|
-
clearLinearKeyInput();
|
|
44
43
|
if (store.get('myUserId') !== actor) return;
|
|
45
44
|
var data = await response.json();
|
|
46
45
|
if (!response.ok) throw new Error(data.error || 'Could not update Linear connection.');
|
|
46
|
+
clearLinearKeyInput();
|
|
47
47
|
store.set({ linearConnection: data, githubWorkRefresh: null });
|
|
48
|
+
form.hidden = true;
|
|
48
49
|
setLinearStatus(data.connected ? 'Connected to ' + data.workspace.name : 'Disconnected', data.connected ? 'connected' : '');
|
|
49
|
-
} catch (error) {
|
|
50
|
+
} catch (error) { setLinearStatus(error.message, 'error'); }
|
|
50
51
|
finally {
|
|
51
52
|
store.set({ linearConnectionSaving: false });
|
|
52
53
|
buttons.forEach(function (button) { button.disabled = false; });
|
|
@@ -32,14 +32,12 @@ marked.use({
|
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
theme: "dark",
|
|
39
|
-
themeVariables: getMermaidThemeVars()
|
|
40
|
-
});
|
|
35
|
+
// Theme and Markdown import each other. Read theme state only after module
|
|
36
|
+
// initialization, when a theme is applied or the first diagram is rendered.
|
|
37
|
+
var mermaidInitialized = false;
|
|
41
38
|
|
|
42
39
|
export function updateMermaidTheme(vars) {
|
|
40
|
+
mermaidInitialized = true;
|
|
43
41
|
mermaid.initialize({
|
|
44
42
|
startOnLoad: false,
|
|
45
43
|
theme: "dark",
|
|
@@ -183,6 +181,7 @@ export function renderMermaidBlocks(el) {
|
|
|
183
181
|
container.className = "mermaid-diagram";
|
|
184
182
|
|
|
185
183
|
try {
|
|
184
|
+
if (!mermaidInitialized) updateMermaidTheme(getMermaidThemeVars());
|
|
186
185
|
mermaid.render(id, source.trim()).then(function (result) {
|
|
187
186
|
container.innerHTML = result.svg;
|
|
188
187
|
container.addEventListener("click", function () {
|