clay-server 2.31.0 → 2.32.0-beta.10

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.
Files changed (82) hide show
  1. package/lib/browser-mcp-server.js +32 -44
  2. package/lib/codex-defaults.js +18 -0
  3. package/lib/debate-mcp-server.js +14 -31
  4. package/lib/mcp-local.js +31 -1
  5. package/lib/project-connection.js +9 -6
  6. package/lib/project-debate.js +8 -0
  7. package/lib/project-filesystem.js +47 -1
  8. package/lib/project-http.js +75 -8
  9. package/lib/project-mate-interaction.js +102 -16
  10. package/lib/project-mcp.js +4 -0
  11. package/lib/project-notifications.js +9 -0
  12. package/lib/project-sessions.js +94 -51
  13. package/lib/project-user-message.js +12 -7
  14. package/lib/project.js +234 -99
  15. package/lib/public/app.js +135 -454
  16. package/lib/public/codex-avatar.png +0 -0
  17. package/lib/public/css/debate.css +3 -2
  18. package/lib/public/css/filebrowser.css +91 -1
  19. package/lib/public/css/icon-strip.css +21 -5
  20. package/lib/public/css/input.css +338 -104
  21. package/lib/public/css/mates.css +43 -0
  22. package/lib/public/css/mention.css +48 -4
  23. package/lib/public/css/menus.css +1 -1
  24. package/lib/public/css/messages.css +2 -0
  25. package/lib/public/css/notifications-center.css +26 -0
  26. package/lib/public/css/tooltip.css +47 -0
  27. package/lib/public/index.html +78 -26
  28. package/lib/public/modules/app-connection.js +138 -37
  29. package/lib/public/modules/app-cursors.js +18 -17
  30. package/lib/public/modules/app-debate-ui.js +9 -9
  31. package/lib/public/modules/app-dm.js +175 -131
  32. package/lib/public/modules/app-favicon.js +28 -26
  33. package/lib/public/modules/app-header.js +79 -68
  34. package/lib/public/modules/app-home-hub.js +55 -47
  35. package/lib/public/modules/app-loop-ui.js +34 -18
  36. package/lib/public/modules/app-loop-wizard.js +6 -6
  37. package/lib/public/modules/app-messages.js +199 -153
  38. package/lib/public/modules/app-misc.js +23 -12
  39. package/lib/public/modules/app-notifications.js +119 -9
  40. package/lib/public/modules/app-panels.js +203 -49
  41. package/lib/public/modules/app-projects.js +161 -150
  42. package/lib/public/modules/app-rate-limit.js +5 -4
  43. package/lib/public/modules/app-rendering.js +149 -101
  44. package/lib/public/modules/app-skills-install.js +4 -4
  45. package/lib/public/modules/context-sources.js +102 -66
  46. package/lib/public/modules/dom-refs.js +21 -0
  47. package/lib/public/modules/filebrowser.js +173 -2
  48. package/lib/public/modules/input.js +122 -0
  49. package/lib/public/modules/markdown.js +5 -1
  50. package/lib/public/modules/mate-sidebar.js +38 -0
  51. package/lib/public/modules/mention.js +24 -6
  52. package/lib/public/modules/scheduler.js +1 -1
  53. package/lib/public/modules/sidebar-mates.js +79 -35
  54. package/lib/public/modules/sidebar-mobile.js +34 -30
  55. package/lib/public/modules/sidebar-projects.js +60 -57
  56. package/lib/public/modules/sidebar-sessions.js +75 -69
  57. package/lib/public/modules/sidebar.js +12 -20
  58. package/lib/public/modules/skills.js +8 -9
  59. package/lib/public/modules/sticky-notes.js +1 -2
  60. package/lib/public/modules/store.js +9 -2
  61. package/lib/public/modules/stt.js +4 -1
  62. package/lib/public/modules/terminal.js +12 -0
  63. package/lib/public/modules/tools.js +18 -13
  64. package/lib/public/modules/tooltip.js +32 -5
  65. package/lib/sdk-bridge.js +562 -1114
  66. package/lib/sdk-message-processor.js +150 -135
  67. package/lib/sdk-worker.js +4 -0
  68. package/lib/server-dm.js +1 -0
  69. package/lib/server.js +86 -1
  70. package/lib/sessions.js +81 -37
  71. package/lib/ws-schema.js +2 -0
  72. package/lib/yoke/adapters/claude-worker.js +559 -0
  73. package/lib/yoke/adapters/claude.js +1483 -0
  74. package/lib/yoke/adapters/codex.js +1121 -0
  75. package/lib/yoke/adapters/gemini.js +709 -0
  76. package/lib/yoke/codex-app-server.js +307 -0
  77. package/lib/yoke/index.js +199 -0
  78. package/lib/yoke/instructions.js +62 -0
  79. package/lib/yoke/interface.js +98 -0
  80. package/lib/yoke/mcp-bridge-server.js +294 -0
  81. package/lib/yoke/package.json +7 -0
  82. package/package.json +3 -1
