@agentshouse/mdruntime-adapter 0.1.0-cc63dd043d0e2 → 0.1.0-cc7da2d4669a3

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 (69) hide show
  1. package/README.md +4 -4
  2. package/dist/actions.d.ts +3 -4
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +10 -327
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +283 -246
  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 +18 -23
  15. package/dist/discovery.d.ts.map +1 -1
  16. package/dist/discovery.js +80 -73
  17. package/dist/history.d.ts +12 -0
  18. package/dist/history.d.ts.map +1 -0
  19. package/dist/history.js +91 -0
  20. package/dist/house-model.d.ts +2915 -0
  21. package/dist/house-model.d.ts.map +1 -0
  22. package/dist/house-model.js +1603 -0
  23. package/dist/index.d.ts +10 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +9 -1
  26. package/dist/model.d.ts +10 -18
  27. package/dist/model.d.ts.map +1 -1
  28. package/dist/model.js +39 -37
  29. package/dist/part.d.ts +14 -0
  30. package/dist/part.d.ts.map +1 -0
  31. package/dist/part.js +90 -0
  32. package/dist/read.d.ts +52 -41
  33. package/dist/read.d.ts.map +1 -1
  34. package/dist/read.js +248 -237
  35. package/dist/refusal.d.ts +4 -11
  36. package/dist/refusal.d.ts.map +1 -1
  37. package/dist/refusal.js +26 -17
  38. package/dist/room-stream.d.ts +19 -0
  39. package/dist/room-stream.d.ts.map +1 -0
  40. package/dist/room-stream.js +57 -0
  41. package/dist/room-types.d.ts +7 -0
  42. package/dist/room-types.d.ts.map +1 -0
  43. package/dist/room-types.js +126 -0
  44. package/dist/site.d.ts +1 -1
  45. package/dist/site.d.ts.map +1 -1
  46. package/dist/site.js +132 -142
  47. package/dist/stream.d.ts +16 -11
  48. package/dist/stream.d.ts.map +1 -1
  49. package/dist/stream.js +229 -143
  50. package/dist/transport.d.ts +109 -22
  51. package/dist/transport.d.ts.map +1 -1
  52. package/dist/transport.js +53 -10
  53. package/dist/upload.d.ts +12 -0
  54. package/dist/upload.d.ts.map +1 -0
  55. package/dist/upload.js +63 -0
  56. package/dist/version.d.ts +2 -0
  57. package/dist/version.d.ts.map +1 -1
  58. package/dist/version.js +10 -1
  59. package/dist/write.d.ts +18 -2
  60. package/dist/write.d.ts.map +1 -1
  61. package/dist/write.js +169 -42
  62. package/package.json +9 -6
  63. package/AGENTS.md +0 -215
  64. package/dist/gather.d.ts +0 -3
  65. package/dist/gather.d.ts.map +0 -1
  66. package/dist/gather.js +0 -40
  67. package/dist/links.d.ts +0 -12
  68. package/dist/links.d.ts.map +0 -1
  69. package/dist/links.js +0 -66
