@agentshouse/mdruntime 0.1.0-cacb4c3f6734e → 0.1.0-caee7332d2235

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 (210) hide show
  1. package/AGENTS.md +277 -222
  2. package/README.md +20 -10
  3. package/dist/adapter.d.ts +95 -20
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +15 -2
  7. package/dist/attempt.d.ts +16 -0
  8. package/dist/attempt.d.ts.map +1 -0
  9. package/dist/attempt.js +70 -0
  10. package/dist/binary.d.ts +23 -0
  11. package/dist/binary.d.ts.map +1 -0
  12. package/dist/binary.js +8 -0
  13. package/dist/bootstrap.d.ts +18 -5
  14. package/dist/bootstrap.d.ts.map +1 -1
  15. package/dist/bootstrap.js +113 -37
  16. package/dist/change-set.d.ts +7 -2
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +54 -16
  19. package/dist/change.d.ts +15 -0
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js +26 -1
  22. package/dist/chat/acts.d.ts +33 -0
  23. package/dist/chat/acts.d.ts.map +1 -0
  24. package/dist/chat/acts.js +36 -0
  25. package/dist/chat/context.d.ts +3 -0
  26. package/dist/chat/context.d.ts.map +1 -0
  27. package/dist/chat/context.js +10 -0
  28. package/dist/chat/earlier.d.ts +10 -0
  29. package/dist/chat/earlier.d.ts.map +1 -0
  30. package/dist/chat/earlier.js +54 -0
  31. package/dist/chat/input.d.ts +9 -0
  32. package/dist/chat/input.d.ts.map +1 -0
  33. package/dist/chat/input.js +99 -0
  34. package/dist/chat/kit.d.ts +61 -0
  35. package/dist/chat/kit.d.ts.map +1 -0
  36. package/dist/chat/kit.js +123 -0
  37. package/dist/chat/lasting.d.ts +6 -0
  38. package/dist/chat/lasting.d.ts.map +1 -0
  39. package/dist/chat/lasting.js +19 -0
  40. package/dist/chat/list.d.ts +27 -0
  41. package/dist/chat/list.d.ts.map +1 -0
  42. package/dist/chat/list.js +99 -0
  43. package/dist/chat/markdown.d.ts +21 -0
  44. package/dist/chat/markdown.d.ts.map +1 -0
  45. package/dist/chat/markdown.js +246 -0
  46. package/dist/chat/message.d.ts +6 -0
  47. package/dist/chat/message.d.ts.map +1 -0
  48. package/dist/chat/message.js +192 -0
  49. package/dist/chat/messages.d.ts +22 -0
  50. package/dist/chat/messages.d.ts.map +1 -0
  51. package/dist/chat/messages.js +171 -0
  52. package/dist/chat/name.d.ts +6 -0
  53. package/dist/chat/name.d.ts.map +1 -0
  54. package/dist/chat/name.js +37 -0
  55. package/dist/chat/opened.d.ts +11 -0
  56. package/dist/chat/opened.d.ts.map +1 -0
  57. package/dist/chat/opened.js +17 -0
  58. package/dist/chat/overlay.d.ts +31 -0
  59. package/dist/chat/overlay.d.ts.map +1 -0
  60. package/dist/chat/overlay.js +97 -0
  61. package/dist/chat/parts.d.ts +57 -0
  62. package/dist/chat/parts.d.ts.map +1 -0
  63. package/dist/chat/parts.js +119 -0
  64. package/dist/chat/pieces.d.ts +62 -0
  65. package/dist/chat/pieces.d.ts.map +1 -0
  66. package/dist/chat/pieces.js +1110 -0
  67. package/dist/chat/process.d.ts +20 -0
  68. package/dist/chat/process.d.ts.map +1 -0
  69. package/dist/chat/process.js +32 -0
  70. package/dist/chat/provider.d.ts +63 -0
  71. package/dist/chat/provider.d.ts.map +1 -0
  72. package/dist/chat/provider.js +630 -0
  73. package/dist/chat/question.d.ts +9 -0
  74. package/dist/chat/question.d.ts.map +1 -0
  75. package/dist/chat/question.js +69 -0
  76. package/dist/chat/questions.d.ts +31 -0
  77. package/dist/chat/questions.d.ts.map +1 -0
  78. package/dist/chat/questions.js +111 -0
  79. package/dist/chat/read.d.ts +5 -0
  80. package/dist/chat/read.d.ts.map +1 -0
  81. package/dist/chat/read.js +13 -0
  82. package/dist/chat/ready.d.ts +34 -0
  83. package/dist/chat/ready.d.ts.map +1 -0
  84. package/dist/chat/ready.js +91 -0
  85. package/dist/chat/steady.d.ts +3 -0
  86. package/dist/chat/steady.d.ts.map +1 -0
  87. package/dist/chat/steady.js +26 -0
  88. package/dist/chat/style.d.ts +4 -0
  89. package/dist/chat/style.d.ts.map +1 -0
  90. package/dist/chat/style.js +302 -0
  91. package/dist/chat.d.ts +14 -0
  92. package/dist/chat.d.ts.map +1 -0
  93. package/dist/chat.js +8 -0
  94. package/dist/client.d.ts +30 -13
  95. package/dist/client.d.ts.map +1 -1
  96. package/dist/client.js +79 -16
  97. package/dist/collection.d.ts +23 -13
  98. package/dist/collection.d.ts.map +1 -1
  99. package/dist/collection.js +349 -36
  100. package/dist/connection.d.ts +50 -16
  101. package/dist/connection.d.ts.map +1 -1
  102. package/dist/connection.js +1968 -424
  103. package/dist/conversation.d.ts +31 -10
  104. package/dist/conversation.d.ts.map +1 -1
  105. package/dist/conversation.js +521 -170
  106. package/dist/durability.d.ts +7 -1
  107. package/dist/durability.d.ts.map +1 -1
  108. package/dist/entry.d.ts +17 -0
  109. package/dist/entry.d.ts.map +1 -0
  110. package/dist/entry.js +157 -0
  111. package/dist/expectation.d.ts +21 -0
  112. package/dist/expectation.d.ts.map +1 -0
  113. package/dist/expectation.js +70 -0
  114. package/dist/failure.d.ts +13 -0
  115. package/dist/failure.d.ts.map +1 -0
  116. package/dist/failure.js +19 -0
  117. package/dist/fence.d.ts +6 -0
  118. package/dist/fence.d.ts.map +1 -0
  119. package/dist/fence.js +10 -0
  120. package/dist/host.d.ts +15 -2
  121. package/dist/host.d.ts.map +1 -1
  122. package/dist/host.js +102 -19
  123. package/dist/identity.d.ts +5 -0
  124. package/dist/identity.d.ts.map +1 -1
  125. package/dist/identity.js +19 -1
  126. package/dist/index.d.ts +16 -8
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +5 -0
  129. package/dist/memory.d.ts +11 -4
  130. package/dist/memory.d.ts.map +1 -1
  131. package/dist/memory.js +91 -24
  132. package/dist/model.d.ts +14 -4
  133. package/dist/model.d.ts.map +1 -1
  134. package/dist/model.js +12 -1
  135. package/dist/observation.d.ts +7 -2
  136. package/dist/observation.d.ts.map +1 -1
  137. package/dist/observation.js +29 -12
  138. package/dist/open.d.ts +2 -0
  139. package/dist/open.d.ts.map +1 -0
  140. package/dist/open.js +1 -0
  141. package/dist/outcome.d.ts +38 -3
  142. package/dist/outcome.d.ts.map +1 -1
  143. package/dist/outcome.js +45 -1
  144. package/dist/overlay.d.ts +18 -5
  145. package/dist/overlay.d.ts.map +1 -1
  146. package/dist/overlay.js +247 -165
  147. package/dist/query.d.ts +60 -4
  148. package/dist/query.d.ts.map +1 -1
  149. package/dist/query.js +41 -38
  150. package/dist/reach.d.ts +8 -3
  151. package/dist/reach.d.ts.map +1 -1
  152. package/dist/reach.js +73 -24
  153. package/dist/react.d.ts +31 -20
  154. package/dist/react.d.ts.map +1 -1
  155. package/dist/react.js +13 -21
  156. package/dist/read-side.d.ts +16 -7
  157. package/dist/read-side.d.ts.map +1 -1
  158. package/dist/read-side.js +495 -102
  159. package/dist/readiness.d.ts +53 -0
  160. package/dist/readiness.d.ts.map +1 -0
  161. package/dist/readiness.js +33 -0
  162. package/dist/reads.d.ts +11 -0
  163. package/dist/reads.d.ts.map +1 -0
  164. package/dist/reads.js +98 -0
  165. package/dist/recovery.d.ts +25 -0
  166. package/dist/recovery.d.ts.map +1 -0
  167. package/dist/recovery.js +197 -0
  168. package/dist/refresh.d.ts +13 -3
  169. package/dist/refresh.d.ts.map +1 -1
  170. package/dist/refresh.js +72 -42
  171. package/dist/replica.d.ts +17 -8
  172. package/dist/replica.d.ts.map +1 -1
  173. package/dist/replica.js +165 -79
  174. package/dist/room-draft.d.ts +38 -9
  175. package/dist/room-draft.d.ts.map +1 -1
  176. package/dist/room-draft.js +141 -33
  177. package/dist/rows.d.ts +10 -13
  178. package/dist/rows.d.ts.map +1 -1
  179. package/dist/rows.js +19 -14
  180. package/dist/save.d.ts +35 -3
  181. package/dist/save.d.ts.map +1 -1
  182. package/dist/save.js +522 -107
  183. package/dist/search.d.ts +52 -8
  184. package/dist/search.d.ts.map +1 -1
  185. package/dist/search.js +192 -47
  186. package/dist/seed.d.ts +16 -0
  187. package/dist/seed.d.ts.map +1 -0
  188. package/dist/seed.js +75 -0
  189. package/dist/shared.d.ts +15 -0
  190. package/dist/shared.d.ts.map +1 -0
  191. package/dist/shared.js +398 -0
  192. package/dist/status.d.ts +6 -2
  193. package/dist/status.d.ts.map +1 -1
  194. package/dist/status.js +0 -8
  195. package/dist/store.d.ts +91 -18
  196. package/dist/store.d.ts.map +1 -1
  197. package/dist/store.js +704 -283
  198. package/dist/turn.d.ts +9 -0
  199. package/dist/turn.d.ts.map +1 -0
  200. package/dist/turn.js +64 -0
  201. package/dist/windows.d.ts +26 -0
  202. package/dist/windows.d.ts.map +1 -0
  203. package/dist/windows.js +93 -0
  204. package/dist/wire.d.ts +157 -33
  205. package/dist/wire.d.ts.map +1 -1
  206. package/dist/wire.js +65 -31
  207. package/package.json +26 -14
  208. package/dist/attachment.d.ts +0 -3
  209. package/dist/attachment.d.ts.map +0 -1
  210. 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,49 +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;
