@agentshouse/kit 0.2.1-c23b83622c698 → 0.2.1-c2f0855c31ca3
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 +26 -26
- package/dist/acp.js +16 -93
- package/dist/agents.js +74 -32
- package/dist/api.js +34 -2
- package/dist/app-git.js +64 -0
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +33 -51
- package/dist/chatgpt.js +26 -0
- package/dist/clis.js +118 -70
- package/dist/codex-main.js +58 -0
- package/dist/conversations.js +284 -236
- package/dist/copies.js +148 -115
- package/dist/end.js +22 -0
- package/dist/enrol-main.js +7 -1
- package/dist/events.js +521 -0
- package/dist/files.js +21 -1
- package/dist/git.js +11 -8
- package/dist/home.js +78 -6
- package/dist/house-main.js +186 -56
- package/dist/instructions.js +9 -32
- package/dist/kit-main.js +54 -6
- package/dist/login.js +94 -104
- package/dist/logout.js +16 -13
- package/dist/parts.js +82 -0
- package/dist/placement.js +48 -0
- package/dist/refusals.js +12 -0
- package/dist/relay.js +12 -2
- package/dist/resident.js +38 -27
- package/dist/scope.js +203 -0
- package/dist/secret-input.js +3 -2
- package/dist/service-main.js +9 -0
- package/dist/service.js +33 -0
- package/dist/shell.js +3 -0
- package/dist/sign-in.js +34 -10
- package/dist/skills.js +80 -12
- package/dist/stream.js +35 -5
- package/dist/transcription.js +57 -9
- package/dist/update.js +30 -6
- package/dist/wire.js +6 -0
- package/dist/work.js +348 -0
- package/how-we-work.md +11 -3
- package/package.json +3 -2
- package/skills/ask-matt/SKILL.md +17 -11
- package/skills/ask-matt/agents/openai.yaml +1 -0
- package/skills/code-review/SKILL.md +5 -5
- package/skills/codebase-design/DESIGN-IT-TWICE.md +1 -1
- package/skills/codebase-design/SKILL.md +0 -2
- package/skills/diagnosing-bugs/SKILL.md +2 -4
- package/skills/domain-modeling/{CONTEXT-FORMAT.md → GLOSSARY-FORMAT.md} +10 -10
- package/skills/domain-modeling/SKILL.md +12 -14
- package/skills/grill-me/SKILL.md +1 -2
- package/skills/grill-me/agents/openai.yaml +1 -0
- package/skills/grill-with-docs/SKILL.md +1 -2
- package/skills/grill-with-docs/agents/openai.yaml +1 -0
- package/skills/grilling/SKILL.md +2 -2
- package/skills/handoff/SKILL.md +2 -3
- package/skills/handoff/agents/openai.yaml +1 -0
- package/skills/implement/SKILL.md +5 -4
- package/skills/implement/agents/openai.yaml +1 -0
- package/skills/implement-spec/SKILL.md +40 -0
- package/skills/implement-spec/agents/openai.yaml +5 -0
- package/skills/improve-codebase-architecture/SKILL.md +6 -7
- package/skills/improve-codebase-architecture/agents/openai.yaml +1 -0
- package/skills/pr/CREDITS.md +3 -0
- package/skills/pr/LICENSE +21 -0
- package/skills/pr/SKILL.md +170 -0
- package/skills/pr/agents/openai.yaml +3 -0
- package/skills/prototype/SKILL.md +0 -2
- package/skills/research/SKILL.md +0 -2
- package/skills/retro/LICENSE +21 -0
- package/skills/retro/SKILL.md +44 -0
- package/skills/retro/agents/openai.yaml +5 -0
- package/skills/tdd/SKILL.md +2 -4
- package/skills/teach/SKILL.md +3 -4
- package/skills/teach/agents/openai.yaml +1 -0
- package/skills/to-questionnaire/SKILL.md +1 -2
- package/skills/to-questionnaire/agents/openai.yaml +1 -0
- package/skills/to-spec/SKILL.md +1 -2
- package/skills/to-spec/agents/openai.yaml +1 -0
- package/skills/to-tickets/SKILL.md +3 -4
- package/skills/to-tickets/agents/openai.yaml +1 -0
- package/skills/triage/AGENT-BRIEF.md +207 -0
- package/skills/triage/LICENSE +21 -0
- package/skills/triage/OUT-OF-SCOPE.md +105 -0
- package/skills/triage/SKILL.md +112 -0
- package/skills/triage/agents/openai.yaml +5 -0
- package/skills/wait-what/SKILL.md +2 -3
- package/skills/wait-what/agents/openai.yaml +1 -0
- package/skills/wayfinder/SKILL.md +5 -6
- package/skills/wayfinder/agents/openai.yaml +1 -0
- package/skills/wizard/LICENSE +21 -0
- package/skills/wizard/SKILL.md +44 -0
- package/skills/wizard/agents/openai.yaml +3 -0
- package/skills/wizard/template.sh +223 -0
- package/skills/writing-for-agents/SKILL.md +0 -2
- package/dist/blocks.js +0 -51
- package/skills/resolving-merge-conflicts/SKILL.md +0 -16
- package/skills/resolving-merge-conflicts/agents/openai.yaml +0 -3
- /package/skills/{resolving-merge-conflicts → implement-spec}/LICENSE +0 -0
package/dist/copies.js
CHANGED
|
@@ -2,8 +2,8 @@ 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';
|
|
6
|
-
import { blobId, blobText, git, HOUSE_REF, importCommits, localCopies, revision, run, succeeded, tree, } from './git.js';
|
|
5
|
+
import { finalRefusal, HouseRefusal, retrying } from './api.js';
|
|
6
|
+
import { blobId, blobText, git, isText, 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';
|
|
@@ -11,7 +11,6 @@ import { changed } from './translate.js';
|
|
|
11
11
|
import { relayed } from './relay.js';
|
|
12
12
|
const BRANCH = 'main';
|
|
13
13
|
const PROVENANCE = '_provenance';
|
|
14
|
-
const REPLICA_RETRY_MS = 30_000;
|
|
15
14
|
const IDENTITY = { GIT_COMMITTER_NAME: 'House Kit', GIT_COMMITTER_EMAIL: 'house-kit@localhost' };
|
|
16
15
|
function causeOf(error) {
|
|
17
16
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -30,9 +29,29 @@ const REBASED = new Set([
|
|
|
30
29
|
function rebaseFixes(refusal) {
|
|
31
30
|
return refusal.code === 'edit_conflict' && refusal.conflicts.some((code) => REBASED.has(code));
|
|
32
31
|
}
|
|
32
|
+
function textOnly(paths) {
|
|
33
|
+
const [named, them] = paths.length === 1 ? [`${paths[0]} is`, 'it'] : [`${paths.join(', ')} are`, 'them'];
|
|
34
|
+
return `${named} not text, and house push sends text only; remove ${them} from the commit and place ${them} with house upload`;
|
|
35
|
+
}
|
|
33
36
|
function short(commit) {
|
|
34
37
|
return commit.slice(0, 12);
|
|
35
38
|
}
|
|
39
|
+
function moved(before, after) {
|
|
40
|
+
if (before.house !== after.house)
|
|
41
|
+
return [`${rootOf(after.room_handle)}: ${HOUSE_REF} is at ${short(after.house)}`];
|
|
42
|
+
return before.position === after.position ? [] : [`${rootOf(after.room_handle)}: read-only files refreshed`];
|
|
43
|
+
}
|
|
44
|
+
function expiredAuthority(error) {
|
|
45
|
+
if (!(error instanceof HouseRefusal))
|
|
46
|
+
return undefined;
|
|
47
|
+
try {
|
|
48
|
+
const { error: refused } = JSON.parse(error.text);
|
|
49
|
+
return refused?.code === 'expired' && typeof refused.authority === 'string' ? refused.authority : undefined;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
36
55
|
function covers(path, prefix) {
|
|
37
56
|
return prefix === '' || path === prefix || path.startsWith(`${prefix}/`);
|
|
38
57
|
}
|
|
@@ -153,19 +172,18 @@ export class LocalCopies {
|
|
|
153
172
|
house;
|
|
154
173
|
copies = new Map();
|
|
155
174
|
queues = new Map();
|
|
156
|
-
|
|
157
|
-
selecting = Promise.resolve();
|
|
175
|
+
answering = Promise.resolve();
|
|
158
176
|
constructor(house) {
|
|
159
177
|
this.house = house;
|
|
160
178
|
this.owner = {
|
|
161
179
|
key: 'owner',
|
|
162
180
|
submit: async (operation, changes) => {
|
|
163
181
|
try {
|
|
164
|
-
const outcome = await house.post('/kit/door/batch', { operation_id: operation, changes });
|
|
182
|
+
const outcome = await retrying(() => house.post('/kit/door/batch', { operation_id: operation, changes }));
|
|
165
183
|
return { accepted: outcome.contents };
|
|
166
184
|
}
|
|
167
185
|
catch (error) {
|
|
168
|
-
if (!(error
|
|
186
|
+
if (!finalRefusal(error))
|
|
169
187
|
throw error;
|
|
170
188
|
return {
|
|
171
189
|
refused: refusalOf(error.text) ?? { code: '', text: `House refused it with ${error.status}`, conflicts: [] },
|
|
@@ -186,42 +204,68 @@ export class LocalCopies {
|
|
|
186
204
|
}
|
|
187
205
|
}
|
|
188
206
|
async mapping() {
|
|
189
|
-
await this.
|
|
207
|
+
await this.answering;
|
|
190
208
|
return [...this.copies.values()]
|
|
191
209
|
.filter((copy) => copy.active)
|
|
192
210
|
.map((copy) => `${rootOf(copy.room_handle)}: ${copy.repository}`)
|
|
193
211
|
.sort();
|
|
194
212
|
}
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
async reselect() {
|
|
201
|
-
const { local_copy: chosen } = await this.house.post('/kit/local-copy/selection', {});
|
|
202
|
-
const selected = (chosen?.rooms ?? []).flatMap((room) => room.room_handle === null ? [] : [{ key: `rooms/${room.room_ref}`, handle: room.room_handle }]);
|
|
203
|
-
const keys = new Set(selected.map((scope) => scope.key));
|
|
204
|
-
const work = [];
|
|
205
|
-
for (const key of this.copies.keys()) {
|
|
206
|
-
if (keys.has(key))
|
|
207
|
-
continue;
|
|
208
|
-
work.push(this.exclusive(key, async () => {
|
|
209
|
-
const copy = this.copies.get(key);
|
|
210
|
-
if (copy.active)
|
|
211
|
-
await this.save({ ...copy, active: false });
|
|
212
|
-
}));
|
|
213
|
-
}
|
|
214
|
-
for (const scope of selected)
|
|
215
|
-
work.push(this.exclusive(scope.key, () => this.apply(scope)).catch(logged));
|
|
216
|
-
await Promise.all(work);
|
|
213
|
+
async connected() {
|
|
214
|
+
const copied = await this.answered(() => this.fetched(false));
|
|
215
|
+
if (copied.refused)
|
|
216
|
+
logged(copied.text);
|
|
217
217
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
fetch() {
|
|
219
|
+
return this.answered(() => this.fetched(true));
|
|
220
|
+
}
|
|
221
|
+
answered(work) {
|
|
222
|
+
const answered = this.answering.then(work);
|
|
223
|
+
this.answering = answered.catch(() => undefined);
|
|
224
|
+
return answered;
|
|
225
|
+
}
|
|
226
|
+
async fetched(refreshing) {
|
|
227
|
+
const { local_copy: answer } = await this.house.post('/kit/local-copy/selection', {});
|
|
228
|
+
const synced = new Map(answer.rooms.map((room) => [`rooms/${room.room_ref}`, room.room_handle]));
|
|
229
|
+
return this.holding([...new Set([...this.copies.keys(), ...synced.keys()])].sort(), async () => {
|
|
230
|
+
const said = [];
|
|
231
|
+
let refused = false;
|
|
232
|
+
for (const copy of this.copies.values()) {
|
|
233
|
+
if (synced.has(copy.key) || !copy.active)
|
|
234
|
+
continue;
|
|
235
|
+
await this.save({ ...copy, active: false });
|
|
236
|
+
said.push(`${rootOf(copy.room_handle)}: no longer synced to this Environment; its files stay`);
|
|
237
|
+
}
|
|
238
|
+
const current = [];
|
|
239
|
+
for (const [key, handle] of synced) {
|
|
240
|
+
try {
|
|
241
|
+
const held = this.copies.get(key);
|
|
242
|
+
if (held === undefined || !(await exists(held.repository))) {
|
|
243
|
+
said.push(await this.materialize(key, handle));
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const copy = held.room_handle === handle ? held : await this.save({ ...held, room_handle: handle });
|
|
247
|
+
if (copy.active)
|
|
248
|
+
current.push(copy);
|
|
249
|
+
else
|
|
250
|
+
said.push(...moved(copy, await this.save(await this.received({ ...copy, active: true }))));
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
refused = true;
|
|
254
|
+
said.push(`${rootOf(handle)}: ${causeOf(error)}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (refreshing && current.length > 0) {
|
|
258
|
+
try {
|
|
259
|
+
const refreshed = await this.refreshed(current);
|
|
260
|
+
current.forEach((copy, index) => said.push(...moved(copy, refreshed[index])));
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
refused = true;
|
|
264
|
+
said.push(error instanceof HouseRefusal ? (refusalOf(error.text)?.text ?? causeOf(error)) : causeOf(error));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return { refused, text: said.length === 0 ? 'Nothing new from House.' : said.join('\n') };
|
|
268
|
+
});
|
|
225
269
|
}
|
|
226
270
|
async observed(report) {
|
|
227
271
|
const key = await this.keyAt(dirname(report.common));
|
|
@@ -271,16 +315,9 @@ export class LocalCopies {
|
|
|
271
315
|
this.queues.set(key, queued.catch(() => undefined));
|
|
272
316
|
return queued;
|
|
273
317
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
this.delivering.add(key);
|
|
278
|
-
void this.exclusive(key, async () => {
|
|
279
|
-
this.delivering.delete(key);
|
|
280
|
-
const copy = this.copies.get(key);
|
|
281
|
-
if (copy.active)
|
|
282
|
-
await this.save(await this.caughtUp(copy));
|
|
283
|
-
}).catch(logged);
|
|
318
|
+
holding(keys, work) {
|
|
319
|
+
const [key, ...rest] = keys;
|
|
320
|
+
return key === undefined ? work() : this.exclusive(key, () => this.holding(rest, work));
|
|
284
321
|
}
|
|
285
322
|
async save(copy) {
|
|
286
323
|
const path = join(kitHome(), 'local-copies', `${copy.key}.json`);
|
|
@@ -326,46 +363,13 @@ export class LocalCopies {
|
|
|
326
363
|
}
|
|
327
364
|
return read;
|
|
328
365
|
}
|
|
329
|
-
async
|
|
330
|
-
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
if (copy.room_handle !== scope.handle)
|
|
336
|
-
copy = await this.save({ ...copy, room_handle: scope.handle });
|
|
337
|
-
if (!copy.active) {
|
|
338
|
-
await this.save(await this.received({ ...copy, active: true }));
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
const discovery = await this.house.post('/kit/door/discover', {
|
|
342
|
-
prefixes: [rootOf(copy.room_handle)],
|
|
343
|
-
});
|
|
344
|
-
const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
|
|
345
|
-
if (authority === undefined)
|
|
346
|
-
return;
|
|
347
|
-
if (authority.managed_replication !== 'admitted') {
|
|
348
|
-
logged(`operation_denied: ${rootOf(copy.room_handle)} is not synchronized to this Environment`);
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
if (JSON.stringify([authority.operations.write, authority.protected_paths]) !==
|
|
352
|
-
JSON.stringify([copy.write, copy.protected])) {
|
|
353
|
-
await this.save(await this.received(copy));
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
await this.save(await this.caughtUp(copy));
|
|
357
|
-
}
|
|
358
|
-
async materialize(scope) {
|
|
359
|
-
const read = await this.read(scope.handle);
|
|
360
|
-
if (read === null) {
|
|
361
|
-
logged(`House serves nothing of ${rootOf(scope.handle)} to copy`);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
366
|
+
async materialize(key, handle) {
|
|
367
|
+
const read = await this.read(handle);
|
|
368
|
+
if (read === null)
|
|
369
|
+
throw new Error('House serves nothing of it to copy');
|
|
364
370
|
const repository = join(localCopies(), 'rooms', read.anchor);
|
|
365
|
-
if (await exists(repository))
|
|
366
|
-
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
371
|
+
if (await exists(repository))
|
|
372
|
+
throw new Error(`${repository} already exists and House Kit leaves it as it is`);
|
|
369
373
|
const staging = join(dirname(repository), `.${randomUUID()}`);
|
|
370
374
|
await mkdir(staging, { recursive: true });
|
|
371
375
|
let house;
|
|
@@ -373,7 +377,7 @@ export class LocalCopies {
|
|
|
373
377
|
try {
|
|
374
378
|
await git(staging, ['init', '-q', '-b', BRANCH]);
|
|
375
379
|
house = await importCommits(staging, [
|
|
376
|
-
{ message: `House ${rootOf(
|
|
380
|
+
{ message: `House ${rootOf(handle)}`, from: null, files: read.writable },
|
|
377
381
|
]);
|
|
378
382
|
await git(staging, ['update-ref', `refs/heads/${BRANCH}`, house]);
|
|
379
383
|
await git(staging, ['reset', '-q', '--hard']);
|
|
@@ -386,9 +390,9 @@ export class LocalCopies {
|
|
|
386
390
|
throw error;
|
|
387
391
|
}
|
|
388
392
|
await this.save({
|
|
389
|
-
key
|
|
393
|
+
key,
|
|
390
394
|
room_ref: read.anchor,
|
|
391
|
-
room_handle:
|
|
395
|
+
room_handle: handle,
|
|
392
396
|
repository,
|
|
393
397
|
active: true,
|
|
394
398
|
house,
|
|
@@ -400,6 +404,7 @@ export class LocalCopies {
|
|
|
400
404
|
manifests: { [house]: { parent: null, files: read.revisions } },
|
|
401
405
|
moves: [],
|
|
402
406
|
});
|
|
407
|
+
return `${rootOf(handle)}: copied to ${repository}`;
|
|
403
408
|
}
|
|
404
409
|
async received(copy) {
|
|
405
410
|
const read = await this.read(copy.room_handle);
|
|
@@ -423,30 +428,52 @@ export class LocalCopies {
|
|
|
423
428
|
await ignoreRules(copy.repository, [...read.writable.keys()], next);
|
|
424
429
|
return next;
|
|
425
430
|
}
|
|
426
|
-
async
|
|
427
|
-
|
|
428
|
-
|
|
431
|
+
async refreshed(copies) {
|
|
432
|
+
const discovery = await this.house.post('/kit/door/discover', {
|
|
433
|
+
prefixes: copies.map((copy) => rootOf(copy.room_handle)),
|
|
434
|
+
});
|
|
435
|
+
const regranted = new Map();
|
|
436
|
+
for (const copy of copies) {
|
|
437
|
+
const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
|
|
438
|
+
if (authority !== undefined &&
|
|
439
|
+
JSON.stringify([authority.operations.write, authority.protected_paths]) !== JSON.stringify([copy.write, copy.protected])) {
|
|
440
|
+
regranted.set(copy.key, await this.save(await this.received(copy)));
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const caught = await this.caughtUp(copies.filter((copy) => !regranted.has(copy.key)), false);
|
|
444
|
+
return copies.map((copy) => regranted.get(copy.key) ?? caught.find((held) => held.key === copy.key));
|
|
445
|
+
}
|
|
446
|
+
async caughtUp(copies, whole) {
|
|
447
|
+
const caught = new Map(copies.map((copy) => [copy.key, copy]));
|
|
448
|
+
let asking = [...copies];
|
|
449
|
+
while (asking.length > 0) {
|
|
429
450
|
let answer;
|
|
430
451
|
try {
|
|
431
452
|
answer = await this.house.post('/kit/door/enumerate', {
|
|
432
|
-
prefixes:
|
|
433
|
-
positions:
|
|
453
|
+
prefixes: asking.map((copy) => rootOf(copy.room_handle)),
|
|
454
|
+
positions: asking.map((copy) => ({ authority: copy.room_ref, position: copy.position, log_epoch: copy.log_epoch })),
|
|
434
455
|
});
|
|
435
456
|
}
|
|
436
457
|
catch (error) {
|
|
437
|
-
const
|
|
438
|
-
if (
|
|
439
|
-
return this.received(copy);
|
|
440
|
-
if (code !== 'replica_behind')
|
|
458
|
+
const expired = asking.find((copy) => copy.room_ref === expiredAuthority(error));
|
|
459
|
+
if (expired === undefined)
|
|
441
460
|
throw error;
|
|
442
|
-
|
|
443
|
-
|
|
461
|
+
caught.set(expired.key, await this.save(await this.received(expired)));
|
|
462
|
+
asking = asking.filter((copy) => copy !== expired);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const advanced = [];
|
|
466
|
+
for (const copy of asking) {
|
|
467
|
+
const view = answer.authorities.find((entry) => entry.authority === copy.room_ref);
|
|
468
|
+
if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
|
|
469
|
+
continue;
|
|
470
|
+
const next = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
|
|
471
|
+
caught.set(copy.key, next);
|
|
472
|
+
advanced.push(next);
|
|
444
473
|
}
|
|
445
|
-
|
|
446
|
-
if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
|
|
447
|
-
return copy;
|
|
448
|
-
copy = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
|
|
474
|
+
asking = whole ? advanced : [];
|
|
449
475
|
}
|
|
476
|
+
return copies.map((copy) => caught.get(copy.key));
|
|
450
477
|
}
|
|
451
478
|
async incorporated(copy, changes, position, logEpoch) {
|
|
452
479
|
const houseTree = await tree(copy.repository, copy.house);
|
|
@@ -549,7 +576,13 @@ export class LocalCopies {
|
|
|
549
576
|
const after = await tree(copy.repository, commit);
|
|
550
577
|
const moved = movedPaths(copy.moves, before, after);
|
|
551
578
|
const arrived = new Set(moved.values());
|
|
552
|
-
const
|
|
579
|
+
const binary = [];
|
|
580
|
+
for (const [path, entry] of after)
|
|
581
|
+
if (before.get(path) !== entry && !(await isText(copy.repository, entry)))
|
|
582
|
+
binary.push(path);
|
|
583
|
+
if (binary.length > 0)
|
|
584
|
+
throw new Error(textOnly(binary));
|
|
585
|
+
const text = (entry) => blobText(copy.repository, entry);
|
|
553
586
|
const changes = [];
|
|
554
587
|
for (const path of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
555
588
|
if (arrived.has(path))
|
|
@@ -562,7 +595,7 @@ export class LocalCopies {
|
|
|
562
595
|
changes.push({ op: 'rename', path: `${root}/${path}`, to: `${root}/${to}`, base: known });
|
|
563
596
|
const moving = after.get(to);
|
|
564
597
|
if (moving !== prior) {
|
|
565
|
-
changes.push({ op: 'replace', path: `${root}/${to}`, base: known, content: await text(moving
|
|
598
|
+
changes.push({ op: 'replace', path: `${root}/${to}`, base: known, content: await text(moving) });
|
|
566
599
|
}
|
|
567
600
|
continue;
|
|
568
601
|
}
|
|
@@ -571,9 +604,9 @@ export class LocalCopies {
|
|
|
571
604
|
if (next === undefined)
|
|
572
605
|
changes.push({ op: 'remove', path: `${root}/${path}`, base: known });
|
|
573
606
|
else if (prior === undefined)
|
|
574
|
-
changes.push({ op: 'create', path: `${root}/${path}`, content: await text(next
|
|
607
|
+
changes.push({ op: 'create', path: `${root}/${path}`, content: await text(next) });
|
|
575
608
|
else
|
|
576
|
-
changes.push(...changed(`${root}/${path}`, path, known, await text(prior
|
|
609
|
+
changes.push(...changed(`${root}/${path}`, path, known, await text(prior), await text(next)));
|
|
577
610
|
}
|
|
578
611
|
return changes;
|
|
579
612
|
}
|
|
@@ -600,12 +633,12 @@ export class LocalCopies {
|
|
|
600
633
|
const { upload, ...unstaged } = copy.push;
|
|
601
634
|
return this.settle(await this.save({ ...copy, push: unstaged }), caller, true);
|
|
602
635
|
}
|
|
603
|
-
if (outcome.refused.code === '
|
|
636
|
+
if (outcome.refused.code === 'expired')
|
|
604
637
|
return this.recovered(copy);
|
|
605
638
|
const rebased = rebaseFixes(outcome.refused);
|
|
606
639
|
let settled = await this.save(without(copy));
|
|
607
640
|
try {
|
|
608
|
-
settled =
|
|
641
|
+
settled = (await this.caughtUp([settled], true))[0];
|
|
609
642
|
}
|
|
610
643
|
catch {
|
|
611
644
|
return {
|
|
@@ -624,7 +657,7 @@ export class LocalCopies {
|
|
|
624
657
|
}
|
|
625
658
|
async recovered(copy) {
|
|
626
659
|
const push = copy.push;
|
|
627
|
-
const current =
|
|
660
|
+
const current = (await this.caughtUp([copy], true))[0];
|
|
628
661
|
const house = await tree(copy.repository, current.house);
|
|
629
662
|
const root = rootOf(current.room_handle);
|
|
630
663
|
if (!(await this.landed(copy.repository, push.changes, house, await tree(copy.repository, push.commit)))) {
|
|
@@ -640,7 +673,7 @@ export class LocalCopies {
|
|
|
640
673
|
written.push({
|
|
641
674
|
path: `${root}/${path}`,
|
|
642
675
|
revision: entry === undefined ? null : (revisionAt(current, current.house, path) ?? null),
|
|
643
|
-
content: entry === undefined ? null : await blobText(copy.repository, entry
|
|
676
|
+
content: entry === undefined ? null : await blobText(copy.repository, entry),
|
|
644
677
|
});
|
|
645
678
|
}
|
|
646
679
|
return this.finished(await this.save({ ...current, push: { ...push, state: 'accepted', written } }));
|
|
@@ -668,7 +701,7 @@ export class LocalCopies {
|
|
|
668
701
|
const push = copy.push;
|
|
669
702
|
let written = push.written;
|
|
670
703
|
if (push.changes.some((change) => change.op === 'rename')) {
|
|
671
|
-
copy =
|
|
704
|
+
copy = (await this.caughtUp([copy], true))[0];
|
|
672
705
|
const house = await tree(copy.repository, copy.house);
|
|
673
706
|
const sent = await tree(copy.repository, push.house);
|
|
674
707
|
if (push.changes.some((change) => change.op === 'rename' && !house.has(relative(change.to)))) {
|
|
@@ -684,7 +717,7 @@ export class LocalCopies {
|
|
|
684
717
|
{
|
|
685
718
|
path: `${rootOf(copy.room_handle)}/${path}`,
|
|
686
719
|
revision: entry === undefined ? null : (revisionAt(copy, copy.house, path) ?? null),
|
|
687
|
-
content: entry === undefined ? null : await blobText(copy.repository, entry
|
|
720
|
+
content: entry === undefined ? null : await blobText(copy.repository, entry),
|
|
688
721
|
},
|
|
689
722
|
];
|
|
690
723
|
}
|
|
@@ -729,7 +762,7 @@ export class LocalCopies {
|
|
|
729
762
|
async landed(repository, changes, house, selected) {
|
|
730
763
|
const text = async (path) => {
|
|
731
764
|
const entry = house.get(relative(path));
|
|
732
|
-
return entry === undefined ? undefined : blobText(repository, entry
|
|
765
|
+
return entry === undefined ? undefined : blobText(repository, entry);
|
|
733
766
|
};
|
|
734
767
|
for (const change of changes) {
|
|
735
768
|
const current = await text(change.path);
|
package/dist/end.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { forgetRejected } from './home.js';
|
|
2
|
+
import { installCommand } from './placement.js';
|
|
3
|
+
import { killDescendants } from './scope.js';
|
|
4
|
+
export const REPLACED = 'another Kit started for this Environment';
|
|
5
|
+
function exit(reason, status) {
|
|
6
|
+
process.stderr.write(`kit: ${reason}\n`);
|
|
7
|
+
killDescendants();
|
|
8
|
+
process.exit(status);
|
|
9
|
+
}
|
|
10
|
+
export function end(reason) {
|
|
11
|
+
exit(reason, 0);
|
|
12
|
+
}
|
|
13
|
+
export function restart(reason) {
|
|
14
|
+
exit(reason, 1);
|
|
15
|
+
}
|
|
16
|
+
export function updateRequired(house) {
|
|
17
|
+
end(`This Kit is too old for House. Update it: ${installCommand(house)}`);
|
|
18
|
+
}
|
|
19
|
+
export async function signInAgain(rejected) {
|
|
20
|
+
await forgetRejected(rejected);
|
|
21
|
+
restart('sign in again');
|
|
22
|
+
}
|
package/dist/enrol-main.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { writeEnrolment } from './home.js';
|
|
3
3
|
const [house, environment] = process.argv.slice(2);
|
|
4
|
-
|
|
4
|
+
const relay = process.env.HOUSE_KIT_RELAY || undefined;
|
|
5
|
+
await writeEnrolment({
|
|
6
|
+
house: house,
|
|
7
|
+
...(relay === undefined ? {} : { relay }),
|
|
8
|
+
environment: environment,
|
|
9
|
+
credential: readFileSync(0, 'utf8').trim(),
|
|
10
|
+
});
|