@agentshouse/mdruntime 0.1.0-c069136dcb4e8 → 0.1.0-c076b00ebf42a

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 (316) hide show
  1. package/README.md +21 -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 +108 -85
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +3 -11
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +20 -60
  16. package/dist/bootstrap.d.ts +9 -5
  17. package/dist/bootstrap.d.ts.map +1 -1
  18. package/dist/bootstrap.js +204 -85
  19. package/dist/cell.d.ts +6 -0
  20. package/dist/cell.d.ts.map +1 -0
  21. package/dist/cell.js +9 -0
  22. package/dist/chain.d.ts +2 -1
  23. package/dist/chain.d.ts.map +1 -1
  24. package/dist/change-set.d.ts +4 -0
  25. package/dist/change-set.d.ts.map +1 -1
  26. package/dist/change-set.js +6 -0
  27. package/dist/change.d.ts +1 -0
  28. package/dist/change.d.ts.map +1 -1
  29. package/dist/change.js +4 -2
  30. package/dist/chat-types.d.ts +3 -0
  31. package/dist/chat-types.d.ts.map +1 -0
  32. package/dist/chat-types.js +11 -0
  33. package/dist/client.d.ts +29 -22
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +36 -20
  36. package/dist/collection.d.ts +26 -4
  37. package/dist/collection.d.ts.map +1 -1
  38. package/dist/collection.js +19 -2
  39. package/dist/compile.d.ts +8 -6
  40. package/dist/compile.d.ts.map +1 -1
  41. package/dist/compile.js +286 -336
  42. package/dist/connection.d.ts +5 -142
  43. package/dist/connection.d.ts.map +1 -1
  44. package/dist/connection.js +110 -4970
  45. package/dist/context.d.ts +2 -0
  46. package/dist/context.d.ts.map +1 -0
  47. package/dist/context.js +7 -0
  48. package/dist/conversation-live.d.ts +150 -0
  49. package/dist/conversation-live.d.ts.map +1 -0
  50. package/dist/conversation-live.js +259 -0
  51. package/dist/conversation-row.d.ts +35 -0
  52. package/dist/conversation-row.d.ts.map +1 -0
  53. package/dist/conversation-row.js +55 -0
  54. package/dist/conversation.d.ts +65 -44
  55. package/dist/conversation.d.ts.map +1 -1
  56. package/dist/conversation.js +999 -881
  57. package/dist/declaration.d.ts +10 -0
  58. package/dist/declaration.d.ts.map +1 -0
  59. package/dist/declaration.js +24 -0
  60. package/dist/discovery.d.ts +10 -0
  61. package/dist/discovery.d.ts.map +1 -0
  62. package/dist/discovery.js +150 -0
  63. package/dist/durability.d.ts +19 -0
  64. package/dist/durability.d.ts.map +1 -1
  65. package/dist/durability.js +4 -0
  66. package/dist/entry.d.ts +2 -2
  67. package/dist/entry.d.ts.map +1 -1
  68. package/dist/entry.js +18 -8
  69. package/dist/expectation.d.ts +26 -13
  70. package/dist/expectation.d.ts.map +1 -1
  71. package/dist/expectation.js +72 -19
  72. package/dist/failure.d.ts +3 -0
  73. package/dist/failure.d.ts.map +1 -1
  74. package/dist/failure.js +6 -0
  75. package/dist/figures.d.ts +49 -0
  76. package/dist/figures.d.ts.map +1 -0
  77. package/dist/figures.js +199 -0
  78. package/dist/file.d.ts.map +1 -1
  79. package/dist/file.js +2 -1
  80. package/dist/holdings.d.ts +29 -0
  81. package/dist/holdings.d.ts.map +1 -0
  82. package/dist/holdings.js +95 -0
  83. package/dist/host.d.ts +21 -7
  84. package/dist/host.d.ts.map +1 -1
  85. package/dist/host.js +77 -41
  86. package/dist/identity.d.ts +0 -1
  87. package/dist/identity.d.ts.map +1 -1
  88. package/dist/identity.js +0 -3
  89. package/dist/index.d.ts +34 -12
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +16 -5
  92. package/dist/install.d.ts +60 -0
  93. package/dist/install.d.ts.map +1 -0
  94. package/dist/install.js +537 -0
  95. package/dist/lifecycle.d.ts +7 -0
  96. package/dist/lifecycle.d.ts.map +1 -0
  97. package/dist/lifecycle.js +278 -0
  98. package/dist/listing.d.ts +52 -0
  99. package/dist/listing.d.ts.map +1 -0
  100. package/dist/listing.js +152 -0
  101. package/dist/live.d.ts +9 -6
  102. package/dist/live.d.ts.map +1 -1
  103. package/dist/live.js +118 -36
  104. package/dist/locks.d.ts +7 -0
  105. package/dist/locks.d.ts.map +1 -0
  106. package/dist/locks.js +32 -0
  107. package/dist/lost.d.ts +5 -0
  108. package/dist/lost.d.ts.map +1 -0
  109. package/dist/lost.js +49 -0
  110. package/dist/media.d.ts +1 -1
  111. package/dist/media.d.ts.map +1 -1
  112. package/dist/media.js +10 -13
  113. package/dist/memory.d.ts +15 -6
  114. package/dist/memory.d.ts.map +1 -1
  115. package/dist/memory.js +178 -89
  116. package/dist/messages.d.ts +35 -5
  117. package/dist/messages.d.ts.map +1 -1
  118. package/dist/messages.js +108 -36
  119. package/dist/model.d.ts +2 -10
  120. package/dist/model.d.ts.map +1 -1
  121. package/dist/model.js +0 -14
  122. package/dist/models.d.ts +10 -0
  123. package/dist/models.d.ts.map +1 -0
  124. package/dist/models.js +153 -0
  125. package/dist/observation.d.ts +28 -13
  126. package/dist/observation.d.ts.map +1 -1
  127. package/dist/observation.js +185 -81
  128. package/dist/opened.d.ts +1 -1
  129. package/dist/opened.d.ts.map +1 -1
  130. package/dist/opened.js +5 -5
  131. package/dist/opening.d.ts +4 -0
  132. package/dist/opening.d.ts.map +1 -0
  133. package/dist/opening.js +53 -0
  134. package/dist/outcome.d.ts +11 -1
  135. package/dist/outcome.d.ts.map +1 -1
  136. package/dist/outcome.js +26 -2
  137. package/dist/overlay.d.ts +6 -1
  138. package/dist/overlay.d.ts.map +1 -1
  139. package/dist/overlay.js +47 -21
  140. package/dist/page-metadata.d.ts +8 -0
  141. package/dist/page-metadata.d.ts.map +1 -0
  142. package/dist/page-metadata.js +19 -0
  143. package/dist/parts.d.ts +4 -0
  144. package/dist/parts.d.ts.map +1 -0
  145. package/dist/parts.js +13 -0
  146. package/dist/paths.d.ts +1 -0
  147. package/dist/paths.d.ts.map +1 -1
  148. package/dist/paths.js +22 -0
  149. package/dist/preparation.d.ts +41 -0
  150. package/dist/preparation.d.ts.map +1 -0
  151. package/dist/preparation.js +314 -0
  152. package/dist/presence.d.ts +58 -0
  153. package/dist/presence.d.ts.map +1 -0
  154. package/dist/presence.js +233 -0
  155. package/dist/queries.d.ts +16 -0
  156. package/dist/queries.d.ts.map +1 -0
  157. package/dist/queries.js +308 -0
  158. package/dist/query.d.ts +14 -210
  159. package/dist/query.d.ts.map +1 -1
  160. package/dist/query.js +3 -505
  161. package/dist/questions.d.ts +29 -0
  162. package/dist/questions.d.ts.map +1 -0
  163. package/dist/questions.js +115 -0
  164. package/dist/queue.d.ts +40 -0
  165. package/dist/queue.d.ts.map +1 -0
  166. package/dist/queue.js +450 -0
  167. package/dist/reach.d.ts +16 -15
  168. package/dist/reach.d.ts.map +1 -1
  169. package/dist/reach.js +248 -147
  170. package/dist/react.d.ts +17 -3
  171. package/dist/react.d.ts.map +1 -1
  172. package/dist/react.js +33 -1
  173. package/dist/read.d.ts +7 -0
  174. package/dist/read.d.ts.map +1 -0
  175. package/dist/read.js +17 -0
  176. package/dist/readiness.d.ts +9 -6
  177. package/dist/readiness.d.ts.map +1 -1
  178. package/dist/readiness.js +3 -5
  179. package/dist/reads.d.ts +39 -0
  180. package/dist/reads.d.ts.map +1 -0
  181. package/dist/reads.js +178 -0
  182. package/dist/recovery.d.ts +3 -1
  183. package/dist/recovery.d.ts.map +1 -1
  184. package/dist/recovery.js +38 -8
  185. package/dist/refresh.d.ts +2 -1
  186. package/dist/refresh.d.ts.map +1 -1
  187. package/dist/refresh.js +31 -3
  188. package/dist/refusal.d.ts +5 -0
  189. package/dist/refusal.d.ts.map +1 -0
  190. package/dist/refusal.js +55 -0
  191. package/dist/replica.d.ts +11 -16
  192. package/dist/replica.d.ts.map +1 -1
  193. package/dist/replica.js +64 -30
  194. package/dist/retried.d.ts +30 -0
  195. package/dist/retried.d.ts.map +1 -0
  196. package/dist/retried.js +72 -0
  197. package/dist/room-draft.d.ts +7 -8
  198. package/dist/room-draft.d.ts.map +1 -1
  199. package/dist/room-draft.js +113 -111
  200. package/dist/room-drafts.d.ts +24 -0
  201. package/dist/room-drafts.d.ts.map +1 -0
  202. package/dist/room-drafts.js +217 -0
  203. package/dist/rows.d.ts +16 -22
  204. package/dist/rows.d.ts.map +1 -1
  205. package/dist/rows.js +49 -186
  206. package/dist/runtime.d.ts +34 -0
  207. package/dist/runtime.d.ts.map +1 -0
  208. package/dist/runtime.js +1 -0
  209. package/dist/save.d.ts +42 -86
  210. package/dist/save.d.ts.map +1 -1
  211. package/dist/save.js +344 -174
  212. package/dist/saves.d.ts +32 -0
  213. package/dist/saves.d.ts.map +1 -0
  214. package/dist/saves.js +409 -0
  215. package/dist/search.d.ts +12 -63
  216. package/dist/search.d.ts.map +1 -1
  217. package/dist/search.js +9 -52
  218. package/dist/seed.d.ts +11 -2
  219. package/dist/seed.d.ts.map +1 -1
  220. package/dist/seed.js +71 -1
  221. package/dist/shared.d.ts +1 -6
  222. package/dist/shared.d.ts.map +1 -1
  223. package/dist/shared.js +13 -95
  224. package/dist/shown.d.ts +33 -0
  225. package/dist/shown.d.ts.map +1 -0
  226. package/dist/shown.js +309 -0
  227. package/dist/socket/admission.d.ts +7 -0
  228. package/dist/socket/admission.d.ts.map +1 -0
  229. package/dist/socket/admission.js +39 -0
  230. package/dist/socket/answers.d.ts +6 -0
  231. package/dist/socket/answers.d.ts.map +1 -0
  232. package/dist/socket/answers.js +20 -0
  233. package/dist/socket/lanes.d.ts +28 -0
  234. package/dist/socket/lanes.d.ts.map +1 -0
  235. package/dist/socket/lanes.js +103 -0
  236. package/dist/socket/reads.d.ts +10 -0
  237. package/dist/socket/reads.d.ts.map +1 -0
  238. package/dist/socket/reads.js +31 -0
  239. package/dist/socket/session.d.ts +38 -0
  240. package/dist/socket/session.d.ts.map +1 -0
  241. package/dist/socket/session.js +23 -0
  242. package/dist/socket.d.ts +67 -0
  243. package/dist/socket.d.ts.map +1 -0
  244. package/dist/socket.js +164 -0
  245. package/dist/source.d.ts +54 -0
  246. package/dist/source.d.ts.map +1 -0
  247. package/dist/source.js +82 -0
  248. package/dist/status.d.ts +0 -2
  249. package/dist/status.d.ts.map +1 -1
  250. package/dist/status.js +0 -6
  251. package/dist/store/installs.d.ts +30 -0
  252. package/dist/store/installs.d.ts.map +1 -0
  253. package/dist/store/installs.js +40 -0
  254. package/dist/store/readiness.d.ts +11 -0
  255. package/dist/store/readiness.d.ts.map +1 -0
  256. package/dist/store/readiness.js +68 -0
  257. package/dist/store/records.d.ts +217 -0
  258. package/dist/store/records.d.ts.map +1 -0
  259. package/dist/store/records.js +464 -0
  260. package/dist/store/room-held.d.ts +8 -0
  261. package/dist/store/room-held.d.ts.map +1 -0
  262. package/dist/store/room-held.js +17 -0
  263. package/dist/store/rooms-shown.d.ts +8 -0
  264. package/dist/store/rooms-shown.d.ts.map +1 -0
  265. package/dist/store/rooms-shown.js +13 -0
  266. package/dist/store/space.d.ts +11 -0
  267. package/dist/store/space.d.ts.map +1 -0
  268. package/dist/store/space.js +41 -0
  269. package/dist/store/watchers.d.ts +17 -0
  270. package/dist/store/watchers.d.ts.map +1 -0
  271. package/dist/store/watchers.js +56 -0
  272. package/dist/store/writes.d.ts +24 -0
  273. package/dist/store/writes.d.ts.map +1 -0
  274. package/dist/store/writes.js +125 -0
  275. package/dist/store.d.ts +113 -144
  276. package/dist/store.d.ts.map +1 -1
  277. package/dist/store.js +171 -364
  278. package/dist/stored.d.ts +72 -35
  279. package/dist/stored.d.ts.map +1 -1
  280. package/dist/stored.js +340 -197
  281. package/dist/surface.d.ts +89 -0
  282. package/dist/surface.d.ts.map +1 -0
  283. package/dist/surface.js +222 -0
  284. package/dist/sync.d.ts +19 -0
  285. package/dist/sync.d.ts.map +1 -0
  286. package/dist/sync.js +535 -0
  287. package/dist/tables.d.ts +124 -30
  288. package/dist/tables.d.ts.map +1 -1
  289. package/dist/tables.js +242 -62
  290. package/dist/tallies.d.ts +18 -0
  291. package/dist/tallies.d.ts.map +1 -0
  292. package/dist/tallies.js +128 -0
  293. package/dist/validation.d.ts.map +1 -1
  294. package/dist/validation.js +9 -12
  295. package/dist/windows.d.ts +1 -12
  296. package/dist/windows.d.ts.map +1 -1
  297. package/dist/windows.js +2 -75
  298. package/dist/wire.d.ts +58 -9
  299. package/dist/wire.d.ts.map +1 -1
  300. package/dist/wire.js +21 -5
  301. package/package.json +3 -2
  302. package/dist/attempt.d.ts +0 -16
  303. package/dist/attempt.d.ts.map +0 -1
  304. package/dist/attempt.js +0 -70
  305. package/dist/fence.d.ts +0 -6
  306. package/dist/fence.d.ts.map +0 -1
  307. package/dist/fence.js +0 -10
  308. package/dist/fulltext.d.ts +0 -27
  309. package/dist/fulltext.d.ts.map +0 -1
  310. package/dist/fulltext.js +0 -370
  311. package/dist/log.d.ts +0 -5
  312. package/dist/log.d.ts.map +0 -1
  313. package/dist/log.js +0 -14
  314. package/dist/words.d.ts +0 -19
  315. package/dist/words.d.ts.map +0 -1
  316. package/dist/words.js +0 -156
