clay-server 3.3.2-beta.2 → 3.4.0-beta.1
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/debate-mcp-server.js +15 -0
- package/lib/project-connection.js +18 -2
- package/lib/project-debate-proposal.js +138 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-file-watch.js +77 -16
- package/lib/project.js +28 -41
- package/lib/public/css/input.css +4 -0
- package/lib/public/css/mates.css +1 -0
- package/lib/public/gemini-avatar.svg +11 -0
- package/lib/public/index.html +8 -0
- package/lib/public/modules/app-panels.js +13 -1
- package/lib/public/modules/app-rendering.js +7 -1
- package/lib/public/modules/mate-sidebar.js +9 -3
- 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/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 +2 -2
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// Shared ACP Process Manager
|
|
2
|
+
// --------------------------
|
|
3
|
+
// Manages an ACP child process over line-delimited JSON-RPC 2.0. The child can
|
|
4
|
+
// answer client requests and initiate its own requests or notifications.
|
|
5
|
+
|
|
6
|
+
var { spawn } = require("child_process");
|
|
7
|
+
var readline = require("readline");
|
|
8
|
+
|
|
9
|
+
function AcpProcessManager(executablePath, opts) {
|
|
10
|
+
this.proc = null;
|
|
11
|
+
this.rl = null;
|
|
12
|
+
this.nextId = 1;
|
|
13
|
+
this.pendingRequests = {};
|
|
14
|
+
this.requestHandlers = {};
|
|
15
|
+
this.handlers = [];
|
|
16
|
+
this.executablePath = executablePath;
|
|
17
|
+
this.opts = opts || {};
|
|
18
|
+
this.started = false;
|
|
19
|
+
this._stderrBuf = "";
|
|
20
|
+
this._logPrefix = this.opts.logPrefix || "acp-process-manager";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
AcpProcessManager.prototype._log = function() {
|
|
24
|
+
var args = Array.prototype.slice.call(arguments);
|
|
25
|
+
args.unshift("[" + this._logPrefix + "]");
|
|
26
|
+
console.log.apply(console, args);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
AcpProcessManager.prototype._warn = function() {
|
|
30
|
+
var args = Array.prototype.slice.call(arguments);
|
|
31
|
+
args.unshift("[" + this._logPrefix + "]");
|
|
32
|
+
console.warn.apply(console, args);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
AcpProcessManager.prototype._error = function() {
|
|
36
|
+
var args = Array.prototype.slice.call(arguments);
|
|
37
|
+
args.unshift("[" + this._logPrefix + "]");
|
|
38
|
+
console.error.apply(console, args);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
AcpProcessManager.prototype.start = function() {
|
|
42
|
+
var self = this;
|
|
43
|
+
|
|
44
|
+
return new Promise(function(resolve, reject) {
|
|
45
|
+
try {
|
|
46
|
+
var args = self.opts.args ? self.opts.args.slice() : [];
|
|
47
|
+
var env = Object.assign({}, process.env, self.opts.env || {});
|
|
48
|
+
|
|
49
|
+
self._log("Spawning:", self.executablePath, args.join(" "));
|
|
50
|
+
self.proc = spawn(self.executablePath, args, {
|
|
51
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
52
|
+
env: env,
|
|
53
|
+
cwd: self.opts.cwd || process.cwd(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
self.proc.on("error", function(err) {
|
|
57
|
+
self._error("Process error:", err.message);
|
|
58
|
+
if (!self.started) reject(err);
|
|
59
|
+
self._rejectAllPending(err);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
self.proc.on("exit", function(code, signal) {
|
|
63
|
+
self._log("Process exited: code=" + code + " signal=" + signal);
|
|
64
|
+
self.started = false;
|
|
65
|
+
self._rejectAllPending(new Error("Process exited: code=" + code));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
self.proc.stderr.on("data", function(chunk) {
|
|
69
|
+
self._stderrBuf += chunk.toString();
|
|
70
|
+
var lines = self._stderrBuf.split("\n");
|
|
71
|
+
while (lines.length > 1) {
|
|
72
|
+
var line = lines.shift();
|
|
73
|
+
if (line.trim() && self.opts.logStderr !== false) self._log("stderr", line);
|
|
74
|
+
if (self.opts.onStderrLine) self.opts.onStderrLine(line, self);
|
|
75
|
+
}
|
|
76
|
+
self._stderrBuf = lines[0] || "";
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
self.rl = readline.createInterface({ input: self.proc.stdout, crlfDelay: Infinity });
|
|
80
|
+
self.rl.on("line", function(line) {
|
|
81
|
+
if (!line.trim()) return;
|
|
82
|
+
try {
|
|
83
|
+
self._handleMessage(JSON.parse(line));
|
|
84
|
+
} catch (e) {
|
|
85
|
+
self._error("Failed to parse line:", line.substring(0, 200));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
self.rl.on("close", function() {
|
|
89
|
+
self._log("stdout closed");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
self.started = true;
|
|
93
|
+
resolve();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
reject(e);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
AcpProcessManager.prototype._handleMessage = function(msg) {
|
|
101
|
+
if (msg.id !== undefined && msg.id !== null && (msg.result !== undefined || msg.error !== undefined)) {
|
|
102
|
+
var pending = this.pendingRequests[msg.id];
|
|
103
|
+
if (pending) {
|
|
104
|
+
delete this.pendingRequests[msg.id];
|
|
105
|
+
if (pending.timer) clearTimeout(pending.timer);
|
|
106
|
+
if (msg.error) {
|
|
107
|
+
var err = new Error(msg.error.message || JSON.stringify(msg.error));
|
|
108
|
+
err.rpcError = msg.error;
|
|
109
|
+
pending.reject(err);
|
|
110
|
+
} else {
|
|
111
|
+
pending.resolve(msg.result);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!msg.method) return;
|
|
118
|
+
|
|
119
|
+
var isRequest = msg.id !== undefined && msg.id !== null;
|
|
120
|
+
var directHandler = isRequest && this.requestHandlers[msg.method];
|
|
121
|
+
if (directHandler) {
|
|
122
|
+
var self = this;
|
|
123
|
+
Promise.resolve().then(function() {
|
|
124
|
+
return directHandler(msg.params || {}, msg);
|
|
125
|
+
}).then(function(result) {
|
|
126
|
+
self.respond(msg.id, result);
|
|
127
|
+
}).catch(function(err) {
|
|
128
|
+
self._error("Request handler failed for " + msg.method + ":", err && err.message ? err.message : err);
|
|
129
|
+
self.respondError(msg.id, -32002, err && err.message ? err.message : "Request handler failed");
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
var sessionId = msg.params && msg.params.sessionId;
|
|
135
|
+
if (isRequest && !sessionId) {
|
|
136
|
+
this._warn("No process handler for request " + msg.method + ", rejecting");
|
|
137
|
+
this.respondError(msg.id, -32601, "No process handler for method " + msg.method);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
var targets;
|
|
141
|
+
if (sessionId) {
|
|
142
|
+
targets = this.handlers.filter(function(handler) { return handler.sessionId === sessionId; });
|
|
143
|
+
} else {
|
|
144
|
+
targets = this.handlers.slice();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!targets.length) {
|
|
148
|
+
if (isRequest) {
|
|
149
|
+
this._warn("No handler for request " + msg.method + " (session=" + (sessionId || "none") + "), rejecting");
|
|
150
|
+
this.respondError(msg.id, -32001, "No active handler for session " + (sessionId || "none"));
|
|
151
|
+
} else {
|
|
152
|
+
this._log("Unhandled event:", msg.method);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (isRequest) {
|
|
158
|
+
try {
|
|
159
|
+
targets[0].fn(msg);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
this._error("Handler threw for " + msg.method + ":", e && e.message ? e.message : e);
|
|
162
|
+
this.respondError(msg.id, -32000, "Handler error");
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
targets.forEach(function(handler) {
|
|
168
|
+
try {
|
|
169
|
+
handler.fn(msg);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
this._error("Handler threw for " + msg.method + ":", e && e.message ? e.message : e);
|
|
172
|
+
}
|
|
173
|
+
}, this);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
AcpProcessManager.prototype.addHandler = function(fn) {
|
|
177
|
+
var entry = { sessionId: null, fn: fn };
|
|
178
|
+
this.handlers.push(entry);
|
|
179
|
+
return entry;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
AcpProcessManager.prototype.removeHandler = function(entry) {
|
|
183
|
+
var index = this.handlers.indexOf(entry);
|
|
184
|
+
if (index !== -1) this.handlers.splice(index, 1);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
AcpProcessManager.prototype.addRequestHandler = function(method, fn) {
|
|
188
|
+
this.requestHandlers[method] = fn;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
AcpProcessManager.prototype.send = function(method, params, timeoutMs) {
|
|
192
|
+
var self = this;
|
|
193
|
+
var id = this.nextId++;
|
|
194
|
+
timeoutMs = timeoutMs || 30000;
|
|
195
|
+
|
|
196
|
+
return new Promise(function(resolve, reject) {
|
|
197
|
+
if (!self.proc || !self.started) {
|
|
198
|
+
reject(new Error("ACP server not started"));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
var timer = setTimeout(function() {
|
|
202
|
+
delete self.pendingRequests[id];
|
|
203
|
+
reject(new Error("Request timeout: " + method + " (id=" + id + ")"));
|
|
204
|
+
}, timeoutMs);
|
|
205
|
+
self.pendingRequests[id] = { resolve: resolve, reject: reject, timer: timer };
|
|
206
|
+
|
|
207
|
+
var msg = { jsonrpc: "2.0", id: id, method: method };
|
|
208
|
+
if (params !== undefined) msg.params = params;
|
|
209
|
+
self._write(msg);
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
AcpProcessManager.prototype.notify = function(method, params) {
|
|
214
|
+
if (!this.proc || !this.started) return;
|
|
215
|
+
var msg = { jsonrpc: "2.0", method: method };
|
|
216
|
+
if (params !== undefined) msg.params = params;
|
|
217
|
+
this._write(msg);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
AcpProcessManager.prototype.respond = function(id, result) {
|
|
221
|
+
if (!this.proc || !this.started) return;
|
|
222
|
+
this._write({ jsonrpc: "2.0", id: id, result: result });
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
AcpProcessManager.prototype.respondError = function(id, code, message) {
|
|
226
|
+
if (!this.proc || !this.started) return;
|
|
227
|
+
this._write({ jsonrpc: "2.0", id: id, error: { code: code || -1, message: message || "Error" } });
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
AcpProcessManager.prototype._write = function(msg) {
|
|
231
|
+
if (!this.proc || !this.proc.stdin || this.proc.stdin.destroyed) return;
|
|
232
|
+
try {
|
|
233
|
+
this.proc.stdin.write(JSON.stringify(msg) + "\n");
|
|
234
|
+
} catch (e) {
|
|
235
|
+
this._error("Write error:", e.message);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
AcpProcessManager.prototype._rejectAllPending = function(err) {
|
|
240
|
+
var ids = Object.keys(this.pendingRequests);
|
|
241
|
+
for (var i = 0; i < ids.length; i++) {
|
|
242
|
+
var pending = this.pendingRequests[ids[i]];
|
|
243
|
+
if (pending.timer) clearTimeout(pending.timer);
|
|
244
|
+
pending.reject(err);
|
|
245
|
+
}
|
|
246
|
+
this.pendingRequests = {};
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
AcpProcessManager.prototype.stop = function() {
|
|
250
|
+
this.started = false;
|
|
251
|
+
this._rejectAllPending(new Error("Stopped"));
|
|
252
|
+
|
|
253
|
+
if (this.rl) {
|
|
254
|
+
this.rl.close();
|
|
255
|
+
this.rl = null;
|
|
256
|
+
}
|
|
257
|
+
if (this.proc) {
|
|
258
|
+
try { this.proc.stdin.end(); } catch (e) {}
|
|
259
|
+
try { this.proc.kill("SIGTERM"); } catch (e) {}
|
|
260
|
+
this.proc = null;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
module.exports = { AcpProcessManager: AcpProcessManager };
|