@agentshouse/mdruntime-adapter 0.1.0-cafd7caa7ae65 → 0.1.0-cb0bbc4ccacd0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +2 -2
  2. package/dist/actions.d.ts +4 -65
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +8 -347
  5. package/dist/adapter.d.ts +1 -0
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +257 -277
  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 +24 -14
  15. package/dist/discovery.d.ts.map +1 -1
  16. package/dist/discovery.js +93 -54
  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 +641 -0
  21. package/dist/house-model.d.ts.map +1 -0
  22. package/dist/house-model.js +361 -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 +8 -4
  27. package/dist/model.d.ts.map +1 -1
  28. package/dist/model.js +36 -36
  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 +58 -43
  33. package/dist/read.d.ts.map +1 -1
  34. package/dist/read.js +245 -204
  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 +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 +123 -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 +120 -131
  50. package/dist/space-schema.d.ts +7 -0
  51. package/dist/space-schema.d.ts.map +1 -0
  52. package/dist/space-schema.js +18 -0
  53. package/dist/stream.d.ts +13 -12
  54. package/dist/stream.d.ts.map +1 -1
  55. package/dist/stream.js +209 -158
  56. package/dist/transport.d.ts +85 -25
  57. package/dist/transport.d.ts.map +1 -1
  58. package/dist/transport.js +54 -11
  59. package/dist/upload.d.ts +12 -0
  60. package/dist/upload.d.ts.map +1 -0
  61. package/dist/upload.js +63 -0
  62. package/dist/version.d.ts +1 -0
  63. package/dist/version.d.ts.map +1 -1
  64. package/dist/version.js +1 -1
  65. package/dist/write.d.ts +18 -2
  66. package/dist/write.d.ts.map +1 -1
  67. package/dist/write.js +105 -71
  68. package/package.json +8 -4
  69. package/AGENTS.md +0 -302
  70. package/dist/gather.d.ts +0 -4
  71. package/dist/gather.d.ts.map +0 -1
  72. package/dist/gather.js +0 -45
  73. package/dist/handed.d.ts +0 -15
  74. package/dist/handed.d.ts.map +0 -1
  75. package/dist/handed.js +0 -38
  76. package/dist/referrer.d.ts +0 -7
  77. package/dist/referrer.d.ts.map +0 -1
  78. package/dist/referrer.js +0 -35