@@ -0,0 +1,19 @@
1
+ import type { BootstrapResult, RoomModels } from '@agentshouse/mdruntime';
2
+ import type { TrackedAuthority } from './discovery.js';
3
+ import { type HouseScope } from './read.js';
4
+ import type { HouseMode } from './transport.js';
5
+ export type StreamedPart = {
6
+ readonly scope: HouseScope;
7
+ readonly first: boolean;
8
+ readonly ended: boolean;
9
+ readonly models: RoomModels | undefined;
10
+ readonly pageToken: string | undefined;
11
+ readonly bytes: number;
12
+ };
13
+ export declare function roomStreams(mode: HouseMode): {
14
+ head: (entry: TrackedAuthority, room: ReadableStream<Uint8Array>, arriving: ((bytes: number) => void) | undefined, signal: AbortSignal | undefined) => Promise<BootstrapResult>;
15
+ part: (entry: TrackedAuthority, token: string) => Promise<StreamedPart | Exclude<BootstrapResult, {
16
+ kind: 'bootstrap';
17
+ }>>;
18
+ };
19
+ //# sourceMappingURL=room-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-stream.d.ts","sourceRoot":"","sources":["../src/room-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,OAAO,EAAuD,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAYhD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS;kBAKhC,gBAAgB,QACjB,cAAc,CAAC,UAAU,CAAC,YACtB,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,UACvC,WAAW,GAAG,SAAS,KAC9B,OAAO,CAAC,eAAe,CAAC;kBAelB,gBAAgB,SAChB,MAAM,KACZ,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;EAkC3E"}
@@ -0,0 +1,57 @@
1
+ import { manifestedModels, partModels } from './model.js';
2
+ import { roomFrames } from './part.js';
3
+ import { housePart, manifested, roomHead } from './read.js';
4
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
5
+ export function roomStreams(mode) {
6
+ const open = new Map();
7
+ let opened = 0;
8
+ async function head(entry, room, arriving, signal) {
9
+ const frames = roomFrames(room, arriving, signal);
10
+ const first = await frames();
11
+ if (first.kind !== 'frame')
12
+ return UNCERTAIN;
13
+ const held = await roomHead(first.payload, mode);
14
+ if (held === null || held.anchor !== entry.authority)
15
+ return UNCERTAIN;
16
+ const { models, seen } = await manifestedModels(held, entry);
17
+ opened += 1;
18
+ const id = String(opened);
19
+ open.set(id, { entry, head: held, frames, next: 1, seen });
20
+ signal?.addEventListener('abort', () => open.delete(id), { once: true });
21
+ return { ...manifested(held, `${id}:1`, models), bytes: first.bytes };
22
+ }
23
+ async function part(entry, token) {
24
+ const [id = '', at = ''] = token.split(':');
25
+ const room = open.get(id);
26
+ if (room === undefined || room.entry.locator !== entry.locator || String(room.next) !== at)
27
+ return UNCERTAIN;
28
+ const frame = await room.frames();
29
+ if (frame.kind !== 'frame') {
30
+ open.delete(id);
31
+ return UNCERTAIN;
32
+ }
33
+ const read = await housePart(room.head, frame.payload, mode);
34
+ if ('kind' in read) {
35
+ open.delete(id);
36
+ return read;
37
+ }
38
+ const { scope, ended } = read;
39
+ const first = room.next === 1;
40
+ room.next += 1;
41
+ room.seen = [
42
+ ...room.seen,
43
+ ...(scope.files.some((file) => file.path === entry.schema) ? [entry.schema] : []),
44
+ ];
45
+ if (ended)
46
+ open.delete(id);
47
+ return {
48
+ scope,
49
+ first,
50
+ ended,
51
+ models: await partModels(scope, entry, new Set(room.seen), ended),
52
+ pageToken: ended ? undefined : `${id}:${room.next}`,
53
+ bytes: frame.bytes,
54
+ };
55
+ }
56
+ return { head, part };
57
+ }
@@ -0,0 +1,7 @@
1
+ export declare const INBOX_CHANNEL_KINDS: readonly ['telegram-bot', 'telegram-business', 'whatsapp', 'messenger', 'instagram', 'viber', 'tiktok'];
2
+ export type InboxChannelKind = (typeof INBOX_CHANNEL_KINDS)[number];
3
+ export declare const INBOX_CHAT_TYPE = "inbox-chat";
4
+ export declare const INBOX_MESSAGE_TYPE = "inbox-message";
5
+ export declare const HOUSE_NAMEABLE_ROOM_TYPES: string[];
6
+ export declare const HOUSE_ROOM_TYPES: string;
7
+ //# sourceMappingURL=room-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-types.d.ts","sourceRoot":"","sources":["../src/room-types.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,YAC9B,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,QAAQ,CACA,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD,eAAO,MAAM,yBAAyB,UAAwC,CAAC;AAyB/E,eAAO,MAAM,gBAAgB,QA8FjB,CAAC"}
@@ -0,0 +1,126 @@
1
+ import { APP_REFERENCE_PATTERN } from './app-reference.js';
2
+ import { HOUSE_MODEL_TYPES } from './house-model.js';
3
+ export const INBOX_CHANNEL_KINDS = [
4
+ 'telegram-bot',
5
+ 'telegram-business',
6
+ 'whatsapp',
7
+ 'messenger',
8
+ 'instagram',
9
+ 'viber',
10
+ 'tiktok',
11
+ ];
12
+ export const INBOX_CHAT_TYPE = 'inbox-chat';
13
+ export const INBOX_MESSAGE_TYPE = 'inbox-message';
14
+ export const HOUSE_NAMEABLE_ROOM_TYPES = [INBOX_CHAT_TYPE, INBOX_MESSAGE_TYPE];
15
+ const WAYFINDING_MAP_TYPE = 'wayfinding-map';
16
+ const WAYFINDING_TICKET_TYPE = 'wayfinding-ticket';
17
+ const WAYFINDING_MAP_SECTIONS = [
18
+ 'Destination',
19
+ 'Notes',
20
+ 'Decisions so far',
21
+ 'Not yet specified',
22
+ 'Out of scope',
23
+ ];
24
+ const IDENTITY = "{ type: string, pattern: '^\\S+$' }";
25
+ const AGENT = [' agent: { type: string, format: uuid }', ' name: { type: string }'];
26
+ const ASSIGNEE = [
27
+ ' type: object',
28
+ ' properties:',
29
+ ' user: { type: string, format: uuid }',
30
+ ...AGENT,
31
+ ];
32
+ export const HOUSE_ROOM_TYPES = [
33
+ `${INBOX_CHAT_TYPE}:`,
34
+ ' properties:',
35
+ ' inbox: { type: string, format: uuid }',
36
+ ` channel: { enum: [${INBOX_CHANNEL_KINDS.join(', ')}] }`,
37
+ ` chat: ${IDENTITY}`,
38
+ ' customer:',
39
+ ' type: object',
40
+ ' properties:',
41
+ ' name: { type: string }',
42
+ ` username: ${IDENTITY}`,
43
+ ` phone: ${IDENTITY}`,
44
+ ' assignee:',
45
+ ...ASSIGNEE,
46
+ ' return_to:',
47
+ ' type: object',
48
+ ' properties:',
49
+ ...AGENT,
50
+ ' conversation: { type: string, format: uuid }',
51
+ ' required: [inbox, channel, chat, customer]',
52
+ `${INBOX_MESSAGE_TYPE}:`,
53
+ ' properties:',
54
+ ' direction: { enum: [in, out] }',
55
+ ' sender:',
56
+ ' type: object',
57
+ ' properties:',
58
+ ' name: { type: string }',
59
+ ` username: ${IDENTITY}`,
60
+ ' sent_at: { type: string, format: date-time }',
61
+ ` channel_message: ${IDENTITY}`,
62
+ ' state: { enum: [sending, sent, failed] }',
63
+ ' reason: { type: string }',
64
+ ' labelled: { const: true }',
65
+ ' reactions:',
66
+ ' type: array',
67
+ ' items:',
68
+ ' type: object',
69
+ ' properties:',
70
+ ' reaction: { type: string, minLength: 1 }',
71
+ ' sender:',
72
+ ' type: object',
73
+ ' properties:',
74
+ ` id: ${IDENTITY}`,
75
+ ' name: { type: string }',
76
+ ` username: ${IDENTITY}`,
77
+ ' count: { type: integer, minimum: 1 }',
78
+ ' required: [reaction]',
79
+ ` post: ${IDENTITY}`,
80
+ ' assignee:',
81
+ ...ASSIGNEE,
82
+ ' sent_outside: { const: true }',
83
+ ' template:',
84
+ ' type: object',
85
+ ' properties:',
86
+ ' name: { type: string, minLength: 1 }',
87
+ ' language: { type: string, minLength: 1 }',
88
+ ' required: [name, language]',
89
+ ' values:',
90
+ ' type: object',
91
+ ' additionalProperties: { type: string }',
92
+ ' withheld: { const: true }',
93
+ ' required: [direction]',
94
+ ' if: { properties: { direction: { const: in } } }',
95
+ ' then: { required: [sent_at] }',
96
+ `${WAYFINDING_MAP_TYPE}:`,
97
+ ' properties:',
98
+ ' title: { type: string }',
99
+ ' required: [title]',
100
+ ' sections:',
101
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
102
+ `${WAYFINDING_TICKET_TYPE}:`,
103
+ ' properties:',
104
+ ' title: { type: string }',
105
+ ' kind: { enum: [research, prototype, grilling, task] }',
106
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
107
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
108
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
109
+ ' assignee:',
110
+ ...ASSIGNEE,
111
+ ' conversation: { type: string, format: uuid }',
112
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
113
+ ' required: [title, kind, status, map, blocked_by]',
114
+ ' sections:',
115
+ ' Question: { kind: text }',
116
+ ' Answer: { kind: text }',
117
+ ' allOf:',
118
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
119
+ ' then: { required: [assignee] }',
120
+ ' else: { properties: { assignee: false } }',
121
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
122
+ ' else: { properties: { conversation: false } }',
123
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
124
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
125
+ HOUSE_MODEL_TYPES,
126
+ ].join('\n');
package/dist/site.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { Adapter } from '@agentshouse/mdruntime';
2
2
  import { type HouseSiteTransport } from './transport.js';
