clay-server 2.9.1 → 2.9.3-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +47 -30
- package/lib/project.js +64 -37
- package/lib/public/app.js +3 -2
- package/lib/public/css/menus.css +1 -4
- package/lib/public/index.html +1 -1
- package/lib/sdk-bridge.js +4 -6
- package/package.json +9 -2
package/bin/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ if (_isDev) process.env.CLAY_DEV = "1";
|
|
|
28
28
|
var { loadConfig, saveConfig, configPath, socketPath, logPath, ensureConfigDir, isDaemonAlive, isDaemonAliveAsync, generateSlug, clearStaleConfig, loadClayrc, saveClayrc, readCrashInfo } = require("../lib/config");
|
|
29
29
|
var { sendIPCCommand } = require("../lib/ipc");
|
|
30
30
|
var { generateAuthToken } = require("../lib/server");
|
|
31
|
-
var { enableMultiUser, hasAdmin, isMultiUser } = require("../lib/users");
|
|
31
|
+
var { enableMultiUser, disableMultiUser, hasAdmin, isMultiUser } = require("../lib/users");
|
|
32
32
|
|
|
33
33
|
function openUrl(url) {
|
|
34
34
|
try {
|
|
@@ -2319,7 +2319,7 @@ function showSettingsMenu(config, ip) {
|
|
|
2319
2319
|
items.push({ label: "Set PIN", value: "pin" });
|
|
2320
2320
|
}
|
|
2321
2321
|
if (muEnabled) {
|
|
2322
|
-
items.push({ label: "
|
|
2322
|
+
items.push({ label: "Disable multi-user mode", value: "disable_multi_user" });
|
|
2323
2323
|
} else {
|
|
2324
2324
|
items.push({ label: "Enable multi-user mode", value: "multi_user" });
|
|
2325
2325
|
}
|
|
@@ -2365,39 +2365,51 @@ function showSettingsMenu(config, ip) {
|
|
|
2365
2365
|
break;
|
|
2366
2366
|
|
|
2367
2367
|
case "multi_user":
|
|
2368
|
-
|
|
2368
|
+
var muResult = enableMultiUser();
|
|
2369
|
+
log(sym.bar);
|
|
2370
|
+
log(sym.bar + " " + a.yellow + sym.warn + " Experimental Feature" + a.reset);
|
|
2371
|
+
log(sym.bar);
|
|
2372
|
+
log(sym.bar + " " + a.dim + "Multi-user mode is experimental and may change in future releases." + a.reset);
|
|
2373
|
+
log(sym.bar + " " + a.dim + "Sharing access to AI-powered tools may be subject to your provider's" + a.reset);
|
|
2374
|
+
log(sym.bar + " " + a.dim + "terms of service. Please review the applicable usage policies before" + a.reset);
|
|
2375
|
+
log(sym.bar + " " + a.dim + "granting access to other users." + a.reset);
|
|
2376
|
+
log(sym.bar);
|
|
2377
|
+
if (muResult.setupCode) {
|
|
2378
|
+
log(sym.bar + " " + a.green + "Multi-user mode enabled." + a.reset);
|
|
2369
2379
|
log(sym.bar);
|
|
2370
|
-
log(sym.bar + " " + a.
|
|
2371
|
-
log(sym.bar + " " + a.dim + "No changes made." + a.reset);
|
|
2380
|
+
log(sym.bar + " Setup code: " + a.bold + muResult.setupCode + a.reset);
|
|
2372
2381
|
log(sym.bar);
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
});
|
|
2382
|
+
log(sym.bar + " " + a.dim + "Open Clay in your browser and enter this code to create the admin account." + a.reset);
|
|
2383
|
+
log(sym.bar + " " + a.dim + "The code is single-use and will be cleared once the admin is set up." + a.reset);
|
|
2376
2384
|
} else {
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2385
|
+
log(sym.bar + " " + a.dim + "Multi-user mode is already enabled." + a.reset);
|
|
2386
|
+
}
|
|
2387
|
+
log(sym.bar);
|
|
2388
|
+
promptSelect("Back?", [{ label: "Back", value: "back" }], function () {
|
|
2389
|
+
showSettingsMenu(config, ip);
|
|
2390
|
+
});
|
|
2391
|
+
break;
|
|
2392
|
+
|
|
2393
|
+
case "disable_multi_user":
|
|
2394
|
+
log(sym.bar);
|
|
2395
|
+
log(sym.bar + " " + a.yellow + sym.warn + " Disable multi-user mode?" + a.reset);
|
|
2396
|
+
log(sym.bar);
|
|
2397
|
+
log(sym.bar + " " + a.dim + "Sessions created by other users will no longer be visible." + a.reset);
|
|
2398
|
+
log(sym.bar + " " + a.dim + "User accounts will be preserved and restored if re-enabled." + a.reset);
|
|
2399
|
+
log(sym.bar);
|
|
2400
|
+
promptSelect("Confirm", [
|
|
2401
|
+
{ label: "Disable multi-user mode", value: "confirm" },
|
|
2402
|
+
{ label: "Cancel", value: "cancel" },
|
|
2403
|
+
], function (confirmChoice) {
|
|
2404
|
+
if (confirmChoice === "confirm") {
|
|
2405
|
+
disableMultiUser();
|
|
2388
2406
|
log(sym.bar);
|
|
2389
|
-
log(sym.
|
|
2407
|
+
log(sym.done + " " + a.green + "Multi-user mode disabled." + a.reset);
|
|
2408
|
+
log(sym.bar + " " + a.dim + "Restart the daemon for changes to take full effect." + a.reset);
|
|
2390
2409
|
log(sym.bar);
|
|
2391
|
-
log(sym.bar + " " + a.dim + "Open Clay in your browser and enter this code to create the admin account." + a.reset);
|
|
2392
|
-
log(sym.bar + " " + a.dim + "The code is single-use and will be cleared once the admin is set up." + a.reset);
|
|
2393
|
-
} else {
|
|
2394
|
-
log(sym.bar + " " + a.dim + "Multi-user mode is already enabled." + a.reset);
|
|
2395
2410
|
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
showSettingsMenu(config, ip);
|
|
2399
|
-
});
|
|
2400
|
-
}
|
|
2411
|
+
showSettingsMenu(config, ip);
|
|
2412
|
+
});
|
|
2401
2413
|
break;
|
|
2402
2414
|
|
|
2403
2415
|
case "logs":
|
|
@@ -2456,7 +2468,12 @@ var currentVersion = require("../package.json").version;
|
|
|
2456
2468
|
clearStaleConfig();
|
|
2457
2469
|
await new Promise(function (resolve) { setTimeout(resolve, 500); });
|
|
2458
2470
|
}
|
|
2459
|
-
//
|
|
2471
|
+
// No running daemon — clear config so setup runs fresh
|
|
2472
|
+
if (!devAlive && devConfig) {
|
|
2473
|
+
if (devConfig.pid) clearStaleConfig();
|
|
2474
|
+
devConfig = null;
|
|
2475
|
+
}
|
|
2476
|
+
// No config — go through setup (disclaimer, port, PIN, etc.)
|
|
2460
2477
|
if (!devConfig) {
|
|
2461
2478
|
setup(function (pin, keepAwake) {
|
|
2462
2479
|
devMode(pin, keepAwake, null);
|
package/lib/project.js
CHANGED
|
@@ -156,6 +156,15 @@ function createProjectContext(opts) {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
function sendToSession(sessionId, obj) {
|
|
160
|
+
var data = JSON.stringify(obj);
|
|
161
|
+
for (var ws of clients) {
|
|
162
|
+
if (ws.readyState === 1 && ws._clayActiveSession === sessionId) {
|
|
163
|
+
ws.send(data);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
159
168
|
function sendToSessionOthers(sender, sessionId, obj) {
|
|
160
169
|
var data = JSON.stringify(obj);
|
|
161
170
|
for (var ws of clients) {
|
|
@@ -712,7 +721,7 @@ function createProjectContext(opts) {
|
|
|
712
721
|
session.isProcessing = true;
|
|
713
722
|
onProcessingChanged();
|
|
714
723
|
session.sentToolResults = {};
|
|
715
|
-
|
|
724
|
+
sendToSession(session.localId, { type: "status", status: "processing" });
|
|
716
725
|
session.acceptEditsAfterStart = true;
|
|
717
726
|
session.singleTurn = true;
|
|
718
727
|
sdk.startQuery(session, loopState.promptText);
|
|
@@ -1025,12 +1034,14 @@ function createProjectContext(opts) {
|
|
|
1025
1034
|
});
|
|
1026
1035
|
}
|
|
1027
1036
|
|
|
1028
|
-
// Session list (filtered for
|
|
1037
|
+
// Session list (filtered for access control)
|
|
1029
1038
|
var allSessions = [].concat(Array.from(sm.sessions.values())).filter(function (s) { return !s.hidden; });
|
|
1030
1039
|
if (usersModule.isMultiUser() && wsUser) {
|
|
1031
1040
|
allSessions = allSessions.filter(function (s) {
|
|
1032
1041
|
return usersModule.canAccessSession(wsUser.id, s, { visibility: "public" });
|
|
1033
1042
|
});
|
|
1043
|
+
} else if (!usersModule.isMultiUser()) {
|
|
1044
|
+
allSessions = allSessions.filter(function (s) { return !s.ownerId; });
|
|
1034
1045
|
}
|
|
1035
1046
|
sendTo(ws, {
|
|
1036
1047
|
type: "session_list",
|
|
@@ -1057,12 +1068,23 @@ function createProjectContext(opts) {
|
|
|
1057
1068
|
}),
|
|
1058
1069
|
});
|
|
1059
1070
|
|
|
1060
|
-
// Restore active session for this client (check access
|
|
1071
|
+
// Restore active session for this client (check access)
|
|
1061
1072
|
var active = sm.getActiveSession();
|
|
1062
1073
|
if (active && usersModule.isMultiUser() && wsUser) {
|
|
1063
1074
|
if (!usersModule.canAccessSession(wsUser.id, active, { visibility: "public" })) {
|
|
1064
1075
|
active = null;
|
|
1065
1076
|
}
|
|
1077
|
+
} else if (active && !usersModule.isMultiUser() && active.ownerId) {
|
|
1078
|
+
active = null;
|
|
1079
|
+
}
|
|
1080
|
+
// Fallback: pick the most recent accessible session
|
|
1081
|
+
if (!active && allSessions.length > 0) {
|
|
1082
|
+
active = allSessions[0];
|
|
1083
|
+
for (var fi = 1; fi < allSessions.length; fi++) {
|
|
1084
|
+
if ((allSessions[fi].lastActivity || 0) > (active.lastActivity || 0)) {
|
|
1085
|
+
active = allSessions[fi];
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1066
1088
|
}
|
|
1067
1089
|
if (active) {
|
|
1068
1090
|
ws._clayActiveSession = active.localId;
|
|
@@ -1110,6 +1132,10 @@ function createProjectContext(opts) {
|
|
|
1110
1132
|
}
|
|
1111
1133
|
|
|
1112
1134
|
// --- WS message handler ---
|
|
1135
|
+
function getSessionForWs(ws) {
|
|
1136
|
+
return sm.sessions.get(ws._clayActiveSession) || null;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1113
1139
|
function handleMessage(ws, msg) {
|
|
1114
1140
|
if (msg.type === "push_subscribe") {
|
|
1115
1141
|
if (pushModule && msg.subscription) pushModule.addSubscription(msg.subscription, msg.replaceEndpoint);
|
|
@@ -1117,7 +1143,7 @@ function createProjectContext(opts) {
|
|
|
1117
1143
|
}
|
|
1118
1144
|
|
|
1119
1145
|
if (msg.type === "load_more_history") {
|
|
1120
|
-
var session =
|
|
1146
|
+
var session = getSessionForWs(ws);
|
|
1121
1147
|
if (!session || typeof msg.before !== "number") return;
|
|
1122
1148
|
var before = msg.before;
|
|
1123
1149
|
var from = sm.findTurnBoundary(session.history, Math.max(0, before - sm.HISTORY_PAGE_SIZE));
|
|
@@ -1135,9 +1161,9 @@ function createProjectContext(opts) {
|
|
|
1135
1161
|
var sessionOpts = {};
|
|
1136
1162
|
if (ws._clayUser) sessionOpts.ownerId = ws._clayUser.id;
|
|
1137
1163
|
if (msg.sessionVisibility) sessionOpts.sessionVisibility = msg.sessionVisibility;
|
|
1138
|
-
var newSess = sm.createSession(sessionOpts,
|
|
1164
|
+
var newSess = sm.createSession(sessionOpts, ws);
|
|
1165
|
+
ws._clayActiveSession = newSess.localId;
|
|
1139
1166
|
if (usersModule.isMultiUser()) {
|
|
1140
|
-
ws._clayActiveSession = newSess.localId;
|
|
1141
1167
|
broadcastPresence();
|
|
1142
1168
|
}
|
|
1143
1169
|
return;
|
|
@@ -1161,11 +1187,11 @@ function createProjectContext(opts) {
|
|
|
1161
1187
|
break;
|
|
1162
1188
|
}
|
|
1163
1189
|
}
|
|
1164
|
-
var
|
|
1165
|
-
|
|
1190
|
+
var resumed = sm.resumeSession(msg.cliSessionId, { history: history, title: title }, ws);
|
|
1191
|
+
if (resumed) ws._clayActiveSession = resumed.localId;
|
|
1166
1192
|
}).catch(function () {
|
|
1167
|
-
var
|
|
1168
|
-
|
|
1193
|
+
var resumed = sm.resumeSession(msg.cliSessionId, undefined, ws);
|
|
1194
|
+
if (resumed) ws._clayActiveSession = resumed.localId;
|
|
1169
1195
|
});
|
|
1170
1196
|
return;
|
|
1171
1197
|
}
|
|
@@ -1210,7 +1236,8 @@ function createProjectContext(opts) {
|
|
|
1210
1236
|
sm.switchSession(msg.id, ws);
|
|
1211
1237
|
broadcastPresence();
|
|
1212
1238
|
} else {
|
|
1213
|
-
|
|
1239
|
+
ws._clayActiveSession = msg.id;
|
|
1240
|
+
sm.switchSession(msg.id, ws);
|
|
1214
1241
|
}
|
|
1215
1242
|
}
|
|
1216
1243
|
return;
|
|
@@ -1218,7 +1245,7 @@ function createProjectContext(opts) {
|
|
|
1218
1245
|
|
|
1219
1246
|
if (msg.type === "delete_session") {
|
|
1220
1247
|
if (msg.id && sm.sessions.has(msg.id)) {
|
|
1221
|
-
sm.deleteSession(msg.id,
|
|
1248
|
+
sm.deleteSession(msg.id, ws);
|
|
1222
1249
|
}
|
|
1223
1250
|
return;
|
|
1224
1251
|
}
|
|
@@ -1285,7 +1312,7 @@ function createProjectContext(opts) {
|
|
|
1285
1312
|
}
|
|
1286
1313
|
|
|
1287
1314
|
if (msg.type === "stop") {
|
|
1288
|
-
var session =
|
|
1315
|
+
var session = getSessionForWs(ws);
|
|
1289
1316
|
if (session && session.abortController && session.isProcessing) {
|
|
1290
1317
|
session.abortController.abort();
|
|
1291
1318
|
}
|
|
@@ -1306,22 +1333,22 @@ function createProjectContext(opts) {
|
|
|
1306
1333
|
// Verify target is actually a claude process before killing
|
|
1307
1334
|
if (!sdk.isClaudeProcess(pid)) {
|
|
1308
1335
|
console.error("[project] Refused to kill PID " + pid + ": not a claude process");
|
|
1309
|
-
|
|
1336
|
+
sendTo(ws, { type: "error", text: "Process " + pid + " is not a Claude process." });
|
|
1310
1337
|
return;
|
|
1311
1338
|
}
|
|
1312
1339
|
try {
|
|
1313
1340
|
process.kill(pid, "SIGTERM");
|
|
1314
1341
|
console.log("[project] Sent SIGTERM to conflicting Claude process PID " + pid);
|
|
1315
|
-
|
|
1342
|
+
sendTo(ws, { type: "process_killed", pid: pid });
|
|
1316
1343
|
} catch (e) {
|
|
1317
1344
|
console.error("[project] Failed to kill PID " + pid + ":", e.message);
|
|
1318
|
-
|
|
1345
|
+
sendTo(ws, { type: "error", text: "Failed to kill process " + pid + ": " + (e.message || e) });
|
|
1319
1346
|
}
|
|
1320
1347
|
return;
|
|
1321
1348
|
}
|
|
1322
1349
|
|
|
1323
1350
|
if (msg.type === "set_model" && msg.model) {
|
|
1324
|
-
var session =
|
|
1351
|
+
var session = getSessionForWs(ws);
|
|
1325
1352
|
if (session) {
|
|
1326
1353
|
sdk.setModel(session, msg.model);
|
|
1327
1354
|
}
|
|
@@ -1332,7 +1359,7 @@ function createProjectContext(opts) {
|
|
|
1332
1359
|
if (typeof opts.onSetServerDefaultModel === "function") {
|
|
1333
1360
|
opts.onSetServerDefaultModel(msg.model);
|
|
1334
1361
|
}
|
|
1335
|
-
var session =
|
|
1362
|
+
var session = getSessionForWs(ws);
|
|
1336
1363
|
if (session) {
|
|
1337
1364
|
sdk.setModel(session, msg.model);
|
|
1338
1365
|
}
|
|
@@ -1343,7 +1370,7 @@ function createProjectContext(opts) {
|
|
|
1343
1370
|
if (typeof opts.onSetProjectDefaultModel === "function") {
|
|
1344
1371
|
opts.onSetProjectDefaultModel(slug, msg.model);
|
|
1345
1372
|
}
|
|
1346
|
-
var session =
|
|
1373
|
+
var session = getSessionForWs(ws);
|
|
1347
1374
|
if (session) {
|
|
1348
1375
|
sdk.setModel(session, msg.model);
|
|
1349
1376
|
}
|
|
@@ -1357,7 +1384,7 @@ function createProjectContext(opts) {
|
|
|
1357
1384
|
return;
|
|
1358
1385
|
}
|
|
1359
1386
|
sm.currentPermissionMode = msg.mode;
|
|
1360
|
-
var session =
|
|
1387
|
+
var session = getSessionForWs(ws);
|
|
1361
1388
|
if (session) {
|
|
1362
1389
|
sdk.setPermissionMode(session, msg.mode);
|
|
1363
1390
|
}
|
|
@@ -1371,7 +1398,7 @@ function createProjectContext(opts) {
|
|
|
1371
1398
|
}
|
|
1372
1399
|
if (!dangerouslySkipPermissions) {
|
|
1373
1400
|
sm.currentPermissionMode = msg.mode;
|
|
1374
|
-
var session =
|
|
1401
|
+
var session = getSessionForWs(ws);
|
|
1375
1402
|
if (session) {
|
|
1376
1403
|
sdk.setPermissionMode(session, msg.mode);
|
|
1377
1404
|
}
|
|
@@ -1386,7 +1413,7 @@ function createProjectContext(opts) {
|
|
|
1386
1413
|
}
|
|
1387
1414
|
if (!dangerouslySkipPermissions) {
|
|
1388
1415
|
sm.currentPermissionMode = msg.mode;
|
|
1389
|
-
var session =
|
|
1416
|
+
var session = getSessionForWs(ws);
|
|
1390
1417
|
if (session) {
|
|
1391
1418
|
sdk.setPermissionMode(session, msg.mode);
|
|
1392
1419
|
}
|
|
@@ -1426,7 +1453,7 @@ function createProjectContext(opts) {
|
|
|
1426
1453
|
}
|
|
1427
1454
|
|
|
1428
1455
|
if (msg.type === "rewind_preview") {
|
|
1429
|
-
var session =
|
|
1456
|
+
var session = getSessionForWs(ws);
|
|
1430
1457
|
if (!session || !session.cliSessionId || !msg.uuid) return;
|
|
1431
1458
|
|
|
1432
1459
|
(async function () {
|
|
@@ -1455,7 +1482,7 @@ function createProjectContext(opts) {
|
|
|
1455
1482
|
}
|
|
1456
1483
|
|
|
1457
1484
|
if (msg.type === "rewind_execute") {
|
|
1458
|
-
var session =
|
|
1485
|
+
var session = getSessionForWs(ws);
|
|
1459
1486
|
if (!session || !session.cliSessionId || !msg.uuid) return;
|
|
1460
1487
|
var mode = msg.mode || "both";
|
|
1461
1488
|
|
|
@@ -1510,11 +1537,11 @@ function createProjectContext(opts) {
|
|
|
1510
1537
|
onProcessingChanged();
|
|
1511
1538
|
|
|
1512
1539
|
sm.saveSessionFile(session);
|
|
1513
|
-
sm.switchSession(session.localId,
|
|
1540
|
+
sm.switchSession(session.localId, ws);
|
|
1514
1541
|
sm.sendAndRecord(session, { type: "rewind_complete", mode: mode });
|
|
1515
1542
|
sm.broadcastSessionList();
|
|
1516
1543
|
} catch (err) {
|
|
1517
|
-
|
|
1544
|
+
sendTo(ws, { type: "rewind_error", text: "Rewind failed: " + err.message });
|
|
1518
1545
|
} finally {
|
|
1519
1546
|
if (result && result.isTemp) result.cleanup();
|
|
1520
1547
|
}
|
|
@@ -1523,7 +1550,7 @@ function createProjectContext(opts) {
|
|
|
1523
1550
|
}
|
|
1524
1551
|
|
|
1525
1552
|
if (msg.type === "ask_user_response") {
|
|
1526
|
-
var session =
|
|
1553
|
+
var session = getSessionForWs(ws);
|
|
1527
1554
|
if (!session) return;
|
|
1528
1555
|
var toolId = msg.toolId;
|
|
1529
1556
|
var answers = msg.answers || {};
|
|
@@ -1544,7 +1571,7 @@ function createProjectContext(opts) {
|
|
|
1544
1571
|
}
|
|
1545
1572
|
|
|
1546
1573
|
if (msg.type === "permission_response") {
|
|
1547
|
-
var session =
|
|
1574
|
+
var session = getSessionForWs(ws);
|
|
1548
1575
|
if (!session) return;
|
|
1549
1576
|
var requestId = msg.requestId;
|
|
1550
1577
|
var decision = msg.decision;
|
|
@@ -1612,17 +1639,17 @@ function createProjectContext(opts) {
|
|
|
1612
1639
|
newSession.title = "Plan execution (cleared context)";
|
|
1613
1640
|
sm.saveSessionFile(newSession);
|
|
1614
1641
|
sm.broadcastSessionList();
|
|
1615
|
-
|
|
1642
|
+
sendToSession(newSession.localId, userMsg);
|
|
1616
1643
|
|
|
1617
1644
|
newSession.isProcessing = true;
|
|
1618
1645
|
onProcessingChanged();
|
|
1619
1646
|
newSession.sentToolResults = {};
|
|
1620
|
-
|
|
1647
|
+
sendToSession(newSession.localId, { type: "status", status: "processing" });
|
|
1621
1648
|
newSession.acceptEditsAfterStart = true;
|
|
1622
1649
|
sdk.startQuery(newSession, planPrompt);
|
|
1623
1650
|
} catch (e) {
|
|
1624
1651
|
console.error("[project] Error starting plan execution:", e);
|
|
1625
|
-
|
|
1652
|
+
sendTo(ws, { type: "error", text: "Failed to start plan execution: " + (e.message || e) });
|
|
1626
1653
|
}
|
|
1627
1654
|
});
|
|
1628
1655
|
return;
|
|
@@ -1640,13 +1667,13 @@ function createProjectContext(opts) {
|
|
|
1640
1667
|
var userMsg = { type: "user_message", text: feedback };
|
|
1641
1668
|
session.history.push(userMsg);
|
|
1642
1669
|
sm.appendToSessionFile(session, userMsg);
|
|
1643
|
-
|
|
1670
|
+
sendToSession(session.localId, userMsg);
|
|
1644
1671
|
|
|
1645
1672
|
if (!session.isProcessing) {
|
|
1646
1673
|
session.isProcessing = true;
|
|
1647
1674
|
onProcessingChanged();
|
|
1648
1675
|
session.sentToolResults = {};
|
|
1649
|
-
|
|
1676
|
+
sendToSession(session.localId, { type: "status", status: "processing" });
|
|
1650
1677
|
if (!session.queryInstance) {
|
|
1651
1678
|
sdk.startQuery(session, feedback);
|
|
1652
1679
|
} else {
|
|
@@ -2415,11 +2442,11 @@ function createProjectContext(opts) {
|
|
|
2415
2442
|
// Send crafting prompt and start the conversation with Claude.
|
|
2416
2443
|
craftingSession.history.push({ type: "user_message", text: craftingPrompt });
|
|
2417
2444
|
sm.appendToSessionFile(craftingSession, { type: "user_message", text: craftingPrompt });
|
|
2418
|
-
|
|
2445
|
+
sendToSession(craftingSession.localId, { type: "user_message", text: craftingPrompt });
|
|
2419
2446
|
craftingSession.isProcessing = true;
|
|
2420
2447
|
onProcessingChanged();
|
|
2421
2448
|
craftingSession.sentToolResults = {};
|
|
2422
|
-
|
|
2449
|
+
sendToSession(craftingSession.localId, { type: "status", status: "processing" });
|
|
2423
2450
|
sdk.startQuery(craftingSession, craftingPrompt);
|
|
2424
2451
|
|
|
2425
2452
|
send({ type: "ralph_crafting_started", sessionId: craftingSession.localId, taskId: newLoopId, source: recordSource });
|
|
@@ -2609,7 +2636,7 @@ function createProjectContext(opts) {
|
|
|
2609
2636
|
if (msg.type !== "message") return;
|
|
2610
2637
|
if (!msg.text && (!msg.images || msg.images.length === 0) && (!msg.pastes || msg.pastes.length === 0)) return;
|
|
2611
2638
|
|
|
2612
|
-
var session =
|
|
2639
|
+
var session = getSessionForWs(ws);
|
|
2613
2640
|
if (!session) return;
|
|
2614
2641
|
|
|
2615
2642
|
var userMsg = { type: "user_message", text: msg.text || "" };
|
|
@@ -2641,7 +2668,7 @@ function createProjectContext(opts) {
|
|
|
2641
2668
|
session.isProcessing = true;
|
|
2642
2669
|
onProcessingChanged();
|
|
2643
2670
|
session.sentToolResults = {};
|
|
2644
|
-
|
|
2671
|
+
sendToSession(session.localId, { type: "status", status: "processing" });
|
|
2645
2672
|
if (!session.queryInstance) {
|
|
2646
2673
|
sdk.startQuery(session, fullText, msg.images);
|
|
2647
2674
|
} else {
|
package/lib/public/app.js
CHANGED
|
@@ -2659,9 +2659,10 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
2659
2659
|
// Non-multi-user mode: simple count in topbar
|
|
2660
2660
|
if (!msg.users) {
|
|
2661
2661
|
var countEl = document.getElementById("client-count");
|
|
2662
|
-
|
|
2662
|
+
var countTextEl = document.getElementById("client-count-text");
|
|
2663
|
+
if (countEl && countTextEl) {
|
|
2663
2664
|
if (msg.count > 1) {
|
|
2664
|
-
|
|
2665
|
+
countTextEl.textContent = msg.count + " connected";
|
|
2665
2666
|
countEl.classList.remove("hidden");
|
|
2666
2667
|
} else {
|
|
2667
2668
|
countEl.classList.add("hidden");
|
package/lib/public/css/menus.css
CHANGED
|
@@ -407,13 +407,10 @@
|
|
|
407
407
|
.notif-action.copied { color: var(--success); }
|
|
408
408
|
|
|
409
409
|
#client-count {
|
|
410
|
-
display: inline-flex;
|
|
411
|
-
align-items: center;
|
|
412
410
|
cursor: default;
|
|
411
|
+
font-size: 11px;
|
|
413
412
|
}
|
|
414
413
|
|
|
415
|
-
#client-count.hidden { display: none; }
|
|
416
|
-
|
|
417
414
|
.client-avatar {
|
|
418
415
|
width: 22px;
|
|
419
416
|
height: 22px;
|
package/lib/public/index.html
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="top-bar-actions">
|
|
44
44
|
<!-- Pill badges -->
|
|
45
45
|
<div id="skip-perms-pill" class="top-bar-pill pill-error hidden"><i data-lucide="shield-off"></i> <span>Skip perms</span></div>
|
|
46
|
-
<
|
|
46
|
+
<div id="client-count" class="top-bar-pill pill-accent hidden"><i data-lucide="users"></i> <span id="client-count-text"></span></div>
|
|
47
47
|
<label id="theme-toggle-btn" class="theme-toggle" title="Toggle dark/light mode">
|
|
48
48
|
<input type="checkbox" id="theme-toggle-check">
|
|
49
49
|
<span class="theme-toggle-track">
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -111,9 +111,7 @@ function createSDKBridge(opts) {
|
|
|
111
111
|
if (parsed.session_id && !session.cliSessionId) {
|
|
112
112
|
session.cliSessionId = parsed.session_id;
|
|
113
113
|
sm.saveSessionFile(session);
|
|
114
|
-
|
|
115
|
-
send({ type: "session_id", cliSessionId: session.cliSessionId });
|
|
116
|
-
}
|
|
114
|
+
sendAndRecord(session, { type: "session_id", cliSessionId: session.cliSessionId });
|
|
117
115
|
} else if (parsed.session_id) {
|
|
118
116
|
session.cliSessionId = parsed.session_id;
|
|
119
117
|
}
|
|
@@ -704,7 +702,7 @@ function createSDKBridge(opts) {
|
|
|
704
702
|
try {
|
|
705
703
|
sdk = await getSDK();
|
|
706
704
|
} catch (e) {
|
|
707
|
-
|
|
705
|
+
sendAndRecord(session, { type: "error", text: "Failed to load Claude SDK: " + (e.message || e) });
|
|
708
706
|
throw e;
|
|
709
707
|
}
|
|
710
708
|
var mq = createMessageQueue();
|
|
@@ -738,7 +736,7 @@ function createSDKBridge(opts) {
|
|
|
738
736
|
} catch (e) {
|
|
739
737
|
session.isProcessing = false;
|
|
740
738
|
onProcessingChanged();
|
|
741
|
-
|
|
739
|
+
sendAndRecord(session, { type: "error", text: "Failed to load Claude SDK: " + (e.message || e) });
|
|
742
740
|
sendAndRecord(session, { type: "done", code: 1 });
|
|
743
741
|
sm.broadcastSessionList();
|
|
744
742
|
return;
|
|
@@ -831,7 +829,7 @@ function createSDKBridge(opts) {
|
|
|
831
829
|
session.queryInstance = null;
|
|
832
830
|
session.messageQueue = null;
|
|
833
831
|
session.abortController = null;
|
|
834
|
-
|
|
832
|
+
sendAndRecord(session, { type: "error", text: "Failed to start query: " + (e.message || e) });
|
|
835
833
|
sendAndRecord(session, { type: "done", code: 1 });
|
|
836
834
|
sm.broadcastSessionList();
|
|
837
835
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clay-server",
|
|
3
|
-
"version": "2.9.1",
|
|
3
|
+
"version": "2.9.3-beta.1",
|
|
4
4
|
"description": "Web UI for Claude Code. Any device. Push notifications.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"clay-server": "./bin/cli.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"dev": "node bin/cli.js --dev",
|
|
11
11
|
"prepack": "npm pkg delete bin.clay-dev",
|
|
12
|
-
"postpack": "npm pkg set bin.clay-dev=./bin/cli.js"
|
|
12
|
+
"postpack": "npm pkg set bin.clay-dev=./bin/cli.js",
|
|
13
|
+
"semantic-release": "semantic-release"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"bin/",
|
|
@@ -45,5 +46,11 @@
|
|
|
45
46
|
"license": "MIT",
|
|
46
47
|
"engines": {
|
|
47
48
|
"node": ">=20.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
52
|
+
"@semantic-release/exec": "^7.1.0",
|
|
53
|
+
"@semantic-release/git": "^10.0.1",
|
|
54
|
+
"semantic-release": "^25.0.3"
|
|
48
55
|
}
|
|
49
56
|
}
|