80
- const parsed = parse(text, change.path);
88
+ return changes.length;
89
+ const parsed = parse(text, path);
81
90
  if (!parsed.ok)
82
- return;
83
- const next = edited(parsed.document, change, priors);
84
- if (next?.outcome === 'applied')
85
- staged.documents[change.path] = serialize(next.document);
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;
86
107
  }
87
108
  function relocate(staged, from, to) {
88
109
  const text = staged.documents[from];
@@ -90,194 +111,255 @@ function relocate(staged, from, to) {
90
111
  delete staged.documents[from];
91
112
  staged.documents[to] = text;
92
113
  }
93
- else if (staged.binaryTargets.delete(from)) {
94
- staged.binaryTargets.add(to);
114
+ else if (staged.binaries[from] !== undefined) {
115
+ staged.binaries[to] = staged.binaries[from];
116
+ delete staged.binaries[from];
95
117
  }
96
118
  else {
97
- return;
119
+ return false;
98
120
  }
99
121
  moveHead(staged, from, to);
122
+ return true;
100
123
  }
101
124
  function moveHead(heads, from, to) {
102
125
  const revision = heads.revisions[from];
126
+ const fileId = heads.fileIds[from];
103
127
  const change = heads.changes[from];
104
128
  delete heads.revisions[from];
129
+ delete heads.fileIds[from];
105
130
  delete heads.changes[from];
131
+ delete heads.fileIds[to];
106
132
  delete heads.changes[to];
107
133
  if (revision !== undefined)
108
134
  heads.revisions[to] = revision;
135
+ if (fileId !== undefined)
136
+ heads.fileIds[to] = fileId;
109
137
  if (change !== undefined)
110
138
  heads.changes[to] = change;
111
139
  }
112
140
  function erase(staged, path) {
113
141
  delete staged.documents[path];
114
142
  delete staged.revisions[path];
143
+ delete staged.fileIds[path];
115
144
  delete staged.changes[path];
116
- staged.binaryTargets.delete(path);
145
+ delete staged.binaries[path];
117
146
  }
118
- function stage(staged, change, priors) {
119
- if (change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble') {
120
- edit(staged, change, priors);
121
- return;
122
- }
147
+ function stage(staged, change) {
123
148
  if (change.kind === 'create') {
124
149
  staged.documents[change.path] =
125
150
  'content' in change ? change.content : compose(change.fields, change.sections);
151
+ delete staged.fileIds[change.path];
126
152
  delete staged.changes[change.path];
127
- return;
153
+ return true;
128
154
  }
129
155
  if (change.kind === 'replace') {
156
+ delete staged.revisions[change.path];
130
157
  if (staged.documents[change.path] === undefined)
131
- return;
158
+ return false;
132
159
  staged.documents[change.path] = change.content;
133
- return;
160
+ return true;
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;
134
175
  }
135
176
  if (change.kind === 'move') {
136
- relocate(staged, change.path, change.to);
137
- return;
177
+ return relocate(staged, change.path, change.to);
138
178
  }
139
179
  erase(staged, change.path);
180
+ return true;
140
181
  }
141
- export function overlay(base, queue) {
182
+ export function* overlaying(base, queue, unapplied) {
142
183
  const staged = {
143
- documents: { ...base.documents },
144
- binaryTargets: new Set(base.binaryTargets),
145
- revisions: { ...base.revisions },
146
- 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),
147
189
  };
148
190
  for (const batch of queue) {
149
- const priors = priorsOf(batch.preconditions);
150
- for (const change of batch.changes)
151
- 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)
210
+ unapplied?.();
211
+ yield ROW_WEIGHT + text.length;
212
+ }
152
213
  }
153
214
  return {
154
- documents: staged.documents,
155
- binaryTargets: [...staged.binaryTargets].sort(),
156
- revisions: staged.revisions,
157
- 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),
158
220
  };
