clay-server 5.2.0-beta.2 → 5.2.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/builtin-mates.js +2 -2
- package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
- package/lib/dm-digest-cursor.js +120 -0
- package/lib/knowledge-db-import-validation.js +46 -0
- package/lib/knowledge-db-import.js +98 -0
- package/lib/knowledge-db-service.js +18 -30
- package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
- package/lib/knowledge-db-storage-nedb.js +66 -0
- package/lib/knowledge-db-storage.js +72 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-file-store.js +7 -1
- package/lib/mate-avatar-catalog.js +12 -0
- package/lib/mate-avatar-migration.js +41 -0
- package/lib/mate-knowledge-mate-bound.js +53 -0
- package/lib/mate-knowledge-mcp-server.js +55 -8
- package/lib/mate-knowledge-service.js +9 -30
- package/lib/mate-knowledge-text-tools.js +106 -0
- package/lib/mates.js +14 -3
- package/lib/mcp-agent-tools.js +117 -0
- package/lib/mcp-connection-store.js +119 -15
- package/lib/mcp-import-credentials.js +31 -0
- package/lib/mcp-local-transport.js +13 -0
- package/lib/mcp-oauth.js +8 -6
- package/lib/mcp-query-bridge.js +30 -0
- package/lib/mcp-remote-connections.js +74 -20
- package/lib/mcp-source-adapters.js +91 -0
- package/lib/mcp-source-context.js +42 -0
- package/lib/mcp-source-discovery.js +169 -0
- package/lib/mcp-source-plugins.js +68 -0
- package/lib/mcp-source-restrictions.js +47 -0
- package/lib/mcp-tool-policy.js +34 -0
- package/lib/project-ask-user.js +6 -4
- package/lib/project-debate.js +1 -0
- package/lib/project-mate-interaction.js +40 -62
- package/lib/project-mcp.js +54 -16
- package/lib/project-session-document.js +8 -3
- package/lib/project-session-github.js +16 -7
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-sessions.js +6 -2
- package/lib/project-shared-browser.js +56 -12
- package/lib/project.js +49 -34
- package/lib/public/app.js +5 -0
- package/lib/public/appearance-bootstrap.js +14 -0
- package/lib/public/css/clay-workspace.css +29 -0
- package/lib/public/css/home-debate-planning.css +2 -0
- package/lib/public/css/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- package/lib/public/css/session-github.css +43 -1
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/index.html +10 -4
- package/lib/public/mate-avatars/B01.png +0 -0
- package/lib/public/mate-avatars/B02.png +0 -0
- package/lib/public/mate-avatars/B03.png +0 -0
- package/lib/public/mate-avatars/B04.png +0 -0
- package/lib/public/mate-avatars/B05.png +0 -0
- package/lib/public/mate-avatars/B06.png +0 -0
- package/lib/public/mate-avatars/B07.png +0 -0
- package/lib/public/mate-avatars/B08.png +0 -0
- package/lib/public/mate-avatars/B09.png +0 -0
- package/lib/public/mate-avatars/B10.png +0 -0
- package/lib/public/mate-avatars/B11.png +0 -0
- package/lib/public/mate-avatars/B12.png +0 -0
- package/lib/public/mate-avatars/B13.png +0 -0
- package/lib/public/mate-avatars/B14.png +0 -0
- package/lib/public/mate-avatars/B15.png +0 -0
- package/lib/public/mate-avatars/B16.png +0 -0
- package/lib/public/mate-avatars/B17.png +0 -0
- package/lib/public/mate-avatars/B18.png +0 -0
- package/lib/public/mate-avatars/B19.png +0 -0
- package/lib/public/mate-avatars/B20.png +0 -0
- package/lib/public/mate-avatars/B21.png +0 -0
- package/lib/public/mate-avatars/B22.png +0 -0
- package/lib/public/mate-avatars/B23.png +0 -0
- package/lib/public/mate-avatars/B24.png +0 -0
- package/lib/public/mate-avatars/B25.png +0 -0
- package/lib/public/mate-avatars/B26.png +0 -0
- package/lib/public/mate-avatars/B27.png +0 -0
- package/lib/public/mate-avatars/B28.png +0 -0
- package/lib/public/mate-avatars/B29.png +0 -0
- package/lib/public/mate-avatars/B30.png +0 -0
- package/lib/public/mate-avatars/B31.png +0 -0
- package/lib/public/mate-avatars/B32.png +0 -0
- package/lib/public/mate-avatars/B33.png +0 -0
- package/lib/public/mate-avatars/B34.png +0 -0
- package/lib/public/mate-avatars/B35.png +0 -0
- package/lib/public/mate-avatars/B36.png +0 -0
- package/lib/public/mate-avatars/B37.png +0 -0
- package/lib/public/mate-avatars/B38.png +0 -0
- package/lib/public/mate-avatars/B39.png +0 -0
- package/lib/public/mate-avatars/B40.png +0 -0
- package/lib/public/mate-avatars/B41.png +0 -0
- package/lib/public/mate-avatars/B42.png +0 -0
- package/lib/public/mate-avatars/B43.png +0 -0
- package/lib/public/mate-avatars/B44.png +0 -0
- package/lib/public/mate-avatars/B45.png +0 -0
- package/lib/public/mate-avatars/B46.png +0 -0
- package/lib/public/mate-avatars/B47.png +0 -0
- package/lib/public/mate-avatars/B48.png +0 -0
- package/lib/public/mate-avatars/C01.png +0 -0
- package/lib/public/mate-avatars/C02.png +0 -0
- package/lib/public/mate-avatars/C03.png +0 -0
- package/lib/public/mate-avatars/C04.png +0 -0
- package/lib/public/mate-avatars/C05.png +0 -0
- package/lib/public/mate-avatars/C06.png +0 -0
- package/lib/public/mate-avatars/C07.png +0 -0
- package/lib/public/mate-avatars/C08.png +0 -0
- package/lib/public/mate-avatars/C09.png +0 -0
- package/lib/public/mate-avatars/C10.png +0 -0
- package/lib/public/mate-avatars/C11.png +0 -0
- package/lib/public/mate-avatars/C12.png +0 -0
- package/lib/public/mate-avatars/C13.png +0 -0
- package/lib/public/mate-avatars/C14.png +0 -0
- package/lib/public/mate-avatars/C15.png +0 -0
- package/lib/public/mate-avatars/C16.png +0 -0
- package/lib/public/mate-avatars/C17.png +0 -0
- package/lib/public/mate-avatars/C18.png +0 -0
- package/lib/public/mate-avatars/C19.png +0 -0
- package/lib/public/mate-avatars/C20.png +0 -0
- package/lib/public/mate-avatars/C21.png +0 -0
- package/lib/public/mate-avatars/C22.png +0 -0
- package/lib/public/mate-avatars/C23.png +0 -0
- package/lib/public/mate-avatars/C24.png +0 -0
- package/lib/public/mate-avatars/C25.png +0 -0
- package/lib/public/mate-avatars/C26.png +0 -0
- package/lib/public/mate-avatars/C27.png +0 -0
- package/lib/public/mate-avatars/C28.png +0 -0
- package/lib/public/mate-avatars/C29.png +0 -0
- package/lib/public/mate-avatars/C30.png +0 -0
- package/lib/public/mate-avatars/C31.png +0 -0
- package/lib/public/mate-avatars/C32.png +0 -0
- package/lib/public/mate-avatars/C33.png +0 -0
- package/lib/public/mate-avatars/C34.png +0 -0
- package/lib/public/mate-avatars/C35.png +0 -0
- package/lib/public/mate-avatars/C36.png +0 -0
- package/lib/public/mate-avatars/C37.png +0 -0
- package/lib/public/mate-avatars/C38.png +0 -0
- package/lib/public/mate-avatars/C39.png +0 -0
- package/lib/public/mate-avatars/C40.png +0 -0
- package/lib/public/mate-avatars/C41.png +0 -0
- package/lib/public/mate-avatars/C42.png +0 -0
- package/lib/public/mate-avatars/C43.png +0 -0
- package/lib/public/mate-avatars/C44.png +0 -0
- package/lib/public/mate-avatars/C45.png +0 -0
- package/lib/public/mate-avatars/C46.png +0 -0
- package/lib/public/mate-avatars/C47.png +0 -0
- package/lib/public/mate-avatars/C48.png +0 -0
- package/lib/public/mate-avatars/catalog.json +482 -0
- package/lib/public/mate-avatars/lead-clay.png +0 -0
- package/lib/public/modules/app-message-router.js +4 -0
- package/lib/public/modules/app-messages.js +13 -2
- package/lib/public/modules/app-rendering.js +1 -1
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +10 -1
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-log-links.js +1 -1
- package/lib/public/modules/command-palette.js +1 -1
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/history-replay-batch.js +5 -1
- package/lib/public/modules/home-debate-live.js +2 -0
- package/lib/public/modules/home-debate-planning.js +7 -7
- package/lib/public/modules/home-mate-avatar-editor.js +127 -208
- package/lib/public/modules/home-mate-chat.js +6 -6
- package/lib/public/modules/home-mate-settings.js +19 -12
- package/lib/public/modules/markdown.js +4 -0
- package/lib/public/modules/mate-avatar-catalog.js +97 -0
- package/lib/public/modules/mate-management.js +40 -7
- package/lib/public/modules/mcp-connection-view.js +31 -13
- package/lib/public/modules/mcp-discovery-view.js +31 -0
- package/lib/public/modules/mcp-ui.js +23 -4
- package/lib/public/modules/mention.js +3 -0
- package/lib/public/modules/pane-browser-bridge.js +20 -0
- package/lib/public/modules/profile.js +1 -238
- package/lib/public/modules/project-mate-navigation.js +99 -14
- package/lib/public/modules/search-clay-chat.js +16 -2
- package/lib/public/modules/session-github.js +23 -9
- package/lib/public/modules/session-work-primary.js +51 -0
- package/lib/public/modules/shared-browser-settings.js +112 -0
- package/lib/public/modules/shared-browser-tabs.js +13 -3
- package/lib/public/modules/shared-browser.js +27 -6
- package/lib/public/modules/split-view.js +2 -0
- package/lib/public/modules/theme.js +8 -1
- package/lib/public/modules/tools.js +2 -1
- package/lib/public/style.css +1 -0
- package/lib/public/sw.js +3 -1
- package/lib/sdk-bridge.js +9 -3
- package/lib/server-appearance-settings.js +13 -1
- package/lib/server-dm.js +1 -0
- package/lib/server-home-chat-events.js +14 -4
- package/lib/server-home-chat.js +10 -2
- package/lib/server-home-mcp-consent.js +14 -0
- package/lib/server-mates.js +6 -1
- package/lib/server-settings.js +4 -1
- package/lib/server.js +45 -12
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +3 -0
- package/lib/shared-browser-cookie-sync.js +32 -0
- package/lib/shared-browser-cookies.js +79 -0
- package/lib/shared-browser-runtime.js +25 -9
- package/lib/shared-browser-storage-sync.js +43 -0
- package/lib/shared-browser-storage.js +101 -0
- package/lib/shared-browser-tools.js +2 -1
- package/lib/shared-browser-worker.js +46 -10
- package/lib/yoke/acp-agent-profiles.js +2 -2
- package/package.json +5 -1
|
@@ -5,12 +5,14 @@ var browserTools = require("./shared-browser-tools");
|
|
|
5
5
|
var createRuntime = require("./shared-browser-runtime").createRuntime;
|
|
6
6
|
|
|
7
7
|
function attachSharedBrowser(ctx) {
|
|
8
|
+
var storageStore = ctx.storageStore || require("./shared-browser-storage").attachStorageStore(require("./config").CONFIG_DIR);
|
|
8
9
|
var records = new Map();
|
|
9
10
|
var viewers = new Map();
|
|
10
11
|
var destroyed = false;
|
|
11
12
|
function allowed(session, ws) {
|
|
12
13
|
try {
|
|
13
|
-
if (
|
|
14
|
+
if (!session || ctx.sm.sessions.get(session.localId) !== session) return false;
|
|
15
|
+
if (ctx.isMate && ctx.usersModule.isMultiUser() && (!ctx.ownerId || session.ownerId !== ctx.ownerId)) return false;
|
|
14
16
|
if (ctx.usersModule.isMultiUser()) {
|
|
15
17
|
var user = ctx.usersModule.findUserById(session.ownerId);
|
|
16
18
|
if (!user || (ws && (!ws._clayUser || String(ws._clayUser.id) !== String(user.id)))) return false;
|
|
@@ -35,7 +37,7 @@ function attachSharedBrowser(ctx) {
|
|
|
35
37
|
function projection(record) {
|
|
36
38
|
if (!record) return null;
|
|
37
39
|
return { id: record.id, phase: record.phase, control: record.control, epoch: record.epoch, handoff: !!record.handoff,
|
|
38
|
-
url: record.url, width: record.width, height: record.height, activity: record.activity || null, activityHistory: record.activityHistory || [], pointer: record.pointer || null, error: record.error || "" };
|
|
40
|
+
browserLink: record.url ? "browser:" + record.url : null, incognito: record.incognito, personalCookiesAvailable: !!ctx.isMate, url: record.url, width: record.width, height: record.height, activity: record.activity || null, activityHistory: record.activityHistory || [], pointer: record.pointer || null, error: record.error || "" };
|
|
39
41
|
}
|
|
40
42
|
function sessionRecords(session) {
|
|
41
43
|
return Array.from(records.values()).filter(function (record) { return record.session === session && recordAllowed(record); });
|
|
@@ -93,6 +95,13 @@ function attachSharedBrowser(ctx) {
|
|
|
93
95
|
if ((record.activity || record.pointer) && record.activityGeneration !== Number(record.session._sdkQueryGeneration || 0)) {
|
|
94
96
|
activityHistory.interruptActivity(record); record.pointer = null; broadcast(record);
|
|
95
97
|
}
|
|
98
|
+
if (message.type === "navigation") {
|
|
99
|
+
try { record.navigationUrl = policy.browserUrl(message.navigationUrl || message.url); } catch (error) { record.navigationUrl = null; }
|
|
100
|
+
}
|
|
101
|
+
if (message.type === "navigation" && !record.incognito) {
|
|
102
|
+
try { storageStore.visit(record.cookieOwner, message.url); }
|
|
103
|
+
catch (error) { end(record, "Could not save personal browsing history"); return; }
|
|
104
|
+
}
|
|
96
105
|
if (message.type === "ready") { record.phase = "live"; record.resolveReady(); }
|
|
97
106
|
if (message.type === "error") { end(record, message.error); return; }
|
|
98
107
|
if (message.url !== undefined) record.url = policy.visibleUrl(message.url);
|
|
@@ -108,10 +117,12 @@ function attachSharedBrowser(ctx) {
|
|
|
108
117
|
}
|
|
109
118
|
// Every new tab starts shared. Exclusive human mode is explicit, per tab, and only the human clears it,
|
|
110
119
|
// so an agent open never reuses (or bypasses) an exclusive tab.
|
|
111
|
-
function create(session, actor, newTab) {
|
|
120
|
+
function create(session, actor, newTab, incognito) {
|
|
112
121
|
requireAccess(session);
|
|
122
|
+
if (incognito !== undefined && typeof incognito !== "boolean") throw new Error("Invalid incognito mode");
|
|
123
|
+
var temporary = !ctx.isMate || incognito === true;
|
|
113
124
|
var tabs = sessionRecords(session);
|
|
114
|
-
var previous = !newTab && tabs.find(function (record) { return record.runtime && (actor === "user" || record.control === "agent"); });
|
|
125
|
+
var previous = !newTab && tabs.find(function (record) { return record.runtime && (incognito === undefined || record.incognito === temporary) && (actor === "user" || record.control === "agent"); });
|
|
115
126
|
if (previous) return previous;
|
|
116
127
|
if (tabs.length >= 12) {
|
|
117
128
|
var expired = tabs.find(function (record) { return !record.runtime; });
|
|
@@ -122,12 +133,15 @@ function attachSharedBrowser(ctx) {
|
|
|
122
133
|
records.forEach(function (record) { if (record.runtime && record.ownerId === session.ownerId) active++; });
|
|
123
134
|
if (active >= 4) throw new Error("End another browser before opening more than four active tabs");
|
|
124
135
|
var record = { session: session, ownerId: session.ownerId, identity: identityKey(session), id: crypto.randomUUID(), phase: "starting", control: "agent", epoch: 0,
|
|
125
|
-
url: "", width: 1280, height: 800, touched: Date.now(), runtime: null, frame: null };
|
|
136
|
+
cookieOwner: ctx.isMate ? (ctx.ownerId || session.ownerId || "default") : null, incognito: temporary, url: "", width: 1280, height: 800, touched: Date.now(), runtime: null, frame: null };
|
|
126
137
|
record.ready = new Promise(function (resolve, reject) { record.resolveReady = resolve; record.rejectReady = reject; });
|
|
127
138
|
record.ready.catch(function () {});
|
|
128
139
|
records.set(record.id, record);
|
|
129
140
|
try {
|
|
130
|
-
record.runtime = (ctx.createRuntime || createRuntime)({ identity: ctx.getIdentity(session),
|
|
141
|
+
record.runtime = (ctx.createRuntime || createRuntime)({ identity: ctx.getIdentity(session), storage: temporary ? null : {
|
|
142
|
+
read: function () { if (!recordAllowed(record)) throw new Error("Browser access was revoked"); return storageStore.read(record.cookieOwner); },
|
|
143
|
+
exchange: function (previous, current) { if (!recordAllowed(record)) throw new Error("Browser access was revoked"); return storageStore.exchange(record.cookieOwner, previous, current); },
|
|
144
|
+
}, onEvent: function (message) { receive(record, message); } });
|
|
131
145
|
} catch (e) { end(record, e.message); }
|
|
132
146
|
broadcast(record, true);
|
|
133
147
|
return record;
|
|
@@ -186,6 +200,7 @@ function attachSharedBrowser(ctx) {
|
|
|
186
200
|
requireAccess(session);
|
|
187
201
|
if (actor === "agent" && Number(session._sdkQueryGeneration || 0) !== generation) throw new Error("Browser result belongs to an older query");
|
|
188
202
|
if (!recordAllowed(record) || records.get(record.id) !== record || record.epoch !== epoch) throw new Error("Browser control changed during the action");
|
|
203
|
+
if (result && result.url !== undefined) record.url = policy.visibleUrl(result.url);
|
|
189
204
|
return result;
|
|
190
205
|
}
|
|
191
206
|
async function tool(session, args) {
|
|
@@ -196,8 +211,10 @@ function attachSharedBrowser(ctx) {
|
|
|
196
211
|
var value;
|
|
197
212
|
if (args.action === "status") value = { browsers: sessionRecords(session).map(projection) };
|
|
198
213
|
else if (args.action === "open") {
|
|
214
|
+
if (args.incognito !== undefined && typeof args.incognito !== "boolean") throw new Error("Invalid incognito mode");
|
|
199
215
|
var url = args.url ? policy.browserUrl(args.url) : null;
|
|
200
|
-
record = args.browserId ? selectRecord(session, args.browserId) : create(session, "agent", args.newTab === true);
|
|
216
|
+
record = args.browserId ? selectRecord(session, args.browserId) : create(session, "agent", args.newTab === true, args.incognito);
|
|
217
|
+
if (args.incognito !== undefined && record.incognito !== (!ctx.isMate || args.incognito)) throw new Error("This tab has a different cookie mode. Open a new tab with the requested mode.");
|
|
201
218
|
if (url) await run(session, record, "agent", "action", { kind: "navigate", url: url }, args.intent);
|
|
202
219
|
value = projection(record);
|
|
203
220
|
} else if (args.action === "finish") {
|
|
@@ -206,14 +223,27 @@ function attachSharedBrowser(ctx) {
|
|
|
206
223
|
} else if (args.action === "inspect") {
|
|
207
224
|
value = await run(session, record, "agent", "inspect", null, args.intent);
|
|
208
225
|
value.browserId = record.id;
|
|
226
|
+
value.browserLink = record.url ? "browser:" + record.url : null;
|
|
209
227
|
var image = value.image; delete value.image;
|
|
210
228
|
return { content: [{ type: "text", text: JSON.stringify(value) }, { type: "image", mimeType: "image/jpeg", data: image }] };
|
|
211
229
|
} else {
|
|
212
230
|
value = await run(session, record, "agent", "action", policy.validateAction(Object.assign({}, args, { kind: args.action })), args.intent);
|
|
213
231
|
}
|
|
232
|
+
if (value && value.url) value.browserLink = "browser:" + policy.visibleUrl(value.url);
|
|
214
233
|
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
215
234
|
} catch (e) { return { isError: true, content: [{ type: "text", text: e.message }] }; }
|
|
216
235
|
}
|
|
236
|
+
async function openLinkedPage(session, url, incognito) {
|
|
237
|
+
var record = sessionRecords(session).find(function (tab) {
|
|
238
|
+
return tab.runtime && ((tab.phase === "live" && (tab.navigationUrl || tab.url) === url) || (tab.linkOpening && tab.linkOpening.url === url));
|
|
239
|
+
});
|
|
240
|
+
if (record) { if (record.linkOpening) await record.linkOpening.promise; return record; }
|
|
241
|
+
record = create(session, "user", true, incognito);
|
|
242
|
+
record.navigationUrl = url;
|
|
243
|
+
record.linkOpening = { url: url, promise: run(session, record, "user", "action", { kind: "navigate", url: url }) };
|
|
244
|
+
try { await record.linkOpening.promise; } finally { record.linkOpening = null; }
|
|
245
|
+
return record;
|
|
246
|
+
}
|
|
217
247
|
function handleMessage(ws, msg) {
|
|
218
248
|
if (!msg.type || msg.type.indexOf("shared_browser_") !== 0) return false;
|
|
219
249
|
var session = ctx.getSessionForWs(ws);
|
|
@@ -221,8 +251,22 @@ function attachSharedBrowser(ctx) {
|
|
|
221
251
|
requireAccess(session, ws);
|
|
222
252
|
if (String(msg.sessionId) !== String(session.localId)) throw new Error("Browser session changed");
|
|
223
253
|
var record;
|
|
254
|
+
if (msg.type === "shared_browser_settings") {
|
|
255
|
+
if (!ctx.isMate) throw new Error("Personal browser settings are available only in Mates");
|
|
256
|
+
if (typeof msg.requestId !== "string" || msg.requestId.length > 100) throw new Error("Invalid browser settings request");
|
|
257
|
+
var owner = ctx.ownerId || session.ownerId || "default";
|
|
258
|
+
var settings = storageStore.manage(owner, msg.operation, msg.target);
|
|
259
|
+
requireAccess(session, ws);
|
|
260
|
+
ctx.sendTo(ws, { type: "shared_browser_settings", sessionId: session.localId, requestId: msg.requestId, settings: settings });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
224
263
|
if (msg.type === "shared_browser_state_request") { sendState(ws, session, sessionRecords(session)[0]); return; }
|
|
225
|
-
if (msg.type === "shared_browser_open") {
|
|
264
|
+
if (msg.type === "shared_browser_open") {
|
|
265
|
+
var targetUrl = msg.url === undefined ? null : policy.browserUrl(msg.url);
|
|
266
|
+
if (targetUrl) record = await openLinkedPage(session, targetUrl, msg.incognito);
|
|
267
|
+
else record = create(session, "user", msg.newTab === true, msg.incognito);
|
|
268
|
+
sendState(ws, session, record, true, true); return;
|
|
269
|
+
}
|
|
226
270
|
record = selectRecord(session, msg.browserId);
|
|
227
271
|
if (!record || !recordAllowed(record, ws) || msg.browserId !== record.id) throw new Error("Browser session expired");
|
|
228
272
|
if (msg.type === "shared_browser_view") {
|
|
@@ -242,7 +286,7 @@ function attachSharedBrowser(ctx) {
|
|
|
242
286
|
await run(session, record, "user", "action", policy.validateAction(msg.event));
|
|
243
287
|
}
|
|
244
288
|
}).catch(function (e) {
|
|
245
|
-
if (ws.readyState === 1) ctx.sendTo(ws, { type: "shared_browser_error", sessionId: msg.sessionId, error: e.message });
|
|
289
|
+
if (ws.readyState === 1) ctx.sendTo(ws, { type: "shared_browser_error", sessionId: msg.sessionId, error: e.message, requestId: msg.requestId });
|
|
246
290
|
});
|
|
247
291
|
return true;
|
|
248
292
|
}
|
|
@@ -257,7 +301,7 @@ function attachSharedBrowser(ctx) {
|
|
|
257
301
|
sweep.unref();
|
|
258
302
|
function getToolDefs(session) {
|
|
259
303
|
var generation = Number(session && session._sdkQueryGeneration || 0);
|
|
260
|
-
return
|
|
304
|
+
return browserTools.getToolDefs(function (args) {
|
|
261
305
|
if (session && Number(session._sdkQueryGeneration || 0) !== generation) {
|
|
262
306
|
return Promise.resolve({ isError: true, content: [{ type: "text", text: "This browser tool belongs to an older query" }] });
|
|
263
307
|
}
|
|
@@ -267,8 +311,8 @@ function attachSharedBrowser(ctx) {
|
|
|
267
311
|
return {
|
|
268
312
|
handleMessage: handleMessage,
|
|
269
313
|
getToolDefs: getToolDefs,
|
|
270
|
-
getSystemPrompt: function () { return
|
|
271
|
-
createMcpServer: function (adapter, session) { return
|
|
314
|
+
getSystemPrompt: function () { return browserTools.PROMPT; },
|
|
315
|
+
createMcpServer: function (adapter, session) { return !adapter || typeof adapter.createToolServer !== "function" ? null : adapter.createToolServer({ name: "clay-shared-browser", version: "1.0.0", tools: getToolDefs(session) }); },
|
|
272
316
|
destroy: function () { destroyed = true; clearInterval(sweep); records.forEach(function (record) { end(record); }); records.clear(); viewers.clear(); },
|
|
273
317
|
};
|
|
274
318
|
}
|
package/lib/project.js
CHANGED
|
@@ -348,6 +348,10 @@ function createProjectContext(opts) {
|
|
|
348
348
|
function getRuntimeEnvForSession(session) {
|
|
349
349
|
var linuxUser = (session && session.linuxUser) || getLinuxUserForSession(session);
|
|
350
350
|
var osUserInfo = getOsUserInfoForLinuxUser(linuxUser);
|
|
351
|
+
return resolveOwnerRuntimeEnv(osUserInfo);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function resolveOwnerRuntimeEnv(osUserInfo) {
|
|
351
355
|
var baseEnv = osUserInfo ? buildUserEnv(osUserInfo) : process.env;
|
|
352
356
|
var shared = typeof opts.onGetSharedEnv === "function" ? opts.onGetSharedEnv() : null;
|
|
353
357
|
var projectEnv = typeof opts.onGetProjectEnv === "function" ? opts.onGetProjectEnv(slug) : null;
|
|
@@ -709,7 +713,22 @@ function createProjectContext(opts) {
|
|
|
709
713
|
|
|
710
714
|
// Personal computer tools use the extension; remote URLs are owner-bound.
|
|
711
715
|
var _mcp = attachMcp({
|
|
712
|
-
sendTo: sendTo, slug: slug, clients: clients,
|
|
716
|
+
sendTo: sendTo, slug: slug, clients: clients, cwd: cwd,
|
|
717
|
+
userInput: function (session) { return _askUser.createHandler(session); },
|
|
718
|
+
runtimeEnvForSession: getRuntimeEnvForSession,
|
|
719
|
+
canDiscoverSession: function (session) { var scope = _requestAccess.fileScope({ _clayUser: session.ownerId && usersModule.findUserById(session.ownerId) }); return !!scope.identity || !scope.projectBound; },
|
|
720
|
+
sessionVendor: function (session) { return session.vendor || sm.defaultVendor || "claude"; },
|
|
721
|
+
runtimeEnv: function (owner, ws) { return resolveOwnerRuntimeEnv(_requestAccess.fileScope(ws).identity); },
|
|
722
|
+
canDiscover: function (ws) { var scope = _requestAccess.fileScope(ws); return !!scope.identity || !scope.projectBound; },
|
|
723
|
+
ownerIdentity: function (owner) {
|
|
724
|
+
if (!osUsers) {
|
|
725
|
+
if (usersModule.isMultiUser() && (usersModule.getAllUsers().length !== 1 || !usersModule.findUserById(owner))) throw new Error('Local MCP requires OS user mapping in a shared installation.');
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
var user = usersModule.findUserById(owner);
|
|
729
|
+
if (!user || !user.linuxUser) throw new Error('OS user identity is unavailable.');
|
|
730
|
+
return getOsUserInfoForWs({ _clayUser: user });
|
|
731
|
+
},
|
|
713
732
|
root: require("./config").CONFIG_DIR,
|
|
714
733
|
isMultiUser: function () { return usersModule.isMultiUser(); },
|
|
715
734
|
canAccess: function (ws) { return _requestAccess.canAccessProject(ws, slug); },
|
|
@@ -769,7 +788,7 @@ function createProjectContext(opts) {
|
|
|
769
788
|
},
|
|
770
789
|
});
|
|
771
790
|
var _sharedBrowser = attachSharedBrowser({
|
|
772
|
-
slug: slug, isMate: isMate, sm: sm, clients: clients, sendTo: sendTo,
|
|
791
|
+
slug: slug, isMate: isMate, ownerId: projectOwnerId, sm: sm, clients: clients, sendTo: sendTo,
|
|
773
792
|
usersModule: usersModule, requestAccess: _requestAccess, osUsers: osUsers,
|
|
774
793
|
getSessionForWs: getSessionForWs,
|
|
775
794
|
getIdentity: function (session) {
|
|
@@ -780,6 +799,7 @@ function createProjectContext(opts) {
|
|
|
780
799
|
var _sessionDocument = attachSessionDocument({
|
|
781
800
|
cwd: cwd,
|
|
782
801
|
isMate: isMate,
|
|
802
|
+
canUseSession: _sessionNotes.canUseSession,
|
|
783
803
|
sendToSession: sendToSession,
|
|
784
804
|
FS_MAX_SIZE: FS_MAX_SIZE,
|
|
785
805
|
getOsUserInfoForSession: function (session) {
|
|
@@ -839,7 +859,12 @@ function createProjectContext(opts) {
|
|
|
839
859
|
sendTo: sendTo, getClients: function () { return clients; }, startWork: _issueWork,
|
|
840
860
|
});
|
|
841
861
|
var _sessionGithub = require("./project-session-github").attachSessionGithub({
|
|
842
|
-
cwd: cwd, sm: sm, isMate: isMate, osUsers: osUsers,
|
|
862
|
+
cwd: cwd, sm: sm, isMate: isMate, osUsers: osUsers, projectSlug: slug, sendTo: sendTo,
|
|
863
|
+
userInput: function (session) { return _askUser.createHandler(session); },
|
|
864
|
+
canAccess: function (ws) {
|
|
865
|
+
return !isMate && clients.has(ws) && ws.readyState === 1 && (!usersModule.isMultiUser() ||
|
|
866
|
+
!!(ws._clayUser && usersModule.findUserById(ws._clayUser.id) && opts.canAccessProjectSlug(ws._clayUser.id, slug)));
|
|
867
|
+
},
|
|
843
868
|
canUse: function (session) {
|
|
844
869
|
if (session.hidden || session.delegated || session._pairDelegation || session._delegatedBy || require("./session-provenance").isWorker(session)) return false;
|
|
845
870
|
if (!usersModule.isMultiUser()) return true;
|
|
@@ -858,9 +883,10 @@ function createProjectContext(opts) {
|
|
|
858
883
|
});
|
|
859
884
|
var _sessionLinear = require("./project-session-linear").attachSessionLinear({
|
|
860
885
|
sm: sm, isMate: isMate, storage: opts.linearStorage, projectSlug: slug,
|
|
886
|
+
userInput: function (session) { return _askUser.createHandler(session); },
|
|
861
887
|
isMultiUser: usersModule.isMultiUser, sendTo: sendTo,
|
|
862
888
|
canAccess: function (ws) {
|
|
863
|
-
return
|
|
889
|
+
return clients.has(ws) && ws.readyState === 1 && (!usersModule.isMultiUser() ||
|
|
864
890
|
!!(ws._clayUser && usersModule.findUserById(ws._clayUser.id) && opts.canAccessProjectSlug(ws._clayUser.id, slug)));
|
|
865
891
|
},
|
|
866
892
|
startWork: require('./project-linear-launch').attachLinearLaunch({
|
|
@@ -1055,14 +1081,12 @@ function createProjectContext(opts) {
|
|
|
1055
1081
|
}
|
|
1056
1082
|
}
|
|
1057
1083
|
|
|
1058
|
-
// Shared sticky-note memory
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
console.error("[project] Failed to create session notes MCP server:", e.message);
|
|
1065
|
-
}
|
|
1084
|
+
// Shared sticky-note memory is available in both owner-private projects and Mates.
|
|
1085
|
+
try {
|
|
1086
|
+
var sessionNotesMcpConfig = _sessionNotes.createMcpServer(adapter);
|
|
1087
|
+
if (sessionNotesMcpConfig) servers[sessionNotesMcpConfig.name || "clay-notes"] = sessionNotesMcpConfig;
|
|
1088
|
+
} catch (e) {
|
|
1089
|
+
console.error("[project] Failed to create session notes MCP server:", e.message);
|
|
1066
1090
|
}
|
|
1067
1091
|
|
|
1068
1092
|
// Project Logs. Project sessions get the project-scoped set; Mate projects
|
|
@@ -1107,13 +1131,11 @@ function createProjectContext(opts) {
|
|
|
1107
1131
|
if (sharedBrowserConfig) servers["clay-shared-browser"] = sharedBrowserConfig;
|
|
1108
1132
|
|
|
1109
1133
|
// Explicit agent signal for user-requested Markdown presentation.
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
console.error("[project] Failed to create session document MCP server:", e.message);
|
|
1116
|
-
}
|
|
1134
|
+
try {
|
|
1135
|
+
var sessionDocumentMcpConfig = _sessionDocument.createMcpServer(adapter);
|
|
1136
|
+
if (sessionDocumentMcpConfig) servers[sessionDocumentMcpConfig.name || "clay-documents"] = sessionDocumentMcpConfig;
|
|
1137
|
+
} catch (e) {
|
|
1138
|
+
console.error("[project] Failed to create session document MCP server:", e.message);
|
|
1117
1139
|
}
|
|
1118
1140
|
|
|
1119
1141
|
// Debate MCP server (available to both mates and main project)
|
|
@@ -2336,6 +2358,8 @@ function createProjectContext(opts) {
|
|
|
2336
2358
|
function getMcpBridgeHandler(sessionId, sessionOnly, queryGeneration) {
|
|
2337
2359
|
var boundSession = Number.isInteger(sessionId) ? sm.sessions.get(sessionId) : null;
|
|
2338
2360
|
var queryToolBridge = createSessionQueryToolBridge({ session: boundSession, sdk: sdk });
|
|
2361
|
+
var externalQueryBridge = require('./mcp-query-bridge').createQueryBridge({ valid: sessionQueryValid,
|
|
2362
|
+
getServers: function () { return _mcp.getMcpServers(boundSession, sessionQueryValid()); } });
|
|
2339
2363
|
function sessionQueryValid() {
|
|
2340
2364
|
return !!boundSession
|
|
2341
2365
|
&& Number.isInteger(queryGeneration)
|
|
@@ -2460,7 +2484,7 @@ function createProjectContext(opts) {
|
|
|
2460
2484
|
}
|
|
2461
2485
|
}
|
|
2462
2486
|
|
|
2463
|
-
if (sessionOnly) return Promise.resolve(tools);
|
|
2487
|
+
if (sessionOnly) return Promise.resolve(tools.concat(externalQueryBridge.list()));
|
|
2464
2488
|
|
|
2465
2489
|
// In-app MCP servers (debate, browser, email).
|
|
2466
2490
|
// Use getLocalMcpServers() so clay-browser is hidden unless the
|
|
@@ -2480,7 +2504,7 @@ function createProjectContext(opts) {
|
|
|
2480
2504
|
}
|
|
2481
2505
|
|
|
2482
2506
|
// Personal computer and remote URL connections.
|
|
2483
|
-
var remoteServers = _mcp.getMcpServers(boundSession);
|
|
2507
|
+
var remoteServers = sessionQueryValid() ? _mcp.getMcpServers(boundSession, sessionQueryValid()) : {};
|
|
2484
2508
|
if (remoteServers) {
|
|
2485
2509
|
var remoteNames = Object.keys(remoteServers);
|
|
2486
2510
|
for (var ri = 0; ri < remoteNames.length; ri++) {
|
|
@@ -2578,7 +2602,7 @@ function createProjectContext(opts) {
|
|
|
2578
2602
|
if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents" || serverName === "clay-shared-browser" || serverName === "clay-debate" || serverName === "clay-mate-creation" || serverName === "clay-workspace" || serverName === "clay-history" || serverName === "clay-github" || serverName === "clay-linear" || serverName === "clay-issues" || serverName === "clay-logs" || serverName === "clay-knowledge" || serverName === "clay-you") {
|
|
2579
2603
|
return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
|
|
2580
2604
|
}
|
|
2581
|
-
if (sessionOnly) return
|
|
2605
|
+
if (sessionOnly) return externalQueryBridge.call(serverName, toolName, args);
|
|
2582
2606
|
// Try in-app servers first (gated by extension connectivity for clay-browser).
|
|
2583
2607
|
var localMcp = getLocalMcpServers(boundSession);
|
|
2584
2608
|
if (localMcp && localMcp[serverName]) {
|
|
@@ -2590,17 +2614,7 @@ function createProjectContext(opts) {
|
|
|
2590
2614
|
}
|
|
2591
2615
|
}
|
|
2592
2616
|
}
|
|
2593
|
-
|
|
2594
|
-
var remoteServers = _mcp.getMcpServers(boundSession);
|
|
2595
|
-
if (remoteServers && remoteServers[serverName]) {
|
|
2596
|
-
var rServer = remoteServers[serverName];
|
|
2597
|
-
if (rServer.instance && rServer.instance._registeredTools && rServer.instance._registeredTools[toolName]) {
|
|
2598
|
-
var rHandler = rServer.instance._registeredTools[toolName].handler;
|
|
2599
|
-
if (typeof rHandler === "function") {
|
|
2600
|
-
return Promise.resolve(rHandler(args));
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2617
|
+
if (externalQueryBridge.list().some(function (tool) { return tool.server === serverName && tool.name === toolName; })) return externalQueryBridge.call(serverName, toolName, args);
|
|
2604
2618
|
return Promise.reject(new Error("Tool not found: " + serverName + "/" + toolName));
|
|
2605
2619
|
},
|
|
2606
2620
|
};
|
|
@@ -2917,7 +2931,8 @@ function createProjectContext(opts) {
|
|
|
2917
2931
|
unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
|
|
2918
2932
|
handleHomeDebateProposalResponse: function (ws, msg, session) { return _debateProposal.handleHomeMessage(ws, msg, session); },
|
|
2919
2933
|
handleHomeMateCreationProposalResponse: function (ws, msg, session) { return _mateCreationProposal.handleHomeMessage(ws, msg, session); },
|
|
2920
|
-
|
|
2934
|
+
registerMcpConsentViewer: _mcp.registerConsentViewer,
|
|
2935
|
+
handleHomeAskUserResponse: function (msg, session, ws) { return _sessions.respondToAskUser(session, msg, ws); },
|
|
2921
2936
|
handleHomePermissionResponse: function (ws, msg, session) { return _sessions.respondToHomePermission(ws, msg, session); },
|
|
2922
2937
|
stopHomeSession: function (session) { return _sessions.stopHomeSession(session); },
|
|
2923
2938
|
handleHomeDebateControl: function (ws, msg, session) { return _debate.handleHomeControl(ws, msg, session); },
|
package/lib/public/app.js
CHANGED
|
@@ -285,6 +285,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
285
285
|
mcpConnections: { screen: "list", servers: [], search: "", loaded: false },
|
|
286
286
|
sharedBrowserOpen: false,
|
|
287
287
|
sharedBrowserUi: {},
|
|
288
|
+
sharedBrowserSettings: {},
|
|
289
|
+
browserLinksBound: false,
|
|
288
290
|
// session / routing
|
|
289
291
|
basePath: basePath,
|
|
290
292
|
wsPath: wsPath,
|
|
@@ -324,9 +326,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
324
326
|
githubWorkSessions: [],
|
|
325
327
|
githubWorkProject: null,
|
|
326
328
|
githubWorkRefresh: null,
|
|
329
|
+
workPrimaryPending: null,
|
|
327
330
|
activeProjectSlug: null,
|
|
328
331
|
activeProjectMateId: null,
|
|
329
332
|
activeProjectMateName: '',
|
|
333
|
+
clayReturnTarget: null,
|
|
334
|
+
clayReturnPendingProjectSlug: null,
|
|
330
335
|
activeSessionMateId: null,
|
|
331
336
|
activeSessionMateName: '',
|
|
332
337
|
sessionActivatedProjectSlug: null,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var root = document.documentElement;
|
|
3
|
+
var light = window.matchMedia && window.matchMedia("(prefers-color-scheme: light)").matches;
|
|
4
|
+
var seed = window.__clayAppearanceSeed;
|
|
5
|
+
|
|
6
|
+
function applyMode(mode) {
|
|
7
|
+
if (mode !== "light" && mode !== "dark") return;
|
|
8
|
+
root.classList.toggle("light-theme", mode === "light");
|
|
9
|
+
root.classList.toggle("dark-theme", mode !== "light");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var savedMode = seed && seed.configured && (seed.mode === "light" || seed.mode === "dark") ? seed.mode : null;
|
|
13
|
+
applyMode(savedMode || (light ? "light" : "dark"));
|
|
14
|
+
}());
|
|
@@ -4,6 +4,35 @@
|
|
|
4
4
|
padding: 0;
|
|
5
5
|
cursor: pointer;
|
|
6
6
|
}
|
|
7
|
+
.clay-brand-flip {
|
|
8
|
+
position: relative;
|
|
9
|
+
display: block;
|
|
10
|
+
width: 38px;
|
|
11
|
+
height: 38px;
|
|
12
|
+
transform-style: preserve-3d;
|
|
13
|
+
transition: transform 220ms cubic-bezier(.2,.75,.25,1);
|
|
14
|
+
}
|
|
15
|
+
.clay-brand-face {
|
|
16
|
+
position: absolute;
|
|
17
|
+
inset: 0;
|
|
18
|
+
width: 38px;
|
|
19
|
+
height: 38px;
|
|
20
|
+
object-fit: contain;
|
|
21
|
+
backface-visibility: hidden;
|
|
22
|
+
transition: opacity 120ms ease;
|
|
23
|
+
}
|
|
24
|
+
.clay-brand-avatar { transform: rotateY(180deg); border-radius: 11px; }
|
|
25
|
+
.icon-strip-brand[data-clay-mode="mate"] .clay-brand-flip { transform: rotateY(180deg); }
|
|
26
|
+
.icon-strip-brand:hover .clay-brand-flip,
|
|
27
|
+
.icon-strip-brand:focus-visible .clay-brand-flip,
|
|
28
|
+
.icon-strip-brand.clay-speaking[data-clay-mode="project"] .clay-brand-flip { transform: rotateY(180deg); }
|
|
29
|
+
.icon-strip-brand[data-clay-mode="mate"]:hover .clay-brand-flip,
|
|
30
|
+
.icon-strip-brand[data-clay-mode="mate"]:focus-visible .clay-brand-flip { transform: rotateY(0deg); }
|
|
31
|
+
.icon-strip-brand.clay-speaking[data-clay-mode="mate"] .clay-brand-flip { transform: rotateY(180deg); }
|
|
32
|
+
.icon-strip-brand.clay-speaking .clay-brand-face { transition-duration: 80ms; }
|
|
33
|
+
@media (prefers-reduced-motion: reduce) {
|
|
34
|
+
.clay-brand-flip, .clay-brand-face { transition: none; }
|
|
35
|
+
}
|
|
7
36
|
.icon-strip-brand:hover::before {
|
|
8
37
|
background: var(--bg-alt);
|
|
9
38
|
box-shadow: 0 1px 2px rgba(var(--shadow-rgb), 0.08);
|
|
@@ -87,6 +87,8 @@
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.home-debate-question-text { margin: 0 0 14px; font-size: 15px; }
|
|
90
|
+
.mcp-import-consent .home-debate-question-text,
|
|
91
|
+
.mcp-import-consent .ask-user-question-text { white-space: pre-line; font-size: 13px; line-height: 1.6; }
|
|
90
92
|
.home-debate-question-form { display: grid; gap: 8px; }
|
|
91
93
|
.home-debate-question-option {
|
|
92
94
|
display: grid;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* Coin-size portraits in an explicit, compact visual catalog. */
|
|
2
|
+
.home-mate-avatar-selection { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
|
|
3
|
+
.home-mate-avatar-selection p { color: var(--text-secondary); font-size: 12px; }
|
|
4
|
+
.home-mate-avatar-editor h4 { margin: 16px 0 8px; font-size: 13px; color: var(--text); }
|
|
5
|
+
.home-mate-avatar-choices { grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 5px; }
|
|
6
|
+
.home-mate-avatar-choice img { width: 42px; height: 42px; }
|
|
7
|
+
.home-mate-avatar-choice[aria-pressed="true"] { border: 2px solid var(--brand-indigo); padding: 4px 2px 5px; }
|
|
8
|
+
.home-mate-avatar-choice:disabled { cursor: default; opacity: .65; }
|
|
9
|
+
.home-mate-avatar-actions { position: sticky; bottom: 0; padding: 10px 0; background: var(--bg); z-index: 1; }
|
|
10
|
+
.home-mate-avatar-actions button.primary { background: var(--brand-indigo); color: white; border-color: var(--brand-indigo); }
|
|
11
|
+
@media (pointer: coarse) { .home-mate-avatar-choice { min-height: 62px; } }
|
|
12
|
+
.home-mate-avatar-actions .home-mate-avatar-status { flex: 0 0 100%; margin: 0; padding-top: 0; }
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/* Restore the Home conversation's reading measure inside Mate projects.
|
|
2
2
|
The existing project renderer, queue and composer still own behavior. */
|
|
3
|
-
body.mate-workspace-active {
|
|
4
|
-
|
|
3
|
+
body.mate-workspace-active {
|
|
4
|
+
--mate-content-width: 860px;
|
|
5
|
+
--content-width: var(--mate-content-width);
|
|
6
|
+
}
|
|
7
|
+
body.mate-workspace-active #messages {
|
|
8
|
+
padding-inline: max(12px, calc((100% - var(--mate-content-width)) / 2));
|
|
9
|
+
}
|
|
5
10
|
body.mate-workspace-active #messages > .msg-assistant,
|
|
6
11
|
body.mate-workspace-active #messages > .msg-user {
|
|
7
12
|
width: 100%;
|
|
8
|
-
max-width:
|
|
13
|
+
max-width: var(--mate-content-width);
|
|
9
14
|
box-sizing: border-box;
|
|
10
15
|
margin: 0 auto 12px;
|
|
11
16
|
padding: 4px 20px;
|
|
@@ -66,7 +71,7 @@ body.mate-workspace-active .msg-user:not(.msg-user-other):not(.msg-user-delegate
|
|
|
66
71
|
|
|
67
72
|
/* One writing row, with secondary tools and model selection underneath.
|
|
68
73
|
Display contents preserves the live controls and their event handlers. */
|
|
69
|
-
body.mate-workspace-active #input-wrapper { max-width:
|
|
74
|
+
body.mate-workspace-active #input-wrapper { max-width: var(--mate-content-width); }
|
|
70
75
|
body.mate-workspace-active #input-row,
|
|
71
76
|
body.mate-workspace-active #input-row:focus-within {
|
|
72
77
|
display: grid;
|
|
@@ -144,7 +149,7 @@ body.mate-workspace-active #messages > .mate-thinking,
|
|
|
144
149
|
body.mate-workspace-active #messages > .mate-permission,
|
|
145
150
|
body.mate-workspace-active #messages > .mate-ask-user {
|
|
146
151
|
box-sizing: border-box;
|
|
147
|
-
max-width:
|
|
152
|
+
max-width: var(--mate-content-width);
|
|
148
153
|
margin: 0 auto 12px;
|
|
149
154
|
padding: 4px 20px;
|
|
150
155
|
gap: 9px;
|
|
@@ -114,9 +114,29 @@
|
|
|
114
114
|
.github-state-merged .github-work-status svg, .github-state-closed .github-work-status svg { color: #a371f7; }
|
|
115
115
|
.github-state-draft .github-work-status svg, .github-state-unknown .github-work-status svg { color: var(--text-muted, #888); }
|
|
116
116
|
#header-github-links { min-width: 0; max-width: 200px; flex: 0 0 auto; margin-left: 4px; }
|
|
117
|
-
.github-work-details { flex-wrap: wrap; padding: 8px 0; gap: 8px 12px; }
|
|
117
|
+
.github-work-details { flex-wrap: wrap; padding: 8px 0; gap: 8px 12px; align-items: flex-start; }
|
|
118
118
|
.github-work-action { color: var(--text-muted, #888); text-decoration: none; font-size: 11px; }
|
|
119
119
|
.github-work-action:hover { text-decoration: underline; }
|
|
120
|
+
.github-work-pr-group {
|
|
121
|
+
display: grid;
|
|
122
|
+
grid-template-columns: minmax(0, auto) minmax(0, 1fr);
|
|
123
|
+
gap: 3px 10px;
|
|
124
|
+
flex: 1 1 100%;
|
|
125
|
+
min-width: 0;
|
|
126
|
+
padding-top: 7px;
|
|
127
|
+
border-top: 1px solid color-mix(in srgb, var(--text, #888) 14%, transparent);
|
|
128
|
+
}
|
|
129
|
+
.github-work-pr-header,
|
|
130
|
+
.github-work-pr-actions,
|
|
131
|
+
.github-work-pr-checks { min-width: 0; }
|
|
132
|
+
.github-work-pr-header { grid-row: span 2; }
|
|
133
|
+
.github-work-pr-actions,
|
|
134
|
+
.github-work-pr-checks { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 10px; }
|
|
135
|
+
.github-work-pr-checks { grid-column: 2; }
|
|
136
|
+
.github-work-check { display: inline-flex; min-width: 0; max-width: min(100%, 220px); align-items: baseline; gap: 4px; }
|
|
137
|
+
.github-work-check-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
138
|
+
.github-work-check-state { flex: 0 0 auto; white-space: nowrap; }
|
|
139
|
+
.github-work-pr-group .session-github-link { max-width: 100%; }
|
|
120
140
|
@media (max-width: 600px) {
|
|
121
141
|
#header-github-links { max-width: 82px; }
|
|
122
142
|
.mobile-session-item .session-github-link { min-height: 28px; padding-right: 4px; }
|
|
@@ -210,3 +230,25 @@
|
|
|
210
230
|
.mobile-session-item .session-row-github-links .github-work-more { padding-inline: 2px; }
|
|
211
231
|
.mobile-session-item .session-row-github-links { min-height: 28px; }
|
|
212
232
|
}
|
|
233
|
+
|
|
234
|
+
.work-primary-group + .work-primary-group { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border, #444); }
|
|
235
|
+
.work-primary-group h3 { margin: 0 0 4px; color: var(--text-muted, #888); font-size: 11px; font-weight: 500; }
|
|
236
|
+
.work-primary-row { display: grid; grid-template-columns: minmax(0, 1fr) 22px; gap: 5px; align-items: start; padding: 5px 0; }
|
|
237
|
+
.work-primary-row .github-work-entry { padding: 0; }
|
|
238
|
+
.work-primary-row .session-linear-link { min-width: 0; max-width: 100%; box-sizing: border-box; }
|
|
239
|
+
.work-primary-row .linear-work-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
240
|
+
.work-primary-choice { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 4px; background: transparent; color: var(--accent, #5857fc); opacity: .65; cursor: pointer; touch-action: manipulation; }
|
|
241
|
+
.work-primary-choice svg { width: 13px; height: 13px; transform: rotate(35deg); }
|
|
242
|
+
.work-primary-choice[aria-pressed="true"] .work-primary-pin-head { fill: currentColor; }
|
|
243
|
+
.work-primary-choice:hover:not(:disabled) { opacity: 1; background: color-mix(in srgb, var(--accent, #5857fc) 10%, transparent); }
|
|
244
|
+
.work-primary-choice:focus-visible { opacity: 1; outline: 2px solid var(--accent, #5857fc); outline-offset: 2px; }
|
|
245
|
+
.work-primary-choice[aria-pressed="true"] { color: var(--accent, #5857fc); opacity: 1; cursor: default; }
|
|
246
|
+
.work-primary-choice:disabled:not([aria-pressed="true"]) { opacity: .5; cursor: wait; }
|
|
247
|
+
.work-primary-feedback { margin: 6px 0 0; color: var(--text-muted, #888); font-size: 11px; }
|
|
248
|
+
.work-primary-feedback:empty { display: none; }
|
|
249
|
+
@media (max-width: 600px), (pointer: coarse) {
|
|
250
|
+
.work-primary-row { grid-template-columns: minmax(0, 1fr) 28px; }
|
|
251
|
+
.work-primary-choice { width: 28px; height: 28px; }
|
|
252
|
+
}
|
|
253
|
+
.work-primary-row .linear-work-id, .work-primary-row .linear-work-state { flex: none; white-space: nowrap; }
|
|
254
|
+
.work-primary-row .linear-work-state { max-width: 62px; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
.shared-browser-monitor-stand::before { content: ""; position: absolute; top: 0; bottom: 3px; left: 30%; right: 30%; background: linear-gradient(#aaa69c, #d2cdbf); clip-path: polygon(18% 0, 82% 0, 100% 100%, 0 100%); }
|
|
30
30
|
.shared-browser-monitor-stand::after { content: ""; position: absolute; inset: auto 0 0; height: 4px; background: #d8d3c6; border-radius: 2px; box-shadow: 0 1px 0 #9b978d, 0 6px 10px rgba(0,0,0,.22); }
|
|
31
31
|
.shared-browser-monitor-label { color: #a5aaaf; font-size: 10px; font-variant-numeric: tabular-nums; letter-spacing: .04em; }
|
|
32
|
-
.shared-browser-monitor .shared-browser-empty { color: #a5aaaf; }
|
|
32
|
+
.shared-browser-monitor .shared-browser-empty { color: #a5aaaf; background: #111315; }
|
|
33
33
|
.shared-browser-monitor .shared-browser-empty h3 { color: #eceeef; }
|
|
34
34
|
.shared-browser-viewport canvas { display: block; width: 100%; height: 100%; object-fit: contain; touch-action: none; }
|
|
35
35
|
.shared-browser-keyboard { position: absolute; bottom: 0; left: 50%; width: 1px; height: 1px; opacity: 0; padding: 0; border: 0; }
|
|
@@ -96,3 +96,37 @@
|
|
|
96
96
|
.shared-browser-tab > button:last-child { padding: 5px; font-size: 15px; color: var(--text-muted); }
|
|
97
97
|
|
|
98
98
|
#shared-browser-toggle-btn[aria-expanded="true"] { color: var(--text); background: rgba(var(--overlay-rgb), .06); }
|
|
99
|
+
|
|
100
|
+
.shared-browser-cookie-mode { font-size: 11px; color: var(--text-muted); margin-right: auto; white-space: nowrap; }
|
|
101
|
+
|
|
102
|
+
/* Personal browser data uses the compact settings anatomy inside the browser panel. */
|
|
103
|
+
.shared-browser-settings { flex: 1; min-height: 0; overflow: auto; padding: 16px 20px; background: var(--bg); color: var(--text); font-size: 13px; }
|
|
104
|
+
.shared-browser-settings[hidden] { display: none; }
|
|
105
|
+
.browser-settings-open > .shared-browser-viewport, .browser-settings-open > .shared-browser-address, .browser-settings-open > .shared-browser-tabs, .browser-settings-open > .shared-browser-footer { display: none; }
|
|
106
|
+
.browser-settings-heading { display: flex; align-items: center; gap: 16px; }
|
|
107
|
+
.browser-settings-heading h3 { font-size: 16px; margin: 0; }
|
|
108
|
+
.shared-browser-settings button { min-height: 28px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt); color: var(--text); padding: 4px 8px; font: inherit; cursor: pointer; }
|
|
109
|
+
.shared-browser-settings button:disabled { opacity: .5; cursor: default; }
|
|
110
|
+
.shared-browser-settings button:hover:not(:disabled) { background: var(--accent-bg); }
|
|
111
|
+
.shared-browser-settings button:focus-visible, .shared-browser-settings input:focus-visible, .shared-browser-settings summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
112
|
+
.browser-settings-muted, .browser-settings-row small, .browser-settings-origin small, .shared-browser-settings summary small { color: var(--text-muted); font-size: 12px; line-height: 1.5; }
|
|
113
|
+
.shared-browser-settings nav { display: flex; gap: 8px; margin: 18px 0 12px; }
|
|
114
|
+
.shared-browser-settings nav [aria-current] { border-color: var(--accent); color: var(--accent); }
|
|
115
|
+
.browser-settings-tools { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
116
|
+
.browser-settings-tools input { flex: 1; min-width: 140px; height: 32px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt); color: var(--text); padding: 0 8px; font: inherit; }
|
|
117
|
+
.browser-settings-feedback { font-size: 12px; min-height: 18px; }
|
|
118
|
+
.browser-settings-review { border: 1px solid var(--border); border-radius: 8px; padding: 12px; margin-bottom: 12px; }
|
|
119
|
+
.browser-settings-review p { font-size: 12px; line-height: 1.5; }
|
|
120
|
+
.browser-settings-review button + button { margin-left: 8px; }
|
|
121
|
+
.browser-settings-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
|
|
122
|
+
.browser-settings-row > div { min-width: 0; overflow-wrap: anywhere; }
|
|
123
|
+
.browser-settings-row button { flex-shrink: 0; }
|
|
124
|
+
.browser-settings-row small, .browser-settings-origin small, .shared-browser-settings summary small { display: block; }
|
|
125
|
+
.shared-browser-settings details { border-bottom: 1px solid var(--border); }
|
|
126
|
+
.shared-browser-settings summary { cursor: pointer; padding: 10px 0; overflow-wrap: anywhere; }
|
|
127
|
+
.browser-settings-origin { font-size: 12px; overflow-wrap: anywhere; }
|
|
128
|
+
|
|
129
|
+
.clay-browser-link { max-width: 100%; }
|
|
130
|
+
.clay-browser-link::before { display: none; }
|
|
131
|
+
.clay-browser-link > svg, .clay-browser-link > i { width: 14px; height: 14px; flex-shrink: 0; color: var(--accent); }
|
|
132
|
+
.clay-browser-link > small { max-width: 24em; }
|
package/lib/public/index.html
CHANGED
|
@@ -27,9 +27,12 @@
|
|
|
27
27
|
is lazy-loaded by terminal-prefs.js the first time the user selects
|
|
28
28
|
it (or boots with it already saved). See ensureD2CodingWebfont(). -->
|
|
29
29
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/css/xterm.min.css">
|
|
30
|
-
<script>
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
<script src="appearance-bootstrap.js"></script>
|
|
31
|
+
<style>
|
|
32
|
+
html { background: #171715; color: #e8e8e2; }
|
|
33
|
+
html.light-theme { background: #f7f7f3; color: #252522; }
|
|
34
|
+
body { background: transparent; color: inherit; }
|
|
35
|
+
</style>
|
|
33
36
|
<script>if(window.navigator.standalone||window.matchMedia("(display-mode:standalone)").matches){document.documentElement.classList.add("pwa-standalone")}</script>
|
|
34
37
|
<link rel="stylesheet" href="style.css?v=20260913-scheduled-tasks4">
|
|
35
38
|
<link rel="stylesheet" href="css/default-ai.css">
|
|
@@ -83,7 +86,10 @@
|
|
|
83
86
|
<!-- === Icon Strip === -->
|
|
84
87
|
<div id="icon-strip">
|
|
85
88
|
<button type="button" class="icon-strip-home icon-strip-brand" aria-label="Open Clay" disabled>
|
|
86
|
-
<
|
|
89
|
+
<span class="clay-brand-flip" aria-hidden="true">
|
|
90
|
+
<img class="icon-strip-logo clay-brand-face clay-brand-logo" src="clay-studio-symbol.png" width="38" height="38" alt="">
|
|
91
|
+
<img class="clay-brand-face clay-brand-avatar" width="38" height="38" alt="">
|
|
92
|
+
</span>
|
|
87
93
|
</button>
|
|
88
94
|
<div class="icon-strip-separator"></div>
|
|
89
95
|
<button type="button" class="icon-strip-hint" id="icon-strip-hint-project" data-switcher-mode="project" aria-label="Switch project"></button>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|