@agentshouse/mdruntime 0.1.0-cc7bd7a53214e → 0.1.0-ccd098ff75bbf

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 (183) hide show
  1. package/README.md +24 -11
  2. package/dist/adapter.d.ts +172 -49
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +1 -9
  5. package/dist/attached-model.d.ts +15 -0
  6. package/dist/attached-model.d.ts.map +1 -0
  7. package/dist/attached-model.js +64 -0
  8. package/dist/attempt.d.ts +16 -0
  9. package/dist/attempt.d.ts.map +1 -0
  10. package/dist/attempt.js +70 -0
  11. package/dist/binary.d.ts +18 -0
  12. package/dist/binary.d.ts.map +1 -0
  13. package/dist/binary.js +8 -0
  14. package/dist/bootstrap.d.ts +39 -7
  15. package/dist/bootstrap.d.ts.map +1 -1
  16. package/dist/bootstrap.js +187 -45
  17. package/dist/chain.d.ts +11 -0
  18. package/dist/chain.d.ts.map +1 -0
  19. package/dist/chain.js +64 -0
  20. package/dist/change-set.d.ts +9 -14
  21. package/dist/change-set.d.ts.map +1 -1
  22. package/dist/change-set.js +11 -56
  23. package/dist/change.d.ts +45 -0
  24. package/dist/change.d.ts.map +1 -1
  25. package/dist/change.js +34 -0
  26. package/dist/client.d.ts +37 -15
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +110 -27
  29. package/dist/collection.d.ts +9 -13
  30. package/dist/collection.d.ts.map +1 -1
  31. package/dist/collection.js +46 -56
  32. package/dist/compile.d.ts +16 -0
  33. package/dist/compile.d.ts.map +1 -0
  34. package/dist/compile.js +740 -0
  35. package/dist/connection.d.ts +62 -25
  36. package/dist/connection.d.ts.map +1 -1
  37. package/dist/connection.js +3831 -958
  38. package/dist/conversation.d.ts +56 -16
  39. package/dist/conversation.d.ts.map +1 -1
  40. package/dist/conversation.js +739 -242
  41. package/dist/digest.d.ts +7 -0
  42. package/dist/digest.d.ts.map +1 -0
  43. package/dist/digest.js +113 -0
  44. package/dist/durability.d.ts +5 -1
  45. package/dist/durability.d.ts.map +1 -1
  46. package/dist/durability.js +5 -0
  47. package/dist/entry.d.ts +19 -0
  48. package/dist/entry.d.ts.map +1 -0
  49. package/dist/entry.js +151 -0
  50. package/dist/expectation.d.ts +21 -0
  51. package/dist/expectation.d.ts.map +1 -0
  52. package/dist/expectation.js +70 -0
  53. package/dist/failure.d.ts +13 -0
  54. package/dist/failure.d.ts.map +1 -0
  55. package/dist/failure.js +19 -0
  56. package/dist/fence.d.ts +6 -0
  57. package/dist/fence.d.ts.map +1 -0
  58. package/dist/fence.js +10 -0
  59. package/dist/file.d.ts +2 -10
  60. package/dist/file.d.ts.map +1 -1
  61. package/dist/file.js +3 -120
  62. package/dist/fulltext.d.ts +27 -0
  63. package/dist/fulltext.d.ts.map +1 -0
  64. package/dist/fulltext.js +368 -0
  65. package/dist/host.d.ts +15 -2
  66. package/dist/host.d.ts.map +1 -1
  67. package/dist/host.js +134 -31
  68. package/dist/identity.d.ts +4 -0
  69. package/dist/identity.d.ts.map +1 -1
  70. package/dist/identity.js +16 -1
  71. package/dist/index.d.ts +20 -9
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +8 -0
  74. package/dist/live.d.ts +22 -0
  75. package/dist/live.d.ts.map +1 -0
  76. package/dist/live.js +123 -0
  77. package/dist/memory.d.ts +22 -8
  78. package/dist/memory.d.ts.map +1 -1
  79. package/dist/memory.js +167 -47
  80. package/dist/messages.d.ts +28 -0
  81. package/dist/messages.d.ts.map +1 -0
  82. package/dist/messages.js +90 -0
  83. package/dist/model.d.ts +17 -14
  84. package/dist/model.d.ts.map +1 -1
  85. package/dist/model.js +16 -4
  86. package/dist/name.d.ts +4 -0
  87. package/dist/name.d.ts.map +1 -0
  88. package/dist/name.js +122 -0
  89. package/dist/observation.d.ts +19 -2
  90. package/dist/observation.d.ts.map +1 -1
  91. package/dist/observation.js +113 -12
  92. package/dist/open.d.ts +2 -0
  93. package/dist/open.d.ts.map +1 -0
  94. package/dist/open.js +1 -0
  95. package/dist/opened.d.ts +22 -0
  96. package/dist/opened.d.ts.map +1 -0
  97. package/dist/opened.js +107 -0
  98. package/dist/outcome.d.ts +62 -3
  99. package/dist/outcome.d.ts.map +1 -1
  100. package/dist/outcome.js +67 -1
  101. package/dist/overlay.d.ts +15 -5
  102. package/dist/overlay.d.ts.map +1 -1
  103. package/dist/overlay.js +136 -180
  104. package/dist/paths.d.ts +0 -1
  105. package/dist/paths.d.ts.map +1 -1
  106. package/dist/paths.js +0 -16
  107. package/dist/query.d.ts +65 -5
  108. package/dist/query.d.ts.map +1 -1
  109. package/dist/query.js +122 -40
  110. package/dist/reach.d.ts +11 -4
  111. package/dist/reach.d.ts.map +1 -1
  112. package/dist/reach.js +211 -75
  113. package/dist/react.d.ts +43 -0
  114. package/dist/react.d.ts.map +1 -0
  115. package/dist/react.js +54 -0
  116. package/dist/readiness.d.ts +64 -0
  117. package/dist/readiness.d.ts.map +1 -0
  118. package/dist/readiness.js +33 -0
  119. package/dist/reads.d.ts +11 -0
  120. package/dist/reads.d.ts.map +1 -0
  121. package/dist/reads.js +100 -0
  122. package/dist/recovery.d.ts +25 -0
  123. package/dist/recovery.d.ts.map +1 -0
  124. package/dist/recovery.js +198 -0
  125. package/dist/refresh.d.ts +19 -7
  126. package/dist/refresh.d.ts.map +1 -1
  127. package/dist/refresh.js +125 -53
  128. package/dist/replica.d.ts +59 -33
  129. package/dist/replica.d.ts.map +1 -1
  130. package/dist/replica.js +321 -156
  131. package/dist/room-draft.d.ts +41 -9
  132. package/dist/room-draft.d.ts.map +1 -1
  133. package/dist/room-draft.js +186 -37
  134. package/dist/rows.d.ts +37 -34
  135. package/dist/rows.d.ts.map +1 -1
  136. package/dist/rows.js +187 -82
  137. package/dist/save.d.ts +72 -6
  138. package/dist/save.d.ts.map +1 -1
  139. package/dist/save.js +889 -178
  140. package/dist/search.d.ts +41 -29
  141. package/dist/search.d.ts.map +1 -1
  142. package/dist/search.js +37 -105
  143. package/dist/seed.d.ts +16 -0
  144. package/dist/seed.d.ts.map +1 -0
  145. package/dist/seed.js +75 -0
  146. package/dist/shared.d.ts +16 -0
  147. package/dist/shared.d.ts.map +1 -0
  148. package/dist/shared.js +431 -0
  149. package/dist/status.d.ts +6 -2
  150. package/dist/status.d.ts.map +1 -1
  151. package/dist/status.js +0 -8
  152. package/dist/store.d.ts +123 -58
  153. package/dist/store.d.ts.map +1 -1
  154. package/dist/store.js +359 -344
  155. package/dist/stored.d.ts +145 -0
  156. package/dist/stored.d.ts.map +1 -0
  157. package/dist/stored.js +557 -0
  158. package/dist/tables.d.ts +354 -0
  159. package/dist/tables.d.ts.map +1 -0
  160. package/dist/tables.js +624 -0
  161. package/dist/turn.d.ts +9 -0
  162. package/dist/turn.d.ts.map +1 -0
  163. package/dist/turn.js +75 -0
  164. package/dist/validation.d.ts +30 -0
  165. package/dist/validation.d.ts.map +1 -0
  166. package/dist/validation.js +162 -0
  167. package/dist/windows.d.ts +22 -0
  168. package/dist/windows.d.ts.map +1 -0
  169. package/dist/windows.js +89 -0
  170. package/dist/wire.d.ts +170 -45
  171. package/dist/wire.d.ts.map +1 -1
  172. package/dist/wire.js +69 -46
  173. package/dist/words.d.ts +19 -0
  174. package/dist/words.d.ts.map +1 -0
  175. package/dist/words.js +150 -0
  176. package/package.json +33 -10
  177. package/AGENTS.md +0 -215
  178. package/dist/attachment.d.ts +0 -3
  179. package/dist/attachment.d.ts.map +0 -1
  180. package/dist/attachment.js +0 -8
  181. package/dist/read-side.d.ts +0 -18
  182. package/dist/read-side.d.ts.map +0 -1
  183. package/dist/read-side.js +0 -377