@@ -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,QA2FjB,CAAC"}
@@ -0,0 +1,123 @@
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: [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
+ ' labelled: { const: true }',
62
+ ' reactions:',
63
+ ' type: array',
64
+ ' items:',
65
+ ' type: object',
66
+ ' properties:',
67
+ ' reaction: { type: string, minLength: 1 }',
68
+ ' sender:',
69
+ ' type: object',
70
+ ' properties:',
71
+ ` id: ${IDENTITY}`,
72
+ ' name: { type: string }',
73
+ ` username: ${IDENTITY}`,
74
+ ' count: { type: integer, minimum: 1 }',
75
+ ' required: [reaction]',
76
+ ` post: ${IDENTITY}`,
77
+ ' assignee:',
78
+ ...ASSIGNEE,
79
+ ' sent_outside: { const: true }',
80
+ ' template:',
81
+ ' type: object',
82
+ ' properties:',
83
+ ' name: { type: string, minLength: 1 }',
84
+ ' language: { type: string, minLength: 1 }',
85
+ ' required: [name, language]',
86
+ ' values:',
87
+ ' type: object',
88
+ ' additionalProperties: { type: string }',
89
+ ' withheld: { const: true }',
90
+ ' required: [direction]',
91
+ ' if: { properties: { direction: { const: in } } }',
92
+ ' then: { required: [sent_at] }',
93
+ `${WAYFINDING_MAP_TYPE}:`,
94
+ ' properties:',
95
+ ' title: { type: string }',
96
+ ' required: [title]',
97
+ ' sections:',
98
+ ...WAYFINDING_MAP_SECTIONS.map((name) => ` ${name}: { kind: text, required: true }`),
99
+ `${WAYFINDING_TICKET_TYPE}:`,
100
+ ' properties:',
101
+ ' title: { type: string }',
102
+ ' kind: { enum: [research, prototype, grilling, task] }',
103
+ ' status: { enum: [open, in-progress, done, out-of-scope] }',
104
+ ` map: { type: string, reference: ${WAYFINDING_MAP_TYPE} }`,
105
+ ` blocked_by: { type: array, items: { type: string, reference: ${WAYFINDING_TICKET_TYPE} } }`,
106
+ ' assignee:',
107
+ ...ASSIGNEE,
108
+ ' conversation: { type: string, format: uuid }',
109
+ ` app: { type: string, pattern: '${APP_REFERENCE_PATTERN.source}' }`,
110
+ ' required: [title, kind, status, map, blocked_by]',
111
+ ' sections:',
112
+ ' Question: { kind: text }',
113
+ ' Answer: { kind: text }',
114
+ ' allOf:',
115
+ ' - if: { properties: { status: { enum: [in-progress, done, out-of-scope] } }, required: [status] }',
116
+ ' then: { required: [assignee] }',
117
+ ' else: { properties: { assignee: false } }',
118
+ ' - if: { properties: { assignee: { required: [agent] } }, required: [assignee] }',
119
+ ' else: { properties: { conversation: false } }',
120
+ ' - if: { properties: { status: { enum: [done, out-of-scope] } }, required: [status] }',
121
+ ' then: { sections: { Answer: { kind: text, required: true } } }',
122
+ HOUSE_MODEL_TYPES,
123
+ ].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,EAOR,MAAM,wBAAwB,CAAC;AAsBhC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAiCxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,CA8KxE"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAQR,MAAM,wBAAwB,CAAC;AAiBhC,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAuBxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,UAAQ,GAAG,OAAO,CA6K1F"}
package/dist/site.js CHANGED
@@ -1,155 +1,146 @@
1
- import { actionOutcome, SITE_SUBMIT } from './actions.js';
1
+ import { stepped } from '@agentshouse/mdruntime';
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 { spaceSchemas } from './space-schema.js';
7
+ import { classifyDoor, discoveryFailure } from './refusal.js';
8
+ import { HOUSE_TYPED_PATHS } from './house-model.js';
9
+ import { HOUSE_NAMEABLE_ROOM_TYPES, HOUSE_ROOM_TYPES } from './room-types.js';
6
10
  import { houseNotifications } from './stream.js';
7
- import { SITE_DOOR_BOOTSTRAP, SITE_DOOR_DISCOVER, SITE_DOOR_ENUMERATE, SITE_DOOR_SUBMIT, SITE_FILE_RECORD, SITE_FILES, } from './transport.js';
8
- import { houseReferrer } from './referrer.js';
9
- import { followsVersion, logPosition, presented, reachedVersion, roomVersion, } from './version.js';
11
+ import { houseSiteRoute, SITE_DOOR_SUBMIT, SITE_FILES, SITE_SUBMISSION, } from './transport.js';
12
+ import { followsVersion, logPosition, presented, reachedVersion, roomVersion } from './version.js';
10
13
  const UNCERTAIN = { kind: 'transport-uncertainty' };
14
+ function unfound() {
15
+ return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
16
+ }
11
17
  function siteRoom(tracked) {
12
18
  return {
13
19
  name: tracked.handle,
14
20
  locator: tracked.locator,
15
21
  handle: tracked.handle,
16
22
  roomVersion: roomVersion(tracked),
17
- operations: { read: [''], sync: [''], write: [], delete: [] },
18
- replica: { selection: tracked.locator, admission: 'admitted' },
23
+ operations: { write: [], erase: [] },
24
+ replica: { selection: tracked.locator, admission: 'admitted', offline: 'open' },
19
25
  providerOwnedPaths: [],
20
26
  };
21
27
  }
