@agentshouse/mdruntime-adapter 0.1.0-cf6a7cf003c4b → 0.1.0-cf75412975d5b

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 (72) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -43
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +8 -295
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +291 -230
  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 +23 -12
  15. package/dist/discovery.d.ts.map +1 -1
  16. package/dist/discovery.js +94 -50
  17. package/dist/history.d.ts +12 -0
  18. package/dist/history.d.ts.map +1 -0
  19. package/dist/history.js +92 -0
  20. package/dist/house-model.d.ts +911 -0
  21. package/dist/house-model.d.ts.map +1 -0
  22. package/dist/house-model.js +496 -0
  23. package/dist/index.d.ts +11 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +10 -1
  26. package/dist/model.d.ts +5 -3
  27. package/dist/model.d.ts.map +1 -1
  28. package/dist/model.js +10 -32
  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 +54 -44
  33. package/dist/read.d.ts.map +1 -1
  34. package/dist/read.js +271 -214
  35. package/dist/refusal.d.ts +0 -3
  36. package/dist/refusal.d.ts.map +1 -1
  37. package/dist/refusal.js +2 -6
  38. package/dist/room-stream.d.ts +20 -0
  39. package/dist/room-stream.d.ts.map +1 -0
  40. package/dist/room-stream.js +78 -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 +125 -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 +130 -104
  50. package/dist/stream.d.ts +12 -12
  51. package/dist/stream.d.ts.map +1 -1
  52. package/dist/stream.js +207 -151
  53. package/dist/transport.d.ts +91 -20
  54. package/dist/transport.d.ts.map +1 -1
  55. package/dist/transport.js +55 -9
  56. package/dist/upload.d.ts +12 -0
  57. package/dist/upload.d.ts.map +1 -0
  58. package/dist/upload.js +63 -0
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.d.ts.map +1 -1
  61. package/dist/version.js +1 -1
  62. package/dist/write.d.ts +19 -10
  63. package/dist/write.d.ts.map +1 -1
  64. package/dist/write.js +142 -54
  65. package/package.json +8 -5
  66. package/AGENTS.md +0 -269
  67. package/dist/gather.d.ts +0 -4
  68. package/dist/gather.d.ts.map +0 -1
  69. package/dist/gather.js +0 -45
  70. package/dist/links.d.ts +0 -20
  71. package/dist/links.d.ts.map +0 -1
  72. package/dist/links.js +0 -104
