@agentshouse/mdruntime-adapter 0.1.0-cfd03209dcd82 → 0.1.0-cfd2dc1938a2c

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.
Files changed (78) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +6 -46
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +23 -342
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +250 -278
  8. package/dist/app-reference.d.ts +2 -0
  9. package/dist/app-reference.d.ts.map +1 -0
  10. package/dist/app-reference.js +2 -0
  11. package/dist/authored-path.d.ts +11 -0
  12. package/dist/authored-path.d.ts.map +1 -0
  13. package/dist/authored-path.js +35 -0
  14. package/dist/chunks.d.ts +38 -0
  15. package/dist/chunks.d.ts.map +1 -0
  16. package/dist/chunks.js +247 -0
  17. package/dist/crockford.d.ts +4 -0
  18. package/dist/crockford.d.ts.map +1 -0
  19. package/dist/crockford.js +3 -0
  20. package/dist/discovery.d.ts +23 -14
  21. package/dist/discovery.d.ts.map +1 -1
  22. package/dist/discovery.js +92 -54
  23. package/dist/history.d.ts +12 -0
  24. package/dist/history.d.ts.map +1 -0
  25. package/dist/history.js +92 -0
  26. package/dist/house-model.d.ts +682 -0
  27. package/dist/house-model.d.ts.map +1 -0
  28. package/dist/house-model.js +397 -0
  29. package/dist/index.d.ts +12 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +11 -1
  32. package/dist/model.d.ts +5 -5
  33. package/dist/model.d.ts.map +1 -1
  34. package/dist/model.js +33 -43
  35. package/dist/read.d.ts +59 -44
  36. package/dist/read.d.ts.map +1 -1
  37. package/dist/read.js +158 -236
  38. package/dist/refusal.d.ts +1 -3
  39. package/dist/refusal.d.ts.map +1 -1
  40. package/dist/refusal.js +6 -6
  41. package/dist/room-types.d.ts +5 -0
  42. package/dist/room-types.d.ts.map +1 -0
  43. package/dist/room-types.js +120 -0
  44. package/dist/search.d.ts +5 -0
  45. package/dist/search.d.ts.map +1 -0
  46. package/dist/search.js +47 -0
  47. package/dist/site.d.ts +1 -1
  48. package/dist/site.d.ts.map +1 -1
  49. package/dist/site.js +110 -131
  50. package/dist/space-schema.d.ts +7 -0
  51. package/dist/space-schema.d.ts.map +1 -0
  52. package/dist/space-schema.js +18 -0
  53. package/dist/stream.d.ts +15 -13
  54. package/dist/stream.d.ts.map +1 -1
  55. package/dist/stream.js +279 -159
  56. package/dist/transport.d.ts +81 -25
  57. package/dist/transport.d.ts.map +1 -1
  58. package/dist/transport.js +54 -11
  59. package/dist/upload.d.ts +12 -0
  60. package/dist/upload.d.ts.map +1 -0
  61. package/dist/upload.js +63 -0
  62. package/dist/version.d.ts +1 -0
  63. package/dist/version.d.ts.map +1 -1
  64. package/dist/version.js +1 -1
  65. package/dist/write.d.ts +18 -2
  66. package/dist/write.d.ts.map +1 -1
  67. package/dist/write.js +108 -76
  68. package/package.json +8 -4
  69. package/AGENTS.md +0 -299
  70. package/dist/gather.d.ts +0 -4
  71. package/dist/gather.d.ts.map +0 -1
  72. package/dist/gather.js +0 -45
  73. package/dist/handed.d.ts +0 -15
  74. package/dist/handed.d.ts.map +0 -1
  75. package/dist/handed.js +0 -38
  76. package/dist/referrer.d.ts +0 -7
  77. package/dist/referrer.d.ts.map +0 -1
  78. package/dist/referrer.js +0 -35
package/dist/stream.js CHANGED
@@ -1,47 +1,129 @@
1
- import { acceptedMessage } from './actions.js';
2
- import { binaryFileOf, headChange } from './read.js';
3
- import { roomVersion } from './version.js';
4
- const HELD_FRAMES_MAX = 256;
1
+ import { ROW_WEIGHT, stepped, } from '@agentshouse/mdruntime';
2
+ import { acceptedMessage, cursorPosition, houseHistory } from './history.js';
3
+ import { keptSpaceSchemas, streamedModels } from './model.js';
4
+ import { answered, answering, binaryFileOf, createdOf, folded, forgotten, headChange, revised, } from './read.js';
5
+ import { classifyDoor } from './refusal.js';
6
+ import { houseDoorRoute, } from './transport.js';
7
+ import { DECIMAL, logPosition, presented, roomVersion } from './version.js';
5
8
  function turnOperation(frame) {
6
9
  const { type: _type, conversation_id: _conversation, turn_id: _turn, ...operation } = frame;
7
10
  return structuredClone(operation);
8
11
  }
