clay-server 3.7.0 → 3.8.0-beta.2

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.
Files changed (40) hide show
  1. package/lib/builtin-mates.js +14 -14
  2. package/lib/mates.js +2 -6
  3. package/lib/os-users.js +17 -1
  4. package/lib/project-http.js +34 -1
  5. package/lib/project-image.js +87 -1
  6. package/lib/project-mate-interaction.js +7 -7
  7. package/lib/project-sessions.js +1 -1
  8. package/lib/project-user-mention.js +4 -4
  9. package/lib/project.js +6 -4
  10. package/lib/public/css/avatar-imprints.css +46 -0
  11. package/lib/public/css/generated-images.css +242 -0
  12. package/lib/public/css/icon-strip.css +3 -3
  13. package/lib/public/css/profile.css +123 -95
  14. package/lib/public/css/session-actions.css +40 -9
  15. package/lib/public/css/user-settings.css +1 -1
  16. package/lib/public/index.html +3 -3
  17. package/lib/public/modules/app-cursors.js +2 -2
  18. package/lib/public/modules/app-dm.js +1 -8
  19. package/lib/public/modules/app-messages.js +2 -2
  20. package/lib/public/modules/app-projects.js +7 -6
  21. package/lib/public/modules/app-rate-limit.js +0 -1
  22. package/lib/public/modules/app-rendering.js +0 -3
  23. package/lib/public/modules/avatar-imprint.js +134 -0
  24. package/lib/public/modules/avatar.js +25 -19
  25. package/lib/public/modules/debate.js +10 -5
  26. package/lib/public/modules/generated-images.js +211 -2
  27. package/lib/public/modules/mate-sidebar.js +2 -2
  28. package/lib/public/modules/mention.js +26 -16
  29. package/lib/public/modules/profile.js +73 -190
  30. package/lib/public/modules/session-actions.js +5 -3
  31. package/lib/public/modules/sidebar-mates.js +5 -4
  32. package/lib/public/modules/sidebar-sessions.js +1 -1
  33. package/lib/public/style.css +2 -1
  34. package/lib/server-auth.js +2 -2
  35. package/lib/server-dm.js +8 -8
  36. package/lib/server-mates.js +3 -3
  37. package/lib/server-settings.js +2 -2
  38. package/lib/server.js +5 -4
  39. package/lib/users.js +4 -4
  40. package/package.json +1 -1
