@agentshouse/mdruntime 0.1.0-c967d1ca66fee → 0.1.0-c97456d63baba
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.
- package/AGENTS.md +257 -227
- package/README.md +11 -1
- package/dist/acquisition.d.ts +14 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +24 -0
- package/dist/adapter.d.ts +69 -20
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attempt.d.ts +16 -0
- package/dist/attempt.d.ts.map +1 -0
- package/dist/attempt.js +70 -0
- package/dist/binary.d.ts +23 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +2 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +33 -14
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +39 -13
- package/dist/change.d.ts +11 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +26 -1
- package/dist/chat/acts.d.ts +33 -0
- package/dist/chat/acts.d.ts.map +1 -0
- package/dist/chat/acts.js +36 -0
- package/dist/chat/context.d.ts +3 -0
- package/dist/chat/context.d.ts.map +1 -0
- package/dist/chat/context.js +10 -0
- package/dist/chat/input.d.ts +9 -0
- package/dist/chat/input.d.ts.map +1 -0
- package/dist/chat/input.js +99 -0
- package/dist/chat/kit.d.ts +61 -0
- package/dist/chat/kit.d.ts.map +1 -0
- package/dist/chat/kit.js +123 -0
- package/dist/chat/lasting.d.ts +6 -0
- package/dist/chat/lasting.d.ts.map +1 -0
- package/dist/chat/lasting.js +19 -0
- package/dist/chat/list.d.ts +27 -0
- package/dist/chat/list.d.ts.map +1 -0
- package/dist/chat/list.js +63 -0
- package/dist/chat/markdown.d.ts +20 -0
- package/dist/chat/markdown.d.ts.map +1 -0
- package/dist/chat/markdown.js +188 -0
- package/dist/chat/message.d.ts +6 -0
- package/dist/chat/message.d.ts.map +1 -0
- package/dist/chat/message.js +192 -0
- package/dist/chat/messages.d.ts +22 -0
- package/dist/chat/messages.d.ts.map +1 -0
- package/dist/chat/messages.js +155 -0
- package/dist/chat/name.d.ts +6 -0
- package/dist/chat/name.d.ts.map +1 -0
- package/dist/chat/name.js +37 -0
- package/dist/chat/opened.d.ts +11 -0
- package/dist/chat/opened.d.ts.map +1 -0
- package/dist/chat/opened.js +17 -0
- package/dist/chat/overlay.d.ts +31 -0
- package/dist/chat/overlay.d.ts.map +1 -0
- package/dist/chat/overlay.js +97 -0
- package/dist/chat/parts.d.ts +57 -0
- package/dist/chat/parts.d.ts.map +1 -0
- package/dist/chat/parts.js +119 -0
- package/dist/chat/process.d.ts +20 -0
- package/dist/chat/process.d.ts.map +1 -0
- package/dist/chat/process.js +32 -0
- package/dist/chat/provider.d.ts +63 -0
- package/dist/chat/provider.d.ts.map +1 -0
- package/dist/chat/provider.js +629 -0
- package/dist/chat/question.d.ts +9 -0
- package/dist/chat/question.d.ts.map +1 -0
- package/dist/chat/question.js +80 -0
- package/dist/chat/questions.d.ts +31 -0
- package/dist/chat/questions.d.ts.map +1 -0
- package/dist/chat/questions.js +111 -0
- package/dist/chat/read.d.ts +5 -0
- package/dist/chat/read.d.ts.map +1 -0
- package/dist/chat/read.js +13 -0
- package/dist/chat/ready.d.ts +34 -0
- package/dist/chat/ready.d.ts.map +1 -0
- package/dist/chat/ready.js +91 -0
- package/dist/chat/style.d.ts +4 -0
- package/dist/chat/style.d.ts.map +1 -0
- package/dist/chat/style.js +302 -0
- package/dist/chat.d.ts +14 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +8 -0
- package/dist/client.d.ts +21 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +14 -2
- package/dist/collection.d.ts +17 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +230 -19
- package/dist/connection.d.ts +32 -12
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1482 -351
- package/dist/conversation.d.ts +23 -9
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +372 -142
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +17 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +156 -0
- package/dist/expectation.d.ts +21 -0
- package/dist/expectation.d.ts.map +1 -0
- package/dist/expectation.js +70 -0
- package/dist/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/host.d.ts +13 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +48 -11
- package/dist/identity.d.ts +4 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +12 -0
- package/dist/index.d.ts +13 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/memory.d.ts +5 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +47 -13
- package/dist/model.d.ts +4 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -1
- package/dist/observation.d.ts +5 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +22 -11
- package/dist/outcome.d.ts +11 -1
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +7 -0
- package/dist/overlay.d.ts +14 -2
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +75 -62
- package/dist/query.d.ts +31 -3
- package/dist/query.d.ts.map +1 -1
- package/dist/reach.d.ts +8 -2
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +42 -8
- package/dist/react.d.ts +7 -4
- package/dist/react.d.ts.map +1 -1
- package/dist/read-side.d.ts +13 -6
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +291 -85
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +197 -0
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +21 -25
- package/dist/replica.d.ts +6 -3
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +78 -45
- package/dist/room-draft.d.ts +20 -3
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +119 -1
- package/dist/rows.d.ts +6 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +5 -13
- package/dist/save.d.ts +28 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +343 -29
- package/dist/search.d.ts +28 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +108 -45
- package/dist/shared.d.ts +11 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +368 -0
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +55 -21
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +424 -206
- package/dist/turn.d.ts +7 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +45 -0
- package/dist/wire.d.ts +137 -30
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +49 -29
- package/package.json +26 -14
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
package/dist/save.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { definitionOf } from './model.js';
|
|
2
2
|
import { apply, ATTACHMENT, links, parse, pointerSegments, references, relative, relativize, retarget, serialize, target, } from '@agentshouse/mdmodel';
|
|
3
|
-
import { immutable, } from './change.js';
|
|
4
|
-
import { collectionOf, documentsOf, governing, validateCollection, } from './collection.js';
|
|
3
|
+
import { immutable, queuedFile, departure, } from './change.js';
|
|
4
|
+
import { available, changedCleanly, collectionOf, documentsOf, governing, referring, validateCollection, } from './collection.js';
|
|
5
5
|
import { changeBatchIdentity } from './identity.js';
|
|
6
6
|
import { overlay } from './overlay.js';
|
|
7
7
|
import { covered, normalize } from './paths.js';
|
|
@@ -122,7 +122,10 @@ function rewrites(changes, visible) {
|
|
|
122
122
|
for (const change of changes) {
|
|
123
123
|
if (change.kind === 'move')
|
|
124
124
|
moves.set(change.path, change.to);
|
|
125
|
-
if (change.kind === 'remove' ||
|
|
125
|
+
if (change.kind === 'remove' ||
|
|
126
|
+
change.kind === 'replace' ||
|
|
127
|
+
change.kind === 'create' ||
|
|
128
|
+
change.kind === 'binary') {
|
|
126
129
|
settled.add(change.path);
|
|
127
130
|
}
|
|
128
131
|
if (change.kind === 'field')
|
|
@@ -174,7 +177,7 @@ export function providerRewritten(batch, visible) {
|
|
|
174
177
|
...anticipated(batch.changes, batch.preconditions, rewritten.changes, visible),
|
|
175
178
|
};
|
|
176
179
|
}
|
|
177
|
-
function incoming(collection, removed) {
|
|
180
|
+
function incoming(collection, removed, candidates) {
|
|
178
181
|
const found = new Map();
|
|
179
182
|
const note = (target, file) => {
|
|
180
183
|
if (!removed.has(target))
|
|
@@ -183,7 +186,13 @@ function incoming(collection, removed) {
|
|
|
183
186
|
referrers.add(file);
|
|
184
187
|
found.set(target, referrers);
|
|
185
188
|
};
|
|
186
|
-
|
|
189
|
+
const read = candidates === null
|
|
190
|
+
? documentsOf(collection)
|
|
191
|
+
: [...new Set(candidates)].sort().flatMap((path) => {
|
|
192
|
+
const document = collection.document(path);
|
|
193
|
+
return document === undefined ? [] : [[path, document]];
|
|
194
|
+
});
|
|
195
|
+
for (const [path, document] of read) {
|
|
187
196
|
const definition = definitionOf(governing(collection.composition, path), document.type);
|
|
188
197
|
for (const { value, to } of definition === undefined ? [] : references(document, definition)) {
|
|
189
198
|
if (to.includes(ATTACHMENT))
|
|
@@ -214,11 +223,14 @@ function affected(change) {
|
|
|
214
223
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
215
224
|
}
|
|
216
225
|
function guard(changes, input) {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
const overridden = new Map();
|
|
227
|
+
const existing = {
|
|
228
|
+
has: (path) => overridden.get(path) ??
|
|
229
|
+
(Object.hasOwn(input.visible.documents, path) || Object.hasOwn(input.visible.binaries, path)),
|
|
230
|
+
add: (path) => void overridden.set(path, true),
|
|
231
|
+
delete: (path) => void overridden.set(path, false),
|
|
232
|
+
};
|
|
233
|
+
for (const [index, change] of changes.entries()) {
|
|
222
234
|
for (const path of affected(change)) {
|
|
223
235
|
const normalized = normalize(path);
|
|
224
236
|
if (normalized === null || normalized === '')
|
|
@@ -236,12 +248,26 @@ function guard(changes, input) {
|
|
|
236
248
|
existing.add(change.path);
|
|
237
249
|
continue;
|
|
238
250
|
}
|
|
251
|
+
if (change.kind === 'binary') {
|
|
252
|
+
if (input.visible.documents[change.path] !== undefined ||
|
|
253
|
+
(existing.has(change.path) &&
|
|
254
|
+
input.bases.some((base) => base.kind === 'absent' && base.path === change.path))) {
|
|
255
|
+
return refuse('path-collision', change.path);
|
|
256
|
+
}
|
|
257
|
+
if (!input.local &&
|
|
258
|
+
existing.has(change.path) &&
|
|
259
|
+
input.visible.revisions[departure(changes, index)] === undefined) {
|
|
260
|
+
return refuse('unknown-revision', change.path);
|
|
261
|
+
}
|
|
262
|
+
existing.add(change.path);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
239
265
|
if (change.kind === 'move') {
|
|
240
266
|
if (!existing.has(change.path))
|
|
241
267
|
return refuse('path-absent', change.path);
|
|
242
268
|
if (existing.has(change.to))
|
|
243
269
|
return refuse('path-collision', change.to);
|
|
244
|
-
if (
|
|
270
|
+
if (unrevised(input, change.path)) {
|
|
245
271
|
return refuse('unknown-revision', change.path);
|
|
246
272
|
}
|
|
247
273
|
existing.delete(change.path);
|
|
@@ -251,7 +277,7 @@ function guard(changes, input) {
|
|
|
251
277
|
if (!existing.has(change.path))
|
|
252
278
|
return refuse('path-absent', change.path);
|
|
253
279
|
if (change.kind === 'remove') {
|
|
254
|
-
if (
|
|
280
|
+
if (unrevised(input, change.path)) {
|
|
255
281
|
return refuse('unknown-revision', change.path);
|
|
256
282
|
}
|
|
257
283
|
existing.delete(change.path);
|
|
@@ -269,8 +295,12 @@ function guard(changes, input) {
|
|
|
269
295
|
}
|
|
270
296
|
return null;
|
|
271
297
|
}
|
|
272
|
-
function
|
|
273
|
-
return visible.revisions[path] === undefined
|
|
298
|
+
function unrevised(input, path) {
|
|
299
|
+
return (!input.local && input.queued?.has(path) !== true && input.visible.revisions[path] === undefined);
|
|
300
|
+
}
|
|
301
|
+
function identity(precondition) {
|
|
302
|
+
const part = precondition.kind === 'field' || precondition.kind === 'section' ? precondition.name : '';
|
|
303
|
+
return `${precondition.kind} ${precondition.path} ${part}`;
|
|
274
304
|
}
|
|
275
305
|
function existence(visible, path) {
|
|
276
306
|
const revision = visible.revisions[path];
|
|
@@ -289,11 +319,10 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
289
319
|
const preconditions = [];
|
|
290
320
|
const seen = new Set();
|
|
291
321
|
const add = (precondition) => {
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
if (seen.has(identity))
|
|
322
|
+
const held = identity(precondition);
|
|
323
|
+
if (seen.has(held))
|
|
295
324
|
return;
|
|
296
|
-
seen.add(
|
|
325
|
+
seen.add(held);
|
|
297
326
|
preconditions.push(precondition);
|
|
298
327
|
};
|
|
299
328
|
for (const change of changes) {
|
|
@@ -328,6 +357,13 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
328
357
|
add({ kind: 'absent', path: change.path });
|
|
329
358
|
continue;
|
|
330
359
|
}
|
|
360
|
+
if (change.kind === 'binary') {
|
|
361
|
+
const revision = visible.revisions[change.path];
|
|
362
|
+
add(visible.binaries[change.path] === undefined || revision === undefined
|
|
363
|
+
? { kind: 'absent', path: change.path }
|
|
364
|
+
: { kind: 'revision', path: change.path, revision });
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
331
367
|
add(existence(visible, change.path));
|
|
332
368
|
if (change.kind === 'move')
|
|
333
369
|
add({ kind: 'absent', path: change.to });
|
|
@@ -337,10 +373,10 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
337
373
|
function depth(path) {
|
|
338
374
|
return path.split('/').length;
|
|
339
375
|
}
|
|
340
|
-
function exceeded(limits, changes, resulting) {
|
|
341
|
-
const written =
|
|
376
|
+
function exceeded(limits, changes, effective, resulting) {
|
|
377
|
+
const written = effective.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
342
378
|
const created = changes
|
|
343
|
-
.filter((change) => change.kind === 'create' || change.kind === 'move')
|
|
379
|
+
.filter((change) => change.kind === 'create' || change.kind === 'move' || change.kind === 'binary')
|
|
344
380
|
.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
345
381
|
for (const limit of limits) {
|
|
346
382
|
const value = limit.value;
|
|
@@ -354,7 +390,7 @@ function exceeded(limits, changes, resulting) {
|
|
|
354
390
|
return refuse('provider-limit', undefined, limit.name);
|
|
355
391
|
}
|
|
356
392
|
if (limit.name === 'document-size') {
|
|
357
|
-
const large = written.find((path) => (resulting.documents[path] ?? '').
|
|
393
|
+
const large = written.find((path) => new TextEncoder().encode(resulting.documents[path] ?? '').byteLength > value);
|
|
358
394
|
if (large !== undefined)
|
|
359
395
|
return refuse('provider-limit', large, limit.name);
|
|
360
396
|
}
|
|
@@ -423,6 +459,8 @@ function relativeChanges(input) {
|
|
|
423
459
|
});
|
|
424
460
|
}
|
|
425
461
|
function unmodeledType(collection, composition) {
|
|
462
|
+
if (available(composition))
|
|
463
|
+
return false;
|
|
426
464
|
for (const [path, document] of documentsOf(collection)) {
|
|
427
465
|
if (document.type !== undefined &&
|
|
428
466
|
document.type !== 'any' &&
|
|
@@ -431,6 +469,270 @@ function unmodeledType(collection, composition) {
|
|
|
431
469
|
}
|
|
432
470
|
return false;
|
|
433
471
|
}
|
|
472
|
+
function unqueueable(file) {
|
|
473
|
+
return { kind: 'refused', refusal: { code: 'unknown-revision', retryable: false, file } };
|
|
474
|
+
}
|
|
475
|
+
function isPart(change) {
|
|
476
|
+
return change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble';
|
|
477
|
+
}
|
|
478
|
+
function touched(change) {
|
|
479
|
+
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
480
|
+
}
|
|
481
|
+
function partApplied(content, path, change) {
|
|
482
|
+
const parsed = parse(content, path);
|
|
483
|
+
if (!parsed.ok)
|
|
484
|
+
return null;
|
|
485
|
+
const document = parsed.document;
|
|
486
|
+
const applied = apply(document, change.kind === 'field'
|
|
487
|
+
? {
|
|
488
|
+
kind: 'field',
|
|
489
|
+
name: change.name,
|
|
490
|
+
value: change.value,
|
|
491
|
+
prior: document.fields[change.name],
|
|
492
|
+
}
|
|
493
|
+
: change.kind === 'section'
|
|
494
|
+
? {
|
|
495
|
+
kind: 'section',
|
|
496
|
+
name: change.name,
|
|
497
|
+
value: change.value,
|
|
498
|
+
prior: document.sections[change.name],
|
|
499
|
+
}
|
|
500
|
+
: { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
501
|
+
return applied.outcome === 'applied' ? serialize(applied.document) : null;
|
|
502
|
+
}
|
|
503
|
+
function folded(changes, change, appending) {
|
|
504
|
+
const held = changes.find((item) => item.path === change.path && (item.kind === 'create' || item.kind === 'replace'));
|
|
505
|
+
const whole = held === undefined ? -1 : changes.indexOf(held);
|
|
506
|
+
const occupied = changes.some((item) => !isPart(item) && item !== held && touched(item).includes(change.path));
|
|
507
|
+
if (isPart(change)) {
|
|
508
|
+
const same = changes.findIndex((item) => item.kind === change.kind &&
|
|
509
|
+
item.path === change.path &&
|
|
510
|
+
(change.kind === 'preamble' || ('name' in item && item.name === change.name)));
|
|
511
|
+
if (same !== -1) {
|
|
512
|
+
changes[same] = change;
|
|
513
|
+
return 'folded';
|
|
514
|
+
}
|
|
515
|
+
if (held === undefined) {
|
|
516
|
+
if (!appending)
|
|
517
|
+
return 'skipped';
|
|
518
|
+
if (occupied)
|
|
519
|
+
return 'refused';
|
|
520
|
+
changes.push(change);
|
|
521
|
+
return 'appended';
|
|
522
|
+
}
|
|
523
|
+
if ('content' in held) {
|
|
524
|
+
const content = partApplied(held.content, held.path, change);
|
|
525
|
+
if (content === null)
|
|
526
|
+
return 'refused';
|
|
527
|
+
changes[whole] = { ...held, content };
|
|
528
|
+
return 'folded';
|
|
529
|
+
}
|
|
530
|
+
if (change.kind === 'preamble')
|
|
531
|
+
return 'refused';
|
|
532
|
+
changes[whole] =
|
|
533
|
+
change.kind === 'field'
|
|
534
|
+
? { ...held, fields: { ...held.fields, [change.name]: change.value } }
|
|
535
|
+
: { ...held, sections: { ...held.sections, [change.name]: change.value } };
|
|
536
|
+
return 'folded';
|
|
537
|
+
}
|
|
538
|
+
if (change.kind === 'replace') {
|
|
539
|
+
if (held !== undefined) {
|
|
540
|
+
if (!('content' in held))
|
|
541
|
+
return 'refused';
|
|
542
|
+
changes[whole] = { ...held, content: change.content };
|
|
543
|
+
return 'folded';
|
|
544
|
+
}
|
|
545
|
+
const parts = changes.filter((item) => isPart(item) && item.path === change.path);
|
|
546
|
+
if (parts.length === 0 && !appending)
|
|
547
|
+
return 'skipped';
|
|
548
|
+
if (occupied)
|
|
549
|
+
return 'refused';
|
|
550
|
+
changes.splice(0, changes.length, ...changes.filter((item) => !parts.includes(item)), change);
|
|
551
|
+
return 'appended';
|
|
552
|
+
}
|
|
553
|
+
if (changes.some((item) => touched(change).some((path) => touched(item).includes(path))))
|
|
554
|
+
return 'refused';
|
|
555
|
+
changes.push(change);
|
|
556
|
+
return 'appended';
|
|
557
|
+
}
|
|
558
|
+
function relinked(batch, move, before, after, appending) {
|
|
559
|
+
const derived = rewrites([move], after);
|
|
560
|
+
if (derived.kind === 'refused')
|
|
561
|
+
return derived;
|
|
562
|
+
const changes = [...batch.changes];
|
|
563
|
+
const appended = [];
|
|
564
|
+
let changed = false;
|
|
565
|
+
for (const change of derived.changes) {
|
|
566
|
+
if (change === move)
|
|
567
|
+
continue;
|
|
568
|
+
const outcome = folded(changes, change, appending);
|
|
569
|
+
if (outcome === 'refused')
|
|
570
|
+
return unqueueable(change.path);
|
|
571
|
+
if (outcome === 'appended')
|
|
572
|
+
appended.push(change);
|
|
573
|
+
if (outcome !== 'skipped')
|
|
574
|
+
changed = true;
|
|
575
|
+
}
|
|
576
|
+
if (!changed)
|
|
577
|
+
return { kind: 'relinked', batch };
|
|
578
|
+
const held = new Set(batch.preconditions.map(identity));
|
|
579
|
+
return {
|
|
580
|
+
kind: 'relinked',
|
|
581
|
+
batch: immutable({
|
|
582
|
+
...batch,
|
|
583
|
+
id: changeBatchIdentity(),
|
|
584
|
+
changes,
|
|
585
|
+
preconditions: [
|
|
586
|
+
...batch.preconditions,
|
|
587
|
+
...preconditionsOf(appended, before, []).filter((precondition) => !held.has(identity(precondition))),
|
|
588
|
+
],
|
|
589
|
+
}),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
function leading(changes, at) {
|
|
593
|
+
const from = departure(changes, at);
|
|
594
|
+
return new Set(changes.filter((change, index) => index < at && change.kind === 'move' && departure(changes, index) === from));
|
|
595
|
+
}
|
|
596
|
+
function created(batch, at) {
|
|
597
|
+
const file = batch.changes[at];
|
|
598
|
+
return (leading(batch.changes, at).size === 0 &&
|
|
599
|
+
batch.preconditions.some((precondition) => precondition.kind === 'absent' && precondition.path === file.path));
|
|
600
|
+
}
|
|
601
|
+
function withdrawnFile(batch, change, at) {
|
|
602
|
+
const file = batch.changes[at];
|
|
603
|
+
const from = departure(batch.changes, at);
|
|
604
|
+
const moves = leading(batch.changes, at);
|
|
605
|
+
const fresh = created(batch, at);
|
|
606
|
+
const vacated = new Set([...moves].map((move) => move.to));
|
|
607
|
+
if (fresh)
|
|
608
|
+
vacated.add(file.path);
|
|
609
|
+
const replaced = fresh
|
|
610
|
+
? change.kind === 'remove'
|
|
611
|
+
? []
|
|
612
|
+
: [{ ...file, path: change.to }]
|
|
613
|
+
: change.kind === 'remove'
|
|
614
|
+
? [{ kind: 'remove', path: from }]
|
|
615
|
+
: change.to === from
|
|
616
|
+
? [{ ...file, path: from }]
|
|
617
|
+
: [
|
|
618
|
+
{ kind: 'move', path: from, to: change.to },
|
|
619
|
+
{ ...file, path: change.to },
|
|
620
|
+
];
|
|
621
|
+
const added = change.kind === 'move' && (fresh || change.to !== from)
|
|
622
|
+
? [{ kind: 'absent', path: change.to }]
|
|
623
|
+
: [];
|
|
624
|
+
const changes = batch.changes.flatMap((item) => item === file ? replaced : item.kind === 'move' && moves.has(item) ? [] : [item]);
|
|
625
|
+
if (changes.length === 0)
|
|
626
|
+
return null;
|
|
627
|
+
const preconditions = [
|
|
628
|
+
...added,
|
|
629
|
+
...batch.preconditions.filter((precondition) => precondition.kind !== 'absent' || !vacated.has(precondition.path)),
|
|
630
|
+
];
|
|
631
|
+
return immutable({ ...batch, id: changeBatchIdentity(), changes, preconditions });
|
|
632
|
+
}
|
|
633
|
+
export function requeued(queue, changes, visible, changeable, state) {
|
|
634
|
+
const next = [...queue];
|
|
635
|
+
const origins = new Map();
|
|
636
|
+
const withdrawn = new Map();
|
|
637
|
+
const owners = new Set();
|
|
638
|
+
const queued = new Set();
|
|
639
|
+
const kept = [];
|
|
640
|
+
const originOf = (batch) => origins.get(batch) ?? batch.id;
|
|
641
|
+
const open = (batch) => origins.has(batch) || changeable(batch);
|
|
642
|
+
for (const change of changes) {
|
|
643
|
+
const held = visible.binaries[change.path];
|
|
644
|
+
if ((change.kind !== 'move' && change.kind !== 'remove') || held?.state !== 'pending') {
|
|
645
|
+
kept.push(change);
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
let index = next.length - 1;
|
|
649
|
+
while (index >= 0 && queuedFile(next[index], change.path, held.localId) === -1)
|
|
650
|
+
index -= 1;
|
|
651
|
+
const owner = next[index];
|
|
652
|
+
if (owner === undefined || !open(owner))
|
|
653
|
+
return unqueueable(change.path);
|
|
654
|
+
const following = next.slice(index);
|
|
655
|
+
const rebuilt = [];
|
|
656
|
+
let before = change.kind === 'move' ? state(next.slice(0, index)) : visible;
|
|
657
|
+
for (const [offset, batch] of following.entries()) {
|
|
658
|
+
let current = batch;
|
|
659
|
+
if (change.kind === 'move') {
|
|
660
|
+
const after = state(next.slice(0, index + offset + 1));
|
|
661
|
+
const appending = offset === 0 && created(batch, queuedFile(batch, change.path, held.localId));
|
|
662
|
+
const relinking = relinked(batch, change, before, after, appending);
|
|
663
|
+
if (relinking.kind === 'refused')
|
|
664
|
+
return relinking;
|
|
665
|
+
current = relinking.batch;
|
|
666
|
+
before = after;
|
|
667
|
+
}
|
|
668
|
+
if (current !== batch && !open(batch))
|
|
669
|
+
return unqueueable(change.path);
|
|
670
|
+
rebuilt.push(offset === 0
|
|
671
|
+
? withdrawnFile(current, change, queuedFile(current, change.path, held.localId))
|
|
672
|
+
: current);
|
|
673
|
+
}
|
|
674
|
+
for (const [offset, batch] of following.entries()) {
|
|
675
|
+
const replaced = rebuilt[offset];
|
|
676
|
+
if (replaced === batch)
|
|
677
|
+
continue;
|
|
678
|
+
const origin = originOf(batch);
|
|
679
|
+
withdrawn.set(origin, replaced);
|
|
680
|
+
if (replaced !== null)
|
|
681
|
+
origins.set(replaced, origin);
|
|
682
|
+
}
|
|
683
|
+
owners.add(originOf(owner));
|
|
684
|
+
next.splice(index, following.length, ...rebuilt.filter((batch) => batch !== null));
|
|
685
|
+
queued.add(change.path);
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
kind: 'requeued',
|
|
689
|
+
queue: withdrawn.size === 0 ? queue : next,
|
|
690
|
+
changes: kept,
|
|
691
|
+
queued,
|
|
692
|
+
withdrawn,
|
|
693
|
+
owners,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function covering(precondition) {
|
|
697
|
+
return precondition.kind === 'field' ||
|
|
698
|
+
precondition.kind === 'section' ||
|
|
699
|
+
precondition.kind === 'preamble'
|
|
700
|
+
? identity(precondition)
|
|
701
|
+
: `path ${precondition.path}`;
|
|
702
|
+
}
|
|
703
|
+
export function joined(queue, owner, extra) {
|
|
704
|
+
const later = new Set(queue.slice(queue.indexOf(owner) + 1).flatMap((batch) => batch.changes.flatMap(touched)));
|
|
705
|
+
const clash = extra.changes.flatMap(touched).find((path) => later.has(path));
|
|
706
|
+
if (clash !== undefined)
|
|
707
|
+
return unqueueable(clash);
|
|
708
|
+
const changes = [...owner.changes];
|
|
709
|
+
for (const change of extra.changes) {
|
|
710
|
+
if (folded(changes, change, true) === 'refused')
|
|
711
|
+
return unqueueable(change.path);
|
|
712
|
+
}
|
|
713
|
+
const held = new Set(owner.preconditions.map(covering));
|
|
714
|
+
const written = new Set(owner.changes.flatMap((change) => change.kind === 'create' || change.kind === 'replace' ? [change.path] : []));
|
|
715
|
+
const preconditions = [
|
|
716
|
+
...owner.preconditions,
|
|
717
|
+
...extra.preconditions.filter((precondition) => {
|
|
718
|
+
const key = covering(precondition);
|
|
719
|
+
return (!held.has(key) && (key === `path ${precondition.path}` || !written.has(precondition.path)));
|
|
720
|
+
}),
|
|
721
|
+
];
|
|
722
|
+
const batch = immutable({
|
|
723
|
+
...owner,
|
|
724
|
+
...(extra.validation === undefined ? {} : { validation: extra.validation }),
|
|
725
|
+
id: changeBatchIdentity(),
|
|
726
|
+
changes,
|
|
727
|
+
preconditions,
|
|
728
|
+
});
|
|
729
|
+
return { kind: 'joined', batch, queue: queue.map((item) => (item === owner ? batch : item)) };
|
|
730
|
+
}
|
|
731
|
+
export function limitedIn(queue, batch, limits, state) {
|
|
732
|
+
const at = queue.indexOf(batch);
|
|
733
|
+
const limited = exceeded(limits, batch.changes, providerRewritten(batch, state(queue.slice(0, at))).changes, state(queue.slice(0, at + 1)));
|
|
734
|
+
return limited?.kind === 'refused' ? limited.refusal : null;
|
|
735
|
+
}
|
|
434
736
|
export function buildBatch(input) {
|
|
435
737
|
const changes = relativeChanges(input);
|
|
436
738
|
const structural = changes.find((change) => change.kind === 'move' || change.kind === 'remove');
|
|
@@ -449,9 +751,16 @@ export function buildBatch(input) {
|
|
|
449
751
|
const resulting = overlay(input.visible, [
|
|
450
752
|
{ id: '', baseRoomVersion: input.baseRoomVersion, ...predicted },
|
|
451
753
|
]);
|
|
754
|
+
const clean = input.clean !== undefined &&
|
|
755
|
+
input.clean.text === input.visible.documents &&
|
|
756
|
+
input.clean.binaries === input.visible.binaries &&
|
|
757
|
+
available(input.composition)
|
|
758
|
+
? input.clean
|
|
759
|
+
: null;
|
|
452
760
|
const removed = new Set(changes.filter((change) => change.kind === 'remove').map((change) => change.path));
|
|
453
761
|
if (removed.size > 0) {
|
|
454
|
-
const
|
|
762
|
+
const referrers = clean === null ? null : referring(clean, input.composition, removed);
|
|
763
|
+
const referenced = incoming(collectionOf(resulting.documents, input.composition), removed, referrers === null ? null : [...referrers, ...predicted.changes.flatMap(affected)]);
|
|
455
764
|
if (referenced !== null)
|
|
456
765
|
return referenced;
|
|
457
766
|
}
|
|
@@ -461,15 +770,20 @@ export function buildBatch(input) {
|
|
|
461
770
|
const parsed = parse(content);
|
|
462
771
|
return parsed.ok && parsed.document.type !== undefined && parsed.document.type !== 'any';
|
|
463
772
|
};
|
|
464
|
-
const
|
|
773
|
+
const touched = [...new Set(predicted.changes.flatMap(affected))];
|
|
774
|
+
const typedPaths = touched.filter((path) => typed(input.visible.documents[path]) || typed(resulting.documents[path]));
|
|
465
775
|
const needsModel = typedPaths.length > 0;
|
|
466
776
|
const withoutModel = typedPaths.find((path) => governing(input.composition, path).status === 'unavailable');
|
|
467
777
|
if (withoutModel !== undefined)
|
|
468
778
|
return refuse('model-unavailable', withoutModel);
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
779
|
+
const verdict = clean !== null &&
|
|
780
|
+
changedCleanly({ text: resulting.documents, binaries: resulting.binaries }, clean, input.composition)
|
|
781
|
+
? { verdict: 'accept' }
|
|
782
|
+
: validateCollection(needsModel
|
|
783
|
+
? resulting.documents
|
|
784
|
+
: Object.fromEntries(touched.flatMap((path) => resulting.documents[path] === undefined
|
|
785
|
+
? []
|
|
786
|
+
: [[path, resulting.documents[path]]])), Object.keys(resulting.binaries), input.composition);
|
|
473
787
|
if (verdict.verdict === 'refuse') {
|
|
474
788
|
return {
|
|
475
789
|
kind: 'refused',
|
|
@@ -482,7 +796,7 @@ export function buildBatch(input) {
|
|
|
482
796
|
},
|
|
483
797
|
};
|
|
484
798
|
}
|
|
485
|
-
const limited = exceeded(input.providerLimits, changes, resulting);
|
|
799
|
+
const limited = exceeded(input.providerLimits, changes, predicted.changes, resulting);
|
|
486
800
|
if (limited !== null)
|
|
487
801
|
return limited;
|
|
488
802
|
const validated = typedPaths
|
package/dist/search.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChangeSet } from './change-set.js';
|
|
2
|
-
import { type Filter } from './query.js';
|
|
2
|
+
import { type CoveredRoom, type Filter, type PendingRoom } from './query.js';
|
|
3
3
|
import type { Open } from './open.js';
|
|
4
4
|
export type DocumentPart = Open<'fields' | 'sections' | 'preamble' | 'path'>;
|
|
5
5
|
export type SearchRequest = {
|
|
@@ -21,10 +21,26 @@ export type MessageHit = {
|
|
|
21
21
|
score: number;
|
|
22
22
|
matches: Readonly<Record<string, readonly Open<'text'>[]>>;
|
|
23
23
|
};
|
|
24
|
-
export type
|
|
24
|
+
export type SearchCoverage = {
|
|
25
|
+
rooms: readonly CoveredRoom[];
|
|
26
|
+
conversations: readonly string[];
|
|
27
|
+
index: string;
|
|
28
|
+
overlay: readonly string[];
|
|
29
|
+
};
|
|
30
|
+
export type PendingConversation = {
|
|
31
|
+
conversation: string;
|
|
32
|
+
awaits: Open<'index'>;
|
|
33
|
+
};
|
|
34
|
+
export type SearchPending = {
|
|
35
|
+
pending: readonly (PendingRoom | PendingConversation)[];
|
|
36
|
+
};
|
|
37
|
+
export type SearchHits = {
|
|
25
38
|
documents: readonly DocumentHit[];
|
|
26
39
|
messages: readonly MessageHit[];
|
|
27
40
|
};
|
|
41
|
+
export type SearchResult = (SearchHits & {
|
|
42
|
+
coverage: SearchCoverage;
|
|
43
|
+
}) | SearchPending;
|
|
28
44
|
export type SearchedDocument = {
|
|
29
45
|
room: string;
|
|
30
46
|
path: string;
|
|
@@ -39,10 +55,8 @@ export type SearchedMessage = {
|
|
|
39
55
|
text: string;
|
|
40
56
|
};
|
|
41
57
|
export type SearchSource = {
|
|
42
|
-
|
|
58
|
+
room(room: string): readonly string[];
|
|
43
59
|
document(room: string, path: string): SearchedDocument | null;
|
|
44
|
-
messages(): readonly SearchedMessage[];
|
|
45
|
-
message(conversation: string, identity: string): SearchedMessage | null;
|
|
46
60
|
};
|
|
47
61
|
export type SearchPlan = {
|
|
48
62
|
text: string;
|
|
@@ -51,11 +65,19 @@ export type SearchPlan = {
|
|
|
51
65
|
limit: number | null;
|
|
52
66
|
};
|
|
53
67
|
export type SearchIndex = {
|
|
68
|
+
generation(): string;
|
|
69
|
+
rooms(): ReadonlySet<string>;
|
|
70
|
+
conversations(): ReadonlySet<string>;
|
|
71
|
+
indexRoom(room: string): Promise<void>;
|
|
72
|
+
indexMessages(conversation: string, messages: readonly SearchedMessage[], whole: boolean): void;
|
|
73
|
+
forget(rooms: readonly string[]): void;
|
|
54
74
|
changed(set: ChangeSet): void;
|
|
75
|
+
changes(): number;
|
|
76
|
+
caughtUp(): Promise<void>;
|
|
55
77
|
search(plan: SearchPlan, documents: readonly {
|
|
56
78
|
room: string;
|
|
57
79
|
path: string;
|
|
58
|
-
}[] | null):
|
|
80
|
+
}[] | null, conversations: readonly string[]): SearchHits;
|
|
59
81
|
};
|
|
60
82
|
export declare function searchPlanOf(input: unknown): SearchPlan;
|
|
61
83
|
export declare function createSearchIndex(source: SearchSource): SearchIndex;
|
package/dist/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|