package/dist/reach.js CHANGED
@@ -1,28 +1,31 @@
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';
9
+ import { undeclaredSearch } from './search.js';
8
10
  const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
9
- const UNDECLARED = { kind: 'undeclared' };
10
- function undeclared() {
11
- return Promise.resolve(UNDECLARED);
11
+ function unconversed(name) {
12
+ return () => Promise.resolve(undeclared(name));
12
13
  }
13
14
  const NO_CONVERSATION = {
14
15
  list: () => Promise.resolve([]),
15
16
  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,
17
+ create: unconversed('conversation.create'),
18
+ send: unconversed('conversation.send'),
19
+ attach: unconversed('conversation.attach'),
20
+ answer: unconversed('conversation.answer'),
21
+ interrupt: unconversed('conversation.interrupt'),
22
+ kill: unconversed('conversation.kill'),
23
+ cancel: unconversed('conversation.cancel'),
24
+ delete: unconversed('conversation.delete'),
23
25
  };
24
26
  const NO_CHAT_DRAFT = {
25
27
  write: () => Promise.resolve(),
28
+ prepend: () => Promise.resolve(),
26
29
  discard: () => Promise.resolve(),
27
30
  };
28
31
  export function holds(reach, room) {
@@ -62,23 +65,7 @@ export function planReach(reach) {
62
65
  };
63
66
  }
64
67
  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
- attachedModel: governed.collection ? room.attachedModel : null,
76
- model: governed.collection ? room.model : modelTypes(NO_MODEL),
77
- typedSelection: governed.selection ? room.typedSelection : null,
78
- roomVersion: null,
79
- attachments: [],
80
- };
81
- });
68
+ return rooms.filter((room) => wholly(reach, room.locator));
82
69
  }
