@agentshouse/mdruntime 0.1.0-cedb03eaa48b6 → 0.1.0-cedd665dffa4c

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 (395) hide show
  1. package/README.md +24 -19
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +299 -0
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +26 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +302 -0
  11. package/dist/adapter.d.ts +173 -125
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +6 -10
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +35 -41
  16. package/dist/binary.d.ts +0 -5
  17. package/dist/binary.d.ts.map +1 -1
  18. package/dist/binary.js +1 -1
  19. package/dist/bootstrap.d.ts +30 -11
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +309 -113
  22. package/dist/cell.d.ts +6 -0
  23. package/dist/cell.d.ts.map +1 -0
  24. package/dist/cell.js +9 -0
  25. package/dist/chain.d.ts +12 -0
  26. package/dist/chain.d.ts.map +1 -0
  27. package/dist/chain.js +64 -0
  28. package/dist/change-set.d.ts +13 -16
  29. package/dist/change-set.d.ts.map +1 -1
  30. package/dist/change-set.js +17 -89
  31. package/dist/change.d.ts +36 -1
  32. package/dist/change.d.ts.map +1 -1
  33. package/dist/change.js +17 -3
  34. package/dist/chat-types.d.ts +3 -0
  35. package/dist/chat-types.d.ts.map +1 -0
  36. package/dist/chat-types.js +11 -0
  37. package/dist/client.d.ts +37 -26
  38. package/dist/client.d.ts.map +1 -1
  39. package/dist/client.js +113 -23
  40. package/dist/collection.d.ts +32 -21
  41. package/dist/collection.d.ts.map +1 -1
  42. package/dist/collection.js +53 -318
  43. package/dist/compile.d.ts +18 -0
  44. package/dist/compile.d.ts.map +1 -0
  45. package/dist/compile.js +723 -0
  46. package/dist/connection.d.ts +7 -137
  47. package/dist/connection.d.ts.map +1 -1
  48. package/dist/connection.js +110 -3602
  49. package/dist/context.d.ts +2 -0
  50. package/dist/context.d.ts.map +1 -0
  51. package/dist/{chat/context.js → context.js} +2 -5
  52. package/dist/conversation-live.d.ts +150 -0
  53. package/dist/conversation-live.d.ts.map +1 -0
  54. package/dist/conversation-live.js +259 -0
  55. package/dist/conversation-row.d.ts +40 -0
  56. package/dist/conversation-row.d.ts.map +1 -0
  57. package/dist/conversation-row.js +66 -0
  58. package/dist/conversation.d.ts +75 -49
  59. package/dist/conversation.d.ts.map +1 -1
  60. package/dist/conversation.js +1029 -806
  61. package/dist/declaration.d.ts +10 -0
  62. package/dist/declaration.d.ts.map +1 -0
  63. package/dist/declaration.js +24 -0
  64. package/dist/digest.d.ts +7 -0
  65. package/dist/digest.d.ts.map +1 -0
  66. package/dist/digest.js +113 -0
  67. package/dist/discovery.d.ts +10 -0
  68. package/dist/discovery.d.ts.map +1 -0
  69. package/dist/discovery.js +150 -0
  70. package/dist/durability.d.ts +20 -4
  71. package/dist/durability.d.ts.map +1 -1
  72. package/dist/durability.js +9 -0
  73. package/dist/entry.d.ts +5 -2
  74. package/dist/entry.d.ts.map +1 -1
  75. package/dist/entry.js +33 -29
  76. package/dist/expectation.d.ts +26 -13
  77. package/dist/expectation.d.ts.map +1 -1
  78. package/dist/expectation.js +72 -19
  79. package/dist/failure.d.ts +3 -0
  80. package/dist/failure.d.ts.map +1 -1
  81. package/dist/failure.js +6 -0
  82. package/dist/figures.d.ts +49 -0
  83. package/dist/figures.d.ts.map +1 -0
  84. package/dist/figures.js +199 -0
  85. package/dist/file.d.ts +2 -19
  86. package/dist/file.d.ts.map +1 -1
  87. package/dist/file.js +8 -122
  88. package/dist/holdings.d.ts +29 -0
  89. package/dist/holdings.d.ts.map +1 -0
  90. package/dist/holdings.js +95 -0
  91. package/dist/host.d.ts +21 -8
  92. package/dist/host.d.ts.map +1 -1
  93. package/dist/host.js +119 -51
  94. package/dist/identity.d.ts +0 -2
  95. package/dist/identity.d.ts.map +1 -1
  96. package/dist/identity.js +0 -6
  97. package/dist/index.d.ts +41 -16
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +19 -4
  100. package/dist/install.d.ts +60 -0
  101. package/dist/install.d.ts.map +1 -0
  102. package/dist/install.js +537 -0
  103. package/dist/lifecycle.d.ts +7 -0
  104. package/dist/lifecycle.d.ts.map +1 -0
  105. package/dist/lifecycle.js +278 -0
  106. package/dist/listing.d.ts +52 -0
  107. package/dist/listing.d.ts.map +1 -0
  108. package/dist/listing.js +152 -0
  109. package/dist/live.d.ts +25 -0
  110. package/dist/live.d.ts.map +1 -0
  111. package/dist/live.js +206 -0
  112. package/dist/loaded.d.ts +5 -0
  113. package/dist/loaded.d.ts.map +1 -0
  114. package/dist/loaded.js +40 -0
  115. package/dist/locks.d.ts +7 -0
  116. package/dist/locks.d.ts.map +1 -0
  117. package/dist/locks.js +32 -0
  118. package/dist/lost.d.ts +5 -0
  119. package/dist/lost.d.ts.map +1 -0
  120. package/dist/lost.js +49 -0
  121. package/dist/media.d.ts +13 -0
  122. package/dist/media.d.ts.map +1 -0
  123. package/dist/media.js +269 -0
  124. package/dist/memory.d.ts +19 -7
  125. package/dist/memory.d.ts.map +1 -1
  126. package/dist/memory.js +281 -118
  127. package/dist/messages.d.ts +58 -0
  128. package/dist/messages.d.ts.map +1 -0
  129. package/dist/messages.js +162 -0
  130. package/dist/model.d.ts +8 -11
  131. package/dist/model.d.ts.map +1 -1
  132. package/dist/model.js +6 -23
  133. package/dist/models.d.ts +10 -0
  134. package/dist/models.d.ts.map +1 -0
  135. package/dist/models.js +153 -0
  136. package/dist/name.d.ts +4 -0
  137. package/dist/name.d.ts.map +1 -0
  138. package/dist/name.js +122 -0
  139. package/dist/observation.d.ts +38 -10
  140. package/dist/observation.d.ts.map +1 -1
  141. package/dist/observation.js +232 -44
  142. package/dist/opened.d.ts +22 -0
  143. package/dist/opened.d.ts.map +1 -0
  144. package/dist/opened.js +107 -0
  145. package/dist/opening.d.ts +4 -0
  146. package/dist/opening.d.ts.map +1 -0
  147. package/dist/opening.js +53 -0
  148. package/dist/outcome.d.ts +51 -9
  149. package/dist/outcome.d.ts.map +1 -1
  150. package/dist/outcome.js +62 -2
  151. package/dist/overlay.d.ts +8 -6
  152. package/dist/overlay.d.ts.map +1 -1
  153. package/dist/overlay.js +121 -182
  154. package/dist/page-metadata.d.ts +8 -0
  155. package/dist/page-metadata.d.ts.map +1 -0
  156. package/dist/page-metadata.js +19 -0
  157. package/dist/parts.d.ts +4 -0
  158. package/dist/parts.d.ts.map +1 -0
  159. package/dist/parts.js +13 -0
  160. package/dist/paths.d.ts +2 -0
  161. package/dist/paths.d.ts.map +1 -1
  162. package/dist/paths.js +26 -0
  163. package/dist/preparation.d.ts +41 -0
  164. package/dist/preparation.d.ts.map +1 -0
  165. package/dist/preparation.js +314 -0
  166. package/dist/presence.d.ts +58 -0
  167. package/dist/presence.d.ts.map +1 -0
  168. package/dist/presence.js +231 -0
  169. package/dist/queries.d.ts +16 -0
  170. package/dist/queries.d.ts.map +1 -0
  171. package/dist/queries.js +308 -0
  172. package/dist/query.d.ts +21 -207
  173. package/dist/query.d.ts.map +1 -1
  174. package/dist/query.js +3 -493
  175. package/dist/{chat/questions.d.ts → questions.d.ts} +5 -7
  176. package/dist/questions.d.ts.map +1 -0
  177. package/dist/{chat/questions.js → questions.js} +11 -7
  178. package/dist/queue.d.ts +40 -0
  179. package/dist/queue.d.ts.map +1 -0
  180. package/dist/queue.js +480 -0
  181. package/dist/reach.d.ts +21 -11
  182. package/dist/reach.d.ts.map +1 -1
  183. package/dist/reach.js +342 -112
  184. package/dist/react.d.ts +17 -3
  185. package/dist/react.d.ts.map +1 -1
  186. package/dist/react.js +33 -1
  187. package/dist/{chat/read.d.ts → read.d.ts} +2 -0
  188. package/dist/read.d.ts.map +1 -0
  189. package/dist/{chat/read.js → read.js} +4 -0
  190. package/dist/readiness.d.ts +22 -20
  191. package/dist/readiness.d.ts.map +1 -1
  192. package/dist/readiness.js +5 -13
  193. package/dist/reads.d.ts +38 -10
  194. package/dist/reads.d.ts.map +1 -1
  195. package/dist/reads.js +163 -83
  196. package/dist/recovery.d.ts +5 -2
  197. package/dist/recovery.d.ts.map +1 -1
  198. package/dist/recovery.js +65 -8
  199. package/dist/refresh.d.ts +18 -15
  200. package/dist/refresh.d.ts.map +1 -1
  201. package/dist/refresh.js +145 -60
  202. package/dist/refusal.d.ts +5 -0
  203. package/dist/refusal.d.ts.map +1 -0
  204. package/dist/refusal.js +55 -0
  205. package/dist/replica.d.ts +49 -36
  206. package/dist/replica.d.ts.map +1 -1
  207. package/dist/replica.js +322 -198
  208. package/dist/retried.d.ts +30 -0
  209. package/dist/retried.d.ts.map +1 -0
  210. package/dist/retried.js +72 -0
  211. package/dist/room-draft.d.ts +55 -13
  212. package/dist/room-draft.d.ts.map +1 -1
  213. package/dist/room-draft.js +416 -122
  214. package/dist/room-drafts.d.ts +24 -0
  215. package/dist/room-drafts.d.ts.map +1 -0
  216. package/dist/room-drafts.js +220 -0
  217. package/dist/rows.d.ts +32 -31
  218. package/dist/rows.d.ts.map +1 -1
  219. package/dist/rows.js +59 -124
  220. package/dist/runtime.d.ts +34 -0
  221. package/dist/runtime.d.ts.map +1 -0
  222. package/dist/runtime.js +1 -0
  223. package/dist/save.d.ts +43 -49
  224. package/dist/save.d.ts.map +1 -1
  225. package/dist/save.js +736 -302
  226. package/dist/saves.d.ts +32 -0
  227. package/dist/saves.d.ts.map +1 -0
  228. package/dist/saves.js +426 -0
  229. package/dist/search.d.ts +12 -95
  230. package/dist/search.d.ts.map +1 -1
  231. package/dist/search.js +10 -266
  232. package/dist/seed.d.ts +11 -2
  233. package/dist/seed.d.ts.map +1 -1
  234. package/dist/seed.js +71 -1
  235. package/dist/shared.d.ts +6 -7
  236. package/dist/shared.d.ts.map +1 -1
  237. package/dist/shared.js +75 -104
  238. package/dist/shown.d.ts +33 -0
  239. package/dist/shown.d.ts.map +1 -0
  240. package/dist/shown.js +309 -0
  241. package/dist/socket/admission.d.ts +7 -0
  242. package/dist/socket/admission.d.ts.map +1 -0
  243. package/dist/socket/admission.js +39 -0
  244. package/dist/socket/answers.d.ts +6 -0
  245. package/dist/socket/answers.d.ts.map +1 -0
  246. package/dist/socket/answers.js +20 -0
  247. package/dist/socket/lanes.d.ts +28 -0
  248. package/dist/socket/lanes.d.ts.map +1 -0
  249. package/dist/socket/lanes.js +103 -0
  250. package/dist/socket/reads.d.ts +10 -0
  251. package/dist/socket/reads.d.ts.map +1 -0
  252. package/dist/socket/reads.js +31 -0
  253. package/dist/socket/session.d.ts +38 -0
  254. package/dist/socket/session.d.ts.map +1 -0
  255. package/dist/socket/session.js +23 -0
  256. package/dist/socket.d.ts +67 -0
  257. package/dist/socket.d.ts.map +1 -0
  258. package/dist/socket.js +164 -0
  259. package/dist/source.d.ts +59 -0
  260. package/dist/source.d.ts.map +1 -0
  261. package/dist/source.js +93 -0
  262. package/dist/status.d.ts +4 -5
  263. package/dist/status.d.ts.map +1 -1
  264. package/dist/status.js +3 -7
  265. package/dist/store/installs.d.ts +30 -0
  266. package/dist/store/installs.d.ts.map +1 -0
  267. package/dist/store/installs.js +40 -0
  268. package/dist/store/readiness.d.ts +11 -0
  269. package/dist/store/readiness.d.ts.map +1 -0
  270. package/dist/store/readiness.js +68 -0
  271. package/dist/store/records.d.ts +217 -0
  272. package/dist/store/records.d.ts.map +1 -0
  273. package/dist/store/records.js +464 -0
  274. package/dist/store/room-held.d.ts +8 -0
  275. package/dist/store/room-held.d.ts.map +1 -0
  276. package/dist/store/room-held.js +17 -0
  277. package/dist/store/rooms-shown.d.ts +8 -0
  278. package/dist/store/rooms-shown.d.ts.map +1 -0
  279. package/dist/store/rooms-shown.js +13 -0
  280. package/dist/store/space.d.ts +11 -0
  281. package/dist/store/space.d.ts.map +1 -0
  282. package/dist/store/space.js +41 -0
  283. package/dist/store/watchers.d.ts +17 -0
  284. package/dist/store/watchers.d.ts.map +1 -0
  285. package/dist/store/watchers.js +56 -0
  286. package/dist/store/writes.d.ts +24 -0
  287. package/dist/store/writes.d.ts.map +1 -0
  288. package/dist/store/writes.js +125 -0
  289. package/dist/store.d.ts +114 -163
  290. package/dist/store.d.ts.map +1 -1
  291. package/dist/store.js +163 -750
  292. package/dist/stored.d.ts +167 -0
  293. package/dist/stored.d.ts.map +1 -0
  294. package/dist/stored.js +703 -0
  295. package/dist/surface.d.ts +89 -0
  296. package/dist/surface.d.ts.map +1 -0
  297. package/dist/surface.js +222 -0
  298. package/dist/sync.d.ts +19 -0
  299. package/dist/sync.d.ts.map +1 -0
  300. package/dist/sync.js +535 -0
  301. package/dist/tables.d.ts +419 -0
  302. package/dist/tables.d.ts.map +1 -0
  303. package/dist/tables.js +758 -0
  304. package/dist/tallies.d.ts +18 -0
  305. package/dist/tallies.d.ts.map +1 -0
  306. package/dist/tallies.js +128 -0
  307. package/dist/transfer.d.ts +0 -5
  308. package/dist/transfer.d.ts.map +1 -1
  309. package/dist/turn.d.ts +4 -2
  310. package/dist/turn.d.ts.map +1 -1
  311. package/dist/turn.js +46 -22
  312. package/dist/validation.d.ts +29 -0
  313. package/dist/validation.d.ts.map +1 -0
  314. package/dist/validation.js +98 -0
  315. package/dist/windows.d.ts +1 -16
  316. package/dist/windows.d.ts.map +1 -1
  317. package/dist/windows.js +2 -79
  318. package/dist/wire.d.ts +74 -9
  319. package/dist/wire.d.ts.map +1 -1
  320. package/dist/wire.js +26 -6
  321. package/package.json +19 -19
  322. package/AGENTS.md +0 -305
  323. package/dist/attempt.d.ts +0 -16
  324. package/dist/attempt.d.ts.map +0 -1
  325. package/dist/attempt.js +0 -70
  326. package/dist/chat/acts.d.ts +0 -33
  327. package/dist/chat/acts.d.ts.map +0 -1
  328. package/dist/chat/acts.js +0 -36
  329. package/dist/chat/context.d.ts +0 -3
  330. package/dist/chat/context.d.ts.map +0 -1
  331. package/dist/chat/earlier.d.ts +0 -10
  332. package/dist/chat/earlier.d.ts.map +0 -1
  333. package/dist/chat/earlier.js +0 -54
  334. package/dist/chat/input.d.ts +0 -9
  335. package/dist/chat/input.d.ts.map +0 -1
  336. package/dist/chat/input.js +0 -99
  337. package/dist/chat/kit.d.ts +0 -61
  338. package/dist/chat/kit.d.ts.map +0 -1
  339. package/dist/chat/kit.js +0 -123
  340. package/dist/chat/lasting.d.ts +0 -6
  341. package/dist/chat/lasting.d.ts.map +0 -1
  342. package/dist/chat/lasting.js +0 -19
  343. package/dist/chat/list.d.ts +0 -27
  344. package/dist/chat/list.d.ts.map +0 -1
  345. package/dist/chat/list.js +0 -99
  346. package/dist/chat/markdown.d.ts +0 -20
  347. package/dist/chat/markdown.d.ts.map +0 -1
  348. package/dist/chat/markdown.js +0 -188
  349. package/dist/chat/message.d.ts +0 -6
  350. package/dist/chat/message.d.ts.map +0 -1
  351. package/dist/chat/message.js +0 -192
  352. package/dist/chat/messages.d.ts +0 -22
  353. package/dist/chat/messages.d.ts.map +0 -1
  354. package/dist/chat/messages.js +0 -155
  355. package/dist/chat/name.d.ts +0 -6
  356. package/dist/chat/name.d.ts.map +0 -1
  357. package/dist/chat/name.js +0 -37
  358. package/dist/chat/opened.d.ts +0 -11
  359. package/dist/chat/opened.d.ts.map +0 -1
  360. package/dist/chat/opened.js +0 -17
  361. package/dist/chat/overlay.d.ts +0 -31
  362. package/dist/chat/overlay.d.ts.map +0 -1
  363. package/dist/chat/overlay.js +0 -97
  364. package/dist/chat/parts.d.ts +0 -57
  365. package/dist/chat/parts.d.ts.map +0 -1
  366. package/dist/chat/parts.js +0 -119
  367. package/dist/chat/process.d.ts +0 -20
  368. package/dist/chat/process.d.ts.map +0 -1
  369. package/dist/chat/process.js +0 -32
  370. package/dist/chat/provider.d.ts +0 -63
  371. package/dist/chat/provider.d.ts.map +0 -1
  372. package/dist/chat/provider.js +0 -628
  373. package/dist/chat/question.d.ts +0 -9
  374. package/dist/chat/question.d.ts.map +0 -1
  375. package/dist/chat/question.js +0 -69
  376. package/dist/chat/questions.d.ts.map +0 -1
  377. package/dist/chat/read.d.ts.map +0 -1
  378. package/dist/chat/ready.d.ts +0 -34
  379. package/dist/chat/ready.d.ts.map +0 -1
  380. package/dist/chat/ready.js +0 -91
  381. package/dist/chat/style.d.ts +0 -4
  382. package/dist/chat/style.d.ts.map +0 -1
  383. package/dist/chat/style.js +0 -302
  384. package/dist/chat.d.ts +0 -14
  385. package/dist/chat.d.ts.map +0 -1
  386. package/dist/chat.js +0 -8
  387. package/dist/fence.d.ts +0 -6
  388. package/dist/fence.d.ts.map +0 -1
  389. package/dist/fence.js +0 -10
  390. package/dist/log.d.ts +0 -5
  391. package/dist/log.d.ts.map +0 -1
  392. package/dist/log.js +0 -14
  393. package/dist/read-side.d.ts +0 -27
  394. package/dist/read-side.d.ts.map +0 -1
  395. package/dist/read-side.js +0 -824