@@ -0,0 +1,78 @@
1
+ import { stepped } from '@agentshouse/mdruntime';
2
+ import { manifestedModels, partModels } from './model.js';
3
+ import { roomFrames } from './part.js';
4
+ import { bootstrapping, housePart, manifested, roomHead, } from './read.js';
5
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
6
+ export function roomStreams(mode) {
7
+ const open = new Map();
8
+ let opened = 0;
9
+ async function head(entry, room, arriving, signal) {
10
+ const frames = roomFrames(room, arriving, signal);
11
+ const first = await frames();
12
+ if (first.kind !== 'frame')
13
+ return UNCERTAIN;
14
+ const held = await roomHead(first.payload, mode);
15
+ if (held === null || held.anchor !== entry.authority)
16
+ return UNCERTAIN;
17
+ const { models, seen } = await manifestedModels(held, entry);
18
+ opened += 1;
19
+ const id = String(opened);
20
+ open.set(id, { entry, head: held, frames, next: 1, seen });
21
+ signal?.addEventListener('abort', () => open.delete(id), { once: true });
22
+ return { ...manifested(held, `${id}:1`, models), bytes: first.bytes };
23
+ }
24
+ async function part(entry, token) {
25
+ const [id = '', at = ''] = token.split(':');
26
+ const room = open.get(id);
27
+ if (room === undefined || room.entry.locator !== entry.locator || String(room.next) !== at)
28
+ return UNCERTAIN;
29
+ const frame = await room.frames();
30
+ if (frame.kind !== 'frame') {
31
+ open.delete(id);
32
+ return UNCERTAIN;
33
+ }
34
+ const read = await housePart(room.head, frame.payload, mode);
35
+ if ('kind' in read) {
36
+ open.delete(id);
37
+ return read;
38
+ }
39
+ const { scope, ended } = read;
40
+ const first = room.next === 1;
41
+ room.next += 1;
42
+ room.seen = [
43
+ ...room.seen,
44
+ ...(scope.files.some((file) => file.path === entry.schema) ? [entry.schema] : []),
45
+ ];
46
+ if (ended)
47
+ open.delete(id);
48
+ return {
49
+ scope,
50
+ first,
51
+ ended,
52
+ models: await partModels(scope, entry, new Set(room.seen), ended),
53
+ pageToken: ended ? undefined : `${id}:${room.next}`,
54
+ bytes: frame.bytes,
55
+ };
56
+ }
57
+ async function named(entry, room, signal) {
58
+ const opened = await head(entry, room, undefined, signal);
59
+ if (opened.kind !== 'bootstrap')
60
+ return opened;
61
+ const files = [];
62
+ const contents = [];
63
+ let last = null;
64
+ for (let token = opened.pageToken; token !== undefined;) {
65
+ const read = await part(entry, token);
66
+ if ('kind' in read)
67
+ return read;
68
+ files.push(...read.scope.files);
69
+ contents.push(...read.scope.contents);
70
+ last = read.scope;
71
+ token = read.pageToken;
72
+ }
73
+ if (last === null)
74
+ return UNCERTAIN;
75
+ return stepped(bootstrapping({ ...last, files, contents }));
76
+ }
77
+ return { head, part, named };
78
+ }
@@ -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 CHAT_TYPE = "chat";
4
+ export declare const CHAT_MESSAGE_TYPE = "chat-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,SAAS,SAAS,CAAC;AAEhC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,eAAO,MAAM,yBAAyB,UAAiC,CAAC;AAyBxE,eAAO,MAAM,gBAAgB,QA6FjB,CAAC"}
@@ -0,0 +1,125 @@
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 CHAT_TYPE = 'chat';
13
+ export const CHAT_MESSAGE_TYPE = 'chat-message';
14
+ export const HOUSE_NAMEABLE_ROOM_TYPES = [CHAT_TYPE, CHAT_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
+ `${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
+ ' required: [inbox, channel, chat, customer]',
51
+ `${CHAT_MESSAGE_TYPE}:`,
52
+ ' properties:',
53
+ ' direction: { enum: [in, out] }',
54
+ ' sender:',
55
+ ' type: object',
56
+ ' properties:',
57
+ ' name: { type: string }',
58
+ ` username: ${IDENTITY}`,
59
+ ' sent_at: { type: string, format: date-time }',
60
+ ` channel_message: ${IDENTITY}`,
61
+ ' state: { enum: [sending, sent, failed] }',
62
+ ' reason: { type: string }',
63
+ ' labelled: { const: true }',
64
+ ' reactions:',
65
+ ' type: array',
66
+ ' items:',
67
+ ' type: object',
68
+ ' properties:',
69
+ ' reaction: { type: string, minLength: 1 }',
70
+ ' sender:',
71
+ ' type: object',
72
+ ' properties:',
73
+ ` id: ${IDENTITY}`,
74
+ ' name: { type: string }',
75
+ ` username: ${IDENTITY}`,
76
+ ' count: { type: integer, minimum: 1 }',
77
+ ' required: [reaction]',
78
+ ` post: ${IDENTITY}`,
79
+ ' assignee:',
80
+ ...ASSIGNEE,
81
+ ' sent_outside: { const: true }',
82
+ ' template:',
83
+ ' type: object',
84
+ ' properties:',
85
+ ' name: { type: string, minLength: 1 }',
86
+ ' language: { type: string, minLength: 1 }',
87
+ ' required: [name, language]',
88
+ ' values:',
89
+ ' type: object',
90
+ ' additionalProperties: { type: string }',
91
+ ' withheld: { const: true }',
92
+ ' required: [direction]',
93
+ ' if: { properties: { direction: { const: in } } }',
94
+ ' then: { required: [sent_at] }',
95
+ `${WAYFINDING_MAP_TYPE}:`,
96
+ ' properties:',
97
+ ' title: { type: string }',
98
+ ' required: [title]',
99
+ ' sections:',
100
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
101
+ `${WAYFINDING_TICKET_TYPE}:`,
102
+ ' properties:',
103
+ ' title: { type: string }',
104
+ ' kind: { enum: [research, prototype, grilling, task] }',
105
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
106
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
107
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
108
+ ' assignee:',
109
+ ...ASSIGNEE,
110
+ ' conversation: { type: string, format: uuid }',
111
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
112
+ ' required: [title, kind, status, map, blocked_by]',
113
+ ' sections:',
114
+ ' Question: { kind: text }',
115
+ ' Answer: { kind: text }',
116
+ ' allOf:',
117
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
118
+ ' then: { required: [assignee] }',
119
+ ' else: { properties: { assignee: false } }',
120
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
121
+ ' else: { properties: { conversation: false } }',
122
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
123
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
124
+ HOUSE_MODEL_TYPES,
125
+ ].join('\n');
@@ -0,0 +1,5 @@
1
+ import type { SearchAnswer, SearchAsk } from '@agentshouse/mdruntime';
2
+ import type { TrackedAuthority } from './discovery.js';
3
+ import { type HouseTransport } from './transport.js';
4
+ export declare function houseSearch(transport: Pick<HouseTransport, 'door'>, tracked: readonly TrackedAuthority[], request: SearchAsk): Promise<SearchAnswer>;
5
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAsBrE,wBAAsB,WAAW,CAC/B,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,EACvC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,YAAY,CAAC,CAoBvB"}
package/dist/search.js ADDED
@@ -0,0 +1,47 @@
1
+ import { doorRefusal } from './refusal.js';
2
+ import { houseDoorRoute } from './transport.js';
3
+ const ROOMS = '/rooms/';
4
+ const UNCERTAIN = { kind: 'transport-uncertainty' };
5
+ function hitOf(file, locators) {
6
+ if (typeof file !== 'object' || file === null)
7
+ return null;
8
+ const { path, line, snippet } = file;
9
+ if (typeof path !== 'string' || !path.startsWith(ROOMS))
10
+ return null;
11
+ const slash = path.indexOf('/', ROOMS.length);
12
+ if (slash < 0)
13
+ return null;
14
+ const room = locators.get(path.slice(ROOMS.length, slash));
15
+ if (room === undefined)
16
+ return null;
17
+ return {
18
+ room,
19
+ path: path.slice(slash + 1),
20
+ ...(typeof line === 'number' ? { line } : {}),
21
+ ...(typeof snippet === 'string' ? { snippet } : {}),
22
+ };
23
+ }
24
+ export async function houseSearch(transport, tracked, request) {
25
+ const named = request.rooms === null
26
+ ? null
27
+ : tracked.filter((entry) => request.rooms.includes(entry.locator));
28
+ if (named !== null && named.length === 0)
29
+ return { kind: 'found', documents: [] };
30
+ const answer = await transport.door(houseDoorRoute('search'), {
31
+ query: request.text,
32
+ ...(named === null ? {} : { paths: named.map((entry) => `${ROOMS}${entry.handle}`) }),
33
+ });
34
+ if (answer.status === 401)
35
+ return { kind: 'revoked-authorization' };
36
+ const refusal = doorRefusal(answer.body);
37
+ if (refusal !== null)
38
+ return { kind: 'rejected', ...refusal };
39
+ const files = answer.body?.files;
40
+ if (answer.status !== 200 || !Array.isArray(files))
41
+ return UNCERTAIN;
42
+ const locators = new Map(tracked.map((entry) => [entry.handle, entry.locator]));
43
+ return {
44
+ kind: 'found',
45
+ documents: files.flatMap((file) => hitOf(file, locators) ?? []),
46
+ };
47
+ }
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,EAMR,MAAM,wBAAwB,CAAC;AAsBhC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAgCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CAwIxE"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAgBhC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAsL1F"}
package/dist/site.js CHANGED
@@ -1,125 +1,153 @@
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 { scopeModels, streamedModels, viewModels } from './model.js';
4
- import { advancedScope, bootstrapOf, parseEnumeration, parseSiteBootstrap, refreshFrom, viewOf, } from './read.js';
5
- import { classifyDoor, classifyRead, discoveryFailure } 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_TYPED_PATHS } from './house-model.js';
8
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
6
9
  import { houseNotifications } from './stream.js';
7
- import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, } from './transport.js';
8
- import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
10
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITE_SUBMISSION, } from './transport.js';
11
+ import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
9
12
  const UNCERTAIN = { kind: 'transport-uncertainty' };
13
+ function unfound() {
14
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
15
+ }
10
16
  function siteRoom(tracked) {
11
17
  return {
12
18
  name: tracked.handle,
13
19
  locator: tracked.locator,
14
20
  handle: tracked.handle,
15
21
  roomVersion: roomVersion(tracked),
16
- operations: { read: [''], sync: [''], write: [], delete: [] },
17
- replica: { selection: tracked.locator, admission: 'admitted' },
22
+ operations: { write: [], delete: [] },
23
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
18
24
  providerOwnedPaths: [],
19
25
  };
20
26
  }
21
- function settled(refused) {
22
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
23
- }
24
- export function createSiteAdapter(transport) {
25
- const notifications = houseNotifications(transport, 'site');
27
+ export function createSiteAdapter(transport, snapshot = false) {
28
+ const notifications = houseNotifications(transport, 'site', {
29
+ opened: async () => {
30
+ const found = await discovered();
31
+ return found.kind === 'discovery' ? found : null;
32
+ },
33
+ changed: () => null,
34
+ });
26
35
  const tracked = new Map();
27
- async function enumeration(entry, from) {
28
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
29
- positions: [presented(entry.authority, from)],
30
- });
31
- const classified = classifyRead(answer.status, answer.body, entry.locator);
32
- if (classified !== null)
33
- return classified;
34
- return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
36
+ const read = new Map();
37
+ const rooms = roomStreams('site');
38
+ function fileRoute(request) {
39
+ const entry = tracked.get(request.locator);
40
+ if (entry === undefined)
41
+ return { kind: 'room-not-readable', locator: request.locator };
42
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
43
+ }
44
+ async function openedRoom(entry, arriving, signal) {
45
+ const cut = read.get(entry.locator);
46
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`, signal ?? new AbortController().signal);
47
+ if (answered.room === null)
48
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
49
+ const head = await rooms.head(entry, answered.room, arriving, signal);
50
+ const at = head.kind === 'bootstrap' ? logPosition(head.roomVersion) : null;
51
+ if (at !== null)
52
+ read.set(entry.locator, at.position);
53
+ return head;
54
+ }
55
+ async function namedDocument(entry, path, signal) {
56
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}?path=${encodeURIComponent(path)}`, signal ?? new AbortController().signal);
57
+ if (answered.room === null)
58
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
59
+ return rooms.named(entry, answered.room, signal);
35
60
  }
36
- async function caughtUp(entry) {
37
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);
38
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
39
- if (classified !== null)
40
- return { failure: classified };
41
- const scope = parseSiteBootstrap(answer.body);
42
- if (scope === null)
43
- return { failure: UNCERTAIN };
44
- if (roomVersion(scope) === roomVersion(entry))
45
- return { scope };
46
- const found = await enumeration(entry, scope);
47
- if ('kind' in found)
48
- return { failure: settled(found) };
49
- const view = viewOf(found, entry);
50
- if (view === undefined)
51
- return { failure: { kind: 'room-not-readable', locator: entry.locator } };
52
- return { scope: advancedScope(scope, view) };
61
+ async function streamedPage(entry, token) {
62
+ const part = await rooms.part(entry, token);
63
+ if ('kind' in part)
64
+ return part;
65
+ const { folders: _folders, ...page } = await stepped(bootstrapping(part.scope));
66
+ return {
67
+ ...page,
68
+ ...(part.models === undefined ? {} : { models: part.models }),
69
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
70
+ bytes: part.bytes,
71
+ };
53
72
  }
54
- async function refreshed(entry, fromRoomVersion) {
55
- const from = logPosition(fromRoomVersion);
56
- if (from === null)
57
- return { kind: 'beyond-horizon' };
58
- const streamed = notifications.advance(entry, from);
59
- if (streamed !== null) {
60
- const models = await streamedModels(streamed.schemas, entry, 'site');
61
- return models === undefined ? streamed.page : { ...streamed.page, models };
62
- }
63
- const found = await enumeration(entry, from);
64
- if ('kind' in found)
65
- return found;
66
- const view = viewOf(found, entry);
67
- if (view === undefined)
68
- return { kind: 'room-not-readable', locator: entry.locator };
69
- notifications.reach(entry.authority, view);
70
- const answer = refreshFrom(view, fromRoomVersion);
71
- if (answer.kind !== 'net-advancement')
72
- return answer;
73
- const models = await viewModels(view, entry);
74
- return models === undefined ? answer : { ...answer, models };
73
+ async function discovered() {
74
+ const answer = await transport.read(houseSiteRoute('discover'));
75
+ const failed = discoveryFailure(answer.status, answer.body);
76
+ if (failed !== null)
77
+ return failed;
78
+ const document = parseSiteDiscovery(answer.body);
79
+ if (document === null)
80
+ return UNCERTAIN;
81
+ const entries = siteTracked(document);
82
+ tracked.clear();
83
+ for (const entry of entries)
84
+ tracked.set(entry.locator, entry);
85
+ notifications.track(entries);
86
+ return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
75
87
  }
76
88
  return {
77
89
  localSaves: true,
90
+ roomTypes: HOUSE_ROOM_TYPES,
91
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
92
+ typedPaths: HOUSE_TYPED_PATHS,
78
93
  async authorize() {
79
94
  return {};
80
95
  },
81
- async discover() {
82
- const answer = await transport.read(SITE_DOOR_DISCOVER);
83
- const failed = discoveryFailure(answer.status, answer.body);
84
- if (failed !== null)
85
- return failed;
86
- const document = parseSiteDiscovery(answer.body);
87
- if (document === null)
88
- return UNCERTAIN;
89
- const entries = siteTracked(document);
90
- tracked.clear();
91
- for (const entry of entries)
92
- tracked.set(entry.locator, entry);
93
- notifications.track(entries);
94
- return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
95
- },
96
96
  async bootstrap(_authorization, request) {
97
97
  const entry = tracked.get(request.locator);
98
98
  if (entry === undefined)
99
99
  return { kind: 'room-not-readable', locator: request.locator };
100
- if (request.pageToken !== undefined)
101
- return UNCERTAIN;
102
- const held = await caughtUp(entry);
103
- if ('failure' in held)
104
- return held.failure;
105
- notifications.reach(entry.authority, held.scope);
106
- const models = await scopeModels(held.scope, entry);
107
- return { ...bootstrapOf(held.scope), ...(models === undefined ? {} : { models }) };
108
- },
109
- async refresh(_authorization, request) {
110
- const entry = tracked.get(request.locator);
111
- if (entry === undefined)
112
- return { kind: 'room-not-readable', locator: request.locator };
113
- if (request.pageToken !== undefined)
114
- return UNCERTAIN;
115
- return refreshed(entry, request.fromRoomVersion);
100
+ if (request.path !== undefined)
101
+ return namedDocument(entry, request.path, request.signal);
102
+ return request.pageToken === undefined
103
+ ? openedRoom(entry, request.arriving, request.signal)
104
+ : streamedPage(entry, request.pageToken);
116
105
  },
106
+ ...(snapshot
107
+ ? {
108
+ discover: discovered,
109
+ async refresh(_authorization, request) {
110
+ const entry = tracked.get(request.locator);
111
+ if (entry === undefined)
112
+ return { kind: 'room-not-readable', locator: request.locator };
113
+ if (request.pageToken !== undefined)
114
+ return UNCERTAIN;
115
+ return request.fromRoomVersion === roomVersion(entry)
116
+ ? { kind: 'still-current' }
117
+ : { kind: 'beyond-horizon' };
118
+ },
119
+ }
120
+ : {}),
117
121
  async mutate() {
118
122
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
119
123
  },
124
+ async attach() {
125
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
126
+ },
120
127
  async history() {
121
128
  return { kind: 'no-history' };
122
129
  },
130
+ async binary(_authorization, request) {
131
+ const route = fileRoute(request);
132
+ if (typeof route !== 'string')
133
+ return route;
134
+ const read = await transport.download(route);
135
+ if (read.status === 404)
136
+ return unfound();
137
+ return read.status === 200 && read.body !== null
138
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
139
+ : UNCERTAIN;
140
+ },
141
+ async link(_authorization, request) {
142
+ const route = fileRoute(request);
143
+ if (typeof route !== 'string')
144
+ return route;
145
+ return {
146
+ kind: 'link',
147
+ url: route,
148
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
149
+ };
150
+ },
123
151
  reached(locator, version, target) {
124
152
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
125
153
  },
@@ -127,7 +155,7 @@ export function createSiteAdapter(transport) {
127
155
  return followsVersion(version, next);
128
156
  },
129
157
  async action(_authorization, request) {
130
- if (request.name !== 'submit') {
158
+ if (request.name !== SITE_SUBMISSION) {
131
159
  return {
132
160
  kind: 'rejected',
133
161
  code: 'action-unimplemented',
@@ -137,22 +165,20 @@ export function createSiteAdapter(transport) {
137
165
  }
138
166
  if (!transport.online())
139
167
  return UNCERTAIN;
140
- return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), 'submit');
168
+ return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMISSION, request.input);
141
169
  },
142
- roomStream: {
143
- hold(rooms) {
144
- notifications.send(rooms.flatMap((room) => {
145
- const entry = tracked.get(room.locator);
146
- const at = logPosition(room.roomVersion);
147
- if (entry === undefined || at === null)
148
- return [];
149
- notifications.reach(entry.authority, at);
150
- return [presented(entry.authority, at)];
151
- }));
170
+ roomStream: snapshot
171
+ ? undefined
172
+ : {
173
+ hold(rooms) {
174
+ notifications.send(rooms.flatMap((room) => {
175
+ const entry = tracked.get(room.locator);
176
+ const at = logPosition(room.roomVersion);
177
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
178
+ }));
179
+ },
180
+ observe: notifications.observe,
152
181
  },
153
- reopen: notifications.reopen,
154
- observe: notifications.observe,
155
- },
156
182
  serviceMode: notifications.serviceMode,
157
183
  };
158
184
  }
package/dist/stream.d.ts CHANGED
@@ -1,23 +1,23 @@
1
- import type { ConversationStream, RefreshPage, RoomStreamEvent, 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, HouseHeldRoom, 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[];
9
- schemas: ReadonlyMap<string, 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;
10
13
  };
11
14
  export type HouseNotifications = {
12
15
  runtime: string;
13
16
  observe(notify: (event: RoomStreamEvent) => void): () => void;
14
17
  send(rooms: readonly HouseHeldRoom[]): void;
15
- reopen(): void;
16
18
  track(authorities: readonly TrackedAuthority[]): void;
17
- reach(authority: string, at: LogPosition): void;
18
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
19
19
  conversations: ConversationStream;
20
20
  serviceMode: ServiceModeSignal;
21
21
  };
22
- export declare function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications;
22
+ export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering): HouseNotifications;
23
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,EAElB,WAAW,EACX,eAAe,EAEf,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAEhC,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;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;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,GAAG,MAAM,IAAI,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IAC5C,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;AAuBF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAyS5F"}
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;AAYvD,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;AAsFF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,gBAAgB,GAC5B,kBAAkB,CA6TpB"}