83
70
  function typesWithin(reach, room, types) {
84
71
  if (room === undefined)
@@ -90,7 +77,7 @@ function typesWithin(reach, room, types) {
90
77
  };
91
78
  }
92
79
  function moves(reach, room, move) {
93
- return move === undefined || covers(reach, room, moveTarget(move));
80
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
94
81
  }
95
82
  function draftWithin(reach, draft) {
96
83
  return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
@@ -104,7 +91,7 @@ function shownDraft(reach, draft) {
104
91
  function writeWithin(reach, write) {
105
92
  return write.outcome === 'written'
106
93
  ? { outcome: 'written', roomDraft: shownDraft(reach, write.roomDraft) }
107
- : { outcome: 'stale', current: shownDraft(reach, write.current) };
94
+ : staleWrite(shownDraft(reach, write.current));
108
95
  }
109
96
  function savedWithin(reach, room, result) {
110
97
  if (reach === null || result.outcome === 'saved')
@@ -123,76 +110,120 @@ function savedWithin(reach, room, result) {
123
110
  function statusWithin(reach, status) {
124
111
  return {
125
112
  ...status,
126
- attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
113
+ attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
127
114
  };
128
115
  }
129
116
  function queueWithin(reach, room, entries) {
130
- return entries.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
131
- (change.kind !== 'move' || covers(reach, room, change.to))));
117
+ return entries
118
+ .filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
119
+ (change.kind !== 'move' || covers(reach, room, change.to))))
120
+ .map((entry) => {
121
+ const { between, ...batch } = entry.batch;
122
+ if (between === undefined)
123
+ return entry;
124
+ return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
125
+ ? entry
126
+ : { ...entry, batch };
127
+ });
132
128
  }
