clay-server 3.8.1 → 4.0.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/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -1065,7 +1065,7 @@ function createKiroAdapter(opts) {
|
|
|
1065
1065
|
var model = queryOpts.model || _defaultModel || "auto";
|
|
1066
1066
|
var ac = queryOpts.abortController || new AbortController();
|
|
1067
1067
|
var kiroOpts = (queryOpts.adapterOptions && queryOpts.adapterOptions.KIRO) || {};
|
|
1068
|
-
var sharedSkills = skillDiscovery.discoverSkills(queryOpts.cwd || _cwd);
|
|
1068
|
+
var sharedSkills = queryOpts.skipSkills ? [] : skillDiscovery.discoverSkills(queryOpts.cwd || _cwd);
|
|
1069
1069
|
var skillIndex = skillDiscovery.buildSkillIndex(sharedSkills);
|
|
1070
1070
|
|
|
1071
1071
|
var activeEntry = { abort: function() { try { ac.abort(); } catch (e) {} } };
|
|
@@ -1123,6 +1123,7 @@ function createKiroAdapter(opts) {
|
|
|
1123
1123
|
var ac = new AbortController();
|
|
1124
1124
|
var handle = await adapter.createQuery({
|
|
1125
1125
|
cwd: (opts && opts.cwd) || _cwd,
|
|
1126
|
+
env: opts && opts.env,
|
|
1126
1127
|
systemPrompt: systemPrompt,
|
|
1127
1128
|
model: "auto",
|
|
1128
1129
|
abortController: ac,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Claude SDK mappings for YOKE structured user input.
|
|
2
|
+
var userInput = require("./user-input");
|
|
3
|
+
|
|
4
|
+
function ask(handler, input, opts) {
|
|
5
|
+
opts = opts || {};
|
|
6
|
+
return userInput.dispatchUserInput(handler, input, {
|
|
7
|
+
requestId: opts.toolUseID || opts.requestId,
|
|
8
|
+
signal: opts.signal,
|
|
9
|
+
source: "claude_ask_user_question",
|
|
10
|
+
native: true,
|
|
11
|
+
provider: "claude",
|
|
12
|
+
}).then(function (result) { return userInput.claudePermissionResult(input, result); });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function elicitation(handler, request, opts) {
|
|
16
|
+
opts = opts || {};
|
|
17
|
+
return userInput.dispatchUserInput(handler, userInput.questionsFromElicitation(request), {
|
|
18
|
+
requestId: opts.requestId || request.elicitationId,
|
|
19
|
+
signal: opts.signal,
|
|
20
|
+
source: "claude_elicitation",
|
|
21
|
+
native: true,
|
|
22
|
+
provider: "claude",
|
|
23
|
+
presentation: "elicitation",
|
|
24
|
+
diagnostics: { elicitation: request },
|
|
25
|
+
}).then(userInput.elicitationResponse);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function canUseTool(queryOpts) {
|
|
29
|
+
var original = queryOpts.canUseTool;
|
|
30
|
+
return function (toolName, input, opts) {
|
|
31
|
+
if (toolName === "AskUserQuestion" && typeof queryOpts.onUserInputRequest === "function") return ask(queryOpts.onUserInputRequest, input, opts);
|
|
32
|
+
if (toolName === "AskUserQuestion") return Promise.resolve({ behavior: "deny", message: "Use the query's structured input fallback tool." });
|
|
33
|
+
if (original) return original(toolName, input, opts);
|
|
34
|
+
return Promise.resolve({ behavior: "deny", message: "No tool permission handler is available." });
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { ask: ask, elicitation: elicitation, canUseTool: canUseTool };
|
|
@@ -13,7 +13,13 @@ var { buildUserEnv } = require("../build-user-env");
|
|
|
13
13
|
var { wrapSpawnAsUser } = require("../os-users");
|
|
14
14
|
|
|
15
15
|
// --- Find the codex binary path ---
|
|
16
|
-
// Mirrors the logic from @openai/codex-sdk findCodexPath()
|
|
16
|
+
// Mirrors the logic from @openai/codex-sdk findCodexPath().
|
|
17
|
+
//
|
|
18
|
+
// The bundled @openai/codex platform package is the default. Set the
|
|
19
|
+
// CLAY_CODEX_PATH env var to an existing executable to run a different codex
|
|
20
|
+
// build (local dev build, system install, pinned older release); the chosen
|
|
21
|
+
// binary is logged on every resolution. An unset or non-existent
|
|
22
|
+
// CLAY_CODEX_PATH silently falls back to the bundled resolution.
|
|
17
23
|
|
|
18
24
|
var PLATFORM_PACKAGE_BY_TARGET = {
|
|
19
25
|
"aarch64-apple-darwin": "@openai/codex-darwin-arm64",
|
|
@@ -39,6 +45,15 @@ function getTargetTriple() {
|
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
function findCodexPath() {
|
|
48
|
+
var override = process.env.CLAY_CODEX_PATH;
|
|
49
|
+
if (override) {
|
|
50
|
+
if (fs.existsSync(override)) {
|
|
51
|
+
console.log("[codex-app-server] Using CLAY_CODEX_PATH binary:", override);
|
|
52
|
+
return override;
|
|
53
|
+
}
|
|
54
|
+
console.warn("[codex-app-server] CLAY_CODEX_PATH does not exist, falling back to bundled codex:", override);
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
var triple = getTargetTriple();
|
|
43
58
|
if (!triple) throw new Error("Unsupported platform: " + process.platform + "/" + process.arch);
|
|
44
59
|
|
|
@@ -59,7 +74,10 @@ function findCodexPath() {
|
|
|
59
74
|
path.join(vendorRoot, triple, "codex", binaryName),
|
|
60
75
|
];
|
|
61
76
|
for (var i = 0; i < candidates.length; i++) {
|
|
62
|
-
if (fs.existsSync(candidates[i]))
|
|
77
|
+
if (fs.existsSync(candidates[i])) {
|
|
78
|
+
console.log("[codex-app-server] Using bundled codex binary:", candidates[i]);
|
|
79
|
+
return candidates[i];
|
|
80
|
+
}
|
|
63
81
|
}
|
|
64
82
|
throw new Error("codex binary not found in any known layout under " + path.join(vendorRoot, triple));
|
|
65
83
|
} catch (e) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Codex app-server 0.147 structured user-input protocol mapping.
|
|
2
|
+
var userInput = require("./user-input");
|
|
3
|
+
|
|
4
|
+
function nativeInput(params) {
|
|
5
|
+
return {
|
|
6
|
+
questions: (params.questions || []).map(function (question) {
|
|
7
|
+
return {
|
|
8
|
+
id: question.id,
|
|
9
|
+
header: question.header || "",
|
|
10
|
+
question: question.question,
|
|
11
|
+
allowOther: question.isOther !== false,
|
|
12
|
+
secret: question.isSecret === true,
|
|
13
|
+
options: Array.isArray(question.options) ? question.options : [],
|
|
14
|
+
};
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function handleNative(appServer, msg, handler, expectedThreadId, signal) {
|
|
20
|
+
var params = msg.params || {};
|
|
21
|
+
if (!params.threadId || (expectedThreadId && params.threadId !== expectedThreadId)) {
|
|
22
|
+
appServer.respondError(msg.id, -32001, "Structured input request does not belong to this query thread.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
userInput.dispatchUserInput(handler, nativeInput(params), {
|
|
26
|
+
requestId: params.itemId || String(msg.id),
|
|
27
|
+
signal: signal,
|
|
28
|
+
source: "codex_request_user_input",
|
|
29
|
+
native: true,
|
|
30
|
+
provider: "codex",
|
|
31
|
+
diagnostics: { threadId: params.threadId, turnId: params.turnId || null, itemId: params.itemId || null },
|
|
32
|
+
}).then(function (result) {
|
|
33
|
+
appServer.respond(msg.id, userInput.codexResponse(result));
|
|
34
|
+
}).catch(function (error) {
|
|
35
|
+
appServer.respondError(msg.id, -32602, error.message);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function handleElicitation(appServer, msg, handler, signal) {
|
|
40
|
+
var params = msg.params || {};
|
|
41
|
+
var request = {
|
|
42
|
+
serverName: params.serverName || (params._meta && params._meta.tool) || "Tool",
|
|
43
|
+
message: params.message || params.prompt || "",
|
|
44
|
+
url: params.url || null,
|
|
45
|
+
elicitationId: params.elicitationId || null,
|
|
46
|
+
requestedSchema: params.requestedSchema || null,
|
|
47
|
+
};
|
|
48
|
+
var input = Array.isArray(params.questions) ? nativeInput(params) : userInput.questionsFromElicitation(request);
|
|
49
|
+
userInput.dispatchUserInput(handler, input, {
|
|
50
|
+
requestId: request.elicitationId || String(msg.id),
|
|
51
|
+
signal: signal,
|
|
52
|
+
source: "codex_mcp_elicitation",
|
|
53
|
+
native: true,
|
|
54
|
+
provider: "codex",
|
|
55
|
+
presentation: "elicitation",
|
|
56
|
+
diagnostics: { threadId: params.threadId || null, elicitation: request },
|
|
57
|
+
}).then(function (result) {
|
|
58
|
+
appServer.respond(msg.id, userInput.elicitationResponse(result));
|
|
59
|
+
}).catch(function (error) {
|
|
60
|
+
appServer.respondError(msg.id, -32602, error.message);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { nativeInput: nativeInput, handleNative: handleNative, handleElicitation: handleElicitation };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Canonical single-turn completion lifecycle for YOKE adapters.
|
|
2
|
+
|
|
3
|
+
function assistantMessageText(event) {
|
|
4
|
+
if (!event || event.yokeType !== "message" || event.messageRole !== "assistant") return "";
|
|
5
|
+
if (!Array.isArray(event.content)) return "";
|
|
6
|
+
var text = "";
|
|
7
|
+
for (var i = 0; i < event.content.length; i++) {
|
|
8
|
+
if (event.content[i] && event.content[i].type === "text" && event.content[i].text) {
|
|
9
|
+
text += event.content[i].text;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return text;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizedText(streamedText, finalText) {
|
|
16
|
+
if (!streamedText) return finalText;
|
|
17
|
+
if (!finalText) return streamedText;
|
|
18
|
+
if (finalText.indexOf(streamedText) === 0) return finalText;
|
|
19
|
+
if (streamedText.indexOf(finalText) === 0) return streamedText;
|
|
20
|
+
return streamedText;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function oneShotError(event) {
|
|
24
|
+
if (!event) return null;
|
|
25
|
+
if (event.yokeType === "error") return new Error(event.text || "One-shot completion failed.");
|
|
26
|
+
if (event.yokeType === "auth_required") {
|
|
27
|
+
return new Error("The " + (event.vendor || "selected") + " provider requires sign-in.");
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function createOneShot(adapter, queryOpts, allowUnknownPersistence) {
|
|
33
|
+
if (typeof adapter.createOneShotQuery === "function") {
|
|
34
|
+
var created = await adapter.createOneShotQuery(queryOpts);
|
|
35
|
+
if (!created || !created.handle) throw new Error("YOKE adapter returned an invalid one-shot query.");
|
|
36
|
+
if (created.backendPersistence !== "ephemeral") {
|
|
37
|
+
if (!allowUnknownPersistence) {
|
|
38
|
+
if (typeof created.handle.abort === "function") created.handle.abort();
|
|
39
|
+
if (typeof created.handle.close === "function") created.handle.close();
|
|
40
|
+
throw new Error("The " + adapter.vendor + " adapter did not confirm ephemeral one-shot execution.");
|
|
41
|
+
}
|
|
42
|
+
created.backendPersistence = "unknown";
|
|
43
|
+
}
|
|
44
|
+
return created;
|
|
45
|
+
}
|
|
46
|
+
if (!allowUnknownPersistence) {
|
|
47
|
+
throw new Error("The " + adapter.vendor + " adapter does not guarantee ephemeral one-shot execution.");
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
handle: await adapter.createQuery(Object.assign({}, queryOpts, { persistSession: false })),
|
|
51
|
+
backendPersistence: "unknown",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function completeOnce(adapter, opts) {
|
|
56
|
+
opts = opts || {};
|
|
57
|
+
if (!adapter || typeof adapter.createQuery !== "function") throw new Error("A YOKE adapter is required.");
|
|
58
|
+
if (typeof opts.prompt !== "string" || !opts.prompt.trim()) throw new Error("A one-shot prompt is required.");
|
|
59
|
+
|
|
60
|
+
var timeoutMs = opts.timeoutMs || 60000;
|
|
61
|
+
var controller = new AbortController();
|
|
62
|
+
var handle = null;
|
|
63
|
+
var timedOut = false;
|
|
64
|
+
var externallyAborted = false;
|
|
65
|
+
var timer = null;
|
|
66
|
+
var externalSignal = opts.signal || null;
|
|
67
|
+
var abortHandle = function() {
|
|
68
|
+
controller.abort();
|
|
69
|
+
if (handle && typeof handle.abort === "function") handle.abort();
|
|
70
|
+
};
|
|
71
|
+
var onExternalAbort = function() {
|
|
72
|
+
externallyAborted = true;
|
|
73
|
+
abortHandle();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (externalSignal) {
|
|
77
|
+
if (externalSignal.aborted) onExternalAbort();
|
|
78
|
+
else externalSignal.addEventListener("abort", onExternalAbort, { once: true });
|
|
79
|
+
}
|
|
80
|
+
timer = setTimeout(function() {
|
|
81
|
+
timedOut = true;
|
|
82
|
+
abortHandle();
|
|
83
|
+
}, timeoutMs);
|
|
84
|
+
|
|
85
|
+
var streamedText = "";
|
|
86
|
+
var finalText = "";
|
|
87
|
+
var resultEvent = null;
|
|
88
|
+
var interactiveRequested = false;
|
|
89
|
+
var created;
|
|
90
|
+
try {
|
|
91
|
+
var queryOpts = Object.assign({}, opts.query || {}, {
|
|
92
|
+
cwd: opts.cwd,
|
|
93
|
+
model: opts.model,
|
|
94
|
+
systemPrompt: opts.systemPrompt,
|
|
95
|
+
abortController: controller,
|
|
96
|
+
onUserInputRequest: function (request, respond) {
|
|
97
|
+
interactiveRequested = true;
|
|
98
|
+
respond.cancel("One-shot completions cannot request interactive user input.");
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
var creationFinished = false;
|
|
102
|
+
var rejectCreation;
|
|
103
|
+
var creationAbort = new Promise(function(resolve, reject) { rejectCreation = reject; });
|
|
104
|
+
var onCreationAbort = function() { rejectCreation(new Error("One-shot completion aborted.")); };
|
|
105
|
+
controller.signal.addEventListener("abort", onCreationAbort, { once: true });
|
|
106
|
+
var creation = createOneShot(adapter, queryOpts, !!opts.allowUnknownBackendPersistence);
|
|
107
|
+
creation.then(function(lateCreated) {
|
|
108
|
+
if (!creationFinished && controller.signal.aborted && lateCreated && lateCreated.handle) {
|
|
109
|
+
if (typeof lateCreated.handle.abort === "function") lateCreated.handle.abort();
|
|
110
|
+
if (typeof lateCreated.handle.close === "function") lateCreated.handle.close();
|
|
111
|
+
}
|
|
112
|
+
}).catch(function() {});
|
|
113
|
+
try {
|
|
114
|
+
created = await Promise.race([creation, creationAbort]);
|
|
115
|
+
creationFinished = true;
|
|
116
|
+
} finally {
|
|
117
|
+
controller.signal.removeEventListener("abort", onCreationAbort);
|
|
118
|
+
}
|
|
119
|
+
handle = created.handle;
|
|
120
|
+
if (controller.signal.aborted) {
|
|
121
|
+
if (typeof handle.abort === "function") handle.abort();
|
|
122
|
+
throw new Error("One-shot completion aborted.");
|
|
123
|
+
}
|
|
124
|
+
if (handle.pushMessage(opts.prompt) !== true) {
|
|
125
|
+
throw new Error("YOKE one-shot query rejected its prompt.");
|
|
126
|
+
}
|
|
127
|
+
handle.endInput();
|
|
128
|
+
|
|
129
|
+
for await (var event of handle) {
|
|
130
|
+
var eventError = oneShotError(event);
|
|
131
|
+
if (eventError) throw eventError;
|
|
132
|
+
if (event.yokeType === "text_delta" && event.text) streamedText += event.text;
|
|
133
|
+
var messageText = assistantMessageText(event);
|
|
134
|
+
if (messageText) finalText = messageText;
|
|
135
|
+
if (event.yokeType === "result") {
|
|
136
|
+
resultEvent = event;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (timedOut) throw new Error("YOKE one-shot timed out after " + timeoutMs + " ms.");
|
|
141
|
+
if (externallyAborted) throw new Error("YOKE one-shot was aborted.");
|
|
142
|
+
if (interactiveRequested) throw new Error("YOKE one-shot completion requested interactive user input.");
|
|
143
|
+
return {
|
|
144
|
+
text: normalizedText(streamedText, finalText).trim(),
|
|
145
|
+
backendPersistence: created.backendPersistence || "unknown",
|
|
146
|
+
vendor: adapter.vendor,
|
|
147
|
+
model: opts.model || null,
|
|
148
|
+
result: resultEvent,
|
|
149
|
+
};
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (timedOut) throw new Error("YOKE one-shot timed out after " + timeoutMs + " ms.");
|
|
152
|
+
if (externallyAborted) throw new Error("YOKE one-shot was aborted.");
|
|
153
|
+
throw error;
|
|
154
|
+
} finally {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
if (externalSignal) externalSignal.removeEventListener("abort", onExternalAbort);
|
|
157
|
+
if (handle && typeof handle.close === "function") handle.close();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
completeOnce: completeOnce,
|
|
163
|
+
normalizedText: normalizedText,
|
|
164
|
+
};
|
package/lib/yoke/index.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
var iface = require("./interface");
|
|
5
5
|
var instructions = require("./instructions");
|
|
6
6
|
var vendorRegistry = require("./vendor-registry");
|
|
7
|
+
var completeOnce = require("./complete-once").completeOnce;
|
|
8
|
+
var userInput = require("./user-input");
|
|
7
9
|
var createClaudeAdapter = require("./adapters/claude").createClaudeAdapter;
|
|
8
10
|
var createCodexAdapter = require("./adapters/codex").createCodexAdapter;
|
|
9
11
|
var createAntigravityAdapter = require("./adapters/antigravity").createAntigravityAdapter;
|
|
@@ -47,7 +49,7 @@ function wrapCreateQuery(adapter, defaultCwd) {
|
|
|
47
49
|
adapter.createQuery = function(queryOpts) {
|
|
48
50
|
queryOpts = queryOpts || {};
|
|
49
51
|
var projectDir = (queryOpts && queryOpts.cwd) || defaultCwd;
|
|
50
|
-
var merged = instructions.scanAndMerge(projectDir, adapter.vendor);
|
|
52
|
+
var merged = queryOpts.skipProjectInstructions ? "" : instructions.scanAndMerge(projectDir, adapter.vendor);
|
|
51
53
|
|
|
52
54
|
if (merged) {
|
|
53
55
|
var parts = [];
|
|
@@ -473,4 +475,6 @@ module.exports = {
|
|
|
473
475
|
TOOL_POLICIES: iface.TOOL_POLICIES,
|
|
474
476
|
validateAdapter: iface.validateAdapter,
|
|
475
477
|
validateQueryHandle: iface.validateQueryHandle,
|
|
478
|
+
completeOnce: completeOnce,
|
|
479
|
+
userInput: userInput,
|
|
476
480
|
};
|
package/lib/yoke/interface.js
CHANGED
|
@@ -40,6 +40,25 @@ var INITIALIZE_TIMEOUT_MS = 90000;
|
|
|
40
40
|
* .createToolServer(def): ToolServer (opaque)
|
|
41
41
|
* .createQuery(opts): QueryHandle
|
|
42
42
|
*
|
|
43
|
+
* Optional one-shot capability:
|
|
44
|
+
* .createOneShotQuery(opts): Promise<{ handle, backendPersistence }>
|
|
45
|
+
* backendPersistence is "ephemeral" only when the adapter can verify the
|
|
46
|
+
* provider does not materialize the backend conversation. Adapters without
|
|
47
|
+
* this method may only use completeOnce's explicit unknown-persistence path.
|
|
48
|
+
*
|
|
49
|
+
* Optional structured user-input capability:
|
|
50
|
+
* .userInputCapability: { mode: "native"|"fallback", native: boolean, transport: string }
|
|
51
|
+
* createQuery({ userInputMode: "auto"|"native"|"fallback",
|
|
52
|
+
* onUserInputRequest(request, respond) })
|
|
53
|
+
* request.presentation is "questions" or "elicitation";
|
|
54
|
+
* request.questions contain 1-3 { id, header, question, multiSelect,
|
|
55
|
+
* allowOther, secret, options }; options contain zero or 2-6 safe
|
|
56
|
+
* { label, description } entries. respond(answerMap),
|
|
57
|
+
* respond.submitContent(typedMap), and respond.cancel(reason) settle
|
|
58
|
+
* exactly once. submitContent preserves typed MCP elicitation forms.
|
|
59
|
+
* Adapters with mode "native" translate their provider protocol directly.
|
|
60
|
+
* Other adapters use createFallbackServer() from yoke/user-input.
|
|
61
|
+
*
|
|
43
62
|
* Lightweight utilities:
|
|
44
63
|
* .generateTitle(messages, opts) : Promise<string> - generate a short session title
|
|
45
64
|
* messages: string[] - user messages to derive the title from
|
|
@@ -102,12 +102,8 @@ function postJson(urlPath, body) {
|
|
|
102
102
|
reject(err);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
// 10 min safety ceiling.
|
|
106
|
-
//
|
|
107
|
-
// user message), so no tool call should legitimately block long.
|
|
108
|
-
// The generous ceiling is just a belt-and-suspenders against slow
|
|
109
|
-
// browser automation or external MCP servers, not the primary
|
|
110
|
-
// mechanism for human-in-the-loop tools.
|
|
105
|
+
// 10 min safety ceiling. Structured user input may legitimately wait
|
|
106
|
+
// for a person, while other tools normally return much sooner.
|
|
111
107
|
req.setTimeout(600000, function () {
|
|
112
108
|
req.destroy(new Error("Request timed out"));
|
|
113
109
|
});
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Provider-neutral structured user-input lifecycle for YOKE queries.
|
|
2
|
+
|
|
3
|
+
var crypto = require("crypto");
|
|
4
|
+
var z;
|
|
5
|
+
try { z = require("zod"); } catch (e) { z = null; }
|
|
6
|
+
|
|
7
|
+
var TOOL_NAME = "ask_user_questions";
|
|
8
|
+
|
|
9
|
+
function cleanText(value, field, max) {
|
|
10
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(field + " must be a non-empty string.");
|
|
11
|
+
var text = value.trim();
|
|
12
|
+
if (text.length > max) throw new Error(field + " must be at most " + max + " characters.");
|
|
13
|
+
return text;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeOptions(options, questionIndex) {
|
|
17
|
+
if (options == null) return [];
|
|
18
|
+
if (!Array.isArray(options)) throw new Error("Question " + (questionIndex + 1) + " options must be an array.");
|
|
19
|
+
if (options.length === 1 || options.length > 6) {
|
|
20
|
+
throw new Error("Question " + (questionIndex + 1) + " must use zero options or 2-6 options.");
|
|
21
|
+
}
|
|
22
|
+
var result = [];
|
|
23
|
+
for (var i = 0; i < options.length; i++) {
|
|
24
|
+
var option = options[i] || {};
|
|
25
|
+
result.push({
|
|
26
|
+
label: cleanText(option.label || option.value, "Option label", 60),
|
|
27
|
+
description: typeof option.description === "string" ? option.description.trim().substring(0, 160) : "",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeQuestions(input) {
|
|
34
|
+
var source = input && Array.isArray(input.questions) ? input.questions : null;
|
|
35
|
+
if (!source || source.length < 1 || source.length > 3) throw new Error("Structured input requires 1-3 questions.");
|
|
36
|
+
var ids = {};
|
|
37
|
+
var questions = [];
|
|
38
|
+
for (var i = 0; i < source.length; i++) {
|
|
39
|
+
var item = source[i] || {};
|
|
40
|
+
var id = typeof item.id === "string" && item.id.trim() ? item.id.trim() : "question_" + (i + 1);
|
|
41
|
+
if (id.length > 128 || ids[id]) throw new Error("Question IDs must be unique strings of at most 128 characters.");
|
|
42
|
+
ids[id] = true;
|
|
43
|
+
questions.push({
|
|
44
|
+
id: id,
|
|
45
|
+
header: typeof item.header === "string" ? item.header.trim().substring(0, 40) : "",
|
|
46
|
+
question: cleanText(item.question || item.prompt, "Question", 2000),
|
|
47
|
+
multiSelect: item.multiSelect === true,
|
|
48
|
+
allowOther: item.allowOther !== false && item.isOther !== false,
|
|
49
|
+
secret: item.secret === true || item.isSecret === true,
|
|
50
|
+
options: normalizeOptions(item.options, i),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return questions;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function questionsFromElicitation(request) {
|
|
57
|
+
var schema = request && request.requestedSchema;
|
|
58
|
+
var properties = schema && schema.properties && typeof schema.properties === "object" ? schema.properties : null;
|
|
59
|
+
var questions = [];
|
|
60
|
+
if (properties) {
|
|
61
|
+
Object.keys(properties).forEach(function (id) {
|
|
62
|
+
var property = properties[id] || {};
|
|
63
|
+
var values = Array.isArray(property.enum) ? property.enum : [];
|
|
64
|
+
questions.push({
|
|
65
|
+
id: id,
|
|
66
|
+
header: request.serverName || "Input",
|
|
67
|
+
question: property.description || request.message || id,
|
|
68
|
+
options: values.map(function (value) { return { label: String(value), description: "" }; }),
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (!questions.length) questions.push({ id: "response", header: request.serverName || "Input", question: request.message || "What should the tool use?", options: [] });
|
|
73
|
+
return { questions: questions };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function answerValues(value) {
|
|
77
|
+
if (value && Array.isArray(value.answers)) value = value.answers;
|
|
78
|
+
if (!Array.isArray(value)) value = value == null ? [] : [value];
|
|
79
|
+
return value.map(function (entry) { return String(entry).trim(); }).filter(Boolean);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizeAnswers(questions, raw) {
|
|
83
|
+
raw = raw || {};
|
|
84
|
+
var answers = {};
|
|
85
|
+
for (var i = 0; i < questions.length; i++) {
|
|
86
|
+
var question = questions[i];
|
|
87
|
+
var value = Object.prototype.hasOwnProperty.call(raw, question.id) ? raw[question.id] : raw[i];
|
|
88
|
+
var values = answerValues(value);
|
|
89
|
+
if (!values.length) throw new Error("An answer is required for " + question.id + ".");
|
|
90
|
+
if (!question.multiSelect && values.length > 1) throw new Error("Only one answer is allowed for " + question.id + ".");
|
|
91
|
+
answers[question.id] = values;
|
|
92
|
+
}
|
|
93
|
+
return answers;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Start one provider-neutral structured-input request.
|
|
98
|
+
*
|
|
99
|
+
* handler receives:
|
|
100
|
+
* request: { id, questions, source, native, provider, diagnostics }
|
|
101
|
+
* respond(answers): submits once; respond.cancel(reason) cancels once.
|
|
102
|
+
*
|
|
103
|
+
* The returned promise resolves to { status, answers|reason }. Provider
|
|
104
|
+
* adapters translate that result back to their own wire protocol. Nothing in
|
|
105
|
+
* this lifecycle is persisted; Clay callers may persist sanitized events.
|
|
106
|
+
*/
|
|
107
|
+
function dispatchUserInput(handler, input, opts) {
|
|
108
|
+
opts = opts || {};
|
|
109
|
+
var questions;
|
|
110
|
+
try { questions = normalizeQuestions(input); } catch (e) { return Promise.reject(e); }
|
|
111
|
+
if (typeof handler !== "function") return Promise.reject(new Error("This query cannot request structured user input."));
|
|
112
|
+
var id = opts.requestId || (input && input.id) || "yoke_input_" + crypto.randomUUID();
|
|
113
|
+
var settled = false;
|
|
114
|
+
var abortHandler = null;
|
|
115
|
+
var settleListeners = [];
|
|
116
|
+
return new Promise(function (resolve, reject) {
|
|
117
|
+
function cleanup(result) {
|
|
118
|
+
if (opts.signal && abortHandler && typeof opts.signal.removeEventListener === "function") opts.signal.removeEventListener("abort", abortHandler);
|
|
119
|
+
for (var li = 0; li < settleListeners.length; li++) {
|
|
120
|
+
try { settleListeners[li](result); } catch (e) {}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function finish(result) {
|
|
124
|
+
if (settled) return false;
|
|
125
|
+
settled = true;
|
|
126
|
+
cleanup(result);
|
|
127
|
+
resolve(result);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
function fail(error) {
|
|
131
|
+
if (settled) return false;
|
|
132
|
+
settled = true;
|
|
133
|
+
cleanup({ status: "error", error: error.message || String(error) });
|
|
134
|
+
reject(error);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
var respond = function (answers) {
|
|
138
|
+
try { return finish({ status: "submitted", answers: normalizeAnswers(questions, answers) }); }
|
|
139
|
+
catch (e) { return fail(e); }
|
|
140
|
+
};
|
|
141
|
+
respond.submitContent = function (content) {
|
|
142
|
+
if (!content || typeof content !== "object" || Array.isArray(content)) return fail(new Error("Structured elicitation content must be an object."));
|
|
143
|
+
return finish({ status: "submitted", answers: {}, content: content });
|
|
144
|
+
};
|
|
145
|
+
respond.cancel = function (reason) { return finish({ status: "cancelled", reason: reason || "Cancelled" }); };
|
|
146
|
+
respond.isPending = function () { return !settled; };
|
|
147
|
+
respond.onSettle = function (listener) {
|
|
148
|
+
if (typeof listener === "function" && !settled) settleListeners.push(listener);
|
|
149
|
+
return respond;
|
|
150
|
+
};
|
|
151
|
+
abortHandler = function () { respond.cancel("Aborted"); };
|
|
152
|
+
if (opts.signal) {
|
|
153
|
+
if (opts.signal.aborted) return abortHandler();
|
|
154
|
+
opts.signal.addEventListener("abort", abortHandler, { once: true });
|
|
155
|
+
}
|
|
156
|
+
var request = {
|
|
157
|
+
id: String(id),
|
|
158
|
+
questions: questions,
|
|
159
|
+
presentation: opts.presentation || "questions",
|
|
160
|
+
source: opts.source || "unknown",
|
|
161
|
+
native: opts.native === true,
|
|
162
|
+
provider: opts.provider || null,
|
|
163
|
+
diagnostics: opts.diagnostics || null,
|
|
164
|
+
};
|
|
165
|
+
try {
|
|
166
|
+
var returned = handler(request, respond);
|
|
167
|
+
if (returned && typeof returned.then === "function") returned.catch(fail);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
fail(error);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function claudePermissionResult(input, result) {
|
|
175
|
+
if (!result || result.status !== "submitted") return { behavior: "deny", message: (result && result.reason) || "Cancelled" };
|
|
176
|
+
var questions = normalizeQuestions(input);
|
|
177
|
+
var byText = {};
|
|
178
|
+
for (var i = 0; i < questions.length; i++) byText[questions[i].question] = result.answers[questions[i].id].join(", ");
|
|
179
|
+
return { behavior: "allow", updatedInput: Object.assign({}, input, { answers: byText }) };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function codexResponse(result) {
|
|
183
|
+
var answers = {};
|
|
184
|
+
if (result && result.status === "submitted") {
|
|
185
|
+
Object.keys(result.answers).forEach(function (id) { answers[id] = { answers: result.answers[id] }; });
|
|
186
|
+
}
|
|
187
|
+
return { answers: answers };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function elicitationResponse(result) {
|
|
191
|
+
if (!result || result.status !== "submitted") return { action: "reject" };
|
|
192
|
+
if (result.content) return { action: "accept", content: result.content };
|
|
193
|
+
var content = {};
|
|
194
|
+
Object.keys(result.answers).forEach(function (id) { content[id] = result.answers[id].length === 1 ? result.answers[id][0] : result.answers[id]; });
|
|
195
|
+
return { action: "accept", content: content };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function buildQuestionShape() {
|
|
199
|
+
if (!z) return {};
|
|
200
|
+
var option = z.object({ label: z.string().min(1).max(60), description: z.string().max(160).optional() }).passthrough();
|
|
201
|
+
var question = z.object({
|
|
202
|
+
id: z.string().max(128).optional(), header: z.string().max(40).optional(), question: z.string().min(1),
|
|
203
|
+
multiSelect: z.boolean().optional(), options: z.array(option).max(6).refine(function (items) { return items.length === 0 || items.length >= 2; }),
|
|
204
|
+
}).passthrough();
|
|
205
|
+
return { questions: z.array(question).min(1).max(3) };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function fallbackToolDefs(handler) {
|
|
209
|
+
return [{
|
|
210
|
+
name: TOOL_NAME,
|
|
211
|
+
description: "Ask the user 1-3 structured questions. Use zero options for freeform or 2-6 options for choices; never one option.",
|
|
212
|
+
inputSchema: buildQuestionShape(),
|
|
213
|
+
handler: function (input) {
|
|
214
|
+
return dispatchUserInput(handler, input, { source: "mcp_fallback", native: false }).then(function (result) {
|
|
215
|
+
if (result.status !== "submitted") return { content: [{ type: "text", text: "The user cancelled this question." }], isError: true };
|
|
216
|
+
return { content: [{ type: "text", text: JSON.stringify(result.answers) }] };
|
|
217
|
+
}).catch(function (error) { return { content: [{ type: "text", text: "Error: " + error.message }], isError: true }; });
|
|
218
|
+
},
|
|
219
|
+
}];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function capability(adapter) {
|
|
223
|
+
return adapter && adapter.userInputCapability ? adapter.userInputCapability : { mode: "fallback", native: false };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function selectMode(adapter, requestedMode) {
|
|
227
|
+
if (requestedMode === "fallback") return "fallback";
|
|
228
|
+
if (requestedMode === "native" && capability(adapter).mode !== "native") {
|
|
229
|
+
throw new Error("This provider does not support native structured user input.");
|
|
230
|
+
}
|
|
231
|
+
return capability(adapter).mode === "native" ? "native" : "fallback";
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function createFallbackServer(adapter, handler) {
|
|
235
|
+
var opts = arguments.length > 2 && arguments[2] ? arguments[2] : {};
|
|
236
|
+
if (!adapter || typeof adapter.createToolServer !== "function") return null;
|
|
237
|
+
if (capability(adapter).mode === "native" && opts.force !== true) return null;
|
|
238
|
+
return adapter.createToolServer({ name: "yoke-user-input", version: "1.0.0", tools: fallbackToolDefs(handler) });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = {
|
|
242
|
+
TOOL_NAME: TOOL_NAME,
|
|
243
|
+
normalizeQuestions: normalizeQuestions,
|
|
244
|
+
questionsFromElicitation: questionsFromElicitation,
|
|
245
|
+
normalizeAnswers: normalizeAnswers,
|
|
246
|
+
dispatchUserInput: dispatchUserInput,
|
|
247
|
+
claudePermissionResult: claudePermissionResult,
|
|
248
|
+
codexResponse: codexResponse,
|
|
249
|
+
elicitationResponse: elicitationResponse,
|
|
250
|
+
fallbackToolDefs: fallbackToolDefs,
|
|
251
|
+
createFallbackServer: createFallbackServer,
|
|
252
|
+
capability: capability,
|
|
253
|
+
selectMode: selectMode,
|
|
254
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clay-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.2",
|
|
4
4
|
"description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"clay-server": "./bin/cli.js",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@anthropic-ai/claude-agent-sdk": "^0.3.241",
|
|
53
53
|
"@lydell/node-pty": "^1.2.0-beta.3",
|
|
54
|
-
"@openai/codex": "^0.
|
|
54
|
+
"@openai/codex": "^0.152.1",
|
|
55
|
+
"@seald-io/nedb": "^4.1.2",
|
|
55
56
|
"imapflow": "^1.3.1",
|
|
56
57
|
"nodemailer": "^9.0.5",
|
|
57
58
|
"qrcode-terminal": "^0.12.0",
|