@agentshouse/mdruntime 0.1.0-c99e5271060cd → 0.1.0-c9b1e59e5baeb

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 (202) hide show
  1. package/AGENTS.md +274 -244
  2. package/README.md +18 -8
  3. package/dist/adapter.d.ts +98 -20
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attempt.d.ts +16 -0
  6. package/dist/attempt.d.ts.map +1 -0
  7. package/dist/attempt.js +70 -0
  8. package/dist/binary.d.ts +23 -0
  9. package/dist/binary.d.ts.map +1 -0
  10. package/dist/binary.js +8 -0
  11. package/dist/bootstrap.d.ts +3 -2
  12. package/dist/bootstrap.d.ts.map +1 -1
  13. package/dist/bootstrap.js +38 -15
  14. package/dist/change-set.d.ts +7 -2
  15. package/dist/change-set.d.ts.map +1 -1
  16. package/dist/change-set.js +45 -13
  17. package/dist/change.d.ts +11 -0
  18. package/dist/change.d.ts.map +1 -1
  19. package/dist/change.js +26 -1
  20. package/dist/chat/acts.d.ts +33 -0
  21. package/dist/chat/acts.d.ts.map +1 -0
  22. package/dist/chat/acts.js +36 -0
  23. package/dist/chat/context.d.ts +3 -0
  24. package/dist/chat/context.d.ts.map +1 -0
  25. package/dist/chat/context.js +10 -0
  26. package/dist/chat/earlier.d.ts +10 -0
  27. package/dist/chat/earlier.d.ts.map +1 -0
  28. package/dist/chat/earlier.js +54 -0
  29. package/dist/chat/input.d.ts +9 -0
  30. package/dist/chat/input.d.ts.map +1 -0
  31. package/dist/chat/input.js +99 -0
  32. package/dist/chat/kit.d.ts +61 -0
  33. package/dist/chat/kit.d.ts.map +1 -0
  34. package/dist/chat/kit.js +123 -0
  35. package/dist/chat/lasting.d.ts +6 -0
  36. package/dist/chat/lasting.d.ts.map +1 -0
  37. package/dist/chat/lasting.js +19 -0
  38. package/dist/chat/list.d.ts +28 -0
  39. package/dist/chat/list.d.ts.map +1 -0
  40. package/dist/chat/list.js +99 -0
  41. package/dist/chat/markdown.d.ts +21 -0
  42. package/dist/chat/markdown.d.ts.map +1 -0
  43. package/dist/chat/markdown.js +246 -0
  44. package/dist/chat/message.d.ts +6 -0
  45. package/dist/chat/message.d.ts.map +1 -0
  46. package/dist/chat/message.js +199 -0
  47. package/dist/chat/messages.d.ts +22 -0
  48. package/dist/chat/messages.d.ts.map +1 -0
  49. package/dist/chat/messages.js +175 -0
  50. package/dist/chat/name.d.ts +6 -0
  51. package/dist/chat/name.d.ts.map +1 -0
  52. package/dist/chat/name.js +37 -0
  53. package/dist/chat/opened.d.ts +11 -0
  54. package/dist/chat/opened.d.ts.map +1 -0
  55. package/dist/chat/opened.js +17 -0
  56. package/dist/chat/overlay.d.ts +32 -0
  57. package/dist/chat/overlay.d.ts.map +1 -0
  58. package/dist/chat/overlay.js +107 -0
  59. package/dist/chat/parts.d.ts +57 -0
  60. package/dist/chat/parts.d.ts.map +1 -0
  61. package/dist/chat/parts.js +119 -0
  62. package/dist/chat/pieces.d.ts +62 -0
  63. package/dist/chat/pieces.d.ts.map +1 -0
  64. package/dist/chat/pieces.js +1110 -0
  65. package/dist/chat/process.d.ts +20 -0
  66. package/dist/chat/process.d.ts.map +1 -0
  67. package/dist/chat/process.js +32 -0
  68. package/dist/chat/provider.d.ts +64 -0
  69. package/dist/chat/provider.d.ts.map +1 -0
  70. package/dist/chat/provider.js +637 -0
  71. package/dist/chat/question.d.ts +9 -0
  72. package/dist/chat/question.d.ts.map +1 -0
  73. package/dist/chat/question.js +69 -0
  74. package/dist/chat/questions.d.ts +31 -0
  75. package/dist/chat/questions.d.ts.map +1 -0
  76. package/dist/chat/questions.js +111 -0
  77. package/dist/chat/read.d.ts +5 -0
  78. package/dist/chat/read.d.ts.map +1 -0
  79. package/dist/chat/read.js +13 -0
  80. package/dist/chat/ready.d.ts +34 -0
  81. package/dist/chat/ready.d.ts.map +1 -0
  82. package/dist/chat/ready.js +91 -0
  83. package/dist/chat/steady.d.ts +3 -0
  84. package/dist/chat/steady.d.ts.map +1 -0
  85. package/dist/chat/steady.js +26 -0
  86. package/dist/chat/style.d.ts +4 -0
  87. package/dist/chat/style.d.ts.map +1 -0
  88. package/dist/chat/style.js +302 -0
  89. package/dist/chat.d.ts +14 -0
  90. package/dist/chat.d.ts.map +1 -0
  91. package/dist/chat.js +8 -0
  92. package/dist/client.d.ts +26 -11
  93. package/dist/client.d.ts.map +1 -1
  94. package/dist/client.js +27 -4
  95. package/dist/collection.d.ts +20 -5
  96. package/dist/collection.d.ts.map +1 -1
  97. package/dist/collection.js +309 -33
  98. package/dist/connection.d.ts +41 -13
  99. package/dist/connection.d.ts.map +1 -1
  100. package/dist/connection.js +1819 -407
  101. package/dist/conversation.d.ts +34 -9
  102. package/dist/conversation.d.ts.map +1 -1
  103. package/dist/conversation.js +552 -168
  104. package/dist/durability.d.ts +7 -1
  105. package/dist/durability.d.ts.map +1 -1
  106. package/dist/entry.d.ts +17 -0
  107. package/dist/entry.d.ts.map +1 -0
  108. package/dist/entry.js +157 -0
  109. package/dist/expectation.d.ts +21 -0
  110. package/dist/expectation.d.ts.map +1 -0
  111. package/dist/expectation.js +70 -0
  112. package/dist/fence.d.ts +6 -0
  113. package/dist/fence.d.ts.map +1 -0
  114. package/dist/fence.js +10 -0
  115. package/dist/host.d.ts +15 -3
  116. package/dist/host.d.ts.map +1 -1
  117. package/dist/host.js +99 -13
  118. package/dist/identity.d.ts +4 -0
  119. package/dist/identity.d.ts.map +1 -1
  120. package/dist/identity.js +12 -0
  121. package/dist/index.d.ts +15 -8
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +5 -0
  124. package/dist/memory.d.ts +10 -4
  125. package/dist/memory.d.ts.map +1 -1
  126. package/dist/memory.js +64 -17
  127. package/dist/model.d.ts +4 -2
  128. package/dist/model.d.ts.map +1 -1
  129. package/dist/model.js +10 -1
  130. package/dist/observation.d.ts +7 -2
  131. package/dist/observation.d.ts.map +1 -1
  132. package/dist/observation.js +29 -12
  133. package/dist/outcome.d.ts +17 -1
  134. package/dist/outcome.d.ts.map +1 -1
  135. package/dist/outcome.js +10 -0
  136. package/dist/overlay.d.ts +18 -5
  137. package/dist/overlay.d.ts.map +1 -1
  138. package/dist/overlay.js +238 -160
  139. package/dist/query.d.ts +58 -4
  140. package/dist/query.d.ts.map +1 -1
  141. package/dist/query.js +36 -7
  142. package/dist/reach.d.ts +8 -3
  143. package/dist/reach.d.ts.map +1 -1
  144. package/dist/reach.js +55 -8
  145. package/dist/react.d.ts +10 -7
  146. package/dist/react.d.ts.map +1 -1
  147. package/dist/react.js +7 -17
  148. package/dist/read-side.d.ts +16 -7
  149. package/dist/read-side.d.ts.map +1 -1
  150. package/dist/read-side.js +495 -102
  151. package/dist/readiness.d.ts +53 -0
  152. package/dist/readiness.d.ts.map +1 -0
  153. package/dist/readiness.js +33 -0
  154. package/dist/reads.d.ts +11 -0
  155. package/dist/reads.d.ts.map +1 -0
  156. package/dist/reads.js +98 -0
  157. package/dist/recovery.d.ts +25 -0
  158. package/dist/recovery.d.ts.map +1 -0
  159. package/dist/recovery.js +197 -0
  160. package/dist/refresh.d.ts +4 -4
  161. package/dist/refresh.d.ts.map +1 -1
  162. package/dist/refresh.js +51 -30
  163. package/dist/replica.d.ts +15 -6
  164. package/dist/replica.d.ts.map +1 -1
  165. package/dist/replica.js +137 -66
  166. package/dist/room-draft.d.ts +32 -3
  167. package/dist/room-draft.d.ts.map +1 -1
  168. package/dist/room-draft.js +129 -12
  169. package/dist/rows.d.ts +8 -13
  170. package/dist/rows.d.ts.map +1 -1
  171. package/dist/rows.js +12 -13
  172. package/dist/save.d.ts +32 -2
  173. package/dist/save.d.ts.map +1 -1
  174. package/dist/save.js +495 -97
  175. package/dist/search.d.ts +49 -6
  176. package/dist/search.d.ts.map +1 -1
  177. package/dist/search.js +192 -47
  178. package/dist/seed.d.ts +16 -0
  179. package/dist/seed.d.ts.map +1 -0
  180. package/dist/seed.js +75 -0
  181. package/dist/shared.d.ts +15 -0
  182. package/dist/shared.d.ts.map +1 -0
  183. package/dist/shared.js +398 -0
  184. package/dist/status.d.ts +4 -1
  185. package/dist/status.d.ts.map +1 -1
  186. package/dist/status.js +0 -8
  187. package/dist/store.d.ts +71 -21
  188. package/dist/store.d.ts.map +1 -1
  189. package/dist/store.js +625 -320
  190. package/dist/turn.d.ts +9 -0
  191. package/dist/turn.d.ts.map +1 -0
  192. package/dist/turn.js +64 -0
  193. package/dist/windows.d.ts +26 -0
  194. package/dist/windows.d.ts.map +1 -0
  195. package/dist/windows.js +93 -0
  196. package/dist/wire.d.ts +153 -30
  197. package/dist/wire.d.ts.map +1 -1
  198. package/dist/wire.js +53 -29
  199. package/package.json +26 -14
  200. package/dist/attachment.d.ts +0 -3
  201. package/dist/attachment.d.ts.map +0 -1
  202. package/dist/attachment.js +0 -8