133
129
  function unreached(room) {
134
- return new Error(`No Local Replica for ${room}`);
130
+ return runtimeError('room-not-held', `No Local Replica for ${room}`);
131
+ }
132
+ function lockedError(room) {
133
+ return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
134
+ }
135
+ function deviceUnreached() {
136
+ return runtimeError('device-unreached', 'Only the panel cleans up this device');
135
137
  }
136
- export function narrowed(runtime, given) {
138
+ export function narrowed(runtime, given, told) {
137
139
  const { md, watch } = runtime;
138
140
  let reach = given;
141
+ let port = told;
139
142
  const open = new Set();
140
- function following(begin) {
143
+ function following(begin, locking = false) {
141
144
  let stop = begin();
142
145
  const restart = () => {
143
146
  stop();
144
147
  stop = begin();
145
148
  };
146
149
  open.add(restart);
150
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
147
151
  return () => {
148
152
  open.delete(restart);
153
+ unwatch();
149
154
  stop();
150
155
  };
151
156
  }
157
+ const unlocking = (rooms) => {
158
+ const locked = (rooms ?? []).filter((room) => runtime.locked(room));
159
+ return locked.length === 0
160
+ ? null
161
+ : { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
162
+ };
163
+ const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
164
+ const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
152
165
  const within = (topic, input, deliver) => {
153
166
  if (topic === 'rooms') {
154
167
  return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
155
168
  }
169
+ if (topic === 'readiness') {
170
+ return following(() => runtime.watchReadiness(port, reach, deliver));
171
+ }
156
172
  if (topic === 'sync-status') {
157
- return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, status))));
173
+ return following(() => watch(topic, input, (status) => {
174
+ const within = statusWithin(reach, status);
175
+ deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
176
+ }), true);
158
177
  }
159
178
  if (topic === 'room-drafts') {
160
- return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
179
+ return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
161
180
  }
162
181
  if (topic === 'queue') {
163
182
  const room = input[0];
164
183
  return following(() => {
165
- if (!holds(reach, room)) {
184
+ if (!holds(reach, room) || runtime.locked(room)) {
166
185
  deliver([]);
167
186
  return () => { };
168
187
  }
169
188
  return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
170
- });
189
+ }, true);
171
190
  }
172
191
  if (topic === 'query') {
173
192
  const plan = runtime.plan(input[0], reach);
174
193
  let held = null;
175
194
  return following(() => {
195
+ const locked = unlocking(plan.rooms);
196
+ if (locked !== null) {
197
+ const answer = { result: locked, keys: [] };
198
+ if (held === null || changeOf(held, answer) !== null)
199
+ deliver(answer);
200
+ held = digestOf(answer);
201
+ return () => { };
202
+ }
176
203
  let first = true;
177
- return runtime.watchPlan({ ...plan, reach: planReach(reach) }, (message) => {
204
+ let open = true;
205
+ const heard = (message) => {
178
206
  if (!first) {
179
- held = applied(held, message);
207
+ held = digestApplied(held, message);
180
208
  deliver(message);
181
209
  return;
182
210
  }
183
211
  first = false;
184
- if (held === null) {
185
- held = message;
186
- deliver(message);
187
- return;
188
- }
189
- const next = reconciled(held, message);
190
- if (next === null)
191
- return;
192
- held = next.keyed;
193
- deliver(next.change);
212
+ const change = held === null ? message : changeOf(held, message);
213
+ held = digestOf(message);
214
+ if (change !== null)
215
+ deliver(change);
216
+ };
217
+ const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
218
+ const stop = runtime.watchPlan(current, (message) => {
219
+ if (open)
220
+ heard(message);
194
221
  });
195
- });
222
+ return () => {
223
+ open = false;
224
+ stop();
225
+ };
226
+ }, true);
196
227
  }
