@agentshouse/mdruntime 0.1.0-ce531b51ff088 → 0.1.0-ce6bc9239a3ee

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 (253) hide show
  1. package/README.md +25 -12
  2. package/dist/acceptance.d.ts +26 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +384 -0
  5. package/dist/adapter.d.ts +218 -62
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +1 -9
  8. package/dist/attached-model.d.ts +8 -0
  9. package/dist/attached-model.d.ts.map +1 -0
  10. package/dist/attached-model.js +46 -0
  11. package/dist/attempt.d.ts +16 -0
  12. package/dist/attempt.d.ts.map +1 -0
  13. package/dist/attempt.js +70 -0
  14. package/dist/binary.d.ts +18 -0
  15. package/dist/binary.d.ts.map +1 -0
  16. package/dist/binary.js +8 -0
  17. package/dist/bootstrap.d.ts +40 -6
  18. package/dist/bootstrap.d.ts.map +1 -1
  19. package/dist/bootstrap.js +336 -51
  20. package/dist/chain.d.ts +12 -0
  21. package/dist/chain.d.ts.map +1 -0
  22. package/dist/chain.js +64 -0
  23. package/dist/change-set.d.ts +9 -14
  24. package/dist/change-set.d.ts.map +1 -1
  25. package/dist/change-set.js +11 -56
  26. package/dist/change.d.ts +46 -0
  27. package/dist/change.d.ts.map +1 -1
  28. package/dist/change.js +34 -0
  29. package/dist/chat-types.d.ts +3 -0
  30. package/dist/chat-types.d.ts.map +1 -0
  31. package/dist/chat-types.js +2 -0
  32. package/dist/client.d.ts +50 -18
  33. package/dist/client.d.ts.map +1 -1
  34. package/dist/client.js +162 -30
  35. package/dist/collection.d.ts +13 -14
  36. package/dist/collection.d.ts.map +1 -1
  37. package/dist/collection.js +52 -56
  38. package/dist/compile.d.ts +16 -0
  39. package/dist/compile.d.ts.map +1 -0
  40. package/dist/compile.js +717 -0
  41. package/dist/connection.d.ts +63 -48
  42. package/dist/connection.d.ts.map +1 -1
  43. package/dist/connection.js +2487 -1575
  44. package/dist/context.d.ts +2 -0
  45. package/dist/context.d.ts.map +1 -0
  46. package/dist/context.js +7 -0
  47. package/dist/conversation-row.d.ts +33 -0
  48. package/dist/conversation-row.d.ts.map +1 -0
  49. package/dist/conversation-row.js +47 -0
  50. package/dist/conversation.d.ts +72 -22
  51. package/dist/conversation.d.ts.map +1 -1
  52. package/dist/conversation.js +1008 -273
  53. package/dist/digest.d.ts +7 -0
  54. package/dist/digest.d.ts.map +1 -0
  55. package/dist/digest.js +113 -0
  56. package/dist/durability.d.ts +10 -1
  57. package/dist/durability.d.ts.map +1 -1
  58. package/dist/durability.js +5 -0
  59. package/dist/entry.d.ts +20 -0
  60. package/dist/entry.d.ts.map +1 -0
  61. package/dist/entry.js +161 -0
  62. package/dist/expectation.d.ts +21 -0
  63. package/dist/expectation.d.ts.map +1 -0
  64. package/dist/expectation.js +70 -0
  65. package/dist/failure.d.ts +13 -0
  66. package/dist/failure.d.ts.map +1 -0
  67. package/dist/failure.js +19 -0
  68. package/dist/figures.d.ts +48 -0
  69. package/dist/figures.d.ts.map +1 -0
  70. package/dist/figures.js +197 -0
  71. package/dist/file.d.ts +2 -19
  72. package/dist/file.d.ts.map +1 -1
  73. package/dist/file.js +7 -122
  74. package/dist/host.d.ts +18 -2
  75. package/dist/host.d.ts.map +1 -1
  76. package/dist/host.js +164 -50
  77. package/dist/identity.d.ts +3 -0
  78. package/dist/identity.d.ts.map +1 -1
  79. package/dist/identity.js +13 -1
  80. package/dist/index.d.ts +31 -10
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +13 -0
  83. package/dist/install.d.ts +86 -0
  84. package/dist/install.d.ts.map +1 -0
  85. package/dist/install.js +537 -0
  86. package/dist/job.d.ts +33 -0
  87. package/dist/job.d.ts.map +1 -0
  88. package/dist/job.js +54 -0
  89. package/dist/live.d.ts +23 -0
  90. package/dist/live.d.ts.map +1 -0
  91. package/dist/live.js +165 -0
  92. package/dist/log.d.ts +1 -0
  93. package/dist/log.d.ts.map +1 -1
  94. package/dist/media.d.ts +8 -0
  95. package/dist/media.d.ts.map +1 -0
  96. package/dist/media.js +218 -0
  97. package/dist/memory.d.ts +30 -9
  98. package/dist/memory.d.ts.map +1 -1
  99. package/dist/memory.js +337 -86
  100. package/dist/messages.d.ts +52 -0
  101. package/dist/messages.d.ts.map +1 -0
  102. package/dist/messages.js +168 -0
  103. package/dist/model.d.ts +17 -16
  104. package/dist/model.d.ts.map +1 -1
  105. package/dist/model.js +9 -9
  106. package/dist/name.d.ts +4 -0
  107. package/dist/name.d.ts.map +1 -0
  108. package/dist/name.js +122 -0
  109. package/dist/observation.d.ts +22 -2
  110. package/dist/observation.d.ts.map +1 -1
  111. package/dist/observation.js +133 -17
  112. package/dist/open.d.ts +2 -0
  113. package/dist/open.d.ts.map +1 -0
  114. package/dist/open.js +1 -0
  115. package/dist/opened.d.ts +22 -0
  116. package/dist/opened.d.ts.map +1 -0
  117. package/dist/opened.js +107 -0
  118. package/dist/outcome.d.ts +73 -5
  119. package/dist/outcome.d.ts.map +1 -1
  120. package/dist/outcome.js +84 -1
  121. package/dist/overlay.d.ts +16 -5
  122. package/dist/overlay.d.ts.map +1 -1
  123. package/dist/overlay.js +147 -180
  124. package/dist/parts.d.ts +59 -0
  125. package/dist/parts.d.ts.map +1 -0
  126. package/dist/parts.js +118 -0
  127. package/dist/paths.d.ts +1 -1
  128. package/dist/paths.d.ts.map +1 -1
  129. package/dist/paths.js +4 -16
  130. package/dist/query.d.ts +56 -180
  131. package/dist/query.d.ts.map +1 -1
  132. package/dist/query.js +3 -422
  133. package/dist/questions.d.ts +32 -0
  134. package/dist/questions.d.ts.map +1 -0
  135. package/dist/questions.js +118 -0
  136. package/dist/reach.d.ts +54 -0
  137. package/dist/reach.d.ts.map +1 -0
  138. package/dist/reach.js +494 -0
  139. package/dist/react.d.ts +46 -0
  140. package/dist/react.d.ts.map +1 -0
  141. package/dist/react.js +54 -0
  142. package/dist/read.d.ts +7 -0
  143. package/dist/read.d.ts.map +1 -0
  144. package/dist/read.js +17 -0
  145. package/dist/readiness.d.ts +50 -0
  146. package/dist/readiness.d.ts.map +1 -0
  147. package/dist/readiness.js +27 -0
  148. package/dist/reads.d.ts +36 -0
  149. package/dist/reads.d.ts.map +1 -0
  150. package/dist/reads.js +136 -0
  151. package/dist/recovery.d.ts +26 -0
  152. package/dist/recovery.d.ts.map +1 -0
  153. package/dist/recovery.js +232 -0
  154. package/dist/refresh.d.ts +21 -7
  155. package/dist/refresh.d.ts.map +1 -1
  156. package/dist/refresh.js +155 -55
  157. package/dist/replica.d.ts +58 -33
  158. package/dist/replica.d.ts.map +1 -1
  159. package/dist/replica.js +355 -158
  160. package/dist/room-draft.d.ts +62 -11
  161. package/dist/room-draft.d.ts.map +1 -1
  162. package/dist/room-draft.js +281 -83
  163. package/dist/room-drafts.d.ts +29 -0
  164. package/dist/room-drafts.d.ts.map +1 -0
  165. package/dist/room-drafts.js +216 -0
  166. package/dist/rows.d.ts +32 -34
  167. package/dist/rows.d.ts.map +1 -1
  168. package/dist/rows.js +65 -87
  169. package/dist/save.d.ts +74 -6
  170. package/dist/save.d.ts.map +1 -1
  171. package/dist/save.js +902 -182
  172. package/dist/saves.d.ts +96 -0
  173. package/dist/saves.d.ts.map +1 -0
  174. package/dist/saves.js +999 -0
  175. package/dist/search.d.ts +15 -54
  176. package/dist/search.d.ts.map +1 -1
  177. package/dist/search.js +10 -121
  178. package/dist/seed.d.ts +30 -0
  179. package/dist/seed.d.ts.map +1 -0
  180. package/dist/seed.js +141 -0
  181. package/dist/shared.d.ts +15 -0
  182. package/dist/shared.d.ts.map +1 -0
  183. package/dist/shared.js +421 -0
  184. package/dist/socket/admission.d.ts +7 -0
  185. package/dist/socket/admission.d.ts.map +1 -0
  186. package/dist/socket/admission.js +39 -0
  187. package/dist/socket/answers.d.ts +6 -0
  188. package/dist/socket/answers.d.ts.map +1 -0
  189. package/dist/socket/answers.js +20 -0
  190. package/dist/socket/reads.d.ts +10 -0
  191. package/dist/socket/reads.d.ts.map +1 -0
  192. package/dist/socket/reads.js +31 -0
  193. package/dist/socket.d.ts +43 -0
  194. package/dist/socket.d.ts.map +1 -0
  195. package/dist/socket.js +96 -0
  196. package/dist/source.d.ts +61 -0
  197. package/dist/source.d.ts.map +1 -0
  198. package/dist/source.js +81 -0
  199. package/dist/status.d.ts +7 -4
  200. package/dist/status.d.ts.map +1 -1
  201. package/dist/status.js +3 -15
  202. package/dist/store/fences.d.ts +16 -0
  203. package/dist/store/fences.d.ts.map +1 -0
  204. package/dist/store/fences.js +26 -0
  205. package/dist/store/installs.d.ts +30 -0
  206. package/dist/store/installs.d.ts.map +1 -0
  207. package/dist/store/installs.js +34 -0
  208. package/dist/store/records.d.ts +212 -0
  209. package/dist/store/records.d.ts.map +1 -0
  210. package/dist/store/records.js +408 -0
  211. package/dist/store/room-held.d.ts +8 -0
  212. package/dist/store/room-held.d.ts.map +1 -0
  213. package/dist/store/room-held.js +17 -0
  214. package/dist/store/watchers.d.ts +15 -0
  215. package/dist/store/watchers.d.ts.map +1 -0
  216. package/dist/store/watchers.js +36 -0
  217. package/dist/store/writes.d.ts +24 -0
  218. package/dist/store/writes.d.ts.map +1 -0
  219. package/dist/store/writes.js +125 -0
  220. package/dist/store.d.ts +77 -94
  221. package/dist/store.d.ts.map +1 -1
  222. package/dist/store.js +118 -389
  223. package/dist/stored.d.ts +156 -0
  224. package/dist/stored.d.ts.map +1 -0
  225. package/dist/stored.js +637 -0
  226. package/dist/tables.d.ts +407 -0
  227. package/dist/tables.d.ts.map +1 -0
  228. package/dist/tables.js +724 -0
  229. package/dist/tallies.d.ts +18 -0
  230. package/dist/tallies.d.ts.map +1 -0
  231. package/dist/tallies.js +129 -0
  232. package/dist/transfer.d.ts +0 -5
  233. package/dist/transfer.d.ts.map +1 -1
  234. package/dist/turn.d.ts +9 -0
  235. package/dist/turn.d.ts.map +1 -0
  236. package/dist/turn.js +75 -0
  237. package/dist/validation.d.ts +29 -0
  238. package/dist/validation.d.ts.map +1 -0
  239. package/dist/validation.js +104 -0
  240. package/dist/windows.d.ts +11 -0
  241. package/dist/windows.d.ts.map +1 -0
  242. package/dist/windows.js +16 -0
  243. package/dist/wire.d.ts +205 -19
  244. package/dist/wire.d.ts.map +1 -1
  245. package/dist/wire.js +95 -61
  246. package/package.json +33 -10
  247. package/AGENTS.md +0 -207
  248. package/dist/attachment.d.ts +0 -3
  249. package/dist/attachment.d.ts.map +0 -1
  250. package/dist/attachment.js +0 -8
  251. package/dist/read-side.d.ts +0 -14
  252. package/dist/read-side.d.ts.map +0 -1
  253. package/dist/read-side.js +0 -371