package/lib/project.js CHANGED
@@ -84,12 +84,8 @@ function validateEnvString(str) {
84
84
  return null;
85
85
  }
86
86
 
87
- // SDK loaded dynamically (ESM module)
88
- var sdkModule = null;
89
- function getSDK() {
90
- if (!sdkModule) sdkModule = import("@anthropic-ai/claude-agent-sdk");
91
- return sdkModule;
92
- }
87
+ // YOKE adapter (replaces direct SDK access)
88
+ var yoke = require("./yoke");
93
89
 
94
90
  // --- Shared constants ---
95
91
  var IGNORED_DIRS = new Set(["node_modules", ".git", ".next", "__pycache__", ".cache", "dist", "build", ".clay", ".claude-relay"]);
@@ -161,8 +157,15 @@ function createProjectContext(opts) {
161
157
  var onCreateWorktree = opts.onCreateWorktree || null;
162
158
  var serverPort = opts.port || 2633;
163
159
  var serverTls = opts.tls || false;
160
+ var serverAuthToken = opts.authToken || null;
164
161
  var latestVersion = null;
165
162
 
163
+ // --- YOKE adapters (multi-vendor, lazy init) ---
164
+ var _yokeState = yoke.createAdapters({ cwd: cwd });
165
+ var adapters = _yokeState.adapters;
166
+ var defaultVendor = adapters.claude ? "claude" : Object.keys(adapters)[0] || "claude";
167
+ var adapter = adapters[defaultVendor] || null;
168
+
166
169
  // Browser MCP server runs in-process via createSdkMcpServer (no child process spawn).
167
170
  // Do NOT write to .claude-local/settings.json -- the SDK reads that too, causing duplicate spawns.
168
171
 
@@ -398,6 +401,9 @@ function createProjectContext(opts) {
398
401
  },
399
402
  onSessionDone: onSessionDone,
400
403
  });
404
+ sm.availableVendors = Object.keys(adapters);
405
+ sm.defaultVendor = defaultVendor;
406
+
401
407
  var _projMode = typeof opts.onGetProjectDefaultMode === "function" ? opts.onGetProjectDefaultMode(slug) : null;
402
408
  var _srvMode = typeof opts.onGetServerDefaultMode === "function" ? opts.onGetServerDefaultMode() : null;
403
409
  sm._savedDefaultMode = (_projMode && _projMode.mode) || (_srvMode && _srvMode.mode) || "default";
@@ -451,6 +457,89 @@ function createProjectContext(opts) {
451
457
  },
452
458
  });
453
459
 