package/dist/overlay.js CHANGED
@@ -1,4 +1,20 @@
1
- import { apply, parse, serialize } from '@agentshouse/mdmodel';
1
+ import { apply, frontmatterValue, parse, serialize, } from '@agentshouse/mdmodel';
2
+ import { differences, drafted, patching, settling } from './shared.js';
3
+ import { ROW_WEIGHT } from './turn.js';
4
+ export function acceptedBinaries(files) {
5
+ return Object.fromEntries(Object.entries(files).map(([path, file]) => [path, { state: 'accepted', ...file }]));
6
+ }
7
+ export function sameBinary(left, right) {
8
+ if (left === undefined || right === undefined)
9
+ return left === right;
10
+ return (left.state === right.state &&
11
+ left.byteLength === right.byteLength &&
12
+ left.mediaType === right.mediaType &&
13
+ left.sha256 === right.sha256 &&
14
+ (left.state === 'accepted'
15
+ ? right.state === 'accepted' && left.fileRef === right.fileRef
16
+ : right.state === 'pending' && left.localId === right.localId));
17
+ }
2
18
  export function sameChange(left, right) {
3
19
  if (left === undefined || right === undefined)
4
20
  return left === right;
@@ -8,10 +24,13 @@ export function sameChange(left, right) {
8
24
  left.author?.name === right.author?.name);
9
25
  }
