clay-server 2.26.0-beta.9 → 2.26.0
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/browser-mcp-server.js +4 -4
- package/lib/debate-mcp-server.js +94 -0
- package/lib/mates.js +12 -24
- package/lib/project-debate.js +304 -166
- package/lib/project-mate-interaction.js +10 -5
- package/lib/project.js +108 -39
- package/lib/public/app.js +317 -85
- package/lib/public/css/debate.css +230 -2
- package/lib/public/css/filebrowser.css +41 -4
- package/lib/public/css/icon-strip.css +10 -10
- package/lib/public/css/input.css +33 -0
- package/lib/public/css/mates.css +17 -38
- package/lib/public/css/messages.css +17 -0
- package/lib/public/css/mobile-nav.css +3 -1
- package/lib/public/css/rewind.css +17 -4
- package/lib/public/index.html +23 -15
- package/lib/public/modules/context-sources.js +21 -6
- package/lib/public/modules/debate.js +298 -97
- package/lib/public/modules/input.js +15 -0
- package/lib/public/modules/mate-knowledge.js +11 -11
- package/lib/public/modules/mate-memory.js +5 -5
- package/lib/public/modules/mate-sidebar.js +13 -9
- package/lib/public/modules/sidebar.js +105 -26
- package/lib/public/modules/terminal.js +62 -6
- package/lib/public/modules/tools.js +2 -2
- package/lib/sdk-bridge.js +123 -22
- package/lib/sessions.js +2 -2
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ function attachMateInteraction(ctx) {
|
|
|
6
6
|
var cwd = ctx.cwd;
|
|
7
7
|
var sm = ctx.sm;
|
|
8
8
|
var sdk = ctx.sdk;
|
|
9
|
+
var send = ctx.send;
|
|
9
10
|
var sendTo = ctx.sendTo;
|
|
10
11
|
var sendToSession = ctx.sendToSession;
|
|
11
12
|
var sendToSessionOthers = ctx.sendToSessionOthers;
|
|
@@ -455,6 +456,9 @@ function attachMateInteraction(ctx) {
|
|
|
455
456
|
avatarSeed: avatarSeed,
|
|
456
457
|
});
|
|
457
458
|
|
|
459
|
+
// Broadcast to all tabs so mate avatar shows activity indicator
|
|
460
|
+
send({ type: "mention_processing", mateId: msg.mateId, active: true });
|
|
461
|
+
|
|
458
462
|
// Shared callbacks for both new and continued sessions
|
|
459
463
|
var mentionCallbacks = {
|
|
460
464
|
onActivity: function (activity) {
|
|
@@ -498,6 +502,7 @@ function attachMateInteraction(ctx) {
|
|
|
498
502
|
);
|
|
499
503
|
|
|
500
504
|
sendToSession(session.localId, { type: "mention_done", mateId: msg.mateId });
|
|
505
|
+
send({ type: "mention_processing", mateId: msg.mateId, active: false });
|
|
501
506
|
|
|
502
507
|
// Check if the mate wrote a debate brief during this turn
|
|
503
508
|
ctx.checkForDmDebateBrief(session, msg.mateId, mateCtx);
|
|
@@ -513,6 +518,7 @@ function attachMateInteraction(ctx) {
|
|
|
513
518
|
}
|
|
514
519
|
console.error("[mention] Error for mate " + msg.mateId + ":", errMsg);
|
|
515
520
|
sendToSession(session.localId, { type: "mention_error", mateId: msg.mateId, error: errMsg });
|
|
521
|
+
send({ type: "mention_processing", mateId: msg.mateId, active: false });
|
|
516
522
|
},
|
|
517
523
|
};
|
|
518
524
|
|
|
@@ -563,11 +569,10 @@ function attachMateInteraction(ctx) {
|
|
|
563
569
|
onDone: mentionCallbacks.onDone,
|
|
564
570
|
onError: mentionCallbacks.onError,
|
|
565
571
|
canUseTool: function (toolName, input, toolOpts) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
// Route through the project session's permission system
|
|
572
|
+
// Use the shared whitelist from sdk-bridge (read-only tools + safe bash commands)
|
|
573
|
+
var whitelisted = sdk.checkToolWhitelist(toolName, input);
|
|
574
|
+
if (whitelisted) return Promise.resolve(whitelisted);
|
|
575
|
+
// Not whitelisted: route through the project session's permission system
|
|
571
576
|
return new Promise(function (resolve) {
|
|
572
577
|
var requestId = crypto.randomUUID();
|
|
573
578
|
session.pendingPermissions[requestId] = {
|
package/lib/project.js
CHANGED
|
@@ -293,6 +293,7 @@ function createProjectContext(opts) {
|
|
|
293
293
|
|
|
294
294
|
// --- Browser extension state ---
|
|
295
295
|
var _browserTabList = {}; // tabId -> { id, url, title, favIconUrl }
|
|
296
|
+
var _pendingDebateProposals = {}; // proposalId -> { resolve, briefData }
|
|
296
297
|
var _extensionWs = null; // WebSocket of the client with the Chrome extension
|
|
297
298
|
var _extToken = crypto.randomUUID(); // Auth token for MCP server bridge
|
|
298
299
|
var pendingExtensionRequests = {}; // requestId -> { resolve, timer }
|
|
@@ -557,47 +558,72 @@ function createProjectContext(opts) {
|
|
|
557
558
|
mateDisplayName: opts.mateDisplayName || "",
|
|
558
559
|
isMate: isMate,
|
|
559
560
|
dangerouslySkipPermissions: dangerouslySkipPermissions,
|
|
560
|
-
mcpServers:
|
|
561
|
+
mcpServers: (function () {
|
|
562
|
+
var servers = {};
|
|
563
|
+
|
|
564
|
+
// Debate MCP server (available to both mates and main project)
|
|
561
565
|
try {
|
|
562
|
-
var
|
|
563
|
-
var
|
|
564
|
-
return
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
575
|
-
return active;
|
|
576
|
-
},
|
|
577
|
-
unwatchTab: function (tabId) {
|
|
578
|
-
var key = "tab:" + tabId;
|
|
579
|
-
var active = loadContextSources(slug);
|
|
580
|
-
var idx = active.indexOf(key);
|
|
581
|
-
if (idx !== -1) {
|
|
582
|
-
active.splice(idx, 1);
|
|
583
|
-
saveContextSources(slug, active);
|
|
584
|
-
var msg = JSON.stringify({ type: "context_sources_state", active: active });
|
|
585
|
-
for (var c of clients) { if (c.readyState === 1) c.send(msg); }
|
|
586
|
-
}
|
|
587
|
-
return active;
|
|
588
|
-
},
|
|
566
|
+
var debateMcp = require("./debate-mcp-server");
|
|
567
|
+
var debateMcpConfig = debateMcp.create(function onPropose(briefData) {
|
|
568
|
+
return new Promise(function (resolve) {
|
|
569
|
+
var proposalId = "dp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
570
|
+
briefData.proposalId = proposalId;
|
|
571
|
+
_pendingDebateProposals[proposalId] = {
|
|
572
|
+
resolve: resolve,
|
|
573
|
+
briefData: briefData,
|
|
574
|
+
};
|
|
575
|
+
// The SDK sends tool_executing with briefData as input.
|
|
576
|
+
// Client renders the debate brief card when it sees propose_debate.
|
|
577
|
+
});
|
|
589
578
|
});
|
|
590
|
-
if (
|
|
591
|
-
var servers = {};
|
|
592
|
-
servers[mcpConfig.name || "clay-browser"] = mcpConfig;
|
|
593
|
-
return servers;
|
|
579
|
+
if (debateMcpConfig) servers[debateMcpConfig.name || "clay-debate"] = debateMcpConfig;
|
|
594
580
|
} catch (e) {
|
|
595
|
-
console.error("[project] Failed to create
|
|
596
|
-
return undefined;
|
|
581
|
+
console.error("[project] Failed to create debate MCP server:", e.message);
|
|
597
582
|
}
|
|
583
|
+
|
|
584
|
+
// Browser MCP server (main project only, not mates)
|
|
585
|
+
if (!isMate) {
|
|
586
|
+
try {
|
|
587
|
+
var browserMcp = require("./browser-mcp-server");
|
|
588
|
+
var mcpConfig = browserMcp.create(sendExtensionCommandAny, function () {
|
|
589
|
+
return Object.values(_browserTabList || {});
|
|
590
|
+
}, {
|
|
591
|
+
watchTab: function (tabId) {
|
|
592
|
+
var key = "tab:" + tabId;
|
|
593
|
+
var active = loadContextSources(slug);
|
|
594
|
+
if (active.indexOf(key) === -1) {
|
|
595
|
+
active.push(key);
|
|
596
|
+
saveContextSources(slug, active);
|
|
597
|
+
var _msg = JSON.stringify({ type: "context_sources_state", active: active });
|
|
598
|
+
for (var c of clients) { if (c.readyState === 1) c.send(_msg); }
|
|
599
|
+
}
|
|
600
|
+
return active;
|
|
601
|
+
},
|
|
602
|
+
unwatchTab: function (tabId) {
|
|
603
|
+
var key = "tab:" + tabId;
|
|
604
|
+
var active = loadContextSources(slug);
|
|
605
|
+
var idx = active.indexOf(key);
|
|
606
|
+
if (idx !== -1) {
|
|
607
|
+
active.splice(idx, 1);
|
|
608
|
+
saveContextSources(slug, active);
|
|
609
|
+
var _msg = JSON.stringify({ type: "context_sources_state", active: active });
|
|
610
|
+
for (var c of clients) { if (c.readyState === 1) c.send(_msg); }
|
|
611
|
+
}
|
|
612
|
+
return active;
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
if (mcpConfig) servers[mcpConfig.name || "clay-browser"] = mcpConfig;
|
|
616
|
+
} catch (e) {
|
|
617
|
+
console.error("[project] Failed to create browser MCP server:", e.message);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return Object.keys(servers).length > 0 ? servers : undefined;
|
|
598
622
|
})(),
|
|
599
623
|
onProcessingChanged: onProcessingChanged,
|
|
600
|
-
onTurnDone: isMate ? function (session, preview) {
|
|
624
|
+
onTurnDone: isMate ? function (session, preview) {
|
|
625
|
+
digestDmTurn(session, preview);
|
|
626
|
+
} : null,
|
|
601
627
|
scheduleMessage: function (session, text, resetsAt) {
|
|
602
628
|
scheduleMessage(session, text, resetsAt);
|
|
603
629
|
},
|
|
@@ -1591,11 +1617,13 @@ function createProjectContext(opts) {
|
|
|
1591
1617
|
if (session.scheduledMessage && session.scheduledMessage.timer) {
|
|
1592
1618
|
clearTimeout(session.scheduledMessage.timer);
|
|
1593
1619
|
}
|
|
1594
|
-
var
|
|
1620
|
+
var isPastReset = resetsAt <= Date.now();
|
|
1621
|
+
var schedDelay = isPastReset ? 5000 : Math.max(0, resetsAt - Date.now()) + 60000; // +1min buffer after reset, or 5s for immediate
|
|
1622
|
+
var sendsAt = Date.now() + schedDelay;
|
|
1595
1623
|
var schedEntry = {
|
|
1596
1624
|
type: "scheduled_message_queued",
|
|
1597
1625
|
text: text,
|
|
1598
|
-
resetsAt:
|
|
1626
|
+
resetsAt: sendsAt,
|
|
1599
1627
|
scheduledAt: Date.now(),
|
|
1600
1628
|
};
|
|
1601
1629
|
sm.sendAndRecord(session, schedEntry);
|
|
@@ -1657,6 +1685,7 @@ function createProjectContext(opts) {
|
|
|
1657
1685
|
}
|
|
1658
1686
|
session._mentionInProgress = false;
|
|
1659
1687
|
sendToSession(session.localId, { type: "mention_done", mateId: mateId, stopped: true });
|
|
1688
|
+
send({ type: "mention_processing", mateId: mateId, active: false });
|
|
1660
1689
|
}
|
|
1661
1690
|
return;
|
|
1662
1691
|
}
|
|
@@ -1666,6 +1695,10 @@ function createProjectContext(opts) {
|
|
|
1666
1695
|
handleDebateStart(ws, msg);
|
|
1667
1696
|
return;
|
|
1668
1697
|
}
|
|
1698
|
+
if (msg.type === "debate_hand_raise") {
|
|
1699
|
+
handleDebateHandRaise(ws);
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1669
1702
|
if (msg.type === "debate_comment") {
|
|
1670
1703
|
handleDebateComment(ws, msg);
|
|
1671
1704
|
return;
|
|
@@ -1682,6 +1715,32 @@ function createProjectContext(opts) {
|
|
|
1682
1715
|
handleDebateConfirmBrief(ws);
|
|
1683
1716
|
return;
|
|
1684
1717
|
}
|
|
1718
|
+
if (msg.type === "debate_proposal_response") {
|
|
1719
|
+
// Match the most recent pending proposal (proposalId may not be
|
|
1720
|
+
// available on the client since it's not part of the tool input)
|
|
1721
|
+
var _dpKeys = Object.keys(_pendingDebateProposals);
|
|
1722
|
+
if (_dpKeys.length === 0) return;
|
|
1723
|
+
var _dpKey = msg.proposalId || _dpKeys[_dpKeys.length - 1];
|
|
1724
|
+
var pending = _pendingDebateProposals[_dpKey];
|
|
1725
|
+
if (!pending) return;
|
|
1726
|
+
delete _pendingDebateProposals[_dpKey];
|
|
1727
|
+
if (msg.action === "start") {
|
|
1728
|
+
// Set up debate state on the session, then transition to live
|
|
1729
|
+
var _dpSession = getSessionForWs(ws);
|
|
1730
|
+
if (_dpSession) {
|
|
1731
|
+
var _dpMateId = isMate ? path.basename(cwd) : null;
|
|
1732
|
+
handleMcpDebateApproval(_dpSession, pending.briefData, _dpMateId, ws);
|
|
1733
|
+
}
|
|
1734
|
+
pending.resolve({ action: "start" });
|
|
1735
|
+
} else {
|
|
1736
|
+
pending.resolve({ action: "cancel" });
|
|
1737
|
+
}
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
if (msg.type === "debate_user_floor_response") {
|
|
1741
|
+
handleDebateUserFloorResponse(ws, msg);
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
1685
1744
|
|
|
1686
1745
|
// --- Knowledge file management ---
|
|
1687
1746
|
if (msg.type === "knowledge_list") {
|
|
@@ -4177,7 +4236,8 @@ function createProjectContext(opts) {
|
|
|
4177
4236
|
data: screenshotData,
|
|
4178
4237
|
file: screenshotName,
|
|
4179
4238
|
tabTitle: tabLabel,
|
|
4180
|
-
tabUrl: tabInfo ? tabInfo.url : ""
|
|
4239
|
+
tabUrl: tabInfo ? tabInfo.url : "",
|
|
4240
|
+
tabFavIconUrl: tabInfo ? tabInfo.favIconUrl : ""
|
|
4181
4241
|
});
|
|
4182
4242
|
parts.push("[Screenshot saved: " + screenshotPath + "]");
|
|
4183
4243
|
}
|
|
@@ -4199,7 +4259,8 @@ function createProjectContext(opts) {
|
|
|
4199
4259
|
}
|
|
4200
4260
|
|
|
4201
4261
|
if (tabContextParts.length > 0) {
|
|
4202
|
-
fullText =
|
|
4262
|
+
fullText = "[The following browser tab data is automatically attached as context sources. Do NOT call browser_read_page, browser_console, browser_network, or browser_screenshot for these tabs — the data is already here.]\n\n" +
|
|
4263
|
+
tabContextParts.join("\n\n---\n\n") + "\n\n" + fullText;
|
|
4203
4264
|
}
|
|
4204
4265
|
|
|
4205
4266
|
// If screenshots were captured, send context preview cards and add to SDK images
|
|
@@ -4213,6 +4274,7 @@ function createProjectContext(opts) {
|
|
|
4213
4274
|
tab: {
|
|
4214
4275
|
title: ss.tabTitle || "",
|
|
4215
4276
|
url: ss.tabUrl || "",
|
|
4277
|
+
favIconUrl: ss.tabFavIconUrl || "",
|
|
4216
4278
|
screenshotFile: ss.file
|
|
4217
4279
|
}
|
|
4218
4280
|
};
|
|
@@ -4223,6 +4285,7 @@ function createProjectContext(opts) {
|
|
|
4223
4285
|
tab: {
|
|
4224
4286
|
title: ss.tabTitle || "",
|
|
4225
4287
|
url: ss.tabUrl || "",
|
|
4288
|
+
favIconUrl: ss.tabFavIconUrl || "",
|
|
4226
4289
|
screenshotUrl: "/p/" + slug + "/images/" + ss.file
|
|
4227
4290
|
}
|
|
4228
4291
|
});
|
|
@@ -4269,6 +4332,7 @@ function createProjectContext(opts) {
|
|
|
4269
4332
|
cwd: cwd,
|
|
4270
4333
|
sm: sm,
|
|
4271
4334
|
sdk: sdk,
|
|
4335
|
+
send: send,
|
|
4272
4336
|
sendTo: sendTo,
|
|
4273
4337
|
sendToSession: sendToSession,
|
|
4274
4338
|
sendToSessionOthers: sendToSessionOthers,
|
|
@@ -4295,6 +4359,8 @@ function createProjectContext(opts) {
|
|
|
4295
4359
|
var _debate = attachDebate({
|
|
4296
4360
|
cwd: cwd,
|
|
4297
4361
|
slug: slug,
|
|
4362
|
+
isMate: isMate,
|
|
4363
|
+
projectOwnerId: projectOwnerId,
|
|
4298
4364
|
send: send,
|
|
4299
4365
|
sendTo: sendTo,
|
|
4300
4366
|
sendToSession: sendToSession,
|
|
@@ -4311,12 +4377,15 @@ function createProjectContext(opts) {
|
|
|
4311
4377
|
initMemorySummary: initMemorySummary,
|
|
4312
4378
|
});
|
|
4313
4379
|
var handleDebateStart = _debate.handleDebateStart;
|
|
4380
|
+
var handleDebateHandRaise = _debate.handleDebateHandRaise;
|
|
4314
4381
|
var handleDebateComment = _debate.handleDebateComment;
|
|
4315
4382
|
var handleDebateStop = _debate.handleDebateStop;
|
|
4316
4383
|
var handleDebateConcludeResponse = _debate.handleDebateConcludeResponse;
|
|
4317
4384
|
var handleDebateConfirmBrief = _debate.handleDebateConfirmBrief;
|
|
4385
|
+
var handleDebateUserFloorResponse = _debate.handleDebateUserFloorResponse;
|
|
4318
4386
|
var restoreDebateState = _debate.restoreDebateState;
|
|
4319
4387
|
var checkForDmDebateBrief = _debate.checkForDmDebateBrief;
|
|
4388
|
+
var handleMcpDebateApproval = _debate.handleMcpDebateApproval;
|
|
4320
4389
|
|
|
4321
4390
|
// --- Session presence (who is viewing which session) ---
|
|
4322
4391
|
function broadcastPresence() {
|