clay-server 2.34.0-beta.3 → 2.34.0-beta.5
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/ask-user-mcp-server.js +120 -0
- package/lib/daemon.js +97 -38
- package/lib/mates.js +2 -2
- package/lib/project-connection.js +15 -0
- package/lib/project-sessions.js +73 -4
- package/lib/project.js +75 -8
- package/lib/public/css/mates.css +26 -11
- package/lib/public/index.html +17 -19
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-messages.js +2 -0
- package/lib/public/modules/mate-sidebar.js +0 -9
- package/lib/public/modules/mate-wizard.js +15 -15
- package/lib/public/modules/tools.js +20 -2
- package/lib/sdk-bridge.js +23 -19
- package/lib/sdk-message-processor.js +14 -3
- package/lib/server.js +28 -72
- package/lib/sessions.js +67 -20
- package/lib/yoke/adapters/claude-worker.js +108 -0
- package/lib/yoke/adapters/claude.js +17 -3
- package/lib/yoke/adapters/codex.js +318 -54
- package/lib/yoke/index.js +40 -28
- package/lib/yoke/mcp-bridge-server.js +14 -6
- package/package.json +1 -1
package/lib/yoke/index.js
CHANGED
|
@@ -19,6 +19,7 @@ function wrapCreateQuery(adapter, defaultCwd) {
|
|
|
19
19
|
var originalCreateQuery = adapter.createQuery.bind(adapter);
|
|
20
20
|
|
|
21
21
|
adapter.createQuery = function(queryOpts) {
|
|
22
|
+
queryOpts = queryOpts || {};
|
|
22
23
|
var projectDir = (queryOpts && queryOpts.cwd) || defaultCwd;
|
|
23
24
|
var merged = instructions.scanAndMerge(projectDir, adapter.vendor);
|
|
24
25
|
|
|
@@ -53,7 +54,7 @@ function createAdapter(opts) {
|
|
|
53
54
|
throw new Error("[YOKE] Unknown adapter vendor: " + vendor);
|
|
54
55
|
}
|
|
55
56
|
iface.validateAdapter(adapter);
|
|
56
|
-
wrapCreateQuery(adapter, opts.cwd);
|
|
57
|
+
wrapCreateQuery(adapter, opts && opts.cwd);
|
|
57
58
|
return adapter;
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -187,8 +188,19 @@ function checkAuth() {
|
|
|
187
188
|
|
|
188
189
|
/**
|
|
189
190
|
* Check which vendor binaries are installed (regardless of auth status).
|
|
191
|
+
*
|
|
192
|
+
* Result is cached at module scope because the check runs two execFileSync
|
|
193
|
+
* calls per invocation and is triggered once per project context on daemon
|
|
194
|
+
* startup. With N projects this used to cost ~2N synchronous subprocesses;
|
|
195
|
+
* caching collapses it to two total. The cache is invalidated alongside
|
|
196
|
+
* the auth cache (via invalidateAuthCache) since "just installed" is the
|
|
197
|
+
* same situation as "just logged in" from the daemon's perspective.
|
|
190
198
|
*/
|
|
199
|
+
var _installedCache = null;
|
|
200
|
+
|
|
191
201
|
function checkInstalled() {
|
|
202
|
+
if (_installedCache) return _installedCache;
|
|
203
|
+
|
|
192
204
|
var fs = require("fs");
|
|
193
205
|
var execFileSync = require("child_process").execFileSync;
|
|
194
206
|
var result = { claude: false, codex: false };
|
|
@@ -204,6 +216,7 @@ function checkInstalled() {
|
|
|
204
216
|
codexBin = findCodexPath();
|
|
205
217
|
if (codexBin && fs.existsSync(codexBin)) {
|
|
206
218
|
result.codex = true;
|
|
219
|
+
_installedCache = result;
|
|
207
220
|
return result;
|
|
208
221
|
}
|
|
209
222
|
} catch (e) {}
|
|
@@ -213,27 +226,25 @@ function checkInstalled() {
|
|
|
213
226
|
: execFileSync("which", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
214
227
|
if (whichOut.trim()) result.codex = true;
|
|
215
228
|
} catch (e) {}
|
|
229
|
+
_installedCache = result;
|
|
216
230
|
return result;
|
|
217
231
|
}
|
|
218
232
|
|
|
219
233
|
function invalidateAuthCache() {
|
|
220
234
|
_authCache = null;
|
|
235
|
+
_installedCache = null;
|
|
221
236
|
}
|
|
222
237
|
|
|
223
238
|
/**
|
|
224
239
|
* Create adapters for all authenticated vendors.
|
|
225
|
-
*
|
|
226
|
-
*
|
|
240
|
+
* Claude may be shared across projects, but Codex is instantiated per project
|
|
241
|
+
* so its app-server and bridge stay scoped to a single project slug.
|
|
227
242
|
* Returns { adapters: { vendor: Adapter }, auth: { vendor: boolean } }
|
|
228
243
|
*/
|
|
229
|
-
var
|
|
230
|
-
var _sharedAuth = null;
|
|
244
|
+
var _sharedClaudeAdapter = null;
|
|
231
245
|
|
|
232
246
|
function createAdapters(opts) {
|
|
233
|
-
|
|
234
|
-
return { adapters: _sharedAdapters, auth: _sharedAuth };
|
|
235
|
-
}
|
|
236
|
-
|
|
247
|
+
opts = opts || {};
|
|
237
248
|
// Gate adapter creation on binary installation, not OAuth auth status.
|
|
238
249
|
// Claude Code supports multiple auth modes (OAuth, Bedrock, Vertex, API key)
|
|
239
250
|
// that `claude auth status` does not always detect. Runtime auth failures are
|
|
@@ -241,22 +252,30 @@ function createAdapters(opts) {
|
|
|
241
252
|
var installed = checkInstalled();
|
|
242
253
|
var auth = { claude: false, codex: false };
|
|
243
254
|
var adapters = {};
|
|
244
|
-
var vendors = Object.keys(installed);
|
|
245
255
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
if (installed.claude) {
|
|
257
|
+
try {
|
|
258
|
+
if (!_sharedClaudeAdapter) {
|
|
259
|
+
_sharedClaudeAdapter = createAdapter({ vendor: "claude", cwd: opts.cwd });
|
|
260
|
+
}
|
|
261
|
+
adapters.claude = _sharedClaudeAdapter;
|
|
262
|
+
auth.claude = true;
|
|
263
|
+
console.log("[yoke] Adapter created: claude");
|
|
264
|
+
} catch (e) {
|
|
265
|
+
console.error("[yoke] Failed to create adapter for claude:", e.message);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (installed.codex) {
|
|
249
270
|
try {
|
|
250
|
-
adapters
|
|
251
|
-
auth
|
|
252
|
-
console.log("[yoke] Adapter created: "
|
|
271
|
+
adapters.codex = createAdapter({ vendor: "codex", cwd: opts.cwd, slug: opts.slug });
|
|
272
|
+
auth.codex = true;
|
|
273
|
+
console.log("[yoke] Adapter created: codex");
|
|
253
274
|
} catch (e) {
|
|
254
|
-
console.error("[yoke] Failed to create adapter for
|
|
275
|
+
console.error("[yoke] Failed to create adapter for codex:", e.message);
|
|
255
276
|
}
|
|
256
277
|
}
|
|
257
278
|
|
|
258
|
-
_sharedAdapters = adapters;
|
|
259
|
-
_sharedAuth = auth;
|
|
260
279
|
return { adapters: adapters, auth: auth };
|
|
261
280
|
}
|
|
262
281
|
|
|
@@ -266,26 +285,19 @@ function createAdapters(opts) {
|
|
|
266
285
|
* Returns the adapter or null.
|
|
267
286
|
*/
|
|
268
287
|
async function lazyCreateAdapter(adapters, vendor, opts) {
|
|
269
|
-
|
|
270
|
-
adapters[vendor] = _sharedAdapters[vendor];
|
|
271
|
-
return adapters[vendor];
|
|
272
|
-
}
|
|
288
|
+
opts = opts || {};
|
|
273
289
|
|
|
274
290
|
// Force re-check since user may have logged in after server start
|
|
275
291
|
invalidateAuthCache();
|
|
276
|
-
_sharedAdapters = null;
|
|
277
|
-
_sharedAuth = null;
|
|
278
292
|
var installed = checkInstalled();
|
|
279
293
|
if (!installed[vendor]) return null;
|
|
280
294
|
|
|
281
295
|
try {
|
|
282
|
-
var ad = createAdapter({ vendor: vendor, cwd: opts.cwd });
|
|
296
|
+
var ad = createAdapter({ vendor: vendor, cwd: opts.cwd, slug: opts.slug });
|
|
283
297
|
if (typeof ad.init === "function") {
|
|
284
298
|
await ad.init(opts || {});
|
|
285
299
|
}
|
|
286
300
|
console.log("[yoke] Lazy adapter created: " + vendor);
|
|
287
|
-
if (_sharedAdapters) _sharedAdapters[vendor] = ad;
|
|
288
|
-
if (_sharedAuth) _sharedAuth[vendor] = true;
|
|
289
301
|
adapters[vendor] = ad;
|
|
290
302
|
return ad;
|
|
291
303
|
} catch (e) {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// --------------------------------------------------
|
|
4
4
|
// Codex spawns this as a native MCP server via config.mcp_servers["clay-tools"].
|
|
5
5
|
// It implements the MCP protocol on stdio (JSON-RPC) and proxies tool
|
|
6
|
-
// list/call requests to Clay's HTTP endpoint
|
|
6
|
+
// list/call requests to Clay's project-scoped HTTP endpoint
|
|
7
|
+
// (/p/{slug}/api/mcp-bridge) when a slug is provided.
|
|
7
8
|
//
|
|
8
9
|
// Usage: node mcp-bridge-server.js --port 2633 --slug my-project
|
|
9
10
|
//
|
|
@@ -37,8 +38,10 @@ for (var i = 0; i < args.length; i++) {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
var CLAY_PROTOCOL = clayTls ? "https" : "http";
|
|
40
|
-
// Use global endpoint (not project-scoped) so bridge works regardless of which project was active at init
|
|
41
41
|
var CLAY_BASE_URL = CLAY_PROTOCOL + "://127.0.0.1:" + clayPort;
|
|
42
|
+
var CLAY_MCP_PATH = claySlug
|
|
43
|
+
? ("/p/" + claySlug + "/api/mcp-bridge")
|
|
44
|
+
: "/api/mcp-bridge";
|
|
42
45
|
|
|
43
46
|
// --- Auth ---
|
|
44
47
|
var clayAuthToken = process.env.CLAY_AUTH_TOKEN || "";
|
|
@@ -91,8 +94,13 @@ function postJson(urlPath, body) {
|
|
|
91
94
|
reject(err);
|
|
92
95
|
});
|
|
93
96
|
|
|
94
|
-
//
|
|
95
|
-
|
|
97
|
+
// 10 min safety ceiling. ask_user_questions is stateless (returns
|
|
98
|
+
// immediately; the user's answer arrives on the next turn as a new
|
|
99
|
+
// user message), so no tool call should legitimately block long.
|
|
100
|
+
// The generous ceiling is just a belt-and-suspenders against slow
|
|
101
|
+
// browser automation or external MCP servers, not the primary
|
|
102
|
+
// mechanism for human-in-the-loop tools.
|
|
103
|
+
req.setTimeout(600000, function () {
|
|
96
104
|
req.destroy(new Error("Request timed out"));
|
|
97
105
|
});
|
|
98
106
|
|
|
@@ -103,7 +111,7 @@ function postJson(urlPath, body) {
|
|
|
103
111
|
|
|
104
112
|
// --- Fetch tools from Clay ---
|
|
105
113
|
function fetchTools() {
|
|
106
|
-
return postJson(
|
|
114
|
+
return postJson(CLAY_MCP_PATH, { action: "list_tools" }).then(function (resp) {
|
|
107
115
|
if (resp.error) {
|
|
108
116
|
log("Failed to fetch tools: " + resp.error);
|
|
109
117
|
return [];
|
|
@@ -124,7 +132,7 @@ function fetchTools() {
|
|
|
124
132
|
|
|
125
133
|
// --- Call a tool via Clay ---
|
|
126
134
|
function callTool(serverName, toolName, args) {
|
|
127
|
-
return postJson(
|
|
135
|
+
return postJson(CLAY_MCP_PATH, {
|
|
128
136
|
action: "call_tool",
|
|
129
137
|
server: serverName,
|
|
130
138
|
tool: toolName,
|