10
26
  const EMPTY_FRONTMATTER = '---\n---\n';
27
+ function isPart(change) {
28
+ return change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble';
29
+ }
11
30
  function at(path, name) {
12
31
  return `${path} ${name}`;
13
32
  }
14
- function priorsOf(preconditions) {
33
+ function* priorsOf(preconditions) {
15
34
  const fields = new Map();
16
35
  const sections = new Map();
17
36
  const preambles = new Map();
@@ -25,6 +44,7 @@ function priorsOf(preconditions) {
25
44
  if (precondition.kind === 'preamble') {
26
45
  preambles.set(precondition.path, precondition.value);
27
46
  }
47
+ yield ROW_WEIGHT;
28
48
  }
29
49
  return {
30
50
  field: (path, name) => fields.get(at(path, name)),
@@ -40,51 +60,50 @@ function compose(fields, sections) {
40
60
  const opened = parse(skeleton);
41
61
  if (!opened.ok)
42
62
  return skeleton;
43
- let document = opened.document;
44
- for (const [name, value] of Object.entries(fields)) {
45
- const next = apply(document, { kind: 'field', name, value, prior: undefined });
46
- if (next.outcome === 'applied')
47
- document = next.document;
48
- }
49
- return serialize(document);
63
+ const next = apply(opened.document, Object.entries(fields).flatMap(([name, value]) => frontmatterValue(value) ? [{ kind: 'field', name, value, prior: undefined }] : []));
64
+ return serialize(next.outcome === 'applied' ? next.document : opened.document);
50
65
  }
51
- function edited(document, change, priors) {
52
- if (change.kind === 'field') {
53
- return apply(document, {
66
+ function edited(change, priors) {
67
+ if (change.kind === 'field')
68
+ return {
54
69
  kind: 'field',
55
70
  name: change.name,
56
71
  value: change.value,
57
72
  prior: priors.field(change.path, change.name),
58
- });
59
- }
60
- if (change.kind === 'preamble') {
61
- return apply(document, {
62
- kind: 'preamble',
63
- value: change.value,
64
- prior: priors.preamble(change.path),
65
- });
66
- }
67
- if (change.kind !== 'section')
68
- return null;
69
- return apply(document, {
73
+ };
74
+ if (change.kind === 'preamble')
75
+ return { kind: 'preamble', value: change.value, prior: priors.preamble(change.path) };
76
+ return {
70
77
  kind: 'section',
71
78
  name: change.name,
72
79
  value: change.value,
73
80
  prior: priors.section(change.path, change.name),
74
- });
81
+ };
75
82
  }
76
- function edit(staged, change, priors) {
77
- const text = staged.documents[change.path];
83
+ function edit(staged, changes, priors) {
84
+ const path = changes[0].path;
85
+ delete staged.revisions[path];
86
+ const text = staged.documents[path];
78
87
  if (text === undefined)
79
- return false;
80
- const parsed = parse(text, change.path);
88
+ return changes.length;
89
+ const parsed = parse(text, path);
81
90
  if (!parsed.ok)
82
- return false;
83
- const next = edited(parsed.document, change, priors);
84
- if (next?.outcome !== 'applied')
85
- return false;
86
- staged.documents[change.path] = serialize(next.document);
87
- return true;
91
+ return changes.length;
92
+ const wanted = changes.map((change) => edited(change, priors));
93
+ const first = apply(parsed.document, wanted);
94
+ if (first.outcome === 'refuse')
95
+ return changes.length;
96
+ if (first.outcome === 'applied') {
97
+ staged.documents[path] = serialize(first.document);
98
+ return 0;
99
+ }
100
+ const stale = new Set(first.stale);
101
+ const kept = wanted.filter((_, at) => !stale.has(at));
102
+ const rest = apply(parsed.document, kept);
103
+ if (rest.outcome !== 'applied')
104
+ return changes.length;
105
+ staged.documents[path] = serialize(rest.document);
106
+ return first.stale.length;
88
107
  }
89
108
  function relocate(staged, from, to) {
90
109
  const text = staged.documents[from];
@@ -92,8 +111,9 @@ function relocate(staged, from, to) {
92
111
  delete staged.documents[from];
93
112
  staged.documents[to] = text;
94
113
  }
95
- else if (staged.binaryTargets.delete(from)) {
96
- staged.binaryTargets.add(to);
114
+ else if (staged.binaries[from] !== undefined) {
115
+ staged.binaries[to] = staged.binaries[from];
116
+ delete staged.binaries[from];
97
117
  }
98
118
  else {
99
119
  return false;
@@ -103,185 +123,243 @@ function relocate(staged, from, to) {
103
123
  }
104
124
  function moveHead(heads, from, to) {
105
125
  const revision = heads.revisions[from];
126
+ const fileId = heads.fileIds[from];
106
127
  const change = heads.changes[from];
107
128
  delete heads.revisions[from];
129
+ delete heads.fileIds[from];
108
130
  delete heads.changes[from];
131
+ delete heads.fileIds[to];
109
132
  delete heads.changes[to];
110
133
  if (revision !== undefined)
111
134
  heads.revisions[to] = revision;
135
+ if (fileId !== undefined)
136
+ heads.fileIds[to] = fileId;
112
137
  if (change !== undefined)
113
138
  heads.changes[to] = change;
114
139
  }
115
140
  function erase(staged, path) {
116
141
  delete staged.documents[path];
117
142
  delete staged.revisions[path];
143
+ delete staged.fileIds[path];
118
144
  delete staged.changes[path];
119
- staged.binaryTargets.delete(path);
145
+ delete staged.binaries[path];
120
146
  }
121
- function stage(staged, change, priors) {
122
- if (change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble') {
123
- return edit(staged, change, priors);
124
- }
147
+ function stage(staged, change) {
125
148
  if (change.kind === 'create') {
126
149
  staged.documents[change.path] =
127
150
  'content' in change ? change.content : compose(change.fields, change.sections);
151
+ delete staged.fileIds[change.path];
128
152
  delete staged.changes[change.path];
129
153
  return true;
130
154
  }
131
155
  if (change.kind === 'replace') {
156
+ delete staged.revisions[change.path];
132
157
  if (staged.documents[change.path] === undefined)
133
158
  return false;
134
159
  staged.documents[change.path] = change.content;
135
160
  return true;
136
161
  }
162
+ if (change.kind === 'binary') {
163
+ if (staged.documents[change.path] !== undefined)
164
+ return false;
165
+ staged.binaries[change.path] = {
166
+ state: 'pending',
167
+ localId: change.localId,
168
+ byteLength: change.byteLength,
169
+ mediaType: change.mediaType,
170
+ sha256: change.sha256,
171
+ };
172
+ delete staged.revisions[change.path];
173
+ delete staged.changes[change.path];
174
+ return true;
175
+ }
137
176
  if (change.kind === 'move') {
138
177
  return relocate(staged, change.path, change.to);
139
178
  }
140
179
  erase(staged, change.path);
141
180
  return true;
142
181
  }
143
- export function overlay(base, queue, unapplied) {
182
+ export function* overlaying(base, queue, unapplied) {
144
183
  const staged = {
145
- documents: { ...base.documents },
146
- binaryTargets: new Set(base.binaryTargets),
147
- revisions: { ...base.revisions },
148
- changes: { ...base.changes },
184
+ documents: drafted(base.documents),
185
+ binaries: drafted(base.binaries),
186
+ revisions: drafted(base.revisions),
187
+ fileIds: drafted(base.fileIds),
188
+ changes: drafted(base.changes),
149
189
  };
150
190
  for (const batch of queue) {
151
- const priors = priorsOf(batch.preconditions);
152
- for (const change of batch.changes) {
153
- if (!stage(staged, change, priors))
191
+ const priors = yield* priorsOf(batch.preconditions);
192
+ for (let index = 0; index < batch.changes.length; index += 1) {
193
+ const change = batch.changes[index];
194
+ if (!isPart(change)) {
195
+ if (!stage(staged, change))
196
+ unapplied?.();
197
+ yield ROW_WEIGHT;
198
+ continue;
199
+ }
200
+ const run = [change];
201
+ while (index + 1 < batch.changes.length) {
202
+ const next = batch.changes[index + 1];
203
+ if (!isPart(next) || next.path !== change.path)
204
+ break;
205
+ run.push(next);
206
+ index += 1;
207
+ }
208
+ const text = staged.documents[change.path] ?? '';
209
+ for (let left = edit(staged, run, priors); left > 0; left -= 1)
154
210
  unapplied?.();
211
+ yield ROW_WEIGHT + text.length;
155
212
  }
156
213
  }
157
214
  return {
158
- documents: staged.documents,
159
- binaryTargets: [...staged.binaryTargets].sort(),
160
- revisions: staged.revisions,
161
- changes: staged.changes,
215
+ documents: yield* settling(staged.documents),
216
+ binaries: yield* settling(staged.binaries),
217
+ revisions: yield* settling(staged.revisions),
218
+ fileIds: yield* settling(staged.fileIds),
219
+ changes: yield* settling(staged.changes),
162
220
  };
163
221
  }
164
- function pathsOf(batch) {
165
- return batch.changes.flatMap((change) => change.kind === 'move' ? [change.path, change.to] : [change.path]);
222
+ function* pathsOf(batch) {
223
+ const paths = new Set();
224
+ for (const change of batch.changes) {
225
+ paths.add(change.path);
226
+ if (change.kind === 'move')
227
+ paths.add(change.to);
228
+ yield ROW_WEIGHT;
229
+ }
230
+ return paths;
166
231
  }
167
- export function sameLayerText(left, right) {
168
- const paths = Object.keys(left.documents);
169
- return (paths.length === Object.keys(right.documents).length &&
170
- paths.every((path) => left.documents[path] === right.documents[path]) &&
171
- left.binaryTargets.length === right.binaryTargets.length &&
172
- left.binaryTargets.every((path) => right.binaryTargets.includes(path)));
232
+ export function* sameText(left, right) {
233
+ return ((yield* differences(left.documents, right.documents)).size === 0 &&
234
+ (yield* differences(left.binaries, right.binaries, sameBinary)).size === 0);
173
235
  }
174
- function replayHeads(base, queue) {
175
- const heads = { revisions: { ...base.revisions }, changes: { ...base.changes } };
176
- for (const batch of queue) {
177
- for (const change of batch.changes) {
178
- if (change.kind === 'remove') {
179
- delete heads.revisions[change.path];
180
- delete heads.changes[change.path];
181
- }
182
- else if (change.kind === 'create') {
183
- delete heads.changes[change.path];
184
- }
185
- else if (change.kind === 'move') {
186
- moveHead(heads, change.path, change.to);
187
- }
236
+ export function* changedPaths(left, right) {
237
+ return new Set([
238
+ ...(yield* differences(left.documents, right.documents)),
239
+ ...(yield* differences(left.revisions, right.revisions)),
240
+ ...(yield* differences(left.fileIds, right.fileIds)),
241
+ ...(yield* differences(left.changes, right.changes, sameChange)),
242
+ ...(yield* differences(left.binaries, right.binaries, sameBinary)),
243
+ ]);
244
+ }
245
+ function* sameItems(left, right) {
246
+ if (left.length !== right.length)
247
+ return false;
248
+ for (let index = 0; index < left.length; index += 1) {
249
+ const item = JSON.stringify(left[index]);
250
+ if (item !== JSON.stringify(right[index]))
251
+ return false;
252
+ yield ROW_WEIGHT + item.length;
253
+ }
254
+ return true;
255
+ }
256
+ function* sameBatch(left, right) {
257
+ if (left === right)
258
+ return true;
259
+ const { changes, preconditions, ...rest } = left;
260
+ const { changes: others, preconditions: priors, ...held } = right;
261
+ return (JSON.stringify(rest) === JSON.stringify(held) &&
262
+ (yield* sameItems(changes, others)) &&
263
+ (yield* sameItems(preconditions, priors)));
264
+ }
265
+ function* replayHeads(base, batch) {
266
+ const heads = {
267
+ revisions: drafted(base.revisions),
268
+ fileIds: drafted(base.fileIds),
269
+ changes: drafted(base.changes),
270
+ };
271
+ for (const change of batch.changes) {
272
+ if (change.kind === 'remove') {
273
+ delete heads.revisions[change.path];
274
+ delete heads.fileIds[change.path];
275
+ delete heads.changes[change.path];
276
+ }
277
+ else if (change.kind === 'create') {
278
+ delete heads.fileIds[change.path];
279
+ delete heads.changes[change.path];
188
280
  }
281
+ else if (change.kind === 'replace' ||
282
+ change.kind === 'field' ||
283
+ change.kind === 'section' ||
284
+ change.kind === 'preamble') {
285
+ delete heads.revisions[change.path];
286
+ }
287
+ else if (change.kind === 'binary') {
288
+ delete heads.revisions[change.path];
289
+ delete heads.changes[change.path];
290
+ }
291
+ else if (change.kind === 'move') {
292
+ moveHead(heads, change.path, change.to);
293
+ }
294
+ yield ROW_WEIGHT;
189
295
  }
190
- return heads;
296
+ return {
297
+ revisions: yield* settling(heads.revisions),
298
+ fileIds: yield* settling(heads.fileIds),
299
+ changes: yield* settling(heads.changes),
300
+ };
301
+ }
302
+ function* repatched(held, paths, value) {
303
+ const set = [];
304
+ const removed = [];
305
+ for (const path of paths) {
306
+ const found = value(path);
307
+ if (found === undefined)
308
+ removed.push(path);
309
+ else
310
+ set.push([path, found]);
311
+ yield ROW_WEIGHT;
312
+ }
313
+ return yield* patching(held, set, removed);
191
314
  }
192
- export function overlayChanged(base, queue, previousBase, previousQueue, previousVisible) {
193
- const before = previousQueue.map((batch) => JSON.stringify(batch));
194
- const after = queue.map((batch) => JSON.stringify(batch));
195
- if (before.length === after.length &&
196
- before.every((id, index) => id === after[index]) &&
197
- sameLayerText(base, previousBase)) {
315
+ export function* overlayChanged(base, batch, previousBase, previousBatch, previousVisible) {
316
+ const same = yield* sameBatch(batch, previousBatch);
317
+ if (same && (yield* sameText(base, previousBase))) {
198
318
  return {
199
319
  documents: previousVisible.documents,
200
- binaryTargets: previousVisible.binaryTargets,
201
- ...replayHeads(base, queue),
320
+ binaries: previousVisible.binaries,
321
+ ...(yield* replayHeads(base, batch)),
202
322
  };
203
323
  }
204
- const affected = new Set();
205
- const paths = new Set([
206
- ...Object.keys(base.documents),
207
- ...Object.keys(previousBase.documents),
208
- ...Object.keys(base.revisions),
209
- ...Object.keys(previousBase.revisions),
210
- ...Object.keys(base.changes),
211
- ...Object.keys(previousBase.changes),
212
- ...base.binaryTargets,
213
- ...previousBase.binaryTargets,
214
- ]);
215
- for (const path of paths) {
216
- if (base.documents[path] !== previousBase.documents[path] ||
217
- base.revisions[path] !== previousBase.revisions[path] ||
218
- !sameChange(base.changes[path], previousBase.changes[path]) ||
219
- base.binaryTargets.includes(path) !== previousBase.binaryTargets.includes(path))
324
+ const affected = new Set(yield* changedPaths(base, previousBase));
325
+ const touched = yield* pathsOf(batch);
326
+ let replayed = !same;
327
+ if (replayed)
328
+ for (const path of yield* pathsOf(previousBatch))
220
329
  affected.add(path);
330
+ for (const path of touched) {
331
+ if (affected.has(path))
332
+ replayed = true;
333
+ yield ROW_WEIGHT;
221
334
  }
222
- const oldIds = new Set(before);
223
- const newIds = new Set(after);
224
- for (const batch of previousQueue) {
225
- if (!newIds.has(JSON.stringify(batch)))
226
- for (const path of pathsOf(batch))
227
- affected.add(path);
228
- }
229
- for (const batch of queue) {
230
- if (!oldIds.has(JSON.stringify(batch)))
231
- for (const path of pathsOf(batch))
232
- affected.add(path);
233
- }
234
- let expanded = true;
235
- while (expanded) {
236
- expanded = false;
237
- for (const batch of queue) {
238
- const touched = pathsOf(batch);
239
- if (!touched.some((path) => affected.has(path)))
240
- continue;
241
- for (const path of touched) {
242
- if (affected.has(path))
243
- continue;
244
- affected.add(path);
245
- expanded = true;
246
- }
247
- }
248
- }
249
- const documents = {};
250
- const revisions = {};
251
- const changes = {};
252
- for (const path of affected) {
335
+ const restricted = {
336
+ documents: {},
337
+ revisions: {},
338
+ fileIds: {},
339
+ changes: {},
340
+ binaries: {},
341
+ };
342
+ for (const path of replayed ? touched : []) {
343
+ affected.add(path);
253
344
  if (base.documents[path] !== undefined)
254
- documents[path] = base.documents[path];
345
+ restricted.documents[path] = base.documents[path];
255
346
  if (base.revisions[path] !== undefined)
256
- revisions[path] = base.revisions[path];
347
+ restricted.revisions[path] = base.revisions[path];
348
+ if (base.fileIds[path] !== undefined)
349
+ restricted.fileIds[path] = base.fileIds[path];
257
350
  if (base.changes[path] !== undefined)
258
- changes[path] = base.changes[path];
259
- }
260
- const staged = overlay({
261
- documents,
262
- revisions,
263
- changes,
264
- binaryTargets: base.binaryTargets.filter((path) => affected.has(path)),
265
- }, queue.filter((batch) => pathsOf(batch).some((path) => affected.has(path))));
266
- const mergedDocuments = { ...previousVisible.documents };
267
- const mergedRevisions = { ...previousVisible.revisions };
268
- const mergedChanges = { ...previousVisible.changes };
269
- const mergedTargets = new Set(previousVisible.binaryTargets);
270
- for (const path of affected) {
271
- delete mergedDocuments[path];
272
- delete mergedRevisions[path];
273
- delete mergedChanges[path];
274
- mergedTargets.delete(path);
351
+ restricted.changes[path] = base.changes[path];
352
+ if (base.binaries[path] !== undefined)
353
+ restricted.binaries[path] = base.binaries[path];
354
+ yield ROW_WEIGHT;
275
355
  }
276
- Object.assign(mergedDocuments, staged.documents);
277
- Object.assign(mergedRevisions, staged.revisions);
278
- Object.assign(mergedChanges, staged.changes);
279
- for (const path of staged.binaryTargets)
280
- mergedTargets.add(path);
356
+ const staged = replayed ? yield* overlaying(restricted, [batch]) : base;
357
+ const from = (path) => (touched.has(path) ? staged : base);
281
358
  return {
282
- documents: mergedDocuments,
283
- revisions: mergedRevisions,
284
- changes: mergedChanges,
285
- binaryTargets: [...mergedTargets].sort(),
359
+ documents: yield* repatched(previousVisible.documents, affected, (path) => from(path).documents[path]),
360
+ revisions: yield* repatched(previousVisible.revisions, affected, (path) => from(path).revisions[path]),
361
+ fileIds: yield* repatched(previousVisible.fileIds, affected, (path) => from(path).fileIds[path]),
362
+ changes: yield* repatched(previousVisible.changes, affected, (path) => from(path).changes[path]),
363
+ binaries: yield* repatched(previousVisible.binaries, affected, (path) => from(path).binaries[path]),
286
364
  };
287
365
  }
package/dist/query.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { type Definition } from '@agentshouse/mdmodel';
2
2
  import type { HeadChange } from './adapter.js';
3
+ import type { BinaryFileRecord } from './binary.js';
4
+ import type { Open } from './open.js';
3
5
  export type Value = string | number | boolean | null;
4
6
  export type Predicate = Value | {
5
7
  $eq: Value;
@@ -36,6 +38,8 @@ export type Filter = {
36
38
  types?: readonly string[];
37
39
  where?: Where;
38
40
  pathPrefix?: string;
41
+ folder?: string;
42
+ paths?: readonly string[];
39
43
  hop?: Related & {
40
44
  field: string;
41
45
  };
@@ -43,7 +47,7 @@ export type Filter = {
43
47
  field?: string;
44
48
  };
45
49
  };
46
- export type Key = 'room' | 'path' | 'type' | {
50
+ export type Key = 'room' | 'path' | 'type' | 'folder' | {
47
51
  field: string;
48
52
  };
49
53
  export type Select = 'all' | {
@@ -53,6 +57,7 @@ export type Select = 'all' | {
53
57
  markdown?: true;
54
58
  backlinks?: true;
55
59
  change?: true;
60
+ fileId?: true;
56
61
  };
57
62
  export type OrderOptions = {
58
63
  nulls?: 'first' | 'last';
@@ -68,6 +73,8 @@ export type DocumentQuery = Filter & {
68
73
  direction?: Direction;
69
74
  } & OrderOptions)[];
70
75
  limit?: number;
76
+ after?: string;
77
+ total?: true;
71
78
  };
72
79
  export type GroupQuery = Filter & {
73
80
  groupBy: readonly Exclude<Key, 'path'>[];
@@ -76,6 +83,8 @@ export type GroupQuery = Filter & {
76
83
  direction?: Direction;
77
84
  }[];
78
85
  limit?: number;
86
+ after?: string;
87
+ total?: true;
79
88
  };
80
89
  export type LocalQuery = DocumentQuery | GroupQuery;
81
90
  export type Backlink = {
@@ -93,18 +102,49 @@ export type QueryDocument = {
93
102
  markdown?: string;
94
103
  backlinks?: readonly Backlink[];
95
104
  change?: HeadChange | null;
105
+ fileId?: string | null;
106
+ binaryFile?: BinaryFileRecord;
96
107
  };
97
108
  export type QueryGroup = {
98
109
  key: readonly unknown[];
99
110
  count: number;
100
111
  };
101
- export type DocumentResult = {
112
+ export type CoveredRoom = {
113
+ room: string;
114
+ generation: string;
115
+ current: boolean;
116
+ };
117
+ export type QueryCoverage = {
118
+ rooms: readonly CoveredRoom[];
119
+ indexes: readonly string[];
120
+ overlay: readonly string[];
121
+ };
122
+ export type Awaits = Open<'acquisition' | 'preparation' | 'index'>;
123
+ export type PendingRoom = {
124
+ room: string;
125
+ awaits: Awaits;
126
+ };
127
+ export type PendingResult = {
128
+ pending: readonly PendingRoom[];
129
+ };
130
+ export type DocumentRows = {
102
131
  documents: readonly QueryDocument[];
132
+ next?: string;
133
+ total?: number;
103
134
  };
104
- export type GroupResult = {
135
+ export type GroupRows = {
105
136
  groups: readonly QueryGroup[];
137
+ next?: string;
138
+ total?: number;
139
+ };
140
+ export type QueryRows = DocumentRows | GroupRows;
141
+ export type DocumentResult = DocumentRows & {
142
+ coverage: QueryCoverage;
143
+ };
144
+ export type GroupResult = GroupRows & {
145
+ coverage: QueryCoverage;
106
146
  };
107
- export type QueryResult = DocumentResult | GroupResult;
147
+ export type QueryResult = DocumentResult | GroupResult | PendingResult;
108
148
  export type QueryErrorCode = 'invalid-query' | 'unknown-type' | 'unknown-field' | 'wrong-kind';
109
149
  export type RoomFacts = {
110
150
  locator: string;
@@ -159,6 +199,8 @@ export type KeyPlan = {
159
199
  of: 'path';
160
200
  } | {
161
201
  of: 'type';
202
+ } | {
203
+ of: 'folder';
162
204
  } | {
163
205
  of: 'field';
164
206
  field: string;
@@ -171,6 +213,7 @@ export type DocumentShape = {
171
213
  markdown: boolean;
172
214
  backlinks: boolean;
173
215
  change: boolean;
216
+ fileId: boolean;
174
217
  orderBy: readonly {
175
218
  key: KeyPlan;
176
219
  options: OrderOptions & {
@@ -190,10 +233,17 @@ export type PlanReach = {
190
233
  rooms: readonly string[];
191
234
  documents: readonly string[];
192
235
  };
236
+ export type Continuation = {
237
+ text: string;
238
+ values: readonly unknown[] | null;
239
+ };
193
240
  export type Plan = {
241
+ key: string;
194
242
  rooms: readonly string[] | null;
195
243
  reach: PlanReach | null;
196
244
  root: Scope;
245
+ folder: string | null;
246
+ paths: readonly string[] | null;
197
247
  hop: (Scope & {
198
248
  field: string;
199
249
  }) | null;
@@ -202,6 +252,8 @@ export type Plan = {
202
252
  }) | null;
203
253
  shape: DocumentShape | GroupShape;
204
254
  limit: number | null;
255
+ after: Continuation | null;
256
+ total: boolean;
205
257
  };
206
258
  export declare class QueryError extends Error {
207
259
  readonly code: QueryErrorCode;
@@ -212,9 +264,11 @@ type Entries = Readonly<Record<string, unknown>>;
212
264
  export declare function invalid(at: string, problem: string): never;
213
265
  export declare function plain(value: unknown): value is Entries;
214
266
  export declare function known(value: Entries, allowed: readonly string[], at: string): void;
267
+ export declare function flag(input: unknown, at: string): boolean;
215
268
  export declare function planOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
216
269
  export declare function limitOf(input: unknown): number | null;
217
270
  export declare function filterOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
271
+ export declare function queryKey(query: unknown): string;
218
272
  export declare function identityOf(plan: Plan): string;
219
273
  export {};
220
274
  //# sourceMappingURL=query.d.ts.map