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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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';
@@ -1463,11 +1463,18 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1463
1463
  var configBetaSection = $("config-beta-section");
1464
1464
  var configBeta1mBtn = $("config-beta-1m");
1465
1465
 
1466
+ var configThinkingSection = $("config-thinking-section");
1467
+ var configThinkingBar = $("config-thinking-bar");
1468
+ var configThinkingBudgetRow = $("config-thinking-budget-row");
1469
+ var configThinkingBudgetInput = $("config-thinking-budget");
1470
+
1466
1471
  var currentModels = [];
1467
1472
  var currentModel = "";
1468
1473
  var currentMode = "default";
1469
1474
  var currentEffort = "medium";
1470
1475
  var currentBetas = [];
1476
+ var currentThinking = "adaptive";
1477
+ var currentThinkingBudget = 10000;
1471
1478
  var skipPermsEnabled = false;
1472
1479
 
1473
1480
  var MODE_OPTIONS = [
@@ -1478,6 +1485,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1478
1485
  var MODE_FULL_AUTO = { value: "bypassPermissions", label: "Full auto" };
1479
1486
 
1480
1487
  var EFFORT_LEVELS = ["low", "medium", "high", "max"];
1488
+ var THINKING_OPTIONS = ["disabled", "adaptive", "budget"];
1481
1489
 
1482
1490
  function modelDisplayName(value, models) {
1483
1491
  if (!value) return "";
@@ -1503,6 +1511,13 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1503
1511
  return value.charAt(0).toUpperCase() + value.slice(1);
1504
1512
  }
1505
1513
 
1514
+ function thinkingDisplayName(value) {
1515
+ if (value === "disabled") return "Off";
1516
+ if (value === "adaptive") return "Adaptive";
1517
+ if (value === "budget") return "Budget";
1518
+ return value || "Adaptive";
1519
+ }
1520
+
1506
1521
  function isSonnetModel(model) {
1507
1522
  if (!model) return false;
1508
1523
  var lower = model.toLowerCase();
@@ -1526,6 +1541,9 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1526
1541
  if (modelSupportsEffort) {
1527
1542
  parts.push(effortDisplayName(currentEffort));
1528
1543
  }
1544
+ if (currentThinking && currentThinking !== "adaptive") {
1545
+ parts.push(thinkingDisplayName(currentThinking));
1546
+ }
1529
1547
  if (hasBeta("context-1m")) {
1530
1548
  parts.push("1M");
1531
1549
  }
@@ -1533,6 +1551,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1533
1551
  rebuildModelList();
1534
1552
  rebuildModeList();
1535
1553
  rebuildEffortBar();
1554
+ rebuildThinkingSection();
1536
1555
  rebuildBetaSection();
1537
1556
  }
1538
1557
 
@@ -1653,6 +1672,51 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
1653
1672
  configBeta1mBtn.setAttribute("aria-checked", active ? "true" : "false");
1654
1673
  }
1655
1674
 
1675
+ function rebuildThinkingSection() {
1676
+ if (!configThinkingBar || !configThinkingSection) return;
1677
+ configThinkingSection.style.display = "";
1678
+ configThinkingBar.innerHTML = "";
1679
+ for (var i = 0; i < THINKING_OPTIONS.length; i++) {
1680
+ var opt = THINKING_OPTIONS[i];
1681
+ var btn = document.createElement("button");
1682
+ btn.className = "config-segment-btn";
1683
+ if (opt === currentThinking) btn.classList.add("active");
1684
+ btn.dataset.thinking = opt;
1685
+ btn.textContent = thinkingDisplayName(opt);
1686
+ btn.addEventListener("click", function () {
1687
+ var thinking = this.dataset.thinking;
1688
+ var msg = { type: "set_thinking", thinking: thinking };
1689
+ if (thinking === "budget") {
1690
+ msg.budgetTokens = currentThinkingBudget;
1691
+ }
1692
+ if (ws && ws.readyState === 1) {
1693
+ ws.send(JSON.stringify(msg));
1694
+ }
1695
+ });
1696
+ configThinkingBar.appendChild(btn);
1697
+ }
1698
+ // Show/hide budget input
1699
+ if (configThinkingBudgetRow) {
1700
+ configThinkingBudgetRow.style.display = currentThinking === "budget" ? "" : "none";
1701
+ }
1702
+ if (configThinkingBudgetInput) {
1703
+ configThinkingBudgetInput.value = currentThinkingBudget;
1704
+ }
1705
+ }
1706
+
1707
+ if (configThinkingBudgetInput) {
1708
+ configThinkingBudgetInput.addEventListener("change", function () {
1709
+ var val = parseInt(this.value, 10);
1710
+ if (isNaN(val) || val < 1024) val = 1024;
1711
+ if (val > 128000) val = 128000;
1712
+ currentThinkingBudget = val;
1713
+ this.value = val;
1714
+ if (ws && ws.readyState === 1) {
1715
+ ws.send(JSON.stringify({ type: "set_thinking", thinking: "budget", budgetTokens: val }));
1716
+ }
1717
+ });
1718
+ }
1719
+
1656
1720
  configBeta1mBtn.addEventListener("click", function (e) {
1657
1721
  e.stopPropagation();
1658
1722
  var active = hasBeta("context-1m");
@@ -2038,6 +2102,18 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2038
2102
  forceScrollToBottom();
2039
2103
  });
