@agentshouse/kit 0.2.1-cbabe8ad337ff → 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 CHANGED
@@ -44,11 +44,11 @@ until you revoke that connection on Connections. `house help` lists the Tools.
44
44
  agent's connection, so `house` and `git` no longer act as you here; a later
45
45
  `kit login` reconnects the same Environment.
46
46
 
47
- `kit resident` keeps the Environment connected, and keeps the Rooms you chose
48
- for this Environment as Git repositories under `local-copies` in the
49
- workspace. Commit in one and run `house push --owner` there to send the
50
- commit to House; in the container, run it through the install command from the
51
- copy's directory. Inside an Agent conversation the Agent runs `house push`.
47
+ `kit resident` keeps the Environment connected and, as it connects, copies each
48
+ Room you may sync here as a Git repository in the workspace's `local-copies`.
49
+ `house fetch` records House's changes on each copy's `refs/house/received`;
50
+ rebase onto it, commit and run `house push --owner` in the copy, through the
51
+ install command in the container. An Agent runs both, without `--owner`.
52
52
 
53
53
  House Kit turns each audio file of your message to an Agent into text on this
54
54
  computer before the Agent reads it. While transcription is on, the speech
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "version": "0.2.1-cbabe8ad337ff",
3
+ "version": "0.2.1-cc988e43abeeb",
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-cbabe8ad337ff/connect-linux.sh"
8
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cc988e43abeeb/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-cbabe8ad337ff/connect-linux.sh"
14
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cc988e43abeeb/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-cbabe8ad337ff/connect-windows.ps1"
20
+ "url": "https://github.com/agentshouse/kit/releases/download/v0.2.1-cc988e43abeeb/connect-windows.ps1"
21
21
  }
22
22
  }
23
23
  }
package/dist/bridge.js CHANGED
@@ -97,7 +97,7 @@ export async function openBridge(house, copies, conversationId, signal) {
97
97
  const after = resendAfter(forwarded, attempt);
98
98
  if (after === null)
99
99
  return forwarded;
100
- // A write House did not settle is sent again on the jittered curve, or after the wait House names for a pending one.
100
+ // A Tool call House did not settle is sent again on the jittered curve, or after the wait House names for a pending one.
101
101
  await delay(after, undefined, { signal: closed.signal });
102
102
  }
103
103
  };
@@ -135,23 +135,9 @@ export async function openBridge(house, copies, conversationId, signal) {
135
135
  const held = JSON.parse(text).transfer;
136
136
  return { url: held.url, operation: held.operation, bytes: bytes.length, sha256 };
137
137
  };
138
- let mutations = null;
139
- const writes = async (tool) => {
140
- mutations ??= house
141
- .post('/kit/tools/mutations', {}, closed.signal)
142
- .then(({ tools }) => new Set(tools.filter((listed) => listed.writes).map((listed) => listed.name)));
143
- try {
144
- return (await mutations).has(tool);
145
- }
146
- catch (error) {
147
- mutations = null;
148
- throw error;
149
- }
150
- };
151
- const forward = async (text) => {
138
+ const forward = (text) => {
152
139
  const message = JSON.parse(text);
153
- const tool = message.method === 'tools/call' ? String(message.params.name) : null;
154
- return send(message, tool !== null && (await writes(tool)) ? operationId() : null);
140
+ return send(message, message.method === 'tools/call' ? operationId() : null);
155
141
  };
156
142
  const caller = {
157
143
  key: `conversation:${conversationId}`,
@@ -173,6 +159,8 @@ export async function openBridge(house, copies, conversationId, signal) {
173
159
  const { cwd, commit } = JSON.parse(text);
174
160
  return { status: 200, text: JSON.stringify(await copies.push(cwd, commit, caller)) };
175
161
  }
162
+ if (path === '/git/fetch')
163
+ return { status: 200, text: JSON.stringify(await copies.fetch()) };
176
164
  if (path === '/git/observed') {
177
165
  await copies.observed(JSON.parse(text));
178
166
  return { status: 200, text: '{}' };
@@ -197,7 +185,8 @@ export async function openBridge(house, copies, conversationId, signal) {
197
185
  response.writeHead(error.status, { 'content-type': 'application/json' }).end(error.text);
198
186
  return;
199
187
  }
200
- response.writeHead(502).end(request.url === '/git/push' && error instanceof Error ? error.message : UNREACHABLE);
188
+ const verb = request.url === '/git/push' || request.url === '/git/fetch';
189
+ response.writeHead(502).end(verb && error instanceof Error ? error.message : UNREACHABLE);
201
190
  }
202
191
  });