package/dist/reach.js ADDED
@@ -0,0 +1,494 @@
1
+ import { unheldView } from './conversation.js';
2
+ import { modelTypes, NO_MODEL } from './model.js';
3
+ import { changeOf, digestApplied, digestOf, observing, } from './observation.js';
4
+ import { runtimeError } from './failure.js';
5
+ import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
6
+ import { beneath } from './paths.js';
7
+ import { moveTarget, readParts, staleWrite, } from './room-draft.js';
8
+ import { documentKey } from './rows.js';
9
+ const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
10
+ function unconversed(name) {
11
+ return () => Promise.resolve(undeclared(name));
12
+ }
13
+ const NO_CONVERSATION = {
14
+ list: () => Promise.resolve([]),
15
+ read: (conversation) => Promise.resolve(unheldView(conversation)),
16
+ create: unconversed('conversations/create'),
17
+ send: unconversed('conversations/send'),
18
+ answer: unconversed('conversations/interaction/answer'),
19
+ interrupt: unconversed('conversations/interrupt'),
20
+ kill: unconversed('conversations/kill'),
21
+ delete: unconversed('conversations/delete'),
22
+ };
23
+ const NO_CHAT_DRAFT = {
24
+ write: () => Promise.resolve(),
25
+ prepend: () => Promise.resolve(),
26
+ discard: () => Promise.resolve(),
27
+ };
28
+ function areasOf(reach) {
29
+ return reach.areas ?? [];
30
+ }
31
+ function fenced(reach, room, path) {
32
+ return areasOf(reach).some((area) => area.room === room &&
33
+ beneath(area.path, path) &&
34
+ !area.open.some((open) => beneath(open, path)));
35
+ }
36
+ export function holds(reach, room) {
37
+ return (reach === null ||
38
+ reach.rooms.includes(room) ||
39
+ reach.documents.some((document) => document.room === room));
40
+ }
41
+ function wholly(reach, room) {
42
+ return reach === null || reach.rooms.includes(room);
43
+ }
44
+ export function governs(reach, room) {
45
+ if (wholly(reach, room.locator)) {
46
+ return { collection: true, selection: room.typedSelection !== null };
47
+ }
48
+ const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
49
+ const paths = reach.documents
50
+ .filter((document) => document.room === room.locator)
51
+ .map(({ path }) => path);
52
+ return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
53
+ }
54
+ function covers(reach, room, path) {
55
+ return (reach === null ||
56
+ (!fenced(reach, room, path) &&
57
+ (reach.rooms.includes(room) ||
58
+ reach.documents.some((document) => document.room === room && document.path === path))));
59
+ }
60
+ function conversing(reach) {
61
+ return reach === null || reach.conversations;
62
+ }
63
+ export function planReach(reach) {
64
+ return reach === null
65
+ ? null
66
+ : {
67
+ rooms: [...new Set(reach.rooms)].sort(),
68
+ documents: [
69
+ ...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
70
+ ].sort(),
71
+ areas: areasOf(reach)
72
+ .map(({ room, path, open }) => ({ room, path, open: [...new Set(open)].sort() }))
73
+ .sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
74
+ };
75
+ }
76
+ function roomsWithin(reach, rooms) {
77
+ return rooms.filter((room) => wholly(reach, room.locator));
78
+ }
79
+ function typesWithin(reach, room, types) {
80
+ if (room === undefined)
81
+ return structuredClone(UNHELD_TYPES);
82
+ const governed = governs(reach, room);
83
+ return {
84
+ collection: governed.collection ? types.collection : modelTypes(NO_MODEL),
85
+ typedSelection: governed.selection ? types.typedSelection : null,
86
+ };
87
+ }
88
+ function moves(reach, room, move) {
89
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
90
+ }
91
+ function draftWithin(reach, draft) {
92
+ return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
93
+ }
94
+ function draftsWithin(reach, drafts) {
95
+ return drafts.filter((draft) => draftWithin(reach, draft));
96
+ }
97
+ function shownDraft(reach, draft) {
98
+ return draft !== null && draftWithin(reach, draft) ? draft : null;
99
+ }
100
+ function writeWithin(reach, write) {
101
+ return write.outcome === 'written'
102
+ ? { outcome: 'written', roomDraft: shownDraft(reach, write.roomDraft) }
103
+ : staleWrite(shownDraft(reach, write.current));
104
+ }
105
+ function savedWithin(reach, room, result) {
106
+ if (reach === null || result.outcome === 'saved')
107
+ return result;
108
+ const { file, location, referrers, ...refusal } = result;
109
+ const hidden = file !== undefined && !covers(reach, room, file);
110
+ return {
111
+ ...refusal,
112
+ ...(file === undefined || hidden ? {} : { file }),
113
+ ...(location === undefined || hidden ? {} : { location }),
114
+ ...(referrers === undefined
115
+ ? {}
116
+ : { referrers: referrers.filter((path) => covers(reach, room, path)) }),
117
+ };
118
+ }
119
+ function statusWithin(reach, status) {
120
+ return {
121
+ ...status,
122
+ attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
123
+ unsent: status.unsent.filter((change) => covers(reach, change.room, change.path)),
124
+ };
125
+ }
126
+ function queueWithin(reach, room, entries) {
127
+ return entries
128
+ .filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
129
+ (change.kind !== 'move' || covers(reach, room, change.to))))
130
+ .map((entry) => {
131
+ const { between, ...batch } = entry.batch;
132
+ if (between === undefined)
133
+ return entry;
134
+ return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
135
+ ? entry
136
+ : { ...entry, batch };
137
+ });
138
+ }
139
+ function unreached(room) {
140
+ return runtimeError('unknown-room', `Unknown Room ${room}`);
141
+ }
142
+ function lockedError(room) {
143
+ return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
144
+ }
145
+ function deviceUnreached() {
146
+ return runtimeError('device-unreached', 'Only the panel reaches this device');
147
+ }
148
+ const ATTACH_REQUIRED = 'attach-required';
149
+ function attachRequired() {
150
+ return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
151
+ }
152
+ function carriesFile(parts) {
153
+ return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
154
+ }
155
+ export function narrowed(runtime, given, port) {
156
+ const { md, watch } = runtime;
157
+ let reach = given;
158
+ const open = new Set();
159
+ function following(begin, locking = false) {
160
+ let stop = begin();
161
+ const restart = () => {
162
+ stop();
163
+ stop = begin();
164
+ };
165
+ open.add(restart);
166
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
167
+ return () => {
168
+ open.delete(restart);
169
+ unwatch();
170
+ stop();
171
+ };
172
+ }
173
+ const unlocking = (rooms, locked) => {
174
+ const held = (rooms ?? []).filter((room) => locked.includes(room));
175
+ return held.length === 0 ? null : { pending: held.map((room) => ({ room, awaits: 'unlock' })) };
176
+ };
177
+ const unlocked = (entries, locked) => entries.filter((entry) => !locked.includes(entry.room));
178
+ const intoLocked = async (held) => {
179
+ for (const move of held) {
180
+ if (move?.room !== undefined && (await runtime.locked(move.room)))
181
+ return true;
182
+ }
183
+ return false;
184
+ };
185
+ function ordered(deliver) {
186
+ let open = true;
187
+ let shown = Promise.resolve();
188
+ return {
189
+ push(making) {
190
+ shown = shown.then(() => making.then((value) => {
191
+ if (open)
192
+ deliver(value);
193
+ }, () => { }), () => { });
194
+ },
195
+ stop() {
196
+ open = false;
197
+ },
198
+ };
199
+ }
200
+ function unlockedWatch(topic, input, deliver, fail, within) {
201
+ const shown = ordered(deliver);
202
+ const stop = watch(topic, input, (message) => {
203
+ shown.push(runtime.lockedRooms().then((locked) => within(message, locked)));
204
+ }, fail);
205
+ return () => {
206
+ shown.stop();
207
+ stop();
208
+ };
209
+ }
210
+ function lockedFirst(room, start, shut) {
211
+ let open = true;
212
+ let stop = () => { };
213
+ void (async () => {
214
+ const closed = !holds(reach, room) || (await runtime.locked(room));
215
+ if (!open)
216
+ return;
217
+ if (closed)
218
+ shut();
219
+ else
220
+ stop = start();
221
+ })();
222
+ return () => {
223
+ open = false;
224
+ stop();
225
+ };
226
+ }
227
+ const within = (topic, input, deliver, fail) => {
228
+ if (topic === 'read' && reach !== null) {
229
+ fail(deviceUnreached());
230
+ return () => { };
231
+ }
232
+ if (topic === 'rooms') {
233
+ return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms)), fail));
234
+ }
235
+ if (topic === 'readiness') {
236
+ return following(() => runtime.watchReadiness(port, reach, deliver));
237
+ }
238
+ if (topic === 'sync-status') {
239
+ return following(() => unlockedWatch(topic, input, deliver, fail, (status, locked) => {
240
+ const shown = statusWithin(reach, status);
241
+ return { ...shown, attentionRequired: unlocked(shown.attentionRequired, locked) };
242
+ }), true);
243
+ }
244
+ if (topic === 'room-drafts') {
245
+ return following(() => unlockedWatch(topic, input, deliver, fail, (drafts, locked) => unlocked(draftsWithin(reach, drafts), locked)), true);
246
+ }
247
+ if (topic === 'queue') {
248
+ const room = input[0];
249
+ return following(() => lockedFirst(room, () => watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)), fail), () => deliver([])), true);
250
+ }
251
+ if (topic === 'query') {
252
+ const planning = runtime.plan(input[0], reach);
253
+ let held = null;
254
+ return following(() => {
255
+ let open = true;
256
+ let stop = () => { };
257
+ void (async () => {
258
+ const plan = await planning;
259
+ const locked = await runtime.lockedRooms();
260
+ if (!open)
261
+ return;
262
+ const pending = unlocking(plan.rooms, locked);
263
+ if (pending !== null) {
264
+ const answer = { result: pending, keys: [] };
265
+ if (held === null || changeOf(held, answer) !== null)
266
+ deliver(answer);
267
+ held = digestOf(answer);
268
+ return;
269
+ }
270
+ let first = true;
271
+ const heard = (message) => {
272
+ if (!first) {
273
+ held = digestApplied(held, message);
274
+ deliver(message);
275
+ return;
276
+ }
277
+ first = false;
278
+ const change = held === null ? message : changeOf(held, message);
279
+ held = digestOf(message);
280
+ if (change !== null)
281
+ deliver(change);
282
+ };
283
+ const current = { ...plan, reach: planReach(reach), locked };
284
+ stop = runtime.watchPlan(current, (message) => {
285
+ if (open)
286
+ heard(message);
287
+ }, (error) => {
288
+ if (open)
289
+ fail(error);
290
+ });
291
+ })().catch((error) => {
292
+ if (open)
293
+ fail(error);
294
+ });
295
+ return () => {
296
+ open = false;
297
+ stop();
298
+ };
299
+ }, true);
300
+ }
301
+ if (topic === 'conversation') {
302
+ return following(() => {
303
+ if (conversing(reach))
304
+ return watch(topic, input, deliver, fail);
305
+ deliver(unheldView(input[0]));
306
+ return () => { };
307
+ });
308
+ }
309
+ if (topic === 'conversations' || topic === 'agents') {
310
+ return following(() => {
311
+ if (conversing(reach))
312
+ return watch(topic, input, deliver, fail);
313
+ deliver([]);
314
+ return () => { };
315
+ });
316
+ }
317
+ if (topic === 'figures') {
318
+ if (reach === null)
319
+ return watch(topic, input, deliver, fail);
320
+ fail(deviceUnreached());
321
+ return () => { };
322
+ }
323
+ return watch(topic, input, deliver, fail);
324
+ };
325
+ const files = new Map();
326
+ let handed = 0;
327
+ async function hand(reading) {
328
+ const answer = await reading;
329
+ if (answer.kind !== 'binary')
330
+ return answer;
331
+ handed += 1;
332
+ const file = String(handed);
333
+ files.set(file, answer.file);
334
+ return { ...answer, file };
335
+ }
336
+ const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
337
+ const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
338
+ const view = {
339
+ ...md,
340
+ rooms: () => md.rooms().then((rooms) => roomsWithin(reach, rooms)),
341
+ query: (async (input) => {
342
+ const plan = await runtime.plan(input, reach);
343
+ const locked = await runtime.lockedRooms();
344
+ return unlocking(plan.rooms, locked) ?? runtime.query({ ...plan, locked });
345
+ }),
346
+ search: (input) => runtime.search(input, reach),
347
+ async types(room) {
348
+ if (holds(reach, room) && (await runtime.locked(room)))
349
+ throw lockedError(room);
350
+ if (wholly(reach, room))
351
+ return md.types(room);
352
+ if (!holds(reach, room))
353
+ return structuredClone(UNHELD_TYPES);
354
+ return typesWithin(reach, await runtime.room(room), await md.types(room));
355
+ },
356
+ async save(room, roomDrafts, writtenBy) {
357
+ if (!holds(reach, room))
358
+ throw unreached(room);
359
+ if (await runtime.locked(room)) {
360
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
361
+ }
362
+ const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
363
+ const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
364
+ if (outside !== undefined) {
365
+ return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
366
+ }
367
+ if (await intoLocked(held))
368
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
369
+ return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
370
+ },
371
+ async saveParts(room, parts, writtenBy) {
372
+ if (!holds(reach, room))
373
+ throw unreached(room);
374
+ const filed = reach === null ? undefined : parts.find(({ parts: one }) => carriesFile(one));
375
+ if (filed !== undefined) {
376
+ return { outcome: 'refused', code: ATTACH_REQUIRED, retryable: false, file: filed.path };
377
+ }
378
+ if (await runtime.locked(room)) {
379
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
380
+ }
381
+ const held = parts.map(({ path, parts: one }) => readParts(one, path).move);
382
+ if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
383
+ throw unreached(room);
384
+ }
385
+ if (await intoLocked(held))
386
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
387
+ return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
388
+ },
389
+ async resolve(room, path, destination) {
390
+ const at = await runtime.located(room, path, destination);
391
+ return at !== null && !covers(reach, at.room, at.path)
392
+ ? UNREADABLE
393
+ : md.resolve(room, path, destination);
394
+ },
395
+ history: async (room, path, query) => !covers(reach, room, path)
396
+ ? failure({ kind: 'room-not-readable', locator: room })
397
+ : (await runtime.locked(room))
398
+ ? lockedRoom(room)
399
+ : md.history(room, path, query),
400
+ binaryFile: {
401
+ read: async (room, path, revision) => !covers(reach, room, path)
402
+ ? failure({ kind: 'room-not-readable', locator: room })
403
+ : (await runtime.locked(room))
404
+ ? lockedRoom(room)
405
+ : hand(md.binaryFile.read(room, path, revision)),
406
+ link: async (room, path, revision) => !covers(reach, room, path)
407
+ ? failure({ kind: 'room-not-readable', locator: room })
408
+ : (await runtime.locked(room))
409
+ ? lockedRoom(room)
410
+ : md.binaryFile.link(room, path, revision),
411
+ show: async (room, path, revision) => !covers(reach, room, path)
412
+ ? failure({ kind: 'room-not-readable', locator: room })
413
+ : (await runtime.locked(room))
414
+ ? lockedRoom(room)
415
+ : hand(md.binaryFile.show(room, path, revision)),
416
+ attach: async (room, file) => !wholly(reach, room)
417
+ ? failure({ kind: 'room-not-readable', locator: room })
418
+ : (await runtime.locked(room))
419
+ ? lockedRoom(room)
420
+ : md.binaryFile.attach(room, file),
421
+ async part(file, part) {
422
+ const key = files.get(file);
423
+ if (key === undefined)
424
+ return null;
425
+ const bytes = await md.binaryFile.part(key, part);
426
+ if (bytes === null)
427
+ files.delete(file);
428
+ return bytes;
429
+ },
430
+ },
431
+ reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
432
+ !(await runtime.locked(room)) &&
433
+ (await md.reached(room, roomVersion, path)),
434
+ log: () => (reach === null ? md.log() : ''),
435
+ cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
436
+ unsent: () => (reach === null ? md.unsent() : Promise.reject(deviceUnreached())),
437
+ reset: () => (reach === null ? md.reset() : Promise.reject(deviceUnreached())),
438
+ readAgain: () => (reach === null ? md.readAgain() : Promise.reject(deviceUnreached())),
439
+ roomDraft: {
440
+ list: async () => unlocked(draftsWithin(reach, await md.roomDraft.list()), await runtime.lockedRooms()),
441
+ async read(room, path) {
442
+ if (!covers(reach, room, path))
443
+ return null;
444
+ if (await runtime.locked(room))
445
+ throw lockedError(room);
446
+ return shownDraft(reach, await md.roomDraft.read(room, path));
447
+ },
448
+ async write(room, path, revision, parts, next) {
449
+ if (reach !== null && carriesFile(parts))
450
+ throw attachRequired();
451
+ const move = readParts(parts, path).move;
452
+ if (!covers(reach, room, path) || !moves(reach, room, move))
453
+ throw unreached(room);
454
+ if (await runtime.locked(room))
455
+ throw lockedError(room);
456
+ if (await intoLocked([move]))
457
+ throw lockedError(move.room);
458
+ return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts, next));
459
+ },
460
+ async discard(room, path, revision) {
461
+ if (!covers(reach, room, path))
462
+ return staleWrite(null);
463
+ if (await runtime.locked(room))
464
+ throw lockedError(room);
465
+ return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
466
+ },
467
+ },
468
+ conversation: {
469
+ list: () => conversation().list(),
470
+ read: (id, options) => conversation().read(id, options),
471
+ create: (input) => conversation().create(input),
472
+ send: (id, operation, draft) => conversation().send(id, operation, draft),
473
+ answer: (id, answer) => conversation().answer(id, answer),
474
+ interrupt: (id) => conversation().interrupt(id),
475
+ kill: (id) => conversation().kill(id),
476
+ delete: (id) => conversation().delete(id),
477
+ },
478
+ chatDraft: {
479
+ write: (id, draft, revision) => chatDraft().write(id, draft, revision),
480
+ prepend: (id, draft) => chatDraft().prepend(id, draft),
481
+ discard: (id) => chatDraft().discard(id),
482
+ },
483
+ observe: observing(within),
484
+ };
485
+ return {
486
+ md: view,
487
+ watch: within,
488
+ narrow(next) {
489
+ reach = next;
490
+ for (const restart of [...open])
491
+ restart();
492
+ },
493
+ };
494
+ }
@@ -0,0 +1,46 @@
1
+ import type { DocumentQuery, GroupQuery } from '@agentshouse/mdmodel';
2
+ import type { MdRuntimeClient } from './client.js';
3
+ import type { AppRoom, ConnectionRefusal } from './connection.js';
4
+ import type { SavedRoomDraft, SaveResult } from './saves.js';
5
+ import type { Member, ServiceMode } from './adapter.js';
6
+ import type { ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
7
+ import { type RuntimeError } from './failure.js';
8
+ import type { QueueEntry } from './outcome.js';
9
+ import type { DocumentResult, GroupResult, PendingResult } from './query.js';
10
+ import type { Readiness } from './readiness.js';
11
+ import type { RoomDraft, RoomDraftParts } from './room-draft.js';
12
+ import type { SyncStatus } from './status.js';
13
+ type Client = MdRuntimeClient | null;
14
+ export type Observed<T> = {
15
+ readonly state: 'loading';
16
+ } | {
17
+ readonly state: 'ready';
18
+ readonly value: T;
19
+ };
20
+ export declare function useObserve(client: Client, topic: 'deployment-facts'): Observed<unknown>;
21
+ export declare function useObserve(client: Client, topic: 'rooms'): Observed<readonly AppRoom[]>;
22
+ export declare function useObserve(client: Client, topic: 'readiness'): Observed<Readiness>;
23
+ export declare function useObserve(client: Client, topic: 'connection-refusal'): Observed<ConnectionRefusal | null>;
24
+ export declare function useObserve(client: Client, topic: 'storage-loss'): Observed<string | null>;
25
+ export declare function useObserve(client: Client, topic: 'sync-status'): Observed<SyncStatus>;
26
+ export declare function useObserve(client: Client, topic: 'service-mode'): Observed<ServiceMode>;
27
+ export declare function useObserve(client: Client, topic: 'member'): Observed<Member | null>;
28
+ export declare function useObserve(client: Client, topic: 'authority-changes'): Observed<number>;
29
+ export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult | PendingResult>;
30
+ export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult | PendingResult>;
31
+ export declare function useObserve(client: Client, topic: 'queue', locator: string): Observed<readonly QueueEntry[]>;
32
+ export declare function useObserve(client: Client, topic: 'room-drafts'): Observed<readonly RoomDraft[]>;
33
+ export declare function useObserve(client: Client, topic: 'presentation'): Observed<unknown>;
34
+ export declare function useObserve(client: Client, topic: 'conversation', conversation: string, options: ConversationOptions): Observed<ConversationView>;
35
+ export declare function useObserve(client: Client, topic: 'conversations'): Observed<readonly ConversationEntry[]>;
36
+ export declare function useObserve(client: Client, topic: 'agents'): Observed<readonly ConversationAgent[]>;
37
+ export type Saving = {
38
+ readonly busy: boolean;
39
+ readonly outcome: SaveResult | null;
40
+ readonly failure: RuntimeError | null;
41
+ save(room: string, parts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
42
+ saveWritten(room: string, roomDrafts: readonly SavedRoomDraft[]): Promise<SaveResult>;
43
+ };
44
+ export declare function useSave(client: MdRuntimeClient): Saving;
45
+ export {};
46
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
package/dist/react.js ADDED
@@ -0,0 +1,54 @@
1
+ import { useCallback, useLayoutEffect, useRef, useState } from 'react';
2
+ import { failed } from './failure.js';
3
+ const LOADING = { state: 'loading' };
4
+ export function useObserve(client, topic, ...input) {
5
+ const key = JSON.stringify([topic, ...input]);
6
+ const [held, setHeld] = useState(null);
7
+ const opened = useRef(input);
8
+ opened.current = input;
9
+ useLayoutEffect(() => {
10
+ if (client === null)
11
+ return;
12
+ let live = true;
13
+ let observation = null;
14
+ const observe = client.observe;
15
+ void observe(topic, ...opened.current).then((open) => {
16
+ if (!live) {
17
+ open.close();
18
+ return;
19
+ }
20
+ observation = open;
21
+ const take = (value) => {
22
+ if (live)
23
+ setHeld({ client, key, observed: { state: 'ready', value } });
24
+ };
25
+ take(open.current());
26
+ open.subscribe(take);
27
+ });
28
+ return () => {
29
+ live = false;
30
+ observation?.close();
31
+ };
32
+ }, [client, key]);
33
+ return held !== null && held.client === client && held.key === key ? held.observed : LOADING;
34
+ }
35
+ const IDLE = { busy: false, outcome: null, failure: null };
36
+ export function useSave(client) {
37
+ const [state, setState] = useState(IDLE);
38
+ const settled = useCallback(async (saving) => {
39
+ setState({ busy: true, outcome: null, failure: null });
40
+ try {
41
+ const outcome = await saving();
42
+ setState({ busy: false, outcome, failure: null });
43
+ return outcome;
44
+ }
45
+ catch (error) {
46
+ const failure = failed(error);
47
+ setState({ busy: false, outcome: null, failure });
48
+ throw failure;
49
+ }
50
+ }, []);
51
+ const save = useCallback((room, parts) => settled(() => client.saveParts(room, [...parts].map(([path, one]) => ({ path, parts: one })))), [client, settled]);
52
+ const saveWritten = useCallback((room, roomDrafts) => settled(() => client.save(room, roomDrafts)), [client, settled]);
53
+ return { ...state, save, saveWritten };
54
+ }
package/dist/read.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export type Fields = Readonly<Record<string, unknown>>;
2
+ export declare const EXCERPT = 512;
3
+ export declare function excerpt(said: string): string;
4
+ export declare function record(entry: unknown): Fields;
5
+ export declare function text(fields: Fields, name: string): string | null;
6
+ export declare function list(fields: Fields, name: string): readonly unknown[];
7
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../src/read.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD,eAAO,MAAM,OAAO,MAAM,CAAC;AAE3B,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7C;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE,CAGrE"}
package/dist/read.js ADDED
@@ -0,0 +1,17 @@
1
+ export const EXCERPT = 512;
2
+ export function excerpt(said) {
3
+ return [...said.slice(0, EXCERPT * 2)].slice(0, EXCERPT).join('');
4
+ }
5
+ export function record(entry) {
6
+ return typeof entry === 'object' && entry !== null && !Array.isArray(entry)
7
+ ? entry
8
+ : {};
9
+ }
10
+ export function text(fields, name) {
11
+ const value = fields[name];
12
+ return typeof value === 'string' && value !== '' ? value : null;
13
+ }
14
+ export function list(fields, name) {
15
+ const value = fields[name];
16
+ return Array.isArray(value) ? value : [];
17
+ }