2040
2104
 
2105
+ // Fork session from a user message
2106
+ messagesEl.addEventListener("click", function(e) {
2107
+ var btn = e.target.closest(".msg-action-fork");
2108
+ if (!btn) return;
2109
+ var msgEl = btn.closest("[data-uuid]");
2110
+ if (!msgEl || !msgEl.dataset.uuid) return;
2111
+ if (!confirm("Fork session from this message?")) return;
2112
+ if (ws && ws.readyState === 1) {
2113
+ ws.send(JSON.stringify({ type: "fork_session", uuid: msgEl.dataset.uuid }));
2114
+ }
2115
+ });
2116
+
2041
2117
  function scrollToBottom() {
2042
2118
  if (prependAnchor) return;
2043
2119
  if (isUserScrolledUp) {
@@ -2145,7 +2221,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2145
2221
  actions.innerHTML =
2146
2222
  '<span class="msg-action-time">' + timeStr + '</span>' +
2147
2223
  '<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>' +
2224
+ '<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
2149
2225
  '<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' +
2150
2226
  '<button class="msg-action-btn msg-action-hidden msg-action-edit" type="button" title="Edit">' + iconHtml("pencil") + '</button>';
2151
2227
  div.appendChild(actions);
@@ -2893,6 +2969,8 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
2893
2969
  if (msg.mode) currentMode = msg.mode;
2894
2970
  if (msg.effort) currentEffort = msg.effort;
2895
2971
  if (msg.betas) currentBetas = msg.betas;
2972
+ if (msg.thinking) currentThinking = msg.thinking;
2973
+ if (msg.thinkingBudget) currentThinkingBudget = msg.thinkingBudget;
2896
2974
  // Validate effort against current model's supported levels
2897
2975
  if (currentModels.length > 0) {
2898
2976
  var levels = getModelEffortLevels();
@@ -3181,6 +3259,16 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3181
3259
  startUrgentBlink();
3182
3260
  break;
3183
3261
 
3262
+ case "elicitation_request":
3263
+ renderElicitationRequest(msg);
3264
+ startUrgentBlink();
3265
+ break;
3266
+
3267
+ case "elicitation_resolved":
3268
+ markElicitationResolved(msg.requestId, msg.action);
3269
+ stopUrgentBlink();
3270
+ break;
3271
+
3184
3272
  case "slash_command_result":
3185
3273
  finalizeAssistantBlock();
3186
3274
  var cmdBlock = document.createElement("div");
@@ -3213,7 +3301,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3213
3301
  break;
3214
3302
 
3215
3303
  case "task_progress":
3216
- updateSubagentProgress(msg.parentToolId, msg.usage, msg.lastToolName);
3304
+ updateSubagentProgress(msg.parentToolId, msg.usage, msg.lastToolName, msg.summary);
3217
3305
  break;
3218
3306
 
3219
3307
  case "result":
@@ -3296,6 +3384,10 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
3296
3384
  addSystemMessage(msg.text || "Rewind failed.", true);
3297
3385
  break;
3298
3386
 
3387
+ case "fork_complete":
3388
+ addSystemMessage("Session forked successfully.");
3389
+ break;
3390
+
3299
3391
  case "fs_list_result":
3300
3392
  handleFsList(msg);
3301
3393
  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.2",
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",