3
- export declare function createSiteAdapter(transport: HouseSiteTransport): Adapter;
3
+ export declare function createSiteAdapter(transport: HouseSiteTransport, snapshot?: boolean): Adapter;
4
4
  //# sourceMappingURL=site.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AA+BhC,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAsCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAuKxE"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAehC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAkK1F"}
package/dist/site.js CHANGED
@@ -1,184 +1,174 @@
1
+ import { stepped } from '@agentshouse/mdruntime';
1
2
  import { actionOutcome } from './actions.js';
2
3
  import { mapDiscovery, parseSiteDiscovery, siteCapabilities, siteTracked, } from './discovery.js';
3
- import { MODEL_ABSENT, failedModel, heldModel, modelKey, modelShelf, } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, schemaOf, schemaPath, viewOf, } from './read.js';
5
- import { classifyDoor, discoveryFailure, doorRefusal } from './refusal.js';
4
+ import { bootstrapping } from './read.js';
5
+ import { roomStreams } from './room-stream.js';
6
+ import { classifyDoor, discoveryFailure } from './refusal.js';
7
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
6
8
  import { houseNotifications } from './stream.js';
7
- import { PRIVATE_LOCATOR, SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, } from './transport.js';
8
- import { logPosition, presented, reachedVersion, roomVersion, } from './version.js';
9
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITE_SUBMISSION, } from './transport.js';
10
+ import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
9
11
  const UNCERTAIN = { kind: 'transport-uncertainty' };
