@agentshouse/mdruntime-adapter 0.1.0-ca218e62303fd → 0.1.0-ca231c2cbedb4

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 (60) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -22
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +23 -134
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +304 -174
  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/crockford.d.ts +4 -0
  12. package/dist/crockford.d.ts.map +1 -0
  13. package/dist/crockford.js +3 -0
  14. package/dist/discovery.d.ts +6 -10
  15. package/dist/discovery.d.ts.map +1 -1
  16. package/dist/discovery.js +37 -32
  17. package/dist/gather.d.ts +1 -1
  18. package/dist/gather.d.ts.map +1 -1
  19. package/dist/gather.js +4 -14
  20. package/dist/house-model.d.ts +2 -0
  21. package/dist/house-model.d.ts.map +1 -0
  22. package/dist/house-model.js +484 -0
  23. package/dist/index.d.ts +7 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +6 -1
  26. package/dist/model.d.ts +5 -1
  27. package/dist/model.d.ts.map +1 -1
  28. package/dist/model.js +11 -13
  29. package/dist/part.d.ts +15 -0
  30. package/dist/part.d.ts.map +1 -0
  31. package/dist/part.js +82 -0
  32. package/dist/read.d.ts +58 -24
  33. package/dist/read.d.ts.map +1 -1
  34. package/dist/read.js +270 -144
  35. package/dist/room-types.d.ts +7 -0
  36. package/dist/room-types.d.ts.map +1 -0
  37. package/dist/room-types.js +124 -0
  38. package/dist/site.d.ts +1 -1
  39. package/dist/site.d.ts.map +1 -1
  40. package/dist/site.js +126 -125
  41. package/dist/stream.d.ts +3 -3
  42. package/dist/stream.d.ts.map +1 -1
  43. package/dist/stream.js +64 -37
  44. package/dist/transport.d.ts +32 -11
  45. package/dist/transport.d.ts.map +1 -1
  46. package/dist/transport.js +2 -1
  47. package/dist/upload.d.ts +12 -0
  48. package/dist/upload.d.ts.map +1 -0
  49. package/dist/upload.js +63 -0
  50. package/dist/write.d.ts +12 -1
  51. package/dist/write.d.ts.map +1 -1
  52. package/dist/write.js +93 -55
  53. package/package.json +8 -4
  54. package/AGENTS.md +0 -309
  55. package/dist/handed.d.ts +0 -15
  56. package/dist/handed.d.ts.map +0 -1
  57. package/dist/handed.js +0 -38
  58. package/dist/referrer.d.ts +0 -7
  59. package/dist/referrer.d.ts.map +0 -1
  60. package/dist/referrer.js +0 -35
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,wBAAwB,CAAC;AA2BhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAmCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAuQxE"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAWR,MAAM,wBAAwB,CAAC;AA+BhC,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAoCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CA4P1F"}
package/dist/site.js CHANGED
@@ -1,34 +1,38 @@
1
+ import { stepped } from '@agentshouse/mdruntime';
1
2
  import { actionOutcome, SITE_SUBMIT } from './actions.js';
2
3
  import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteTracked, } from './discovery.js';
3
- import { partModels, streamedModels, viewModels } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, siteBootstrapNext, siteBootstrapOffset, viewOf, wholeView, } from './read.js';
5
- import { sha256Hex } from './digest.js';
4
+ import { manifestedModels, partModels, streamedModels, viewModels } from './model.js';
5
+ import { bootstrapping, emptyScope, housePart, manifested, parseEnumeration, parseSiteParted, partInventory, refreshFrom, viewOf, wholeView, } from './read.js';
6
+ import { PART_ATTEMPTS, partArrival, partFrame, unverifiedPart } from './part.js';
6
7
  import { classifyDoor, classifyRead, discoveryFailure } from './refusal.js';
8
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
7
9
  import { houseNotifications } from './stream.js';
