@agentshouse/mdruntime 0.1.0-ca7c26c6bc27e → 0.1.0-ca8707258fdde

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 +200 -54
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/adapter.js +1 -9
  8. package/dist/attached-model.d.ts +7 -10
  9. package/dist/attached-model.d.ts.map +1 -1
  10. package/dist/attached-model.js +40 -28
  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 +37 -5
  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 +61 -43
  42. package/dist/connection.d.ts.map +1 -1
  43. package/dist/connection.js +2377 -1476
  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 +71 -22
  51. package/dist/conversation.d.ts.map +1 -1
  52. package/dist/conversation.js +996 -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 +11 -2
  75. package/dist/host.d.ts.map +1 -1
  76. package/dist/host.js +134 -34
  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 +22 -8
  98. package/dist/memory.d.ts.map +1 -1
  99. package/dist/memory.js +299 -94
  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 -12
  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 -4
  110. package/dist/observation.d.ts.map +1 -1
  111. package/dist/observation.js +120 -14
  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 +52 -181
  131. package/dist/query.d.ts.map +1 -1
  132. package/dist/query.js +3 -423
  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 +19 -5
  137. package/dist/reach.d.ts.map +1 -1
  138. package/dist/reach.js +309 -92
  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 +35 -0
  149. package/dist/reads.d.ts.map +1 -0
  150. package/dist/reads.js +128 -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 +20 -7
  155. package/dist/refresh.d.ts.map +1 -1
  156. package/dist/refresh.js +155 -59
  157. package/dist/replica.d.ts +58 -34
  158. package/dist/replica.d.ts.map +1 -1
  159. package/dist/replica.js +355 -162
  160. package/dist/room-draft.d.ts +59 -11
  161. package/dist/room-draft.d.ts.map +1 -1
  162. package/dist/room-draft.js +276 -80
  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 -93
  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 +185 -45
  244. package/dist/wire.d.ts.map +1 -1
  245. package/dist/wire.js +75 -46
  246. package/package.json +33 -10
  247. package/AGENTS.md +0 -215
  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 -18
  252. package/dist/read-side.d.ts.map +0 -1
  253. package/dist/read-side.js +0 -377
package/dist/reach.js CHANGED
@@ -1,30 +1,38 @@
1
1
  import { unheldView } from './conversation.js';
2
2
  import { modelTypes, NO_MODEL } from './model.js';
3
- import { applied, observing } from './observation.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';
4
6
  import { beneath } from './paths.js';
5
- import { reconciled } from './read-side.js';
6
- import { moveTarget, readParts } from './room-draft.js';
7
+ import { moveTarget, readParts, staleWrite, } from './room-draft.js';
7
8
  import { documentKey } from './rows.js';
8
9
  const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
