@agentshouse/kit 0.2.1-cb6679d048e60 → 0.2.1-cc988e43abeeb
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/README.md +19 -19
- package/dist/acp.js +16 -93
- package/dist/agents.js +81 -39
- package/dist/api.js +32 -3
- package/dist/app-git.js +64 -0
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +36 -52
- package/dist/clis.js +95 -65
- package/dist/codex-main.js +58 -0
- package/dist/conversations.js +284 -236
- package/dist/copies.js +149 -131
- package/dist/end.js +8 -0
- package/dist/events.js +521 -0
- package/dist/files.js +16 -1
- package/dist/house-main.js +41 -12
- package/dist/instructions.js +4 -3
- package/dist/kit-main.js +3 -0
- package/dist/login.js +23 -98
- package/dist/logout.js +16 -13
- package/dist/mcp.js +2 -1
- package/dist/parts.js +64 -0
- package/dist/refusals.js +12 -0
- package/dist/relay.js +10 -0
- package/dist/resident.js +24 -22
- package/dist/scope.js +203 -0
- package/dist/secret-input.js +4 -1
- package/dist/shell.js +3 -0
- package/dist/sign-in.js +34 -9
- package/dist/skills.js +1 -1
- package/dist/stream.js +31 -5
- package/dist/transcription.js +54 -6
- package/dist/update.js +2 -0
- package/dist/work.js +348 -0
- package/package.json +2 -2
- package/dist/blocks.js +0 -51
package/dist/copies.js
CHANGED
|
@@ -2,15 +2,15 @@ import { parse } from '@agentshouse/mdmodel';
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { mkdir, readFile, readdir, realpath, rename, rm, rmdir, stat, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
|
-
import { HouseRefusal } from './api.js';
|
|
5
|
+
import { finalRefusal, HouseRefusal, retrying } from './api.js';
|
|
6
6
|
import { blobId, blobText, git, HOUSE_REF, importCommits, localCopies, revision, run, succeeded, tree, } from './git.js';
|
|
7
7
|
import { kitHome } from './home.js';
|
|
8
8
|
import { operationId } from './operation.js';
|
|
9
9
|
import { refusalOf } from './refusals.js';
|
|
10
10
|
import { changed } from './translate.js';
|
|
11
|
+
import { relayed } from './relay.js';
|
|
11
12
|
const BRANCH = 'main';
|
|
12
13
|
const PROVENANCE = '_provenance';
|
|
13
|
-
const REPLICA_RETRY_MS = 30_000;
|
|
14
14
|
const IDENTITY = { GIT_COMMITTER_NAME: 'House Kit', GIT_COMMITTER_EMAIL: 'house-kit@localhost' };
|
|
15
15
|
function causeOf(error) {
|
|
16
16
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -32,6 +32,22 @@ function rebaseFixes(refusal) {
|
|
|
32
32
|
function short(commit) {
|
|
33
33
|
return commit.slice(0, 12);
|
|
34
34
|
}
|
|
35
|
+
function moved(before, after) {
|
|
36
|
+
if (before.house !== after.house)
|
|
37
|
+
return [`${rootOf(after.room_handle)}: ${HOUSE_REF} is at ${short(after.house)}`];
|
|
38
|
+
return before.position === after.position ? [] : [`${rootOf(after.room_handle)}: read-only files refreshed`];
|
|
39
|
+
}
|
|
40
|
+
function expiredAuthority(error) {
|
|
41
|
+
if (!(error instanceof HouseRefusal))
|
|
42
|
+
return undefined;
|
|
43
|
+
try {
|
|
44
|
+
const { error: refused } = JSON.parse(error.text);
|
|
45
|
+
return refused?.code === 'expired' && typeof refused.authority === 'string' ? refused.authority : undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
35
51
|
function covers(path, prefix) {
|
|
36
52
|
return prefix === '' || path === prefix || path.startsWith(`${prefix}/`);
|
|
37
53
|
}
|
|
@@ -40,11 +56,11 @@ function sidecar(path) {
|
|
|
40
56
|
segments.splice(-1, 0, PROVENANCE);
|
|
41
57
|
return segments.join('/');
|
|
42
58
|
}
|
|
43
|
-
function rootOf(
|
|
44
|
-
return
|
|
59
|
+
function rootOf(handle) {
|
|
60
|
+
return `/rooms/${handle}`;
|
|
45
61
|
}
|
|
46
62
|
function relative(path) {
|
|
47
|
-
return path.replace(/^\/
|
|
63
|
+
return path.replace(/^\/rooms\/[^/]+\//, '');
|
|
48
64
|
}
|
|
49
65
|
function declaredWritable(path, copy) {
|
|
50
66
|
const deepest = (scopes) => Math.max(-1, ...scopes.filter((scope) => covers(path, scope)).map((scope) => scope.length));
|
|
@@ -152,19 +168,18 @@ export class LocalCopies {
|
|
|
152
168
|
house;
|
|
153
169
|
copies = new Map();
|
|
154
170
|
queues = new Map();
|
|
155
|
-
|
|
156
|
-
selecting = Promise.resolve();
|
|
171
|
+
answering = Promise.resolve();
|
|
157
172
|
constructor(house) {
|
|
158
173
|
this.house = house;
|
|
159
174
|
this.owner = {
|
|
160
175
|
key: 'owner',
|
|
161
176
|
submit: async (operation, changes) => {
|
|
162
177
|
try {
|
|
163
|
-
const outcome = await house.post('/kit/door/batch', { operation_id: operation, changes });
|
|
178
|
+
const outcome = await retrying(() => house.post('/kit/door/batch', { operation_id: operation, changes }));
|
|
164
179
|
return { accepted: outcome.contents };
|
|
165
180
|
}
|
|
166
181
|
catch (error) {
|
|
167
|
-
if (!(error
|
|
182
|
+
if (!finalRefusal(error))
|
|
168
183
|
throw error;
|
|
169
184
|
return {
|
|
170
185
|
refused: refusalOf(error.text) ?? { code: '', text: `House refused it with ${error.status}`, conflicts: [] },
|
|
@@ -176,7 +191,7 @@ export class LocalCopies {
|
|
|
176
191
|
async load() {
|
|
177
192
|
const home = join(kitHome(), 'local-copies');
|
|
178
193
|
const names = (await readdir(join(home, 'rooms')).catch(() => [])).filter((name) => name.endsWith('.json'));
|
|
179
|
-
for (const path of
|
|
194
|
+
for (const path of names.map((name) => join(home, 'rooms', name))) {
|
|
180
195
|
const text = await readFile(path, 'utf8').catch(() => null);
|
|
181
196
|
if (text === null)
|
|
182
197
|
continue;
|
|
@@ -185,47 +200,68 @@ export class LocalCopies {
|
|
|
185
200
|
}
|
|
186
201
|
}
|
|
187
202
|
async mapping() {
|
|
188
|
-
await this.
|
|
203
|
+
await this.answering;
|
|
189
204
|
return [...this.copies.values()]
|
|
190
205
|
.filter((copy) => copy.active)
|
|
191
|
-
.map((copy) => `${rootOf(copy)}: ${copy.repository}`)
|
|
206
|
+
.map((copy) => `${rootOf(copy.room_handle)}: ${copy.repository}`)
|
|
192
207
|
.sort();
|
|
193
208
|
}
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
async reselect() {
|
|
200
|
-
const { local_copy: chosen } = await this.house.post('/kit/local-copy/selection', {});
|
|
201
|
-
const selected = [
|
|
202
|
-
...(chosen?.rooms ?? [])
|
|
203
|
-
.filter((room) => room.room_handle !== null)
|
|
204
|
-
.map((room) => ({ key: `rooms/${room.room_ref}`, private: false, handle: room.room_handle })),
|
|
205
|
-
...(chosen?.private === true ? [{ key: 'private', private: true, handle: null }] : []),
|
|
206
|
-
];
|
|
207
|
-
const keys = new Set(selected.map((scope) => scope.key));
|
|
208
|
-
const work = [];
|
|
209
|
-
for (const key of this.copies.keys()) {
|
|
210
|
-
if (keys.has(key))
|
|
211
|
-
continue;
|
|
212
|
-
work.push(this.exclusive(key, async () => {
|
|
213
|
-
const copy = this.copies.get(key);
|
|
214
|
-
if (copy.active)
|
|
215
|
-
await this.save({ ...copy, active: false });
|
|
216
|
-
}));
|
|
217
|
-
}
|
|
218
|
-
for (const scope of selected)
|
|
219
|
-
work.push(this.exclusive(scope.key, () => this.apply(scope)).catch(logged));
|
|
220
|
-
await Promise.all(work);
|
|
209
|
+
async connected() {
|
|
210
|
+
const copied = await this.answered(() => this.fetched(false));
|
|
211
|
+
if (copied.refused)
|
|
212
|
+
logged(copied.text);
|
|
221
213
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
214
|
+
fetch() {
|
|
215
|
+
return this.answered(() => this.fetched(true));
|
|
216
|
+
}
|
|
217
|
+
answered(work) {
|
|
218
|
+
const answered = this.answering.then(work);
|
|
219
|
+
this.answering = answered.catch(() => undefined);
|
|
220
|
+
return answered;
|
|
221
|
+
}
|
|
222
|
+
async fetched(refreshing) {
|
|
223
|
+
const { local_copy: answer } = await this.house.post('/kit/local-copy/selection', {});
|
|
224
|
+
const synced = new Map(answer.rooms.map((room) => [`rooms/${room.room_ref}`, room.room_handle]));
|
|
225
|
+
return this.holding([...new Set([...this.copies.keys(), ...synced.keys()])].sort(), async () => {
|
|
226
|
+
const said = [];
|
|
227
|
+
let refused = false;
|
|
228
|
+
for (const copy of this.copies.values()) {
|
|
229
|
+
if (synced.has(copy.key) || !copy.active)
|
|
230
|
+
continue;
|
|
231
|
+
await this.save({ ...copy, active: false });
|
|
232
|
+
said.push(`${rootOf(copy.room_handle)}: no longer synced to this Environment; its files stay`);
|
|
233
|
+
}
|
|
234
|
+
const current = [];
|
|
235
|
+
for (const [key, handle] of synced) {
|
|
236
|
+
try {
|
|
237
|
+
const held = this.copies.get(key);
|
|
238
|
+
if (held === undefined || !(await exists(held.repository))) {
|
|
239
|
+
said.push(await this.materialize(key, handle));
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const copy = held.room_handle === handle ? held : await this.save({ ...held, room_handle: handle });
|
|
243
|
+
if (copy.active)
|
|
244
|
+
current.push(copy);
|
|
245
|
+
else
|
|
246
|
+
said.push(...moved(copy, await this.save(await this.received({ ...copy, active: true }))));
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
refused = true;
|
|
250
|
+
said.push(`${rootOf(handle)}: ${causeOf(error)}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (refreshing && current.length > 0) {
|
|
254
|
+
try {
|
|
255
|
+
const refreshed = await this.refreshed(current);
|
|
256
|
+
current.forEach((copy, index) => said.push(...moved(copy, refreshed[index])));
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
refused = true;
|
|
260
|
+
said.push(error instanceof HouseRefusal ? (refusalOf(error.text)?.text ?? causeOf(error)) : causeOf(error));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { refused, text: said.length === 0 ? 'Nothing new from House.' : said.join('\n') };
|
|
264
|
+
});
|
|
229
265
|
}
|
|
230
266
|
async observed(report) {
|
|
231
267
|
const key = await this.keyAt(dirname(report.common));
|
|
@@ -275,19 +311,12 @@ export class LocalCopies {
|
|
|
275
311
|
this.queues.set(key, queued.catch(() => undefined));
|
|
276
312
|
return queued;
|
|
277
313
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.delivering.add(key);
|
|
282
|
-
void this.exclusive(key, async () => {
|
|
283
|
-
this.delivering.delete(key);
|
|
284
|
-
const copy = this.copies.get(key);
|
|
285
|
-
if (copy.active)
|
|
286
|
-
await this.save(await this.caughtUp(copy));
|
|
287
|
-
}).catch(logged);
|
|
314
|
+
holding(keys, work) {
|
|
315
|
+
const [key, ...rest] = keys;
|
|
316
|
+
return key === undefined ? work() : this.exclusive(key, () => this.holding(rest, work));
|
|
288
317
|
}
|
|
289
318
|
async save(copy) {
|
|
290
|
-
const path = join(kitHome(), 'local-copies',
|
|
319
|
+
const path = join(kitHome(), 'local-copies', `${copy.key}.json`);
|
|
291
320
|
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
292
321
|
const temporary = `${path}.${process.pid}`;
|
|
293
322
|
await writeFile(temporary, JSON.stringify(copy), { mode: 0o600 });
|
|
@@ -295,12 +324,12 @@ export class LocalCopies {
|
|
|
295
324
|
this.copies.set(copy.key, copy);
|
|
296
325
|
return copy;
|
|
297
326
|
}
|
|
298
|
-
async read(
|
|
299
|
-
const prefixes = [rootOf(
|
|
327
|
+
async read(handle) {
|
|
328
|
+
const prefixes = [rootOf(handle)];
|
|
300
329
|
const discovery = await this.house.post('/kit/door/discover', { prefixes });
|
|
301
330
|
let bundle = await this.house.post('/kit/door/bootstrap', { prefixes });
|
|
302
331
|
if ('transfer' in bundle)
|
|
303
|
-
bundle = (await (await fetch(bundle.transfer.url)).json());
|
|
332
|
+
bundle = (await (await fetch(relayed(bundle.transfer.url))).json());
|
|
304
333
|
const [view] = bundle.scopes;
|
|
305
334
|
if (view === undefined)
|
|
306
335
|
return null;
|
|
@@ -330,46 +359,13 @@ export class LocalCopies {
|
|
|
330
359
|
}
|
|
331
360
|
return read;
|
|
332
361
|
}
|
|
333
|
-
async
|
|
334
|
-
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
copy = await this.save({ ...copy, room_handle: scope.handle });
|
|
341
|
-
if (!copy.active) {
|
|
342
|
-
await this.save(await this.received({ ...copy, active: true }));
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
const discovery = await this.house.post('/kit/door/discover', {
|
|
346
|
-
prefixes: [rootOf(copy)],
|
|
347
|
-
});
|
|
348
|
-
const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
|
|
349
|
-
if (authority === undefined)
|
|
350
|
-
return;
|
|
351
|
-
if (authority.managed_replication !== 'admitted') {
|
|
352
|
-
logged(`operation_denied: ${rootOf(copy)} is not synchronized to this Environment`);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (JSON.stringify([authority.operations.write, authority.protected_paths]) !==
|
|
356
|
-
JSON.stringify([copy.write, copy.protected])) {
|
|
357
|
-
await this.save(await this.received(copy));
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
await this.save(await this.caughtUp(copy));
|
|
361
|
-
}
|
|
362
|
-
async materialize(scope) {
|
|
363
|
-
const read = await this.read({ private: scope.private, room_handle: scope.handle });
|
|
364
|
-
if (read === null) {
|
|
365
|
-
logged(`House serves nothing of ${rootOf({ private: scope.private, room_handle: scope.handle })} to copy`);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
const repository = scope.private ? join(localCopies(), 'private') : join(localCopies(), 'rooms', read.anchor);
|
|
369
|
-
if (await exists(repository)) {
|
|
370
|
-
logged(`${repository} already exists and House Kit leaves it as it is`);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
362
|
+
async materialize(key, handle) {
|
|
363
|
+
const read = await this.read(handle);
|
|
364
|
+
if (read === null)
|
|
365
|
+
throw new Error('House serves nothing of it to copy');
|
|
366
|
+
const repository = join(localCopies(), 'rooms', read.anchor);
|
|
367
|
+
if (await exists(repository))
|
|
368
|
+
throw new Error(`${repository} already exists and House Kit leaves it as it is`);
|
|
373
369
|
const staging = join(dirname(repository), `.${randomUUID()}`);
|
|
374
370
|
await mkdir(staging, { recursive: true });
|
|
375
371
|
let house;
|
|
@@ -377,7 +373,7 @@ export class LocalCopies {
|
|
|
377
373
|
try {
|
|
378
374
|
await git(staging, ['init', '-q', '-b', BRANCH]);
|
|
379
375
|
house = await importCommits(staging, [
|
|
380
|
-
{ message: `House ${rootOf(
|
|
376
|
+
{ message: `House ${rootOf(handle)}`, from: null, files: read.writable },
|
|
381
377
|
]);
|
|
382
378
|
await git(staging, ['update-ref', `refs/heads/${BRANCH}`, house]);
|
|
383
379
|
await git(staging, ['reset', '-q', '--hard']);
|
|
@@ -390,10 +386,9 @@ export class LocalCopies {
|
|
|
390
386
|
throw error;
|
|
391
387
|
}
|
|
392
388
|
await this.save({
|
|
393
|
-
key
|
|
394
|
-
private: scope.private,
|
|
389
|
+
key,
|
|
395
390
|
room_ref: read.anchor,
|
|
396
|
-
room_handle:
|
|
391
|
+
room_handle: handle,
|
|
397
392
|
repository,
|
|
398
393
|
active: true,
|
|
399
394
|
house,
|
|
@@ -405,13 +400,14 @@ export class LocalCopies {
|
|
|
405
400
|
manifests: { [house]: { parent: null, files: read.revisions } },
|
|
406
401
|
moves: [],
|
|
407
402
|
});
|
|
403
|
+
return `${rootOf(handle)}: copied to ${repository}`;
|
|
408
404
|
}
|
|
409
405
|
async received(copy) {
|
|
410
|
-
const read = await this.read(copy);
|
|
406
|
+
const read = await this.read(copy.room_handle);
|
|
411
407
|
if (read === null)
|
|
412
408
|
return copy;
|
|
413
409
|
const house = await importCommits(copy.repository, [
|
|
414
|
-
{ message: `House ${rootOf(copy)} at position ${read.position}`, from: copy.house, replaces: true, files: read.writable },
|
|
410
|
+
{ message: `House ${rootOf(copy.room_handle)} at position ${read.position}`, from: copy.house, replaces: true, files: read.writable },
|
|
415
411
|
]);
|
|
416
412
|
const removed = copy.read_only.filter((path) => !read.readOnly.has(path));
|
|
417
413
|
const readOnly = await readOnlyPlaced(copy.repository, copy.read_only, read.readOnly, removed);
|
|
@@ -428,30 +424,52 @@ export class LocalCopies {
|
|
|
428
424
|
await ignoreRules(copy.repository, [...read.writable.keys()], next);
|
|
429
425
|
return next;
|
|
430
426
|
}
|
|
431
|
-
async
|
|
432
|
-
|
|
433
|
-
|
|
427
|
+
async refreshed(copies) {
|
|
428
|
+
const discovery = await this.house.post('/kit/door/discover', {
|
|
429
|
+
prefixes: copies.map((copy) => rootOf(copy.room_handle)),
|
|
430
|
+
});
|
|
431
|
+
const regranted = new Map();
|
|
432
|
+
for (const copy of copies) {
|
|
433
|
+
const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
|
|
434
|
+
if (authority !== undefined &&
|
|
435
|
+
JSON.stringify([authority.operations.write, authority.protected_paths]) !== JSON.stringify([copy.write, copy.protected])) {
|
|
436
|
+
regranted.set(copy.key, await this.save(await this.received(copy)));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
const caught = await this.caughtUp(copies.filter((copy) => !regranted.has(copy.key)), false);
|
|
440
|
+
return copies.map((copy) => regranted.get(copy.key) ?? caught.find((held) => held.key === copy.key));
|
|
441
|
+
}
|
|
442
|
+
async caughtUp(copies, whole) {
|
|
443
|
+
const caught = new Map(copies.map((copy) => [copy.key, copy]));
|
|
444
|
+
let asking = [...copies];
|
|
445
|
+
while (asking.length > 0) {
|
|
434
446
|
let answer;
|
|
435
447
|
try {
|
|
436
448
|
answer = await this.house.post('/kit/door/enumerate', {
|
|
437
|
-
prefixes:
|
|
438
|
-
positions:
|
|
449
|
+
prefixes: asking.map((copy) => rootOf(copy.room_handle)),
|
|
450
|
+
positions: asking.map((copy) => ({ authority: copy.room_ref, position: copy.position, log_epoch: copy.log_epoch })),
|
|
439
451
|
});
|
|
440
452
|
}
|
|
441
453
|
catch (error) {
|
|
442
|
-
const
|
|
443
|
-
if (
|
|
444
|
-
return this.received(copy);
|
|
445
|
-
if (code !== 'replica_behind')
|
|
454
|
+
const expired = asking.find((copy) => copy.room_ref === expiredAuthority(error));
|
|
455
|
+
if (expired === undefined)
|
|
446
456
|
throw error;
|
|
447
|
-
|
|
448
|
-
|
|
457
|
+
caught.set(expired.key, await this.save(await this.received(expired)));
|
|
458
|
+
asking = asking.filter((copy) => copy !== expired);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
const advanced = [];
|
|
462
|
+
for (const copy of asking) {
|
|
463
|
+
const view = answer.authorities.find((entry) => entry.authority === copy.room_ref);
|
|
464
|
+
if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
|
|
465
|
+
continue;
|
|
466
|
+
const next = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
|
|
467
|
+
caught.set(copy.key, next);
|
|
468
|
+
advanced.push(next);
|
|
449
469
|
}
|
|
450
|
-
|
|
451
|
-
if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
|
|
452
|
-
return copy;
|
|
453
|
-
copy = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
|
|
470
|
+
asking = whole ? advanced : [];
|
|
454
471
|
}
|
|
472
|
+
return copies.map((copy) => caught.get(copy.key));
|
|
455
473
|
}
|
|
456
474
|
async incorporated(copy, changes, position, logEpoch) {
|
|
457
475
|
const houseTree = await tree(copy.repository, copy.house);
|
|
@@ -484,7 +502,7 @@ export class LocalCopies {
|
|
|
484
502
|
let { house, manifests } = copy;
|
|
485
503
|
if (files.size > 0) {
|
|
486
504
|
house = await importCommits(copy.repository, [
|
|
487
|
-
{ message: `House ${rootOf(copy)} at position ${position}`, from: copy.house, files },
|
|
505
|
+
{ message: `House ${rootOf(copy.room_handle)} at position ${position}`, from: copy.house, files },
|
|
488
506
|
]);
|
|
489
507
|
manifests = { ...manifests, [house]: { parent: copy.house, files: revisions } };
|
|
490
508
|
}
|
|
@@ -515,7 +533,7 @@ export class LocalCopies {
|
|
|
515
533
|
copy = await this.save(without(copy));
|
|
516
534
|
}
|
|
517
535
|
if (!copy.active) {
|
|
518
|
-
return { refused: true, text: `${rootOf(copy)} is no longer synced to this Environment, so House takes no push from it` };
|
|
536
|
+
return { refused: true, text: `${rootOf(copy.room_handle)} is no longer synced to this Environment, so House takes no push from it` };
|
|
519
537
|
}
|
|
520
538
|
const listed = (await git(copy.repository, ['rev-list', '--topo-order', commit])).split('\n');
|
|
521
539
|
const base = listed.find((ancestor) => ancestor in copy.manifests);
|
|
@@ -549,7 +567,7 @@ export class LocalCopies {
|
|
|
549
567
|
return this.settle(submitted, caller);
|
|
550
568
|
}
|
|
551
569
|
async derived(copy, base, commit) {
|
|
552
|
-
const root = rootOf(copy);
|
|
570
|
+
const root = rootOf(copy.room_handle);
|
|
553
571
|
const before = await tree(copy.repository, base);
|
|
554
572
|
const after = await tree(copy.repository, commit);
|
|
555
573
|
const moved = movedPaths(copy.moves, before, after);
|
|
@@ -605,12 +623,12 @@ export class LocalCopies {
|
|
|
605
623
|
const { upload, ...unstaged } = copy.push;
|
|
606
624
|
return this.settle(await this.save({ ...copy, push: unstaged }), caller, true);
|
|
607
625
|
}
|
|
608
|
-
if (outcome.refused.code === '
|
|
626
|
+
if (outcome.refused.code === 'expired')
|
|
609
627
|
return this.recovered(copy);
|
|
610
628
|
const rebased = rebaseFixes(outcome.refused);
|
|
611
629
|
let settled = await this.save(without(copy));
|
|
612
630
|
try {
|
|
613
|
-
settled =
|
|
631
|
+
settled = (await this.caughtUp([settled], true))[0];
|
|
614
632
|
}
|
|
615
633
|
catch {
|
|
616
634
|
return {
|
|
@@ -629,9 +647,9 @@ export class LocalCopies {
|
|
|
629
647
|
}
|
|
630
648
|
async recovered(copy) {
|
|
631
649
|
const push = copy.push;
|
|
632
|
-
const current =
|
|
650
|
+
const current = (await this.caughtUp([copy], true))[0];
|
|
633
651
|
const house = await tree(copy.repository, current.house);
|
|
634
|
-
const root = rootOf(current);
|
|
652
|
+
const root = rootOf(current.room_handle);
|
|
635
653
|
if (!(await this.landed(copy.repository, push.changes, house, await tree(copy.repository, push.commit)))) {
|
|
636
654
|
await this.save(without(current));
|
|
637
655
|
return {
|
|
@@ -673,7 +691,7 @@ export class LocalCopies {
|
|
|
673
691
|
const push = copy.push;
|
|
674
692
|
let written = push.written;
|
|
675
693
|
if (push.changes.some((change) => change.op === 'rename')) {
|
|
676
|
-
copy =
|
|
694
|
+
copy = (await this.caughtUp([copy], true))[0];
|
|
677
695
|
const house = await tree(copy.repository, copy.house);
|
|
678
696
|
const sent = await tree(copy.repository, push.house);
|
|
679
697
|
if (push.changes.some((change) => change.op === 'rename' && !house.has(relative(change.to)))) {
|
|
@@ -687,7 +705,7 @@ export class LocalCopies {
|
|
|
687
705
|
written = [
|
|
688
706
|
...written,
|
|
689
707
|
{
|
|
690
|
-
path: `${rootOf(copy)}/${path}`,
|
|
708
|
+
path: `${rootOf(copy.room_handle)}/${path}`,
|
|
691
709
|
revision: entry === undefined ? null : (revisionAt(copy, copy.house, path) ?? null),
|
|
692
710
|
content: entry === undefined ? null : await blobText(copy.repository, entry, path),
|
|
693
711
|
},
|
|
@@ -707,7 +725,7 @@ export class LocalCopies {
|
|
|
707
725
|
}
|
|
708
726
|
const edits = new Map([...files].filter(([path, content]) => (content === null ? selected.has(path) : selected.get(path) !== blobId(content))));
|
|
709
727
|
const received = [...files.keys()].filter((path) => revisionAt(copy, copy.house, path) === revisionAt(copy, push.house, path));
|
|
710
|
-
const accepted = `House ${rootOf(copy)} with ${push.commit} accepted`;
|
|
728
|
+
const accepted = `House ${rootOf(copy.room_handle)} with ${push.commit} accepted`;
|
|
711
729
|
const house = await importCommits(copy.repository, [
|
|
712
730
|
...(edits.size === 0 ? [] : [{ message: accepted, from: push.commit, files: edits }]),
|
|
713
731
|
{
|
package/dist/end.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { killDescendants } from './scope.js';
|
|
2
|
+
export const REPLACED = 'another Kit started for this Environment';
|
|
3
|
+
export const SIGN_IN_AGAIN = 'sign in again';
|
|
4
|
+
export function end(reason) {
|
|
5
|
+
process.stderr.write(`kit: ${reason}\n`);
|
|
6
|
+
killDescendants();
|
|
7
|
+
process.exit(0);
|
|
8
|
+
}
|