8
- import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILE_RECORD, SITE_FILES, } from './transport.js';
9
- import { houseReferrer } from './referrer.js';
10
+ import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILES, } from './transport.js';
10
11
  import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
11
12
  const UNCERTAIN = { kind: 'transport-uncertainty' };
13
+ function unfound() {
14
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
15
+ }
12
16
  function siteRoom(tracked) {
13
17
  return {
14
18
  name: tracked.handle,
15
19
  locator: tracked.locator,
16
20
  handle: tracked.handle,
17
21
  roomVersion: roomVersion(tracked),
18
- operations: { read: [''], sync: [''], write: [], delete: [] },
19
- replica: { selection: tracked.locator, admission: 'admitted' },
22
+ operations: { write: [], delete: [] },
23
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
20
24
  providerOwnedPaths: [],
21
25
  };
22
26
  }
23
- function settled(refused) {
24
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
25
- }
26
- export function createSiteAdapter(transport) {
27
+ export function createSiteAdapter(transport, snapshot = false) {
27
28
  const notifications = houseNotifications(transport, 'site');
28
29
  const tracked = new Map();
29
- function published(referrer) {
30
- const named = houseReferrer(referrer, tracked);
31
- return named === null || !tracked.has(named.locator) ? null : named;
30
+ const expired = new Map();
31
+ function fileRoute(request) {
32
+ const entry = tracked.get(request.locator);
33
+ if (entry === undefined)
34
+ return { kind: 'room-not-readable', locator: request.locator };
35
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
32
36
  }
33
37
  async function enumerated(entry, from, page) {
34
38
  const answer = await transport.door(SITE_DOOR_ENUMERATE, {
@@ -53,73 +57,43 @@ export function createSiteAdapter(transport) {
53
57
  const first = await enumerated(entry, from);
54
58
  return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
55
59
  }
56
- async function bootstrapPart(entry, after, offset) {
57
- const query = [
58
- ...(after === null ? [] : [`after=${encodeURIComponent(after)}`]),
59
- ...(offset === null ? [] : [`offset=${offset}`]),
60
- ];
61
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${query.length === 0 ? '' : `?${query.join('&')}`}`);
60
+ async function partedRoom(entry) {
61
+ const cut = expired.get(entry.locator);
62
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`);
62
63
  const classified = classifyDoor(answer.status, answer.body, entry.locator);
63
64
  if (classified !== null)
64
- return { failure: classified };
65
- const scope = parseSiteBootstrap(answer.body);
66
- return scope === null ? { failure: UNCERTAIN } : { body: answer.body, scope };
67
- }
68
- async function assembled(entry, scope, path, offset) {
69
- const opened = scope.contents.at(-1);
70
- if (opened === undefined || opened.path !== path || opened.content.length !== offset) {
71
- return UNCERTAIN;
72
- }
73
- let text = opened.content;
74
- for (;;) {
75
- const part = await bootstrapPart(entry, path, text.length);
76
- if ('failure' in part)
77
- return part.failure;
78
- const [piece] = part.scope.contents;
79
- if (piece === undefined ||
80
- part.scope.contents.length !== 1 ||
81
- piece.path !== path ||
82
- piece.content.length === 0) {
83
- return UNCERTAIN;
84
- }
85
- text += piece.content;
86
- const more = siteBootstrapOffset(part.body);
87
- if (more === null)
88
- break;
89
- if (more !== text.length)
90
- return UNCERTAIN;
91
- }
92
- const file = scope.files.find((held) => held.path === path);
93
- if (file === undefined || (await sha256Hex(text)) !== file.version)
94
- return UNCERTAIN;
95
- return { ...scope, contents: [...scope.contents.slice(0, -1), { path, content: text }] };
65
+ return classified;
66
+ const room = parseSiteParted(answer.body);
67
+ return room === null || room.anchor !== entry.authority ? UNCERTAIN : room;
96
68
  }
97
- async function caughtUp(entry, after) {
98
- const part = await bootstrapPart(entry, after, null);
99
- if ('failure' in part)
100
- return part;
101
- const next = siteBootstrapNext(part.body);
102
- const offset = siteBootstrapOffset(part.body);
103
- if (offset !== null) {
104
- if (next === null)
105
- return { failure: UNCERTAIN };
106
- const scope = await assembled(entry, part.scope, next, offset);
107
- return 'kind' in scope ? { failure: scope } : { scope, next };
69
+ async function fetchedPart(entry, room, listed, received, arriving) {
70
+ if (received !== undefined) {
71
+ const kept = new Uint8Array(received);
72
+ const held = await housePart(room, kept, listed, 'site');
73
+ if (held !== null)
74
+ return 'kind' in held ? held : { scope: held, frame: kept };
108
75
  }
109
- const { scope } = part;
110
- if (after !== null || next !== null || roomVersion(scope) === roomVersion(entry)) {
111
- return { scope, next };
76
+ for (let attempt = 0; attempt < PART_ATTEMPTS; attempt += 1) {
77
+ const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}?part=${encodeURIComponent(listed.part)}`, partArrival(listed, arriving));
78
+ const failure = classifyRead(answer.status, answer.body, entry.locator);
79
+ if (failure?.kind === 'beyond-horizon')
80
+ expired.set(entry.locator, room.position);
81
+ if (failure !== null)
82
+ return failure;
83
+ const frame = partFrame(answer.body);
84
+ if (frame === null)
85
+ continue;
86
+ const scope = await housePart(room, frame, listed, 'site');
87
+ if (scope !== null)
88
+ return 'kind' in scope ? scope : { scope, frame };
112
89
  }
113
- const view = await enumeration(entry, scope);
114
- if ('kind' in view)
115
- return { failure: settled(view) };
116
- return { scope: advancedScope(scope, view), next: null };
90
+ return unverifiedPart(entry.locator);
117
91
  }
118
92
  async function refreshed(entry, fromRoomVersion) {
119
93
  const from = logPosition(fromRoomVersion);
120
94
  if (from === null)
121
95
  return { kind: 'beyond-horizon' };
122
- const streamed = notifications.advance(entry, from);
96
+ const streamed = await stepped(notifications.advance(entry, from));
123
97
  if (streamed !== null) {
124
98
  const models = await streamedModels(streamed.schemas, entry, 'site');
125
99
  return models === undefined ? streamed.page : { ...streamed.page, models };
@@ -128,7 +102,7 @@ export function createSiteAdapter(transport) {
128
102
  if ('kind' in view)
129
103
  return view;
130
104
  notifications.reach(entry.authority, view);
131
- const answer = refreshFrom(view, fromRoomVersion);
105
+ const answer = await refreshFrom(view, fromRoomVersion);
132
106
  if (answer.kind !== 'net-advancement')
133
107
  return answer;
134
108
  const models = await viewModels(view, entry);
@@ -137,6 +111,8 @@ export function createSiteAdapter(transport) {
137
111
  return {
138
112
  localSaves: true,
139
113
  exhaustiveDiscovery: true,
114
+ roomTypes: HOUSE_ROOM_TYPES,
115
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
140
116
  async authorize() {
141
117
  return {};
142
118
  },
@@ -159,23 +135,43 @@ export function createSiteAdapter(transport) {
159
135
  const entry = tracked.get(request.locator);
160
136
  if (entry === undefined)
161
137
  return { kind: 'room-not-readable', locator: request.locator };
162
- const continued = request.pageToken === undefined
163
- ? null
164
- : JSON.parse(request.pageToken);
165
- const held = await caughtUp(entry, continued?.after ?? null);
166
- if ('failure' in held)
167
- return held.failure;
168
- notifications.reach(entry.authority, held.scope);
138
+ let continued;
139
+ let inventory;
140
+ if (request.pageToken === undefined) {
141
+ const room = await partedRoom(entry);
142
+ if ('kind' in room)
143
+ return room;
144
+ const { models, seen } = await manifestedModels(room, entry);
145
+ continued = { room, next: 0, seen };
146
+ inventory = partInventory(room);
147
+ if (inventory.parts > 0) {
148
+ return manifested(room, inventory, JSON.stringify(continued), models);
149
+ }
150
+ }
151
+ else
152
+ continued = JSON.parse(request.pageToken);
153
+ const listed = continued.room.parts[continued.next];
154
+ const sent = listed === undefined
155
+ ? { scope: emptyScope(continued.room), frame: null }
156
+ : await fetchedPart(entry, continued.room, listed, request.received, request.arriving);
157
+ if ('kind' in sent)
158
+ return sent;
159
+ const { scope } = sent;
160
+ notifications.reach(entry.authority, scope);
161
+ const next = continued.next + 1;
162
+ const more = next < continued.room.parts.length;
169
163
  const seen = [
170
- ...(continued?.seen ?? []),
171
- ...entry.schemas.filter((schema) => held.scope.files.some((file) => file.path === schema)),
164
+ ...continued.seen,
165
+ ...(scope.files.some((file) => file.path === entry.schema) ? [entry.schema] : []),
172
166
  ];
173
- const models = await partModels(held.scope, entry, new Set(seen), held.next === null);
174
- const continuation = held.next === null ? null : { after: held.next, seen };
167
+ const models = await partModels(scope, entry, new Set(seen), !more);
168
+ const { folders: _folders, ...page } = await stepped(bootstrapping(scope));
175
169
  return {
176
- ...bootstrapOf(held.scope),
170
+ ...page,
177
171
  ...(models === undefined ? {} : { models }),
178
- ...(continuation === null ? {} : { pageToken: JSON.stringify(continuation) }),
172
+ ...(more ? { pageToken: JSON.stringify({ ...continued, next, seen }) } : {}),
173
+ ...(inventory === undefined ? {} : { inventory }),
174
+ ...(sent.frame === null ? {} : { received: sent.frame }),
179
175
  };
180
176
  },
181
177
  async refresh(_authorization, request) {
@@ -184,39 +180,42 @@ export function createSiteAdapter(transport) {
184
180
  return { kind: 'room-not-readable', locator: request.locator };
185
181
  if (request.pageToken !== undefined)
186
182
  return UNCERTAIN;
183
+ if (snapshot) {
184
+ return request.fromRoomVersion === roomVersion(entry)
185
+ ? { kind: 'still-current' }
186
+ : { kind: 'beyond-horizon' };
187
+ }
187
188
  return refreshed(entry, request.fromRoomVersion);
188
189
  },
189
190
  async mutate() {
190
191
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
191
192
  },
193
+ async attach() {
194
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
195
+ },
192
196
  async history() {
193
197
  return { kind: 'no-history' };
194
198
  },
195
199
  async binary(_authorization, request) {
196
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
197
- if (named === null) {
198
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
199
- }
200
- if (request.fileRef === undefined) {
201
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
202
- }
203
- const { room_ref, path, record } = named.referrer;
204
- const read = await transport.download(`${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
205
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
206
- : encodeURIComponent(path)}`);
207
- if (read.status === 404) {
208
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
209
- }
210
- return read.status === 200 && read.blob !== null
211
- ? { kind: 'binary', blob: read.blob }
200
+ const route = fileRoute(request);
201
+ if (typeof route !== 'string')
202
+ return route;
203
+ const read = await transport.download(route);
204
+ if (read.status === 404)
205
+ return unfound();
206
+ return read.status === 200 && read.body !== null
207
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
212
208
  : UNCERTAIN;
213
209
  },
214
- referrerScope(referrer) {
215
- const named = published(referrer);
216
- if (named === null)
217
- return null;
218
- const { path } = named.referrer;
219
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
210
+ async link(_authorization, request) {
211
+ const route = fileRoute(request);
212
+ if (typeof route !== 'string')
213
+ return route;
214
+ return {
215
+ kind: 'link',
216
+ url: route,
217
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
218
+ };
220
219
  },
221
220
  reached(locator, version, target) {
222
221
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
@@ -237,25 +236,27 @@ export function createSiteAdapter(transport) {
237
236
  return UNCERTAIN;
238
237
  return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
239
238
  },
240
- roomStream: {
241
- hold(rooms) {
242
- notifications.send(rooms.flatMap((room) => {
243
- const entry = tracked.get(room.locator);
244
- const at = logPosition(room.roomVersion);
245
- if (entry === undefined || at === null)
246
- return [];
247
- notifications.reach(entry.authority, at);
248
- return [presented(entry.authority, at)];
249
- }));
239
+ roomStream: snapshot
240
+ ? undefined
241
+ : {
242
+ hold(rooms) {
243
+ notifications.send(rooms.flatMap((room) => {
244
+ const entry = tracked.get(room.locator);
245
+ const at = logPosition(room.roomVersion);
246
+ if (entry === undefined || at === null)
247
+ return [];
248
+ notifications.reach(entry.authority, at);
249
+ return [presented(entry.authority, at)];
250
+ }));
251
+ },
252
+ reopen: notifications.reopen,
253
+ observe: notifications.observe,
254
+ published(locator, roomVersion) {
255
+ const at = logPosition(roomVersion);
256
+ if (at !== null)
257
+ notifications.published(locator, at);
258
+ },
250
259
  },
251
- reopen: notifications.reopen,
252
- observe: notifications.observe,
253
- published(locator, roomVersion) {
254
- const at = logPosition(roomVersion);
255
- if (at !== null)
256
- notifications.published(locator, at);
257
- },
258
- },
259
260
  serviceMode: notifications.serviceMode,
260
261
  };
261
262
  }
package/dist/stream.d.ts CHANGED
@@ -1,11 +1,10 @@
1
- import type { ConversationStream, RefreshPage, RoomStreamEvent, ServiceModeSignal, StreamReceipts } from '@agentshouse/mdruntime';
1
+ import { type ConversationStream, type RefreshPage, type RoomStreamEvent, type ServiceModeSignal, type StreamReceipts } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
3
  import type { HouseDoor, HouseHeldRoom, HouseMode, HouseStreamEntry } from './transport.js';
4
4
  import { type LogPosition } from './version.js';
5
5
  export type HeldRevision = (path: string, revision: string) => boolean;
6
6
  export type StreamedAdvancement = {
7
7
  page: RefreshPage;
8
- entries: readonly HouseStreamEntry[];
9
8
  schemas: ReadonlyMap<string, HouseStreamEntry>;
10
9
  };
11
10
  export type HouseNotifications = {
@@ -16,7 +15,8 @@ export type HouseNotifications = {
16
15
  reopen(): void;
17
16
  track(authorities: readonly TrackedAuthority[]): void;
18
17
  reach(authority: string, at: LogPosition): void;
19
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
18
+ edited(tracked: TrackedAuthority, from: LogPosition): readonly string[];
19
+ advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): Generator<number, StreamedAdvancement | null, void>;
20
20
  conversations: ConversationStream;
21
21
  serviceMode: ServiceModeSignal;
22
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAElB,WAAW,EACX,eAAe,EAEf,iBAAiB,EACjB,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EAEb,SAAS,EAET,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0C7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,OAAO,CACL,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,CAAC,EAAE,YAAY,GACnB,mBAAmB,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAkFF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAmhB5F"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAUvD,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EAEb,SAAS,EAET,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0C7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS,MAAM,EAAE,CAAC;IACxE,OAAO,CACL,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,CAAC,EAAE,YAAY,GACnB,SAAS,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;IACvD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAmFF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA8jB5F"}
package/dist/stream.js CHANGED
@@ -1,6 +1,7 @@
1
+ import { ROW_WEIGHT, } from '@agentshouse/mdruntime';
1
2
  import { acceptedMessage } from './actions.js';
2
3
  import { sha256Hex } from './digest.js';
3
- import { binaryFileOf, headChange } from './read.js';
4
+ import { answered, answering, binaryFileOf, folded, forgotten, headChange, revised, } from './read.js';
4
5
  import { roomVersion } from './version.js';
5
6
  const HELD_FRAMES_MAX = 256;
6
7
  function turnOperation(frame) {
@@ -15,6 +16,7 @@ function listedConversation(listed) {
15
16
  created: listed.created_at,
16
17
  finished: listed.finished_at,
17
18
  outcome: listed.outcome,
19
+ waiting: listed.waiting,
18
20
  };
19
21
  }
20
22
  function position(value) {
@@ -111,7 +113,10 @@ export function houseNotifications(transport, mode) {
111
113
  event.kind === 'questions' ||
112
114
  event.kind === 'process' ||
113
115
  event.kind === 'commands' ||
114
- event.kind === 'options') {
116
+ event.kind === 'options' ||
117
+ event.kind === 'starting' ||
118
+ event.kind === 'link' ||
119
+ event.kind === 'deliveries') {
115
120
  live.add(event.conversation);
116
121
  }
117
122
  for (const observer of conversationObservers)
@@ -157,6 +162,18 @@ export function houseNotifications(transport, mode) {
157
162
  emitConversation({ kind: 'options', conversation, options: structuredClone(frame.options) });
158
163
  return;
159
164
  }
165
+ if (frame.type === 'starting') {
166
+ emitConversation({ kind: 'starting', conversation, step: frame.step });
167
+ return;
168
+ }
169
+ if (frame.type === 'link') {
170
+ emitConversation({ kind: 'link', conversation, connected: frame.connected });
171
+ return;
172
+ }
173
+ if (frame.type === 'deliveries') {
174
+ emitConversation({ kind: 'deliveries', conversation, unknown: [...frame.unknown] });
175
+ return;
176
+ }
160
177
  if (frame.type === 'interactions') {
161
178
  emitConversation({
162
179
  kind: 'questions',
@@ -352,6 +369,10 @@ export function houseNotifications(transport, mode) {
352
369
  });
353
370
  return;
354
371
  }
372
+ if (frame.type === 'authority_changed') {
373
+ emit({ kind: 'authority-changed', scope: { authorities: frame.rooms } });
374
+ return;
375
+ }
355
376
  if (frame.type === 'conversations') {
356
377
  emitConversation({ kind: 'list', entries: frame.conversations.map(listedConversation) });
357
378
  return;
@@ -368,6 +389,9 @@ export function houseNotifications(transport, mode) {
368
389
  frame.type === 'process' ||
369
390
  frame.type === 'commands' ||
370
391
  frame.type === 'options' ||
392
+ frame.type === 'starting' ||
393
+ frame.type === 'link' ||
394
+ frame.type === 'deliveries' ||
371
395
  frame.type === 'interactions' ||
372
396
  frame.type === 'message') {
373
397
  converse(frame);
@@ -421,10 +445,10 @@ export function houseNotifications(transport, mode) {
421
445
  });
422
446
  });
423
447
  stream.opened(reopened);
424
- stream.closed((revoked) => {
448
+ stream.closed(({ revoked, lost }) => {
425
449
  opening = null;
426
450
  acknowledging = null;
427
- emit({ kind: 'closed', revoked });
451
+ emit({ kind: 'closed', revoked, lost });
428
452
  });
429
453
  return {
430
454
  runtime,
@@ -532,7 +556,18 @@ export function houseNotifications(transport, mode) {
532
556
  held,
533
557
  });
534
558
  },
535
- advance(tracked, from, holds) {
559
+ edited(tracked, from) {
560
+ const line = lines.get(tracked.authority);
561
+ const start = position(from.position);
562
+ if (line === undefined || start === null || line.logEpoch !== from.logEpoch)
563
+ return [];
564
+ return [
565
+ ...new Set(line.frames
566
+ .filter((frame) => frame.position > start)
567
+ .flatMap((frame) => frame.entries.flatMap((entry) => entry.kind === 'edited' && entry.revision !== undefined ? [entry.path] : []))),
568
+ ];
569
+ },
570
+ *advance(tracked, from, holds) {
536
571
  const line = lines.get(tracked.authority);
537
572
  const start = position(from.position);
538
573
  if (line === undefined || start === null || line.logEpoch !== from.logEpoch)
@@ -541,36 +576,26 @@ export function houseNotifications(transport, mode) {
541
576
  const first = pending[0];
542
577
  if (first === undefined || first.after > start)
543
578
  return null;
544
- const documents = {};
545
- const revisions = {};
546
- const changes = {};
547
- const binaryFiles = {};
548
- const removals = [];
549
- const applied = [];
579
+ const answer = answering();
550
580
  const schemas = new Map();
551
- const forget = (path) => {
552
- delete documents[path];
553
- delete revisions[path];
554
- delete changes[path];
555
- delete binaryFiles[path];
556
- const removed = removals.indexOf(path);
557
- if (removed !== -1)
558
- removals.splice(removed, 1);
559
- };
560
581
  for (const frame of pending) {
561
582
  for (const entry of frame.entries) {
583
+ yield ROW_WEIGHT + (entry.text?.length ?? 0);
584
+ if (entry.kind === 'folder') {
585
+ folded(answer, entry.path, entry.removed === true);
586
+ continue;
587
+ }
562
588
  if (entry.kind === 'edited' &&
563
589
  entry.revision !== undefined &&
564
590
  holds?.(entry.path, entry.revision) === true) {
565
- forget(entry.path);
591
+ forgotten(answer, entry.path);
566
592
  continue;
567
593
  }
568
- applied.push(entry);
569
- if (tracked.schemas.includes(entry.path))
594
+ if (entry.path === tracked.schema)
570
595
  schemas.set(entry.path, entry);
571
596
  if (entry.kind === 'removed') {
572
- forget(entry.path);
573
- removals.push(entry.path);
597
+ forgotten(answer, entry.path);
598
+ answer.removals.add(entry.path);
574
599
  continue;
575
600
  }
576
601
  const binary = binaryFileOf(entry);
@@ -581,31 +606,33 @@ export function houseNotifications(transport, mode) {
581
606
  const head = headChange(entry);
582
607
  if (head === null)
583
608
  return null;
584
- forget(entry.path);
609
+ forgotten(answer, entry.path);
585
610
  if (binary === undefined)
586
- documents[entry.path] = entry.text;
611
+ answer.documents.set(entry.path, entry.text);
587
612
  else
588
- binaryFiles[entry.path] = binary;
613
+ answer.binaryFiles.set(entry.path, binary);
589
614
  const revision = entry.revision ?? binary?.sha256;
590
615
  if (revision !== undefined)
591
- revisions[entry.path] = revision;
616
+ revised(answer, entry.path, revision);
592
617
  if (head !== undefined)
593
- changes[entry.path] = head;
618
+ answer.changes.set(entry.path, head);
594
619
  }
595
620
  }
596
621
  const last = pending.at(-1);
597
- lines.set(tracked.authority, { ...line, frames: pending, held: last.position });
622
+ const current = lines.get(tracked.authority);
623
+ if (current?.logEpoch === line.logEpoch) {
624
+ lines.set(tracked.authority, {
625
+ ...current,
626
+ frames: current.frames.filter((frame) => frame.position > start),
627
+ held: current.held !== null && current.held > last.position ? current.held : last.position,
628
+ });
629
+ }
598
630
  return {
599
631
  page: {
600
632
  kind: 'net-advancement',
601
633
  roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),
602
- documents,
603
- revisions,
604
- changes,
605
- binaryFiles,
606
- removals: removals.sort(),
634
+ ...(yield* answered(answer)),
607
635
  },
608
- entries: applied,
609
636
  schemas,
610
637
  };
611
638
  },