12
+ async function houseAgents(transport) {
13
+ const answer = await transport.door(houseDoorRoute('agents/list'), {});
14
+ if (classifyDoor(answer.status, answer.body, 'agents/list')?.kind === 'transport-uncertainty') {
15
+ throw new Error('agents/list reached no answer');
16
+ }
17
+ const agents = answer.status === 200 ? answer.body?.agents : null;
18
+ if (!Array.isArray(agents))
19
+ return null;
20
+ return agents.flatMap((one) => {
21
+ const { id, name, retired_at: retired } = (one ?? {});
22
+ return typeof id === 'string' && typeof name === 'string'
23
+ ? [{ agent: id, name, retired: retired !== null && retired !== undefined }]
24
+ : [];
25
+ });
26
+ }
9
27
  function listedConversation(listed) {
10
28
  return {
11
29
  conversation: listed.conversation_id,
12
30
  agent: listed.agent_id,
31
+ agentName: listed.agent_name,
32
+ agentRetired: listed.agent_retired,
13
33
  name: listed.name,
14
34
  created: listed.created_at,
15
35
  finished: listed.finished_at,
16
36
  outcome: listed.outcome,
37
+ waiting: listed.waiting,
38
+ newest: listed.newest === null ? null : cursorPosition(listed.newest),
39
+ processEnded: listed.process_ended_at,
17
40
  };
18
41
  }
19
42
  function position(value) {
20
- if (!/^(?:0|[1-9][0-9]*)$/.test(value))
43
+ if (!DECIMAL.test(value))
21
44
  return null;
22
45
  return BigInt(value);
23
46
  }