159
221
  }
160
- function pathsOf(batch) {
161
- 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;
162
231
  }
163
- export function sameLayerText(left, right) {
164
- const paths = Object.keys(left.documents);
165
- return (paths.length === Object.keys(right.documents).length &&
166
- paths.every((path) => left.documents[path] === right.documents[path]) &&
167
- left.binaryTargets.length === right.binaryTargets.length &&
168
- 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);
169
235
  }
170
- function replayHeads(base, queue) {
171
- const heads = { revisions: { ...base.revisions }, changes: { ...base.changes } };
172
- for (const batch of queue) {
173
- for (const change of batch.changes) {
174
- if (change.kind === 'remove') {
175
- delete heads.revisions[change.path];
176
- delete heads.changes[change.path];
177
- }
178
- else if (change.kind === 'create') {
179
- delete heads.changes[change.path];
180
- }
181
- else if (change.kind === 'move') {
182
- moveHead(heads, change.path, change.to);
183
- }
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];
184
276
  }
277
+ else if (change.kind === 'create') {
278
+ delete heads.fileIds[change.path];
279
+ delete heads.changes[change.path];
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;
185
295
  }
186
- return heads;
296
+ return {
297
+ revisions: yield* settling(heads.revisions),
298
+ fileIds: yield* settling(heads.fileIds),
299
+ changes: yield* settling(heads.changes),
300
+ };
187
301
  }