package/dist/reach.js CHANGED
@@ -1,13 +1,13 @@
1
+ import { QueryError } from '@agentshouse/mdmodel';
2
+ import { selected } from './collection.js';
1
3
  import { unheldView } from './conversation.js';
2
4
  import { modelTypes, NO_MODEL } from './model.js';
3
- import { applied, observing } from './observation.js';
4
- import { runtimeError } from './failure.js';
5
- import { failure, undeclared, } from './outcome.js';
5
+ import { changeOf, digestApplied, digestOf, observing, unchanged, } from './observation.js';
6
+ import { runtimeError, uncaught } from './failure.js';
7
+ import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
6
8
  import { beneath } from './paths.js';
7
- import { reconciled } from './read-side.js';
8
9
  import { moveTarget, readParts, staleWrite, } from './room-draft.js';
9
10
  import { documentKey } from './rows.js';
10
- import { undeclaredSearch } from './search.js';
11
11
  const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
12
12
  function unconversed(name) {
13
13
  return () => Promise.resolve(undeclared(name));
@@ -15,19 +15,35 @@ function unconversed(name) {
15
15
  const NO_CONVERSATION = {
16
16
  list: () => Promise.resolve([]),
17
17
  read: (conversation) => Promise.resolve(unheldView(conversation)),
18
- create: unconversed('conversation.create'),
19
- send: unconversed('conversation.send'),
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'),
18
+ create: unconversed('conversations/create'),
19
+ send: unconversed('conversations/send'),
20
+ answer: unconversed('conversations/interaction/answer'),
21
+ interrupt: unconversed('conversations/interrupt'),
22
+ kill: unconversed('conversations/kill'),
23
+ delete: unconversed('conversations/delete'),
24
+ takeOut: unconversed('conversations/take-out'),
25
+ decide: unconversed('agent-functions/decide'),
26
+ rename: unconversed('conversations/rename'),
27
+ option: unconversed('conversations/option/set'),
28
+ retry: unconversed('conversations/retry'),
29
+ pin: () => Promise.resolve(),
30
+ openTurn: () => Promise.resolve(),
31
+ dismissSuggestion: () => Promise.resolve(),
25
32
  };
26
33
  const NO_CHAT_DRAFT = {
27
34
  write: () => Promise.resolve(),
28
35
  prepend: () => Promise.resolve(),
36
+ append: () => Promise.resolve(),
29
37
  discard: () => Promise.resolve(),
30
38
  };
39
+ function areasOf(reach) {
40
+ return reach.areas ?? [];
41
+ }
42
+ function fenced(reach, room, path) {
43
+ return areasOf(reach).some((area) => area.room === room &&
44
+ beneath(area.path, path) &&
45
+ !area.open.some((open) => beneath(open, path)));
46
+ }
31
47
  export function holds(reach, room) {
32
48
  return (reach === null ||
33
49
  reach.rooms.includes(room) ||
@@ -40,33 +56,33 @@ export function governs(reach, room) {
40
56
  if (wholly(reach, room.locator)) {
41
57
  return { collection: true, selection: room.typedSelection !== null };
42
58
  }
43
- const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
59
+ const within = (path) => selected({ selection: room.typedSelection }, path);
44
60
  const paths = reach.documents
45
61
  .filter((document) => document.room === room.locator)
46
62
  .map(({ path }) => path);
47
- return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
63
+ return { collection: paths.some((path) => !within(path)), selection: paths.some(within) };
48
64
  }
49
65
  function covers(reach, room, path) {
50
66
  return (reach === null ||
51
- reach.rooms.includes(room) ||
52
- reach.documents.some((document) => document.room === room && document.path === path));
67
+ (!fenced(reach, room, path) &&
68
+ (reach.rooms.includes(room) ||
69
+ reach.documents.some((document) => document.room === room && document.path === path))));
53
70
  }
54
71
  function conversing(reach) {
55
72
  return reach === null || reach.conversations;
56
73
  }
57
- function refers(reach, scope) {
58
- if (reach === null)
59
- return true;
60
- if (scope === null)
61
- return false;
62
- if (scope.kind === 'conversations')
63
- return reach.conversations;
64
- return scope.path === undefined
65
- ? wholly(reach, scope.locator)
66
- : covers(reach, scope.locator, scope.path);
74
+ function roomsAwaited(error, reach) {
75
+ return error.code === 'unknown-type' && reach !== null && reach.rooms.length === 0;
67
76
  }
68
- function unreachedReference(fileRef) {
69
- return { kind: 'absent', code: 'binary-file-absent', fields: { fileRef }, retryable: false };
77
+ async function planInReach(runtime, input, reach, answered) {
78
+ try {
79
+ return await runtime.plan(input, reach);
80
+ }
81
+ catch (error) {
82
+ if (error instanceof QueryError && (answered || roomsAwaited(error, reach)))
83
+ return null;
84
+ throw error;
85
+ }
70
86
  }
71
87
  export function planReach(reach) {
72
88
  return reach === null
@@ -76,11 +92,22 @@ export function planReach(reach) {
76
92
  documents: [
77
93
  ...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
78
94
  ].sort(),
95
+ areas: areasOf(reach)
96
+ .map(({ room, path, open }) => ({ room, path, open: [...new Set(open)].sort() }))
97
+ .sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
79
98
  };
80
99
  }
81
100
  function roomsWithin(reach, rooms) {
82
101
  return rooms.filter((room) => wholly(reach, room.locator));
83
102
  }
103
+ function roomsChangeWithin(reach, { changed, removed, order }) {
104
+ const within = {
105
+ changed: changed.filter(([locator]) => wholly(reach, locator)),
106
+ removed,
107
+ order: order === null ? null : order.filter((locator) => wholly(reach, locator)),
108
+ };
109
+ return unchanged(within) ? null : within;
110
+ }
84
111
  function typesWithin(reach, room, types) {
85
112
  if (room === undefined)
86
113
  return structuredClone(UNHELD_TYPES);
@@ -91,7 +118,7 @@ function typesWithin(reach, room, types) {
91
118
  };
92
119
  }
93
120
  function moves(reach, room, move) {
94
- return move === undefined || covers(reach, room, moveTarget(move));
121
+ return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
95
122
  }
96
123
  function draftWithin(reach, draft) {
97
124
  return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
@@ -110,12 +137,13 @@ function writeWithin(reach, write) {
110
137
  function savedWithin(reach, room, result) {
111
138
  if (reach === null || result.outcome === 'saved')
112
139
  return result;
113
- const { file, location, referrers, ...refusal } = result;
140
+ const { file, location, line, referrers, ...refusal } = result;
114
141
  const hidden = file !== undefined && !covers(reach, room, file);
115
142
  return {
116
143
  ...refusal,
117
144
  ...(file === undefined || hidden ? {} : { file }),
118
145
  ...(location === undefined || hidden ? {} : { location }),
146
+ ...(line === undefined || hidden ? {} : { line }),
119
147
  ...(referrers === undefined
120
148
  ? {}
121
149
  : { referrers: referrers.filter((path) => covers(reach, room, path)) }),
@@ -124,85 +152,201 @@ function savedWithin(reach, room, result) {
124
152
  function statusWithin(reach, status) {
125
153
  return {
126
154
  ...status,
127
- attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
155
+ attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
156
+ unsent: status.unsent.filter((change) => covers(reach, change.room, change.path)),
128
157
  };
129
158
  }
130
159
  function queueWithin(reach, room, entries) {
131
- return entries.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
132
- (change.kind !== 'move' || covers(reach, room, change.to))));
160
+ return entries
161
+ .filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
162
+ (change.kind !== 'move' || covers(reach, room, change.to))))
163
+ .map((entry) => {
164
+ const { between, ...batch } = entry.batch;
165
+ if (between === undefined)
166
+ return entry;
167
+ return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
168
+ ? entry
169
+ : { ...entry, batch };
170
+ });
133
171
  }
134
172
  function unreached(room) {
135
- return runtimeError('room-not-held', `No Local Replica for ${room}`);
173
+ return runtimeError('unknown-room', `Unknown Room ${room}`);
174
+ }
175
+ function lockedError(room) {
176
+ return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
177
+ }
178
+ function deviceUnreached() {
179
+ return runtimeError('device-unreached', 'Only the panel reaches this device');
136
180
  }
137
- export function narrowed(runtime, given, told) {
181
+ const ATTACH_REQUIRED = 'attach-required';
182
+ function attachRequired() {
183
+ return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
184
+ }
185
+ function carriesFile(parts) {
186
+ return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
187
+ }
188
+ export function narrowed(runtime, given, port) {
138
189
  const { md, watch } = runtime;
139
190
  let reach = given;
140
- let port = told;
141
191
  const open = new Set();
142
- function following(begin) {
192
+ function following(begin, locking = false) {
143
193
  let stop = begin();
144
194
  const restart = () => {
145
195
  stop();
146
196
  stop = begin();
147
197
  };
148
198
  open.add(restart);
199
+ const unwatch = locking ? runtime.watchLocks(restart) : () => { };
149
200
  return () => {
150
201
  open.delete(restart);
202
+ unwatch();
151
203
  stop();
152
204
  };
153
205
  }
154
- const within = (topic, input, deliver) => {
206
+ const unlocking = (rooms, locked) => {
207
+ const held = (rooms ?? []).filter((room) => locked.includes(room));
208
+ return held.length === 0 ? null : { pending: held.map((room) => ({ room, awaits: 'unlock' })) };
209
+ };
210
+ const unlocked = (entries, locked) => entries.filter((entry) => !locked.includes(entry.room));
211
+ const intoLocked = async (held) => {
212
+ for (const move of held) {
213
+ if (move?.room !== undefined && (await runtime.locked(move.room)))
214
+ return true;
215
+ }
216
+ return false;
217
+ };
218
+ function ordered(deliver) {
219
+ let open = true;
220
+ let shown = Promise.resolve();
221
+ return {
222
+ push(making) {
223
+ shown = shown.then(() => making.then((value) => {
224
+ if (open)
225
+ deliver(value);
226
+ }, uncaught), uncaught);
227
+ },
228
+ stop() {
229
+ open = false;
230
+ },
231
+ };
232
+ }
233
+ function unlockedWatch(topic, input, deliver, fail, within) {
234
+ const shown = ordered(deliver);
235
+ const stop = watch(topic, input, (message) => {
236
+ shown.push(runtime.lockedRooms().then((locked) => within(message, locked)));
237
+ }, fail);
238
+ return () => {
239
+ shown.stop();
240
+ stop();
241
+ };
242
+ }
243
+ function lockedFirst(room, start, shut) {
244
+ let open = true;
245
+ let stop = () => { };
246
+ void (async () => {
247
+ const closed = !holds(reach, room) || (await runtime.locked(room));
248
+ if (!open)
249
+ return;
250
+ if (closed)
251
+ shut();
252
+ else
253
+ stop = start();
254
+ })();
255
+ return () => {
256
+ open = false;
257
+ stop();
258
+ };
259
+ }
260
+ const within = (topic, input, deliver, fail) => {
261
+ if (topic === 'read' && reach !== null) {
262
+ fail(deviceUnreached());
263
+ return () => { };
264
+ }
155
265
  if (topic === 'rooms') {
156
- return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
266
+ return following(() => watch(topic, input, (rooms) => {
267
+ const shown = Array.isArray(rooms)
268
+ ? roomsWithin(reach, rooms)
269
+ : roomsChangeWithin(reach, rooms);
270
+ if (shown !== null)
271
+ deliver(shown);
272
+ }, fail));
157
273
  }
158
274
  if (topic === 'readiness') {
159
275
  return following(() => runtime.watchReadiness(port, reach, deliver));
160
276
  }
161
277
  if (topic === 'sync-status') {
162
- return following(() => watch(topic, input, (status) => deliver(statusWithin(reach, status))));
278
+ return following(() => unlockedWatch(topic, input, deliver, fail, (status, locked) => {
279
+ const shown = statusWithin(reach, status);
280
+ return { ...shown, attentionRequired: unlocked(shown.attentionRequired, locked) };
281
+ }), true);
163
282
  }
164
283
  if (topic === 'room-drafts') {
165
- return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
284
+ return following(() => unlockedWatch(topic, input, deliver, fail, (drafts, locked) => unlocked(draftsWithin(reach, drafts), locked)), true);
166
285
  }
167
286
  if (topic === 'queue') {
168
287
  const room = input[0];
169
- return following(() => {
170
- if (!holds(reach, room)) {
171
- deliver([]);
172
- return () => { };
173
- }
174
- return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
175
- });
288
+ return following(() => lockedFirst(room, () => watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)), fail), () => deliver([])), true);
176
289
  }
177
290
  if (topic === 'query') {
178
- const plan = runtime.plan(input[0], reach);
179
291
  let held = null;
292
+ let planning = null;
293
+ const waiting = (result) => {
294
+ const answer = { result, keys: [] };
295
+ if (held === null || changeOf(held, answer) !== null)
296
+ deliver(answer);
297
+ held = digestOf(answer);
298
+ };
180
299
  return following(() => {
181
- let first = true;
182
- return runtime.watchPlan({ ...plan, reach: planReach(reach) }, (message) => {
183
- if (!first) {
184
- held = applied(held, message);
185
- deliver(message);
186
- return;
187
- }
188
- first = false;
189
- if (held === null) {
190
- held = message;
191
- deliver(message);
192
- return;
193
- }
194
- const next = reconciled(held, message);
195
- if (next === null)
300
+ let open = true;
301
+ let stop = () => { };
302
+ if (planning?.reach !== reach) {
303
+ planning = { reach, plan: planInReach(runtime, input[0], reach, held !== null) };
304
+ }
305
+ const planned = planning.plan;
306
+ void (async () => {
307
+ const plan = await planned;
308
+ const locked = await runtime.lockedRooms();
309
+ if (!open)
196
310
  return;
197
- held = next.keyed;
198
- deliver(next.message);
311
+ if (plan === null)
312
+ return waiting({ pending: [] });
313
+ const pending = unlocking(plan.rooms, locked);
314
+ if (pending !== null)
315
+ return waiting(pending);
316
+ let first = true;
317
+ const heard = (message) => {
318
+ if (!first) {
319
+ held = digestApplied(held, message);
320
+ deliver(message);
321
+ return;
322
+ }
323
+ first = false;
324
+ const change = held === null ? message : changeOf(held, message);
325
+ held = digestOf(message);
326
+ if (change !== null)
327
+ deliver(change);
328
+ };
329
+ stop = runtime.watchPlan({ ...plan, locked }, (message) => {
330
+ if (open)
331
+ heard(message);
332
+ }, (error) => {
333
+ if (open)
334
+ fail(error);
335
+ });
336
+ })().catch((error) => {
337
+ if (open)
338
+ fail(error);
199
339
  });
200
- });
340
+ return () => {
341
+ open = false;
342
+ stop();
343
+ };
344
+ }, true);
201
345
  }
202
346
  if (topic === 'conversation') {
203
347
  return following(() => {
204
348
  if (conversing(reach))
205
- return watch(topic, input, deliver);
349
+ return watch(topic, input, deliver, fail);
206
350
  deliver(unheldView(input[0]));
207
351
  return () => { };
208
352
  });
@@ -210,77 +354,160 @@ export function narrowed(runtime, given, told) {
210
354
  if (topic === 'conversations' || topic === 'agents') {
211
355
  return following(() => {
212
356
  if (conversing(reach))
213
- return watch(topic, input, deliver);
357
+ return watch(topic, input, deliver, fail);
214
358
  deliver([]);
215
359
  return () => { };
216
360
  });
217
361
  }
218
- return watch(topic, input, deliver);
362
+ if (topic === 'figures' || topic === 'holdings' || topic === 'listed-agents') {
363
+ if (reach === null)
364
+ return watch(topic, input, deliver, fail);
365
+ fail(deviceUnreached());
366
+ return () => { };
367
+ }
368
+ return watch(topic, input, deliver, fail);
219
369
  };
370
+ const files = new Map();
371
+ let handed = 0;
372
+ async function hand(reading) {
373
+ const answer = await reading;
374
+ if (answer.kind !== 'binary')
375
+ return answer;
376
+ handed += 1;
377
+ const file = String(handed);
378
+ files.set(file, answer.file);
379
+ return { ...answer, file };
380
+ }
220
381
  const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
221
382
  const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
222
383
  const view = {
223
384
  ...md,
224
- rooms: () => roomsWithin(reach, md.rooms()),
225
- query: ((input) => runtime.query(runtime.plan(input, reach))),
226
- search: (input) => port.search === 'required'
227
- ? runtime.search(input, reach)
228
- : Promise.resolve(undeclaredSearch()),
229
- types(room) {
385
+ rooms: () => md.rooms().then((rooms) => roomsWithin(reach, rooms)),
386
+ query: (async (input) => {
387
+ const plan = await planInReach(runtime, input, reach, false);
388
+ if (plan === null)
389
+ return { pending: [] };
390
+ const locked = await runtime.lockedRooms();
391
+ return unlocking(plan.rooms, locked) ?? runtime.query({ ...plan, locked });
392
+ }),
393
+ search: (input) => runtime.search(input, reach),
394
+ async types(room) {
395
+ if (holds(reach, room) && (await runtime.locked(room)))
396
+ throw lockedError(room);
230
397
  if (wholly(reach, room))
231
398
  return md.types(room);
232
399
  if (!holds(reach, room))
233
400
  return structuredClone(UNHELD_TYPES);
234
- const listed = md.rooms().find(({ locator }) => locator === room);
235
- return typesWithin(reach, listed, md.types(room));
401
+ return typesWithin(reach, await runtime.room(room), await md.types(room));
236
402
  },
237
403
  async save(room, roomDrafts, writtenBy) {
238
404
  if (!holds(reach, room))
239
405
  throw unreached(room);
240
- const outside = roomDrafts.find(({ path }) => !covers(reach, room, path) ||
241
- !moves(reach, room, md.roomDraft.read(room, path)?.parts.move));
406
+ if (await runtime.locked(room)) {
407
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
408
+ }
409
+ const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
410
+ const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
242
411
  if (outside !== undefined) {
243
412
  return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
244
413
  }
414
+ if (await intoLocked(held))
415
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
245
416
  return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
246
417
  },
247
418
  async saveParts(room, parts, writtenBy) {
248
419
  if (!holds(reach, room))
249
420
  throw unreached(room);
250
- if (parts.some(({ path, parts: one }) => !covers(reach, room, path) || !moves(reach, room, readParts(one).move))) {
421
+ const filed = reach === null ? undefined : parts.find(({ parts: one }) => carriesFile(one));
422
+ if (filed !== undefined) {
423
+ return { outcome: 'refused', code: ATTACH_REQUIRED, retryable: false, file: filed.path };
424
+ }
425
+ if (await runtime.locked(room)) {
426
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
427
+ }
428
+ const held = parts.map(({ path, parts: one }) => readParts(one, path).move);
429
+ if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
251
430
  throw unreached(room);
252
431
  }
432
+ if (await intoLocked(held))
433
+ return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
253
434
  return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
254
435
  },
255
- history: (room, path, query) => covers(reach, room, path)
256
- ? md.history(room, path, query)
257
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
436
+ async resolve(room, path, destination) {
437
+ const at = await runtime.located(room, path, destination);
438
+ return at !== null && !covers(reach, at.room, at.path)
439
+ ? UNREADABLE
440
+ : md.resolve(room, path, destination);
441
+ },
442
+ history: async (room, path, query) => !covers(reach, room, path)
443
+ ? failure({ kind: 'room-not-readable', locator: room })
444
+ : (await runtime.locked(room))
445
+ ? lockedRoom(room)
446
+ : md.history(room, path, query),
258
447
  binaryFile: {
259
- read: (room, path, revision) => covers(reach, room, path)
260
- ? md.binaryFile.read(room, path, revision)
261
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
262
- link: (room, path, revision) => covers(reach, room, path)
263
- ? md.binaryFile.link(room, path, revision)
264
- : Promise.resolve(failure({ kind: 'room-not-readable', locator: room })),
265
- readReference: (reference) => refers(reach, runtime.referrerScope(reference.referrer))
266
- ? md.binaryFile.readReference(reference)
267
- : Promise.resolve(unreachedReference(reference.fileRef)),
448
+ read: async (room, path, revision) => !covers(reach, room, path)
449
+ ? failure({ kind: 'room-not-readable', locator: room })
450
+ : (await runtime.locked(room))
451
+ ? lockedRoom(room)
452
+ : hand(md.binaryFile.read(room, path, revision)),
453
+ link: async (room, path, revision) => !covers(reach, room, path)
454
+ ? failure({ kind: 'room-not-readable', locator: room })
455
+ : (await runtime.locked(room))
456
+ ? lockedRoom(room)
457
+ : md.binaryFile.link(room, path, revision),
458
+ show: async (room, path, revision) => !covers(reach, room, path)
459
+ ? failure({ kind: 'room-not-readable', locator: room })
460
+ : (await runtime.locked(room))
461
+ ? lockedRoom(room)
462
+ : hand(md.binaryFile.show(room, path, revision)),
463
+ attach: async (room, file) => !wholly(reach, room)
464
+ ? failure({ kind: 'room-not-readable', locator: room })
465
+ : (await runtime.locked(room))
466
+ ? lockedRoom(room)
467
+ : md.binaryFile.attach(room, file),
468
+ async part(file, part) {
469
+ const key = files.get(file);
470
+ if (key === undefined)
471
+ return null;
472
+ const bytes = await md.binaryFile.part(key, part);
473
+ if (bytes === null)
474
+ files.delete(file);
475
+ return bytes;
476
+ },
268
477
  },
269
- reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
270
- md.reached(room, roomVersion, path),
271
- log: () => (reach === null ? md.log() : ''),
478
+ reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
479
+ !(await runtime.locked(room)) &&
480
+ (await md.reached(room, roomVersion, path)),
481
+ cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
482
+ unsent: () => (reach === null ? md.unsent() : Promise.reject(deviceUnreached())),
483
+ reset: () => (reach === null ? md.reset() : Promise.reject(deviceUnreached())),
484
+ readAgain: () => (reach === null ? md.readAgain() : Promise.reject(deviceUnreached())),
272
485
  roomDraft: {
273
- list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
274
- read: (room, path) => covers(reach, room, path) ? shownDraft(reach, md.roomDraft.read(room, path)) : null,
275
- async write(room, path, revision, parts) {
276
- if (!covers(reach, room, path) || !moves(reach, room, readParts(parts).move)) {
486
+ list: async () => unlocked(draftsWithin(reach, await md.roomDraft.list()), await runtime.lockedRooms()),
487
+ async read(room, path) {
488
+ if (!covers(reach, room, path))
489
+ return null;
490
+ if (await runtime.locked(room))
491
+ throw lockedError(room);
492
+ return shownDraft(reach, await md.roomDraft.read(room, path));
493
+ },
494
+ async write(room, path, revision, parts, next) {
495
+ if (reach !== null && carriesFile(parts))
496
+ throw attachRequired();
497
+ const move = readParts(parts, path).move;
498
+ if (!covers(reach, room, path) || !moves(reach, room, move))
277
499
  throw unreached(room);
278
- }
279
- return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts));
500
+ if (await runtime.locked(room))
501
+ throw lockedError(room);
502
+ if (await intoLocked([move]))
503
+ throw lockedError(move.room);
504
+ return writeWithin(reach, await md.roomDraft.write(room, path, revision, parts, next));
280
505
  },
281
506
  async discard(room, path, revision) {
282
507
  if (!covers(reach, room, path))
283
508
  return staleWrite(null);
509
+ if (await runtime.locked(room))
510
+ throw lockedError(room);
284
511
  return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
285
512
  },
286
513
  },
@@ -289,15 +516,23 @@ export function narrowed(runtime, given, told) {
289
516
  read: (id, options) => conversation().read(id, options),
290
517
  create: (input) => conversation().create(input),
291
518
  send: (id, operation, draft) => conversation().send(id, operation, draft),
292
- answer: (id, answer) => conversation().answer(id, answer),
293
- interrupt: (id) => conversation().interrupt(id),
294
- kill: (id) => conversation().kill(id),
295
- cancel: (id, turn) => conversation().cancel(id, turn),
296
- delete: (id) => conversation().delete(id),
519
+ answer: (id, answer, operation) => conversation().answer(id, answer, operation),
520
+ interrupt: (id, operation) => conversation().interrupt(id, operation),
521
+ kill: (id, operation) => conversation().kill(id, operation),
522
+ delete: (id, operation) => conversation().delete(id, operation),
523
+ takeOut: (id, message, operation) => conversation().takeOut(id, message, operation),
524
+ decide: (request, decision, operation) => conversation().decide(request, decision, operation),
525
+ rename: (id, name, operation) => conversation().rename(id, name, operation),
526
+ option: (id, option, value, operation) => conversation().option(id, option, value, operation),
527
+ retry: (id, message, operation) => conversation().retry(id, message, operation),
528
+ pin: (figures) => conversation().pin(figures),
529
+ openTurn: (id, turn) => conversation().openTurn(id, turn),
530
+ dismissSuggestion: (id, suggestion) => conversation().dismissSuggestion(id, suggestion),
297
531
  },
298
532
  chatDraft: {
299
533
  write: (id, draft, revision) => chatDraft().write(id, draft, revision),
300
534
  prepend: (id, draft) => chatDraft().prepend(id, draft),
535
+ append: (id, draft) => chatDraft().append(id, draft),
301
536
  discard: (id) => chatDraft().discard(id),
302
537
  },
303
538
  observe: observing(within),
@@ -310,10 +545,5 @@ export function narrowed(runtime, given, told) {
310
545
  for (const restart of [...open])
311
546
  restart();
312
547
  },
313
- facts(next) {
314
- port = next;
315
- for (const restart of [...open])
316
- restart();
317
- },
318
548
  };
319
549
  }