10
- function siteRoom(tracked, attachedModel) {
12
+ function unfound() {
13
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
14
+ }
15
+ function siteRoom(tracked) {
11
16
  return {
12
17
  name: tracked.handle,
13
18
  locator: tracked.locator,
19
+ handle: tracked.handle,
14
20
  roomVersion: roomVersion(tracked),
15
- operations: { read: [''], sync: [''], write: [], delete: [] },
16
- replica: { selection: tracked.locator, admission: 'admitted' },
17
- attachedModel,
21
+ operations: { write: [], delete: [] },
22
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
18
23
  providerOwnedPaths: [],
19
24
  };
20
25
  }
21
- function settled(refused) {
22
- return refused.kind === 'beyond-horizon' || refused.kind === 'retryable-refusal'
23
- ? UNCERTAIN
24
- : refused;
25
- }
26
- export function createSiteAdapter(transport) {
27
- const notifications = houseNotifications(transport, 'site');
26
+ export function createSiteAdapter(transport, snapshot = false) {
27
+ const notifications = houseNotifications(transport, 'site', {
28
+ opened: async () => {
29
+ const found = await discovered();
30
+ return found.kind === 'discovery' ? found : null;
31
+ },
32
+ changed: () => null,
33
+ });
28
34
  const tracked = new Map();
29
- const models = modelShelf();
30
- const acquired = new Map();
31
- let caught = new Map();
32
- async function enumeration(entry, from) {
33
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
34
- positions: [presented(entry.authority, from)],
35
- });
36
- const behind = doorRefusal(answer.body);
37
- if (behind?.code === 'replica_behind' && behind.retryable) {
38
- return { kind: 'retryable-refusal', code: behind.code, fields: behind.fields };
39
- }
40
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
41
- if (classified !== null)
42
- return classified;
43
- return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
35
+ const read = new Map();
36
+ const rooms = roomStreams('site');
37
+ function fileRoute(request) {
38
+ const entry = tracked.get(request.locator);
39
+ if (entry === undefined)
40
+ return { kind: 'room-not-readable', locator: request.locator };
41
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
44
42
  }
45
- async function caughtUp(entry) {
46
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);
47
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
48
- if (classified !== null)
49
- return { failure: settled(classified) };
50
- const scope = parseSiteBootstrap(answer.body);
51
- if (scope === null)
52
- return { failure: UNCERTAIN };
53
- if (roomVersion(scope) === roomVersion(entry))
54
- return { scope };
55
- const found = await enumeration(entry, scope);
56
- if ('kind' in found)
57
- return { failure: settled(found) };
58
- const view = viewOf(found, entry);
59
- if (view === undefined)
60
- return { failure: { kind: 'room-not-readable', locator: entry.locator } };
61
- return { scope: advancedScope(scope, view) };
43
+ async function openedRoom(entry, arriving, signal) {
44
+ const cut = read.get(entry.locator);
45
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`, signal ?? new AbortController().signal);
46
+ if (answered.room === null)
47
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
48
+ const head = await rooms.head(entry, answered.room, arriving, signal);
49
+ const at = head.kind === 'bootstrap' ? logPosition(head.roomVersion) : null;
50
+ if (at !== null)
51
+ read.set(entry.locator, at.position);
52
+ return head;
62
53
  }
63
- async function refreshed(entry, fromRoomVersion) {
64
- const from = logPosition(fromRoomVersion);
65
- if (from === null)
66
- return { kind: 'beyond-horizon' };
67
- const streamed = notifications.advance(entry, from);
68
- if (streamed !== null)
69
- return streamed.page;
70
- const found = await enumeration(entry, from);
71
- if ('kind' in found)
72
- return found;
73
- const view = viewOf(found, entry);
74
- if (view === undefined)
75
- return { kind: 'room-not-readable', locator: entry.locator };
76
- notifications.hold(entry.authority, view);
77
- return refreshFrom(view, fromRoomVersion);
54
+ async function streamedPage(entry, token) {
55
+ const part = await rooms.part(entry, token);
56
+ if ('kind' in part)
57
+ return part;
58
+ const { folders: _folders, ...page } = await stepped(bootstrapping(part.scope));
59
+ return {
60
+ ...page,
61
+ ...(part.models === undefined ? {} : { models: part.models }),
62
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
63
+ bytes: part.bytes,
64
+ };
78
65
  }
79
- async function acquire(entry, held) {
80
- if ('failure' in held)
81
- return { snapshot: failedModel(held.failure), identity: null };
82
- const model = await heldModel(schemaOf(held.scope, entry.schema), schemaPath(entry.handle, entry.schema), MODEL_ABSENT);
83
- acquired.set(entry.authority, { roomVersion: roomVersion(held.scope), model });
84
- return model;
66
+ async function discovered() {
67
+ const answer = await transport.read(houseSiteRoute('discover'));
68
+ const failed = discoveryFailure(answer.status, answer.body);
69
+ if (failed !== null)
70
+ return failed;
71
+ const document = parseSiteDiscovery(answer.body);
72
+ if (document === null)
73
+ return UNCERTAIN;
74
+ const entries = siteTracked(document);
75
+ tracked.clear();
76
+ for (const entry of entries)
77
+ tracked.set(entry.locator, entry);
78
+ notifications.track(entries);
79
+ return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
85
80
  }
86
81
  return {
82
+ localSaves: true,
83
+ roomTypes: HOUSE_ROOM_TYPES,
84
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
87
85
  async authorize() {
88
86
  return {};
89
87
  },
90
- async model(_authorization, request) {
91
- return models.answer(request);
92
- },
93
- async discover() {
94
- const answer = await transport.read(SITE_DOOR_DISCOVER);
95
- const classified = classifyDoor(answer.status, answer.body, PRIVATE_LOCATOR);
96
- if (classified !== null)
97
- return discoveryFailure(classified);
98
- const document = parseSiteDiscovery(answer.body);
99
- if (document === null)
100
- return UNCERTAIN;
101
- const entries = siteTracked(document);
102
- tracked.clear();
103
- for (const entry of entries)
104
- tracked.set(entry.locator, entry);
105
- notifications.track(entries);
106
- const published = new Set(entries.map((entry) => entry.authority));
107
- for (const authority of [...acquired.keys()]) {
108
- if (!published.has(authority))
109
- acquired.delete(authority);
110
- }
111
- const fresh = new Map();
112
- const current = new Map();
113
- for (const entry of entries) {
114
- const kept = acquired.get(entry.authority);
115
- if (kept !== undefined && kept.roomVersion === roomVersion(entry)) {
116
- current.set(entry.authority, kept.model);
117
- continue;
118
- }
119
- const held = await caughtUp(entry);
120
- fresh.set(entry.authority, held);
121
- current.set(entry.authority, await acquire(entry, held));
122
- }
123
- caught = fresh;
124
- const rooms = entries.map((entry) => {
125
- const shelved = models.retain(modelKey(entry.locator, 'collection'), current.get(entry.authority));
126
- return siteRoom(entry, shelved?.identity ?? null);
127
- });
128
- models.keep(entries.map((entry) => entry.locator));
129
- return mapDiscovery(document, rooms, siteCapabilities());
130
- },
131
88
  async bootstrap(_authorization, request) {
132
89
  const entry = tracked.get(request.locator);
133
90
  if (entry === undefined)
134
91
  return { kind: 'room-not-readable', locator: request.locator };
135
- if (request.pageToken !== undefined)
136
- return UNCERTAIN;
137
- const held = caught.get(entry.authority) ?? (await caughtUp(entry));
138
- if ('failure' in held)
139
- return held.failure;
140
- notifications.hold(entry.authority, held.scope);
141
- return bootstrapOf(held.scope);
92
+ return request.pageToken === undefined
93
+ ? openedRoom(entry, request.arriving, request.signal)
94
+ : streamedPage(entry, request.pageToken);
142
95
  },
143
- async refresh(_authorization, request) {
144
- const entry = tracked.get(request.locator);
145
- if (entry === undefined)
146
- return { kind: 'room-not-readable', locator: request.locator };
147
- if (request.pageToken !== undefined)
148
- return UNCERTAIN;
149
- const result = await refreshed(entry, request.fromRoomVersion);
150
- if (result.kind === 'beyond-horizon')
151
- caught.delete(entry.authority);
152
- const answered = result.kind === 'net-advancement'
153
- ? result.roomVersion
154
- : result.kind === 'still-current'
155
- ? request.fromRoomVersion
156
- : null;
157
- if (request.minPosition !== undefined &&
158
- answered !== null &&
159
- !reachedVersion(answered, request.minPosition, entry.logEpoch)) {
160
- return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
96
+ ...(snapshot
97
+ ? {
98
+ discover: discovered,
99
+ async refresh(_authorization, request) {
100
+ const entry = tracked.get(request.locator);
101
+ if (entry === undefined)
102
+ return { kind: 'room-not-readable', locator: request.locator };
103
+ if (request.pageToken !== undefined)
104
+ return UNCERTAIN;
105
+ return request.fromRoomVersion === roomVersion(entry)
106
+ ? { kind: 'still-current' }
107
+ : { kind: 'beyond-horizon' };
108
+ },
161
109
  }
162
- return result;
163
- },
110
+ : {}),
164
111
  async mutate() {
165
- return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {} };
112
+ return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
113
+ },
114
+ async attach() {
115
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
166
116
  },
167
117
  async history() {
168
118
  return { kind: 'no-history' };
169
119
  },
120
+ async binary(_authorization, request) {
121
+ const route = fileRoute(request);
122
+ if (typeof route !== 'string')
123
+ return route;
124
+ const read = await transport.download(route);
125
+ if (read.status === 404)
126
+ return unfound();
127
+ return read.status === 200 && read.body !== null
128
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
129
+ : UNCERTAIN;
130
+ },
131
+ async link(_authorization, request) {
132
+ const route = fileRoute(request);
133
+ if (typeof route !== 'string')
134
+ return route;
135
+ return {
136
+ kind: 'link',
137
+ url: route,
138
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
139
+ };
140
+ },
170
141
  reached(locator, version, target) {
171
142
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
172
143
  },
144
+ follows(_locator, version, next) {
145
+ return followsVersion(version, next);
146
+ },
173
147
  async action(_authorization, request) {
174
- if (request.name !== 'submit') {
175
- return { kind: 'rejected', code: 'action-unimplemented', fields: { name: request.name } };
148
+ if (request.name !== SITE_SUBMISSION) {
149
+ return {
150
+ kind: 'rejected',
151
+ code: 'action-unimplemented',
152
+ fields: { name: request.name },
153
+ retryable: false,
154
+ };
176
155
  }
177
156
  if (!transport.online())
178
157
  return UNCERTAIN;
179
- return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), 'submit');
158
+ return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMISSION);
180
159
  },
181
- roomVersions: notifications,
160
+ roomStream: snapshot
161
+ ? undefined
162
+ : {
163
+ hold(rooms) {
164
+ notifications.send(rooms.flatMap((room) => {
165
+ const entry = tracked.get(room.locator);
166
+ const at = logPosition(room.roomVersion);
167
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
168
+ }));
169
+ },
170
+ observe: notifications.observe,
171
+ },
182
172
  serviceMode: notifications.serviceMode,
183
173
  };
184
174
  }
package/dist/stream.d.ts CHANGED
@@ -1,18 +1,23 @@
1
- import type { ConversationStream, RefreshPage, SelectedRooms, ServiceModeSignal } from '@agentshouse/mdruntime';
1
+ import { type AuthorityChange, type Discovery, type ConversationStream, type RoomStreamEvent, type ServiceModeSignal } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
- import type { HouseDoor, HouseMode, HouseStreamEntry } from './transport.js';
4
- import { type LogPosition } from './version.js';
5
- export type HeldRevision = (path: string, revision: string) => boolean;
6
- export type StreamedAdvancement = {
7
- page: RefreshPage;
8
- entries: readonly HouseStreamEntry[];
3
+ import { type HouseDoor, type HouseHeldRoom, type HouseMode, type HouseStreamFrame } from './transport.js';
4
+ export type HouseOpeningFrame = Extract<HouseStreamFrame, {
5
+ type: 'opening';
6
+ }>;
7
+ export type HouseAuthorityChangedFrame = Extract<HouseStreamFrame, {
8
+ type: 'authority_changed';
9
+ }>;
10
+ export type HouseDiscovering = {
11
+ opened(frame: HouseOpeningFrame | null): Promise<Discovery | null>;
12
+ changed(frame: HouseAuthorityChangedFrame): AuthorityChange | null;
9
13
  };
10
- export type HouseNotifications = SelectedRooms & {
14
+ export type HouseNotifications = {
15
+ runtime: string;
16
+ observe(notify: (event: RoomStreamEvent) => void): () => void;
17
+ send(rooms: readonly HouseHeldRoom[]): void;
11
18
  track(authorities: readonly TrackedAuthority[]): void;
12
- hold(authority: string, at: LogPosition): void;
13
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
14
19
  conversations: ConversationStream;
15
20
  serviceMode: ServiceModeSignal;
16
21
  };
17
- export declare function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications;
22
+ export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering): HouseNotifications;
18
23
  //# sourceMappingURL=stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,kBAAkB,EAClB,WAAW,EAEX,aAAa,EAEb,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAoB,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAgB7D,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;CACtC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG;IAC/C,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,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;AAYF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CA2P5F"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,SAAS,EACd,KAAK,kBAAkB,EAIvB,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAWvD,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,aAAa,EAElB,KAAK,SAAS,EAGd,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAaxB,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAE/E,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;AAElG,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,EAAE,0BAA0B,GAAG,eAAe,GAAG,IAAI,CAAC;CACpE,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AAkFF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,gBAAgB,GAC5B,kBAAkB,CAuSpB"}