460
+ // --- MCP tool servers (created via YOKE adapter) ---
461
+ var mcpServers = (function () {
462
+ var servers = {};
463
+
464
+ // Debate MCP server (available to both mates and main project)
465
+ try {
466
+ var debateMcp = require("./debate-mcp-server");
467
+ var debateToolDefs = debateMcp.getToolDefs(function onPropose(briefData) {
468
+ return new Promise(function (resolve) {
469
+ var proposalId = "dp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
470
+ briefData.proposalId = proposalId;
471
+ _pendingDebateProposals[proposalId] = {
472
+ resolve: resolve,
473
+ briefData: briefData,
474
+ };
475
+ // The SDK sends tool_executing with briefData as input.
476
+ // Client renders the debate brief card when it sees propose_debate.
477
+ });
478
+ });
479
+ var debateMcpConfig = adapter.createToolServer({ name: "clay-debate", version: "1.0.0", tools: debateToolDefs });
480
+ if (debateMcpConfig) servers[debateMcpConfig.name || "clay-debate"] = debateMcpConfig;
481
+ } catch (e) {
482
+ console.error("[project] Failed to create debate MCP server:", e.message);
483
+ }
484
+
485
+ // Browser MCP server (main project only, not mates)
486
+ if (!isMate) {
487
+ try {
488
+ var browserMcp = require("./browser-mcp-server");
489
+ var browserToolDefs = browserMcp.getToolDefs(sendExtensionCommandAny, function () {
490
+ return Object.values(browserState._browserTabList || {});
491
+ }, {
492
+ watchTab: function (tabId) {
493
+ var key = "tab:" + tabId;
494
+ // Apply to all connected clients' active sessions
495
+ for (var c of clients) {
496
+ if (c.readyState !== 1) continue;
497
+ var sid = c._clayActiveSession || null;
498
+ var active = loadContextSources(slug, sid);
499
+ if (active.indexOf(key) === -1) {
500
+ active.push(key);
501
+ saveContextSources(slug, sid, active);
502
+ c.send(JSON.stringify({ type: "context_sources_state", active: active }));
503
+ }
504
+ }
505
+ return [];
506
+ },
507
+ unwatchTab: function (tabId) {
508
+ var key = "tab:" + tabId;
509
+ for (var c of clients) {
510
+ if (c.readyState !== 1) continue;
511
+ var sid = c._clayActiveSession || null;
512
+ var active = loadContextSources(slug, sid);
513
+ var idx = active.indexOf(key);
514
+ if (idx !== -1) {
515
+ active.splice(idx, 1);
516
+ saveContextSources(slug, sid, active);
517
+ c.send(JSON.stringify({ type: "context_sources_state", active: active }));
518
+ }
519
+ }
520
+ return active;
521
+ },
522
+ });
523
+ var mcpConfig = adapter.createToolServer({ name: "clay-browser", version: "1.0.0", tools: browserToolDefs });
524
+ if (mcpConfig) servers[mcpConfig.name || "clay-browser"] = mcpConfig;
525
+ } catch (e) {
526
+ console.error("[project] Failed to create browser MCP server:", e.message);
527
+ }
528
+ }
529
+
530
+ // Email MCP server (available to both mates and main project)
531
+ // Note: email-mcp-server still uses the legacy create() pattern (not yet converted to getToolDefs).
532
+ try {
533
+ var emailMcp = require("./email-mcp-server");
534
+ var emailMcpConfig = emailMcp.create(_email.createMcpDeps());
535
+ if (emailMcpConfig) servers[emailMcpConfig.name || "clay-email"] = emailMcpConfig;
536
+ } catch (e) {
537
+ console.error("[project] Failed to create email MCP server:", e.message);
538
+ }
539
+
540
+ return Object.keys(servers).length > 0 ? servers : undefined;
541
+ })();
542
+
454
543
  // --- SDK bridge ---
