clay-server 2.11.0-beta.1 → 2.11.0-beta.3

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/project.js CHANGED
@@ -979,7 +979,7 @@ function createProjectContext(opts) {
979
979
  if (sm.currentModel) {
980
980
  sendTo(ws, { type: "model_info", model: sm.currentModel, models: sm.availableModels || [] });
981
981
  }
982
- sendTo(ws, { type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
982
+ sendTo(ws, { type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
983
983
  sendTo(ws, { type: "term_list", terminals: tm.list() });
984
984
  sendTo(ws, { type: "notes_list", notes: nm.list() });
985
985
  sendTo(ws, { type: "loop_registry_updated", records: getHubSchedules() });
@@ -1187,17 +1187,31 @@ function createProjectContext(opts) {
1187
1187
  if (msg.type === "resume_session") {
1188
1188
  if (!msg.cliSessionId) return;
1189
1189
  var cliSess = require("./cli-sessions");
1190
- cliSess.readCliSessionHistory(cwd, msg.cliSessionId).then(function (history) {
1191
- var title = "Resumed session";
1192
- for (var i = 0; i < history.length; i++) {
1193
- if (history[i].type === "user_message" && history[i].text) {
1194
- title = history[i].text.substring(0, 50);
1195
- break;
1190
+ // Try SDK for title first, then fall back to manual parsing
1191
+ var titlePromise = getSDK().then(function(sdkMod) {
1192
+ return sdkMod.getSessionInfo(msg.cliSessionId, { dir: cwd });
1193
+ }).then(function(info) {
1194
+ return (info && info.summary) ? info.summary.substring(0, 100) : null;
1195
+ }).catch(function() { return null; });
1196
+
1197
+ Promise.all([
1198
+ cliSess.readCliSessionHistory(cwd, msg.cliSessionId),
1199
+ titlePromise
1200
+ ]).then(function(results) {
1201
+ var history = results[0];
1202
+ var sdkTitle = results[1];
1203
+ var title = sdkTitle || "Resumed session";
1204
+ if (!sdkTitle) {
1205
+ for (var i = 0; i < history.length; i++) {
1206
+ if (history[i].type === "user_message" && history[i].text) {
1207
+ title = history[i].text.substring(0, 50);
1208
+ break;
1209
+ }
1196
1210
  }
1197
1211
  }
1198
1212
  var resumed = sm.resumeSession(msg.cliSessionId, { history: history, title: title }, ws);
1199
1213
  if (resumed) ws._clayActiveSession = resumed.localId;
1200
- }).catch(function () {
1214
+ }).catch(function() {
1201
1215
  var resumed = sm.resumeSession(msg.cliSessionId, undefined, ws);
1202
1216
  if (resumed) ws._clayActiveSession = resumed.localId;
1203
1217
  });
@@ -1205,9 +1219,7 @@ function createProjectContext(opts) {
1205
1219
  }
1206
1220
 
1207
1221
  if (msg.type === "list_cli_sessions") {
1208
- var cliSessions = require("./cli-sessions");
1209
1222
  var _fs = require("fs");
1210
- var _path = require("path");
1211
1223
  // Collect session IDs already in relay (in-memory + persisted on disk)
1212
1224
  var relayIds = {};
1213
1225
  sm.sessions.forEach(function (s) {
@@ -1222,13 +1234,34 @@ function createProjectContext(opts) {
1222
1234
  }
1223
1235
  }
1224
1236
  } catch (e) {}
1225
- cliSessions.listCliSessions(cwd).then(function (sessions) {
1226
- var filtered = sessions.filter(function (s) {
1237
+
1238
+ getSDK().then(function(sdkMod) {
1239
+ return sdkMod.listSessions({ dir: cwd });
1240
+ }).then(function(sdkSessions) {
1241
+ var filtered = sdkSessions.filter(function(s) {
1227
1242
  return !relayIds[s.sessionId];
1243
+ }).map(function(s) {
1244
+ return {
1245
+ sessionId: s.sessionId,
1246
+ firstPrompt: s.summary || s.firstPrompt || "",
1247
+ model: null,
1248
+ gitBranch: s.gitBranch || null,
1249
+ startTime: s.createdAt ? new Date(s.createdAt).toISOString() : null,
1250
+ lastActivity: s.lastModified ? new Date(s.lastModified).toISOString() : null,
1251
+ };
1228
1252
  });
1229
1253
  sendTo(ws, { type: "cli_session_list", sessions: filtered });
1230
- }).catch(function () {
1231
- sendTo(ws, { type: "cli_session_list", sessions: [] });
1254
+ }).catch(function() {
1255
+ // Fallback to manual parsing if SDK fails
1256
+ var cliSessions = require("./cli-sessions");
1257
+ cliSessions.listCliSessions(cwd).then(function(sessions) {
1258
+ var filtered = sessions.filter(function(s) {
1259
+ return !relayIds[s.sessionId];
1260
+ });
1261
+ sendTo(ws, { type: "cli_session_list", sessions: filtered });
1262
+ }).catch(function() {
1263
+ sendTo(ws, { type: "cli_session_list", sessions: [] });
1264
+ });
1232
1265
  });
1233
1266
  return;
1234
1267
  }
@@ -1264,6 +1297,14 @@ function createProjectContext(opts) {
1264
1297
  s.title = String(msg.title).substring(0, 100);
1265
1298
  sm.saveSessionFile(s);
1266
1299
  sm.broadcastSessionList();
1300
+ // Sync title to SDK session
1301
+ if (s.cliSessionId) {
1302
+ getSDK().then(function(sdk) {
1303
+ sdk.renameSession(s.cliSessionId, s.title, { dir: cwd }).catch(function(e) {
1304
+ console.error("[project] SDK renameSession failed:", e.message);
1305
+ });
1306
+ }).catch(function() {});
1307
+ }
1267
1308
  }
1268
1309
  return;
1269
1310
  }
@@ -1388,7 +1429,7 @@ function createProjectContext(opts) {
1388
1429
  if (msg.type === "set_permission_mode" && msg.mode) {
1389
1430
  // When dangerouslySkipPermissions is active, don't allow UI to change mode
1390
1431
  if (dangerouslySkipPermissions) {
1391
- send({ type: "config_state", model: sm.currentModel || "", mode: "bypassPermissions", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1432
+ send({ type: "config_state", model: sm.currentModel || "", mode: "bypassPermissions", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1392
1433
  return;
1393
1434
  }
1394
1435
  sm.currentPermissionMode = msg.mode;
@@ -1396,7 +1437,7 @@ function createProjectContext(opts) {
1396
1437
  if (session) {
1397
1438
  sdk.setPermissionMode(session, msg.mode);
1398
1439
  }
1399
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1440
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1400
1441
  return;
1401
1442
  }
1402
1443
 
@@ -1410,7 +1451,7 @@ function createProjectContext(opts) {
1410
1451
  if (session) {
1411
1452
  sdk.setPermissionMode(session, msg.mode);
1412
1453
  }
1413
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1454
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1414
1455
  }
1415
1456
  return;
1416
1457
  }
@@ -1425,14 +1466,18 @@ function createProjectContext(opts) {
1425
1466
  if (session) {
1426
1467
  sdk.setPermissionMode(session, msg.mode);
1427
1468
  }
1428
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1469
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1429
1470
  }
1430
1471
  return;
1431
1472
  }
1432
1473
 
1433
1474
  if (msg.type === "set_effort" && msg.effort) {
1434
1475
  sm.currentEffort = msg.effort;
1435
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1476
+ var session = getSessionForWs(ws);
1477
+ if (session) {
1478
+ sdk.setEffort(session, msg.effort);
1479
+ }
1480
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1436
1481
  return;
1437
1482
  }
1438
1483
 
@@ -1441,7 +1486,7 @@ function createProjectContext(opts) {
1441
1486
  opts.onSetServerDefaultEffort(msg.effort);
1442
1487
  }
1443
1488
  sm.currentEffort = msg.effort;
1444
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1489
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1445
1490
  return;
1446
1491
  }
1447
1492
 
@@ -1450,13 +1495,20 @@ function createProjectContext(opts) {
1450
1495
  opts.onSetProjectDefaultEffort(slug, msg.effort);
1451
1496
  }
1452
1497
  sm.currentEffort = msg.effort;
1453
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1498
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1454
1499
  return;
1455
1500
  }
1456
1501
 
1457
1502
  if (msg.type === "set_betas") {
1458
1503
  sm.currentBetas = msg.betas || [];
1459
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas });
1504
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas, thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1505
+ return;
1506
+ }
1507
+
1508
+ if (msg.type === "set_thinking") {
1509
+ sm.currentThinking = msg.thinking || "adaptive";
1510
+ if (msg.budgetTokens) sm.currentThinkingBudget = msg.budgetTokens;
1511
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1460
1512
  return;
1461
1513
  }
1462
1514
 
@@ -1557,6 +1609,34 @@ function createProjectContext(opts) {
1557
1609
  return;
1558
1610
  }
1559
1611
 
1612
+ if (msg.type === "fork_session" && msg.uuid) {
1613
+ var session = getSessionForWs(ws);
1614
+ if (!session || !session.cliSessionId) {
1615
+ sendTo(ws, { type: "error", text: "Cannot fork: no CLI session" });
1616
+ return;
1617
+ }
1618
+ var forkCliId = session.cliSessionId;
1619
+ var forkTitle = (session.title || "New Session") + " (fork)";
1620
+ getSDK().then(function(sdkMod) {
1621
+ return sdkMod.forkSession(forkCliId, {
1622
+ upToMessageId: msg.uuid,
1623
+ dir: cwd,
1624
+ });
1625
+ }).then(function(result) {
1626
+ var cliSess = require("./cli-sessions");
1627
+ return cliSess.readCliSessionHistory(cwd, result.sessionId).then(function(history) {
1628
+ var forked = sm.resumeSession(result.sessionId, { history: history, title: forkTitle }, ws);
1629
+ if (forked) {
1630
+ ws._clayActiveSession = forked.localId;
1631
+ sendTo(ws, { type: "fork_complete", sessionId: forked.localId });
1632
+ }
1633
+ });
1634
+ }).catch(function(e) {
1635
+ sendTo(ws, { type: "error", text: "Fork failed: " + (e.message || e) });
1636
+ });
1637
+ return;
1638
+ }
1639
+
1560
1640
  if (msg.type === "ask_user_response") {
1561
1641
  var session = getSessionForWs(ws);
1562
1642
  if (!session) return;
@@ -1591,7 +1671,7 @@ function createProjectContext(opts) {
1591
1671
  if (decision === "allow_accept_edits") {
1592
1672
  sdk.setPermissionMode(session, "acceptEdits");
1593
1673
  sm.currentPermissionMode = "acceptEdits";
1594
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1674
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1595
1675
  pending.resolve({ behavior: "allow", updatedInput: pending.toolInput });
1596
1676
  sm.sendAndRecord(session, { type: "permission_resolved", requestId: requestId, decision: decision });
1597
1677
  return;
@@ -1620,7 +1700,7 @@ function createProjectContext(opts) {
1620
1700
 
1621
1701
  // Update permission mode for the new session
1622
1702
  sm.currentPermissionMode = "acceptEdits";
1623
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [] });
1703
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode, effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
1624
1704
 
1625
1705
  // Build prompt from plan content (sent from client) or plan file path
1626
1706
  var clientPlanContent = msg.planContent || "";
@@ -1713,6 +1793,26 @@ function createProjectContext(opts) {
1713
1793
  return;
1714
1794
  }
1715
1795
 
1796
+ // --- MCP elicitation response ---
1797
+ if (msg.type === "elicitation_response") {
1798
+ var session = getSessionForWs(ws);
1799
+ if (!session) return;
1800
+ var pending = session.pendingElicitations && session.pendingElicitations[msg.requestId];
1801
+ if (!pending) return;
1802
+ delete session.pendingElicitations[msg.requestId];
1803
+ if (msg.action === "accept") {
1804
+ pending.resolve({ action: "accept", content: msg.content || {} });
1805
+ } else {
1806
+ pending.resolve({ action: "reject" });
1807
+ }
1808
+ sm.sendAndRecord(session, {
1809
+ type: "elicitation_resolved",
1810
+ requestId: msg.requestId,
1811
+ action: msg.action,
1812
+ });
1813
+ return;
1814
+ }
1815
+
1716
1816
  // --- Browse directories (for add-project autocomplete) ---
1717
1817
  if (msg.type === "browse_dir") {
1718
1818
  var rawPath = (msg.path || "").replace(/^~/, process.env.HOME || "/");
@@ -2662,6 +2762,14 @@ function createProjectContext(opts) {
2662
2762
  session.title = (msg.text || "Image").substring(0, 50);
2663
2763
  sm.saveSessionFile(session);
2664
2764
  sm.broadcastSessionList();
2765
+ // Sync auto-title to SDK
2766
+ if (session.cliSessionId) {
2767
+ getSDK().then(function(sdk) {
2768
+ sdk.renameSession(session.cliSessionId, session.title, { dir: cwd }).catch(function(e) {
2769
+ console.error("[project] SDK renameSession failed:", e.message);
2770
+ });
2771
+ }).catch(function() {});
2772
+ }
2665
2773
  }
2666
2774
 
2667
2775
  var fullText = msg.text || "";
@@ -3162,6 +3270,8 @@ function createProjectContext(opts) {
3162
3270
  },
3163
3271
  warmup: function () {
3164
3272
  sdk.warmup();
3273
+ // Migrate existing relay session titles to SDK format (one-time, async)
3274
+ sm.migrateSessionTitles(getSDK, cwd);
3165
3275
  },
3166
3276
  destroy: destroy,
3167
3277
  };
package/lib/public/app.js CHANGED
@@ -10,7 +10,7 @@ import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFs
10
10
  import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
11
11
  import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen } from './modules/sticky-notes.js';
12
12
  import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme } from './modules/theme.js';
13
- import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
13
+ import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
14
14
  import { initServerSettings, updateSettingsStats, updateSettingsModels, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './modules/server-settings.js';
15
15
  import { initProjectSettings, handleInstructionsRead, handleInstructionsWrite, handleProjectEnv, handleProjectEnvSaved, isProjectSettingsOpen, handleProjectSharedEnv, handleProjectSharedEnvSaved } from './modules/project-settings.js';
16
16
  import { initSkills, handleSkillInstalled, handleSkillUninstalled } from './modules/skills.js';
@@ -1162,9 +1162,11 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1162
1162
 
1163
1163
  var confirmCallback = null;
1164
1164
 
1165
- function showConfirm(text, onConfirm) {
1165
+ function showConfirm(text, onConfirm, okLabel, destructive) {
1166
1166
  confirmText.textContent = text;
1167
1167
  confirmCallback = onConfirm;
1168
+ confirmOk.textContent = okLabel || "Delete";
1169
+ confirmOk.className = "confirm-btn " + (destructive === false ? "confirm-ok" : "confirm-delete");
1168
1170
  confirmModal.classList.remove("hidden");
1169
1171
  }
1170
1172
 
@@ -1463,11 +1465,18 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1463
1465
  var configBetaSection = $("config-beta-section");
1464
1466
  var configBeta1mBtn = $("config-beta-1m");
1465
1467
 
1468
+ var configThinkingSection = $("config-thinking-section");
1469
+ var configThinkingBar = $("config-thinking-bar");
1470
+ var configThinkingBudgetRow = $("config-thinking-budget-row");
1471
+ var configThinkingBudgetInput = $("config-thinking-budget");
1472
+
1466
1473
  var currentModels = [];
1467
1474
  var currentModel = "";
1468
1475
  var currentMode = "default";
1469
1476
  var currentEffort = "medium";
1470
1477
  var currentBetas = [];
1478
+ var currentThinking = "adaptive";
1479
+ var currentThinkingBudget = 10000;
1471
1480
  var skipPermsEnabled = false;
1472
1481
 
1473
1482
  var MODE_OPTIONS = [
@@ -1478,6 +1487,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1478
1487
  var MODE_FULL_AUTO = { value: "bypassPermissions", label: "Full auto" };
1479
1488
 
1480
1489
  var EFFORT_LEVELS = ["low", "medium", "high", "max"];
1490
+ var THINKING_OPTIONS = ["disabled", "adaptive", "budget"];
1481
1491
 
1482
1492
  function modelDisplayName(value, models) {
1483
1493
  if (!value) return "";
@@ -1503,6 +1513,13 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1503
1513
  return value.charAt(0).toUpperCase() + value.slice(1);
1504
1514
  }
1505
1515
 
1516
+ function thinkingDisplayName(value) {
1517
+ if (value === "disabled") return "Off";
1518
+ if (value === "adaptive") return "Adaptive";
1519
+ if (value === "budget") return "Budget";
1520
+ return value || "Adaptive";
1521
+ }
1522
+
1506
1523
  function isSonnetModel(model) {
1507
1524
  if (!model) return false;
1508
1525
  var lower = model.toLowerCase();
@@ -1526,6 +1543,9 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1526
1543
  if (modelSupportsEffort) {
1527
1544
  parts.push(effortDisplayName(currentEffort));
1528
1545
  }
1546
+ if (currentThinking && currentThinking !== "adaptive") {
1547
+ parts.push(thinkingDisplayName(currentThinking));
1548
+ }
1529
1549
  if (hasBeta("context-1m")) {
1530
1550
  parts.push("1M");
1531
1551
  }
@@ -1533,6 +1553,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1533
1553
  rebuildModelList();
1534
1554
  rebuildModeList();
1535
1555
  rebuildEffortBar();
1556
+ rebuildThinkingSection();
1536
1557
  rebuildBetaSection();
1537
1558
  }
1538
1559
 
@@ -1653,6 +1674,51 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1653
1674
  configBeta1mBtn.setAttribute("aria-checked", active ? "true" : "false");
1654
1675
  }
1655
1676
 
1677
+ function rebuildThinkingSection() {
1678
+ if (!configThinkingBar || !configThinkingSection) return;
1679
+ configThinkingSection.style.display = "";
1680
+ configThinkingBar.innerHTML = "";
1681
+ for (var i = 0; i < THINKING_OPTIONS.length; i++) {
1682
+ var opt = THINKING_OPTIONS[i];
1683
+ var btn = document.createElement("button");
1684
+ btn.className = "config-segment-btn";
1685
+ if (opt === currentThinking) btn.classList.add("active");
1686
+ btn.dataset.thinking = opt;
1687
+ btn.textContent = thinkingDisplayName(opt);
1688
+ btn.addEventListener("click", function () {
1689
+ var thinking = this.dataset.thinking;
1690
+ var msg = { type: "set_thinking", thinking: thinking };
1691
+ if (thinking === "budget") {
1692
+ msg.budgetTokens = currentThinkingBudget;
1693
+ }
1694
+ if (ws && ws.readyState === 1) {
1695
+ ws.send(JSON.stringify(msg));
1696
+ }
1697
+ });
1698
+ configThinkingBar.appendChild(btn);
1699
+ }
1700
+ // Show/hide budget input
1701
+ if (configThinkingBudgetRow) {
1702
+ configThinkingBudgetRow.style.display = currentThinking === "budget" ? "" : "none";
1703
+ }
1704
+ if (configThinkingBudgetInput) {
1705
+ configThinkingBudgetInput.value = currentThinkingBudget;
1706
+ }
1707
+ }
1708
+
1709
+ if (configThinkingBudgetInput) {
1710
+ configThinkingBudgetInput.addEventListener("change", function () {
1711
+ var val = parseInt(this.value, 10);
1712
+ if (isNaN(val) || val < 1024) val = 1024;
1713
+ if (val > 128000) val = 128000;
1714
+ currentThinkingBudget = val;
1715
+ this.value = val;
1716
+ if (ws && ws.readyState === 1) {
1717
+ ws.send(JSON.stringify({ type: "set_thinking", thinking: "budget", budgetTokens: val }));
1718
+ }
1719
+ });
1720
+ }
1721
+
1656
1722
  configBeta1mBtn.addEventListener("click", function (e) {
1657
1723
  e.stopPropagation();
1658
1724
  var active = hasBeta("context-1m");
@@ -2038,6 +2104,20 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2038
2104
  forceScrollToBottom();
2039
2105
  });
2040
2106
 
2107
+ // Fork session from a user message
2108
+ messagesEl.addEventListener("click", function(e) {
2109
+ var btn = e.target.closest(".msg-action-fork");
2110
+ if (!btn) return;
2111
+ var msgEl = btn.closest("[data-uuid]");
2112
+ if (!msgEl || !msgEl.dataset.uuid) return;
2113
+ var forkUuid = msgEl.dataset.uuid;
2114
+ showConfirm("Fork session from this message?", function() {
2115
+ if (ws && ws.readyState === 1) {
2116
+ ws.send(JSON.stringify({ type: "fork_session", uuid: forkUuid }));
2117
+ }
2118
+ }, "Fork", false);
2119
+ });
2120
+
2041
2121
  function scrollToBottom() {
2042
2122
  if (prependAnchor) return;
2043
2123
  if (isUserScrolledUp) {
@@ -2145,7 +2225,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2145
2225
  actions.innerHTML =
2146
2226
  '<span class="msg-action-time">' + timeStr + '</span>' +
2147
2227
  '<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' + iconHtml("copy") + '</button>' +
2148
- '<button class="msg-action-btn msg-action-hidden msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
2228
+ '<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
2149
2229
  '<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' +
2150
2230
  '<button class="msg-action-btn msg-action-hidden msg-action-edit" type="button" title="Edit">' + iconHtml("pencil") + '</button>';
2151
2231
  div.appendChild(actions);
@@ -2893,6 +2973,8 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2893
2973
  if (msg.mode) currentMode = msg.mode;
2894
2974
  if (msg.effort) currentEffort = msg.effort;
2895
2975
  if (msg.betas) currentBetas = msg.betas;
2976
+ if (msg.thinking) currentThinking = msg.thinking;
2977
+ if (msg.thinkingBudget) currentThinkingBudget = msg.thinkingBudget;
2896
2978
  // Validate effort against current model's supported levels
2897
2979
  if (currentModels.length > 0) {
2898
2980
  var levels = getModelEffortLevels();
@@ -3181,6 +3263,16 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3181
3263
  startUrgentBlink();
3182
3264
  break;
3183
3265
 
3266
+ case "elicitation_request":
3267
+ renderElicitationRequest(msg);
3268
+ startUrgentBlink();
3269
+ break;
3270
+
3271
+ case "elicitation_resolved":
3272
+ markElicitationResolved(msg.requestId, msg.action);
3273
+ stopUrgentBlink();
3274
+ break;
3275
+
3184
3276
  case "slash_command_result":
3185
3277
  finalizeAssistantBlock();
3186
3278
  var cmdBlock = document.createElement("div");
@@ -3213,7 +3305,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3213
3305
  break;
3214
3306
 
3215
3307
  case "task_progress":
3216
- updateSubagentProgress(msg.parentToolId, msg.usage, msg.lastToolName);
3308
+ updateSubagentProgress(msg.parentToolId, msg.usage, msg.lastToolName, msg.summary);
3217
3309
  break;
3218
3310
 
3219
3311
  case "result":
@@ -3296,6 +3388,10 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3296
3388
  addSystemMessage(msg.text || "Rewind failed.", true);
3297
3389
  break;
3298
3390
 
3391
+ case "fork_complete":
3392
+ addSystemMessage("Session forked successfully.");
3393
+ break;
3394
+
3299
3395
  case "fs_list_result":
3300
3396
  handleFsList(msg);
3301
3397
  break;
@@ -617,6 +617,29 @@
617
617
  background: var(--accent);
618
618
  }
619
619
 
620
+ .config-budget-row {
621
+ padding: 4px 14px 8px;
622
+ display: flex;
623
+ align-items: center;
624
+ gap: 8px;
625
+ }
626
+
627
+ .config-budget-label {
628
+ font-size: 11px;
629
+ color: var(--text-muted);
630
+ white-space: nowrap;
631
+ }
632
+
633
+ .config-budget-input {
634
+ width: 80px;
635
+ padding: 4px 6px;
636
+ border: 1px solid var(--border);
637
+ border-radius: 4px;
638
+ background: var(--bg);
639
+ color: var(--text);
640
+ font-size: 11px;
641
+ }
642
+
620
643
  /* --- Info panels container --- */
621
644
  #info-panels {
622
645
  position: fixed;
@@ -984,6 +984,14 @@ pre.mermaid-error {
984
984
  color: var(--text-dimmer);
985
985
  }
986
986
 
987
+ .subagent-summary {
988
+ margin: 2px 0 2px 24px;
989
+ padding: 2px 12px;
990
+ font-size: 12px;
991
+ color: var(--text-muted);
992
+ font-style: italic;
993
+ }
994
+
987
995
  .subagent-stop-btn {
988
996
  margin-left: auto;
989
997
  padding: 2px 10px;
@@ -336,6 +336,15 @@
336
336
  <div class="config-section-label">EFFORT</div>
337
337
  <div id="config-effort-bar" class="config-segmented"></div>
338
338
  </div>
339
+ <div id="config-thinking-section" class="config-section">
340
+ <div class="config-section-label">THINKING</div>
341
+ <div id="config-thinking-bar" class="config-segmented"></div>
342
+ <div id="config-thinking-budget-row" class="config-budget-row" style="display:none">
343
+ <label class="config-budget-label">Budget tokens</label>
344
+ <input id="config-thinking-budget" type="number" class="config-budget-input"
345
+ min="1024" max="128000" step="1024" value="10000">
346
+ </div>
347
+ </div>
339
348
  <div id="config-beta-section" class="config-section" style="display:none">
340
349
  <div class="config-section-label">BETA</div>
341
350
  <div class="config-toggle-row">
@@ -693,6 +693,207 @@ export function markPermissionCancelled(requestId) {
693
693
  delete pendingPermissions[requestId];
694
694
  }
695
695
 
696
+ // --- MCP elicitation rendering ---
697
+
698
+ var pendingElicitations = {};
699
+
700
+ export function renderElicitationRequest(msg) {
701
+ if (pendingElicitations[msg.requestId]) return;
702
+ ctx.finalizeAssistantBlock();
703
+ stopThinking();
704
+ closeToolGroup();
705
+
706
+ var container = document.createElement("div");
707
+ container.className = "permission-container elicitation-container";
708
+ container.dataset.requestId = msg.requestId;
709
+
710
+ // Header
711
+ var header = document.createElement("div");
712
+ header.className = "permission-header";
713
+ header.innerHTML =
714
+ '<span class="permission-icon">' + iconHtml("key") + '</span>' +
715
+ '<span class="permission-title">' + escapeHtml(msg.serverName || "MCP Server") + ' requests input</span>';
716
+
717
+ // Body
718
+ var body = document.createElement("div");
719
+ body.className = "permission-body";
720
+
721
+ if (msg.message) {
722
+ var messageEl = document.createElement("div");
723
+ messageEl.className = "permission-reason";
724
+ messageEl.textContent = msg.message;
725
+ body.appendChild(messageEl);
726
+ }
727
+
728
+ // Form fields (form mode) or URL button (url mode)
729
+ var formData = {};
730
+
731
+ if (msg.mode === "url" && msg.url) {
732
+ var urlInfo = document.createElement("div");
733
+ urlInfo.className = "elicitation-url-info";
734
+ urlInfo.style.cssText = "margin-top: 8px; font-size: 12px; color: var(--text-muted);";
735
+ urlInfo.textContent = "Opens: " + msg.url;
736
+ body.appendChild(urlInfo);
737
+ } else if (msg.requestedSchema && msg.requestedSchema.properties) {
738
+ var formEl = document.createElement("div");
739
+ formEl.className = "elicitation-form";
740
+ formEl.style.cssText = "margin-top: 8px; display: flex; flex-direction: column; gap: 8px;";
741
+
742
+ var props = msg.requestedSchema.properties;
743
+ var required = msg.requestedSchema.required || [];
744
+ var propNames = Object.keys(props);
745
+ for (var i = 0; i < propNames.length; i++) {
746
+ var propName = propNames[i];
747
+ var prop = props[propName];
748
+ var isRequired = required.indexOf(propName) !== -1;
749
+
750
+ var fieldWrapper = document.createElement("div");
751
+ fieldWrapper.style.cssText = "display: flex; flex-direction: column; gap: 2px;";
752
+
753
+ var label = document.createElement("label");
754
+ label.style.cssText = "font-size: 12px; font-weight: 500; color: var(--text-secondary);";
755
+ label.textContent = propName + (isRequired ? " *" : "");
756
+ if (prop.description) {
757
+ label.title = prop.description;
758
+ }
759
+
760
+ var input;
761
+ if (prop.type === "boolean") {
762
+ input = document.createElement("input");
763
+ input.type = "checkbox";
764
+ input.dataset.propName = propName;
765
+ input.dataset.propType = "boolean";
766
+ } else if (prop.enum) {
767
+ input = document.createElement("select");
768
+ input.dataset.propName = propName;
769
+ input.dataset.propType = "enum";
770
+ input.style.cssText = "padding: 4px 8px; border-radius: 4px; border: 1px solid var(--border); background: var(--input-bg); color: var(--text-primary); font-size: 13px;";
771
+ for (var ei = 0; ei < prop.enum.length; ei++) {
772
+ var opt = document.createElement("option");
773
+ opt.value = prop.enum[ei];
774
+ opt.textContent = prop.enum[ei];
775
+ input.appendChild(opt);
776
+ }
777
+ } else {
778
+ input = document.createElement("input");
779
+ input.type = prop.type === "number" || prop.type === "integer" ? "number" : "text";
780
+ input.dataset.propName = propName;
781
+ input.dataset.propType = prop.type || "string";
782
+ input.placeholder = prop.description || propName;
783
+ input.style.cssText = "padding: 4px 8px; border-radius: 4px; border: 1px solid var(--border); background: var(--input-bg); color: var(--text-primary); font-size: 13px;";
784
+ }
785
+
786
+ fieldWrapper.appendChild(label);
787
+ fieldWrapper.appendChild(input);
788
+ formEl.appendChild(fieldWrapper);
789
+ }
790
+ body.appendChild(formEl);
791
+ }
792
+
793
+ // Actions
794
+ var actions = document.createElement("div");
795
+ actions.className = "permission-actions";
796
+
797
+ var acceptBtn = document.createElement("button");
798
+ acceptBtn.className = "permission-btn permission-allow";
799
+
800
+ if (msg.mode === "url" && msg.url) {
801
+ acceptBtn.textContent = "Open & Approve";
802
+ acceptBtn.addEventListener("click", function () {
803
+ window.open(msg.url, "_blank");
804
+ sendElicitationResponse(container, msg.requestId, "accept", {});
805
+ });
806
+ } else {
807
+ acceptBtn.textContent = "Submit";
808
+ acceptBtn.addEventListener("click", function () {
809
+ // Collect form values
810
+ var content = {};
811
+ var inputs = container.querySelectorAll("[data-prop-name]");
812
+ for (var j = 0; j < inputs.length; j++) {
813
+ var inp = inputs[j];
814
+ var name = inp.dataset.propName;
815
+ var pType = inp.dataset.propType;
816
+ if (pType === "boolean") {
817
+ content[name] = inp.checked;
818
+ } else if (pType === "number" || pType === "integer") {
819
+ content[name] = Number(inp.value);
820
+ } else {
821
+ content[name] = inp.value;
822
+ }
823
+ }
824
+ sendElicitationResponse(container, msg.requestId, "accept", content);
825
+ });
826
+ }
827
+
828
+ var denyBtn = document.createElement("button");
829
+ denyBtn.className = "permission-btn permission-deny";
830
+ denyBtn.textContent = "Deny";
831
+ denyBtn.addEventListener("click", function () {
832
+ sendElicitationResponse(container, msg.requestId, "reject", null);
833
+ });
834
+
835
+ actions.appendChild(acceptBtn);
836
+ actions.appendChild(denyBtn);
837
+
838
+ container.appendChild(header);
839
+ container.appendChild(body);
840
+ container.appendChild(actions);
841
+ ctx.addToMessages(container);
842
+
843
+ pendingElicitations[msg.requestId] = container;
844
+ refreshIcons();
845
+ ctx.setActivity(null);
846
+ ctx.scrollToBottom();
847
+ }
848
+
849
+ function sendElicitationResponse(container, requestId, action, content) {
850
+ if (container.classList.contains("resolved")) return;
851
+ container.classList.add("resolved");
852
+ if (ctx.stopUrgentBlink) ctx.stopUrgentBlink();
853
+
854
+ var label = action === "reject" ? "Denied" : "Submitted";
855
+ var resolvedClass = action === "reject" ? "resolved-denied" : "resolved-allowed";
856
+ container.classList.add(resolvedClass);
857
+
858
+ var actions = container.querySelector(".permission-actions");
859
+ if (actions) {
860
+ actions.innerHTML = '<span class="permission-decision-label">' + label + '</span>';
861
+ }
862
+
863
+ if (ctx.ws && ctx.connected) {
864
+ var msg = {
865
+ type: "elicitation_response",
866
+ requestId: requestId,
867
+ action: action,
868
+ };
869
+ if (action === "accept" && content) {
870
+ msg.content = content;
871
+ }
872
+ ctx.ws.send(JSON.stringify(msg));
873
+ }
874
+
875
+ delete pendingElicitations[requestId];
876
+ }
877
+
878
+ export function markElicitationResolved(requestId, action) {
879
+ var container = pendingElicitations[requestId];
880
+ if (!container) {
881
+ container = ctx.messagesEl.querySelector('.elicitation-container[data-request-id="' + requestId + '"]');
882
+ }
883
+ if (!container || container.classList.contains("resolved")) return;
884
+
885
+ container.classList.add("resolved");
886
+ var isDeny = action === "reject";
887
+ container.classList.add(isDeny ? "resolved-denied" : "resolved-allowed");
888
+
889
+ var label = isDeny ? "Denied" : "Submitted";
890
+ var actionsEl = container.querySelector(".permission-actions");
891
+ if (actionsEl) {
892
+ actionsEl.innerHTML = '<span class="permission-decision-label">' + label + '</span>';
893
+ }
894
+ delete pendingElicitations[requestId];
895
+ }
896
+
696
897
  // --- Plan mode rendering ---
697
898
  export function renderPlanBanner(type) {
698
899
  ctx.finalizeAssistantBlock();
@@ -1504,7 +1705,7 @@ function fmtDuration(ms) {
1504
1705
  return secs + "s";
1505
1706
  }
1506
1707
 
1507
- export function updateSubagentProgress(parentToolId, usage, lastToolName) {
1708
+ export function updateSubagentProgress(parentToolId, usage, lastToolName, summary) {
1508
1709
  var tool = tools[parentToolId];
1509
1710
  if (!tool || !tool.el) return;
1510
1711
  var progressEl = tool.el.querySelector(".subagent-progress");
@@ -1523,6 +1724,17 @@ export function updateSubagentProgress(parentToolId, usage, lastToolName) {
1523
1724
  }
1524
1725
  if (lastToolName) parts.push(lastToolName);
1525
1726
  progressEl.textContent = parts.join(" · ");
1727
+
1728
+ // AI-generated progress summary (agentProgressSummaries)
1729
+ if (summary) {
1730
+ var summaryEl = tool.el.querySelector(".subagent-summary");
1731
+ if (!summaryEl) {
1732
+ summaryEl = document.createElement("div");
1733
+ summaryEl.className = "subagent-summary";
1734
+ progressEl.parentNode.insertBefore(summaryEl, progressEl.nextSibling);
1735
+ }
1736
+ summaryEl.textContent = summary;
1737
+ }
1526
1738
  }
1527
1739
 
1528
1740
  export function initSubagentStop(parentToolId, taskId) {
@@ -1640,6 +1852,7 @@ export function resetToolState() {
1640
1852
  todoWidgetVisible = true;
1641
1853
  if (todoObserver) { todoObserver.disconnect(); todoObserver = null; }
1642
1854
  pendingPermissions = {};
1855
+ pendingElicitations = {};
1643
1856
  currentToolGroup = null;
1644
1857
  toolGroupCounter = 0;
1645
1858
  toolGroups = {};
package/lib/sdk-bridge.js CHANGED
@@ -314,6 +314,7 @@ function createSDKBridge(opts) {
314
314
  session.blocks = {};
315
315
  session.sentToolResults = {};
316
316
  session.pendingPermissions = {};
317
+ session.pendingElicitations = {};
317
318
  // Record ask_user_answered for any leftover pending questions so replay pairs correctly
318
319
  var leftoverAskIds = Object.keys(session.pendingAskUser);
319
320
  for (var lai = 0; lai < leftoverAskIds.length; lai++) {
@@ -386,6 +387,7 @@ function createSDKBridge(opts) {
386
387
  usage: parsed.usage || null,
387
388
  lastToolName: parsed.last_tool_name || null,
388
389
  description: parsed.description || "",
390
+ summary: parsed.summary || null,
389
391
  });
390
392
  }
391
393
 
@@ -494,6 +496,51 @@ function createSDKBridge(opts) {
494
496
  // user messages with parent_tool_use_id contain tool_results — skip silently
495
497
  }
496
498
 
499
+ // --- MCP elicitation ---
500
+
501
+ function handleElicitation(session, request, opts) {
502
+ // Ralph Loop: auto-reject elicitation in autonomous mode
503
+ if (session.loop && session.loop.active && session.loop.role !== "crafting") {
504
+ return Promise.resolve({ action: "reject" });
505
+ }
506
+
507
+ return new Promise(function(resolve) {
508
+ var requestId = crypto.randomUUID();
509
+ if (!session.pendingElicitations) session.pendingElicitations = {};
510
+ session.pendingElicitations[requestId] = {
511
+ resolve: resolve,
512
+ request: request,
513
+ };
514
+ sendAndRecord(session, {
515
+ type: "elicitation_request",
516
+ requestId: requestId,
517
+ serverName: request.serverName,
518
+ message: request.message,
519
+ mode: request.mode || "form",
520
+ url: request.url || null,
521
+ elicitationId: request.elicitationId || null,
522
+ requestedSchema: request.requestedSchema || null,
523
+ });
524
+
525
+ if (pushModule) {
526
+ pushModule.sendPush({
527
+ type: "elicitation",
528
+ slug: slug,
529
+ title: (request.serverName || "MCP Server") + " needs input",
530
+ body: request.message || "Waiting for your response",
531
+ tag: "claude-elicitation",
532
+ });
533
+ }
534
+
535
+ if (opts.signal) {
536
+ opts.signal.addEventListener("abort", function() {
537
+ delete session.pendingElicitations[requestId];
538
+ resolve({ action: "reject" });
539
+ });
540
+ }
541
+ });
542
+ }
543
+
497
544
  // --- SDK query lifecycle ---
498
545
 
499
546
  function handleCanUseTool(session, toolName, input, opts) {
@@ -710,6 +757,7 @@ function createSDKBridge(opts) {
710
757
  session.taskStopRequested = false;
711
758
  session.pendingPermissions = {};
712
759
  session.pendingAskUser = {};
760
+ session.pendingElicitations = {};
713
761
  }
714
762
  // Ralph Loop: notify completion so loop orchestrator can proceed
715
763
  if (session.onQueryComplete) {
@@ -773,6 +821,7 @@ function createSDKBridge(opts) {
773
821
  session.blocks = {};
774
822
  session.sentToolResults = {};
775
823
  session.activeTaskToolIds = {};
824
+ session.pendingElicitations = {};
776
825
  session.streamedText = false;
777
826
  session.responsePreview = "";
778
827
 
@@ -805,9 +854,13 @@ function createSDKBridge(opts) {
805
854
  extraArgs: { "replay-user-messages": null },
806
855
  abortController: session.abortController,
807
856
  promptSuggestions: true,
857
+ agentProgressSummaries: true,
808
858
  canUseTool: function(toolName, input, toolOpts) {
809
859
  return handleCanUseTool(session, toolName, input, toolOpts);
810
860
  },
861
+ onElicitation: function(request, elicitOpts) {
862
+ return handleElicitation(session, request, elicitOpts);
863
+ },
811
864
  };
812
865
 
813
866
  if (sm.currentModel) {
@@ -822,6 +875,12 @@ function createSDKBridge(opts) {
822
875
  queryOptions.betas = sm.currentBetas;
823
876
  }
824
877
 
878
+ if (sm.currentThinking === "disabled") {
879
+ queryOptions.thinking = { type: "disabled" };
880
+ } else if (sm.currentThinking === "budget" && sm.currentThinkingBudget) {
881
+ queryOptions.thinking = { type: "enabled", budgetTokens: sm.currentThinkingBudget };
882
+ }
883
+
825
884
  if (dangerouslySkipPermissions) {
826
885
  queryOptions.permissionMode = "bypassPermissions";
827
886
  queryOptions.allowDangerouslySkipPermissions = true;
@@ -1009,6 +1068,21 @@ function createSDKBridge(opts) {
1009
1068
  }
1010
1069
  }
1011
1070
 
1071
+ async function setEffort(session, effort) {
1072
+ if (!session.queryInstance) {
1073
+ sm.currentEffort = effort;
1074
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1075
+ return;
1076
+ }
1077
+ try {
1078
+ await session.queryInstance.setEffort(effort);
1079
+ sm.currentEffort = effort;
1080
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1081
+ } catch (e) {
1082
+ send({ type: "error", text: "Failed to set effort: " + (e.message || e) });
1083
+ }
1084
+ }
1085
+
1012
1086
  async function setPermissionMode(session, mode) {
1013
1087
  // When dangerouslySkipPermissions is active, ignore mode changes from UI
1014
1088
  // to prevent accidentally downgrading from bypassPermissions
@@ -1051,11 +1125,13 @@ function createSDKBridge(opts) {
1051
1125
  createMessageQueue: createMessageQueue,
1052
1126
  processSDKMessage: processSDKMessage,
1053
1127
  handleCanUseTool: handleCanUseTool,
1128
+ handleElicitation: handleElicitation,
1054
1129
  processQueryStream: processQueryStream,
1055
1130
  getOrCreateRewindQuery: getOrCreateRewindQuery,
1056
1131
  startQuery: startQuery,
1057
1132
  pushMessage: pushMessage,
1058
1133
  setModel: setModel,
1134
+ setEffort: setEffort,
1059
1135
  setPermissionMode: setPermissionMode,
1060
1136
  isClaudeProcess: isClaudeProcess,
1061
1137
  permissionPushTitle: permissionPushTitle,
package/lib/sessions.js CHANGED
@@ -508,6 +508,31 @@ function createSessionManager(opts) {
508
508
  return results;
509
509
  }
510
510
 
511
+ function migrateSessionTitles(getSDK, migrateCwd) {
512
+ var toMigrate = [];
513
+ sessions.forEach(function(s) {
514
+ if (s.cliSessionId && s.title && s.title !== "New Session" && s.title !== "Resumed session") {
515
+ toMigrate.push({ cliSessionId: s.cliSessionId, title: s.title });
516
+ }
517
+ });
518
+ if (toMigrate.length === 0) return;
519
+ getSDK().then(function(sdkMod) {
520
+ var chain = Promise.resolve();
521
+ for (var i = 0; i < toMigrate.length; i++) {
522
+ (function(item) {
523
+ chain = chain.then(function() {
524
+ return sdkMod.renameSession(item.cliSessionId, item.title, { dir: migrateCwd }).catch(function(e) {
525
+ console.error("[session] Migration failed for " + item.cliSessionId + ":", e.message);
526
+ });
527
+ });
528
+ })(toMigrate[i]);
529
+ }
530
+ chain.then(function() {
531
+ console.log("[session] Migrated " + toMigrate.length + " session title(s) to SDK format");
532
+ });
533
+ }).catch(function() {});
534
+ }
535
+
511
536
  return {
512
537
  get activeSessionId() { return activeSessionId; },
513
538
  get nextLocalId() { return nextLocalId; },
@@ -532,6 +557,7 @@ function createSessionManager(opts) {
532
557
  replayHistory: replayHistory,
533
558
  searchSessions: searchSessions,
534
559
  setResolveLoopInfo: setResolveLoopInfo,
560
+ migrateSessionTitles: migrateSessionTitles,
535
561
  setSessionVisibility: function (localId, visibility) {
536
562
  var session = sessions.get(localId);
537
563
  if (!session) return { error: "Session not found" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.11.0-beta.1",
3
+ "version": "2.11.0-beta.3",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",
@@ -36,7 +36,7 @@
36
36
  "homepage": "https://github.com/chadbyte/claude-relay#readme",
37
37
  "author": "Chad",
38
38
  "dependencies": {
39
- "@anthropic-ai/claude-agent-sdk": "^0.2.63",
39
+ "@anthropic-ai/claude-agent-sdk": "^0.2.76",
40
40
  "@lydell/node-pty": "^1.2.0-beta.3",
41
41
  "nodemailer": "^6.10.1",
42
42
  "qrcode-terminal": "^0.12.0",