188
- export function overlayChanged(base, queue, previousBase, previousQueue, previousVisible) {
189
- const before = previousQueue.map((batch) => JSON.stringify(batch));
190
- const after = queue.map((batch) => JSON.stringify(batch));
191
- if (before.length === after.length &&
192
- before.every((id, index) => id === after[index]) &&
193
- sameLayerText(base, previousBase)) {
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);
314
+ }
315
+ export function* overlayChanged(base, batch, previousBase, previousBatch, previousVisible) {
316
+ const same = yield* sameBatch(batch, previousBatch);
317
+ if (same && (yield* sameText(base, previousBase))) {
194
318
  return {
195
319
  documents: previousVisible.documents,
196
- binaryTargets: previousVisible.binaryTargets,
197
- ...replayHeads(base, queue),
320
+ binaries: previousVisible.binaries,
321
+ ...(yield* replayHeads(base, batch)),
198
322
  };
199
323
  }
200
- const affected = new Set();
201
- const paths = new Set([
202
- ...Object.keys(base.documents),
203
- ...Object.keys(previousBase.documents),
204
- ...Object.keys(base.revisions),
205
- ...Object.keys(previousBase.revisions),
206
- ...Object.keys(base.changes),
207
- ...Object.keys(previousBase.changes),
208
- ...base.binaryTargets,
209
- ...previousBase.binaryTargets,
210
- ]);
211
- for (const path of paths) {
212
- if (base.documents[path] !== previousBase.documents[path] ||
213
- base.revisions[path] !== previousBase.revisions[path] ||
214
- !sameChange(base.changes[path], previousBase.changes[path]) ||
215
- 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))
216
329
  affected.add(path);
330
+ for (const path of touched) {
331
+ if (affected.has(path))
332
+ replayed = true;
333
+ yield ROW_WEIGHT;
217
334
  }
218
- const oldIds = new Set(before);
219
- const newIds = new Set(after);
220
- for (const batch of previousQueue) {
221
- if (!newIds.has(JSON.stringify(batch)))
222
- for (const path of pathsOf(batch))
223
- affected.add(path);
224
- }
225
- for (const batch of queue) {
226
- if (!oldIds.has(JSON.stringify(batch)))
227
- for (const path of pathsOf(batch))
228
- affected.add(path);
229
- }
230
- let expanded = true;
231
- while (expanded) {
232
- expanded = false;
233
- for (const batch of queue) {
234
- const touched = pathsOf(batch);
235
- if (!touched.some((path) => affected.has(path)))
236
- continue;
237
- for (const path of touched) {
238
- if (affected.has(path))
239
- continue;
240
- affected.add(path);
241
- expanded = true;
242
- }
243
- }
244
- }
245
- const documents = {};
246
- const revisions = {};
247
- const changes = {};
248
- 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);
249
344
  if (base.documents[path] !== undefined)
