@agentshouse/kit 0.2.1-c70284f7a7466 → 0.2.1-c7a397cb0cce7
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/dist/acp.js +34 -14
- package/dist/agents.js +34 -14
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +1 -1
- package/dist/conversations.js +195 -79
- package/dist/copies.js +38 -22
- package/dist/files.js +1 -1
- package/dist/inputs.js +63 -0
- package/dist/resident.js +9 -5
- package/dist/scope.js +3 -0
- package/dist/service.js +22 -0
- package/dist/sign-in.js +5 -23
- package/dist/stream.js +4 -4
- package/dist/translate.js +2 -8
- package/dist/update.js +20 -23
- package/dist/wire.js +1 -1
- package/package.json +2 -2
package/dist/acp.js
CHANGED
|
@@ -3,6 +3,7 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
import { Readable, Writable } from 'node:stream';
|
|
4
4
|
import { CLIS, KIT_VERSION, adapterCommand, withoutProxy } from './clis.js';
|
|
5
5
|
import { killTree } from './scope.js';
|
|
6
|
+
const RETIRED = 'the CLI was retired';
|
|
6
7
|
export async function startAdapter(kind, cli, cwd, app, events = () => undefined, added = {}, signal, scope = null) {
|
|
7
8
|
const adapter = CLIS[kind].adapter;
|
|
8
9
|
const started = [adapter === null ? cli : adapterCommand(kind), CLIS[kind].args];
|
|
@@ -13,34 +14,53 @@ export async function startAdapter(kind, cli, cwd, app, events = () => undefined
|
|
|
13
14
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
14
15
|
detached: true,
|
|
15
16
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
child.on('exit', () => signal?.removeEventListener('abort', stop));
|
|
17
|
+
let owned = true;
|
|
18
|
+
let retired = false;
|
|
19
19
|
let stderr = '';
|
|
20
20
|
child.stderr.on('data', (chunk) => {
|
|
21
21
|
stderr = (stderr + chunk.toString('utf8')).slice(-4000);
|
|
22
22
|
});
|
|
23
|
-
const exited = new Promise((resolve) => {
|
|
24
|
-
child.on('error', (error) => resolve(`the CLI did not start: ${error.message}`));
|
|
25
|
-
child.on('exit', (code, signal) => {
|
|
26
|
-
const last = stderr.trim().split('\n').at(-1);
|
|
27
|
-
resolve(`the CLI exited with ${code ?? signal}${last ? `: ${last}` : ''}`);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
23
|
const stream = ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
|
|
31
24
|
const connection = app.connect({
|
|
32
25
|
writable: stream.writable,
|
|
33
26
|
readable: stream.readable.pipeThrough(new TransformStream({
|
|
34
27
|
transform(message, controller) {
|
|
35
28
|
const read = message;
|
|
36
|
-
|
|
29
|
+
if (owned)
|
|
30
|
+
events(read);
|
|
37
31
|
if (read.id !== undefined || (read.method !== 'session/update' && !read.method.startsWith('_'))) {
|
|
38
32
|
controller.enqueue(message);
|
|
39
33
|
}
|
|
40
34
|
},
|
|
41
35
|
})),
|
|
42
36
|
});
|
|
43
|
-
|
|
37
|
+
const { promise: lost, resolve: lose } = Promise.withResolvers();
|
|
38
|
+
const exited = new Promise((resolve) => {
|
|
39
|
+
const end = (cause) => {
|
|
40
|
+
if (owned)
|
|
41
|
+
lose(cause);
|
|
42
|
+
owned = false;
|
|
43
|
+
connection.close(new Error(cause));
|
|
44
|
+
resolve(cause);
|
|
45
|
+
};
|
|
46
|
+
child.on('error', (error) => end(`the CLI did not start: ${error.message}`));
|
|
47
|
+
child.on('exit', (code, signal) => {
|
|
48
|
+
const last = stderr.trim().split('\n').at(-1);
|
|
49
|
+
end(`the CLI exited with ${code ?? signal}${last ? `: ${last}` : ''}`);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
const retire = () => {
|
|
53
|
+
owned = false;
|
|
54
|
+
if (retired)
|
|
55
|
+
return;
|
|
56
|
+
retired = true;
|
|
57
|
+
if (child.pid !== undefined)
|
|
58
|
+
killTree(child);
|
|
59
|
+
scope?.kill();
|
|
60
|
+
connection.close(new Error(RETIRED));
|
|
61
|
+
};
|
|
62
|
+
signal?.addEventListener('abort', retire, { once: true });
|
|
63
|
+
child.on('exit', () => signal?.removeEventListener('abort', retire));
|
|
44
64
|
try {
|
|
45
65
|
const initialized = await connection.agent.request('initialize', {
|
|
46
66
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -54,10 +74,10 @@ export async function startAdapter(kind, cli, cwd, app, events = () => undefined
|
|
|
54
74
|
clientInfo: { name: '@agentshouse/kit', version: KIT_VERSION },
|
|
55
75
|
});
|
|
56
76
|
scope?.entered(child.pid);
|
|
57
|
-
return {
|
|
77
|
+
return { connection, initialized, exited, lost, retire };
|
|
58
78
|
}
|
|
59
79
|
catch (error) {
|
|
60
|
-
|
|
80
|
+
retire();
|
|
61
81
|
throw error;
|
|
62
82
|
}
|
|
63
83
|
}
|
package/dist/agents.js
CHANGED
|
@@ -5,12 +5,12 @@ import { startAdapter } from './acp.js';
|
|
|
5
5
|
import { CLIS, KIT_VERSION, below, installAdapter, installCli, locate, run, versionOf } from './clis.js';
|
|
6
6
|
import { agentBase, kitHome } from './home.js';
|
|
7
7
|
import { updatesItself } from './placement.js';
|
|
8
|
-
import { killTree } from './scope.js';
|
|
9
8
|
import { holdTranscription, transcriptionReport } from './transcription.js';
|
|
10
9
|
import { KIT_WIRE } from './wire.js';
|
|
11
10
|
// Two quiet seconds let a fresh conversation start before background model discovery competes for its CPU.
|
|
12
11
|
const MODEL_PROBE_QUIET_MS = 2_000;
|
|
13
12
|
const SIGNED_OUT = { signed_in: false, models: [], modes: [] };
|
|
13
|
+
const INSTALLING = { release: null, failure: null, installing: true, ...SIGNED_OUT };
|
|
14
14
|
function select(options, category) {
|
|
15
15
|
const option = options.find((candidate) => candidate.category === category);
|
|
16
16
|
return option?.type === 'select' ? option : undefined;
|
|
@@ -109,8 +109,7 @@ async function offer(kind, cli, known, signal) {
|
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
finally {
|
|
112
|
-
|
|
113
|
-
killTree(adapter.child);
|
|
112
|
+
adapter?.retire();
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
function reported(kind, reading) {
|
|
@@ -119,6 +118,7 @@ function reported(kind, reading) {
|
|
|
119
118
|
release: reading.release,
|
|
120
119
|
...(reading.minimum === undefined ? {} : { minimum: reading.minimum }),
|
|
121
120
|
failure: reading.failure,
|
|
121
|
+
...(reading.installing === undefined ? {} : { installing: reading.installing }),
|
|
122
122
|
signed_in: reading.signed_in,
|
|
123
123
|
models: reading.models,
|
|
124
124
|
modes: reading.modes,
|
|
@@ -164,6 +164,7 @@ export class Agents {
|
|
|
164
164
|
reading = Promise.resolve();
|
|
165
165
|
queues = new Map();
|
|
166
166
|
installing = Promise.resolve();
|
|
167
|
+
installs = new Map();
|
|
167
168
|
readings = new Map();
|
|
168
169
|
reads = new Map();
|
|
169
170
|
starts = 0;
|
|
@@ -219,7 +220,7 @@ export class Agents {
|
|
|
219
220
|
const { cli, release } = resolved;
|
|
220
221
|
const known = this.readings.get(kind);
|
|
221
222
|
const kept = known?.release === null || known?.minimum !== undefined ? SIGNED_OUT : (known ?? SIGNED_OUT);
|
|
222
|
-
if (known?.release !== release || known.minimum !== undefined) {
|
|
223
|
+
if (known?.release !== release || known.minimum !== undefined || this.installs.has(kind)) {
|
|
223
224
|
this.update(kind, { release, failure: null, signed_in: kept.signed_in, models: kept.models, modes: kept.modes });
|
|
224
225
|
}
|
|
225
226
|
const read = this.nextRead(kind);
|
|
@@ -234,7 +235,8 @@ export class Agents {
|
|
|
234
235
|
});
|
|
235
236
|
}
|
|
236
237
|
located(kind, signal) {
|
|
237
|
-
|
|
238
|
+
const owner = {};
|
|
239
|
+
return this.queue(kind, () => this.ensure(kind, signal, owner).finally(() => this.settle(kind, owner)), signal);
|
|
238
240
|
}
|
|
239
241
|
async reread(kind) {
|
|
240
242
|
await this.examine(kind, this.readings.get(kind) ?? SIGNED_OUT, offer);
|
|
@@ -242,7 +244,13 @@ export class Agents {
|
|
|
242
244
|
}
|
|
243
245
|
async recheck(kind, signal) {
|
|
244
246
|
const known = this.readings.get(kind) ?? SIGNED_OUT;
|
|
245
|
-
|
|
247
|
+
const owner = {};
|
|
248
|
+
try {
|
|
249
|
+
await this.examine(kind, known, async (kind, cli) => ((await signedIn(kind, cli, known, signal)) ? { ...known, signed_in: true } : SIGNED_OUT), signal, owner);
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
this.settle(kind, owner);
|
|
253
|
+
}
|
|
246
254
|
if (!signal.aborted)
|
|
247
255
|
await this.report();
|
|
248
256
|
}
|
|
@@ -256,8 +264,18 @@ export class Agents {
|
|
|
256
264
|
this.reads.set(kind, read);
|
|
257
265
|
return read;
|
|
258
266
|
}
|
|
259
|
-
|
|
267
|
+
hold(kind, reading) {
|
|
260
268
|
this.readings.set(kind, reading);
|
|
269
|
+
this.installs.delete(kind);
|
|
270
|
+
}
|
|
271
|
+
update(kind, reading) {
|
|
272
|
+
this.hold(kind, reading);
|
|
273
|
+
this.report().catch(logged);
|
|
274
|
+
}
|
|
275
|
+
settle(kind, owner) {
|
|
276
|
+
if (this.installs.get(kind) !== owner)
|
|
277
|
+
return;
|
|
278
|
+
this.installs.delete(kind);
|
|
261
279
|
this.report().catch(logged);
|
|
262
280
|
}
|
|
263
281
|
queue(kind, work, signal) {
|
|
@@ -268,13 +286,15 @@ export class Agents {
|
|
|
268
286
|
this.queues.set(kind, queued.catch(() => undefined));
|
|
269
287
|
return signal === undefined ? queued : Promise.race([queued, ended(signal)]);
|
|
270
288
|
}
|
|
271
|
-
async ensure(kind, signal) {
|
|
289
|
+
async ensure(kind, signal, owner = {}) {
|
|
272
290
|
const failed = await installAdapter(kind, signal);
|
|
273
291
|
if (failed !== null)
|
|
274
292
|
throw new Error(failed);
|
|
275
293
|
const found = await locate(kind, signal);
|
|
276
294
|
if (found !== null)
|
|
277
295
|
return found;
|
|
296
|
+
this.installs.set(kind, owner);
|
|
297
|
+
this.report().catch(logged);
|
|
278
298
|
const installing = this.installing.catch(() => undefined).then(() => installCli(kind, signal));
|
|
279
299
|
this.installing = installing;
|
|
280
300
|
const failure = await installing;
|
|
@@ -285,10 +305,10 @@ export class Agents {
|
|
|
285
305
|
throw new Error(`the login shell does not find ${CLIS[kind].bin} after its install`);
|
|
286
306
|
return installed;
|
|
287
307
|
}
|
|
288
|
-
async resolve(kind, signal) {
|
|
308
|
+
async resolve(kind, signal, owner) {
|
|
289
309
|
let cli;
|
|
290
310
|
try {
|
|
291
|
-
cli = await realpath(await this.ensure(kind, signal));
|
|
311
|
+
cli = await realpath(await this.ensure(kind, signal, owner));
|
|
292
312
|
}
|
|
293
313
|
catch (error) {
|
|
294
314
|
const failure = causeOf(error);
|
|
@@ -303,12 +323,12 @@ export class Agents {
|
|
|
303
323
|
return { release, minimum, failure: null, ...SIGNED_OUT };
|
|
304
324
|
return { cli, release };
|
|
305
325
|
}
|
|
306
|
-
async examine(kind, known, read, signal) {
|
|
326
|
+
async examine(kind, known, read, signal, owner) {
|
|
307
327
|
const current = this.nextRead(kind);
|
|
308
|
-
const resolved = await this.queue(kind, () => this.resolve(kind, signal), signal);
|
|
328
|
+
const resolved = await this.queue(kind, () => this.resolve(kind, signal, owner), signal);
|
|
309
329
|
const reading = 'cli' in resolved ? { release: resolved.release, failure: null, ...(await read(kind, resolved.cli, known)) } : resolved;
|
|
310
330
|
if (this.reads.get(kind) === current && !signal?.aborted)
|
|
311
|
-
this.
|
|
331
|
+
this.hold(kind, reading);
|
|
312
332
|
}
|
|
313
333
|
async quietOffer(kind, cli, known) {
|
|
314
334
|
for (let seen = -1; seen !== this.starts;) {
|
|
@@ -326,7 +346,7 @@ export class Agents {
|
|
|
326
346
|
}
|
|
327
347
|
async send() {
|
|
328
348
|
const agents = this.desired.agents.flatMap((kind) => {
|
|
329
|
-
const reading = this.readings.get(kind);
|
|
349
|
+
const reading = this.installs.has(kind) ? INSTALLING : this.readings.get(kind);
|
|
330
350
|
return reading === undefined ? [] : [reported(kind, reading)];
|
|
331
351
|
});
|
|
332
352
|
const hostKey = await sshHostKey();
|
package/dist/bootstrap.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"version": "0.2.1-
|
|
3
|
+
"version": "0.2.1-c7a397cb0cce7",
|
|
4
4
|
"hosts": {
|
|
5
5
|
"macos": {
|
|
6
6
|
"asset": {
|
|
7
7
|
"name": "connect-linux.sh",
|
|
8
|
-
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-
|
|
8
|
+
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-c7a397cb0cce7/connect-linux.sh"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"linux": {
|
|
12
12
|
"asset": {
|
|
13
13
|
"name": "connect-linux.sh",
|
|
14
|
-
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-
|
|
14
|
+
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-c7a397cb0cce7/connect-linux.sh"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"windows": {
|
|
18
18
|
"asset": {
|
|
19
19
|
"name": "connect-windows.ps1",
|
|
20
|
-
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-
|
|
20
|
+
"url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-c7a397cb0cce7/connect-windows.ps1"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}
|
package/dist/bridge.js
CHANGED
|
@@ -81,7 +81,7 @@ function editAnswer(forwarded) {
|
|
|
81
81
|
export async function openBridge(house, copies, conversationId, signal) {
|
|
82
82
|
const path = [join(kitHome(), 'shim'), dirname(process.execPath), await loginPath()].join(delimiter);
|
|
83
83
|
const origin = (await readEnrolment()).house;
|
|
84
|
-
const { credential } = await house.post(`/kit/conversations/${conversationId}/credential`, {}, signal);
|
|
84
|
+
const { credential } = await retrying(() => house.post(`/kit/conversations/${conversationId}/credential`, {}, signal), signal);
|
|
85
85
|
const closed = new AbortController();
|
|
86
86
|
const sent = (message, operation) => callHouse(origin, credential, message, operation, closed.signal);
|
|
87
87
|
const send = async (message, operation) => {
|