24
- export function houseNotifications(transport, mode) {
47
+ function* changed(tracked, entries, version, schemas) {
48
+ const answer = answering();
49
+ for (const entry of entries) {
50
+ yield ROW_WEIGHT + (entry.text?.length ?? 0);
51
+ if (entry.kind === 'folder') {
52
+ folded(answer, entry.path, entry.removed === true);
53
+ continue;
54
+ }
55
+ if (entry.path === tracked.schema)
56
+ schemas.set(entry.path, entry);
57
+ forgotten(answer, entry.path);
58
+ if (entry.space !== undefined) {
59
+ answer.removals.add(entry.path);
60
+ continue;
61
+ }
62
+ if (entry.kind === 'removed') {
63
+ answer.removals.add(entry.path);
64
+ continue;
65
+ }
66
+ const binary = binaryFileOf(entry);
67
+ if (binary === undefined)
68
+ answer.documents.set(entry.path, entry.text ?? '');
69
+ else if (binary !== null)
70
+ answer.binaryFiles.set(entry.path, binary);
71
+ if (binary === undefined && entry.facts !== undefined)
72
+ answer.facts.set(entry.path, entry.facts);
73
+ const revision = entry.revision ?? binary?.sha256;
74
+ if (revision !== undefined)
75
+ revised(answer, entry.path, revision);
76
+ const head = headChange(entry);
77
+ if (head)
78
+ answer.changes.set(entry.path, head);
79
+ const created = createdOf(entry);
80
+ if (created)
81
+ answer.created.set(entry.path, created);
82
+ }
83
+ return { kind: 'net-advancement', roomVersion: version, ...(yield* answered(answer)) };
84
+ }
85
+ async function changePage(tracked, entries, version, mode, spaces, whole) {
86
+ const schemas = new Map();
87
+ const page = await stepped(changed(tracked, entries, version, schemas));
88
+ const models = await streamedModels(schemas, tracked, mode, spaces, whole);
89
+ return models === undefined ? page : { ...page, models };
90
+ }
91
+ export function houseNotifications(transport, mode, discovering, spaces) {
25
92
  const stream = transport.stream;
26
- const lines = new Map();
27
- const locators = new Map();
93
+ const staged = new Map();
94
+ let socket = null;
95
+ const tracking = new Map();
28
96
  const observers = new Set();
97
+ const replaying = new Map();
29
98
  const conversationObservers = new Set();
30
99
  const modeObservers = new Set();
31
100
  let replicated = [];
101
+ let listedCursor = null;
102
+ const unanswered = [];
103
+ const heldAtZero = new Set();
32
104
  const live = new Set();
33
105
  let opening = null;
106
+ let announced = null;
34
107
  const runtime = crypto.randomUUID();
35
108
  function emit(event) {
36
- for (const observer of observers)
37
- observer(event);
109
+ for (const observer of observers) {
110
+ const held = replaying.get(observer);
111
+ if (held === undefined)
112
+ observer(event);
113
+ else
114
+ held.push(event);
115
+ }
38
116
  }
39
117
  function emitConversation(event) {
40
118
  if (event.kind === 'turn' ||
41
119
  event.kind === 'questions' ||
42
120
  event.kind === 'process' ||
43
121
  event.kind === 'commands' ||
44
- event.kind === 'options') {
122
+ event.kind === 'options' ||
123
+ event.kind === 'starting' ||
124
+ event.kind === 'subagents' ||
125
+ event.kind === 'link' ||
126
+ event.kind === 'deliveries') {
45
127
  live.add(event.conversation);
46
128
  }
47
129
  for (const observer of conversationObservers)
@@ -49,11 +131,33 @@ export function houseNotifications(transport, mode) {
49
131
  }
50
132
  function reopened(next) {
51
133
  opening = next;
134
+ announced = null;
135
+ socket = next;
136
+ staged.clear();
137
+ unanswered.length = 0;
138
+ heldAtZero.clear();
52
139
  const gapped = new Set([...replicated, ...live]);
53
140
  live.clear();
54
141
  for (const conversation of gapped)
55
142
  emitConversation({ kind: 'gap', conversation });
56
143
  emit({ kind: 'opened' });
144
+ if (mode === 'site')
145
+ announce(next, null);
146
+ }
147
+ function announce(via, frame) {
148
+ void discovering.opened(frame).then((discovery) => {
149
+ if (socket !== via)
150
+ return;
151
+ if (discovery === null) {
152
+ via.close();
153
+ return;
154
+ }
155
+ announced = { kind: 'discovered', discovery };
156
+ emit(announced);
157
+ }, () => {
158
+ if (socket === via)
159
+ via.close();
160
+ });
57
161
  }
58
162
  function converse(frame) {
59
163
  const conversation = frame.conversation_id;
@@ -72,6 +176,7 @@ export function houseNotifications(transport, mode) {
72
176
  return;
73
177
  emitConversation({ kind: 'commands', conversation, commands: [] });
74
178
  emitConversation({ kind: 'options', conversation, options: [] });
179
+ emitConversation({ kind: 'subagents', conversation, subagents: [] });
75
180
  return;
76
181
  }
77
182
  if (frame.type === 'commands') {
@@ -86,6 +191,26 @@ export function houseNotifications(transport, mode) {
86
191
  emitConversation({ kind: 'options', conversation, options: structuredClone(frame.options) });
87
192
  return;
88
193
  }
194
+ if (frame.type === 'starting') {
195
+ emitConversation({ kind: 'starting', conversation, step: frame.step });
196
+ return;
197
+ }
198
+ if (frame.type === 'subagents') {
199
+ emitConversation({
200
+ kind: 'subagents',
201
+ conversation,
202
+ subagents: structuredClone(frame.subagents),
203
+ });
204
+ return;
205
+ }
206
+ if (frame.type === 'link') {
207
+ emitConversation({ kind: 'link', conversation, connected: frame.connected });
208
+ return;
209
+ }
210
+ if (frame.type === 'deliveries') {
211
+ emitConversation({ kind: 'deliveries', conversation, unknown: [...frame.unknown] });
212
+ return;
213
+ }
89
214
  if (frame.type === 'interactions') {
90
215
  emitConversation({
91
216
  kind: 'questions',
@@ -99,18 +224,33 @@ export function houseNotifications(transport, mode) {
99
224
  return;
100
225
  emitConversation({ kind: 'accepted-message', conversation, message });
101
226
  }
102
- function announce(authority, at) {
103
- const version = roomVersion(at);
104
- for (const locator of locators.get(authority) ?? []) {
105
- emit({ kind: 'room-version', locator, roomVersion: version });
227
+ function stage(frame, via) {
228
+ const held = staged.get(frame.carry);
229
+ if (frame.index !== (held?.parts ?? 0)) {
230
+ staged.delete(frame.carry);
231
+ return;
232
+ }
233
+ if (held === undefined) {
234
+ for (const [carry, other] of staged) {
235
+ if (other.authority === frame.authority)
236
+ staged.delete(carry);
237
+ }
106
238
  }
239
+ const next = held ?? { authority: frame.authority, parts: 0, entries: [] };
240
+ keptSpaceSchemas(frame.entries, spaces);
241
+ next.entries.push(...frame.entries);
242
+ next.parts += 1;
243
+ staged.set(frame.carry, next);
244
+ via?.received(frame.authority, frame.carry, frame.index);
107
245
  }
108
- function interrupt(authority) {
109
- const line = lines.get(authority);
110
- if (line !== undefined)
111
- lines.set(authority, { ...line, frames: [] });
246
+ function carried(frame) {
247
+ const held = staged.get(frame.carry);
248
+ staged.delete(frame.carry);
249
+ if ((held?.parts ?? 0) !== frame.parts)
250
+ return;
251
+ publish(frame, held?.entries ?? []);
112
252
  }
113
- function receive(frame) {
253
+ function handle(frame, via) {
114
254
  if (frame.type === 'signal') {
115
255
  const mode = frame.service_mode;
116
256
  if (mode !== 'open' && mode !== 'write-halted')
@@ -120,14 +260,35 @@ export function houseNotifications(transport, mode) {
120
260
  return;
121
261
  }
122
262
  if (frame.type === 'opening') {
263
+ if (via !== null && mode === 'credential')
264
+ announce(via, frame);
265
+ return;
266
+ }
267
+ if (frame.type === 'caught_up') {
268
+ discovering.expired?.(frame.expired);
123
269
  emit({
124
- kind: 'opening',
125
- expired: frame.expired.flatMap((authority) => locators.get(authority) ?? []),
270
+ kind: 'caught-up',
271
+ expired: [
272
+ ...frame.expired.flatMap((authority) => (tracking.get(authority) ?? []).map((tracked) => tracked.locator)),
273
+ ...(unanswered.shift() ?? []),
274
+ ],
126
275
  });
127
276
  return;
128
277
  }
278
+ if (frame.type === 'authority_changed') {
279
+ const change = discovering.changed(frame);
280
+ if (change !== null)
281
+ emit(change);
282
+ return;
283
+ }
129
284
  if (frame.type === 'conversations') {
130
- emitConversation({ kind: 'list', entries: frame.conversations.map(listedConversation) });
285
+ emitConversation({
286
+ kind: 'list',
287
+ entries: frame.conversations.map(listedConversation),
288
+ whole: frame.whole,
289
+ more: frame.more,
290
+ cursor: frame.cursor,
291
+ });
131
292
  return;
132
293
  }
133
294
  if (frame.type === 'conversation') {
@@ -142,40 +303,49 @@ export function houseNotifications(transport, mode) {
142
303
  frame.type === 'process' ||
143
304
  frame.type === 'commands' ||
144
305
  frame.type === 'options' ||
306
+ frame.type === 'starting' ||
307
+ frame.type === 'subagents' ||
308
+ frame.type === 'link' ||
309
+ frame.type === 'deliveries' ||
145
310
  frame.type === 'interactions' ||
146
311
  frame.type === 'message') {
147
312
  converse(frame);
148
313
  return;
149
314
  }
150
- if (frame.type !== 'entries')
151
- return;
315
+ if (frame.type === 'part')
316
+ stage(frame, via);
317
+ else if (frame.type === 'carried')
318
+ carried(frame);
319
+ }
320
+ function publish(frame, entries) {
152
321
  const at = position(frame.position);
153
322
  const after = position(frame.after);
154
- if (at === null || after === null || after >= at) {
155
- interrupt(frame.authority);
323
+ if (at === null || after === null || after >= at)
156
324
  return;
325
+ const from = after === 0n && !heldAtZero.has(frame.authority)
326
+ ? null
327
+ : roomVersion({ position: frame.after, logEpoch: frame.log_epoch });
328
+ const version = roomVersion({ position: frame.position, logEpoch: frame.log_epoch });
329
+ for (const tracked of tracking.get(frame.authority) ?? []) {
330
+ emit({
331
+ kind: 'room-change',
332
+ locator: tracked.locator,
333
+ from,
334
+ roomVersion: version,
335
+ read: () => changePage(tracked, entries, version, mode, spaces, from === null),
336
+ });
157
337
  }
158
- const line = lines.get(frame.authority);
159
- if (line?.logEpoch === frame.log_epoch) {
160
- if (line.held !== null && at <= line.held)
161
- return;
162
- const last = line.frames.at(-1);
163
- if (last !== undefined && at <= last.position)
164
- return;
165
- const held = { after, position: at, entries: frame.entries };
166
- const next = last !== undefined && after <= last.position ? [...line.frames, held] : [held];
167
- lines.set(frame.authority, { ...line, frames: next.length > HELD_FRAMES_MAX ? [] : next });
168
- }
169
- else {
170
- interrupt(frame.authority);
171
- }
172
- announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch });
173
338
  }
174
- stream.observe(receive);
339
+ stream.observe((frame) => handle(frame, socket));
175
340
  stream.opened(reopened);
176
- stream.closed((revoked) => {
341
+ stream.closed(({ revoked, lost, authorityChanged }) => {
177
342
  opening = null;
178
- emit({ kind: 'closed', revoked });
343
+ announced = null;
344
+ socket = null;
345
+ staged.clear();
346
+ unanswered.length = 0;
347
+ heldAtZero.clear();
348
+ emit({ kind: 'closed', revoked, lost, authorityChanged });
179
349
  });
180
350
  return {
181
351
  runtime,
@@ -191,19 +361,34 @@ export function houseNotifications(transport, mode) {
191
361
  replicate(next) {
192
362
  replicated = [...next];
193
363
  },
364
+ hold(cursor) {
365
+ listedCursor = cursor;
366
+ },
194
367
  observe(notify) {
195
368
  conversationObservers.add(notify);
196
369
  return () => {
197
370
  conversationObservers.delete(notify);
198
371
  };
199
372
  },
373
+ ...(mode === 'credential'
374
+ ? {
375
+ agents: () => houseAgents(transport),
376
+ history: (request) => houseHistory(transport, request),
377
+ }
378
+ : {}),
200
379
  },
201
380
  observe(notify) {
202
381
  observers.add(notify);
203
382
  if (opening !== null) {
383
+ const replayed = [{ kind: 'opened' }];
384
+ if (announced !== null)
385
+ replayed.push(announced);
386
+ replaying.set(notify, replayed);
204
387
  queueMicrotask(() => {
205
- if (observers.has(notify))
206
- notify({ kind: 'opened' });
388
+ replaying.delete(notify);
389
+ for (const event of replayed)
390
+ if (observers.has(notify))
391
+ notify(event);
207
392
  });
208
393
  }
209
394
  return () => {
@@ -211,124 +396,59 @@ export function houseNotifications(transport, mode) {
211
396
  };
212
397
  },
213
398
  send(rooms) {
214
- for (const room of rooms) {
215
- const line = lines.get(room.authority);
216
- const held = position(room.position);
217
- if (line === undefined || held === null || line.logEpoch !== room.log_epoch)
218
- continue;
219
- lines.set(room.authority, { ...line, frames: [], held });
220
- }
221
- const current = opening;
222
- opening = null;
223
- current?.hold(rooms, runtime);
224
- },
225
- reopen() {
226
- const current = opening;
227
399
  opening = null;
228
- current?.close();
229
- },
230
- track(entries) {
231
- locators.clear();
232
- for (const entry of entries) {
233
- locators.set(entry.authority, [...(locators.get(entry.authority) ?? []), entry.locator]);
234
- if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {
235
- lines.set(entry.authority, { logEpoch: entry.logEpoch, frames: [], held: null });
236
- }
237
- }
238
- for (const authority of lines.keys()) {
239
- if (!locators.has(authority))
240
- lines.delete(authority);
241
- }
242
- },
243
- reach(authority, at) {
244
- const line = lines.get(authority);
245
- const held = position(at.position);
246
- if (line === undefined || held === null || line.logEpoch !== at.logEpoch)
400
+ announced = null;
401
+ if (socket === null)
247
402
  return;
248
- if (line.held !== null && held <= line.held)
403
+ const entries = new Map([...tracking.values()].flat().map((tracked) => [tracked.locator, tracked]));
404
+ const named = rooms.flatMap((room) => {
405
+ const entry = entries.get(room.locator);
406
+ const at = room.roomVersion === null ? null : logPosition(room.roomVersion);
407
+ return entry === undefined || at === null ? [] : [{ entry, at }];
408
+ });
409
+ const unheld = rooms.flatMap((room) => {
410
+ const entry = entries.get(room.locator);
411
+ return entry === undefined || room.roomVersion !== null ? [] : [entry];
412
+ });
413
+ for (const { entry, at } of named) {
414
+ if (at.position === '0')
415
+ heldAtZero.add(entry.authority);
416
+ else
417
+ heldAtZero.delete(entry.authority);
418
+ }
419
+ for (const entry of unheld)
420
+ heldAtZero.delete(entry.authority);
421
+ const site = mode === 'site';
422
+ unanswered.push(site ? unheld.map((entry) => entry.locator) : []);
423
+ socket.hold([
424
+ ...named.map(({ entry, at }) => presented(entry.authority, at)),
425
+ ...(site ? [] : unheld).map((entry) => presented(entry.authority, { position: '0', logEpoch: entry.logEpoch })),
426
+ ], runtime, listedCursor);
427
+ if (site)
249
428
  return;
250
- lines.set(authority, {
251
- ...line,
252
- frames: line.frames.filter((frame) => frame.position > held),
253
- held,
429
+ const made = unheld.filter((entry) => entry.position === '0');
430
+ queueMicrotask(() => {
431
+ for (const entry of made) {
432
+ const version = roomVersion(entry);
433
+ emit({
434
+ kind: 'room-change',
435
+ locator: entry.locator,
436
+ from: null,
437
+ roomVersion: version,
438
+ read: () => changePage(entry, [], version, mode, spaces, true),
439
+ });
440
+ }
254
441
  });
255
442
  },
256
- advance(tracked, from, holds) {
257
- const line = lines.get(tracked.authority);
258
- const start = position(from.position);
259
- if (line === undefined || start === null || line.logEpoch !== from.logEpoch)
260
- return null;
261
- const pending = line.frames.filter((frame) => frame.position > start);
262
- const first = pending[0];
263
- if (first === undefined || first.after > start)
264
- return null;
265
- const documents = {};
266
- const revisions = {};
267
- const changes = {};
268
- const binaryFiles = {};
269
- const removals = [];
270
- const applied = [];
271
- const schemas = new Map();
272
- const forget = (path) => {
273
- delete documents[path];
274
- delete revisions[path];
275
- delete changes[path];
276
- delete binaryFiles[path];
277
- const removed = removals.indexOf(path);
278
- if (removed !== -1)
279
- removals.splice(removed, 1);
280
- };
281
- for (const frame of pending) {
282
- for (const entry of frame.entries) {
283
- if (entry.kind === 'edited' &&
284
- entry.revision !== undefined &&
285
- holds?.(entry.path, entry.revision) === true) {
286
- forget(entry.path);
287
- continue;
288
- }
289
- applied.push(entry);
290
- if (tracked.schemas.includes(entry.path))
291
- schemas.set(entry.path, entry);
292
- if (entry.kind === 'removed') {
293
- forget(entry.path);
294
- removals.push(entry.path);
295
- continue;
296
- }
297
- const binary = binaryFileOf(entry);
298
- if (binary === null || (binary === undefined && entry.text === undefined))
299
- return null;
300
- if (mode === 'credential' && entry.revision === undefined)
301
- return null;
302
- const head = headChange(entry);
303
- if (head === null)
304
- return null;
305
- forget(entry.path);
306
- if (binary === undefined)
307
- documents[entry.path] = entry.text;
308
- else
309
- binaryFiles[entry.path] = binary;
310
- const revision = entry.revision ?? binary?.sha256;
311
- if (revision !== undefined)
312
- revisions[entry.path] = revision;
313
- if (head !== undefined)
314
- changes[entry.path] = head;
315
- }
443
+ track(entries) {
444
+ tracking.clear();
445
+ for (const entry of entries) {
446
+ tracking.set(entry.authority, [...(tracking.get(entry.authority) ?? []), entry]);
447
+ }
448
+ for (const [carry, held] of staged) {
449
+ if (!tracking.has(held.authority))
450
+ staged.delete(carry);
316
451
  }
317
- const last = pending.at(-1);
318
- lines.set(tracked.authority, { ...line, frames: pending, held: last.position });
319
- return {
320
- page: {
321
- kind: 'net-advancement',
322
- roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),
323
- documents,
324
- revisions,
325
- changes,
326
- binaryFiles,
327
- removals: removals.sort(),
328
- },
329
- entries: applied,
330
- schemas,
331
- };
332
452
  },
333
453
  };
334
454
  }