package/dist/tables.js CHANGED
@@ -1,11 +1,17 @@
1
+ import { sql } from '@agentshouse/mdmodel';
1
2
  import { answerQuery } from './compile.js';
2
- import { searched, SEARCH_TABLES } from './fulltext.js';
3
- import { droppedMessages, forgottenMessages, heldConversations, keptMessages, messageCount, messageWindow, MESSAGE_TABLES, turnArrived, } from './messages.js';
4
- import { abandon, release, commit, counts, ended, entries, erase, fenceRooms, files, folders, opened, rederive, referrers, refreshing, REPLICA_TABLES, stage, typed, typedWithin, unrefresh, } from './stored.js';
3
+ import { conversationFacts, conversationRows, forgottenConversations, heldConversations, keptFact, keptMessages, messageCount, messageWindow, MESSAGE_TABLES, turnArrived, } from './messages.js';
4
+ import { keptRead, READ_TABLES, readsOfOtherBuildsForgotten, storedRead, } from './reads.js';
5
+ import { conversationTallies, roomTallies, } from './tallies.js';
6
+ import { abandon, release, commit, covering, demoted, ended, entries, erase, facts, fenceRooms, folders, heldLocators, heldRoom, heldRooms, offlineMode, opened, overlaid, presentation, rederive, referrers, refreshing, REPLICA_TABLES, resume, stage, typed, stagedLocators, tablesOf, typedWithin, unrefresh, } from './stored.js';
5
7
  const STATEMENTS_HELD = 256;