455
544
  var sdk = createSDKBridge({
456
545
  cwd: cwd,
@@ -458,92 +547,17 @@ function createProjectContext(opts) {
458
547
  sessionManager: sm,
459
548
  send: send,
460
549
  pushModule: pushModule,
550
+ adapter: adapter,
551
+ adapters: adapters,
461
552
  getNotificationsModule: function () { return _notifications; },
462
- getSDK: getSDK,
463
553
  mateDisplayName: opts.mateDisplayName || "",
464
554
  isMate: isMate,
465
555
  dangerouslySkipPermissions: dangerouslySkipPermissions,
466
- mcpServers: (function () {
467
- var servers = {};
468
-
469
- // Debate MCP server (available to both mates and main project)
470
- try {
471
- var debateMcp = require("./debate-mcp-server");
472
- var debateMcpConfig = debateMcp.create(function onPropose(briefData) {
473
- return new Promise(function (resolve) {
474
- var proposalId = "dp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
475
- briefData.proposalId = proposalId;
476
- _pendingDebateProposals[proposalId] = {
477
- resolve: resolve,
478
- briefData: briefData,
479
- };
480
- // The SDK sends tool_executing with briefData as input.
481
- // Client renders the debate brief card when it sees propose_debate.
482
- });
483
- });
484
- if (debateMcpConfig) servers[debateMcpConfig.name || "clay-debate"] = debateMcpConfig;
485
- } catch (e) {
486
- console.error("[project] Failed to create debate MCP server:", e.message);
487
- }
488
-
489
- // Browser MCP server (main project only, not mates)
490
- if (!isMate) {
491
- try {
492
- var browserMcp = require("./browser-mcp-server");
493
- var mcpConfig = browserMcp.create(sendExtensionCommandAny, function () {
494
- return Object.values(browserState._browserTabList || {});
495
- }, {
496
- watchTab: function (tabId) {
497
- var key = "tab:" + tabId;
498
- // Apply to all connected clients' active sessions
499
- for (var c of clients) {
500
- if (c.readyState !== 1) continue;
501
- var sid = c._clayActiveSession || null;
502
- var active = loadContextSources(slug, sid);
503
- if (active.indexOf(key) === -1) {
504
- active.push(key);
505
- saveContextSources(slug, sid, active);
506
- c.send(JSON.stringify({ type: "context_sources_state", active: active }));
507
- }
508
- }
509
- return [];
510
- },
511
- unwatchTab: function (tabId) {
512
- var key = "tab:" + tabId;
513
- for (var c of clients) {
514
- if (c.readyState !== 1) continue;
515
- var sid = c._clayActiveSession || null;
516
- var active = loadContextSources(slug, sid);
517
- var idx = active.indexOf(key);
518
- if (idx !== -1) {
519
- active.splice(idx, 1);
520
- saveContextSources(slug, sid, active);
521
- c.send(JSON.stringify({ type: "context_sources_state", active: active }));
522
- }
523
- }
524
- return active;
525
- },
526
- });
527
- if (mcpConfig) servers[mcpConfig.name || "clay-browser"] = mcpConfig;
528
- } catch (e) {
529
- console.error("[project] Failed to create browser MCP server:", e.message);
530
- }
531
- }
532
-
533
- // Email MCP server (available to both mates and main project)
534
- try {
535
- var emailMcp = require("./email-mcp-server");
536
- // Use "default" userId initially; the actual userId is resolved per-tool-call
537
- // via the deps closures which read from the active WS connection.
538
- var emailMcpConfig = emailMcp.create(_email.createMcpDeps());
539
- if (emailMcpConfig) servers[emailMcpConfig.name || "clay-email"] = emailMcpConfig;
540
- } catch (e) {
541
- console.error("[project] Failed to create email MCP server:", e.message);
542
- }
543
-
544
- return Object.keys(servers).length > 0 ? servers : undefined;
545
- })(),
556
+ mcpServers: mcpServers,
546
557
  getRemoteMcpServers: function () { return _mcp.getMcpServers(); },
558
+ clayPort: serverPort,
559
+ clayTls: serverTls,
560
+ clayAuthToken: serverAuthToken,
547
561
  onProcessingChanged: onProcessingChanged,
548
562
  onTurnDone: isMate ? function (session, preview) {
549
563
  digestDmTurn(session, preview);
@@ -601,15 +615,33 @@ function createProjectContext(opts) {
601
615
  var tm = createTerminalManager({ cwd: cwd, send: send, sendTo: sendTo });
602
616
  var nm = createNotesManager({ cwd: cwd, send: send, sendTo: sendTo });
603
617
 
604
- // Check for updates in background (admin only)
605
- fetchVersion(updateChannel).then(function (v) {
606
- if (v && isNewer(v, currentVersion)) {
607
- latestVersion = v;
608
- sendToAdmins({ type: "update_available", version: v });
609
- }
610
- }).catch(function (e) {
611
- console.error("[project] Background version check failed:", e.message || e);
612
- });
618
+ // Check for updates in background (admin only). The result is stored in
619
+ // latestVersion; broadcast is handled by the hourly scheduler below, so
620
+ // page refreshes don't re-trigger the banner.
621
+ function runVersionCheck(broadcast) {
622
+ fetchVersion(updateChannel).then(function (v) {
623
+ if (v && isNewer(v, currentVersion)) {
624
+ latestVersion = v;
625
+ if (broadcast) sendToAdmins({ type: "update_available", version: v });
626
+ }
627
+ }).catch(function (e) {
628
+ console.error("[project] Background version check failed:", e.message || e);
629
+ });
630
+ }
631
+ runVersionCheck(false);
632
+
633
+ // Push update_available on every hour boundary. Clients can dismiss the
634
+ // banner; the next hourly push acts as a fresh ping. This avoids needing
635
+ // any dismissed-state persistence.
636
+ function scheduleNextHourlyBroadcast() {
637
+ var now = Date.now();
638
+ var msUntilNextHour = 60 * 60 * 1000 - (now % (60 * 60 * 1000));
639
+ setTimeout(function tick() {
640
+ runVersionCheck(true);
641
+ setTimeout(tick, 60 * 60 * 1000);
642
+ }, msUntilNextHour);
643
+ }
644
+ scheduleNextHourlyBroadcast();
613
645
 
614
646
  // --- WS connection handler (delegated to project-connection.js) ---
615
647
  function handleConnection(ws, wsUser) {
@@ -712,12 +744,23 @@ function createProjectContext(opts) {
712
744
  delete session._mentionSessions[mateId];
713
745
  }
714
746
  session._mentionInProgress = false;
747
+ session._mentionActiveMateId = null;
715
748
  sendToSession(session.localId, { type: "mention_done", mateId: mateId, stopped: true });
716
749
  send({ type: "mention_processing", mateId: mateId, active: false });
717
750
  }
718
751
  return;
719
752
  }
720
753
 
754
+ // --- Vendor model switching ---
755
+ if (msg.type === "get_vendor_models") {
756
+ var vendorModels = (sm.modelsByVendor && sm.modelsByVendor[msg.vendor]) || [];
757
+ var firstModel = vendorModels[0] || "";
758
+ // model value can be string or {value, displayName} object
759
+ var defaultModel = typeof firstModel === "string" ? firstModel : (firstModel.value || "");
760
+ sendTo(ws, { type: "model_info", model: defaultModel, models: vendorModels, vendor: msg.vendor, availableVendors: sm.availableVendors || [], installedVendors: sm.installedVendors || [] });
761
+ return;
762
+ }
763
+
721
764
  // --- Debate ---
722
765
  if (msg.type === "debate_start") {
723
766
  handleDebateStart(ws, msg);
@@ -825,6 +868,7 @@ function createProjectContext(opts) {
825
868
  // so we use a lazy getter that resolves at call time.
826
869
  var _mateInteraction = attachMateInteraction({
827
870
  cwd: cwd,
871
+ slug: slug,
828
872
  sm: sm,
829
873
  sdk: sdk,
830
874
  send: send,
@@ -842,6 +886,7 @@ function createProjectContext(opts) {
842
886
  loadMateDigests: loadMateDigests,
843
887
  updateMemorySummary: updateMemorySummary,
844
888
  initMemorySummary: initMemorySummary,
889
+ getNotificationsModule: function () { return _notifications; },
845
890
  get checkForDmDebateBrief() { return checkForDmDebateBrief; },
846
891
  });
847
892
  var handleMention = _mateInteraction.handleMention;
@@ -950,7 +995,7 @@ function createProjectContext(opts) {
950
995
  hydrateImageRefs: hydrateImageRefs,
951
996
  onProcessingChanged: onProcessingChanged,
952
997
  broadcastPresence: broadcastPresence,
953
- getSDK: getSDK,
998
+ adapter: adapter,
954
999
  getProjectList: getProjectList,
955
1000
  getProjectCount: getProjectCount,
956
1001
  getScheduleCount: getScheduleCount,
@@ -1010,7 +1055,7 @@ function createProjectContext(opts) {
1010
1055
  digestDmTurn: digestDmTurn,
1011
1056
  gateMemory: gateMemory,
1012
1057
  escapeRegex: escapeRegex,
1013
- getSDK: getSDK,
1058
+ adapter: adapter,
1014
1059
  getHubSchedules: getHubSchedules,
1015
1060
  getProjectOwnerId: function () { return projectOwnerId; },
1016
1061
  _email: _email,
@@ -1040,6 +1085,94 @@ function createProjectContext(opts) {
1040
1085
  FS_MAX_SIZE: FS_MAX_SIZE,
1041
1086
  });
1042
1087
 
1088
+ // --- MCP bridge handler for Codex (Track 2) ---
1089
+ // Provides list_tools and call_tool operations over HTTP for mcp-bridge-server.js.
1090
+ // Excludes local MCP servers since Codex manages those natively via Track 1.
1091
+ function getMcpBridgeHandler() {
1092
+ // Build set of local MCP server names to exclude (Codex handles these natively)
1093
+ var localMcpNames = {};
1094
+ try {
1095
+ var mcpLocalModule = require("./mcp-local");
1096
+ var localConfig = mcpLocalModule.readMergedServers();
1097
+ var lcNames = Object.keys(localConfig);
1098
+ for (var li = 0; li < lcNames.length; li++) {
1099
+ localMcpNames[lcNames[li]] = true;
1100
+ }
1101
+ } catch (e) { /* no local MCP config */ }
1102
+
1103
+ return {
1104
+ listTools: function () {
1105
+ var tools = [];
1106
+ var toJSONSchema;
1107
+ try { toJSONSchema = require("zod").toJSONSchema; } catch (e) { /* fallback */ }
1108
+
1109
+ // Helper to extract tools from an SDK MCP server object
1110
+ function extractServerTools(serverName, server) {
1111
+ if (!server || !server.instance || !server.instance._registeredTools) return;
1112
+ var toolNames = Object.keys(server.instance._registeredTools);
1113
+ for (var j = 0; j < toolNames.length; j++) {
1114
+ var toolDef = server.instance._registeredTools[toolNames[j]];
1115
+ var inputSchema = { type: "object", properties: {} };
1116
+ try {
1117
+ if (toJSONSchema && toolDef.inputSchema) inputSchema = toJSONSchema(toolDef.inputSchema);
1118
+ } catch (e) { /* fallback */ }
1119
+ tools.push({
1120
+ server: serverName,
1121
+ name: toolNames[j],
1122
+ description: toolDef.description || toolNames[j],
1123
+ inputSchema: inputSchema,
1124
+ });
1125
+ }
1126
+ }
1127
+
1128
+ // In-app MCP servers (debate, browser, email)
1129
+ if (mcpServers) {
1130
+ var inAppNames = Object.keys(mcpServers);
1131
+ for (var i = 0; i < inAppNames.length; i++) {
1132
+ extractServerTools(inAppNames[i], mcpServers[inAppNames[i]]);
1133
+ }
1134
+ }
1135
+
1136
+ // Remote MCP servers (extension-proxied only, skip local proxy servers)
1137
+ var remoteServers = _mcp.getMcpServers();
1138
+ if (remoteServers) {
1139
+ var remoteNames = Object.keys(remoteServers);
1140
+ for (var ri = 0; ri < remoteNames.length; ri++) {
1141
+ // Skip servers that Codex manages natively via Track 1
1142
+ if (localMcpNames[remoteNames[ri]]) continue;
1143
+ extractServerTools(remoteNames[ri], remoteServers[remoteNames[ri]]);
1144
+ }
1145
+ }
1146
+
1147
+ return Promise.resolve(tools);
1148
+ },
1149
+ callTool: function (serverName, toolName, args) {
1150
+ // Try in-app servers first
1151
+ if (mcpServers && mcpServers[serverName]) {
1152
+ var server = mcpServers[serverName];
1153
+ if (server.instance && server.instance._registeredTools && server.instance._registeredTools[toolName]) {
1154
+ var handler = server.instance._registeredTools[toolName].handler;
1155
+ if (typeof handler === "function") {
1156
+ return Promise.resolve(handler(args));
1157
+ }
1158
+ }
1159
+ }
1160
+ // Try remote/local proxy servers
1161
+ var remoteServers = _mcp.getMcpServers();
1162
+ if (remoteServers && remoteServers[serverName]) {
1163
+ var rServer = remoteServers[serverName];
1164
+ if (rServer.instance && rServer.instance._registeredTools && rServer.instance._registeredTools[toolName]) {
1165
+ var rHandler = rServer.instance._registeredTools[toolName].handler;
1166
+ if (typeof rHandler === "function") {
1167
+ return Promise.resolve(rHandler(args));
1168
+ }
1169
+ }
1170
+ }
1171
+ return Promise.reject(new Error("Tool not found: " + serverName + "/" + toolName));
1172
+ },
1173
+ };
1174
+ }
1175
+
1043
1176
  // --- HTTP handler (delegated to project-http.js) ---
1044
1177
  var _http = attachHTTP({
1045
1178
  cwd: cwd,
@@ -1056,6 +1189,7 @@ function createProjectContext(opts) {
1056
1189
  sendExtensionCommandAny: sendExtensionCommandAny,
1057
1190
  _extToken: _extToken,
1058
1191
  _browserTabList: browserState._browserTabList,
1192
+ getMcpBridgeHandler: getMcpBridgeHandler,
1059
1193
  });
1060
1194
  var handleHTTP = _http.handleHTTP;
1061
1195
 
@@ -1275,6 +1409,7 @@ function createProjectContext(opts) {
1275
1409
  handleMessage: handleMessage,
1276
1410
  handleDisconnection: handleDisconnection,
1277
1411
  handleHTTP: handleHTTP,
1412
+ getMcpBridgeHandler: getMcpBridgeHandler,
1278
1413
  getStatus: getStatus,
1279
1414
  getSessionManager: function () { return sm; },
1280
1415
  getNotificationsModule: function () { return _notifications; },
@@ -1300,7 +1435,7 @@ function createProjectContext(opts) {
1300
1435
  sdk.warmup();
1301
1436
  sdk.startIdleReaper();
1302
1437
  // Migrate existing relay session titles to SDK format (one-time, async)
1303
- sm.migrateSessionTitles(getSDK, cwd);
1438
+ sm.migrateSessionTitles(adapter, cwd);
1304
1439
  },
1305
1440
  destroy: function () {
1306
1441
  sdk.stopIdleReaper();