22
- function settled(refused) {
23
- return refused.kind === 'beyond-horizon' ? UNCERTAIN : refused;
24
- }
25
- export function createSiteAdapter(transport) {
26
- const notifications = houseNotifications(transport, 'site');
28
+ export function createSiteAdapter(transport, snapshot = false) {
29
+ const spaces = spaceSchemas();
30
+ const notifications = houseNotifications(transport, 'site', {
31
+ opened: async () => {
32
+ const found = await discovered();
33
+ return found.kind === 'discovery' ? found : null;
34
+ },
35
+ changed: () => null,
36
+ }, spaces);
27
37
  const tracked = new Map();
28
- function published(referrer) {
29
- const named = houseReferrer(referrer, tracked);
30
- return named === null || !tracked.has(named.locator) ? null : named;
38
+ const read = new Map();
39
+ const rooms = roomStreams('site', spaces);
40
+ function fileRoute(request) {
41
+ const entry = tracked.get(request.locator);
42
+ if (entry === undefined)
43
+ return { kind: 'room-not-readable', locator: request.locator };
44
+ return `${SITE_FILES}${entry.authority}/${encodeURIComponent(request.revision)}/${encodeURIComponent(request.path)}`;
31
45
  }
32
- async function enumeration(entry, from) {
33
- const answer = await transport.door(SITE_DOOR_ENUMERATE, {
34
- positions: [presented(entry.authority, from)],
35
- });
36
- const classified = classifyRead(answer.status, answer.body, entry.locator);
37
- if (classified !== null)
38
- return classified;
39
- return parseEnumeration(answer.body, 'site') ?? UNCERTAIN;
46
+ async function openedRoom(entry, arriving, signal) {
47
+ const cut = read.get(entry.locator);
48
+ const answered = await transport.streamed(`${houseSiteRoute('bootstrap')}/${entry.authority}${cut === undefined ? '' : `?expired=${cut}`}`, signal ?? new AbortController().signal);
49
+ if (answered.room === null)
50
+ return classifyDoor(answered.status, answered.body, entry.locator) ?? UNCERTAIN;
51
+ const head = await rooms.head(entry, answered.room, arriving, signal);
52
+ const at = head.kind === 'bootstrap' ? logPosition(head.roomVersion) : null;
53
+ if (at !== null)
54
+ read.set(entry.locator, at.position);
55
+ return head;
40
56
  }
41
- async function caughtUp(entry) {
42
- const answer = await transport.read(`${SITE_DOOR_BOOTSTRAP}${entry.authority}`);
43
- const classified = classifyDoor(answer.status, answer.body, entry.locator);
44
- if (classified !== null)
45
- return { failure: classified };
46
- const scope = parseSiteBootstrap(answer.body);
47
- if (scope === null)
48
- return { failure: UNCERTAIN };
49
- if (roomVersion(scope) === roomVersion(entry))
50
- return { scope };
51
- const found = await enumeration(entry, scope);
52
- if ('kind' in found)
53
- return { failure: settled(found) };
54
- const view = viewOf(found, entry);
55
- if (view === undefined)
56
- return { failure: { kind: 'room-not-readable', locator: entry.locator } };
57
- return { scope: advancedScope(scope, view) };
57
+ async function streamedPage(entry, token) {
58
+ const part = await rooms.part(entry, token);
59
+ if ('kind' in part)
60
+ return part;
61
+ const { folders: _folders, ...page } = await stepped(bootstrapping(part.scope));
62
+ return {
63
+ ...page,
64
+ ...(part.models === undefined ? {} : { models: part.models }),
65
+ ...(part.pageToken === undefined ? {} : { pageToken: part.pageToken }),
66
+ bytes: part.bytes,
67
+ };
58
68
  }
59
- async function refreshed(entry, fromRoomVersion) {
60
- const from = logPosition(fromRoomVersion);
61
- if (from === null)
62
- return { kind: 'beyond-horizon' };
63
- const streamed = notifications.advance(entry, from);
64
- if (streamed !== null) {
65
- const models = await streamedModels(streamed.schemas, entry, 'site');
66
- return models === undefined ? streamed.page : { ...streamed.page, models };
67
- }
68
- const found = await enumeration(entry, from);
69
- if ('kind' in found)
70
- return found;
71
- const view = viewOf(found, entry);
72
- if (view === undefined)
73
- return { kind: 'room-not-readable', locator: entry.locator };
74
- notifications.reach(entry.authority, view);
75
- const answer = refreshFrom(view, fromRoomVersion);
76
- if (answer.kind !== 'net-advancement')
77
- return answer;
78
- const models = await viewModels(view, entry);
79
- return models === undefined ? answer : { ...answer, models };
69
+ async function discovered() {
70
+ const answer = await transport.read(houseSiteRoute('discover'));
71
+ const failed = discoveryFailure(answer.status, answer.body);
72
+ if (failed !== null)
73
+ return failed;
74
+ const document = parseSiteDiscovery(answer.body);
75
+ if (document === null)
76
+ return UNCERTAIN;
77
+ const entries = siteTracked(document);
78
+ tracked.clear();
79
+ for (const entry of entries)
80
+ tracked.set(entry.locator, entry);
81
+ notifications.track(entries);
82
+ return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
80
83
  }
81
84
  return {
82
85
  localSaves: true,
86
+ roomTypes: HOUSE_ROOM_TYPES,
87
+ nameableRoomTypes: HOUSE_NAMEABLE_ROOM_TYPES,
88
+ typedPaths: HOUSE_TYPED_PATHS,
83
89
  async authorize() {
84
90
  return {};
85
91
  },
86
- async discover() {
87
- const answer = await transport.read(SITE_DOOR_DISCOVER);
88
- const failed = discoveryFailure(answer.status, answer.body);
89
- if (failed !== null)
90
- return failed;
91
- const document = parseSiteDiscovery(answer.body);
92
- if (document === null)
93
- return UNCERTAIN;
94
- const entries = siteTracked(document);
95
- tracked.clear();
96
- for (const entry of entries)
97
- tracked.set(entry.locator, entry);
98
- notifications.track(entries);
99
- return mapDiscovery(document, entries.map(siteRoom), siteCapabilities());
100
- },
101
92
  async bootstrap(_authorization, request) {
102
93
  const entry = tracked.get(request.locator);
103
94
  if (entry === undefined)
104
95
  return { kind: 'room-not-readable', locator: request.locator };
105
- if (request.pageToken !== undefined)
106
- return UNCERTAIN;
107
- const held = await caughtUp(entry);
108
- if ('failure' in held)
109
- return held.failure;
110
- notifications.reach(entry.authority, held.scope);
111
- const models = await scopeModels(held.scope, entry);
112
- return { ...bootstrapOf(held.scope), ...(models === undefined ? {} : { models }) };
113
- },
114
- async refresh(_authorization, request) {
115
- const entry = tracked.get(request.locator);
116
- if (entry === undefined)
117
- return { kind: 'room-not-readable', locator: request.locator };
118
- if (request.pageToken !== undefined)
119
- return UNCERTAIN;
120
- return refreshed(entry, request.fromRoomVersion);
96
+ return request.pageToken === undefined
97
+ ? openedRoom(entry, request.arriving, request.signal)
98
+ : streamedPage(entry, request.pageToken);
121
99
  },
100
+ ...(snapshot
101
+ ? {
102
+ discover: discovered,
103
+ async refresh(_authorization, request) {
104
+ const entry = tracked.get(request.locator);
105
+ if (entry === undefined)
106
+ return { kind: 'room-not-readable', locator: request.locator };
107
+ if (request.pageToken !== undefined)
108
+ return UNCERTAIN;
109
+ return request.fromRoomVersion === roomVersion(entry)
110
+ ? { kind: 'still-current' }
111
+ : { kind: 'beyond-horizon' };
112
+ },
113
+ }
114
+ : {}),
122
115
  async mutate() {
123
116
  return { kind: 'rejected', affected: {}, code: 'write-grant', fields: {}, retryable: false };
124
117
  },
118
+ async attach() {
119
+ return { kind: 'rejected', code: 'write-grant', fields: {}, retryable: false };
120
+ },
125
121
  async history() {
126
122
  return { kind: 'no-history' };
127
123
  },
128
124
  async binary(_authorization, request) {
129
- const named = published(request.kind === 'path' ? { room: request.locator, path: request.path } : request.referrer);
130
- if (named === null) {
131
- return { kind: 'rejected', code: 'referrer_unknown', fields: {}, retryable: false };
132
- }
133
- if (request.fileRef === undefined) {
134
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
135
- }
136
- const { room_ref, path, record } = named.referrer;
137
- const read = await transport.download(`${SITE_FILES}${room_ref}/${encodeURIComponent(request.fileRef)}/${path === undefined
138
- ? `${SITE_FILE_RECORD}/${encodeURIComponent(record)}`
139
- : encodeURIComponent(path)}`);
140
- if (read.status === 404) {
141
- return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
142
- }
143
- return read.status === 200 && read.blob !== null
144
- ? { kind: 'binary', blob: read.blob }
125
+ const route = fileRoute(request);
126
+ if (typeof route !== 'string')
127
+ return route;
128
+ const read = await transport.download(route);
129
+ if (read.status === 404)
130
+ return unfound();
131
+ return read.status === 200 && read.body !== null
132
+ ? { kind: 'binary', body: read.body, mediaType: read.mediaType }
145
133
  : UNCERTAIN;
146
134
  },
147
- referrerScope(referrer) {
148
- const named = published(referrer);
149
- if (named === null)
150
- return null;
151
- const { path } = named.referrer;
152
- return { kind: 'room', locator: named.locator, ...(path === undefined ? {} : { path }) };
135
+ async link(_authorization, request) {
136
+ const route = fileRoute(request);
137
+ if (typeof route !== 'string')
138
+ return route;
139
+ return {
140
+ kind: 'link',
141
+ url: route,
142
+ name: request.path.slice(request.path.lastIndexOf('/') + 1),
143
+ };
153
144
  },
154
145
  reached(locator, version, target) {
155
146
  return reachedVersion(version, target, tracked.get(locator)?.logEpoch);
@@ -158,7 +149,7 @@ export function createSiteAdapter(transport) {
158
149
  return followsVersion(version, next);
159
150
  },
160
151
  async action(_authorization, request) {
161
- if (request.name !== SITE_SUBMIT) {
152
+ if (request.name !== SITE_SUBMISSION) {
162
153
  return {
163
154
  kind: 'rejected',
164
155
  code: 'action-unimplemented',
@@ -168,22 +159,20 @@ export function createSiteAdapter(transport) {
168
159
  }
169
160
  if (!transport.online())
170
161
  return UNCERTAIN;
171
- return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMIT);
162
+ return actionOutcome(await transport.door(SITE_DOOR_SUBMIT, request.input), SITE_SUBMISSION, request.input);
172
163
  },
173
- roomStream: {
174
- hold(rooms) {
175
- notifications.send(rooms.flatMap((room) => {
176
- const entry = tracked.get(room.locator);
177
- const at = logPosition(room.roomVersion);
178
- if (entry === undefined || at === null)
179
- return [];
180
- notifications.reach(entry.authority, at);
181
- return [presented(entry.authority, at)];
182
- }));
164
+ roomStream: snapshot
165
+ ? undefined
166
+ : {
167
+ hold(rooms) {
168
+ notifications.send(rooms.flatMap((room) => {
169
+ const entry = tracked.get(room.locator);
170
+ const at = logPosition(room.roomVersion);
171
+ return entry === undefined || at === null ? [] : [presented(entry.authority, at)];
172
+ }));
173
+ },
174
+ observe: notifications.observe,
183
175
  },
184
- reopen: notifications.reopen,
185
- observe: notifications.observe,
186
- },
187
176
  serviceMode: notifications.serviceMode,
188
177
  };
189
178
  }
@@ -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,23 +1,24 @@
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 { SpaceSchemas } from './space-schema.js';
4
+ import { type HouseDoor, type HouseHeldRoom, 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;
10
14
  };
11
15
  export type HouseNotifications = {
12
16
  runtime: string;
13
17
  observe(notify: (event: RoomStreamEvent) => void): () => void;
14
18
  send(rooms: readonly HouseHeldRoom[]): void;
15
- reopen(): void;
16
19
  track(authorities: readonly TrackedAuthority[]): void;
17
- reach(authority: string, at: LogPosition): void;
18
- advance(tracked: TrackedAuthority, from: LogPosition, holds?: HeldRevision): StreamedAdvancement | null;
19
20
  conversations: ConversationStream;
20
21
  serviceMode: ServiceModeSignal;
21
22
  };
22
- export declare function houseNotifications(transport: HouseDoor, mode: HouseMode): HouseNotifications;
23
+ export declare function houseNotifications(transport: HouseDoor, mode: HouseMode, discovering: HouseDiscovering, spaces: SpaceSchemas): HouseNotifications;
23
24
  //# 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,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,CA8S5F"}
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;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUtD,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;AA0FF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,gBAAgB,EAC7B,MAAM,EAAE,YAAY,GACnB,kBAAkB,CA8TpB"}