6
8
  export function sqliteConnection(engine, database) {
7
9
  const decoder = new TextDecoder();
8
10
  const held = new Map();
11
+ database.createFunction(sql.HOLDS_PHRASE, sql.holdsPhrase, {
12
+ arity: 2,
13
+ deterministic: true,
14
+ });
9
15
  function prepared(sql) {
10
16
  if (sql.includes(';'))
11
17
  return null;
@@ -72,7 +78,7 @@ const TABLES = [
72
78
  ['authored_queues', 'locator TEXT PRIMARY KEY, ids TEXT NOT NULL'],
73
79
  [
74
80
  'authored_pending',
75
- 'locator TEXT NOT NULL, id TEXT NOT NULL, batch TEXT NOT NULL, state TEXT NOT NULL, files TEXT NOT NULL, PRIMARY KEY (locator, id)',
81
+ 'locator TEXT NOT NULL, id TEXT NOT NULL, batch TEXT NOT NULL, state TEXT NOT NULL, files TEXT NOT NULL, paths TEXT NOT NULL, moving INTEGER NOT NULL, PRIMARY KEY (locator, id)',
76
82
  ],
77
83
  [
78
84
  'authored_room_drafts',
@@ -89,35 +95,54 @@ export const RUNTIME_TABLES = [
89
95
  'CREATE INDEX opened_files_name ON opened_files (locator, path, revision)',
90
96
  ...REPLICA_TABLES,
91
97
  ...MESSAGE_TABLES,
92
- ...SEARCH_TABLES,
98
+ ...READ_TABLES,
93
99
  ];
94
100
  const OWNERS = ['authored_pending', 'authored_room_drafts', 'authored_calls'];
95
101
  const AUTHORED_KEYS = OWNERS.map((table) => `SELECT value FROM ${table}, json_each(${table}.files)`).join(' UNION ');
96
102
  const UNOWNED_PARTS = `DELETE FROM file_parts WHERE key NOT IN (${AUTHORED_KEYS} UNION SELECT key FROM opened_files)`;
103
+ const CLEANABLE_BYTES = `SELECT coalesce(sum(length(bytes)), 0) AS bytes FROM file_parts WHERE key NOT IN (${AUTHORED_KEYS})`;
97
104
  const READS = new Set([
98
- 'authored.queues',
105
+ 'authored.status',
106
+ 'authored.moving',
107
+ 'authored.pending',
108
+ 'authored.batch',
109
+ 'authored.order',
110
+ 'authored.queued',
99
111
  'authored.roomDrafts',
112
+ 'authored.chatDraft.read',
100
113
  'authored.chatDrafts',
101
114
  'authored.calls',
102
115
  'authored.fences',
116
+ 'authored.unsent',
103
117
  'authored.fact',
104
118
  'authored.file',
105
119
  'replica.open',
120
+ 'replica.rooms',
121
+ 'replica.room',
122
+ 'replica.covering',
123
+ 'replica.offline',
124
+ 'replica.held',
125
+ 'replica.facts',
126
+ 'replica.presentation',
106
127
  'replica.query',
128
+ 'replica.tallies',
107
129
  'replica.entries',
108
130
  'replica.typed',
109
131
  'replica.referrers',
110
- 'replica.files',
111
132
  'replica.folders',
112
133
  'replica.typedWithin',
113
- 'replica.counts',
114
- 'replica.search',
115
134
  'opened.find',
135
+ 'opened.held',
116
136
  'file.part',
117
137
  'conversation.held',
118
138
  'conversation.window',
119
139
  'conversation.count',
120
140
  'conversation.turn',
141
+ 'conversation.rows',
142
+ 'conversation.tallies',
143
+ 'conversation.facts',
144
+ 'conversation.stored',
145
+ 'read.stored',
121
146
  ]);
122
147
  const KINDS = new Set([
123
148
  ...READS,
@@ -129,14 +154,17 @@ const KINDS = new Set([
129
154
  'authored.claim',
130
155
  'authored.end',
131
156
  'replica.stage',
157
+ 'replica.resume',
132
158
  'replica.refresh',
133
159
  'replica.unrefresh',
134
160
  'replica.commit',
135
161
  'replica.fence',
136
162
  'replica.erase',
137
163
  'replica.abandon',
164
+ 'replica.unfence',
138
165
  'replica.release',
139
166
  'replica.rederive',
167
+ 'replica.demote',
140
168
  'replica.fact',
141
169
  'replica.present',
142
170
  'opened.begin',
@@ -145,8 +173,11 @@ const KINDS = new Set([
145
173
  'opened.drop',
146
174
  'opened.clean',
147
175
  'conversation.keep',
176
+ 'conversation.fact',
148
177
  'conversation.drop',
149
178
  'space.probe',
179
+ 'read.keep',
180
+ 'read.builds',
150
181
  ]);
151
182
  export function isRuntime(request) {
152
183
  return KINDS.has(request.kind);
@@ -219,21 +250,66 @@ function unowned(connection) {
219
250
  connection.run(UNOWNED_PARTS);
220
251
  }
221
252
  function queued(connection) {
253
+ return connection.rows('SELECT locator, ids FROM authored_queues').map((row) => ({
254
+ locator: text(row.locator),
255
+ ids: JSON.parse(text(row.ids)),
256
+ }));
257
+ }
258
+ function heldWork(connection, locator) {
259
+ const room = heldRoom(connection, locator);
260
+ const pending = new Map(connection
261
+ .rows('SELECT id, batch, state FROM authored_pending WHERE locator = ?', [locator])
262
+ .map((row) => [
263
+ text(row.id),
264
+ { id: text(row.id), batch: text(row.batch), state: text(row.state) },
265
+ ]));
222
266
  return {
223
- queues: connection.rows('SELECT locator, ids FROM authored_queues').map((row) => ({
224
- locator: text(row.locator),
225
- ids: JSON.parse(text(row.ids)),
226
- })),
227
- pending: connection
228
- .rows('SELECT locator, id, batch, state FROM authored_pending')
229
- .map((row) => ({
230
- locator: text(row.locator),
231
- id: text(row.id),
232
- batch: text(row.batch),
233
- state: text(row.state),
234
- })),
267
+ room: room === null ? null : { ...room, overlaid: overlaid(connection, room.key) },
268
+ queue: heldOrder(connection, locator).map((id) => {
269
+ const held = pending.get(id);
270
+ if (held === undefined)
271
+ throw new Error(`Missing Pending Change ${locator}/${id}`);
272
+ return held;
273
+ }),
274
+ };
275
+ }
276
+ function status(connection) {
277
+ const [completed] = connection.rows("SELECT value FROM replica_facts WHERE name = 'lastCompleted'");
278
+ return {
279
+ queued: texts(connection.rows('SELECT locator FROM authored_queues'), 'locator'),
280
+ lastCompleted: completed === undefined ? null : text(completed.value),
281
+ changes: connection
282
+ .rows('SELECT p.locator, c.value AS path FROM authored_pending p, json_each(p.paths) c')
283
+ .map((row) => ({ locator: text(row.locator), path: text(row.path) })),
284
+ resets: connection
285
+ .rows(`SELECT locator, json_extract(state, '$.submission.reset') AS reset FROM authored_pending
286
+ WHERE json_extract(state, '$.submission.state') = 'reset'`)
287
+ .map((row) => ({ locator: text(row.locator), reset: text(row.reset) })),
288
+ returned: texts(connection.rows(`SELECT record FROM authored_room_drafts WHERE json_type(record, '$.returned') = 'object'`), 'record'),
289
+ };
290
+ }
291
+ function pendingOf(connection, locator, id) {
292
+ const [held] = connection.rows('SELECT state FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
293
+ return {
294
+ state: held === undefined ? null : text(held.state),
295
+ room: connection.rows('SELECT 1 FROM replica_rooms WHERE locator = ?', [locator]).length > 0,
235
296
  };
236
297
  }
298
+ function roomDraftRecords(connection, locator, paths) {
299
+ if (locator === null) {
300
+ return texts(connection.rows('SELECT record FROM authored_room_drafts'), 'record');
301
+ }
302
+ if (paths === null) {
303
+ return texts(connection.rows('SELECT record FROM authored_room_drafts WHERE locator = ?', [locator]), 'record');
304
+ }
305
+ return texts(connection.rows('SELECT record FROM authored_room_drafts WHERE locator = ? AND path IN (SELECT value FROM json_each(?))', [locator, JSON.stringify(paths)]), 'record');
306
+ }
307
+ function chatDraftRecord(connection, conversation) {
308
+ const [held] = connection.rows('SELECT record FROM authored_chat_drafts WHERE conversation = ?', [
309
+ conversation,
310
+ ]);
311
+ return held === undefined ? null : text(held.record);
312
+ }
237
313
  function heldOrder(connection, locator) {
238
314
  const [held] = connection.rows('SELECT ids FROM authored_queues WHERE locator = ?', [locator]);
239
315
  return held === undefined ? [] : JSON.parse(text(held.ids));
@@ -265,19 +341,26 @@ function keptRows(connection, { locator, order, added, founded, roomDrafts, cons
265
341
  connection.run('DELETE FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
266
342
  }
267
343
  }
268
- for (const { id, batch, state, files } of added ?? []) {
269
- if (before.has(id) || !after.has(id))
344
+ for (const { id, batch, state, files, paths, moving } of added ?? []) {
345
+ if (before.has(id))
270
346
  continue;
271
- connection.run('INSERT OR REPLACE INTO authored_pending (locator, id, batch, state, files) VALUES (?, ?, ?, ?, ?)', [locator, id, batch, state, owned(files)]);
347
+ connection.run('INSERT OR REPLACE INTO authored_pending (locator, id, batch, state, files, paths, moving) VALUES (?, ?, ?, ?, ?, ?, ?)', [locator, id, batch, state, owned(files), JSON.stringify(paths), moving ? 1 : 0]);
272
348
  }
273
- for (const { id, batch, files } of founded ?? []) {
349
+ for (const { id, batch, files, paths, moving } of founded ?? []) {
274
350
  const [held] = connection.rows('SELECT files FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
275
351
  if (held === undefined || !before.has(id))
276
352
  continue;
277
- connection.run('UPDATE authored_pending SET batch = ?, files = ? WHERE locator = ? AND id = ?', [batch, owned([...JSON.parse(text(held.files)), ...files]), locator, id]);
353
+ connection.run('UPDATE authored_pending SET batch = ?, files = ?, paths = ?, moving = ? WHERE locator = ? AND id = ?', [
354
+ batch,
355
+ owned([...JSON.parse(text(held.files)), ...files]),
356
+ JSON.stringify(paths),
357
+ moving ? 1 : 0,
358
+ locator,
359
+ id,
360
+ ]);
278
361
  }
279
362
  }
280
- async function kept(connection, { writes, files, whole, discards }) {
363
+ async function kept(connection, { writes, files, whole }) {
281
364
  const refused = writes.find(({ locator }) => fenced(connection, locator));
282
365
  if (refused !== undefined && whole)
283
366
  return refused.locator;
@@ -286,8 +369,6 @@ async function kept(connection, { writes, files, whole, discards }) {
286
369
  if (!fenced(connection, write.locator))
287
370
  keptRows(connection, write);
288
371
  }
289
- for (const locator of discards ?? [])
290
- roomWork(connection, locator);
291
372
  unowned(connection);
292
373
  return refused?.locator ?? null;
293
374
  }
@@ -323,6 +404,25 @@ async function roomDraft(connection, { locator, path, kept: draft, files }) {
323
404
  unowned(connection);
324
405
  return null;
325
406
  }
407
+ function conversationTables() {
408
+ return [...tablesOf(MESSAGE_TABLES), 'authored_chat_drafts'];
409
+ }
410
+ function storedConversations(connection, conversations) {
411
+ const named = conversations === null ? '' : ' WHERE conversation IN (SELECT value FROM json_each(?))';
412
+ const bound = conversations === null ? [] : [JSON.stringify(conversations)];
413
+ return [
414
+ ...new Set(conversationTables().flatMap((table) => texts(connection.rows(`SELECT DISTINCT conversation FROM ${table}${named}`, bound), 'conversation'))),
415
+ ];
416
+ }
417
+ function droppedConversations(connection, conversations) {
418
+ const held = storedConversations(connection, conversations);
419
+ for (const table of conversationTables()) {
420
+ connection.run(`DELETE FROM ${table} WHERE conversation IN (SELECT value FROM json_each(?))`, [
421
+ JSON.stringify(conversations),
422
+ ]);
423
+ }
424
+ return held;
425
+ }
326
426
  function chatDraft(connection, { kept: drafts, dropped }) {
327
427
  for (const conversation of dropped) {
328
428
  connection.run('DELETE FROM authored_chat_drafts WHERE conversation = ?', [conversation]);
@@ -357,11 +457,15 @@ function fence(connection, locators) {
357
457
  return fenceRooms(connection, locators);
358
458
  }
359
459
  function erased(connection, { locator, limit }) {
360
- const done = erase(connection, locator, limit);
361
- if (locator !== null && !done.remaining) {
460
+ return erase(connection, locator, limit);
461
+ }
462
+ function unfenced(connection, locators) {
463
+ const erased = locators.filter((locator) => connection.rows('SELECT 1 FROM replica_erasing WHERE locator = ? LIMIT 1', [locator])
464
+ .length === 0);
465
+ for (const locator of erased) {
362
466
  connection.run('DELETE FROM authored_fences WHERE locator = ?', [locator]);
363
467
  }
364
- return done;
468
+ return erased;
365
469
  }
366
470
  function claim(connection, holder) {
367
471
  const held = fact(connection, 'holder');
@@ -372,7 +476,7 @@ function claim(connection, holder) {
372
476
  }
373
477
  function end(connection, holder) {
374
478
  ended(connection);
375
- forgottenMessages(connection);
479
+ forgottenConversations(connection);
376
480
  if (holder !== null && claim(connection, holder))
377
481
  return true;
378
482
  for (const [table] of TABLES)
@@ -424,9 +528,9 @@ function keptOpened(connection, { key, sha256, byteLength, parts }) {
424
528
  if (fetched === null)
425
529
  return false;
426
530
  const [held] = connection.rows('SELECT count(*) AS parts, min(part) AS first, max(part) AS last, coalesce(sum(length(bytes)), 0) AS bytes FROM file_parts WHERE key = ?', [key]);
427
- const whole = count(held?.parts) === parts &&
428
- count(held?.bytes) === byteLength &&
429
- (parts === 0 || (count(held?.first) === 0 && count(held?.last) === parts - 1));
531
+ const whole = count(held.parts) === parts &&
532
+ count(held.bytes) === byteLength &&
533
+ (parts === 0 || (count(held.first) === 0 && count(held.last) === parts - 1));
430
534
  if (!whole) {
431
535
  dropped(connection, key);
432
536
  return false;
@@ -440,16 +544,38 @@ function keptOpened(connection, { key, sha256, byteLength, parts }) {
440
544
  unowned(connection);
441
545
  return true;
442
546
  }
547
+ const UNSENT = [
548
+ ['pending-change', 'authored_pending'],
549
+ ['call', 'authored_calls'],
550
+ ['room-draft', 'authored_room_drafts'],
551
+ ['chat-draft', 'authored_chat_drafts'],
552
+ ];
553
+ function unsent(connection) {
554
+ const [held] = connection.rows(`SELECT ${UNSENT.map(([kind, table]) => `(SELECT count(*) FROM ${table}) AS "${kind}"`).join(', ')}`);
555
+ return UNSENT.map(([kind]) => ({ kind, count: count(held[kind]) })).filter((work) => work.count > 0);
556
+ }
557
+ function cleanable(connection) {
558
+ const [held] = connection.rows(CLEANABLE_BYTES);
559
+ return count(held.bytes);
560
+ }
443
561
  function cleaned(connection) {
444
562
  connection.run('DELETE FROM opened_files');
445
- const [freed] = connection.rows(`SELECT coalesce(sum(length(bytes)), 0) AS bytes FROM file_parts WHERE key NOT IN (${AUTHORED_KEYS})`);
563
+ const freed = cleanable(connection);
446
564
  unowned(connection);
447
- return count(freed?.bytes);
565
+ return freed;
566
+ }
567
+ function openedHeld(connection) {
568
+ return {
569
+ rooms: connection
570
+ .rows('SELECT locator, count(*) AS files, sum(byte_length) AS bytes FROM opened_files WHERE byte_length IS NOT NULL GROUP BY locator ORDER BY locator')
571
+ .map((row) => ({ room: text(row.locator), count: count(row.files), size: count(row.bytes) })),
572
+ cleanable: cleanable(connection),
573
+ };
448
574
  }
449
575
  async function committed(connection, { authored, rooms }) {
450
576
  const refused = authored === undefined ? null : await kept(connection, authored);
451
577
  if (refused !== null && authored?.whole === true) {
452
- return { fenced: refused, counts: {}, changed: {}, indexed: {} };
578
+ return { fenced: refused, changed: {}, indexed: {} };
453
579
  }
454
580
  return {
455
581
  fenced: refused,
@@ -458,16 +584,42 @@ async function committed(connection, { authored, rooms }) {
458
584
  }
459
585
  export function answerRuntime(connection, request, spool) {
460
586
  switch (request.kind) {
461
- case 'authored.queues':
462
- return queued(connection);
587
+ case 'authored.status':
588
+ return status(connection);
589
+ case 'authored.moving':
590
+ return {
591
+ queues: queued(connection),
592
+ pending: connection
593
+ .rows('SELECT locator, id, batch, state FROM authored_pending WHERE moving = 1 ORDER BY locator')
594
+ .map((row) => ({
595
+ locator: text(row.locator),
596
+ id: text(row.id),
597
+ batch: text(row.batch),
598
+ state: text(row.state),
599
+ })),
600
+ };
601
+ case 'authored.pending':
602
+ return pendingOf(connection, request.locator, request.id);
603
+ case 'authored.batch': {
604
+ const [held] = connection.rows('SELECT batch FROM authored_pending WHERE locator = ? AND id = ?', [request.locator, request.id]);
605
+ return held === undefined ? null : text(held.batch);
606
+ }
607
+ case 'authored.order':
608
+ return heldOrder(connection, request.locator);
609
+ case 'authored.queued':
610
+ return texts(connection.rows('SELECT locator FROM authored_queues'), 'locator');
463
611
  case 'authored.roomDrafts':
464
- return texts(connection.rows('SELECT record FROM authored_room_drafts'), 'record');
612
+ return roomDraftRecords(connection, request.locator, request.paths);
613
+ case 'authored.chatDraft.read':
614
+ return chatDraftRecord(connection, request.conversation);
465
615
  case 'authored.chatDrafts':
466
616
  return texts(connection.rows('SELECT record FROM authored_chat_drafts'), 'record');
467
617
  case 'authored.calls':
468
618
  return texts(connection.rows('SELECT record FROM authored_calls'), 'record');
469
619
  case 'authored.fences':
470
620
  return texts(connection.rows('SELECT locator FROM authored_fences'), 'locator');
621
+ case 'authored.unsent':
622
+ return unsent(connection);
471
623
  case 'authored.fact':
472
624
  return fact(connection, request.name);
473
625
  case 'authored.file':
@@ -488,28 +640,40 @@ export function answerRuntime(connection, request, spool) {
488
640
  return end(connection, request.holder);
489
641
  case 'replica.open':
490
642
  return opened(connection);
643
+ case 'replica.rooms':
644
+ return heldRooms(connection, request.locators);
645
+ case 'replica.room':
646
+ return heldWork(connection, request.locator);
647
+ case 'replica.covering':
648
+ return { ...covering(connection, request.since), queues: queued(connection) };
649
+ case 'replica.offline':
650
+ return offlineMode(connection, request.locator);
651
+ case 'replica.held':
652
+ return { held: heldLocators(connection), staged: stagedLocators(connection) };
653
+ case 'replica.demote':
654
+ return demoted(connection);
655
+ case 'replica.facts':
656
+ return facts(connection, request.names);
657
+ case 'replica.presentation':
658
+ return presentation(connection, request.app);
491
659
  case 'replica.query':
492
660
  return answerQuery(connection, request.plan, request.rooms, request.budget);
661
+ case 'replica.tallies':
662
+ return roomTallies(connection, request.totals, request.rooms, request.since);
493
663
  case 'replica.entries':
494
664
  return entries(connection, request.key, request.view, request.paths);
495
665
  case 'replica.typed':
496
666
  return typed(connection, request.key, request.view, request.paths);
497
667
  case 'replica.referrers':
498
- return referrers(connection, request.key, request.view, request.targets, request.kinds);
499
- case 'replica.files':
500
- return files(connection, request.key, request.view, request.after, request.limit);
668
+ return referrers(connection, request.key, request.view, request.targets);
501
669
  case 'replica.folders':
502
- return folders(connection, request.key, request.view, request.paths);
670
+ return folders(connection, request.key, request.paths);
503
671
  case 'replica.typedWithin':
504
672
  return typedWithin(connection, request.key, request.view, request.roots, request.within);
505
- case 'replica.counts':
506
- return counts(connection, request.rooms);
507
- case 'replica.search': {
508
- const { kind: _kind, ...ask } = request;
509
- return searched(connection, ask);
510
- }
511
673
  case 'replica.stage':
512
674
  return fenced(connection, request.locator) ? null : stage(connection, request);
675
+ case 'replica.resume':
676
+ return fenced(connection, request.locator) ? null : resume(connection, request);
513
677
  case 'replica.refresh':
514
678
  return refreshing(connection, request);
515
679
  case 'replica.unrefresh':
@@ -522,6 +686,8 @@ export function answerRuntime(connection, request, spool) {
522
686
  return erased(connection, request);
523
687
  case 'replica.abandon':
524
688
  return abandon(connection, request.locator);
689
+ case 'replica.unfence':
690
+ return unfenced(connection, request.locators);
525
691
  case 'replica.release':
526
692
  return release(connection, request.key);
527
693
  case 'replica.rederive':
@@ -550,29 +716,43 @@ export function answerRuntime(connection, request, spool) {
550
716
  return dropped(connection, request.key);
551
717
  case 'opened.clean':
552
718
  return cleaned(connection);
719
+ case 'opened.held':
720
+ return openedHeld(connection);
553
721
  case 'file.part':
554
722
  return filePart(connection, request.key, request.part);
555
723
  case 'conversation.held':
556
- return heldConversations(connection);
724
+ return heldConversations(connection, request.conversations);
557
725
  case 'conversation.keep': {
558
726
  const { kind: _kind, ...write } = request;
559
727
  return keptMessages(connection, write);
560
728
  }
561
729
  case 'conversation.window':
562
- return messageWindow(connection, request.conversation, request.limit, request.before);
730
+ return messageWindow(connection, request.conversation, request.limit, request.before, request.phrase);
563
731
  case 'conversation.count':
564
- return messageCount(connection, request.conversation);
732
+ return messageCount(connection, request.conversation, request.phrase);
565
733
  case 'conversation.turn':
566
734
  return turnArrived(connection, request.conversation, request.turn);
735
+ case 'conversation.rows':
736
+ return conversationRows(connection, request.conversations);
737
+ case 'conversation.tallies':
738
+ return conversationTallies(connection, request.conversations, request.since);
739
+ case 'conversation.facts':
740
+ return conversationFacts(connection);
741
+ case 'conversation.fact': {
742
+ const { kind: _kind, ...fact } = request;
743
+ return keptFact(connection, fact);
744
+ }
745
+ case 'conversation.stored':
746
+ return storedConversations(connection, null);
567
747
  case 'conversation.drop':
568
- chatDraft(connection, {
569
- kind: 'authored.chatDraft',
570
- kept: [],
571
- dropped: request.conversations,
572
- });
573
- droppedMessages(connection, request.conversations);
574
- return null;
748
+ return droppedConversations(connection, request.conversations);
575
749
  case 'space.probe':
576
750
  return spool.probe(PROBE_BYTES).then(() => null);
751
+ case 'read.stored':
752
+ return storedRead(connection, request);
753
+ case 'read.keep':
754
+ return keptRead(connection, request, request.answer);
755
+ case 'read.builds':
756
+ return readsOfOtherBuildsForgotten(connection, request.build);
577
757
  }
578
758
  }
@@ -0,0 +1,18 @@
1
+ import { type QueryRoom } from './compile.js';
2
+ import type { GroupTotal, Plan } from './query.js';
3
+ import type { Connection } from './tables.js';
4
+ export type RoomTally = {
5
+ readonly key: number;
6
+ readonly documents: GroupTotal;
7
+ readonly files: GroupTotal;
8
+ readonly documentTimes: readonly (readonly [string | null, string | null])[];
9
+ readonly chatTimes: readonly string[];
10
+ readonly messageTimes: readonly string[];
11
+ };
12
+ export type ConversationTally = {
13
+ readonly conversation: string;
14
+ readonly said: readonly string[];
15
+ };
16
+ export declare function roomTallies(connection: Connection, totals: Plan, rooms: readonly QueryRoom[], since: string): RoomTally[];
17
+ export declare function conversationTallies(connection: Connection, conversations: readonly string[] | null, since: string): ConversationTally[];
18
+ //# sourceMappingURL=tallies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tallies.d.ts","sourceRoot":"","sources":["../src/tallies.ts"],"names":[],"mappings":"AACA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAI1D,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;IAC7E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAmHpG,wBAAgB,WAAW,CACzB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,KAAK,EAAE,MAAM,GACZ,SAAS,EAAE,CAwBb;AA0BD,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,EACvC,KAAK,EAAE,MAAM,GACZ,iBAAiB,EAAE,CAerB"}
@@ -0,0 +1,128 @@
1
+ import { CHAT_MESSAGE_TYPE, CHAT_TYPE, instantKey, sql } from '@agentshouse/mdmodel';
2
+ import { answerQuery, VISIBLE, within } from './compile.js';
3
+ import { HOUSE_DIRECTORY } from './figures.js';
4
+ const NONE = { count: 0, size: 0 };
5
+ const { all, fragment, joined } = sql;
6
+ function instant(value) {
7
+ return typeof value === 'string' ? value : null;
8
+ }
9
+ function held(alias, keys) {
10
+ const reserved = within(alias, HOUSE_DIRECTORY);
11
+ return all([
12
+ fragment(`${alias}.key IN (SELECT value FROM json_each(?))`, [JSON.stringify(keys)]),
13
+ fragment(VISIBLE(alias)),
14
+ fragment(`NOT ${reserved.sql}`, reserved.bind),
15
+ ]);
16
+ }
17
+ function valued(alias, document, field) {
18
+ return joined([
19
+ fragment(`${alias}.doc = ${document}.id AND `),
20
+ sql.grouped(sql.placed(alias, field, 'exact')),
21
+ fragment(` AND ${alias}.item = -1`),
22
+ ], '');
23
+ }
24
+ function inboxed(card) {
25
+ return joined([
26
+ fragment('EXISTS (SELECT 1 FROM replica_values i WHERE '),
27
+ valued('i', card, '/inbox'),
28
+ fragment(" AND i.kind = 'string')"),
29
+ ], '');
30
+ }
31
+ function rowsOf(connection, query) {
32
+ return connection.rows(query.sql, query.bind);
33
+ }
34
+ function documentTimes(connection, keys, since) {
35
+ return rowsOf(connection, joined([
36
+ fragment('SELECT d.key AS key, d.created_instant AS created, d.changed_instant AS changed FROM replica_entries d WHERE '),
37
+ held('d', keys),
38
+ fragment(" AND d.binary IS NULL AND COALESCE(d.type, '') NOT IN (?, ?) AND (d.created_instant >= ? OR d.changed_instant >= ?)", [CHAT_TYPE, CHAT_MESSAGE_TYPE, since, since]),
39
+ ], ''));
40
+ }
41
+ function chatTimes(connection, keys, since) {
42
+ return rowsOf(connection, joined([
43
+ fragment('SELECT d.key AS key, d.created_instant AS at FROM replica_entries d WHERE '),
44
+ held('d', keys),
45
+ fragment(' AND d.type = ? AND d.created_instant >= ? AND ', [CHAT_TYPE, since]),
46
+ inboxed('d'),
47
+ ], ''));
48
+ }
49
+ function messageTimes(connection, keys, since) {
50
+ return rowsOf(connection, joined([
51
+ fragment('SELECT m.key AS key, s.instant AS at FROM replica_entries m JOIN replica_values s ON '),
52
+ valued('s', 'm', '/sent_at'),
53
+ fragment(' AND s.instant >= ? JOIN replica_values r ON ', [since]),
54
+ valued('r', 'm', '/direction'),
55
+ fragment(" AND r.kind = 'string' AND r.value = 'in' WHERE "),
56
+ held('m', keys),
57
+ fragment(` AND m.type = ? AND EXISTS (SELECT 1 FROM replica_entries c WHERE c.key = m.key AND c.type = ? AND ${VISIBLE('c')} AND c.folder = m.folder AND `, [CHAT_MESSAGE_TYPE, CHAT_TYPE]),
58
+ inboxed('c'),
59
+ fragment(')'),
60
+ ], ''));
61
+ }
62
+ function byKey(rows, read) {
63
+ const kept = new Map();
64
+ for (const row of rows) {
65
+ const key = Number(row.key);
66
+ const list = kept.get(key) ?? [];
67
+ list.push(read(row));
68
+ kept.set(key, list);
69
+ }
70
+ return kept;
71
+ }
72
+ export function roomTallies(connection, totals, rooms, since) {
73
+ const keys = rooms.map(({ key }) => key);
74
+ const from = instantKey(since);
75
+ const answered = answerQuery(connection, totals, rooms);
76
+ const summed = new Map(('groups' in answered ? answered.groups : []).map((group) => [String(group.key[0]), group]));
77
+ const documents = byKey(documentTimes(connection, keys, from), (row) => [instant(row.created), instant(row.changed)]);
78
+ const chats = byKey(chatTimes(connection, keys, from), (row) => instant(row.at));
79
+ const messages = byKey(messageTimes(connection, keys, from), (row) => instant(row.at));
80
+ return rooms.map(({ locator, key }) => {
81
+ const total = summed.get(locator);
82
+ return {
83
+ key,
84
+ documents: total?.documents ?? NONE,
85
+ files: total?.files ?? NONE,
86
+ documentTimes: documents.get(key) ?? [],
87
+ chatTimes: chats.get(key) ?? [],
88
+ messageTimes: messages.get(key) ?? [],
89
+ };
90
+ });
91
+ }
92
+ const ACCEPTED = "message ->> '$.accepted_at'";
93
+ const NEWER = 'ORDER BY n.position DESC, n.identity DESC LIMIT 1';
94
+ const SAID = `WITH RECURSIVE
95
+ named(conversation) AS (SELECT value FROM json_each(?)),
96
+ walk(conversation, position, identity, at, role) AS (
97
+ SELECT m.conversation, m.position, m.identity, m.${ACCEPTED}, m.message ->> '$.role'
98
+ FROM named JOIN conversation_messages m ON m.id = (
99
+ SELECT n.id FROM conversation_messages n WHERE n.conversation = named.conversation ${NEWER}
100
+ )
101
+ UNION ALL
102
+ SELECT m.conversation, m.position, m.identity, m.${ACCEPTED}, m.message ->> '$.role'
103
+ FROM walk JOIN conversation_messages m ON m.id = (
104
+ SELECT n.id FROM conversation_messages n WHERE n.conversation = walk.conversation
105
+ AND (n.position < walk.position OR (n.position = walk.position AND n.identity < walk.identity))
106
+ ${NEWER}
107
+ )
108
+ WHERE julianday(walk.at) >= julianday(?)
109
+ )
110
+ SELECT walk.conversation AS conversation, walk.at AS at
111
+ FROM walk
112
+ WHERE walk.role IN ('user', 'assistant') AND julianday(walk.at) >= julianday(?)`;
113
+ export function conversationTallies(connection, conversations, since) {
114
+ const named = conversations ??
115
+ connection
116
+ .rows('SELECT DISTINCT conversation FROM conversation_messages')
117
+ .map((row) => String(row.conversation));
118
+ const from = instantKey(since);
119
+ const said = new Map();
120
+ for (const row of connection.rows(SAID, [JSON.stringify(named), since, since])) {
121
+ const at = instantKey(row.at);
122
+ if (at === null || at < from)
123
+ continue;
124
+ const conversation = String(row.conversation);
125
+ said.set(conversation, [...(said.get(conversation) ?? []), at]);
126
+ }
127
+ return named.map((conversation) => ({ conversation, said: said.get(conversation) ?? [] }));
128
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EAGhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAM7D,KAAK,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,IAAI,GAAG,CACjB,KAAK,EAAE,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC;AAEtF,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAyBvF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1F,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CAChF,CAAC;AAkBF,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,UAAU,CAAC,CAgCrB"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAGhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAgD,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAMjG,KAAK,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,IAAI,GAAG,CACjB,KAAK,EAAE,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC;AAEtF,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAoBvF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,UAAU,CAAC,CA6CrB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1F,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CAChF,CAAC;AAgBF,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,UAAU,CAAC,CAgCrB"}