clay-server 2.34.0-beta.2 → 2.34.0-beta.4
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/mate-datastore.js +27 -5
- package/lib/mates.js +2 -2
- package/lib/project-connection.js +15 -0
- package/lib/project-mate-datastore.js +16 -2
- package/lib/project-sessions.js +73 -4
- package/lib/project.js +75 -8
- package/lib/public/css/mates.css +94 -52
- package/lib/public/index.html +17 -47
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-messages.js +3 -5
- package/lib/public/modules/app-rendering.js +0 -2
- package/lib/public/modules/mate-datastore-ui.js +108 -98
- package/lib/public/modules/mate-sidebar.js +0 -9
- package/lib/public/modules/mate-wizard.js +15 -15
- package/lib/public/modules/tools.js +21 -3
- package/lib/sdk-bridge.js +20 -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/codex.js +318 -54
- package/lib/yoke/index.js +73 -35
- package/lib/yoke/instructions.js +0 -1
- package/lib/yoke/mcp-bridge-server.js +14 -6
- package/package.json +1 -2
- package/lib/yoke/adapters/gemini.js +0 -709
package/lib/yoke/index.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
var iface = require("./interface");
|
|
5
5
|
var instructions = require("./instructions");
|
|
6
6
|
var createClaudeAdapter = require("./adapters/claude").createClaudeAdapter;
|
|
7
|
-
var createGeminiAdapter = require("./adapters/gemini").createGeminiAdapter;
|
|
8
7
|
var createCodexAdapter = require("./adapters/codex").createCodexAdapter;
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -20,6 +19,7 @@ function wrapCreateQuery(adapter, defaultCwd) {
|
|
|
20
19
|
var originalCreateQuery = adapter.createQuery.bind(adapter);
|
|
21
20
|
|
|
22
21
|
adapter.createQuery = function(queryOpts) {
|
|
22
|
+
queryOpts = queryOpts || {};
|
|
23
23
|
var projectDir = (queryOpts && queryOpts.cwd) || defaultCwd;
|
|
24
24
|
var merged = instructions.scanAndMerge(projectDir, adapter.vendor);
|
|
25
25
|
|
|
@@ -48,15 +48,13 @@ function createAdapter(opts) {
|
|
|
48
48
|
var adapter;
|
|
49
49
|
if (vendor === "claude") {
|
|
50
50
|
adapter = createClaudeAdapter(opts);
|
|
51
|
-
} else if (vendor === "gemini") {
|
|
52
|
-
adapter = createGeminiAdapter(opts);
|
|
53
51
|
} else if (vendor === "codex") {
|
|
54
52
|
adapter = createCodexAdapter(opts);
|
|
55
53
|
} else {
|
|
56
54
|
throw new Error("[YOKE] Unknown adapter vendor: " + vendor);
|
|
57
55
|
}
|
|
58
56
|
iface.validateAdapter(adapter);
|
|
59
|
-
wrapCreateQuery(adapter, opts.cwd);
|
|
57
|
+
wrapCreateQuery(adapter, opts && opts.cwd);
|
|
60
58
|
return adapter;
|
|
61
59
|
}
|
|
62
60
|
|
|
@@ -113,7 +111,31 @@ function checkAuth() {
|
|
|
113
111
|
return false;
|
|
114
112
|
}
|
|
115
113
|
|
|
114
|
+
function hasThirdPartyProviderAuth() {
|
|
115
|
+
// Claude Code supports third-party providers via env vars. When these are set,
|
|
116
|
+
// `claude auth status` reports "not logged in" because there is no OAuth session,
|
|
117
|
+
// but Claude Code itself authenticates directly through the provider.
|
|
118
|
+
var env = process.env;
|
|
119
|
+
if (env.CLAUDE_CODE_USE_BEDROCK === "1"
|
|
120
|
+
&& (env.AWS_BEARER_TOKEN_BEDROCK
|
|
121
|
+
|| env.AWS_ACCESS_KEY_ID
|
|
122
|
+
|| env.AWS_PROFILE
|
|
123
|
+
|| env.AWS_SESSION_TOKEN)) {
|
|
124
|
+
return "bedrock";
|
|
125
|
+
}
|
|
126
|
+
if (env.CLAUDE_CODE_USE_VERTEX === "1") return "vertex";
|
|
127
|
+
if (env.ANTHROPIC_API_KEY) return "api_key";
|
|
128
|
+
if (env.ANTHROPIC_AUTH_TOKEN) return "auth_token";
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
116
132
|
function checkClaude() {
|
|
133
|
+
var provider = hasThirdPartyProviderAuth();
|
|
134
|
+
if (provider) {
|
|
135
|
+
console.log("[yoke] Claude auth via third-party provider: " + provider);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
117
139
|
try {
|
|
118
140
|
var out = execSync("claude auth status --json", { timeout: 5000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
119
141
|
var parsed = parseClaudeAuthStatusJson(out);
|
|
@@ -159,15 +181,26 @@ function checkAuth() {
|
|
|
159
181
|
}
|
|
160
182
|
}
|
|
161
183
|
|
|
162
|
-
_authCache = { claude: checkClaude(), codex: checkCodex()
|
|
184
|
+
_authCache = { claude: checkClaude(), codex: checkCodex() };
|
|
163
185
|
logAuthCheck(_authCache);
|
|
164
186
|
return _authCache;
|
|
165
187
|
}
|
|
166
188
|
|
|
167
189
|
/**
|
|
168
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.
|
|
169
198
|
*/
|
|
199
|
+
var _installedCache = null;
|
|
200
|
+
|
|
170
201
|
function checkInstalled() {
|
|
202
|
+
if (_installedCache) return _installedCache;
|
|
203
|
+
|
|
171
204
|
var fs = require("fs");
|
|
172
205
|
var execFileSync = require("child_process").execFileSync;
|
|
173
206
|
var result = { claude: false, codex: false };
|
|
@@ -183,6 +216,7 @@ function checkInstalled() {
|
|
|
183
216
|
codexBin = findCodexPath();
|
|
184
217
|
if (codexBin && fs.existsSync(codexBin)) {
|
|
185
218
|
result.codex = true;
|
|
219
|
+
_installedCache = result;
|
|
186
220
|
return result;
|
|
187
221
|
}
|
|
188
222
|
} catch (e) {}
|
|
@@ -192,45 +226,56 @@ function checkInstalled() {
|
|
|
192
226
|
: execFileSync("which", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
193
227
|
if (whichOut.trim()) result.codex = true;
|
|
194
228
|
} catch (e) {}
|
|
229
|
+
_installedCache = result;
|
|
195
230
|
return result;
|
|
196
231
|
}
|
|
197
232
|
|
|
198
233
|
function invalidateAuthCache() {
|
|
199
234
|
_authCache = null;
|
|
235
|
+
_installedCache = null;
|
|
200
236
|
}
|
|
201
237
|
|
|
202
238
|
/**
|
|
203
239
|
* Create adapters for all authenticated vendors.
|
|
204
|
-
*
|
|
205
|
-
*
|
|
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.
|
|
206
242
|
* Returns { adapters: { vendor: Adapter }, auth: { vendor: boolean } }
|
|
207
243
|
*/
|
|
208
|
-
var
|
|
209
|
-
var _sharedAuth = null;
|
|
244
|
+
var _sharedClaudeAdapter = null;
|
|
210
245
|
|
|
211
246
|
function createAdapters(opts) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
247
|
+
opts = opts || {};
|
|
248
|
+
// Gate adapter creation on binary installation, not OAuth auth status.
|
|
249
|
+
// Claude Code supports multiple auth modes (OAuth, Bedrock, Vertex, API key)
|
|
250
|
+
// that `claude auth status` does not always detect. Runtime auth failures are
|
|
251
|
+
// handled downstream via query-level error detection.
|
|
252
|
+
var installed = checkInstalled();
|
|
253
|
+
var auth = { claude: false, codex: false };
|
|
217
254
|
var adapters = {};
|
|
218
|
-
var vendors = Object.keys(auth);
|
|
219
255
|
|
|
220
|
-
|
|
221
|
-
var vendor = vendors[i];
|
|
222
|
-
if (!auth[vendor]) continue;
|
|
256
|
+
if (installed.claude) {
|
|
223
257
|
try {
|
|
224
|
-
|
|
225
|
-
|
|
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");
|
|
226
264
|
} catch (e) {
|
|
227
|
-
console.error("[yoke] Failed to create adapter for
|
|
228
|
-
|
|
265
|
+
console.error("[yoke] Failed to create adapter for claude:", e.message);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (installed.codex) {
|
|
270
|
+
try {
|
|
271
|
+
adapters.codex = createAdapter({ vendor: "codex", cwd: opts.cwd, slug: opts.slug });
|
|
272
|
+
auth.codex = true;
|
|
273
|
+
console.log("[yoke] Adapter created: codex");
|
|
274
|
+
} catch (e) {
|
|
275
|
+
console.error("[yoke] Failed to create adapter for codex:", e.message);
|
|
229
276
|
}
|
|
230
277
|
}
|
|
231
278
|
|
|
232
|
-
_sharedAdapters = adapters;
|
|
233
|
-
_sharedAuth = auth;
|
|
234
279
|
return { adapters: adapters, auth: auth };
|
|
235
280
|
}
|
|
236
281
|
|
|
@@ -240,26 +285,19 @@ function createAdapters(opts) {
|
|
|
240
285
|
* Returns the adapter or null.
|
|
241
286
|
*/
|
|
242
287
|
async function lazyCreateAdapter(adapters, vendor, opts) {
|
|
243
|
-
|
|
244
|
-
adapters[vendor] = _sharedAdapters[vendor];
|
|
245
|
-
return adapters[vendor];
|
|
246
|
-
}
|
|
288
|
+
opts = opts || {};
|
|
247
289
|
|
|
248
290
|
// Force re-check since user may have logged in after server start
|
|
249
291
|
invalidateAuthCache();
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
var auth = checkAuth();
|
|
253
|
-
if (!auth[vendor]) return null;
|
|
292
|
+
var installed = checkInstalled();
|
|
293
|
+
if (!installed[vendor]) return null;
|
|
254
294
|
|
|
255
295
|
try {
|
|
256
|
-
var ad = createAdapter({ vendor: vendor, cwd: opts.cwd });
|
|
296
|
+
var ad = createAdapter({ vendor: vendor, cwd: opts.cwd, slug: opts.slug });
|
|
257
297
|
if (typeof ad.init === "function") {
|
|
258
298
|
await ad.init(opts || {});
|
|
259
299
|
}
|
|
260
300
|
console.log("[yoke] Lazy adapter created: " + vendor);
|
|
261
|
-
if (_sharedAdapters) _sharedAdapters[vendor] = ad;
|
|
262
|
-
if (_sharedAuth) _sharedAuth[vendor] = true;
|
|
263
301
|
adapters[vendor] = ad;
|
|
264
302
|
return ad;
|
|
265
303
|
} catch (e) {
|
package/lib/yoke/instructions.js
CHANGED
|
@@ -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,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clay-server",
|
|
3
|
-
"version": "2.34.0-beta.
|
|
3
|
+
"version": "2.34.0-beta.4",
|
|
4
4
|
"description": "Self-hosted Claude Code in your browser. Multi-session, multi-user, push notifications.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"clay-server": "./bin/cli.js",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"author": "Chad",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@anthropic-ai/claude-agent-sdk": "^0.2.112",
|
|
40
|
-
"@google/genai": "^1.49.0",
|
|
41
40
|
"@lydell/node-pty": "^1.2.0-beta.3",
|
|
42
41
|
"@openai/codex": "^0.121.0",
|
|
43
42
|
"imapflow": "^1.3.1",
|