9
- const UNDECLARED = { kind: 'undeclared' };
10
- function undeclared() {
11
- return Promise.resolve(UNDECLARED);
10
+ function unconversed(name) {
11
+ return () => Promise.resolve(undeclared(name));
12
12
  }
13
13
  const NO_CONVERSATION = {
14
14
  list: () => Promise.resolve([]),
15
15
  read: (conversation) => Promise.resolve(unheldView(conversation)),
16
- create: undeclared,
17
- send: undeclared,
18
- answer: undeclared,
19
- interrupt: undeclared,
20
- kill: undeclared,
21
- cancel: undeclared,
22
- delete: undeclared,
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'),
23
22
  };
24
23
  const NO_CHAT_DRAFT = {
25
24
  write: () => Promise.resolve(),
25
+ prepend: () => Promise.resolve(),
26
26
  discard: () => Promise.resolve(),
27
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
+ }
28
36
  export function holds(reach, room) {
29
37
  return (reach === null ||
30
38
  reach.rooms.includes(room) ||
@@ -45,8 +53,9 @@ export function governs(reach, room) {
45
53
  }
46
54
  function covers(reach, room, path) {
47
55
  return (reach === null ||
48
- reach.rooms.includes(room) ||
49
- reach.documents.some((document) => document.room === room && document.path === path));
56
+ (!fenced(reach, room, path) &&
57
+ (reach.rooms.includes(room) ||
58
+ reach.documents.some((document) => document.room === room && document.path === path))));
50
59
  }
51
60
  function conversing(reach) {
52
61
  return reach === null || reach.conversations;
@@ -59,25 +68,13 @@ export function planReach(reach) {
59
68
  documents: [
60
69
  ...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
61
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),
62
74
  };
63
75
  }
64
76
  function roomsWithin(reach, rooms) {
65
- if (reach === null)
66
- return rooms;
67
- return rooms
68
- .filter((room) => holds(reach, room.locator))
69
- .map((room) => {
70
- if (wholly(reach, room.locator))
71
- return room;
72
- const governed = governs(reach, room);
73
- return {
74
- ...room,
75
- model: governed.collection ? room.model : modelTypes(NO_MODEL),
76
- typedSelection: governed.selection ? room.typedSelection : null,
77
- roomVersion: null,
78
- attachments: [],
79
- };
80
- });
77
+ return rooms.filter((room) => wholly(reach, room.locator));
81
78
  }
82
79
  function typesWithin(reach, room, types) {
83
80
  if (room === undefined)
@@ -89,7 +86,7 @@ function typesWithin(reach, room, types) {
89
86
  };
90
87
  }
91
88
  function moves(reach, room, move) {
92
- return move === undefined || covers(reach, room, moveTarget(move));
89
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
93
90
  }
94
91
  function draftWithin(reach, draft) {
95
92
  return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
@@ -103,7 +100,7 @@ function shownDraft(reach, draft) {
103
100
  function writeWithin(reach, write) {
104
101
  return write.outcome === 'written'
105
102
  ? { outcome: 'written', roomDraft: shownDraft(reach, write.roomDraft) }
106
- : { outcome: 'stale', current: shownDraft(reach, write.current) };
103
+ : staleWrite(shownDraft(reach, write.current));
107
104
  }
108
105
  function savedWithin(reach, room, result) {
109
106
  if (reach === null || result.outcome === 'saved')
@@ -123,128 +120,348 @@ function statusWithin(reach, status) {
123
120
  return {
124
121
  ...status,
125
122
  attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
123
+ unsent: status.unsent.filter((change) => covers(reach, change.room, change.path)),
126
124
  };
127
125
  }
128
126
  function queueWithin(reach, room, entries) {
129
- return entries.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
130
- (change.kind !== 'move' || covers(reach, room, change.to))));
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
+ });
131
138
  }
132
139
  function unreached(room) {
133
- return new Error(`No Local Replica for ${room}`);
140
+ return runtimeError('unknown-room', `Unknown Room ${room}`);
134
141
  }
135
- export function narrowed(runtime, given) {
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) {
136
156
  const { md, watch } = runtime;
137
157
  let reach = given;
138
158
  const open = new Set();
139
- function following(begin) {
159
+ function following(begin, locking = false) {
140
160
  let stop = begin();
141
161
  const restart = () => {
142
162
  stop();
143
163
  stop = begin();
144
164
  };
145
165
  open.add(restart);
166
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
146
167
  return () => {
147
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;
148
224
  stop();
149
225
  };
150
226
  }
151
- const within = (topic, input, deliver) => {
227
+ const within = (topic, input, deliver, fail) => {
228
+ if (topic === 'read' && reach !== null) {
229
+ fail(deviceUnreached());
230
+ return () => { };
231
+ }
152
232
  if (topic === 'rooms') {
153
- return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, 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));
154
237
  }
155
238
  if (topic === 'sync-status') {
156
- return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, 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);
157
243
  }
158
244
  if (topic === 'room-drafts') {
159
- return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
245
+ return following(() => unlockedWatch(topic, input, deliver, fail, (drafts, locked) => unlocked(draftsWithin(reach, drafts), locked)), true);
160
246
  }
161
247
  if (topic === 'queue') {
162
248
  const room = input[0];
163
- return following(() => {
164
- if (!holds(reach, room)) {
165
- deliver([]);
166
- return () => { };
167
- }
168
- return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
169
- });
249
+ return following(() => lockedFirst(room, () => watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)), fail), () => deliver([])), true);
170
250
  }