197
228
  if (topic === 'conversation') {
198
229
  return following(() => {
@@ -202,16 +233,42 @@ export function narrowed(runtime, given) {
202
233
  return () => { };
203
234
  });
204
235
  }
236
+ if (topic === 'conversations' || topic === 'agents') {
237
+ return following(() => {
238
+ if (conversing(reach))
239
+ return watch(topic, input, deliver);
240
+ deliver([]);
241
+ return () => { };
242
+ });
243
+ }
205
244
  return watch(topic, input, deliver);
206
245
  };
246
+ const files = new Map();
247
+ let handed = 0;
248
+ const hand = async (reading) => {
249
+ const answer = await reading;
250
+ if (answer.kind !== 'binary')
251
+ return answer;
252
+ handed += 1;
253
+ const file = String(handed);
254
+ files.set(file, answer.file);
255
+ return { ...answer, file };
256
+ };
207
257
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
208
258
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
209
259
  const view = {
210
260
  ...md,
211
261
  rooms: () => roomsWithin(reach, md.rooms()),
212
- query: ((input) => runtime.query(runtime.plan(input, reach))),
213
- search: (input) => runtime.search(input, reach),
262
+ query: ((input) => {
263
+ const plan = runtime.plan(input, reach);
264
+ return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
265
+ }),
266
+ search: (input) => port.search === 'required'
267
+ ? runtime.search(input, reach, runtime.lockedRooms())
268
+ : Promise.resolve(undeclaredSearch()),
214
269
  types(room) {
270
+ if (holds(reach, room) && runtime.locked(room))
271
+ throw lockedError(room);
215
272
  if (wholly(reach, room))
216
273
  return md.types(room);
217
274
  if (!holds(reach, room))
@@ -222,30 +279,98 @@ export function narrowed(runtime, given) {
222
279
  async save(room, roomDrafts, writtenBy) {
223
280
  if (!holds(reach, room))
224
281
  throw unreached(room);
225
- const outside = roomDrafts.find(({ path }) => !covers(reach, room, path) ||
226
- !moves(reach, room, md.roomDraft.read(room, path)?.parts.move));
227
- if (outside !== undefined)
228
- return { outcome: 'refused', rule: 'stale', file: outside.path };
282
+ if (runtime.locked(room))
283
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
284
+ const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
285
+ const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
286
+ if (outside !== undefined) {
287
+ return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
288
+ }
289
+ if (intoLocked(held))
290
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
229
291
  return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
230
292
  },
231
- history: (room, path, query) => covers(reach, room, path)
232
- ? md.history(room, path, query)
233
- : Promise.resolve({ kind: 'room-not-readable', locator: room }),
234
- reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
235
- md.reached(room, roomVersion, path),
293
+ async saveParts(room, parts, writtenBy) {
294
+ if (!holds(reach, room))
295
+ throw unreached(room);
296
+ if (runtime.locked(room))
297
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
298
+ const held = parts.map(({ parts: one }) => readParts(one).move);
299
+ if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
300
+ throw unreached(room);
301
+ }
302
+ if (intoLocked(held))
303
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
304
+ return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
305
+ },
306
+ resolve(room, path, destination) {
307
+ const at = runtime.located(room, path, destination);
308
+ return at !== null && !covers(reach, at.room, at.path)
309
+ ? Promise.resolve(UNREADABLE)
310
+ : md.resolve(room, path, destination);
311
+ },
312
+ history: (room, path, query) => !covers(reach, room, path)
313
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
314
+ : runtime.locked(room)
315
+ ? Promise.resolve(lockedRoom(room))
316
+ : md.history(room, path, query),
317
+ binaryFile: {
318
+ read: (room, path, revision) => !covers(reach, room, path)
319
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
320
+ : runtime.locked(room)
321
+ ? Promise.resolve(lockedRoom(room))
322
+ : hand(md.binaryFile.read(room, path, revision)),
323
+ link: (room, path, revision) => !covers(reach, room, path)
324
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
325
+ : runtime.locked(room)
326
+ ? Promise.resolve(lockedRoom(room))
327
+ : md.binaryFile.link(room, path, revision),
328
+ async part(file, part) {
329
+ const key = files.get(file);
330
+ if (key === undefined)
331
+ return null;
332
+ const bytes = await md.binaryFile.part(key, part);
333
+ if (bytes === null)
334
+ files.delete(file);
335
+ return bytes;
336
+ },
337
+ },
338
+ reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
339
+ !runtime.locked(room) &&
340
+ (await md.reached(room, roomVersion, path)),
236
341
  log: () => (reach === null ? md.log() : ''),
342
+ cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
237
343
  roomDraft: {
238
- list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
239
- read: (room, path) => covers(reach, room, path) ? shownDraft(reach, md.roomDraft.read(room, path)) : null,
240
- async write(room, path, revision, parts) {
241
- if (!covers(reach, room, path) || !moves(reach, room, readParts(parts).move)) {
242
- throw unreached(room);
344
+ list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
345
+ async read(room, path) {
346
+ if (!covers(reach, room, path))
347
+ return null;
348
+ if (runtime.locked(room))
349
+ throw lockedError(room);
350
+ return shownDraft(reach, await md.roomDraft.read(room, path));
351
+ },
352
+ write(room, path, revision, parts, next) {
353
+ try {
354
+ const move = readParts(parts).move;
355
+ if (!covers(reach, room, path) || !moves(reach, room, move))
356
+ throw unreached(room);
357
+ if (runtime.locked(room))
358
+ throw lockedError(room);
359
+ if (intoLocked([move]))
360
+ throw lockedError(move.room);
243
361
  }
244
- return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
362
+ catch (error) {
363
+ return Promise.reject(error);
364
+ }
365
+ return md.roomDraft
366
+ .write(room, path, revision, parts, next)
367
+ .then((written) => writeWithin(reach, written));
245
368
  },
246
369
  async discard(room, path, revision) {
247
370
  if (!covers(reach, room, path))
248
- return { outcome: 'stale', current: null };
371
+ return staleWrite(null);
372
+ if (runtime.locked(room))
373
+ throw lockedError(room);
249
374
  return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
250
375
  },
251
376
  },
@@ -253,7 +378,12 @@ export function narrowed(runtime, given) {
253
378
  list: () => conversation().list(),
254
379
  read: (id, options) => conversation().read(id, options),
255
380
  create: (input) => conversation().create(input),
256
- send: (id) => conversation().send(id),
381
+ send: (id, operation, draft) => conversation().send(id, operation, draft),
382
+ attach: (room, file) => !wholly(reach, room)
383
+ ? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
384
+ : runtime.locked(room)
385
+ ? Promise.resolve(lockedRoom(room))
386
+ : conversation().attach(room, file),
257
387
  answer: (id, answer) => conversation().answer(id, answer),
258
388
  interrupt: (id) => conversation().interrupt(id),
259
389
  kill: (id) => conversation().kill(id),
@@ -261,7 +391,8 @@ export function narrowed(runtime, given) {
261
391
  delete: (id) => conversation().delete(id),
262
392
  },
263
393
  chatDraft: {
264
- write: (id, draft) => chatDraft().write(id, draft),
394
+ write: (id, draft, revision) => chatDraft().write(id, draft, revision),
395
+ prepend: (id, draft) => chatDraft().prepend(id, draft),
265
396
  discard: (id) => chatDraft().discard(id),
266
397
  },
267
398
  observe: observing(within),
@@ -274,5 +405,10 @@ export function narrowed(runtime, given) {
274
405
  for (const restart of [...open])
275
406
  restart();
276
407
  },
408
+ facts(next) {
409
+ port = next;
410
+ for (const restart of [...open])
411
+ restart();
412
+ },
277
413
  };
278
414
  }
@@ -0,0 +1,43 @@
1
+ import type { MdRuntimeClient } from './client.js';
2
+ import type { AppRoom, ConnectionRefusal, SavedRoomDraft, SaveResult } from './connection.js';
3
+ import type { Member, ServiceMode } from './adapter.js';
4
+ import type { ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
5
+ import { type RuntimeError } from './failure.js';
6
+ import type { QueueEntry } from './outcome.js';
7
+ import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult, PendingResult } from './query.js';
8
+ import type { Readiness } from './readiness.js';
9
+ import type { RoomDraft, RoomDraftParts } from './room-draft.js';
10
+ import type { SyncStatus } from './status.js';
11
+ type Client = MdRuntimeClient | null;
12
+ export type Observed<T> = {
13
+ readonly state: 'loading';
14
+ } | {
15
+ readonly state: 'ready';
16
+ readonly value: T;
17
+ };
18
+ export declare function useObserve(client: Client, topic: 'deployment-facts'): Observed<unknown>;
19
+ export declare function useObserve(client: Client, topic: 'rooms'): Observed<readonly AppRoom[]>;
20
+ export declare function useObserve(client: Client, topic: 'readiness'): Observed<Readiness>;
21
+ export declare function useObserve(client: Client, topic: 'connection-refusal'): Observed<ConnectionRefusal | null>;
22
+ export declare function useObserve(client: Client, topic: 'storage-loss'): Observed<string | null>;
23
+ export declare function useObserve(client: Client, topic: 'sync-status'): Observed<SyncStatus>;
24
+ export declare function useObserve(client: Client, topic: 'service-mode'): Observed<ServiceMode>;
25
+ export declare function useObserve(client: Client, topic: 'member'): Observed<Member | null>;
26
+ export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult | PendingResult>;
27
+ export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult | PendingResult>;
28
+ export declare function useObserve(client: Client, topic: 'queue', locator: string): Observed<readonly QueueEntry[]>;
29
+ export declare function useObserve(client: Client, topic: 'room-drafts'): Observed<readonly RoomDraft[]>;
30
+ export declare function useObserve(client: Client, topic: 'presentation'): Observed<unknown>;
31
+ export declare function useObserve(client: Client, topic: 'conversation', conversation: string, options: ConversationOptions): Observed<ConversationView>;
32
+ export declare function useObserve(client: Client, topic: 'conversations'): Observed<readonly ConversationEntry[]>;
33
+ export declare function useObserve(client: Client, topic: 'agents'): Observed<readonly ConversationAgent[]>;
34
+ export type Saving = {
35
+ readonly busy: boolean;
36
+ readonly outcome: SaveResult | null;
37
+ readonly failure: RuntimeError | null;
38
+ save(room: string, parts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
39
+ saveWritten(room: string, roomDrafts: readonly SavedRoomDraft[]): Promise<SaveResult>;
40
+ };
41
+ export declare function useSave(client: MdRuntimeClient): Saving;
42
+ export {};
43
+ //# 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
+ }
@@ -0,0 +1,64 @@
1
+ import type { Open } from './open.js';
2
+ export type CodeAvailability = Open<'stored' | 'absent'>;
3
+ export type RoomPreparation = Open<'complete' | 'acquiring' | 'preparing' | 'refused' | 'unadmitted'>;
4
+ export type RoomCoverage = {
5
+ readonly room: string;
6
+ readonly state: RoomPreparation;
7
+ };
8
+ export type ConversationCoverage = Open<'complete' | 'acquiring' | 'undeclared'>;
9
+ export type SearchObligation = Open<'required' | 'unused'>;
10
+ export type TargetCoverage = {
11
+ readonly complete: boolean;
12
+ readonly listed: boolean;
13
+ readonly rooms: readonly RoomCoverage[];
14
+ readonly conversations: ConversationCoverage;
15
+ readonly search: SearchObligation;
16
+ };
17
+ export type Persistence = Open<'granted' | 'denied' | 'unavailable'>;
18
+ export type Durability = Open<'persistent' | 'best-effort'>;
19
+ export type ConnectionAvailability = Open<'connected' | 'connecting' | 'unreachable'>;
20
+ export type HouseOutcome = Open<'open' | 'write-halted' | 'refused'>;
21
+ export type Space = Open<'full'>;
22
+ export type RefusedRoom = {
23
+ readonly room: string;
24
+ readonly name: string;
25
+ readonly file: string;
26
+ readonly rule: string;
27
+ readonly location: string | null;
28
+ };
29
+ export type InstallationStep = Open<'listing' | 'downloading' | 'writing' | 'replaying'>;
30
+ export type InstallationPause = Open<'hidden'>;
31
+ export type InstallationAmount = {
32
+ readonly done: number;
33
+ readonly total: number;
34
+ };
35
+ export type Installation = {
36
+ readonly step: InstallationStep | null;
37
+ readonly paused: InstallationPause | null;
38
+ readonly rooms: InstallationAmount;
39
+ readonly parts: InstallationAmount;
40
+ readonly bytes: InstallationAmount;
41
+ readonly received: InstallationAmount;
42
+ };
43
+ export type ReadinessStatus = Open<'preparing' | 'paused' | 'refused' | 'ready' | 'lost'>;
44
+ export type Readiness = {
45
+ readonly status: ReadinessStatus;
46
+ readonly ready: boolean;
47
+ readonly usable: boolean;
48
+ readonly code: CodeAvailability;
49
+ readonly coverage: TargetCoverage;
50
+ readonly durability: Durability;
51
+ readonly persistence: Persistence;
52
+ readonly connection: ConnectionAvailability;
53
+ readonly house: HouseOutcome;
54
+ readonly space: Space | null;
55
+ readonly installation: Installation;
56
+ readonly refused: readonly RefusedRoom[];
57
+ readonly lost: boolean;
58
+ };
59
+ export type ReadinessFacts = Omit<Readiness, 'status' | 'ready' | 'usable' | 'durability' | 'coverage'> & {
60
+ readonly coverage: Omit<TargetCoverage, 'complete'>;
61
+ readonly established: boolean;
62
+ };
63
+ export declare function readinessOf(facts: ReadinessFacts): Readiness;
64
+ //# sourceMappingURL=readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ const COMPLETE_ROOMS = new Set(['complete', 'unadmitted']);
2
+ const SETTLED_ROOMS = new Set([...COMPLETE_ROOMS, 'refused']);
3
+ export function readinessOf(facts) {
4
+ const { established, coverage: held, ...reported } = facts;
5
+ const settledConversations = held.conversations === 'complete' || held.conversations === 'undeclared';
6
+ const complete = held.listed &&
7
+ settledConversations &&
8
+ held.rooms.every((room) => COMPLETE_ROOMS.has(room.state));
9
+ const settled = held.listed &&
10
+ settledConversations &&
11
+ held.rooms.every((room) => SETTLED_ROOMS.has(room.state));
12
+ const coverage = { ...held, complete };
13
+ const stored = facts.code === 'stored';
14
+ const ready = stored && complete;
15
+ const usable = stored && (ready || established);
16
+ const status = ready
17
+ ? 'ready'
18
+ : facts.space !== null || facts.installation.paused !== null
19
+ ? 'paused'
20
+ : settled && !complete
21
+ ? 'refused'
22
+ : facts.lost && !established
23
+ ? 'lost'
24
+ : 'preparing';
25
+ return {
26
+ ...reported,
27
+ coverage,
28
+ status,
29
+ ready,
30
+ usable,
31
+ durability: facts.persistence === 'granted' ? 'persistent' : 'best-effort',
32
+ };
33
+ }
@@ -0,0 +1,11 @@
1
+ import type { Adapter } from './adapter.js';
2
+ import type { Reads } from './bootstrap.js';
3
+ export type DoorReads = Reads & {
4
+ carried(locator: string): number;
5
+ finished(locator: string, turn: number): void;
6
+ opened(): void;
7
+ applied(): void;
8
+ lost(): void;
9
+ };
10
+ export declare function doorReads(adapter: Adapter, declaration: (locator: string) => unknown, generation: () => number): DoorReads;
11
+ //# sourceMappingURL=reads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAkCF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA4FX"}