250
- documents[path] = base.documents[path];
345
+ restricted.documents[path] = base.documents[path];
251
346
  if (base.revisions[path] !== undefined)
252
- 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];
253
350
  if (base.changes[path] !== undefined)
254
- changes[path] = base.changes[path];
255
- }
256
- const staged = overlay({
257
- documents,
258
- revisions,
259
- changes,
260
- binaryTargets: base.binaryTargets.filter((path) => affected.has(path)),
261
- }, queue.filter((batch) => pathsOf(batch).some((path) => affected.has(path))));
262
- const mergedDocuments = { ...previousVisible.documents };
263
- const mergedRevisions = { ...previousVisible.revisions };
264
- const mergedChanges = { ...previousVisible.changes };
265
- const mergedTargets = new Set(previousVisible.binaryTargets);
266
- for (const path of affected) {
267
- delete mergedDocuments[path];
268
- delete mergedRevisions[path];
269
- delete mergedChanges[path];
270
- 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;
271
355
  }
272
- Object.assign(mergedDocuments, staged.documents);
273
- Object.assign(mergedRevisions, staged.revisions);
274
- Object.assign(mergedChanges, staged.changes);
275
- for (const path of staged.binaryTargets)
276
- mergedTargets.add(path);
356
+ const staged = replayed ? yield* overlaying(restricted, [batch]) : base;
357
+ const from = (path) => (touched.has(path) ? staged : base);
277
358
  return {
278
- documents: mergedDocuments,
279
- revisions: mergedRevisions,
280
- changes: mergedChanges,
281
- 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]),
282
364
  };
283
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,17 +252,23 @@ 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 {
259
+ readonly code: QueryErrorCode;
260
+ readonly retryable = false;
207
261
  constructor(code: QueryErrorCode, at: string, problem: string);
208
262
  }
209
263
  type Entries = Readonly<Record<string, unknown>>;
210
264
  export declare function invalid(at: string, problem: string): never;
211
265
  export declare function plain(value: unknown): value is Entries;
212
266
  export declare function known(value: Entries, allowed: readonly string[], at: string): void;
267
+ export declare function flag(input: unknown, at: string): boolean;
213
268
  export declare function planOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
214
269
  export declare function limitOf(input: unknown): number | null;
215
270
  export declare function filterOf(input: unknown, facts: HeldRooms, reach?: PlanReach | null): Plan;
271
+ export declare function queryKey(query: unknown): string;
216
272
  export declare function identityOf(plan: Plan): string;
217
273
  export {};
218
274
  //# sourceMappingURL=query.d.ts.map