171
251
  if (topic === 'query') {
172
- const plan = runtime.plan(input[0], reach);
252
+ const planning = runtime.plan(input[0], reach);
173
253
  let held = null;
174
254
  return following(() => {
175
- let first = true;
176
- return runtime.watchPlan({ ...plan, reach: planReach(reach) }, (message) => {
177
- if (!first) {
178
- held = applied(held, message);
179
- deliver(message);
255
+ let open = true;
256
+ let stop = () => { };
257
+ void (async () => {
258
+ const plan = await planning;
259
+ const locked = await runtime.lockedRooms();
260
+ if (!open)
180
261
  return;
181
- }
182
- first = false;
183
- if (held === null) {
184
- held = message;
185
- deliver(message);
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);
186
268
  return;
187
269
  }
188
- const next = reconciled(held, message);
189
- if (next === null)
190
- return;
191
- held = next.keyed;
192
- deliver(next.change);
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);
193
294
  });
194
- });
295
+ return () => {
296
+ open = false;
297
+ stop();
298
+ };
299
+ }, true);
195
300
  }
196
301
  if (topic === 'conversation') {
197
302
  return following(() => {
198
303
  if (conversing(reach))
199
- return watch(topic, input, deliver);
304
+ return watch(topic, input, deliver, fail);
200
305
  deliver(unheldView(input[0]));
201
306
  return () => { };
202
307
  });
203
308
  }
204
- return watch(topic, input, deliver);
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);
205
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
+ }
206
336
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
207
337
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
208
338
  const view = {
209
339
  ...md,
210
- rooms: () => roomsWithin(reach, md.rooms()),
211
- query: ((input) => runtime.query(runtime.plan(input, reach))),
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
+ }),
212
346
  search: (input) => runtime.search(input, reach),
213
- types(room) {
347
+ async types(room) {
348
+ if (holds(reach, room) && (await runtime.locked(room)))
349
+ throw lockedError(room);
214
350
  if (wholly(reach, room))
215
351
  return md.types(room);
216
352
  if (!holds(reach, room))
217
353
  return structuredClone(UNHELD_TYPES);
218
- const listed = md.rooms().find(({ locator }) => locator === room);
219
- return typesWithin(reach, listed, md.types(room));
354
+ return typesWithin(reach, await runtime.room(room), await md.types(room));
220
355
  },
221
356
  async save(room, roomDrafts, writtenBy) {
222
357
  if (!holds(reach, room))
223
358
  throw unreached(room);
224
- const outside = roomDrafts.find(({ path }) => !covers(reach, room, path) ||
225
- !moves(reach, room, md.roomDraft.read(room, path)?.parts.move));
226
- if (outside !== undefined)
227
- return { outcome: 'refused', rule: 'stale', file: outside.path };
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 };
228
369
  return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
229
370
  },
230
- history: (room, path, query) => covers(reach, room, path)
231
- ? md.history(room, path, query)
232
- : Promise.resolve({ kind: 'room-not-readable', locator: room }),
233
- reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
234
- md.reached(room, roomVersion, path),
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)),
235
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())),
236
439
  roomDraft: {
237
- list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
238
- read: (room, path) => covers(reach, room, path) ? shownDraft(reach, md.roomDraft.read(room, path)) : null,
239
- async write(room, path, revision, parts) {
240
- if (!covers(reach, room, path) || !moves(reach, room, readParts(parts).move)) {
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))
241
453
  throw unreached(room);
242
- }
243
- return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
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));
244
459
  },
245
460
  async discard(room, path, revision) {
246
461
  if (!covers(reach, room, path))
247
- return { outcome: 'stale', current: null };
462
+ return staleWrite(null);
463
+ if (await runtime.locked(room))
464
+ throw lockedError(room);
248
465
  return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
249
466
  },
250
467
  },
@@ -252,15 +469,15 @@ export function narrowed(runtime, given) {
252
469
  list: () => conversation().list(),
253
470
  read: (id, options) => conversation().read(id, options),
254
471
  create: (input) => conversation().create(input),
255
- send: (id) => conversation().send(id),
472
+ send: (id, operation, draft) => conversation().send(id, operation, draft),
256
473
  answer: (id, answer) => conversation().answer(id, answer),
257
474
  interrupt: (id) => conversation().interrupt(id),
258
475
  kill: (id) => conversation().kill(id),
259
- cancel: (id, turn) => conversation().cancel(id, turn),
260
476
  delete: (id) => conversation().delete(id),
261
477
  },
262
478
  chatDraft: {
263
- write: (id, draft) => chatDraft().write(id, draft),
479
+ write: (id, draft, revision) => chatDraft().write(id, draft, revision),
480
+ prepend: (id, draft) => chatDraft().prepend(id, draft),
264
481
  discard: (id) => chatDraft().discard(id),
265
482
  },
266
483
  observe: observing(within),
@@ -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"}