@agentshouse/mdruntime-adapter 0.1.0-ca764edcceec6 → 0.1.0-ca7fab027bb19

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 (70) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -66
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +7 -338
  5. package/dist/adapter.d.ts.map +1 -1
  6. package/dist/adapter.js +228 -364
  7. package/dist/app-reference.d.ts +2 -0
  8. package/dist/app-reference.d.ts.map +1 -0
  9. package/dist/app-reference.js +2 -0
  10. package/dist/chunks.d.ts +38 -0
  11. package/dist/chunks.d.ts.map +1 -0
  12. package/dist/chunks.js +247 -0
  13. package/dist/crockford.d.ts +4 -0
  14. package/dist/crockford.d.ts.map +1 -0
  15. package/dist/crockford.js +3 -0
  16. package/dist/discovery.d.ts +23 -15
  17. package/dist/discovery.d.ts.map +1 -1
  18. package/dist/discovery.js +92 -55
  19. package/dist/history.d.ts +12 -0
  20. package/dist/history.d.ts.map +1 -0
  21. package/dist/history.js +92 -0
  22. package/dist/house-model.d.ts +672 -0
  23. package/dist/house-model.d.ts.map +1 -0
  24. package/dist/house-model.js +377 -0
  25. package/dist/index.d.ts +11 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +10 -1
  28. package/dist/model.d.ts +5 -4
  29. package/dist/model.d.ts.map +1 -1
  30. package/dist/model.js +34 -41
  31. package/dist/read.d.ts +57 -64
  32. package/dist/read.d.ts.map +1 -1
  33. package/dist/read.js +154 -318
  34. package/dist/refusal.d.ts +0 -3
  35. package/dist/refusal.d.ts.map +1 -1
  36. package/dist/refusal.js +0 -5
  37. package/dist/room-types.d.ts +5 -0
  38. package/dist/room-types.d.ts.map +1 -0
  39. package/dist/room-types.js +120 -0
  40. package/dist/search.d.ts +5 -0
  41. package/dist/search.d.ts.map +1 -0
  42. package/dist/search.js +47 -0
  43. package/dist/site.d.ts.map +1 -1
  44. package/dist/site.js +81 -200
  45. package/dist/space-schema.d.ts +7 -0
  46. package/dist/space-schema.d.ts.map +1 -0
  47. package/dist/space-schema.js +18 -0
  48. package/dist/stream.d.ts +16 -15
  49. package/dist/stream.d.ts.map +1 -1
  50. package/dist/stream.js +254 -422
  51. package/dist/transport.d.ts +64 -43
  52. package/dist/transport.d.ts.map +1 -1
  53. package/dist/transport.js +54 -11
  54. package/dist/upload.d.ts +12 -0
  55. package/dist/upload.d.ts.map +1 -0
  56. package/dist/upload.js +63 -0
  57. package/dist/write.d.ts +18 -2
  58. package/dist/write.d.ts.map +1 -1
  59. package/dist/write.js +105 -75
  60. package/package.json +8 -4
  61. package/AGENTS.md +0 -299
  62. package/dist/gather.d.ts +0 -4
  63. package/dist/gather.d.ts.map +0 -1
  64. package/dist/gather.js +0 -45
  65. package/dist/handed.d.ts +0 -15
  66. package/dist/handed.d.ts.map +0 -1
  67. package/dist/handed.js +0 -38
  68. package/dist/referrer.d.ts +0 -7
  69. package/dist/referrer.d.ts.map +0 -1
  70. package/dist/referrer.js +0 -35
