clay-server 4.0.0-beta.7 → 4.0.0-beta.8

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.
@@ -63,7 +63,8 @@ function looksLikeLoginSuccess(text) {
63
63
  * sm, tm, adapters,
64
64
  * send, sendTo,
65
65
  * usersModule,
66
- * getOsUserInfoForWs, getOsUserInfoForLinuxUser, getLinuxUserForSession
66
+ * getOsUserInfoForWs, getOsUserInfoForLinuxUser, getLinuxUserForSession,
67
+ * refreshVendorAuthEverywhere
67
68
  */
68
69
  function attachVendorLogin(ctx) {
69
70
  var slug = ctx.slug;
@@ -81,6 +82,7 @@ function attachVendorLogin(ctx) {
81
82
  var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
82
83
  var getOsUserInfoForLinuxUser = ctx.getOsUserInfoForLinuxUser;
83
84
  var getLinuxUserForSession = ctx.getLinuxUserForSession;
85
+ var refreshVendorAuthEverywhere = ctx.refreshVendorAuthEverywhere;
84
86
 
85
87
  // vendor -> flow record. At most one live login terminal per vendor.
86
88
  var _flows = Object.create(null);
@@ -182,13 +184,17 @@ function attachVendorLogin(ctx) {
182
184
  // the credentials the login just wrote. Shared adapter instances (Claude) are
183
185
  // reused by every project, so tearing one down here would kill unrelated
184
186
  // sessions; those runtimes pick up new credentials on their own.
185
- function refreshVendorAuth(vendor) {
187
+ function refreshVendorAuth(vendor, linuxUser) {
186
188
  var adapter = adapters[vendor];
187
189
  if (!adapter || typeof adapter.shutdown !== "function") return Promise.resolve(false);
188
190
  if (adapter.shared) {
189
191
  console.log("[vendor-login] " + vendor + " adapter is shared; skipping restart for " + slug);
190
192
  return Promise.resolve(false);
191
193
  }
194
+ if (typeof adapter.refreshAuthIdentity === "function") {
195
+ return Promise.resolve(adapter.refreshAuthIdentity(linuxUser || null));
196
+ }
197
+ if (linuxUser) return Promise.resolve(false);
192
198
  // adapter.shutdown() already fans out to every per-OS-user runtime it
193
199
  // created (shutdownUserRuntimes), so one call covers isolated setups too.
194
200
  return Promise.resolve()
@@ -214,7 +220,12 @@ function attachVendorLogin(ctx) {
214
220
  // result. Re-check before restarting the runtime, which will then read
215
221
  // the newly written credential file.
216
222
  if (succeeded) yoke.invalidateAuthCache();
217
- var refresh = succeeded ? refreshVendorAuth(vendor) : Promise.resolve(false);
223
+ var refresh = Promise.resolve(false);
224
+ if (succeeded) {
225
+ refresh = typeof refreshVendorAuthEverywhere === "function"
226
+ ? refreshVendorAuthEverywhere(vendor, flow.linuxUser || null)
227
+ : refreshVendorAuth(vendor, flow.linuxUser || null);
228
+ }
218
229
  refresh.then(function (restarted) {
219
230
  discardFlow(vendor);
220
231
  closeFlowTerminal(flow);
@@ -396,6 +407,7 @@ function attachVendorLogin(ctx) {
396
407
  listFlows: listFlows,
397
408
  forgetTerminal: forgetTerminal,
398
409
  isLoginTerminal: isLoginTerminal,
410
+ refreshVendorAuth: refreshVendorAuth,
399
411
  };
400
412
  }
401
413
 
package/lib/project.js CHANGED
@@ -1610,6 +1610,7 @@ function createProjectContext(opts) {
1610
1610
  getOsUserInfoForWs: getOsUserInfoForWs,
1611
1611
  getOsUserInfoForLinuxUser: getOsUserInfoForLinuxUser,
1612
1612
  getLinuxUserForSession: getLinuxUserForSession,
1613
+ refreshVendorAuthEverywhere: opts.refreshVendorAuthEverywhere,
1613
1614
  });
1614
1615
 
1615
1616
  // --- Filesystem handler (delegated to project-filesystem.js) ---
@@ -2141,6 +2142,7 @@ function createProjectContext(opts) {
2141
2142
  listKnowledgeFiles: _knowledge.listKnowledgeFiles,
2142
2143
  refreshCapsuleCatalog: _capsuleCatalog.refreshSessions,
2143
2144
  getNotificationsModule: function () { return _notifications; },
2145
+ refreshVendorAuth: _vendorLogin.refreshVendorAuth,
2144
2146
  getSchedules: _loop.getSchedules,
2145
2147
  importSchedule: _loop.importSchedule,
2146
2148
  removeSchedule: _loop.removeSchedule,
package/lib/server.js CHANGED
@@ -1155,6 +1155,24 @@ function createServer(opts) {
1155
1155
  }
1156
1156
 
1157
1157
  // --- Project management ---
1158
+ function refreshVendorAuthEverywhere(vendor, linuxUser) {
1159
+ var refreshes = [];
1160
+ projects.forEach(function (projectCtx) {
1161
+ if (!projectCtx || typeof projectCtx.refreshVendorAuth !== "function") return;
1162
+ try {
1163
+ refreshes.push(Promise.resolve(projectCtx.refreshVendorAuth(vendor, linuxUser)).catch(function (err) {
1164
+ console.error("[server] Cross-project " + vendor + " auth refresh failed:", err && err.message ? err.message : err);
1165
+ return false;
1166
+ }));
1167
+ } catch (err) {
1168
+ console.error("[server] Cross-project " + vendor + " auth refresh threw:", err && err.message ? err.message : err);
1169
+ }
1170
+ });
1171
+ return Promise.all(refreshes).then(function (results) {
1172
+ return results.some(function (refreshed) { return !!refreshed; });
1173
+ });
1174
+ }
1175
+
1158
1176
  function addProject(cwd, slug, title, icon, projectOwnerId, worktreeMeta, extraOpts) {
1159
1177
  if (projects.has(slug)) return false;
1160
1178
  var extra = extraOpts || {};
@@ -1327,6 +1345,7 @@ function createServer(opts) {
1327
1345
  onDmMessage: handleDmMessage,
1328
1346
  broadcastAll: broadcastAll,
1329
1347
  notificationsModule: _globalNotifications,
1348
+ refreshVendorAuthEverywhere: refreshVendorAuthEverywhere,
1330
1349
  getProject: function (s) { return projects.get(s) || null; },
1331
1350
  isUserOnline: isUserOnline,
1332
1351
  });
@@ -1943,6 +1943,23 @@ function createCodexAdapter(opts) {
1943
1943
  ]).then(function() { return true; });
1944
1944
  },
1945
1945
 
1946
+ // A device login writes credentials for one OS identity. Refresh only
1947
+ // that identity in OS-isolated deployments; single-user projects restart
1948
+ // their sole app-server.
1949
+ refreshAuthIdentity: function(linuxUser) {
1950
+ if (!_runtimeLinuxUser && linuxUser) {
1951
+ var userRuntime = _userRuntimes[linuxUser];
1952
+ if (!userRuntime) return Promise.resolve(false);
1953
+ return userRuntime.shutdown().then(function() {
1954
+ delete _userRuntimes[linuxUser];
1955
+ return true;
1956
+ });
1957
+ }
1958
+ if (_runtimeLinuxUser && linuxUser !== _runtimeLinuxUser) return Promise.resolve(false);
1959
+ if (_requiresLinuxUser) return Promise.resolve(false);
1960
+ return adapter.shutdown();
1961
+ },
1962
+
1946
1963
  shutdownIfIdle: function(idleMs) {
1947
1964
  if (!_runtimeLinuxUser && Object.keys(_userRuntimes).length > 0) {
1948
1965
  return shutdownUserRuntimes("shutdownIfIdle", idleMs).then(function(results) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "4.0.0-beta.7",
3
+ "version": "4.0.0-beta.8",
4
4
  "description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",