@agentshouse/kit 0.2.1-c15804a0fa28d → 0.2.1-c23bd93c02c83
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 +32 -31
- package/dist/acp.js +16 -93
- package/dist/agents.js +153 -44
- package/dist/api.js +34 -2
- package/dist/app-git.js +48 -0
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +35 -56
- package/dist/chatgpt.js +32 -0
- package/dist/clis.js +137 -65
- package/dist/codex-main.js +58 -0
- package/dist/conversations.js +352 -244
- package/dist/copies.js +157 -116
- package/dist/end.js +23 -0
- package/dist/enrol-main.js +7 -1
- package/dist/events.js +524 -0
- package/dist/files.js +21 -1
- package/dist/git.js +10 -8
- package/dist/home.js +96 -7
- package/dist/house-cli.js +291 -0
- package/dist/house-main.js +7 -159
- package/dist/instructions.js +10 -32
- package/dist/kit-cli.js +68 -0
- package/dist/kit-main.js +8 -19
- package/dist/login.js +118 -103
- package/dist/logout.js +14 -13
- package/dist/parts.js +82 -0
- package/dist/placement.js +30 -0
- package/dist/refusals.js +12 -0
- package/dist/relay.js +12 -2
- package/dist/resident.js +84 -32
- package/dist/scope.js +203 -0
- package/dist/secret-input.js +4 -1
- 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 -9
- package/dist/skills.js +81 -12
- package/dist/stream.js +87 -11
- package/dist/transcription.js +57 -9
- package/dist/update.js +30 -6
- package/dist/wire.js +6 -0
- package/dist/work.js +346 -0
- package/how-we-work.md +13 -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,11 +11,13 @@ 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);
|
|
18
17
|
}
|
|
18
|
+
function houseCause(error) {
|
|
19
|
+
return error instanceof HouseRefusal ? (refusalOf(error.text)?.text ?? causeOf(error)) : causeOf(error);
|
|
20
|
+
}
|
|
19
21
|
function logged(error) {
|
|
20
22
|
process.stderr.write(`kit: ${causeOf(error)}\n`);
|
|
21
23
|
}
|
|
@@ -30,9 +32,29 @@ const REBASED = new Set([
|
|
|
30
32
|
function rebaseFixes(refusal) {
|
|
31
33
|
return refusal.code === 'edit_conflict' && refusal.conflicts.some((code) => REBASED.has(code));
|
|
32
34
|
}
|
|
35
|
+
function textOnly(paths) {
|
|
36
|
+
const [named, them] = paths.length === 1 ? [`${paths[0]} is`, 'it'] : [`${paths.join(', ')} are`, 'them'];
|
|
37
|
+
return `${named} not text, and house push sends text only; remove ${them} from the commit and place ${them} with house upload`;
|
|
38
|
+
}
|
|
33
39
|
function short(commit) {
|
|
34
40
|
return commit.slice(0, 12);
|
|
35
41
|
}
|
|
42
|
+
function moved(before, after) {
|
|
43
|
+
if (before.house !== after.house)
|
|
44
|
+
return [`${rootOf(after.room_handle)}: ${HOUSE_REF} is at ${short(after.house)}`];
|
|
45
|
+
return before.position === after.position ? [] : [`${rootOf(after.room_handle)}: read-only files refreshed`];
|
|
46
|
+
}
|
|
47
|
+
function expiredAuthority(error) {
|
|
48
|
+
if (!(error instanceof HouseRefusal))
|
|
49
|
+
return undefined;
|
|
50
|
+
try {
|
|
51
|
+
const { error: refused } = JSON.parse(error.text);
|
|
52
|
+
return refused?.code === 'expired' && typeof refused.authority === 'string' ? refused.authority : undefined;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
36
58
|
function covers(path, prefix) {
|
|
37
59
|
return prefix === '' || path === prefix || path.startsWith(`${prefix}/`);
|
|
38
60
|
}
|
|
@@ -153,19 +175,18 @@ export class LocalCopies {
|
|
|
153
175
|
house;
|
|
154
176
|
copies = new Map();
|
|
155
177
|
queues = new Map();
|
|
156
|
-
|
|
157
|
-
selecting = Promise.resolve();
|
|
178
|
+
answering = Promise.resolve();
|
|
158
179
|
constructor(house) {
|
|
159
180
|
this.house = house;
|
|
160
181
|
this.owner = {
|
|
161
182
|
key: 'owner',
|
|
162
183
|
submit: async (operation, changes) => {
|
|
163
184
|
try {
|
|
164
|
-
const outcome = await house.post('/kit/door/batch', { operation_id: operation, changes });
|
|
185
|
+
const outcome = await retrying(() => house.post('/kit/door/batch', { operation_id: operation, changes }));
|
|
165
186
|
return { accepted: outcome.contents };
|
|
166
187
|
}
|
|
167
188
|
catch (error) {
|
|
168
|
-
if (!(error
|
|
189
|
+
if (!finalRefusal(error))
|
|
169
190
|
throw error;
|
|
170
191
|
return {
|
|
171
192
|
refused: refusalOf(error.text) ?? { code: '', text: `House refused it with ${error.status}`, conflicts: [] },
|
|
@@ -186,42 +207,68 @@ export class LocalCopies {
|
|
|
186
207
|
}
|
|
187
208
|
}
|
|
188
209
|
async mapping() {
|
|
189
|
-
await this.
|
|
210
|
+
await this.answering;
|
|
190
211
|
return [...this.copies.values()]
|
|
191
212
|
.filter((copy) => copy.active)
|
|
192
213
|
.map((copy) => `${rootOf(copy.room_handle)}: ${copy.repository}`)
|
|
193
214
|
.sort();
|
|
194
215
|
}
|
|
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);
|
|
216
|
+
async connected() {
|
|
217
|
+
const copied = await this.answered(() => this.fetched(false));
|
|
218
|
+
if (copied.refused)
|
|
219
|
+
logged(copied.text);
|
|
217
220
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
221
|
+
fetch() {
|
|
222
|
+
return this.answered(() => this.fetched(true));
|
|
223
|
+
}
|
|
224
|
+
answered(work) {
|
|
225
|
+
const answered = this.answering.then(work);
|
|
226
|
+
this.answering = answered.catch(() => undefined);
|
|
227
|
+
return answered;
|
|
228
|
+
}
|
|
229
|
+
async fetched(refreshing) {
|
|
230
|
+
const { local_copy: answer } = await this.house.post('/kit/local-copy/selection', {});
|
|
231
|
+
const synced = new Map(answer.rooms.map((room) => [`rooms/${room.room_ref}`, room.room_handle]));
|
|
232
|
+
return this.holding([...new Set([...this.copies.keys(), ...synced.keys()])].sort(), async () => {
|
|
233
|
+
const said = [];
|
|
234
|
+
let refused = false;
|
|
235
|
+
for (const copy of this.copies.values()) {
|
|
236
|
+
if (synced.has(copy.key) || !copy.active)
|
|
237
|
+
continue;
|
|
238
|
+
await this.save({ ...copy, active: false });
|
|
239
|
+
said.push(`${rootOf(copy.room_handle)}: no longer synced to this Environment; its files stay`);
|
|
240
|
+
}
|
|
241
|
+
const current = [];
|
|
242
|
+
for (const [key, handle] of synced) {
|
|
243
|
+
try {
|
|
244
|
+
const held = this.copies.get(key);
|
|
245
|
+
if (held === undefined || !(await exists(held.repository))) {
|
|
246
|
+
said.push(await this.materialize(key, handle));
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const copy = held.room_handle === handle ? held : await this.save({ ...held, room_handle: handle });
|
|
250
|
+
if (copy.active)
|
|
251
|
+
current.push(copy);
|
|
252
|
+
else
|
|
253
|
+
said.push(...moved(copy, await this.save(await this.received({ ...copy, active: true }))));
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
refused = true;
|
|
257
|
+
said.push(`${rootOf(handle)}: ${causeOf(error)}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (refreshing && current.length > 0) {
|
|
261
|
+
try {
|
|
262
|
+
const refreshed = await this.refreshed(current);
|
|
263
|
+
current.forEach((copy, index) => said.push(...moved(copy, refreshed[index])));
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
refused = true;
|
|
267
|
+
said.push(houseCause(error));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return { refused, text: said.length === 0 ? 'Nothing new from House.' : said.join('\n') };
|
|
271
|
+
});
|
|
225
272
|
}
|
|
226
273
|
async observed(report) {
|
|
227
274
|
const key = await this.keyAt(dirname(report.common));
|
|
@@ -271,16 +318,9 @@ export class LocalCopies {
|
|
|
271
318
|
this.queues.set(key, queued.catch(() => undefined));
|
|
272
319
|
return queued;
|
|
273
320
|
}
|
|
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);
|
|
321
|
+
holding(keys, work) {
|
|
322
|
+
const [key, ...rest] = keys;
|
|
323
|
+
return key === undefined ? work() : this.exclusive(key, () => this.holding(rest, work));
|
|
284
324
|
}
|
|
285
325
|
async save(copy) {
|
|
286
326
|
const path = join(kitHome(), 'local-copies', `${copy.key}.json`);
|
|
@@ -326,46 +366,13 @@ export class LocalCopies {
|
|
|
326
366
|
}
|
|
327
367
|
return read;
|
|
328
368
|
}
|
|
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
|
-
}
|
|
369
|
+
async materialize(key, handle) {
|
|
370
|
+
const read = await this.read(handle);
|
|
371
|
+
if (read === null)
|
|
372
|
+
throw new Error('House serves nothing of it to copy');
|
|
364
373
|
const repository = join(localCopies(), 'rooms', read.anchor);
|
|
365
|
-
if (await exists(repository))
|
|
366
|
-
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
374
|
+
if (await exists(repository))
|
|
375
|
+
throw new Error(`${repository} already exists and House Kit leaves it as it is`);
|
|
369
376
|
const staging = join(dirname(repository), `.${randomUUID()}`);
|
|
370
377
|
await mkdir(staging, { recursive: true });
|
|
371
378
|
let house;
|
|
@@ -373,7 +380,7 @@ export class LocalCopies {
|
|
|
373
380
|
try {
|
|
374
381
|
await git(staging, ['init', '-q', '-b', BRANCH]);
|
|
375
382
|
house = await importCommits(staging, [
|
|
376
|
-
{ message: `House ${rootOf(
|
|
383
|
+
{ message: `House ${rootOf(handle)}`, from: null, files: read.writable },
|
|
377
384
|
]);
|
|
378
385
|
await git(staging, ['update-ref', `refs/heads/${BRANCH}`, house]);
|
|
379
386
|
await git(staging, ['reset', '-q', '--hard']);
|
|
@@ -386,9 +393,9 @@ export class LocalCopies {
|
|
|
386
393
|
throw error;
|
|
387
394
|
}
|
|
388
395
|
await this.save({
|
|
389
|
-
key
|
|
396
|
+
key,
|
|
390
397
|
room_ref: read.anchor,
|
|
391
|
-
room_handle:
|
|
398
|
+
room_handle: handle,
|
|
392
399
|
repository,
|
|
393
400
|
active: true,
|
|
394
401
|
house,
|
|
@@ -400,6 +407,7 @@ export class LocalCopies {
|
|
|
400
407
|
manifests: { [house]: { parent: null, files: read.revisions } },
|
|
401
408
|
moves: [],
|
|
402
409
|
});
|
|
410
|
+
return `${rootOf(handle)}: copied to ${repository}`;
|
|
403
411
|
}
|
|
404
412
|
async received(copy) {
|
|
405
413
|
const read = await this.read(copy.room_handle);
|
|
@@ -423,30 +431,52 @@ export class LocalCopies {
|
|
|
423
431
|
await ignoreRules(copy.repository, [...read.writable.keys()], next);
|
|
424
432
|
return next;
|
|
425
433
|
}
|
|
426
|
-
async
|
|
427
|
-
|
|
428
|
-
|
|
434
|
+
async refreshed(copies) {
|
|
435
|
+
const discovery = await this.house.post('/kit/door/discover', {
|
|
436
|
+
prefixes: copies.map((copy) => rootOf(copy.room_handle)),
|
|
437
|
+
});
|
|
438
|
+
const regranted = new Map();
|
|
439
|
+
for (const copy of copies) {
|
|
440
|
+
const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
|
|
441
|
+
if (authority !== undefined &&
|
|
442
|
+
JSON.stringify([authority.operations.write, authority.protected_paths]) !== JSON.stringify([copy.write, copy.protected])) {
|
|
443
|
+
regranted.set(copy.key, await this.save(await this.received(copy)));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const caught = await this.caughtUp(copies.filter((copy) => !regranted.has(copy.key)), false);
|
|
447
|
+
return copies.map((copy) => regranted.get(copy.key) ?? caught.find((held) => held.key === copy.key));
|
|
448
|
+
}
|
|
449
|
+
async caughtUp(copies, whole) {
|
|
450
|
+
const caught = new Map(copies.map((copy) => [copy.key, copy]));
|
|
451
|
+
let asking = [...copies];
|
|
452
|
+
while (asking.length > 0) {
|
|
429
453
|
let answer;
|
|
430
454
|
try {
|
|
431
455
|
answer = await this.house.post('/kit/door/enumerate', {
|
|
432
|
-
prefixes:
|
|
433
|
-
positions:
|
|
456
|
+
prefixes: asking.map((copy) => rootOf(copy.room_handle)),
|
|
457
|
+
positions: asking.map((copy) => ({ authority: copy.room_ref, position: copy.position, log_epoch: copy.log_epoch })),
|
|
434
458
|
});
|
|
435
459
|
}
|
|
436
460
|
catch (error) {
|
|
437
|
-
const
|
|
438
|
-
if (
|
|
439
|
-
return this.received(copy);
|
|
440
|
-
if (code !== 'replica_behind')
|
|
461
|
+
const expired = asking.find((copy) => copy.room_ref === expiredAuthority(error));
|
|
462
|
+
if (expired === undefined)
|
|
441
463
|
throw error;
|
|
442
|
-
|
|
443
|
-
|
|
464
|
+
caught.set(expired.key, await this.save(await this.received(expired)));
|
|
465
|
+
asking = asking.filter((copy) => copy !== expired);
|
|
466
|
+
continue;
|
|
444
467
|
}
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
468
|
+
const advanced = [];
|
|
469
|
+
for (const copy of asking) {
|
|
470
|
+
const view = answer.authorities.find((entry) => entry.authority === copy.room_ref);
|
|
471
|
+
if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
|
|
472
|
+
continue;
|
|
473
|
+
const next = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
|
|
474
|
+
caught.set(copy.key, next);
|
|
475
|
+
advanced.push(next);
|
|
476
|
+
}
|
|
477
|
+
asking = whole ? advanced : [];
|
|
449
478
|
}
|
|
479
|
+
return copies.map((copy) => caught.get(copy.key));
|
|
450
480
|
}
|
|
451
481
|
async incorporated(copy, changes, position, logEpoch) {
|
|
452
482
|
const houseTree = await tree(copy.repository, copy.house);
|
|
@@ -522,7 +552,7 @@ export class LocalCopies {
|
|
|
522
552
|
changes = await this.derived(copy, base, commit);
|
|
523
553
|
}
|
|
524
554
|
catch (error) {
|
|
525
|
-
return { refused: true, text:
|
|
555
|
+
return { refused: true, text: houseCause(error) };
|
|
526
556
|
}
|
|
527
557
|
if (changes.length === 0)
|
|
528
558
|
return { refused: false, text: `Nothing to submit: ${short(commit)} matches House.` };
|
|
@@ -549,7 +579,18 @@ export class LocalCopies {
|
|
|
549
579
|
const after = await tree(copy.repository, commit);
|
|
550
580
|
const moved = movedPaths(copy.moves, before, after);
|
|
551
581
|
const arrived = new Set(moved.values());
|
|
552
|
-
const
|
|
582
|
+
const arriving = [...after].filter(([path, entry]) => before.get(path) !== entry);
|
|
583
|
+
if (arriving.length > 0) {
|
|
584
|
+
const { bounds } = await this.house.post('/kit/door/discover', { prefixes: [root] });
|
|
585
|
+
const binary = [];
|
|
586
|
+
for (const [path, entry] of arriving) {
|
|
587
|
+
if (!(await isText(copy.repository, entry, bounds.max_authored_file_bytes)))
|
|
588
|
+
binary.push(path);
|
|
589
|
+
}
|
|
590
|
+
if (binary.length > 0)
|
|
591
|
+
throw new Error(textOnly(binary));
|
|
592
|
+
}
|
|
593
|
+
const text = (entry) => blobText(copy.repository, entry);
|
|
553
594
|
const changes = [];
|
|
554
595
|
for (const path of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
555
596
|
if (arrived.has(path))
|
|
@@ -562,7 +603,7 @@ export class LocalCopies {
|
|
|
562
603
|
changes.push({ op: 'rename', path: `${root}/${path}`, to: `${root}/${to}`, base: known });
|
|
563
604
|
const moving = after.get(to);
|
|
564
605
|
if (moving !== prior) {
|
|
565
|
-
changes.push({ op: 'replace', path: `${root}/${to}`, base: known, content: await text(moving
|
|
606
|
+
changes.push({ op: 'replace', path: `${root}/${to}`, base: known, content: await text(moving) });
|
|
566
607
|
}
|
|
567
608
|
continue;
|
|
568
609
|
}
|
|
@@ -571,9 +612,9 @@ export class LocalCopies {
|
|
|
571
612
|
if (next === undefined)
|
|
572
613
|
changes.push({ op: 'remove', path: `${root}/${path}`, base: known });
|
|
573
614
|
else if (prior === undefined)
|
|
574
|
-
changes.push({ op: 'create', path: `${root}/${path}`, content: await text(next
|
|
615
|
+
changes.push({ op: 'create', path: `${root}/${path}`, content: await text(next) });
|
|
575
616
|
else
|
|
576
|
-
changes.push(...changed(`${root}/${path}`, path, known, await text(prior
|
|
617
|
+
changes.push(...changed(`${root}/${path}`, path, known, await text(prior), await text(next)));
|
|
577
618
|
}
|
|
578
619
|
return changes;
|
|
579
620
|
}
|
|
@@ -600,12 +641,12 @@ export class LocalCopies {
|
|
|
600
641
|
const { upload, ...unstaged } = copy.push;
|
|
601
642
|
return this.settle(await this.save({ ...copy, push: unstaged }), caller, true);
|
|
602
643
|
}
|
|
603
|
-
if (outcome.refused.code === '
|
|
644
|
+
if (outcome.refused.code === 'expired')
|
|
604
645
|
return this.recovered(copy);
|
|
605
646
|
const rebased = rebaseFixes(outcome.refused);
|
|
606
647
|
let settled = await this.save(without(copy));
|
|
607
648
|
try {
|
|
608
|
-
settled =
|
|
649
|
+
settled = (await this.caughtUp([settled], true))[0];
|
|
609
650
|
}
|
|
610
651
|
catch {
|
|
611
652
|
return {
|
|
@@ -624,7 +665,7 @@ export class LocalCopies {
|
|
|
624
665
|
}
|
|
625
666
|
async recovered(copy) {
|
|
626
667
|
const push = copy.push;
|
|
627
|
-
const current =
|
|
668
|
+
const current = (await this.caughtUp([copy], true))[0];
|
|
628
669
|
const house = await tree(copy.repository, current.house);
|
|
629
670
|
const root = rootOf(current.room_handle);
|
|
630
671
|
if (!(await this.landed(copy.repository, push.changes, house, await tree(copy.repository, push.commit)))) {
|
|
@@ -640,7 +681,7 @@ export class LocalCopies {
|
|
|
640
681
|
written.push({
|
|
641
682
|
path: `${root}/${path}`,
|
|
642
683
|
revision: entry === undefined ? null : (revisionAt(current, current.house, path) ?? null),
|
|
643
|
-
content: entry === undefined ? null : await blobText(copy.repository, entry
|
|
684
|
+
content: entry === undefined ? null : await blobText(copy.repository, entry),
|
|
644
685
|
});
|
|
645
686
|
}
|
|
646
687
|
return this.finished(await this.save({ ...current, push: { ...push, state: 'accepted', written } }));
|
|
@@ -668,7 +709,7 @@ export class LocalCopies {
|
|
|
668
709
|
const push = copy.push;
|
|
669
710
|
let written = push.written;
|
|
670
711
|
if (push.changes.some((change) => change.op === 'rename')) {
|
|
671
|
-
copy =
|
|
712
|
+
copy = (await this.caughtUp([copy], true))[0];
|
|
672
713
|
const house = await tree(copy.repository, copy.house);
|
|
673
714
|
const sent = await tree(copy.repository, push.house);
|
|
674
715
|
if (push.changes.some((change) => change.op === 'rename' && !house.has(relative(change.to)))) {
|
|
@@ -684,7 +725,7 @@ export class LocalCopies {
|
|
|
684
725
|
{
|
|
685
726
|
path: `${rootOf(copy.room_handle)}/${path}`,
|
|
686
727
|
revision: entry === undefined ? null : (revisionAt(copy, copy.house, path) ?? null),
|
|
687
|
-
content: entry === undefined ? null : await blobText(copy.repository, entry
|
|
728
|
+
content: entry === undefined ? null : await blobText(copy.repository, entry),
|
|
688
729
|
},
|
|
689
730
|
];
|
|
690
731
|
}
|
|
@@ -729,7 +770,7 @@ export class LocalCopies {
|
|
|
729
770
|
async landed(repository, changes, house, selected) {
|
|
730
771
|
const text = async (path) => {
|
|
731
772
|
const entry = house.get(relative(path));
|
|
732
|
-
return entry === undefined ? undefined : blobText(repository, entry
|
|
773
|
+
return entry === undefined ? undefined : blobText(repository, entry);
|
|
733
774
|
};
|
|
734
775
|
for (const change of changes) {
|
|
735
776
|
const current = await text(change.path);
|
package/dist/end.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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() {
|
|
17
|
+
const command = installCommand();
|
|
18
|
+
end(command === null ? 'This Kit is too old for House; install it again.' : `This Kit is too old for House. Update it: ${command}`);
|
|
19
|
+
}
|
|
20
|
+
export async function signInAgain(rejected) {
|
|
21
|
+
await forgetRejected(rejected);
|
|
22
|
+
restart('sign in again');
|
|
23
|
+
}
|
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
|
+
});
|