clay-server 2.47.0-beta.2 → 2.47.0-beta.4
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/claude-hook-installer.js +0 -1
- package/lib/codex-defaults.js +12 -2
- package/lib/project-connection.js +2 -1
- package/lib/project-notifications.js +3 -1
- package/lib/project-session-spawn.js +366 -0
- package/lib/project-sessions.js +17 -9
- package/lib/project.js +47 -29
- package/lib/public/app.js +2 -2
- package/lib/public/css/mates.css +0 -196
- package/lib/public/modules/app-messages.js +3 -23
- package/lib/public/modules/app-notifications.js +12 -4
- package/lib/public/modules/app-panels.js +6 -3
- package/lib/public/modules/app-rate-limit.js +41 -13
- package/lib/public/modules/app-rendering.js +2 -0
- package/lib/public/modules/input.js +4 -5
- package/lib/public/modules/mate-sidebar.js +0 -3
- package/lib/public/modules/tui-grab.js +12 -3
- package/lib/sdk-bridge.js +55 -36
- package/lib/sdk-message-processor.js +4 -6
- package/lib/session-spawn-mcp-server.js +56 -0
- package/lib/sessions.js +3 -0
- package/lib/ws-schema.js +0 -14
- package/lib/yoke/adapters/claude.js +25 -0
- package/lib/yoke/adapters/codex.js +34 -21
- package/lib/yoke/adapters/kiro.js +33 -19
- package/lib/yoke/index.js +18 -6
- package/lib/yoke/vendor-registry.js +55 -0
- package/package.json +3 -3
- package/lib/mate-datastore.js +0 -359
- package/lib/project-mate-datastore.js +0 -232
- package/lib/public/modules/mate-datastore-ui.js +0 -280
package/lib/project.js
CHANGED
|
@@ -28,9 +28,9 @@ var { attachSessions } = require("./project-sessions");
|
|
|
28
28
|
var { attachUserMessage } = require("./project-user-message");
|
|
29
29
|
var { attachConnection } = require("./project-connection");
|
|
30
30
|
var { attachMcp } = require("./project-mcp");
|
|
31
|
-
var { attachMateDatastore } = require("./project-mate-datastore");
|
|
32
31
|
var { createLocalMcp } = require("./mcp-local");
|
|
33
32
|
var { attachEmail: attachEmailModule } = require("./project-email");
|
|
33
|
+
var { attachSessionSpawn } = require("./project-session-spawn");
|
|
34
34
|
// project-notifications is attached globally in server.js, passed via opts.notificationsModule
|
|
35
35
|
|
|
36
36
|
// --- Context Sources persistence ---
|
|
@@ -476,23 +476,34 @@ function createProjectContext(opts) {
|
|
|
476
476
|
},
|
|
477
477
|
});
|
|
478
478
|
|
|
479
|
-
//
|
|
480
|
-
|
|
479
|
+
// The SDK bridge is created after local MCP servers. Session spawning uses
|
|
480
|
+
// a getter so tool handlers see the initialized bridge when they run.
|
|
481
|
+
var sdk = null;
|
|
482
|
+
var _sessionSpawn = attachSessionSpawn({
|
|
481
483
|
cwd: cwd,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
+
sm: sm,
|
|
485
|
+
getSdk: function () { return sdk; },
|
|
484
486
|
send: send,
|
|
485
|
-
|
|
486
|
-
clients: clients,
|
|
487
|
-
getSessionForWs: getSessionForWs,
|
|
487
|
+
isMate: isMate,
|
|
488
488
|
usersModule: usersModule,
|
|
489
|
-
|
|
489
|
+
adapters: adapters,
|
|
490
|
+
getLinuxUserForSession: getLinuxUserForSession,
|
|
490
491
|
});
|
|
491
492
|
|
|
492
493
|
// --- MCP tool servers (created via YOKE adapter) ---
|
|
493
494
|
var mcpServers = (function () {
|
|
494
495
|
var servers = {};
|
|
495
496
|
|
|
497
|
+
// Agent-driven sibling session fan-out (main projects only).
|
|
498
|
+
if (!isMate) {
|
|
499
|
+
try {
|
|
500
|
+
var sessionSpawnMcpConfig = _sessionSpawn.createMcpServer(adapter);
|
|
501
|
+
if (sessionSpawnMcpConfig) servers[sessionSpawnMcpConfig.name || "clay-sessions"] = sessionSpawnMcpConfig;
|
|
502
|
+
} catch (e) {
|
|
503
|
+
console.error("[project] Failed to create session spawn MCP server:", e.message);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
496
507
|
// Debate MCP server (available to both mates and main project)
|
|
497
508
|
try {
|
|
498
509
|
var debateMcp = require("./debate-mcp-server");
|
|
@@ -643,15 +654,6 @@ function createProjectContext(opts) {
|
|
|
643
654
|
console.error("[project] Failed to create email MCP server:", e.message);
|
|
644
655
|
}
|
|
645
656
|
|
|
646
|
-
if (isMate) {
|
|
647
|
-
try {
|
|
648
|
-
var datastoreMcp = _mateDatastore.createMcpServer();
|
|
649
|
-
if (datastoreMcp) servers[datastoreMcp.name || "clay-datastore"] = datastoreMcp;
|
|
650
|
-
} catch (e) {
|
|
651
|
-
console.error("[project] Failed to create datastore MCP server:", e.message);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
657
|
return Object.keys(servers).length > 0 ? servers : undefined;
|
|
656
658
|
})();
|
|
657
659
|
|
|
@@ -663,7 +665,12 @@ function createProjectContext(opts) {
|
|
|
663
665
|
//
|
|
664
666
|
// clay-browser -> only when the Chrome extension is connected
|
|
665
667
|
// clay-email -> only when the user has an account or server SMTP
|
|
666
|
-
|
|
668
|
+
//
|
|
669
|
+
// forSession (optional): the session whose query these servers are mounted
|
|
670
|
+
// into. clay-sessions must know its caller (depth guard + child ownership),
|
|
671
|
+
// so it is re-instantiated bound to that session; the static instance in
|
|
672
|
+
// mcpServers only serves descriptor listing and fails closed on calls.
|
|
673
|
+
function getLocalMcpServers(forSession) {
|
|
667
674
|
if (!mcpServers) return undefined;
|
|
668
675
|
var extWs = browserState._extensionWs;
|
|
669
676
|
var extConnected = !!(extWs && extWs.readyState === 1);
|
|
@@ -675,6 +682,15 @@ function createProjectContext(opts) {
|
|
|
675
682
|
var name = keys[i];
|
|
676
683
|
if (name === "clay-browser" && !extConnected) continue;
|
|
677
684
|
if (name === "clay-email" && !emailAvailable) continue;
|
|
685
|
+
if (name === "clay-sessions" && forSession) {
|
|
686
|
+
try {
|
|
687
|
+
var boundSpawn = _sessionSpawn.createMcpServer(adapter, forSession);
|
|
688
|
+
if (boundSpawn) { filtered[name] = boundSpawn; hasAny = true; }
|
|
689
|
+
} catch (e) {
|
|
690
|
+
console.error("[project] Failed to bind session spawn MCP server:", e.message);
|
|
691
|
+
}
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
678
694
|
filtered[name] = mcpServers[name];
|
|
679
695
|
hasAny = true;
|
|
680
696
|
}
|
|
@@ -682,7 +698,7 @@ function createProjectContext(opts) {
|
|
|
682
698
|
}
|
|
683
699
|
|
|
684
700
|
// --- SDK bridge ---
|
|
685
|
-
|
|
701
|
+
sdk = createSDKBridge({
|
|
686
702
|
cwd: cwd,
|
|
687
703
|
slug: slug,
|
|
688
704
|
sessionManager: sm,
|
|
@@ -914,18 +930,25 @@ function createProjectContext(opts) {
|
|
|
914
930
|
clayAuthToken: serverAuthToken,
|
|
915
931
|
slug: slug,
|
|
916
932
|
});
|
|
917
|
-
}
|
|
933
|
+
}
|
|
934
|
+
var needsReadyMetadata = !sm.capabilitiesByVendor || !sm.capabilitiesByVendor[msg.vendor]
|
|
935
|
+
|| !sm.modelsByVendor || !sm.modelsByVendor[msg.vendor];
|
|
936
|
+
if (vendorAdapter && needsReadyMetadata && typeof vendorAdapter.init === "function") {
|
|
918
937
|
// Init warms the adapter, but a slow/failed init must not block
|
|
919
938
|
// model listing (e.g. Codex models are a fixed list). Keep going
|
|
920
939
|
// to supportedModels() even if init throws.
|
|
921
940
|
try {
|
|
922
|
-
await vendorAdapter.init({
|
|
941
|
+
var readyResult = await vendorAdapter.init({
|
|
923
942
|
cwd: cwd,
|
|
924
943
|
clayPort: serverPort,
|
|
925
944
|
clayTls: serverTls,
|
|
926
945
|
clayAuthToken: serverAuthToken,
|
|
927
946
|
slug: slug,
|
|
928
947
|
});
|
|
948
|
+
sm.capabilitiesByVendor = sm.capabilitiesByVendor || {};
|
|
949
|
+
sm.capabilitiesByVendor[msg.vendor] = readyResult.capabilities || {};
|
|
950
|
+
sm.modelsByVendor = sm.modelsByVendor || {};
|
|
951
|
+
if (Array.isArray(readyResult.models)) sm.modelsByVendor[msg.vendor] = readyResult.models;
|
|
929
952
|
} catch (e) {
|
|
930
953
|
console.error("[project] " + msg.vendor + " init failed (continuing to model list):", e.message || e);
|
|
931
954
|
}
|
|
@@ -957,7 +980,8 @@ function createProjectContext(opts) {
|
|
|
957
980
|
}
|
|
958
981
|
}
|
|
959
982
|
}
|
|
960
|
-
|
|
983
|
+
var vendorCapabilities = (sm.capabilitiesByVendor && sm.capabilitiesByVendor[msg.vendor]) || {};
|
|
984
|
+
sendTo(ws, { type: "model_info", model: modelToSend, models: vendorModels, vendor: msg.vendor, capabilities: vendorCapabilities, availableVendors: sm.availableVendors || [], installedVendors: sm.installedVendors || [] });
|
|
961
985
|
})();
|
|
962
986
|
return;
|
|
963
987
|
}
|
|
@@ -1020,9 +1044,6 @@ function createProjectContext(opts) {
|
|
|
1020
1044
|
// --- MCP bridge (remote MCP servers via extension) ---
|
|
1021
1045
|
if (_mcp.handleMcpMessage(ws, msg)) return;
|
|
1022
1046
|
|
|
1023
|
-
// --- Mate datastore ---
|
|
1024
|
-
if (_mateDatastore.handleMateDatastoreMessage(ws, msg)) return;
|
|
1025
|
-
|
|
1026
1047
|
// --- Knowledge file management (delegated to project-knowledge.js) ---
|
|
1027
1048
|
if (_knowledge.handleKnowledgeMessage(ws, msg)) return;
|
|
1028
1049
|
|
|
@@ -1483,9 +1504,6 @@ function createProjectContext(opts) {
|
|
|
1483
1504
|
function destroy() {
|
|
1484
1505
|
_loop.stopTimer();
|
|
1485
1506
|
_email.destroy();
|
|
1486
|
-
if (_mateDatastore && typeof _mateDatastore.closeAllDatastores === "function") {
|
|
1487
|
-
try { _mateDatastore.closeAllDatastores(); } catch (e) {}
|
|
1488
|
-
}
|
|
1489
1507
|
stopFileWatch();
|
|
1490
1508
|
stopAllDirWatches();
|
|
1491
1509
|
// Abort all active sessions and clean up mention sessions
|
package/lib/public/app.js
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
openMobileSheet, setMobileSheetMateData, refreshMobileChatSheet
|
|
19
19
|
} from './modules/sidebar-mobile.js';
|
|
20
20
|
import { initMateSidebar, showMateSidebar, hideMateSidebar, renderMateSessionList, updateMateSidebarProfile, handleMateSearchResults } from './modules/mate-sidebar.js';
|
|
21
|
-
import { initMateDatastoreUI } from './modules/mate-datastore-ui.js';
|
|
22
21
|
import { initMateKnowledge, requestKnowledgeList, renderKnowledgeList, handleKnowledgeContent, hideKnowledge } from './modules/mate-knowledge.js';
|
|
23
22
|
import { initMateMemory, renderMemoryList, hideMemory } from './modules/mate-memory.js';
|
|
24
23
|
import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, addRewindButton, onRewindComplete, onRewindError } from './modules/rewind.js';
|
|
@@ -312,6 +311,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
312
311
|
currentModels: [],
|
|
313
312
|
// Project's last-used vendor; seeds the sidebar's "New session" button.
|
|
314
313
|
lastVendor: "",
|
|
314
|
+
// Static adapter metadata sent before any vendor is initialized.
|
|
315
|
+
vendorInfo: {},
|
|
315
316
|
// How Claude sessions open: "gui" (default) or "tui". The server sends
|
|
316
317
|
// claude_open_mode_changed on connect; this seeds it beforehand so the
|
|
317
318
|
// new-session menu doesn't flash the TUI-only entry.
|
|
@@ -414,7 +415,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
414
415
|
initSidebar(sidebarCtx);
|
|
415
416
|
var wsGetter = function () { return _getWsRef(); };
|
|
416
417
|
initMateSidebar(wsGetter);
|
|
417
|
-
initMateDatastoreUI(wsGetter);
|
|
418
418
|
initMateKnowledge(wsGetter);
|
|
419
419
|
initMateMemory(wsGetter, { onShow: function () { hideKnowledge(); hideNotes(); } });
|
|
420
420
|
initMateWizard(
|
package/lib/public/css/mates.css
CHANGED
|
@@ -2011,202 +2011,6 @@ body.mate-dm-active #layout.sidebar-collapsed .mate-collapsed-info {
|
|
|
2011
2011
|
color: var(--accent);
|
|
2012
2012
|
}
|
|
2013
2013
|
|
|
2014
|
-
/* Mate datastore inspector */
|
|
2015
|
-
#mate-datastore-panel {
|
|
2016
|
-
position: absolute;
|
|
2017
|
-
inset: 0;
|
|
2018
|
-
z-index: 40;
|
|
2019
|
-
background: var(--bg);
|
|
2020
|
-
display: flex;
|
|
2021
|
-
flex-direction: column;
|
|
2022
|
-
overflow: hidden;
|
|
2023
|
-
}
|
|
2024
|
-
|
|
2025
|
-
#mate-datastore-panel.hidden {
|
|
2026
|
-
display: none !important;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
#main-column.mate-datastore-open > .title-bar-content,
|
|
2030
|
-
#main-column.mate-datastore-open > .dm-header-bar,
|
|
2031
|
-
#main-column.mate-datastore-open > #main-panels {
|
|
2032
|
-
display: none !important;
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
.mate-datastore-top-bar {
|
|
2036
|
-
display: flex;
|
|
2037
|
-
align-items: center;
|
|
2038
|
-
justify-content: space-between;
|
|
2039
|
-
height: 48px;
|
|
2040
|
-
padding: 0 16px;
|
|
2041
|
-
border-bottom: 1px solid var(--border-subtle);
|
|
2042
|
-
flex-shrink: 0;
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
.mate-datastore-top-title {
|
|
2046
|
-
display: flex;
|
|
2047
|
-
align-items: center;
|
|
2048
|
-
gap: 6px;
|
|
2049
|
-
font-weight: 700;
|
|
2050
|
-
font-size: 15px;
|
|
2051
|
-
color: var(--text);
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
.mate-datastore-top-title .lucide {
|
|
2055
|
-
width: 14px;
|
|
2056
|
-
height: 14px;
|
|
2057
|
-
color: var(--accent);
|
|
2058
|
-
opacity: 0.85;
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
.mate-datastore-top-actions {
|
|
2062
|
-
display: flex;
|
|
2063
|
-
align-items: center;
|
|
2064
|
-
gap: 8px;
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
.mate-db-status {
|
|
2068
|
-
padding: 10px 14px 0;
|
|
2069
|
-
font-size: 12px;
|
|
2070
|
-
color: var(--text-secondary, #8e8e8e);
|
|
2071
|
-
}
|
|
2072
|
-
|
|
2073
|
-
.mate-db-status[data-kind="error"] {
|
|
2074
|
-
color: var(--error, #ff6b6b);
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
|
-
.mate-db-status[data-kind="warn"] {
|
|
2078
|
-
color: var(--warning, #f5a524);
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
.mate-db-status[data-kind="ok"] {
|
|
2082
|
-
color: var(--success, #36b37e);
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
|
-
.mate-db-layout {
|
|
2086
|
-
display: grid;
|
|
2087
|
-
grid-template-columns: 220px minmax(0, 1fr);
|
|
2088
|
-
gap: 10px;
|
|
2089
|
-
padding: 12px 10px 10px;
|
|
2090
|
-
min-height: 0;
|
|
2091
|
-
flex: 1;
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
.mate-db-table-column,
|
|
2095
|
-
.mate-db-detail {
|
|
2096
|
-
min-height: 0;
|
|
2097
|
-
display: flex;
|
|
2098
|
-
flex-direction: column;
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
|
-
.mate-db-table-list {
|
|
2102
|
-
overflow-y: auto;
|
|
2103
|
-
border: 1px solid var(--border-subtle, rgba(255,255,255,0.06));
|
|
2104
|
-
border-radius: 12px;
|
|
2105
|
-
background: var(--sidebar-bg, rgba(255,255,255,0.03));
|
|
2106
|
-
padding: 6px;
|
|
2107
|
-
flex: 1;
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2110
|
-
.mate-db-table-item {
|
|
2111
|
-
width: 100%;
|
|
2112
|
-
display: flex;
|
|
2113
|
-
justify-content: space-between;
|
|
2114
|
-
gap: 6px;
|
|
2115
|
-
padding: 8px 10px;
|
|
2116
|
-
border: none;
|
|
2117
|
-
background: transparent;
|
|
2118
|
-
color: var(--text-secondary, #aaa);
|
|
2119
|
-
border-radius: 8px;
|
|
2120
|
-
text-align: left;
|
|
2121
|
-
cursor: pointer;
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
.mate-db-table-item:hover,
|
|
2125
|
-
.mate-db-table-item.active {
|
|
2126
|
-
background: var(--sidebar-active, rgba(255,255,255,0.08));
|
|
2127
|
-
color: var(--text, #fff);
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
.mate-db-table-item-name {
|
|
2131
|
-
overflow: hidden;
|
|
2132
|
-
text-overflow: ellipsis;
|
|
2133
|
-
white-space: nowrap;
|
|
2134
|
-
min-width: 0;
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2137
|
-
.mate-db-table-item-type {
|
|
2138
|
-
font-size: 10px;
|
|
2139
|
-
text-transform: uppercase;
|
|
2140
|
-
letter-spacing: 0.05em;
|
|
2141
|
-
opacity: 0.7;
|
|
2142
|
-
flex-shrink: 0;
|
|
2143
|
-
}
|
|
2144
|
-
|
|
2145
|
-
.mate-db-empty {
|
|
2146
|
-
padding: 16px 10px;
|
|
2147
|
-
color: var(--text-secondary, #8e8e8e);
|
|
2148
|
-
font-size: 12px;
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
|
-
.mate-db-section-title {
|
|
2152
|
-
font-size: 11px;
|
|
2153
|
-
font-weight: 700;
|
|
2154
|
-
text-transform: uppercase;
|
|
2155
|
-
letter-spacing: 0.08em;
|
|
2156
|
-
color: var(--text-muted, #9aa0a6);
|
|
2157
|
-
margin: 0 0 6px;
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2160
|
-
.mate-db-detail {
|
|
2161
|
-
gap: 8px;
|
|
2162
|
-
min-width: 0;
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
.mate-db-table-schema,
|
|
2166
|
-
.mate-db-result {
|
|
2167
|
-
margin: 0;
|
|
2168
|
-
padding: 10px;
|
|
2169
|
-
border-radius: 10px;
|
|
2170
|
-
border: 1px solid var(--border-subtle, rgba(255,255,255,0.08));
|
|
2171
|
-
background: var(--bg-alt, rgba(255,255,255,0.03));
|
|
2172
|
-
color: var(--text-secondary, #b8b8b8);
|
|
2173
|
-
font-size: 11px;
|
|
2174
|
-
line-height: 1.5;
|
|
2175
|
-
overflow: auto;
|
|
2176
|
-
white-space: pre-wrap;
|
|
2177
|
-
word-break: break-word;
|
|
2178
|
-
min-height: 0;
|
|
2179
|
-
}
|
|
2180
|
-
|
|
2181
|
-
.mate-db-table-schema {
|
|
2182
|
-
max-height: 180px;
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
@media (max-width: 900px) {
|
|
2186
|
-
.mate-db-layout {
|
|
2187
|
-
grid-template-columns: 1fr;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
body.mate-dm-active .mate-datastore-top-bar {
|
|
2192
|
-
background: var(--mate-color);
|
|
2193
|
-
color: #fff;
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
|
-
body.mate-dm-active .mate-datastore-top-title,
|
|
2197
|
-
body.mate-dm-active .mate-datastore-top-title .lucide {
|
|
2198
|
-
color: #fff;
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
body.mate-dm-active .mate-datastore-top-bar .scheduler-close-btn {
|
|
2202
|
-
color: rgba(255, 255, 255, 0.85);
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
body.mate-dm-active .mate-datastore-top-bar .scheduler-close-btn:hover {
|
|
2206
|
-
color: #fff;
|
|
2207
|
-
background: rgba(255, 255, 255, 0.15);
|
|
2208
|
-
}
|
|
2209
|
-
|
|
2210
2014
|
.mate-session-item.search-match {
|
|
2211
2015
|
background: var(--accent-12, rgba(108, 92, 231, 0.12));
|
|
2212
2016
|
}
|
|
@@ -14,7 +14,6 @@ import { renderSessionList, updateSessionPresence, handleSearchResults, updateSe
|
|
|
14
14
|
import { updateDmBadge, renderSidebarPresence, setMentionActive, renderUserStrip } from './sidebar-mates.js';
|
|
15
15
|
import { refreshMobileChatSheet } from './sidebar-mobile.js';
|
|
16
16
|
import { renderMateSessionList, handleMateSearchResults, updateMateSidebarProfile } from './mate-sidebar.js';
|
|
17
|
-
import { handleMateDatastoreTablesResult, handleMateDatastoreDescribeResult, handleMateDatastoreQueryResult, handleMateDatastoreError, handleMateDatastoreChange } from './mate-datastore-ui.js';
|
|
18
17
|
import { handleHomeClayHistory, handleHomeClayDelta, handleHomeClayDone, handleHomeClayError } from './home-chat.js';
|
|
19
18
|
import { renderKnowledgeList, handleKnowledgeContent } from './mate-knowledge.js';
|
|
20
19
|
import { renderMemoryList } from './mate-memory.js';
|
|
@@ -289,7 +288,7 @@ export function processMessage(msg) {
|
|
|
289
288
|
// host lives on document.body (it's position: fixed), so it
|
|
290
289
|
// survives project navigation unless we detach explicitly here.
|
|
291
290
|
detachTuiView();
|
|
292
|
-
store.set({ projectName: msg.project || msg.cwd });
|
|
291
|
+
store.set({ projectName: msg.project || msg.cwd, vendorInfo: msg.vendors || {} });
|
|
293
292
|
if (msg.cwd) store.set({ cwd: msg.cwd });
|
|
294
293
|
if (msg.slug) store.set({ currentSlug: msg.slug });
|
|
295
294
|
try { var _is = store.snap(); localStorage.setItem("clay-project-name-" + (_is.currentSlug || "default"), _is.projectName); } catch (e) {}
|
|
@@ -327,26 +326,6 @@ export function processMessage(msg) {
|
|
|
327
326
|
updateProjectList(msg);
|
|
328
327
|
break;
|
|
329
328
|
|
|
330
|
-
case "mate_db_tables_result":
|
|
331
|
-
handleMateDatastoreTablesResult(msg);
|
|
332
|
-
break;
|
|
333
|
-
|
|
334
|
-
case "mate_db_describe_result":
|
|
335
|
-
handleMateDatastoreDescribeResult(msg);
|
|
336
|
-
break;
|
|
337
|
-
|
|
338
|
-
case "mate_db_query_result":
|
|
339
|
-
handleMateDatastoreQueryResult(msg);
|
|
340
|
-
break;
|
|
341
|
-
|
|
342
|
-
case "mate_db_error":
|
|
343
|
-
handleMateDatastoreError(msg);
|
|
344
|
-
break;
|
|
345
|
-
|
|
346
|
-
case "mate_db_change":
|
|
347
|
-
handleMateDatastoreChange(msg);
|
|
348
|
-
break;
|
|
349
|
-
|
|
350
329
|
case "update_available":
|
|
351
330
|
// In multi-user mode, only show update UI to admins
|
|
352
331
|
if (store.get('isMultiUserMode')) {
|
|
@@ -464,6 +443,7 @@ export function processMessage(msg) {
|
|
|
464
443
|
if (msg.vendor && !store.get('vendorSelectionLocked')) _miUpdate.currentVendor = msg.vendor;
|
|
465
444
|
if (msg.availableVendors) _miUpdate.availableVendors = msg.availableVendors;
|
|
466
445
|
if (msg.installedVendors) _miUpdate.installedVendors = msg.installedVendors;
|
|
446
|
+
if (msg.capabilities) _miUpdate.vendorCapabilities = msg.capabilities;
|
|
467
447
|
store.set(_miUpdate);
|
|
468
448
|
updateSettingsModels(_modelVal, msg.models || []);
|
|
469
449
|
break;
|
|
@@ -1359,7 +1339,7 @@ export function processMessage(msg) {
|
|
|
1359
1339
|
var _lm = store.get('pendingLoginModal');
|
|
1360
1340
|
store.set({ pendingLoginModal: null });
|
|
1361
1341
|
openTuiModal(msg.id, _lm.slug, {
|
|
1362
|
-
sessionTitle: (_lm.vendor
|
|
1342
|
+
sessionTitle: (VENDOR_NAMES[_lm.vendor] || "Claude Code") + " login",
|
|
1363
1343
|
projectName: _lm.slug,
|
|
1364
1344
|
compact: true,
|
|
1365
1345
|
});
|
|
@@ -19,6 +19,14 @@ var bannerContainer = null;
|
|
|
19
19
|
var bellBtn = null;
|
|
20
20
|
var badgeEl = null;
|
|
21
21
|
|
|
22
|
+
function getVendorLoginCommand(vendor) {
|
|
23
|
+
var vendors = store.get('vendorInfo') || {};
|
|
24
|
+
var info = vendors[vendor];
|
|
25
|
+
if (info && info.loginCommand) return info.loginCommand;
|
|
26
|
+
var fallbacks = { codex: "codex login --device-auth", claude: "claude login" };
|
|
27
|
+
return fallbacks[vendor] || fallbacks.claude;
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
// --- Pending TUI attention tracking ---
|
|
23
31
|
// Mirrors the icon-shake / favicon-blink behavior the SDK side already gets
|
|
24
32
|
// from `pendingPermissions` on project status broadcasts. The notification
|
|
@@ -252,7 +260,7 @@ function showBanner(notif, autoDismissMs) {
|
|
|
252
260
|
removeBanner(banner);
|
|
253
261
|
dismissNotif(notif.id);
|
|
254
262
|
var authMeta = notif.meta || {};
|
|
255
|
-
startLoginInModal(authMeta.loginCommand || (
|
|
263
|
+
startLoginInModal(authMeta.loginCommand || getVendorLoginCommand(authMeta.vendor || "claude"), authMeta.vendor || "claude");
|
|
256
264
|
showLoginReminderBanner();
|
|
257
265
|
});
|
|
258
266
|
}
|
|
@@ -332,7 +340,7 @@ function startLoginInModal(loginCommand, vendor) {
|
|
|
332
340
|
if (authReminderVisible) return;
|
|
333
341
|
var ws = getWs();
|
|
334
342
|
if (!ws || ws.readyState !== 1) return;
|
|
335
|
-
var cmd = loginCommand || (vendor
|
|
343
|
+
var cmd = loginCommand || getVendorLoginCommand(vendor);
|
|
336
344
|
var slug = currentProjectSlug();
|
|
337
345
|
if (!slug) { startLoginCommand(cmd); return; }
|
|
338
346
|
store.set({ pendingLoginModal: { slug: slug, vendor: vendor || "claude" } });
|
|
@@ -366,7 +374,7 @@ export function autoStartLoginIfNeeded(msg) {
|
|
|
366
374
|
if (authReminderVisible) return false;
|
|
367
375
|
var vendor = msg.vendor || "claude";
|
|
368
376
|
var cmd = msg.loginCommand
|
|
369
|
-
|| (vendor
|
|
377
|
+
|| getVendorLoginCommand(vendor);
|
|
370
378
|
startLoginInModal(cmd, vendor);
|
|
371
379
|
showLoginReminderBanner();
|
|
372
380
|
return true;
|
|
@@ -426,7 +434,7 @@ function showLoginReminderBanner() {
|
|
|
426
434
|
export function showAuthRequiredBanner(msg) {
|
|
427
435
|
if (!bannerContainer) return;
|
|
428
436
|
var vendor = (msg && (msg.vendor || (msg.meta && msg.meta.vendor))) || "claude";
|
|
429
|
-
var loginCommand = (msg && (msg.loginCommand || (msg.meta && msg.meta.loginCommand))) || (vendor
|
|
437
|
+
var loginCommand = (msg && (msg.loginCommand || (msg.meta && msg.meta.loginCommand))) || getVendorLoginCommand(vendor);
|
|
430
438
|
activeAuthRequiredMsg = Object.assign({}, msg || {}, {
|
|
431
439
|
id: (msg && msg.id) || ("_auth_" + Date.now()),
|
|
432
440
|
type: "auth_required",
|
|
@@ -93,7 +93,7 @@ var EFFORT_LEVELS_BY_VENDOR = {
|
|
|
93
93
|
var THINKING_OPTIONS = ["disabled", "adaptive", "budget"];
|
|
94
94
|
var CODEX_APPROVAL_OPTIONS = [
|
|
95
95
|
{ value: "never", label: "Auto" },
|
|
96
|
-
{ value: "
|
|
96
|
+
{ value: "untrusted", label: "Untrusted" },
|
|
97
97
|
{ value: "on-request", label: "Ask" },
|
|
98
98
|
];
|
|
99
99
|
var CODEX_SANDBOX_OPTIONS = [
|
|
@@ -641,11 +641,14 @@ export function updateConfigChip() {
|
|
|
641
641
|
rebuildModeList();
|
|
642
642
|
rebuildEffortBar();
|
|
643
643
|
|
|
644
|
-
//
|
|
644
|
+
// MODE remains Claude-specific until adapter modes become capabilities.
|
|
645
645
|
var isClaude = vendor === "claude";
|
|
646
|
-
// MODE, THINKING, BETA are Claude-only
|
|
647
646
|
if (configModeList && configModeList.parentElement) configModeList.parentElement.style.display = isClaude ? "" : "none";
|
|
648
647
|
rebuildThinkingSection();
|
|
648
|
+
// capabilities.thinking means "emits a thinking stream" (true for every
|
|
649
|
+
// vendor), NOT "accepts thinking config". The adaptive/extended toggle and
|
|
650
|
+
// budget only feed Claude queries (sm.currentThinking), so the section
|
|
651
|
+
// stays Claude-only until a dedicated thinkingConfig capability exists.
|
|
649
652
|
if (configThinkingSection) configThinkingSection.style.display = isClaude ? "" : "none";
|
|
650
653
|
// BETA section deprecated (1M context is now standard)
|
|
651
654
|
if (configBetaSection) configBetaSection.style.display = "none";
|
|
@@ -23,20 +23,37 @@ var fastModeIndicatorEl = null;
|
|
|
23
23
|
// --- Internal helpers ---
|
|
24
24
|
|
|
25
25
|
function getVendorUsageMeta(vendor) {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
var vendors = store.get('vendorInfo') || {};
|
|
27
|
+
var info = vendors[vendor];
|
|
28
|
+
if (info && info.usageDashboard) return info.usageDashboard;
|
|
29
|
+
var fallbacks = {
|
|
30
|
+
codex: {
|
|
28
31
|
icon: "/codex-avatar.png",
|
|
29
32
|
alt: "Codex",
|
|
30
33
|
href: "https://chatgpt.com/admin/usage",
|
|
31
34
|
title: "Check usage on ChatGPT",
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
},
|
|
36
|
+
claude: {
|
|
37
|
+
icon: "/claude-code-avatar.png",
|
|
38
|
+
alt: "Claude Code",
|
|
39
|
+
href: "https://claude.ai/settings/usage",
|
|
40
|
+
title: "Check usage on claude.ai",
|
|
41
|
+
},
|
|
39
42
|
};
|
|
43
|
+
return fallbacks[vendor] || fallbacks.claude;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function vendorTracksRateLimits(vendor) {
|
|
47
|
+
var vendors = store.get('vendorInfo') || {};
|
|
48
|
+
var info = vendors[vendor];
|
|
49
|
+
if (info) return info.rateLimitTracking !== false;
|
|
50
|
+
var legacyTrackedVendors = ["claude", "codex"];
|
|
51
|
+
return legacyTrackedVendors.indexOf(vendor) !== -1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function vendorSupportsScheduledMessages(vendor) {
|
|
55
|
+
var scheduledMessageVendors = ["claude"];
|
|
56
|
+
return scheduledMessageVendors.indexOf(vendor) !== -1;
|
|
40
57
|
}
|
|
41
58
|
|
|
42
59
|
function rateLimitTypeLabel(type) {
|
|
@@ -178,8 +195,13 @@ function tickRateLimitUsage() {
|
|
|
178
195
|
|
|
179
196
|
export function initRateLimit() {
|
|
180
197
|
store.subscribe(function(state, prev) {
|
|
181
|
-
if (state.currentVendor !== prev.currentVendor && state.currentVendor
|
|
182
|
-
clearScheduleDelay();
|
|
198
|
+
if (state.currentVendor !== prev.currentVendor && state.currentVendor) {
|
|
199
|
+
if (!vendorSupportsScheduledMessages(state.currentVendor)) clearScheduleDelay();
|
|
200
|
+
}
|
|
201
|
+
if (state.currentVendor !== prev.currentVendor || state.vendorInfo !== prev.vendorInfo) {
|
|
202
|
+
if (rateLimitUsageEl) {
|
|
203
|
+
rateLimitUsageEl.style.display = vendorTracksRateLimits(state.currentVendor || "claude") ? "" : "none";
|
|
204
|
+
}
|
|
183
205
|
}
|
|
184
206
|
});
|
|
185
207
|
}
|
|
@@ -203,7 +225,7 @@ export function handleRateLimitEvent(msg) {
|
|
|
203
225
|
if (rateLimitResetTimer) clearTimeout(rateLimitResetTimer);
|
|
204
226
|
// Auto-switch input to schedule mode: any message typed will be queued for after reset
|
|
205
227
|
var delayUntilReset = msg.resetsAt - Date.now();
|
|
206
|
-
if (delayUntilReset > 0 && (store.get('currentVendor') || "claude")
|
|
228
|
+
if (delayUntilReset > 0 && vendorSupportsScheduledMessages(store.get('currentVendor') || "claude")) {
|
|
207
229
|
setScheduleDelayMs(delayUntilReset + 60000); // +1min buffer after reset
|
|
208
230
|
}
|
|
209
231
|
rateLimitResetTimer = setTimeout(function () {
|
|
@@ -222,6 +244,11 @@ export function handleRateLimitEvent(msg) {
|
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
export function updateRateLimitUsage(msg) {
|
|
247
|
+
var activeVendor = store.get('currentVendor') || "claude";
|
|
248
|
+
if (!vendorTracksRateLimits(activeVendor)) {
|
|
249
|
+
if (rateLimitUsageEl) rateLimitUsageEl.style.display = "none";
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
225
252
|
if (msg.rateLimitType && msg.resetsAt) {
|
|
226
253
|
rateLimitResetState[msg.rateLimitType] = { resetsAt: msg.resetsAt, status: msg.status };
|
|
227
254
|
}
|
|
@@ -238,6 +265,7 @@ export function updateRateLimitUsage(msg) {
|
|
|
238
265
|
var ref = document.getElementById("skip-perms-pill");
|
|
239
266
|
topBarActions.insertBefore(rateLimitUsageEl, ref);
|
|
240
267
|
}
|
|
268
|
+
rateLimitUsageEl.style.display = "";
|
|
241
269
|
|
|
242
270
|
// Build label from available reset times
|
|
243
271
|
var parts = [];
|
|
@@ -251,7 +279,7 @@ export function updateRateLimitUsage(msg) {
|
|
|
251
279
|
}
|
|
252
280
|
|
|
253
281
|
var label = parts.length > 0 ? parts.join(" · ") : "Check usage";
|
|
254
|
-
var vendor =
|
|
282
|
+
var vendor = activeVendor;
|
|
255
283
|
var meta = getVendorUsageMeta(vendor);
|
|
256
284
|
rateLimitUsageEl.href = meta.href;
|
|
257
285
|
rateLimitUsageEl.title = meta.title;
|
|
@@ -14,6 +14,8 @@ import { sendMessage, hasSendableContent } from './input.js';
|
|
|
14
14
|
import { getChatLayout } from './theme.js';
|
|
15
15
|
import { getScheduledMsgEl } from './app-rate-limit.js';
|
|
16
16
|
|
|
17
|
+
// Keep these client constants aligned with lib/yoke/vendor-registry.js. The
|
|
18
|
+
// browser cannot import the server's CommonJS registry directly.
|
|
17
19
|
export var VENDOR_AVATARS = {
|
|
18
20
|
claude: "/claude-code-avatar.png",
|
|
19
21
|
codex: "/codex-avatar.png",
|
|
@@ -5,6 +5,7 @@ import { checkForMention, showMentionMenu, hideMentionMenu, isMentionMenuVisible
|
|
|
5
5
|
import { store } from './store.js';
|
|
6
6
|
import { mateAvatarUrl } from './avatar.js';
|
|
7
7
|
import { tuiIsActive, tuiSubmitText } from './session-tui-view.js';
|
|
8
|
+
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
8
9
|
|
|
9
10
|
var ctx;
|
|
10
11
|
|
|
@@ -300,11 +301,9 @@ export function sendMessage() {
|
|
|
300
301
|
_vtw2.classList.remove("locked");
|
|
301
302
|
}
|
|
302
303
|
if (_avi && _avIcon) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
_avIcon.alt = _vendorNames[_committedVendor] || _vendorNames.claude;
|
|
307
|
-
_avi.title = (_vendorNames[_committedVendor] || _vendorNames.claude) + " session";
|
|
304
|
+
_avIcon.src = VENDOR_AVATARS[_committedVendor] || VENDOR_AVATARS.claude;
|
|
305
|
+
_avIcon.alt = VENDOR_NAMES[_committedVendor] || VENDOR_NAMES.claude;
|
|
306
|
+
_avi.title = (VENDOR_NAMES[_committedVendor] || VENDOR_NAMES.claude) + " session";
|
|
308
307
|
_avi.classList.remove("hidden");
|
|
309
308
|
}
|
|
310
309
|
} else if (_vtw2) {
|