@@ -0,0 +1,120 @@
1
+ import { CHAT_MESSAGE_TYPE, CHAT_TYPE } from '@agentshouse/mdruntime';
2
+ import { APP_REFERENCE_PATTERN } from './app-reference.js';
3
+ import { HOUSE_MODEL_TYPES } from './house-model.js';
4
+ export const INBOX_CHANNEL_KINDS = [
5
+ 'telegram-bot',
6
+ 'telegram-business',
7
+ 'whatsapp',
8
+ 'messenger',
9
+ 'instagram',
10
+ 'viber',
11
+ 'tiktok',
12
+ ];
13
+ export const HOUSE_NAMEABLE_ROOM_TYPES = [CHAT_TYPE, CHAT_MESSAGE_TYPE];
14
+ const WAYFINDING_MAP_TYPE = 'wayfinding-map';
15
+ const WAYFINDING_TICKET_TYPE = 'wayfinding-ticket';
16
+ const WAYFINDING_MAP_SECTIONS = [
17
+ 'Destination',
18
+ 'Notes',
19
+ 'Decisions so far',
20
+ 'Not yet specified',
21
+ 'Out of scope',
22
+ ];
23
+ const IDENTITY = "{ type: string, pattern: '^\\S+$' }";
24
+ const AGENT = [' agent: { type: string, format: uuid }', ' name: { type: string }'];
25
+ const ASSIGNEE = [
26
+ ' type: object',
27
+ ' properties:',
28
+ ' user: { type: string, format: uuid }',
29
+ ...AGENT,
30
+ ];
31
+ export const HOUSE_ROOM_TYPES = [
32
+ `${CHAT_TYPE}:`,
33
+ ' properties:',
34
+ ' inbox: { type: string, format: uuid }',
35
+ ` channel: { enum: [${INBOX_CHANNEL_KINDS.join(', ')}] }`,
36
+ ` chat: ${IDENTITY}`,
37
+ ' customer:',
38
+ ' type: object',
39
+ ' properties:',
40
+ ' name: { type: string }',
41
+ ` username: ${IDENTITY}`,
42
+ ` phone: ${IDENTITY}`,
43
+ ' assignee:',
44
+ ...ASSIGNEE,
45
+ ' return_to:',
46
+ ' type: object',
47
+ ' properties:',
48
+ ...AGENT,
49
+ ' required: [chat, customer]',
50
+ `${CHAT_MESSAGE_TYPE}:`,
51
+ ' properties:',
52
+ ' direction: { enum: [in, out] }',
53
+ ' sender:',
54
+ ...ASSIGNEE,
55
+ ` username: ${IDENTITY}`,
56
+ ' sent_at: { type: string, format: date-time }',
57
+ ` channel_message: ${IDENTITY}`,
58
+ ' labelled: { const: true }',
59
+ ' reactions:',
60
+ ' type: array',
61
+ ' items:',
62
+ ' type: object',
63
+ ' properties:',
64
+ ' reaction: { type: string, minLength: 1 }',
65
+ ' sender:',
66
+ ' type: object',
67
+ ' properties:',
68
+ ` id: ${IDENTITY}`,
69
+ ' name: { type: string }',
70
+ ` username: ${IDENTITY}`,
71
+ ' count: { type: integer, minimum: 1 }',
72
+ ' required: [reaction]',
73
+ ` post: ${IDENTITY}`,
74
+ ' assignee:',
75
+ ...ASSIGNEE,
76
+ ' sent_outside: { const: true }',
77
+ ' template:',
78
+ ' type: object',
79
+ ' properties:',
80
+ ' name: { type: string, minLength: 1 }',
81
+ ' language: { type: string, minLength: 1 }',
82
+ ' required: [name, language]',
83
+ ' values:',
84
+ ' type: object',
85
+ ' additionalProperties: { type: string }',
86
+ ' withheld: { const: true }',
87
+ ' required: [direction]',
88
+ ' if: { properties: { direction: { const: in } } }',
89
+ ' then: { required: [sent_at] }',
90
+ `${WAYFINDING_MAP_TYPE}:`,
91
+ ' properties:',
92
+ ' title: { type: string }',
93
+ ' required: [title]',
94
+ ' sections:',
95
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
96
+ `${WAYFINDING_TICKET_TYPE}:`,
97
+ ' properties:',
98
+ ' title: { type: string }',
99
+ ' kind: { enum: [research, prototype, grilling, task] }',
100
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
101
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
102
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
103
+ ' assignee:',
104
+ ...ASSIGNEE,
105
+ ' conversation: { type: string, format: uuid }',
106
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
107
+ ' required: [title, kind, status, map, blocked_by]',
108
+ ' sections:',
109
+ ' Question: { kind: text }',
110
+ ' Answer: { kind: text }',
111
+ ' allOf:',
112
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
113
+ ' then: { required: [assignee] }',
114
+ ' else: { properties: { assignee: false } }',
115
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
116
+ ' else: { properties: { conversation: false } }',
117
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
118
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
119
+ HOUSE_MODEL_TYPES,
120
+ ].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('rooms/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
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAUR,MAAM,wBAAwB,CAAC;AA2BhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAyCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAyR1F"}
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,CAiK1F"}
package/dist/site.js CHANGED
@@ -1,13 +1,13 @@
1
- import { actionOutcome, SITE_SUBMIT } from './actions.js';
1
+ import { actionOutcome } from './actions.js';
2
+ import { chunkedHead, chunkPart, siteChunkList } from './chunks.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';
6
- import { classifyDoor, classifyRead, discoveryFailure } from './refusal.js';
4
+ import { spaceSchemas } from './space-schema.js';
5
+ import { discoveryFailure } from './refusal.js';
6
+ import { HOUSE_TYPED_PATHS } from './house-model.js';
7
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
7
8
  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 { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
9
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITES_SUBMISSIONS_CREATE, } from './transport.js';
10
+ import { followsVersion, reachedVersion, roomVersion } from './version.js';
11
11
  const UNCERTAIN = { kind: 'transport-uncertainty' };
12
12
  function unfound() {
13
13
  return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
@@ -18,197 +18,100 @@ function siteRoom(tracked) {
18
18
  locator: tracked.locator,
19
19
  handle: tracked.handle,
20
20
  roomVersion: roomVersion(tracked),
21
- operations: { read: [''], sync: [''], write: [], delete: [] },
22
- replica: { selection: tracked.locator, admission: 'admitted' },
21
+ operations: { write: [], erase: [] },
22
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
23
23
  providerOwnedPaths: [],
24
24
  };
25
25
  }
26
- function settled(refused) {
27
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
28
- }
29
26
  export function createSiteAdapter(transport, snapshot = false) {
30
- const notifications = houseNotifications(transport, 'site');
27
+ const spaces = spaceSchemas();
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
+ }, spaces);
31
35
  const tracked = new Map();