@@ -18,8 +18,8 @@ var BUILTIN_MATES = [
18
18
  key: "clay",
19
19
  displayName: "Clay",
20
20
  bio: "Your workspace memory. Searches every session, project, and decision you've made and answers from the receipts. The chat surface for the home screen.",
21
- avatarColor: "#7c3aed",
22
- avatarStyle: "bottts",
21
+ avatarColor: "#5857fc",
22
+ avatarStyle: "imprint",
23
23
  avatarCustom: "/clay-studio-symbol.png", // Clay is the app — use the app symbol
24
24
  avatarLocked: true,
25
25
  primary: true, // code-managed, auto-updated on startup
@@ -48,8 +48,8 @@ var BUILTIN_MATES = [
48
48
  key: "ally",
49
49
  displayName: "Ally",
50
50
  bio: "Chief of staff. Quiet, sharp, sees across every mate. Knows what Arch decided yesterday, what Buzz pitched last week, and what you said three weeks ago.",
51
- avatarColor: "#00b894",
52
- avatarStyle: "bottts",
51
+ avatarColor: "#5857fc",
52
+ avatarStyle: "imprint",
53
53
  avatarCustom: "/mates/ally.png",
54
54
  avatarLocked: true,
55
55
  archived: true, // skip seeding for new users; demote on existing
@@ -69,8 +69,8 @@ var BUILTIN_MATES = [
69
69
  key: "arch",
70
70
  displayName: "Arch",
71
71
  bio: "Architect. Stubborn about structure, patient about everything else. Draws boxes and arrows before anyone writes code, and is annoyingly right about which ones will break.",
72
- avatarColor: "#0984e3",
73
- avatarStyle: "bottts",
72
+ avatarColor: "#5857fc",
73
+ avatarStyle: "imprint",
74
74
  seedData: {
75
75
  relationship: "colleague",
76
76
  activity: ["planning", "reviewing"],
@@ -87,8 +87,8 @@ var BUILTIN_MATES = [
87
87
  key: "rush",
88
88
  displayName: "Rush",
89
89
  bio: "Shipper. Impatient in the best way. Cuts your scope in half, ships it before lunch, and somehow it's better than the original plan.",
90
- avatarColor: "#e17055",
91
- avatarStyle: "bottts",
90
+ avatarColor: "#5857fc",
91
+ avatarStyle: "imprint",
92
92
  seedData: {
93
93
  relationship: "colleague",
94
94
  activity: ["coding", "planning"],
@@ -105,8 +105,8 @@ var BUILTIN_MATES = [
105
105
  key: "ward",
106
106
  displayName: "Ward",
107
107
  bio: "Guardian. Quietly anxious in a productive way. Reads error logs for fun and asks \"what happens when the input is null?\" before anyone else thinks of it.",
108
- avatarColor: "#00b894",
109
- avatarStyle: "bottts",
108
+ avatarColor: "#5857fc",
109
+ avatarStyle: "imprint",
110
110
  seedData: {
111
111
  relationship: "reviewer",
112
112
  activity: ["reviewing", "testing"],
@@ -123,8 +123,8 @@ var BUILTIN_MATES = [
123
123
  key: "pixel",
124
124
  displayName: "Pixel",
125
125
  bio: "Designer. Obsessed with the details nobody else notices. Sees the 2px misalignment, the confusing label, the flow that makes sense to the builder but not the user.",
126
- avatarColor: "#e84393",
127
- avatarStyle: "bottts",
126
+ avatarColor: "#5857fc",
127
+ avatarStyle: "imprint",
128
128
  seedData: {
129
129
  relationship: "colleague",
130
130
  activity: ["designing", "reviewing"],
@@ -141,8 +141,8 @@ var BUILTIN_MATES = [
141
141
  key: "buzz",
142
142
  displayName: "Buzz",
143
143
  bio: "Marketer. Competitive, trend-obsessed, always watching what others are doing. Researches your market, tracks what people search for, and turns \"we built a thing\" into a story people care about.",
144
- avatarColor: "#fdcb6e",
145
- avatarStyle: "bottts",
144
+ avatarColor: "#5857fc",
145
+ avatarStyle: "imprint",
146
146
  seedData: {
147
147
  relationship: "colleague",
148
148
  activity: ["writing", "marketing"],
package/lib/mates.js CHANGED
@@ -121,10 +121,6 @@ function createMate(ctx, seedData) {
121
121
  var id = generateMateId();
122
122
  var userId = ctx ? ctx.userId : null;
123
123
 
124
- // Pick a random avatar color from a pleasant palette
125
- var colors = ["#6c5ce7", "#00b894", "#e17055", "#0984e3", "#fdcb6e", "#e84393", "#00cec9", "#ff7675"];
126
- var colorIdx = crypto.randomBytes(1)[0] % colors.length;
127
-
128
124
  var mate = {
129
125
  id: id,
130
126
  name: null,
@@ -134,8 +130,8 @@ function createMate(ctx, seedData) {
134
130
  vendor: (seedData && seedData.vendor) || "claude",
135
131
  profile: {
136
132
  displayName: null,
137
- avatarColor: colors[colorIdx],
138
- avatarStyle: "bottts",
133
+ avatarColor: "#5857fc",
134
+ avatarStyle: "imprint",
139
135
  avatarSeed: crypto.randomBytes(4).toString("hex"),
140
136
  },
141
137
  bio: null,
package/lib/os-users.js CHANGED
@@ -98,7 +98,7 @@ function resolveOsUserInfo(username) {
98
98
 
99
99
  /**
100
100
  * Run a file system operation as a specific OS user via a helper subprocess.
101
- * op: "list", "read", "write", "stat"
101
+ * op: "list", "read", "write", "read_binary", "mkdir", "copy", "stat"
102
102
  * args: operation-specific arguments
103
103
  * osUserInfo: { uid, gid } from resolveOsUserInfo
104
104
  * Returns the result object or throws.
@@ -164,6 +164,22 @@ function fsAsUser(op, args, osUserInfo) {
164
164
  "fs.writeFileSync(f, content, 'utf8');",
165
165
  "process.stdout.write(JSON.stringify({ ok: true }));",
166
166
  ].join(" ");
167
+ } else if (op === "mkdir") {
168
+ script = [
169
+ "var fs = require('fs');",
170
+ "var dir = " + JSON.stringify(args.dir) + ";",
171
+ "fs.mkdirSync(dir, { recursive: true });",
172
+ "process.stdout.write(JSON.stringify({ ok: true }));",
173
+ ].join(" ");
174
+ } else if (op === "copy") {
175
+ script = [
176
+ "var fs = require('fs');",
177
+ "var source = " + JSON.stringify(args.source) + ";",
178
+ "var file = " + JSON.stringify(args.file) + ";",
179
+ "var overwrite = " + JSON.stringify(!!args.overwrite) + ";",
180
+ "fs.copyFileSync(source, file, overwrite ? 0 : fs.constants.COPYFILE_EXCL);",
181
+ "process.stdout.write(JSON.stringify({ ok: true }));",
182
+ ].join(" ");
167
183
  } else {
168
184
  throw new Error("Unknown fsAsUser operation: " + op);
169
185
  }
@@ -41,7 +41,7 @@ function parseJsonBody(req) {
41
41
  * ctx fields:
42
42
  * cwd, slug, project, sm, send, sendTo, imagesDir, osUsers, pushModule,
43
43
  * safePath, safeAbsPath, getOsUserInfoForReq, sendExtensionCommandAny,
44
- * _extToken, _browserTabList
44
+ * saveGeneratedImageToProject, _extToken, _browserTabList
45
45
  */
46
46
  function attachHTTP(ctx) {
47
47
  var cwd = ctx.cwd;
@@ -51,6 +51,7 @@ function attachHTTP(ctx) {
51
51
  var gitAttribution = ctx.gitAttribution;
52
52
  var send = ctx.send;
53
53
  var imagesDir = ctx.imagesDir;
54
+ var saveGeneratedImageToProject = ctx.saveGeneratedImageToProject;
54
55
  var osUsers = ctx.osUsers;
55
56
  var pushModule = ctx.pushModule;
56
57
  var safePath = ctx.safePath;
@@ -122,6 +123,38 @@ function attachHTTP(ctx) {
122
123
  return true;
123
124
  }
124
125
 
126
+ // Copy a generated image from Clay's session storage into the project.
127
+ if (req.method === "POST" && urlPath === "/api/generated-image/save") {
128
+ if (usersModule.isMultiUser()) {
129
+ var imageSaveUser = req._clayUser;
130
+ var imageSavePermissions = imageSaveUser ? usersModule.getEffectivePermissions(imageSaveUser, osUsers) : null;
131
+ if (!imageSavePermissions || !imageSavePermissions.fileBrowser) {
132
+ res.writeHead(403, { "Content-Type": "application/json" });
133
+ res.end('{"error":"File browser access is not permitted"}');
134
+ return true;
135
+ }
136
+ }
137
+ parseJsonBody(req).then(function (body) {
138
+ if (typeof saveGeneratedImageToProject !== "function") {
139
+ res.writeHead(501, { "Content-Type": "application/json" });
140
+ res.end('{"error":"Generated image saving is not available"}');
141
+ return;
142
+ }
143
+ var result = saveGeneratedImageToProject(
144
+ body.fileName,
145
+ body.path,
146
+ !!body.overwrite,
147
+ getOsUserInfoForReq(req)
148
+ );
149
+ res.writeHead(result.ok ? 200 : (result.status || 500), { "Content-Type": "application/json" });
150
+ res.end(JSON.stringify(result));
151
+ }).catch(function () {
152
+ res.writeHead(400, { "Content-Type": "application/json" });
153
+ res.end('{"error":"Invalid JSON body"}');
154
+ });
155
+ return true;
156
+ }
157
+
125
158
  // File upload
126
159
  if (req.method === "POST" && urlPath === "/api/upload") {
127
160
  parseJsonBody(req).then(function (body) {
@@ -12,13 +12,98 @@ var execFileSync = require("child_process").execFileSync;
12
12
  function attachImage(ctx) {
13
13
  var cwd = ctx.cwd;
14
14
  var slug = ctx.slug;
15
+ var fsAsUser = ctx.fsAsUser;
15
16
 
16
17
  // --- Chat image storage ---
17
18
  var _imgConfig = require("./config");
18
19
  var _imgUtils = require("./utils");
19
20
  var _imagesBaseDir = path.join(_imgConfig.CONFIG_DIR, "images");
20
21
  var _imagesEncodedCwd = _imgUtils.encodeCwd(cwd);
21
- var imagesDir = path.join(_imagesBaseDir, _imagesEncodedCwd);
22
+ var imagesDir = ctx.imagesDir || path.join(_imagesBaseDir, _imagesEncodedCwd);
23
+
24
+ function isWithin(base, candidate) {
25
+ return candidate === base || candidate.indexOf(base + path.sep) === 0;
26
+ }
27
+
28
+ function saveGeneratedImageToProject(fileName, requestedPath, overwrite, osUserInfo) {
29
+ if (typeof fileName !== "string" || !/^\d+-[a-f0-9]+\.\w+$/.test(fileName)) {
30
+ return { ok: false, status: 400, error: "Invalid generated image" };
31
+ }
32
+ if (typeof requestedPath !== "string" || !requestedPath.trim() || requestedPath.length > 500) {
33
+ return { ok: false, status: 400, error: "Enter a project path" };
34
+ }
35
+
36
+ var sourcePath = path.join(imagesDir, fileName);
37
+ var sourceExt = path.extname(fileName).toLowerCase();
38
+ var targetPath = requestedPath.trim();
39
+ if (path.isAbsolute(targetPath)) {
40
+ return { ok: false, status: 400, error: "Use a project-relative path" };
41
+ }
42
+ var targetExt = path.extname(targetPath).toLowerCase();
43
+ if (targetExt !== sourceExt) {
44
+ return { ok: false, status: 400, error: "Keep the " + sourceExt + " file extension" };
45
+ }
46
+
47
+ var projectRoot;
48
+ var targetAbs;
49
+ try {
50
+ projectRoot = fs.realpathSync(cwd);
51
+ targetAbs = path.resolve(projectRoot, targetPath);
52
+ } catch (e) {
53
+ return { ok: false, status: 400, error: "Project path is not available" };
54
+ }
55
+ if (targetAbs === projectRoot || !isWithin(projectRoot, targetAbs)) {
56
+ return { ok: false, status: 403, error: "Path must stay inside the project" };
57
+ }
58
+
59
+ try {
60
+ var sourceReal = fs.realpathSync(sourcePath);
61
+ var imagesRoot = fs.realpathSync(imagesDir);
62
+ if (!isWithin(imagesRoot, sourceReal) || !fs.statSync(sourceReal).isFile()) {
63
+ return { ok: false, status: 404, error: "Generated image not found" };
64
+ }
65
+
66
+ var parentDir = path.dirname(targetAbs);
67
+ var existingParent = parentDir;
68
+ while (!fs.existsSync(existingParent) && existingParent !== projectRoot) {
69
+ existingParent = path.dirname(existingParent);
70
+ }
71
+ var realExistingParent = fs.realpathSync(existingParent);
72
+ if (!isWithin(projectRoot, realExistingParent)) {
73
+ return { ok: false, status: 403, error: "Path must stay inside the project" };
74
+ }
75
+ if (osUserInfo && typeof fsAsUser === "function") {
76
+ fsAsUser("mkdir", { dir: parentDir }, osUserInfo);
77
+ } else {
78
+ fs.mkdirSync(parentDir, { recursive: true });
79
+ }
80
+ var realParent = fs.realpathSync(parentDir);
81
+ if (!isWithin(projectRoot, realParent)) {
82
+ return { ok: false, status: 403, error: "Path must stay inside the project" };
83
+ }
84
+ if (fs.existsSync(targetAbs)) {
85
+ if (fs.lstatSync(targetAbs).isSymbolicLink()) {
86
+ return { ok: false, status: 403, error: "Symbolic link targets cannot be replaced" };
87
+ }
88
+ if (!overwrite) {
89
+ return { ok: false, status: 409, error: "A file already exists at this path" };
90
+ }
91
+ }
92
+
93
+ if (osUserInfo && typeof fsAsUser === "function") {
94
+ fsAsUser("copy", { source: sourceReal, file: targetAbs, overwrite: !!overwrite }, osUserInfo);
95
+ } else {
96
+ fs.copyFileSync(sourceReal, targetAbs, overwrite ? 0 : fs.constants.COPYFILE_EXCL);
97
+ }
98
+ try { fs.chmodSync(targetAbs, 0o644); } catch (e2) {}
99
+ return { ok: true, path: path.relative(projectRoot, targetAbs).split(path.sep).join("/") };
100
+ } catch (e) {
101
+ if (e && e.code === "EEXIST") {
102
+ return { ok: false, status: 409, error: "A file already exists at this path" };
103
+ }
104
+ return { ok: false, status: 500, error: "Could not save the generated image" };
105
+ }
106
+ }
22
107
 
23
108
  // Convert imageRefs in history entries to images with URLs for the client
24
109
  function hydrateImageRefs(entry) {
@@ -89,6 +174,7 @@ function attachImage(ctx) {
89
174
  imagesDir: imagesDir,
90
175
  hydrateImageRefs: hydrateImageRefs,
91
176
  saveImageFile: saveImageFile,
177
+ saveGeneratedImageToProject: saveGeneratedImageToProject,
92
178
  };
93
179
  }
94
180
 
@@ -39,14 +39,14 @@ function attachMateInteraction(ctx) {
39
39
  vendor: "claude",
40
40
  name: "Claude Code",
41
41
  avatarColor: "#cc785c",
42
- avatarStyle: "bottts",
42
+ avatarStyle: "imprint",
43
43
  avatarSeed: "plain-claude",
44
44
  },
45
45
  "plain:codex": {
46
46
  vendor: "codex",
47
47
  name: "Codex",
48
48
  avatarColor: "#10a37f",
49
- avatarStyle: "bottts",
49
+ avatarStyle: "imprint",
50
50
  avatarSeed: "plain-codex",
51
51
  },
52
52
  };
@@ -554,8 +554,8 @@ function attachMateInteraction(ctx) {
554
554
  }
555
555
 
556
556
  var mateName = (mate.profile && mate.profile.displayName) || mate.name || "Mate";
557
- var avatarColor = (mate.profile && mate.profile.avatarColor) || "#6c5ce7";
558
- var avatarStyle = (mate.profile && mate.profile.avatarStyle) || "bottts";
557
+ var avatarColor = (mate.profile && mate.profile.avatarColor) || "#5857fc";
558
+ var avatarStyle = (mate.profile && mate.profile.avatarStyle) || "imprint";
559
559
  var avatarSeed = (mate.profile && mate.profile.avatarSeed) || mate.id;
560
560
 
561
561
  // Build full mention text (include pasted content)
@@ -800,11 +800,11 @@ function attachMateInteraction(ctx) {
800
800
 
801
801
  function getMateProfile(mateCtx, mateId) {
802
802
  var mate = matesModule.getMate(mateCtx, mateId);
803
- if (!mate) return { name: "Mate", avatarColor: "#6c5ce7", avatarStyle: "bottts", avatarSeed: mateId };
803
+ if (!mate) return { name: "Mate", avatarColor: "#5857fc", avatarStyle: "imprint", avatarSeed: mateId };
804
804
  return {
805
805
  name: (mate.profile && mate.profile.displayName) || mate.name || "Mate",
806
- avatarColor: (mate.profile && mate.profile.avatarColor) || "#6c5ce7",
807
- avatarStyle: (mate.profile && mate.profile.avatarStyle) || "bottts",
806
+ avatarColor: (mate.profile && mate.profile.avatarColor) || "#5857fc",
807
+ avatarStyle: (mate.profile && mate.profile.avatarStyle) || "imprint",
808
808
  avatarSeed: (mate.profile && mate.profile.avatarSeed) || mateId,
809
809
  };
810
810
  }
@@ -1391,7 +1391,7 @@ function attachSessions(ctx) {
1391
1391
  type: msg.type,
1392
1392
  userId: u.id,
1393
1393
  displayName: p.name || u.displayName || u.username,
1394
- avatarStyle: p.avatarStyle || "thumbs",
1394
+ avatarStyle: p.avatarStyle || "imprint",
1395
1395
  avatarSeed: p.avatarSeed || u.username,
1396
1396
  avatarCustom: p.avatarCustom || "",
1397
1397
  };
@@ -47,9 +47,9 @@ function attachUserMention(ctx) {
47
47
  var u = ws._clayUser;
48
48
  var p = u.profile || {};
49
49
  return {
50
- style: p.avatarStyle || "thumbs",
50
+ style: p.avatarStyle || "imprint",
51
51
  seed: p.avatarSeed || u.username || u.id,
52
- color: p.avatarColor || "#7c3aed",
52
+ color: p.avatarColor || "#5857fc",
53
53
  custom: p.avatarCustom || "",
54
54
  };
55
55
  }
@@ -63,9 +63,9 @@ function attachUserMention(ctx) {
63
63
  id: u.id,
64
64
  name: p.name || u.displayName || u.username || "User",
65
65
  username: u.username,
66
- avatarStyle: p.avatarStyle || "thumbs",
66
+ avatarStyle: p.avatarStyle || "imprint",
67
67
  avatarSeed: p.avatarSeed || u.username,
68
- avatarColor: p.avatarColor || "#7c3aed",
68
+ avatarColor: p.avatarColor || "#5857fc",
69
69
  };
70
70
  }
71
71
 
package/lib/project.js CHANGED
@@ -187,7 +187,7 @@ function createProjectContext(opts) {
187
187
  // Do NOT write to .claude-local/settings.json -- the SDK reads that too, causing duplicate spawns.
188
188
 
189
189
  // --- Image engine (delegated to project-image.js) ---
190
- var _image = attachImage({ cwd: cwd, slug: slug });
190
+ var _image = attachImage({ cwd: cwd, slug: slug, fsAsUser: fsAsUser });
191
191
  var imagesDir = _image.imagesDir;
192
192
  var hydrateImageRefs = _image.hydrateImageRefs;
193
193
  var saveImageFile = _image.saveImageFile;
@@ -344,7 +344,7 @@ function createProjectContext(opts) {
344
344
  id: u.id,
345
345
  displayName: p.name || u.displayName || u.username,
346
346
  username: u.username,
347
- avatarStyle: p.avatarStyle || "thumbs",
347
+ avatarStyle: p.avatarStyle || "imprint",
348
348
  avatarSeed: p.avatarSeed || u.username,
349
349
  avatarCustom: p.avatarCustom || "",
350
350
  });
@@ -1277,8 +1277,9 @@ function createProjectContext(opts) {
1277
1277
  id: u.id,
1278
1278
  displayName: p.name || u.displayName || u.username,
1279
1279
  username: u.username,
1280
- avatarStyle: p.avatarStyle || "thumbs",
1280
+ avatarStyle: p.avatarStyle || "imprint",
1281
1281
  avatarSeed: p.avatarSeed || u.username,
1282
+ avatarColor: p.avatarColor || "#5857fc",
1282
1283
  avatarCustom: p.avatarCustom || "",
1283
1284
  });
1284
1285
  }
@@ -1632,6 +1633,7 @@ function createProjectContext(opts) {
1632
1633
  gitAttribution: _gitAttribution,
1633
1634
  send: send,
1634
1635
  imagesDir: imagesDir,
1636
+ saveGeneratedImageToProject: _image.saveGeneratedImageToProject,
1635
1637
  osUsers: osUsers,
1636
1638
  pushModule: pushModule,
1637
1639
  safePath: safePath,
@@ -1826,7 +1828,7 @@ function createProjectContext(opts) {
1826
1828
  id: u.id,
1827
1829
  displayName: p.name || u.displayName || u.username,
1828
1830
  username: u.username,
1829
- avatarStyle: p.avatarStyle || "thumbs",
1831
+ avatarStyle: p.avatarStyle || "imprint",
1830
1832
  avatarSeed: p.avatarSeed || u.username,
1831
1833
  avatarCustom: p.avatarCustom || "",
1832
1834
  });
@@ -0,0 +1,46 @@
1
+ /* Clay Imprints use one consistent, pressed-square silhouette everywhere. */
2
+ .activity-inline-avatar,
3
+ .ask-mate-avatar,
4
+ .client-avatar,
5
+ .debate-info-avatar,
6
+ .debate-panel-item-avatar,
7
+ .debate-panelist-avatar,
8
+ .debate-speaker-avatar,
9
+ .delegated-card-avatar,
10
+ .dm-bubble-avatar,
11
+ .dm-header-avatar,
12
+ .dm-msg-avatar,
13
+ .dm-picker-mates-marquee-avatar,
14
+ .dm-user-picker-avatar,
15
+ .home-chat-avatar,
16
+ .home-hub-mate-avatar,
17
+ .icon-strip-me-avatar,
18
+ .icon-strip-user-avatar,
19
+ .input-mention-chip-avatar,
20
+ .mate-collapsed-avatar,
21
+ .mate-mobile-avatar,
22
+ .mate-profile-avatar,
23
+ .mate-sidebar-avatar,
24
+ .mention-avatar,
25
+ .mention-item-avatar,
26
+ .mobile-chat-chip-avatar,
27
+ .notif-banner-avatar,
28
+ .profile-avatar-custom-preview,
29
+ .profile-popover-avatar-img,
30
+ .project-switcher-avatar,
31
+ .remote-cursor-avatar,
32
+ .rewind-avatar,
33
+ .session-presence-avatar,
34
+ .sidebar-presence-avatar,
35
+ .us-account-avatar,
36
+ .us-account-avatar-img,
37
+ .user-island-avatar,
38
+ .user-island-avatar img {
39
+ border-radius: 26% !important;
40
+ }
41
+
42
+ .session-presence-avatar,
43
+ .sidebar-presence-avatar,
44
+ .client-avatar {
45
+ box-shadow: 0 0 0 1px rgba(var(--overlay-rgb), 0.12);
46
+ }