203
192
  bridge.listen(socketPath);
package/dist/copies.js CHANGED
@@ -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
  }
@@ -152,8 +168,7 @@ export class LocalCopies {
152
168
  house;
153
169
  copies = new Map();
154
170
  queues = new Map();
155
- delivering = new Set();
156
- selecting = Promise.resolve();
171
+ answering = Promise.resolve();
157
172
  constructor(house) {
158
173
  this.house = house;
159
174
  this.owner = {
@@ -185,42 +200,68 @@ export class LocalCopies {
185
200
  }
186
201
  }
187
202
  async mapping() {
188
- await this.selecting;
203
+ await this.answering;
189
204
  return [...this.copies.values()]
190
205
  .filter((copy) => copy.active)
191
206
  .map((copy) => `${rootOf(copy.room_handle)}: ${copy.repository}`)
192
207
  .sort();
193
208
  }
194
- select() {
195
- const selected = this.selecting.then(() => this.reselect());
196
- this.selecting = selected.catch(() => undefined);
197
- return selected;
198
- }
199
- async reselect() {
200
- const { local_copy: chosen } = await this.house.post('/kit/local-copy/selection', {});
201
- const selected = (chosen?.rooms ?? []).flatMap((room) => room.room_handle === null ? [] : [{ key: `rooms/${room.room_ref}`, handle: room.room_handle }]);
202
- const keys = new Set(selected.map((scope) => scope.key));
203
- const work = [];
204
- for (const key of this.copies.keys()) {
205
- if (keys.has(key))
206
- continue;
207
- work.push(this.exclusive(key, async () => {
208
- const copy = this.copies.get(key);
209
- if (copy.active)
210
- await this.save({ ...copy, active: false });
211
- }));
212
- }
213
- for (const scope of selected)
214
- work.push(this.exclusive(scope.key, () => this.apply(scope)).catch(logged));
215
- await Promise.all(work);
209
+ async connected() {
210
+ const copied = await this.answered(() => this.fetched(false));
211
+ if (copied.refused)
212
+ logged(copied.text);
216
213
  }
217
- entries(frame) {
218
- const copy = [...this.copies.values()].find((held) => held.active && held.room_ref === frame.authority);
219
- if (copy === undefined)
220
- return;
221
- if (copy.log_epoch === frame.log_epoch && BigInt(frame.position) <= BigInt(copy.position))
222
- return;
223
- this.deliver(copy.key);
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
+ });
224
265
  }
225
266
  async observed(report) {
226
267
  const key = await this.keyAt(dirname(report.common));
@@ -270,16 +311,9 @@ export class LocalCopies {
270
311
  this.queues.set(key, queued.catch(() => undefined));
271
312
  return queued;
272
313
  }
273
- deliver(key) {
274
- if (this.delivering.has(key))
275
- return;
276
- this.delivering.add(key);
277
- void this.exclusive(key, async () => {
278
- this.delivering.delete(key);
279
- const copy = this.copies.get(key);
280
- if (copy.active)
281
- await this.save(await this.caughtUp(copy));
282
- }).catch(logged);
314
+ holding(keys, work) {
315
+ const [key, ...rest] = keys;
316
+ return key === undefined ? work() : this.exclusive(key, () => this.holding(rest, work));
283
317
  }
284
318
  async save(copy) {
285
319
  const path = join(kitHome(), 'local-copies', `${copy.key}.json`);
@@ -325,46 +359,13 @@ export class LocalCopies {
325
359
  }
326
360
  return read;
327
361
  }
328
- async apply(scope) {
329
- let copy = this.copies.get(scope.key);
330
- if (copy === undefined || !(await exists(copy.repository))) {
331
- await this.materialize(scope);
332
- return;
333
- }
334
- if (copy.room_handle !== scope.handle)
335
- copy = await this.save({ ...copy, room_handle: scope.handle });
336
- if (!copy.active) {
337
- await this.save(await this.received({ ...copy, active: true }));
338
- return;
339
- }
340
- const discovery = await this.house.post('/kit/door/discover', {
341
- prefixes: [rootOf(copy.room_handle)],
342
- });
343
- const authority = discovery.authorities.find((entry) => entry.room_ref === copy.room_ref);
344
- if (authority === undefined)
345
- return;
346
- if (authority.managed_replication !== 'admitted') {
347
- logged(`operation_denied: ${rootOf(copy.room_handle)} is not synchronized to this Environment`);
348
- return;
349
- }
350
- if (JSON.stringify([authority.operations.write, authority.protected_paths]) !==
351
- JSON.stringify([copy.write, copy.protected])) {
352
- await this.save(await this.received(copy));
353
- return;
354
- }
355
- await this.save(await this.caughtUp(copy));
356
- }
357
- async materialize(scope) {
358
- const read = await this.read(scope.handle);
359
- if (read === null) {
360
- logged(`House serves nothing of ${rootOf(scope.handle)} to copy`);
361
- return;
362
- }
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');
363
366
  const repository = join(localCopies(), 'rooms', read.anchor);
364
- if (await exists(repository)) {
365
- logged(`${repository} already exists and House Kit leaves it as it is`);
366
- return;
367
- }
367
+ if (await exists(repository))
368
+ throw new Error(`${repository} already exists and House Kit leaves it as it is`);
368
369
  const staging = join(dirname(repository), `.${randomUUID()}`);
369
370
  await mkdir(staging, { recursive: true });
370
371
  let house;
@@ -372,7 +373,7 @@ export class LocalCopies {
372
373
  try {
373
374
  await git(staging, ['init', '-q', '-b', BRANCH]);
374
375
  house = await importCommits(staging, [
375
- { message: `House ${rootOf(scope.handle)}`, from: null, files: read.writable },
376
+ { message: `House ${rootOf(handle)}`, from: null, files: read.writable },
376
377
  ]);
377
378
  await git(staging, ['update-ref', `refs/heads/${BRANCH}`, house]);
378
379
  await git(staging, ['reset', '-q', '--hard']);
@@ -385,9 +386,9 @@ export class LocalCopies {
385
386
  throw error;
386
387
  }
387
388
  await this.save({
388
- key: scope.key,
389
+ key,
389
390
  room_ref: read.anchor,
390
- room_handle: scope.handle,
391
+ room_handle: handle,
391
392
  repository,
392
393
  active: true,
393
394
  house,
@@ -399,6 +400,7 @@ export class LocalCopies {
399
400
  manifests: { [house]: { parent: null, files: read.revisions } },
400
401
  moves: [],
401
402
  });
403
+ return `${rootOf(handle)}: copied to ${repository}`;
402
404
  }
403
405
  async received(copy) {
404
406
  const read = await this.read(copy.room_handle);
@@ -422,29 +424,52 @@ export class LocalCopies {
422
424
  await ignoreRules(copy.repository, [...read.writable.keys()], next);
423
425
  return next;
424
426
  }
425
- async caughtUp(start) {
426
- let copy = start;
427
- for (;;) {
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) {
428
446
  let answer;
429
447
  try {
430
448
  answer = await this.house.post('/kit/door/enumerate', {
431
- prefixes: [rootOf(copy.room_handle)],
432
- positions: [{ authority: copy.room_ref, position: copy.position, log_epoch: copy.log_epoch }],
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 })),
433
451
  });
434
452
  }
435
453
  catch (error) {
436
- const code = error instanceof HouseRefusal ? (refusalOf(error.text)?.code ?? null) : null;
437
- if (code === 'position_expired')
438
- return this.received(copy);
439
- if (code !== 'replica_behind')
454
+ const expired = asking.find((copy) => copy.room_ref === expiredAuthority(error));
455
+ if (expired === undefined)
440
456
  throw error;
441
- return copy;
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);
442
469
  }
443
- const view = answer.authorities.find((entry) => entry.authority === copy.room_ref);
444
- if (view === undefined || (view.position === copy.position && view.log_epoch === copy.log_epoch))
445
- return copy;
446
- copy = await this.save(await this.incorporated(copy, view.changes, view.position, view.log_epoch));
470
+ asking = whole ? advanced : [];
447
471
  }
472
+ return copies.map((copy) => caught.get(copy.key));
448
473
  }
449
474
  async incorporated(copy, changes, position, logEpoch) {
450
475
  const houseTree = await tree(copy.repository, copy.house);
@@ -598,12 +623,12 @@ export class LocalCopies {
598
623
  const { upload, ...unstaged } = copy.push;
599
624
  return this.settle(await this.save({ ...copy, push: unstaged }), caller, true);
600
625
  }
601
- if (outcome.refused.code === 'operation_expired')
626
+ if (outcome.refused.code === 'expired')
602
627
  return this.recovered(copy);
603
628
  const rebased = rebaseFixes(outcome.refused);
604
629
  let settled = await this.save(without(copy));
605
630
  try {
606
- settled = await this.save(await this.caughtUp(settled));
631
+ settled = (await this.caughtUp([settled], true))[0];
607
632
  }
608
633
  catch {
609
634
  return {
@@ -622,7 +647,7 @@ export class LocalCopies {
622
647
  }
623
648
  async recovered(copy) {
624
649
  const push = copy.push;
625
- const current = await this.save(await this.caughtUp(copy));
650
+ const current = (await this.caughtUp([copy], true))[0];
626
651
  const house = await tree(copy.repository, current.house);
627
652
  const root = rootOf(current.room_handle);
628
653
  if (!(await this.landed(copy.repository, push.changes, house, await tree(copy.repository, push.commit)))) {
@@ -666,7 +691,7 @@ export class LocalCopies {
666
691
  const push = copy.push;
667
692
  let written = push.written;
668
693
  if (push.changes.some((change) => change.op === 'rename')) {
669
- copy = await this.save(await this.caughtUp(copy));
694
+ copy = (await this.caughtUp([copy], true))[0];
670
695
  const house = await tree(copy.repository, copy.house);
671
696
  const sent = await tree(copy.repository, push.house);
672
697
  if (push.changes.some((change) => change.op === 'rename' && !house.has(relative(change.to)))) {
@@ -3,6 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  import { readFile } from 'node:fs/promises';
4
4
  import { request, setGlobalProxyFromEnv } from 'node:http';
5
5
  import { basename, join } from 'node:path';
6
+ import { HOUSE_REF } from './git.js';
6
7
  import { kitHome, readOwnAgent } from './home.js';
7
8
  import { callHouse, rpc, UNREACHABLE } from './mcp.js';
8
9
  import { refusalOf } from './refusals.js';
@@ -11,6 +12,8 @@ import { parse } from 'yaml';
11
12
  const USAGE = "usage: house <tool> ['<arguments as JSON>']";
12
13
  const PUSH_USAGE = 'usage: house push [commit] [--owner]';
13
14
  const PUSH = "push [commit]: sends the Local copy's committed changes to House";
15
+ const FETCH_USAGE = 'usage: house fetch';
16
+ const FETCH = `fetch: records House's changes on each Local copy's ${HOUSE_REF}`;
14
17
  const ARGUMENTS = `the arguments are one JSON object in single quotes, like house search '{"query":"invoice"}'`;
15
18
  const CLOSED = "this conversation's House connection is closed; nothing to do from here";
16
19
  const SANDBOXED = "your CLI's sandbox kept house from House; run house directly, not through another program";
@@ -125,6 +128,14 @@ async function push(args) {
125
128
  throw new Error(pushed.text);
126
129
  return pushed.text;
127
130
  }
131
+ async function fetched(args) {
132
+ if (args.includes('--help'))
133
+ return FETCH_USAGE;
134
+ const answer = JSON.parse(await bridged('/git/fetch', {}, undefined, socketPath ?? join(kitHome(), 'owner.sock')));
135
+ if (answer.refused)
136
+ throw new Error(answer.text);
137
+ return answer.text;
138
+ }
128
139
  function argumentsOf(argument) {
129
140
  if (argument === undefined)
130
141
  return {};
@@ -141,7 +152,7 @@ function argumentsOf(argument) {
141
152
  }
142
153
  async function house([verb, argument]) {
143
154
  if (verb === undefined || verb === '--help' || verb === 'help') {
144
- return [USAGE, 'help', PUSH, ...(await tools()).map((tool) => (tool.description === undefined ? tool.name : `${tool.name}: ${tool.description}`))].join('\n');
155
+ return [USAGE, 'help', PUSH, FETCH, ...(await tools()).map((tool) => (tool.description === undefined ? tool.name : `${tool.name}: ${tool.description}`))].join('\n');
145
156
  }
146
157
  if (argument === '--help') {
147
158
  const tool = (await tools()).find((listed) => listed.name === verb);
@@ -170,7 +181,7 @@ async function called(name, args) {
170
181
  return text;
171
182
  }
172
183
  const argv = process.argv.slice(2);
173
- (argv[0] === 'push' ? push(argv.slice(1)) : house(argv)).then((text) => {
184
+ (argv[0] === 'push' ? push(argv.slice(1)) : argv[0] === 'fetch' ? fetched(argv.slice(1)) : house(argv)).then((text) => {
174
185
  process.stdout.write(`${text}\n`);
175
186
  if (argv[0] === 'shell')
176
187
  process.exitCode = Number(/^exit: (\d+)(?:\n|$)/.exec(text)?.[1] ?? 0);
@@ -1,8 +1,9 @@
1
+ import { HOUSE_REF } from './git.js';
1
2
  import { HOW_WE_WORK } from './skills.js';
2
3
  const HOUSE_LINE = 'Work with House through the `house` CLI: run `house --help`.';
3
4
  const FILE_LINE = 'To give the User a file or a page, upload it with `house upload` and link it; never start a server.';
4
5
  const READ_LINE = 'Before working in a Room, read `/rooms/private/rooms/<handle>/AGENTS.md`.';
5
- const COPIES_LINE = 'House Local copies; commit, then `house push`:';
6
+ const COPIES_LINE = `House Local copies; before work run \`house fetch\` and rebase onto \`${HOUSE_REF}\`; after it commit, then \`house push\`:`;
6
7
  const UNREADABLE = /^(?:\S+: )?(?:path_not_found|room_not_found|operation_denied)\b/;
7
8
  const FAILED = /^exit: [1-9]\d*$/;
8
9
  const CUT = /^stderr: shell: output_cut (\d+) of \d+ bytes; continue with: (.+)$/;
package/dist/resident.js CHANGED
@@ -33,13 +33,20 @@ async function serveOwner(copies) {
33
33
  await rm(socketPath, { force: true });
34
34
  const server = createServer(async (request, response) => {
35
35
  try {
36
- if (request.url !== '/git/push') {
36
+ const text = await received(request);
37
+ let answered;
38
+ if (request.url === '/git/fetch') {
39
+ answered = await copies.fetch();
40
+ }
41
+ else if (request.url === '/git/push') {
42
+ const { cwd, commit } = JSON.parse(text);
43
+ answered = await copies.push(cwd, commit, copies.owner);
44
+ }
45
+ else {
37
46
  response.writeHead(404).end();
38
47
  return;
39
48
  }
40
- const { cwd, commit } = JSON.parse(await received(request));
41
- const pushed = await copies.push(cwd, commit, copies.owner);
42
- response.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(pushed));
49
+ response.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(answered));
43
50
  }
44
51
  catch (error) {
45
52
  response.writeHead(502).end(error instanceof Error ? error.message : String(error));
@@ -115,18 +122,13 @@ export async function resident() {
115
122
  opened: () => {
116
123
  conversations.opened();
117
124
  changed();
118
- logged(copies.select());
125
+ logged(copies.connected());
119
126
  },
120
127
  frame: (arrived) => {
121
128
  if (arrived.type === 'watching')
122
129
  conversations.watching(arrived.watching === true);
123
130
  if (arrived.type === 'work_available' && arrived.subject === 'agents')
124
131
  logged(agents.refresh());
125
- if (arrived.type === 'work_available' && arrived.subject === 'local_copy')
126
- logged(copies.select());
127
- if (arrived.type === 'entries') {
128
- copies.entries(arrived);
129
- }
130
132
  if (arrived.type === 'input') {
131
133
  reported = false;
132
134
  if (arrived.kind === 'sign_in')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/kit",
3
- "version": "0.2.1-cbabe8ad337ff",
3
+ "version": "0.2.1-cc988e43abeeb",
4
4
  "description": "House Kit connects an Environment to agents.house.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@agentclientprotocol/sdk": "1.7.0",
30
- "@agentshouse/mdmodel": "0.1.0-alpha.19",
30
+ "@agentshouse/mdmodel": "0.1.0-c68e2039f1ca8",
31
31
  "yaml": "2.9.1"
32
32
  },
33
33
  "peerDependencies": {