clay-server 3.3.2-beta.3 → 3.4.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/project-file-watch.js +77 -16
- package/lib/project-shell-command.js +160 -0
- package/lib/project-user-message.js +10 -0
- package/lib/project.js +13 -0
- package/lib/public/app.js +10 -0
- package/lib/public/css/input.css +67 -0
- package/lib/public/css/mates.css +1 -0
- package/lib/public/gemini-avatar.svg +11 -0
- package/lib/public/index.html +13 -0
- package/lib/public/modules/app-messages.js +16 -1
- package/lib/public/modules/app-panels.js +13 -1
- package/lib/public/modules/app-projects.js +2 -0
- package/lib/public/modules/app-rendering.js +7 -1
- package/lib/public/modules/input.js +58 -28
- package/lib/public/modules/mate-sidebar.js +9 -3
- package/lib/public/modules/shell-command.js +148 -0
- package/lib/public/modules/sidebar-mates.js +7 -1
- package/lib/public/modules/tools.js +7 -1
- package/lib/public/opencode-avatar.svg +4 -0
- package/lib/sdk-bridge.js +18 -2
- package/lib/sdk-message-processor.js +10 -1
- package/lib/ws-schema.js +3 -0
- package/lib/yoke/acp-agent-profiles.js +188 -0
- package/lib/yoke/acp-driver-runtime.js +50 -0
- package/lib/yoke/acp-event-normalizer.js +179 -0
- package/lib/yoke/acp-process-manager.js +264 -0
- package/lib/yoke/acp-query-handle.js +487 -0
- package/lib/yoke/adapters/acp.js +317 -0
- package/lib/yoke/adapters/gemini.js +7 -0
- package/lib/yoke/adapters/kiro.js +4 -4
- package/lib/yoke/adapters/opencode.js +7 -0
- package/lib/yoke/index.js +45 -11
- package/lib/yoke/interface.js +2 -0
- package/lib/yoke/kiro-acp-server.js +30 -276
- package/lib/yoke/vendor-registry.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// Shared ACP Adapter
|
|
2
|
+
// ------------------
|
|
3
|
+
// Implements the YOKE Adapter contract once for standard ACP agents.
|
|
4
|
+
|
|
5
|
+
var AcpProcessManager = require("../acp-process-manager").AcpProcessManager;
|
|
6
|
+
var createAcpQueryHandle = require("../acp-query-handle").createAcpQueryHandle;
|
|
7
|
+
var profiles = require("../acp-agent-profiles");
|
|
8
|
+
var driverRuntime = require("../acp-driver-runtime");
|
|
9
|
+
var skillDiscovery = require("../skill-discovery");
|
|
10
|
+
|
|
11
|
+
function modelValues(configOptions) {
|
|
12
|
+
var models = [];
|
|
13
|
+
var options = Array.isArray(configOptions) ? configOptions : [];
|
|
14
|
+
for (var i = 0; i < options.length; i++) {
|
|
15
|
+
var option = options[i];
|
|
16
|
+
if (option.category !== "model" && option.id !== "model") continue;
|
|
17
|
+
var values = Array.isArray(option.options) ? option.options : [];
|
|
18
|
+
for (var j = 0; j < values.length; j++) {
|
|
19
|
+
var value = values[j] && values[j].value;
|
|
20
|
+
if (value && models.indexOf(value) === -1) models.push(value);
|
|
21
|
+
}
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
return models;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createAcpAdapter(vendor, opts) {
|
|
28
|
+
opts = opts || {};
|
|
29
|
+
var driver = opts._profile || opts._driver || profiles.getAcpAgentDriver(vendor);
|
|
30
|
+
if (!driver) throw new Error("[YOKE] Unknown ACP agent driver: " + vendor);
|
|
31
|
+
|
|
32
|
+
var cwd = opts.cwd || process.cwd();
|
|
33
|
+
var binaryPath = opts._binaryPath || profiles.findAcpAgentPath(driver);
|
|
34
|
+
var ProcessManagerCtor = opts._AcpProcessManagerCtor || AcpProcessManager;
|
|
35
|
+
var fetchModels = opts._fetchModels || driver.fetchModels || null;
|
|
36
|
+
var acp = null;
|
|
37
|
+
var initPromise = null;
|
|
38
|
+
var initialized = false;
|
|
39
|
+
var shuttingDown = false;
|
|
40
|
+
var initResult = null;
|
|
41
|
+
var driverState = {};
|
|
42
|
+
var cachedModels = (driver.defaultModels || []).slice();
|
|
43
|
+
var defaultModel = driver.defaultModel || cachedModels[0] || "auto";
|
|
44
|
+
var activeHandles = [];
|
|
45
|
+
var lastActiveAt = Date.now();
|
|
46
|
+
|
|
47
|
+
function context(extra) {
|
|
48
|
+
return Object.assign({
|
|
49
|
+
vendor: vendor,
|
|
50
|
+
cwd: cwd,
|
|
51
|
+
driver: driver,
|
|
52
|
+
acp: acp,
|
|
53
|
+
initResult: initResult,
|
|
54
|
+
adapter: adapter,
|
|
55
|
+
binaryPath: binaryPath,
|
|
56
|
+
driverState: driverState,
|
|
57
|
+
}, extra || {});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function supportsSessionCapability(name) {
|
|
61
|
+
var capabilities = initResult && initResult.agentCapabilities;
|
|
62
|
+
return !!(capabilities && capabilities.sessionCapabilities && capabilities.sessionCapabilities[name]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function canLoadSession() {
|
|
66
|
+
if (driver.sessionResume === false) return false;
|
|
67
|
+
return !!(initResult && initResult.agentCapabilities && initResult.agentCapabilities.loadSession);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function canResumeSession() {
|
|
71
|
+
if (driver.sessionResume === false) return false;
|
|
72
|
+
return supportsSessionCapability("resume");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function capabilities() {
|
|
76
|
+
var base = {
|
|
77
|
+
effort: false,
|
|
78
|
+
midSessionModelSwitch: false,
|
|
79
|
+
fork: false,
|
|
80
|
+
rollback: false,
|
|
81
|
+
sessionListing: false,
|
|
82
|
+
sessionRename: false,
|
|
83
|
+
thinking: true,
|
|
84
|
+
betas: false,
|
|
85
|
+
rewind: false,
|
|
86
|
+
sessionResume: canResumeSession() || canLoadSession(),
|
|
87
|
+
promptSuggestions: false,
|
|
88
|
+
elicitation: false,
|
|
89
|
+
fileCheckpointing: false,
|
|
90
|
+
contextCompacting: false,
|
|
91
|
+
skillSharing: true,
|
|
92
|
+
toolPolicy: ["ask", "allow-all"],
|
|
93
|
+
};
|
|
94
|
+
return driverRuntime.mergeCapabilities(driver, context(), base);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readyResult() {
|
|
98
|
+
var skills = skillDiscovery.discoverSkills(cwd).map(function(skill) { return skill.name; });
|
|
99
|
+
var result = {
|
|
100
|
+
models: cachedModels.slice(),
|
|
101
|
+
defaultModel: defaultModel,
|
|
102
|
+
skills: skills,
|
|
103
|
+
slashCommands: skills,
|
|
104
|
+
fastModeState: null,
|
|
105
|
+
capabilities: capabilities(),
|
|
106
|
+
};
|
|
107
|
+
return driverRuntime.call(driver, "extendReadyResult", context({ result: result }), function() { return result; }) || result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function updateModelsFromSession(sessionResult) {
|
|
111
|
+
var discovered = modelValues(sessionResult && sessionResult.configOptions);
|
|
112
|
+
if (!discovered.length) return;
|
|
113
|
+
cachedModels = discovered;
|
|
114
|
+
var configOptions = sessionResult.configOptions;
|
|
115
|
+
for (var i = 0; i < configOptions.length; i++) {
|
|
116
|
+
if (configOptions[i].category === "model" || configOptions[i].id === "model") {
|
|
117
|
+
defaultModel = configOptions[i].currentValue || defaultModel;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function removeHandle(handle) {
|
|
124
|
+
var index = activeHandles.indexOf(handle);
|
|
125
|
+
if (index !== -1) activeHandles.splice(index, 1);
|
|
126
|
+
lastActiveAt = Date.now();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
var adapter = {
|
|
130
|
+
vendor: vendor,
|
|
131
|
+
|
|
132
|
+
init: function(initOpts) {
|
|
133
|
+
if (shuttingDown) return Promise.reject(new Error(driver.displayName + " adapter is shutting down"));
|
|
134
|
+
if (initialized && acp && acp.started) return Promise.resolve(readyResult());
|
|
135
|
+
if (initPromise) return initPromise;
|
|
136
|
+
|
|
137
|
+
initPromise = (async function() {
|
|
138
|
+
if (!binaryPath) {
|
|
139
|
+
binaryPath = profiles.findAcpAgentPath(driver);
|
|
140
|
+
if (!binaryPath) throw new Error(driver.displayName + " binary not found: " + driver.binaryName);
|
|
141
|
+
}
|
|
142
|
+
var effectiveOpts = Object.assign({}, opts, initOpts || {});
|
|
143
|
+
var prepared = await Promise.all([
|
|
144
|
+
fetchModels ? fetchModels(binaryPath, cwd) : Promise.resolve([]),
|
|
145
|
+
driverRuntime.callAsync(driver, "prepare", context({ initOpts: effectiveOpts }), function() {}),
|
|
146
|
+
]);
|
|
147
|
+
if (fetchModels) {
|
|
148
|
+
var fetched = prepared[0];
|
|
149
|
+
if (Array.isArray(fetched) && fetched.length) {
|
|
150
|
+
cachedModels = fetched;
|
|
151
|
+
if (cachedModels.indexOf(defaultModel) === -1) defaultModel = cachedModels[0];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
155
|
+
|
|
156
|
+
var processOptions = driverRuntime.buildParams(driver, "buildProcessOptions", context({ initOpts: effectiveOpts }), {
|
|
157
|
+
args: driver.args || [],
|
|
158
|
+
cwd: cwd,
|
|
159
|
+
env: effectiveOpts.env || null,
|
|
160
|
+
logPrefix: vendor + "-acp",
|
|
161
|
+
});
|
|
162
|
+
await driverRuntime.callAsync(driver, "validateProcessOptions", context({
|
|
163
|
+
initOpts: effectiveOpts,
|
|
164
|
+
processOptions: processOptions,
|
|
165
|
+
}), function() {});
|
|
166
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
167
|
+
acp = new ProcessManagerCtor(binaryPath, processOptions);
|
|
168
|
+
await driverRuntime.callAsync(driver, "registerRequestHandlers", context({ acp: acp }), function() {});
|
|
169
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
170
|
+
await acp.start();
|
|
171
|
+
try {
|
|
172
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
173
|
+
var initializeParams = driverRuntime.buildParams(driver, "buildInitializeParams", context({ acp: acp }), {
|
|
174
|
+
protocolVersion: 1,
|
|
175
|
+
clientInfo: { name: "clay", version: "1.0.0" },
|
|
176
|
+
clientCapabilities: {
|
|
177
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
178
|
+
session: { configOptions: { boolean: {} } },
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
initResult = await acp.send("initialize", initializeParams, 30000);
|
|
182
|
+
await driverRuntime.callAsync(driver, "onInitialize", context({ acp: acp, initResult: initResult }), function() {});
|
|
183
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
184
|
+
} catch (e) {
|
|
185
|
+
acp.stop();
|
|
186
|
+
acp = null;
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
initialized = true;
|
|
190
|
+
lastActiveAt = Date.now();
|
|
191
|
+
return readyResult();
|
|
192
|
+
})().then(function(result) {
|
|
193
|
+
initPromise = null;
|
|
194
|
+
return result;
|
|
195
|
+
}, function(err) {
|
|
196
|
+
initPromise = null;
|
|
197
|
+
initialized = false;
|
|
198
|
+
throw err;
|
|
199
|
+
});
|
|
200
|
+
return initPromise;
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
supportedModels: function() {
|
|
204
|
+
return driverRuntime.callAsync(driver, "supportedModels", context({ models: cachedModels.slice() }), function() {
|
|
205
|
+
if (!fetchModels || !binaryPath) return cachedModels.slice();
|
|
206
|
+
return fetchModels(binaryPath, cwd).then(function(fetched) {
|
|
207
|
+
if (Array.isArray(fetched) && fetched.length) cachedModels = fetched;
|
|
208
|
+
return cachedModels.slice();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
createToolServer: function(definition) {
|
|
214
|
+
return driverRuntime.call(driver, "createToolServer", context({ definition: definition }), function() { return null; });
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
createQuery: async function(queryOpts) {
|
|
218
|
+
queryOpts = queryOpts || {};
|
|
219
|
+
if (!initialized || !acp || !acp.started) await adapter.init(queryOpts);
|
|
220
|
+
if (shuttingDown) throw new Error(driver.displayName + " adapter is shutting down");
|
|
221
|
+
var controller = queryOpts.abortController || new AbortController();
|
|
222
|
+
var sharedSkills = skillDiscovery.discoverSkills(queryOpts.cwd || cwd);
|
|
223
|
+
var skillIndex = skillDiscovery.buildSkillIndex(sharedSkills);
|
|
224
|
+
var acpOptions = (queryOpts.adapterOptions && queryOpts.adapterOptions.ACP) || {};
|
|
225
|
+
var handle = null;
|
|
226
|
+
handle = createAcpQueryHandle(acp, {
|
|
227
|
+
vendor: vendor,
|
|
228
|
+
driver: driver,
|
|
229
|
+
cwd: queryOpts.cwd || cwd,
|
|
230
|
+
model: queryOpts.model || defaultModel,
|
|
231
|
+
mode: queryOpts.mode || null,
|
|
232
|
+
systemPrompt: queryOpts.systemPrompt || "",
|
|
233
|
+
appendSystemPrompt: [queryOpts.appendSystemPrompt, skillIndex].filter(function(part) { return !!part; }).join("\n\n"),
|
|
234
|
+
abortController: controller,
|
|
235
|
+
canUseTool: queryOpts.canUseTool || null,
|
|
236
|
+
resumeSessionId: queryOpts.resumeSessionId || null,
|
|
237
|
+
canLoadSession: canLoadSession(),
|
|
238
|
+
canResumeSession: canResumeSession(),
|
|
239
|
+
mcpServers: acpOptions.mcpServers || queryOpts.mcpServers || [],
|
|
240
|
+
onSessionReady: updateModelsFromSession,
|
|
241
|
+
onFinished: function() { removeHandle(handle); },
|
|
242
|
+
});
|
|
243
|
+
activeHandles.push(handle);
|
|
244
|
+
lastActiveAt = Date.now();
|
|
245
|
+
return handle;
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
generateTitle: async function(messages, titleOpts) {
|
|
249
|
+
if (driverRuntime.hasHook(driver, "generateTitle")) {
|
|
250
|
+
return driver.generateTitle(context({ messages: messages, opts: titleOpts }));
|
|
251
|
+
}
|
|
252
|
+
var prompt = "Generate a short descriptive title of 3 to 8 words. Output only the title.\n\n";
|
|
253
|
+
for (var i = 0; i < messages.length; i++) prompt += "User message " + (i + 1) + ": " + messages[i] + "\n";
|
|
254
|
+
var handle = await adapter.createQuery({
|
|
255
|
+
cwd: (titleOpts && titleOpts.cwd) || cwd,
|
|
256
|
+
systemPrompt: "You generate concise conversation titles. Output only the title.",
|
|
257
|
+
canUseTool: function() { return Promise.resolve({ behavior: "deny" }); },
|
|
258
|
+
});
|
|
259
|
+
handle.pushMessage(prompt);
|
|
260
|
+
var title = "";
|
|
261
|
+
try {
|
|
262
|
+
for await (var event of handle) {
|
|
263
|
+
if (event.yokeType === "text_delta" && event.text) title += event.text;
|
|
264
|
+
if (event.yokeType === "result") break;
|
|
265
|
+
}
|
|
266
|
+
} finally {
|
|
267
|
+
handle.close();
|
|
268
|
+
}
|
|
269
|
+
return title.replace(/[\r\n]+/g, " ").replace(/^["'\s]+|["'\s.]+$/g, "").trim();
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
getSessionInfo: function(sessionId, methodOpts) {
|
|
273
|
+
return driverRuntime.callAsync(driver, "getSessionInfo", context({ sessionId: sessionId, opts: methodOpts }), function() { return null; });
|
|
274
|
+
},
|
|
275
|
+
listSessions: function(methodOpts) {
|
|
276
|
+
return driverRuntime.callAsync(driver, "listSessions", context({ opts: methodOpts }), function() { return []; });
|
|
277
|
+
},
|
|
278
|
+
renameSession: function(sessionId, title, methodOpts) {
|
|
279
|
+
return driverRuntime.callAsync(driver, "renameSession", context({ sessionId: sessionId, title: title, opts: methodOpts }), function() {});
|
|
280
|
+
},
|
|
281
|
+
forkSession: function(sessionId, methodOpts) {
|
|
282
|
+
return driverRuntime.callAsync(driver, "forkSession", context({ sessionId: sessionId, opts: methodOpts }), function() { return null; });
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
shutdown: async function() {
|
|
286
|
+
shuttingDown = true;
|
|
287
|
+
var pendingInit = initPromise;
|
|
288
|
+
if (acp) acp.stop();
|
|
289
|
+
if (pendingInit) {
|
|
290
|
+
try { await pendingInit; } catch (e) {}
|
|
291
|
+
}
|
|
292
|
+
var handles = activeHandles.slice();
|
|
293
|
+
for (var i = 0; i < handles.length; i++) handles[i].abort();
|
|
294
|
+
activeHandles = [];
|
|
295
|
+
try {
|
|
296
|
+
if (acp) acp.stop();
|
|
297
|
+
await driverRuntime.callAsync(driver, "onShutdown", context(), function() {});
|
|
298
|
+
} finally {
|
|
299
|
+
acp = null;
|
|
300
|
+
initialized = false;
|
|
301
|
+
shuttingDown = false;
|
|
302
|
+
}
|
|
303
|
+
return true;
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
shutdownIfIdle: function(idleMs) {
|
|
307
|
+
if (!acp || activeHandles.length || Date.now() - lastActiveAt < (idleMs || 0)) return Promise.resolve(false);
|
|
308
|
+
return adapter.shutdown();
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
return adapter;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
module.exports = {
|
|
315
|
+
createAcpAdapter: createAcpAdapter,
|
|
316
|
+
modelValues: modelValues,
|
|
317
|
+
};
|
|
@@ -477,10 +477,10 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
477
477
|
var method = msg.method;
|
|
478
478
|
var params = msg.params || {};
|
|
479
479
|
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
480
|
+
// The shared ACP manager routes by sessionId and guarantees unroutable
|
|
481
|
+
// requests get an error response. Do not add a silent sessionId filter here:
|
|
482
|
+
// dropping a request without calling acp.respond() blocks kiro-cli until the
|
|
483
|
+
// session/prompt timeout.
|
|
484
484
|
|
|
485
485
|
// Tool permission request (server -> client, has an id we must answer)
|
|
486
486
|
if (method === "session/request_permission") {
|
package/lib/yoke/index.js
CHANGED
|
@@ -6,11 +6,13 @@ var instructions = require("./instructions");
|
|
|
6
6
|
var vendorRegistry = require("./vendor-registry");
|
|
7
7
|
var createClaudeAdapter = require("./adapters/claude").createClaudeAdapter;
|
|
8
8
|
var createCodexAdapter = require("./adapters/codex").createCodexAdapter;
|
|
9
|
+
var createGeminiAdapter = require("./adapters/gemini").createGeminiAdapter;
|
|
10
|
+
var createOpenCodeAdapter = require("./adapters/opencode").createOpenCodeAdapter;
|
|
9
11
|
var createKiroAdapter = require("./adapters/kiro").createKiroAdapter;
|
|
10
12
|
|
|
11
13
|
// Keep the first session in a new project predictable. This order is also
|
|
12
14
|
// used by the UI when a project has no remembered vendor yet.
|
|
13
|
-
var DEFAULT_VENDOR_ORDER = ["claude", "codex", "kiro"];
|
|
15
|
+
var DEFAULT_VENDOR_ORDER = ["claude", "codex", "gemini", "opencode", "kiro"];
|
|
14
16
|
|
|
15
17
|
function resolveDefaultVendor(availableVendors) {
|
|
16
18
|
availableVendors = availableVendors || {};
|
|
@@ -71,6 +73,10 @@ function createAdapter(opts) {
|
|
|
71
73
|
adapter = createClaudeAdapter(opts);
|
|
72
74
|
} else if (vendor === "codex") {
|
|
73
75
|
adapter = createCodexAdapter(opts);
|
|
76
|
+
} else if (vendor === "gemini") {
|
|
77
|
+
adapter = createGeminiAdapter(opts);
|
|
78
|
+
} else if (vendor === "opencode") {
|
|
79
|
+
adapter = createOpenCodeAdapter(opts);
|
|
74
80
|
} else if (vendor === "kiro") {
|
|
75
81
|
adapter = createKiroAdapter(opts);
|
|
76
82
|
} else {
|
|
@@ -96,7 +102,7 @@ function logAuthCheck(auth) {
|
|
|
96
102
|
if (_lastAuthLogKey === key && now - _lastAuthLogAt < 30000) return;
|
|
97
103
|
_lastAuthLogKey = key;
|
|
98
104
|
_lastAuthLogAt = now;
|
|
99
|
-
console.log("[yoke] Auth check: claude=" + auth.claude + " codex=" + auth.codex + " kiro=" + auth.kiro);
|
|
105
|
+
console.log("[yoke] Auth check: claude=" + auth.claude + " codex=" + auth.codex + " gemini=" + auth.gemini + " opencode=" + auth.opencode + " kiro=" + auth.kiro);
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
function checkAuth() {
|
|
@@ -227,7 +233,13 @@ function checkAuth() {
|
|
|
227
233
|
}
|
|
228
234
|
}
|
|
229
235
|
|
|
230
|
-
_authCache = {
|
|
236
|
+
_authCache = {
|
|
237
|
+
claude: checkClaude(),
|
|
238
|
+
codex: checkCodex(),
|
|
239
|
+
gemini: !!lookupBinary("gemini"),
|
|
240
|
+
opencode: !!lookupBinary("opencode"),
|
|
241
|
+
kiro: checkKiro(),
|
|
242
|
+
};
|
|
231
243
|
logAuthCheck(_authCache);
|
|
232
244
|
return _authCache;
|
|
233
245
|
}
|
|
@@ -249,7 +261,7 @@ function checkInstalled() {
|
|
|
249
261
|
|
|
250
262
|
var fs = require("fs");
|
|
251
263
|
var execFileSync = require("child_process").execFileSync;
|
|
252
|
-
var result = { claude: false, codex: false, kiro: false };
|
|
264
|
+
var result = { claude: false, codex: false, gemini: false, opencode: false, kiro: false };
|
|
253
265
|
try {
|
|
254
266
|
if (process.platform === "win32") execFileSync("where", ["claude"], { timeout: 3000, stdio: ["pipe", "pipe", "pipe"] });
|
|
255
267
|
else execFileSync("which", ["claude"], { timeout: 3000, stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -267,15 +279,20 @@ function checkInstalled() {
|
|
|
267
279
|
codexBin = findCodexPath();
|
|
268
280
|
if (codexBin && fs.existsSync(codexBin)) {
|
|
269
281
|
result.codex = true;
|
|
270
|
-
_installedCache = result;
|
|
271
|
-
return result;
|
|
272
282
|
}
|
|
273
283
|
} catch (e) {}
|
|
274
284
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
285
|
+
if (!result.codex) {
|
|
286
|
+
var whichOut = process.platform === "win32"
|
|
287
|
+
? execFileSync("where", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] })
|
|
288
|
+
: execFileSync("which", ["codex"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
289
|
+
if (whichOut.trim()) result.codex = true;
|
|
290
|
+
}
|
|
291
|
+
} catch (e) {}
|
|
292
|
+
try {
|
|
293
|
+
var acpProfiles = require("./acp-agent-profiles");
|
|
294
|
+
result.gemini = !!acpProfiles.findAcpAgentPath(acpProfiles.getAcpAgentProfile("gemini"));
|
|
295
|
+
result.opencode = !!acpProfiles.findAcpAgentPath(acpProfiles.getAcpAgentProfile("opencode"));
|
|
279
296
|
} catch (e) {}
|
|
280
297
|
_installedCache = result;
|
|
281
298
|
return result;
|
|
@@ -301,7 +318,7 @@ function createAdapters(opts) {
|
|
|
301
318
|
// that `claude auth status` does not always detect. Runtime auth failures are
|
|
302
319
|
// handled downstream via query-level error detection.
|
|
303
320
|
var installed = checkInstalled();
|
|
304
|
-
var auth = { claude: false, codex: false, kiro: false };
|
|
321
|
+
var auth = { claude: false, codex: false, gemini: false, opencode: false, kiro: false };
|
|
305
322
|
var adapters = {};
|
|
306
323
|
|
|
307
324
|
function supportsConfiguredIsolation(vendor) {
|
|
@@ -336,6 +353,23 @@ function createAdapters(opts) {
|
|
|
336
353
|
}
|
|
337
354
|
}
|
|
338
355
|
|
|
356
|
+
var acpVendors = ["gemini", "opencode"];
|
|
357
|
+
for (var acpIndex = 0; acpIndex < acpVendors.length; acpIndex++) {
|
|
358
|
+
var acpVendor = acpVendors[acpIndex];
|
|
359
|
+
var acpInfo = vendorRegistry.getVendorInfo(acpVendor);
|
|
360
|
+
if (installed[acpVendor] && supportsConfiguredIsolation(acpVendor)) {
|
|
361
|
+
try {
|
|
362
|
+
adapters[acpVendor] = createAdapter({ vendor: acpVendor, cwd: opts.cwd, slug: opts.slug });
|
|
363
|
+
auth[acpVendor] = true;
|
|
364
|
+
console.log("[yoke] Adapter created: " + acpVendor);
|
|
365
|
+
} catch (e) {
|
|
366
|
+
console.error("[yoke] Failed to create adapter for " + acpVendor + ":", e.message);
|
|
367
|
+
}
|
|
368
|
+
} else if (installed[acpVendor] && opts.osUsers) {
|
|
369
|
+
console.log("[yoke] " + acpInfo.displayName + " adapter disabled: OS-user isolation requires per-user spawning");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
339
373
|
var kiroInfo = vendorRegistry.getVendorInfo("kiro");
|
|
340
374
|
if (installed.kiro && supportsConfiguredIsolation("kiro")) {
|
|
341
375
|
try {
|
package/lib/yoke/interface.js
CHANGED
|
@@ -41,6 +41,7 @@ var TOOL_POLICIES = ["ask", "allow-all"];
|
|
|
41
41
|
* .setToolPolicy(policy) - "ask" | "allow-all"
|
|
42
42
|
* .stopTask(taskId)
|
|
43
43
|
* .getContextUsage() - Promise<object|null>
|
|
44
|
+
* .endInput() - stop accepting turns after queued input drains
|
|
44
45
|
* .abort()
|
|
45
46
|
* .close()
|
|
46
47
|
*/
|
|
@@ -59,6 +60,7 @@ var QUERY_HANDLE_METHODS = [
|
|
|
59
60
|
"setToolPolicy",
|
|
60
61
|
"stopTask",
|
|
61
62
|
"getContextUsage",
|
|
63
|
+
"endInput",
|
|
62
64
|
"abort",
|
|
63
65
|
"close",
|
|
64
66
|
];
|