clay-server 2.19.0 → 2.20.0-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/lib/sdk-bridge.js CHANGED
@@ -59,14 +59,14 @@ function createSDKBridge(opts) {
59
59
  var isMate = opts.isMate || (slug.indexOf("mate-") === 0);
60
60
  var dangerouslySkipPermissions = opts.dangerouslySkipPermissions || false;
61
61
  var onProcessingChanged = opts.onProcessingChanged || function () {};
62
-
62
+ var onTurnDone = opts.onTurnDone || null;
63
63
 
64
64
  // --- Skill discovery helpers ---
65
65
 
66
66
  function discoverSkillDirs() {
67
67
  var skills = {};
68
68
  var dirs = [
69
- path.join(os.homedir(), ".claude", "skills"),
69
+ path.join(require("./config").REAL_HOME, ".claude", "skills"),
70
70
  path.join(cwd, ".claude", "skills"),
71
71
  ];
72
72
  for (var d = 0; d < dirs.length; d++) {
@@ -387,9 +387,13 @@ function createSDKBridge(opts) {
387
387
  });
388
388
  }
389
389
  // Reset for next turn in the same query
390
+ var donePreview = session.responsePreview || "";
390
391
  session.responsePreview = "";
391
392
  session.streamedText = false;
392
393
  sm.broadcastSessionList();
394
+ if (onTurnDone) {
395
+ try { onTurnDone(session, donePreview); } catch (e) {}
396
+ }
393
397
 
394
398
  } else if (parsed.type === "system" && parsed.subtype === "status") {
395
399
  if (parsed.status === "compacting") {
@@ -459,6 +463,18 @@ function createSDKBridge(opts) {
459
463
 
460
464
  } else if (parsed.type === "rate_limit_event" && parsed.rate_limit_info) {
461
465
  var info = parsed.rate_limit_info;
466
+
467
+ // Broadcast reset time for top-bar usage link
468
+ if (info.rateLimitType && info.resetsAt) {
469
+ send({
470
+ type: "rate_limit_usage",
471
+ rateLimitType: info.rateLimitType,
472
+ resetsAt: info.resetsAt * 1000,
473
+ status: info.status,
474
+ });
475
+ }
476
+
477
+ // Warning/rejection handling (existing behavior)
462
478
  if (info.status === "allowed_warning" || info.status === "rejected") {
463
479
  sendAndRecord(session, {
464
480
  type: "rate_limit",
@@ -832,14 +848,12 @@ function createSDKBridge(opts) {
832
848
  }
833
849
 
834
850
  if (dangerouslySkipPermissions) {
835
- queryOptions.permissionMode = "bypassPermissions";
836
851
  queryOptions.allowDangerouslySkipPermissions = true;
837
- } else {
838
- var modeToApply = session.acceptEditsAfterStart ? "acceptEdits" : sm.currentPermissionMode;
839
- if (session.acceptEditsAfterStart) delete session.acceptEditsAfterStart;
840
- if (modeToApply && modeToApply !== "default") {
841
- queryOptions.permissionMode = modeToApply;
842
- }
852
+ }
853
+ var modeToApply = session.acceptEditsAfterStart ? "acceptEdits" : sm.currentPermissionMode;
854
+ if (session.acceptEditsAfterStart) delete session.acceptEditsAfterStart;
855
+ if (modeToApply && modeToApply !== "default") {
856
+ queryOptions.permissionMode = modeToApply;
843
857
  }
844
858
 
845
859
  if (session.cliSessionId) {
@@ -980,10 +994,11 @@ function createSDKBridge(opts) {
980
994
  sm.broadcastSessionList();
981
995
  }
982
996
  cleanupSessionWorker(session);
983
- // Auto-continue for scheduler sessions on rate limit
997
+ // Auto-continue on rate limit (scheduler sessions, or user setting)
984
998
  var workerDidScheduleAC = false;
999
+ var workerACEnabled = session.onQueryComplete || (typeof opts.getAutoContinueSetting === "function" && opts.getAutoContinueSetting(session));
985
1000
  if (session.rateLimitResetsAt && session.rateLimitResetsAt > Date.now()
986
- && session.onQueryComplete && !session.destroying) {
1001
+ && workerACEnabled && !session.destroying) {
987
1002
  var wacDelay = session.rateLimitResetsAt - Date.now() + 3000;
988
1003
  var wacResetsAt = session.rateLimitResetsAt;
989
1004
  session.rateLimitResetsAt = null;
@@ -1149,6 +1164,52 @@ function createSDKBridge(opts) {
1149
1164
  if (mateAutoTools[toolName]) {
1150
1165
  return Promise.resolve({ behavior: "allow", updatedInput: input });
1151
1166
  }
1167
+ // Auto-approve safe Bash commands (read-only, non-destructive)
1168
+ if (toolName === "Bash" && input && input.command) {
1169
+ var cmd = input.command.trim();
1170
+ var firstWord = cmd.split(/[\s;|&]/)[0];
1171
+ var safeBashCommands = {
1172
+ ls: true, cat: true, head: true, tail: true, wc: true, file: true,
1173
+ // File/dir inspection
1174
+ ls: true, cat: true, head: true, tail: true, wc: true, file: true,
1175
+ stat: true, find: true, tree: true, du: true, df: true,
1176
+ readlink: true, realpath: true, basename: true, dirname: true,
1177
+ // Search
1178
+ grep: true, rg: true, ag: true, ack: true, fgrep: true, egrep: true,
1179
+ // Lookup
1180
+ which: true, type: true, whereis: true, command: true, hash: true,
1181
+ // Environment/system info
1182
+ echo: true, printf: true, env: true, printenv: true, pwd: true,
1183
+ whoami: true, id: true, groups: true,
1184
+ date: true, uname: true, hostname: true, uptime: true, arch: true,
1185
+ nproc: true, free: true, lsb_release: true, sw_vers: true,
1186
+ locale: true, timedatectl: true,
1187
+ // Version checks
1188
+ git: true, dotnet: true, ruby: true, java: true, javac: true,
1189
+ rustc: true, gcc: true, clang: true, cmake: true,
1190
+ // Text processing (pure stdin/stdout, no side effects)
1191
+ jq: true, yq: true, sort: true, uniq: true, cut: true, tr: true,
1192
+ awk: true, sed: true, paste: true, column: true, fold: true,
1193
+ rev: true, tac: true, nl: true, expand: true, unexpand: true,
1194
+ fmt: true, pr: true, csplit: true, comm: true, join: true,
1195
+ // Comparison/hashing
1196
+ diff: true, cmp: true, md5sum: true, sha256sum: true, sha1sum: true,
1197
+ shasum: true, cksum: true, sum: true, b2sum: true, base64: true,
1198
+ xxd: true, od: true, hexdump: true,
1199
+ // Misc read-only
1200
+ test: true, true: true, false: true, seq: true, yes: true,
1201
+ sleep: true, tee: true, xargs: true, time: true,
1202
+ man: true, help: true, info: true, apropos: true,
1203
+ cal: true, bc: true, expr: true, factor: true,
1204
+ lsof: true, ps: true, top: true, htop: true, pgrep: true,
1205
+ netstat: true, ss: true, ifconfig: true, ip: true, dig: true,
1206
+ nslookup: true, host: true, ping: true, traceroute: true,
1207
+ curl: true, wget: true, http: true,
1208
+ };
1209
+ if (safeBashCommands[firstWord]) {
1210
+ return Promise.resolve({ behavior: "allow", updatedInput: input });
1211
+ }
1212
+ }
1152
1213
  }
1153
1214
 
1154
1215
  // AskUserQuestion: wait for user answers via WebSocket
@@ -1373,10 +1434,11 @@ function createSDKBridge(opts) {
1373
1434
  session.pendingAskUser = {};
1374
1435
  session.pendingElicitations = {};
1375
1436
 
1376
- // Auto-continue for scheduler (Ralph Loop) sessions on rate limit
1437
+ // Auto-continue on rate limit (scheduler sessions, or user setting)
1377
1438
  var didScheduleAutoContinue = false;
1439
+ var acEnabled = session.onQueryComplete || (typeof opts.getAutoContinueSetting === "function" && opts.getAutoContinueSetting(session));
1378
1440
  if (session.rateLimitResetsAt && session.rateLimitResetsAt > Date.now()
1379
- && session.onQueryComplete && !session.destroying) {
1441
+ && acEnabled && !session.destroying) {
1380
1442
  var acDelay = session.rateLimitResetsAt - Date.now() + 3000;
1381
1443
  var acResetsAt = session.rateLimitResetsAt;
1382
1444
  session.rateLimitResetsAt = null;
@@ -1527,15 +1589,13 @@ function createSDKBridge(opts) {
1527
1589
  }
1528
1590
 
1529
1591
  if (dangerouslySkipPermissions) {
1530
- queryOptions.permissionMode = "bypassPermissions";
1531
1592
  queryOptions.allowDangerouslySkipPermissions = true;
1532
- } else {
1533
- // Pass permissionMode in queryOptions at creation time to avoid race condition
1534
- var modeToApply = session.acceptEditsAfterStart ? "acceptEdits" : sm.currentPermissionMode;
1535
- if (session.acceptEditsAfterStart) delete session.acceptEditsAfterStart;
1536
- if (modeToApply && modeToApply !== "default") {
1537
- queryOptions.permissionMode = modeToApply;
1538
- }
1593
+ }
1594
+ // Pass permissionMode in queryOptions at creation time to avoid race condition
1595
+ var modeToApply = session.acceptEditsAfterStart ? "acceptEdits" : sm.currentPermissionMode;
1596
+ if (session.acceptEditsAfterStart) delete session.acceptEditsAfterStart;
1597
+ if (modeToApply && modeToApply !== "default") {
1598
+ queryOptions.permissionMode = modeToApply;
1539
1599
  }
1540
1600
 
1541
1601
  if (session.cliSessionId) {
@@ -1745,12 +1805,6 @@ function createSDKBridge(opts) {
1745
1805
  }
1746
1806
 
1747
1807
  async function setPermissionMode(session, mode) {
1748
- // When dangerouslySkipPermissions is active, ignore mode changes from UI
1749
- // to prevent accidentally downgrading from bypassPermissions
1750
- if (dangerouslySkipPermissions) {
1751
- send({ type: "config_state", model: sm.currentModel || "", mode: "bypassPermissions", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1752
- return;
1753
- }
1754
1808
  if (session.worker) {
1755
1809
  session.worker.send({ type: "set_permission_mode", mode: mode });
1756
1810
  return;
@@ -1819,9 +1873,7 @@ function createSDKBridge(opts) {
1819
1873
 
1820
1874
  var query;
1821
1875
  try {
1822
- query = sdk.query({
1823
- prompt: mq,
1824
- options: {
1876
+ var mentionQueryOptions = {
1825
1877
  cwd: cwd,
1826
1878
  systemPrompt: opts.claudeMd,
1827
1879
  settingSources: ["user"],
@@ -1837,18 +1889,32 @@ function createSDKBridge(opts) {
1837
1889
  message: "Read-only access. You cannot make changes via @mention.",
1838
1890
  });
1839
1891
  },
1840
- },
1892
+ };
1893
+ if (opts.model) mentionQueryOptions.model = opts.model;
1894
+ query = sdk.query({
1895
+ prompt: mq,
1896
+ options: mentionQueryOptions,
1841
1897
  });
1842
1898
  } catch (e) {
1843
1899
  opts.onError("Failed to create mention query: " + (e.message || e));
1844
1900
  return null;
1845
1901
  }
1846
1902
 
1847
- // Push the initial message (context + question)
1903
+ // Push the initial message (context + question, with optional images)
1848
1904
  var initialPrompt = opts.initialContext + "\n\n" + opts.initialMessage;
1905
+ var initialContent = [];
1906
+ if (opts.initialImages && opts.initialImages.length > 0) {
1907
+ for (var ii = 0; ii < opts.initialImages.length; ii++) {
1908
+ initialContent.push({
1909
+ type: "image",
1910
+ source: { type: "base64", media_type: opts.initialImages[ii].mediaType, data: opts.initialImages[ii].data },
1911
+ });
1912
+ }
1913
+ }
1914
+ initialContent.push({ type: "text", text: initialPrompt });
1849
1915
  mq.push({
1850
1916
  type: "user",
1851
- message: { role: "user", content: [{ type: "text", text: initialPrompt }] },
1917
+ message: { role: "user", content: initialContent },
1852
1918
  });
1853
1919
 
1854
1920
  // Background stream processing loop
@@ -1951,7 +2017,7 @@ function createSDKBridge(opts) {
1951
2017
 
1952
2018
  return {
1953
2019
  // Push a follow-up message to the existing mention session
1954
- pushMessage: function (text, callbacks) {
2020
+ pushMessage: function (text, callbacks, images) {
1955
2021
  currentOnDelta = callbacks.onDelta;
1956
2022
  currentOnDone = callbacks.onDone;
1957
2023
  currentOnError = callbacks.onError;
@@ -1959,11 +2025,24 @@ function createSDKBridge(opts) {
1959
2025
  mentionBlocks = {};
1960
2026
  responseFullText = "";
1961
2027
  responseStreamedText = false;
2028
+ var content = [];
2029
+ if (images && images.length > 0) {
2030
+ for (var pi = 0; pi < images.length; pi++) {
2031
+ content.push({
2032
+ type: "image",
2033
+ source: { type: "base64", media_type: images[pi].mediaType, data: images[pi].data },
2034
+ });
2035
+ }
2036
+ }
2037
+ content.push({ type: "text", text: text });
1962
2038
  mq.push({
1963
2039
  type: "user",
1964
- message: { role: "user", content: [{ type: "text", text: text }] },
2040
+ message: { role: "user", content: content },
1965
2041
  });
1966
2042
  },
2043
+ abort: function () {
2044
+ try { abortController.abort(); } catch (e) {}
2045
+ },
1967
2046
  close: function () {
1968
2047
  alive = false;
1969
2048
  try { mq.end(); } catch (e) {}
package/lib/server.js CHANGED
@@ -1128,6 +1128,7 @@ function createServer(opts) {
1128
1128
  profile.username = mu.username;
1129
1129
  profile.userId = mu.id;
1130
1130
  profile.role = mu.role;
1131
+ profile.autoContinueOnRateLimit = !!mu.autoContinueOnRateLimit;
1131
1132
  res.writeHead(200, { "Content-Type": "application/json" });
1132
1133
  res.end(JSON.stringify(profile));
1133
1134
  return;
@@ -1143,6 +1144,11 @@ function createServer(opts) {
1143
1144
  if (saved.avatarSeed) profile.avatarSeed = saved.avatarSeed;
1144
1145
  if (saved.avatarCustom) profile.avatarCustom = saved.avatarCustom;
1145
1146
  } catch (e) { /* file doesn't exist yet */ }
1147
+ // Single-user auto-continue from daemon config
1148
+ if (typeof opts.onGetDaemonConfig === "function") {
1149
+ var dc = opts.onGetDaemonConfig();
1150
+ profile.autoContinueOnRateLimit = !!dc.autoContinueOnRateLimit;
1151
+ }
1146
1152
  // Check if custom avatar file exists
1147
1153
  try {
1148
1154
  var avatarFiles = fs.readdirSync(path.join(CONFIG_DIR, "avatars"));
@@ -1431,6 +1437,69 @@ function createServer(opts) {
1431
1437
  return;
1432
1438
  }
1433
1439
 
1440
+ // PUT /api/user/auto-continue
1441
+ if (req.method === "PUT" && fullUrl === "/api/user/auto-continue") {
1442
+ var mu = getMultiUserFromReq(req);
1443
+ if (!mu) {
1444
+ // Single-user: use daemon config fallback
1445
+ var body = "";
1446
+ req.on("data", function (chunk) { body += chunk; });
1447
+ req.on("end", function () {
1448
+ try {
1449
+ var data = JSON.parse(body);
1450
+ if (typeof opts.onSetAutoContinue === "function") {
1451
+ opts.onSetAutoContinue(!!data.enabled);
1452
+ }
1453
+ res.writeHead(200, { "Content-Type": "application/json" });
1454
+ res.end(JSON.stringify({ ok: true, autoContinueOnRateLimit: !!data.enabled }));
1455
+ } catch (e) {
1456
+ res.writeHead(400, { "Content-Type": "application/json" });
1457
+ res.end('{"error":"Invalid request"}');
1458
+ }
1459
+ });
1460
+ return;
1461
+ }
1462
+ var body = "";
1463
+ req.on("data", function (chunk) { body += chunk; });
1464
+ req.on("end", function () {
1465
+ try {
1466
+ var data = JSON.parse(body);
1467
+ var result = users.setAutoContinue(mu.id, !!data.enabled);
1468
+ if (result.error) {
1469
+ res.writeHead(400, { "Content-Type": "application/json" });
1470
+ res.end(JSON.stringify({ error: result.error }));
1471
+ return;
1472
+ }
1473
+ res.writeHead(200, { "Content-Type": "application/json" });
1474
+ res.end(JSON.stringify({ ok: true, autoContinueOnRateLimit: result.autoContinueOnRateLimit }));
1475
+ } catch (e) {
1476
+ res.writeHead(400, { "Content-Type": "application/json" });
1477
+ res.end('{"error":"Invalid request"}');
1478
+ }
1479
+ });
1480
+ return;
1481
+ }
1482
+
1483
+ // GET /api/user/auto-continue
1484
+ if (req.method === "GET" && fullUrl === "/api/user/auto-continue") {
1485
+ var mu = getMultiUserFromReq(req);
1486
+ if (!mu) {
1487
+ // Single-user: read from daemon config
1488
+ var enabled = false;
1489
+ if (typeof opts.onGetDaemonConfig === "function") {
1490
+ var dc = opts.onGetDaemonConfig();
1491
+ enabled = !!dc.autoContinueOnRateLimit;
1492
+ }
1493
+ res.writeHead(200, { "Content-Type": "application/json" });
1494
+ res.end(JSON.stringify({ autoContinueOnRateLimit: enabled }));
1495
+ return;
1496
+ }
1497
+ var val = users.getAutoContinue(mu.id);
1498
+ res.writeHead(200, { "Content-Type": "application/json" });
1499
+ res.end(JSON.stringify({ autoContinueOnRateLimit: val }));
1500
+ return;
1501
+ }
1502
+
1434
1503
  // --- Admin API endpoints (multi-user mode only) ---
1435
1504
 
1436
1505
  // List all users (admin only)
@@ -2109,7 +2178,6 @@ function createServer(opts) {
2109
2178
  var pResults = [];
2110
2179
  projects.forEach(function (pCtx, pSlug) {
2111
2180
  var status = pCtx.getStatus();
2112
- if (status.isMate) return;
2113
2181
  if (status.isWorktree) return;
2114
2182
  // Access check
2115
2183
  if (paletteUser && onGetProjectAccess) {
@@ -2131,7 +2199,7 @@ function createServer(opts) {
2131
2199
  }
2132
2200
  if (!pQuery) {
2133
2201
  // Recent mode: return all sessions sorted by lastActivity
2134
- pResults.push({
2202
+ var pItem = {
2135
2203
  projectSlug: pSlug,
2136
2204
  projectTitle: status.title || status.project,
2137
2205
  projectIcon: status.icon || null,
@@ -2140,7 +2208,12 @@ function createServer(opts) {
2140
2208
  lastActivity: session.lastActivity || session.createdAt || 0,
2141
2209
  matchType: null,
2142
2210
  snippet: null
2143
- });
2211
+ };
2212
+ if (status.isMate) {
2213
+ pItem.isMate = true;
2214
+ pItem.mateId = status.mateId || null;
2215
+ }
2216
+ pResults.push(pItem);
2144
2217
  } else {
2145
2218
  // Search mode: match title and content
2146
2219
  var q = pQuery.toLowerCase();
@@ -2148,7 +2221,7 @@ function createServer(opts) {
2148
2221
  var contentSnippet = null;
2149
2222
  for (var hi = 0; hi < session.history.length; hi++) {
2150
2223
  var entry = session.history[hi];
2151
- if ((entry.type === "delta" || entry.type === "user_message") && entry.text) {
2224
+ if ((entry.type === "delta" || entry.type === "user_message" || entry.type === "mention_user" || entry.type === "mention_response" || entry.type === "debate_turn_done") && entry.text) {
2152
2225
  var lowerText = entry.text.toLowerCase();
2153
2226
  var matchIdx = lowerText.indexOf(q);
2154
2227
  if (matchIdx !== -1) {
@@ -2162,7 +2235,7 @@ function createServer(opts) {
2162
2235
  }
2163
2236
  }
2164
2237
  if (titleMatch || contentSnippet) {
2165
- pResults.push({
2238
+ var sItem = {
2166
2239
  projectSlug: pSlug,
2167
2240
  projectTitle: status.title || status.project,
2168
2241
  projectIcon: status.icon || null,
@@ -2171,7 +2244,12 @@ function createServer(opts) {
2171
2244
  lastActivity: session.lastActivity || session.createdAt || 0,
2172
2245
  matchType: titleMatch && contentSnippet ? "both" : titleMatch ? "title" : "content",
2173
2246
  snippet: contentSnippet
2174
- });
2247
+ };
2248
+ if (status.isMate) {
2249
+ sItem.isMate = true;
2250
+ sItem.mateId = status.mateId || null;
2251
+ }
2252
+ pResults.push(sItem);
2175
2253
  }
2176
2254
  }
2177
2255
  });
package/lib/sessions.js CHANGED
@@ -31,7 +31,7 @@ function createSessionManager(opts) {
31
31
  // v2: ~/.claude-relay/sessions/{encoded-cwd}/ (if config.js rename didn't cover it)
32
32
  var legacySessionDirs = [
33
33
  path.join(cwd, ".claude-relay", "sessions"),
34
- path.join(require("os").homedir(), ".claude-relay", "sessions", encodedCwd),
34
+ path.join(require("./config").REAL_HOME, ".claude-relay", "sessions", encodedCwd),
35
35
  ];
36
36
  for (var li = 0; li < legacySessionDirs.length; li++) {
37
37
  var oldSessionsDir = legacySessionDirs[li];
@@ -569,7 +569,7 @@ function createSessionManager(opts) {
569
569
  var contentMatch = false;
570
570
  for (var i = 0; i < session.history.length; i++) {
571
571
  var entry = session.history[i];
572
- if ((entry.type === "delta" || entry.type === "user_message") && entry.text) {
572
+ if ((entry.type === "delta" || entry.type === "user_message" || entry.type === "mention_user" || entry.type === "mention_response" || entry.type === "debate_turn_done") && entry.text) {
573
573
  if (entry.text.toLowerCase().indexOf(q) !== -1) {
574
574
  contentMatch = true;
575
575
  break;
@@ -602,11 +602,11 @@ function createSessionManager(opts) {
602
602
  var currentTurnStart = -1;
603
603
  for (var i = 0; i < history.length; i++) {
604
604
  var entry = history[i];
605
- if (entry.type === "user_message") {
605
+ if (entry.type === "user_message" || entry.type === "mention_user") {
606
606
  currentTurnStart = i;
607
607
  lastAssistantHitTurn = -1;
608
608
  }
609
- if ((entry.type === "delta" || entry.type === "user_message") && entry.text) {
609
+ if ((entry.type === "delta" || entry.type === "user_message" || entry.type === "mention_user" || entry.type === "mention_response" || entry.type === "debate_turn_done") && entry.text) {
610
610
  // Skip duplicate delta hits within the same assistant turn
611
611
  if (entry.type === "delta" && currentTurnStart === lastAssistantHitTurn) continue;
612
612
  var text = entry.text;
package/lib/users.js CHANGED
@@ -641,6 +641,30 @@ function canAccessSession(userId, session, project) {
641
641
  return false;
642
642
  }
643
643
 
644
+ // --- Per-user auto-continue setting ---
645
+
646
+ function getAutoContinue(userId) {
647
+ var data = loadUsers();
648
+ for (var i = 0; i < data.users.length; i++) {
649
+ if (data.users[i].id === userId) {
650
+ return !!data.users[i].autoContinueOnRateLimit;
651
+ }
652
+ }
653
+ return false;
654
+ }
655
+
656
+ function setAutoContinue(userId, enabled) {
657
+ var data = loadUsers();
658
+ for (var i = 0; i < data.users.length; i++) {
659
+ if (data.users[i].id === userId) {
660
+ data.users[i].autoContinueOnRateLimit = !!enabled;
661
+ saveUsers(data);
662
+ return { ok: true, autoContinueOnRateLimit: !!enabled };
663
+ }
664
+ }
665
+ return { error: "User not found" };
666
+ }
667
+
644
668
  module.exports = {
645
669
  USERS_FILE: USERS_FILE,
646
670
  loadUsers: loadUsers,
@@ -691,4 +715,6 @@ module.exports = {
691
715
  getDmHidden: getDmHidden,
692
716
  addDmHidden: addDmHidden,
693
717
  removeDmHidden: removeDmHidden,
718
+ getAutoContinue: getAutoContinue,
719
+ setAutoContinue: setAutoContinue,
694
720
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.19.0",
3
+ "version": "2.20.0-beta.1",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",