32
- function published(referrer) {
33
- const named = houseReferrer(referrer, tracked);
34
- return named === null || !tracked.has(named.locator) ? null : named;
35
- }
36
+ const chunked = new Map();
36
37
  function fileRoute(request) {
37
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
38
- if (named === null) {
39
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
40
- }
41
- if (request.fileRef === undefined)
42
- return unfound();
43
- const { room_ref, path, record } = named.referrer;
44
- return `${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
45
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
46
- : encodeURIComponent(path)}`;
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)}`;
47
42
  }
48
- async function enumerated(entry, from, page) {
49
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
50
- positions: [
51
- page === undefined
52
- ? presented(entry.authority, from)
53
- : {
54
- ...presented(entry.authority, { position: page.after, logEpoch: from.logEpoch }),
55
- page: { through: page.through, read: page.read },
56
- },
57
- ],
58
- });
59
- const classified = classifyRead(answer.status, answer.body, entry.locator);
60
- if (classified !== null)
61
- return classified;
62
- const found = parseEnumeration(answer.body, 'site');
63
- if (found === null)
64
- return UNCERTAIN;
65
- return viewOf(found, entry) ?? { kind: 'room-not-readable', locator: entry.locator };
43
+ async function listedRoom(entry) {
44
+ const past = chunked.get(entry.locator)?.position;
45
+ const listed = siteChunkList(await transport.read(`${houseSiteRoute('chunks')}/${entry.authority}${past === undefined ? '' : `?expired=${past}`}`), entry.locator);
46
+ if ('kind' in listed)
47
+ return listed;
48
+ const head = await chunkedHead(listed, entry, spaces);
49
+ if (head.kind === 'bootstrap')
50
+ chunked.set(entry.locator, listed);
51
+ return head;
66
52
  }
67
- async function enumeration(entry, from) {
68
- const first = await enumerated(entry, from);
69
- return 'kind' in first ? first : wholeView(first, (page) => enumerated(entry, from, page));
70
- }
71
- async function bootstrapPart(entry, after, offset) {
72
- const query = [
73
- ...(after === null ? [] : [`after=${encodeURIComponent(after)}`]),
74
- ...(offset === null ? [] : [`offset=${offset}`]),
75
- ];
76
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}${query.length === 0 ? '' : `?${query.join('&')}`}`);
77
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
78
- if (classified !== null)
79
- return { failure: classified };
80
- const scope = parseSiteBootstrap(answer.body);
81
- return scope === null ? { failure: UNCERTAIN } : { body: answer.body, scope };
82
- }
83
- async function assembled(entry, scope, path, offset) {
84
- const opened = scope.contents.at(-1);
85
- if (opened === undefined || opened.path !== path || opened.content.length !== offset) {
53
+ async function chunkPage(entry, id, arriving) {
54
+ const room = chunked.get(entry.locator);
55
+ const address = room?.chunks.get(id);
56
+ if (room === undefined || address === undefined)
86
57
  return UNCERTAIN;
87
- }
88
- let text = opened.content;
89
- for (;;) {
90
- const part = await bootstrapPart(entry, path, text.length);
91
- if ('failure' in part)
92
- return part.failure;
93
- const [piece] = part.scope.contents;
94
- if (piece === undefined ||
95
- part.scope.contents.length !== 1 ||
96
- piece.path !== path ||
97
- piece.content.length === 0) {
98
- return UNCERTAIN;
99
- }
100
- text += piece.content;
101
- const more = siteBootstrapOffset(part.body);
102
- if (more === null)
103
- break;
104
- if (more !== text.length)
105
- return UNCERTAIN;
106
- }
107
- const file = scope.files.find((held) => held.path === path);
108
- if (file === undefined || (await sha256Hex(text)) !== file.version)
58
+ const read = await transport.download(address.url);
59
+ if (read.status !== 200)
109
60
  return UNCERTAIN;
110
- return { ...scope, contents: [...scope.contents.slice(0, -1), { path, content: text }] };
111
- }
112
- async function caughtUp(entry, after) {
113
- const part = await bootstrapPart(entry, after, null);
114
- if ('failure' in part)
115
- return part;
116
- const next = siteBootstrapNext(part.body);
117
- const offset = siteBootstrapOffset(part.body);
118
- if (offset !== null) {
119
- if (next === null)
120
- return { failure: UNCERTAIN };
121
- const scope = await assembled(entry, part.scope, next, offset);
122
- return 'kind' in scope ? { failure: scope } : { scope, next };
123
- }
124
- const { scope } = part;
125
- if (after !== null || next !== null || roomVersion(scope) === roomVersion(entry)) {
126
- return { scope, next };
127
- }
128
- const view = await enumeration(entry, scope);
129
- if ('kind' in view)
130
- return { failure: settled(view) };
131
- return { scope: advancedScope(scope, view), next: null };
61
+ return chunkPart(read.body, room, id, arriving);
132
62
  }
133
- async function refreshed(entry, fromRoomVersion) {
134
- const from = logPosition(fromRoomVersion);
135
- if (from === null)
136
- return { kind: 'beyond-horizon' };
137
- const streamed = notifications.advance(entry, from);
138
- if (streamed !== null) {
139
- const models = await streamedModels(streamed.schemas, entry, 'site');
140
- return models === undefined ? streamed.page : { ...streamed.page, models };
141
- }
142
- const view = await enumeration(entry, from);
143
- if ('kind' in view)
144
- return view;
145
- notifications.reach(entry.authority, view);
146
- const answer = refreshFrom(view, fromRoomVersion);
147
- if (answer.kind !== 'net-advancement')
148
- return answer;
149
- const models = await viewModels(view, entry);
150
- return models === undefined ? answer : { ...answer, models };
63
+ async function discovered() {
64
+ const answer = await transport.read(houseSiteRoute('discover'));
65
+ const failed = discoveryFailure(answer.status, answer.body);
66
+ if (failed !== null)
67
+ return failed;
68
+ const document = parseSiteDiscovery(answer.body);
69
+ if (document === null)
70
+ return UNCERTAIN;
71
+ const entries = siteTracked(document);
72
+ tracked.clear();
73
+ for (const entry of entries)
74
+ tracked.set(entry.locator, entry);
75
+ notifications.track(entries);
76
+ return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
151
77
  }
152
78
  return {
153
79
  localSaves: true,
154
- exhaustiveDiscovery: true,
80
+ roomTypes: HOUSE_ROOM_TYPES,
81
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
82
+ typedPaths: HOUSE_TYPED_PATHS,
155
83
  async authorize() {
156
84
  return {};
157
85
  },
158
- async discover() {
159
- const answer = await transport.read(SITE_DOOR_DISCOVER);
160
- const failed = discoveryFailure(answer.status, answer.body);
161
- if (failed !== null)
162
- return failed;
163
- const document = parseSiteDiscovery(answer.body);
164
- if (document === null)
165
- return UNCERTAIN;
166
- const entries = siteTracked(document);
167
- tracked.clear();
168
- for (const entry of entries)
169
- tracked.set(entry.locator, entry);
170
- notifications.track(entries);
171
- return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
172
- },
173
86
  async bootstrap(_authorization, request) {
174
87
  const entry = tracked.get(request.locator);
175
88
  if (entry === undefined)
176
89
  return { kind: 'room-not-readable', locator: request.locator };
177
- const continued = request.pageToken === undefined
178
- ? null
179
- : JSON.parse(request.pageToken);
180
- const held = await caughtUp(entry, continued?.after ?? null);
181
- if ('failure' in held)
182
- return held.failure;
183
- notifications.reach(entry.authority, held.scope);
184
- const seen = [
185
- ...(continued?.seen ?? []),
186
- ...entry.schemas.filter((schema) => held.scope.files.some((file) => file.path === schema)),
187
- ];
188
- const models = await partModels(held.scope, entry, new Set(seen), held.next === null);
189
- const continuation = held.next === null ? null : { after: held.next, seen };
190
- return {
191
- ...bootstrapOf(held.scope),
192
- ...(models === undefined ? {} : { models }),
193
- ...(continuation === null ? {} : { pageToken: JSON.stringify(continuation) }),
194
- };
90
+ return request.pageToken === undefined
91
+ ? listedRoom(entry)
92
+ : chunkPage(entry, request.pageToken, request.arriving);
195
93
  },
196
- async refresh(_authorization, request) {
197
- const entry = tracked.get(request.locator);
198
- if (entry === undefined)
199
- return { kind: 'room-not-readable', locator: request.locator };
200
- if (request.pageToken !== undefined)
201
- return UNCERTAIN;
202
- if (snapshot) {
203
- return request.fromRoomVersion === roomVersion(entry)
204
- ? { kind: 'still-current' }
205
- : { kind: 'beyond-horizon' };
94
+ ...(snapshot
95
+ ? {
96
+ discover: discovered,
97
+ async refresh(_authorization, request) {
98
+ const entry = tracked.get(request.locator);
99
+ if (entry === undefined)
100
+ return { kind: 'room-not-readable', locator: request.locator };
101
+ if (request.pageToken !== undefined)
102
+ return UNCERTAIN;
103
+ return request.fromRoomVersion === roomVersion(entry)
104
+ ? { kind: 'still-current' }
105
+ : { kind: 'beyond-horizon' };
106
+ },
206
107
  }
207
- return refreshed(entry, request.fromRoomVersion);
208
- },
108
+ : {}),
209
109
  async mutate() {
210
110
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
211
111
  },
112
+ async attach() {
113
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
114
+ },
212
115
  async history() {
213
116
  return { kind: 'no-history' };
214
117
  },
@@ -219,8 +122,8 @@ export function createSiteAdapter(transport, snapshot = false) {
219
122
  const read = await transport.download(route);
220
123
  if (read.status === 404)
221
124
  return unfound();
222
- return read.status === 200 && read.blob !== null
223
- ? { kind: 'binary', blob: read.blob }
125
+ return read.status === 200 && read.body !== null
126
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
224
127
  : UNCERTAIN;
225
128
  },
226
129
  async link(_authorization, request) {
@@ -233,13 +136,6 @@ export function createSiteAdapter(transport, snapshot = false) {
233
136
  name: request.path.slice(request.path.lastIndexOf('/') + 1),
234
137
  };
235
138
  },
236
- referrerScope(referrer) {
237
- const named = published(referrer);
238
- if (named === null)
239
- return null;
240
- const { path } = named.referrer;
241
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
242
- },
243
139
  reached(locator, version, target) {
244
140
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
245
141
  },
@@ -247,7 +143,7 @@ export function createSiteAdapter(transport, snapshot = false) {
247
143
  return followsVersion(version, next);
248
144
  },
249
145
  async action(_authorization, request) {
250
- if (request.name !== SITE_SUBMIT) {
146
+ if (request.name !== SITES_SUBMISSIONS_CREATE) {
251
147
  return {
252
148
  kind: 'rejected',
253
149
  code: 'action-unimplemented',
@@ -257,28 +153,13 @@ export function createSiteAdapter(transport, snapshot = false) {
257
153
  }
258
154
  if (!transport.online())
259
155
  return UNCERTAIN;
260
- return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
156
+ return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITES_SUBMISSIONS_CREATE, request.input);
261
157
  },
262
158
  roomStream: snapshot
263
159
  ? undefined
264
160
  : {
265
- hold(rooms) {
266
- notifications.send(rooms.flatMap((room) => {
267
- const entry = tracked.get(room.locator);
268
- const at = logPosition(room.roomVersion);
269
- if (entry === undefined || at === null)
270
- return [];
271
- notifications.reach(entry.authority, at);
272
- return [presented(entry.authority, at)];
273
- }), null);
274
- },
275
- reopen: notifications.reopen,
161
+ hold: notifications.send,
276
162
  observe: notifications.observe,
277
- published(locator, roomVersion) {
278
- const at = logPosition(roomVersion);
279
- if (at !== null)
280
- notifications.published(locator, at);
281
- },
282
163
  },
283
164
  serviceMode: notifications.serviceMode,
284
165
  };
@@ -0,0 +1,7 @@
1
+ export type SpaceSchemas = {
2
+ held(space: string, revision: string): string | undefined;
3
+ keep(space: string, revision: string, text: string): void;
4
+ };
5
+ export declare function spaceSchemas(): SpaceSchemas;
6
+ export declare function spaceIdentity(space: string): string;
7
+ //# sourceMappingURL=space-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-schema.d.ts","sourceRoot":"","sources":["../src/space-schema.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D,CAAC;AAEF,wBAAgB,YAAY,IAAI,YAAY,CAY3C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,18 @@
1
+ const HELD_TEXTS = 16;
2
+ export function spaceSchemas() {
3
+ const texts = new Map();
4
+ const key = (space, revision) => `${space} ${revision}`;
5
+ return {
6
+ held: (space, revision) => texts.get(key(space, revision)),
7
+ keep(space, revision, text) {
8
+ const named = key(space, revision);
9
+ texts.delete(named);
10
+ texts.set(named, text);
11
+ if (texts.size > HELD_TEXTS)
12
+ texts.delete(texts.keys().next().value);
13
+ },
14
+ };
15
+ }
16
+ export function spaceIdentity(space) {
17
+ return `space:${space}`;
18
+ }
package/dist/stream.d.ts CHANGED
@@ -1,24 +1,25 @@
1
- import type { ConversationStream, RefreshPage, RoomStreamEvent, ServiceModeSignal, StreamReceipts } from '@agentshouse/mdruntime';
1
+ import { type AuthorityChange, type Discovery, type ConversationStream, type HeldRoom, type RoomStreamEvent, type ServiceModeSignal } from '@agentshouse/mdruntime';
2
2
  import type { TrackedAuthority } from './discovery.js';
3
- import type { HouseDemand, 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 { SpaceSchemas } from './space-schema.js';
4
+ import { type HouseDoor, type HouseMode, type HouseStreamFrame } from './transport.js';
5
+ export type HouseOpeningFrame = Extract<HouseStreamFrame, {
6
+ type: 'opening';
7
+ }>;
8
+ export type HouseAuthorityChangedFrame = Extract<HouseStreamFrame, {
9
+ type: 'authority_changed';
10
+ }>;
11
+ export type HouseDiscovering = {
12
+ opened(frame: HouseOpeningFrame | null): Promise<Discovery | null>;
13
+ changed(frame: HouseAuthorityChangedFrame): AuthorityChange | null;
14
+ expired?(authorities: readonly string[]): void;
10
15
  };
11
16
  export type HouseNotifications = {
12
17
  runtime: string;
13
- observe(notify: (event: RoomStreamEvent) => void, receipts: StreamReceipts): () => void;
14
- send(rooms: readonly HouseHeldRoom[], demand: HouseDemand | null): void;
15
- published(locator: string, at: LogPosition): void;
16
- reopen(): void;
18
+ observe(notify: (event: RoomStreamEvent) => void): () => void;
19
+ send(rooms: readonly HeldRoom[]): void;
17
20
  track(authorities: readonly TrackedAuthority[]): void;
18
- reach(authority: string, at: LogPosition): void;
19
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
20
21
  conversations: ConversationStream;
21
22
  serviceMode: ServiceModeSignal;
22
23
  };
23
- export declare function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications;
24
+ export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering, spaces: SpaceSchemas): HouseNotifications;
24
25
  //# sourceMappingURL=stream.d.ts.map
@@ -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,WAAW,EACX,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,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC;IACxE,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,CAwhB5F"}
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,EAEvB,KAAK,QAAQ,EAGb,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWtD,OAAO,EAEL,KAAK,SAAS,EAEd,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;IACnE,OAAO,CAAC,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,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,QAAQ,EAAE,GAAG,IAAI,CAAC;IACvC,KAAK,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACtD,aAAa,EAAE,kBAAkB,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AA6FF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,gBAAgB,EAC7B,MAAM,EAAE,YAAY,GACnB,kBAAkB,CA8XpB"}