@agentshouse/mdruntime 0.1.0-c2c52158b7381 → 0.1.0-c2e8a6f99866d
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 +14 -10
- package/dist/adapter.d.ts +14 -5
- package/dist/adapter.d.ts.map +1 -1
- package/dist/bootstrap.d.ts +13 -6
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +86 -88
- package/dist/chain.d.ts +11 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +5 -9
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +10 -86
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +1 -1
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +8 -1
- package/dist/chat/messages.d.ts +1 -0
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +9 -1
- package/dist/chat/provider.d.ts +2 -0
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +17 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/collection.d.ts +5 -19
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +22 -360
- package/dist/compile.d.ts +11 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +712 -0
- package/dist/connection.d.ts +2 -2
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1396 -624
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +26 -17
- package/dist/entry.d.ts +2 -1
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -23
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +123 -0
- package/dist/memory.d.ts +1 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +12 -0
- package/dist/observation.d.ts +12 -0
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +84 -0
- package/dist/overlay.d.ts +0 -3
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +1 -151
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +15 -35
- package/dist/reads.js +1 -1
- package/dist/refresh.d.ts +10 -13
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +74 -70
- package/dist/replica.d.ts +55 -38
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +273 -214
- package/dist/rows.d.ts +29 -31
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +113 -69
- package/dist/save.d.ts +9 -10
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +59 -57
- package/dist/search.d.ts +2 -2
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +60 -28
- package/dist/shared.d.ts +0 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +1 -31
- package/dist/store.d.ts +79 -62
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +164 -330
- package/dist/stored.d.ts +143 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +561 -0
- package/dist/tables.d.ts +246 -168
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +156 -25
- package/dist/turn.d.ts +1 -1
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +28 -20
- package/dist/validation.d.ts +30 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +162 -0
- package/dist/windows.d.ts +2 -1
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +30 -25
- package/package.json +2 -3
- package/dist/read-side.d.ts +0 -27
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -1179
package/dist/tables.js
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
import { answerQuery } from './compile.js';
|
|
2
|
+
import { abandon, release, commit, counts, ended, entries, erase, fenceRooms, files, opened, rederive, referrers, refreshing, REPLICA_TABLES, searched, stage, typed, typedWithin, unrefresh, walk, } from './stored.js';
|
|
3
|
+
export function sqliteConnection(engine, database) {
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
return {
|
|
6
|
+
run(sql, bind = []) {
|
|
7
|
+
database.exec({ sql, bind });
|
|
8
|
+
},
|
|
9
|
+
rows(sql, bind = []) {
|
|
10
|
+
return database.exec({ sql, bind, rowMode: 'object', returnValue: 'resultRows' });
|
|
11
|
+
},
|
|
12
|
+
collate(name, compare) {
|
|
13
|
+
const answered = engine.capi.sqlite3_create_collation_v2(database.pointer, name, engine.capi.SQLITE_UTF8, 0, (_argument, leftLength, left, rightLength, right) => {
|
|
14
|
+
const heap = engine.wasm.heap8u();
|
|
15
|
+
return Math.sign(compare(decoder.decode(heap.subarray(left, left + leftLength)), decoder.decode(heap.subarray(right, right + rightLength))));
|
|
16
|
+
}, 0);
|
|
17
|
+
if (answered !== 0)
|
|
18
|
+
throw new Error(`the database refused the collation ${name}`);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
1
22
|
export const FILE_PART_BYTES = 1_048_576;
|
|
2
23
|
const TABLES = [
|
|
3
24
|
['authored_facts', 'name TEXT PRIMARY KEY, value TEXT NOT NULL'],
|
|
@@ -19,6 +40,7 @@ export const RUNTIME_TABLES = [
|
|
|
19
40
|
'CREATE TABLE file_parts (key TEXT NOT NULL, part INTEGER NOT NULL, bytes BLOB NOT NULL, PRIMARY KEY (key, part))',
|
|
20
41
|
'CREATE TABLE opened_files (key TEXT PRIMARY KEY, locator TEXT NOT NULL, path TEXT NOT NULL, revision TEXT NOT NULL, media_type TEXT NOT NULL, sha256 TEXT, byte_length INTEGER) WITHOUT ROWID',
|
|
21
42
|
'CREATE INDEX opened_files_name ON opened_files (locator, path, revision)',
|
|
43
|
+
...REPLICA_TABLES,
|
|
22
44
|
];
|
|
23
45
|
const OWNERS = ['authored_pending', 'authored_room_drafts', 'authored_calls'];
|
|
24
46
|
const AUTHORED_KEYS = OWNERS.map((table) => `SELECT value FROM ${table}, json_each(${table}.files)`).join(' UNION ');
|
|
@@ -31,22 +53,43 @@ const READS = new Set([
|
|
|
31
53
|
'authored.fences',
|
|
32
54
|
'authored.fact',
|
|
33
55
|
'authored.file',
|
|
56
|
+
'replica.open',
|
|
57
|
+
'replica.query',
|
|
58
|
+
'replica.entries',
|
|
59
|
+
'replica.typed',
|
|
60
|
+
'replica.referrers',
|
|
61
|
+
'replica.walk',
|
|
62
|
+
'replica.files',
|
|
63
|
+
'replica.typedWithin',
|
|
64
|
+
'replica.counts',
|
|
65
|
+
'replica.searched',
|
|
66
|
+
'replica.received',
|
|
67
|
+
'replica.receivedParts',
|
|
34
68
|
'opened.find',
|
|
35
69
|
'file.part',
|
|
36
70
|
]);
|
|
37
71
|
const KINDS = new Set([
|
|
38
72
|
...READS,
|
|
39
|
-
'authored.keep',
|
|
40
73
|
'authored.amend',
|
|
41
74
|
'authored.roomDraft',
|
|
42
75
|
'authored.chatDraft',
|
|
43
76
|
'authored.call',
|
|
44
|
-
'authored.fence',
|
|
45
|
-
'authored.unfence',
|
|
46
|
-
'authored.discard',
|
|
47
77
|
'authored.remember',
|
|
48
78
|
'authored.claim',
|
|
49
79
|
'authored.end',
|
|
80
|
+
'replica.stage',
|
|
81
|
+
'replica.refresh',
|
|
82
|
+
'replica.unrefresh',
|
|
83
|
+
'replica.commit',
|
|
84
|
+
'replica.fence',
|
|
85
|
+
'replica.erase',
|
|
86
|
+
'replica.abandon',
|
|
87
|
+
'replica.release',
|
|
88
|
+
'replica.rederive',
|
|
89
|
+
'replica.fact',
|
|
90
|
+
'replica.present',
|
|
91
|
+
'replica.receive',
|
|
92
|
+
'replica.unreceive',
|
|
50
93
|
'opened.begin',
|
|
51
94
|
'opened.part',
|
|
52
95
|
'opened.keep',
|
|
@@ -143,7 +186,10 @@ function heldOrder(connection, locator) {
|
|
|
143
186
|
const [held] = connection.rows('SELECT ids FROM authored_queues WHERE locator = ?', [locator]);
|
|
144
187
|
return held === undefined ? [] : JSON.parse(text(held.ids));
|
|
145
188
|
}
|
|
146
|
-
function keptRows(connection, { locator, order, added, founded, roomDrafts, consumedRoomDrafts }) {
|
|
189
|
+
function keptRows(connection, { locator, order, added, founded, roomDrafts, consumedRoomDrafts, amendments }) {
|
|
190
|
+
for (const { id, amendment } of amendments ?? []) {
|
|
191
|
+
amended(connection, { kind: 'authored.amend', locator, id, amendment });
|
|
192
|
+
}
|
|
147
193
|
for (const path of consumedRoomDrafts ?? []) {
|
|
148
194
|
connection.run('DELETE FROM authored_room_drafts WHERE locator = ? AND path = ?', [
|
|
149
195
|
locator,
|
|
@@ -176,12 +222,13 @@ function keptRows(connection, { locator, order, added, founded, roomDrafts, cons
|
|
|
176
222
|
connection.run('INSERT OR REPLACE INTO authored_pending (locator, id, batch, state, files) VALUES (?, ?, ?, ?, ?)', [locator, id, batch, state, owned(files)]);
|
|
177
223
|
}
|
|
178
224
|
for (const { id, batch, files } of founded ?? []) {
|
|
179
|
-
|
|
225
|
+
const [held] = connection.rows('SELECT files FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
|
|
226
|
+
if (held === undefined || !before.has(id))
|
|
180
227
|
continue;
|
|
181
|
-
connection.run('UPDATE authored_pending SET batch = ?, files = ? WHERE locator = ? AND id = ?', [batch, owned(files), locator, id]);
|
|
228
|
+
connection.run('UPDATE authored_pending SET batch = ?, files = ? WHERE locator = ? AND id = ?', [batch, owned([...JSON.parse(text(held.files)), ...files]), locator, id]);
|
|
182
229
|
}
|
|
183
230
|
}
|
|
184
|
-
async function kept(connection, { writes, files, whole }) {
|
|
231
|
+
async function kept(connection, { writes, files, whole, discards }) {
|
|
185
232
|
const refused = writes.find(({ locator }) => fenced(connection, locator));
|
|
186
233
|
if (refused !== undefined && whole)
|
|
187
234
|
return refused.locator;
|
|
@@ -190,6 +237,8 @@ async function kept(connection, { writes, files, whole }) {
|
|
|
190
237
|
if (!fenced(connection, write.locator))
|
|
191
238
|
keptRows(connection, write);
|
|
192
239
|
}
|
|
240
|
+
for (const locator of discards ?? [])
|
|
241
|
+
roomWork(connection, locator);
|
|
193
242
|
unowned(connection);
|
|
194
243
|
return refused?.locator ?? null;
|
|
195
244
|
}
|
|
@@ -256,18 +305,14 @@ function fence(connection, locators) {
|
|
|
256
305
|
connection.run('DELETE FROM opened_files WHERE locator = ?', [locator]);
|
|
257
306
|
}
|
|
258
307
|
unowned(connection);
|
|
259
|
-
return
|
|
308
|
+
return fenceRooms(connection, locators);
|
|
260
309
|
}
|
|
261
|
-
function
|
|
262
|
-
|
|
310
|
+
function erased(connection, { locator, limit }) {
|
|
311
|
+
const done = erase(connection, locator, limit);
|
|
312
|
+
if (locator !== null && !done.remaining) {
|
|
263
313
|
connection.run('DELETE FROM authored_fences WHERE locator = ?', [locator]);
|
|
264
314
|
}
|
|
265
|
-
return
|
|
266
|
-
}
|
|
267
|
-
function discard(connection, locator) {
|
|
268
|
-
roomWork(connection, locator);
|
|
269
|
-
unowned(connection);
|
|
270
|
-
return null;
|
|
315
|
+
return done;
|
|
271
316
|
}
|
|
272
317
|
function claim(connection, holder) {
|
|
273
318
|
const held = fact(connection, 'holder');
|
|
@@ -277,6 +322,7 @@ function claim(connection, holder) {
|
|
|
277
322
|
return true;
|
|
278
323
|
}
|
|
279
324
|
function end(connection, holder) {
|
|
325
|
+
ended(connection);
|
|
280
326
|
if (holder !== null && claim(connection, holder))
|
|
281
327
|
return true;
|
|
282
328
|
for (const [table] of TABLES)
|
|
@@ -350,6 +396,38 @@ function cleaned(connection) {
|
|
|
350
396
|
unowned(connection);
|
|
351
397
|
return count(freed?.bytes);
|
|
352
398
|
}
|
|
399
|
+
async function committed(connection, { authored, rooms }) {
|
|
400
|
+
const refused = authored === undefined ? null : await kept(connection, authored);
|
|
401
|
+
if (refused !== null && authored?.whole === true) {
|
|
402
|
+
return { fenced: refused, counts: {}, changed: {}, prepared: {} };
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
fenced: refused,
|
|
406
|
+
...commit(connection, rooms.filter(({ locator }) => !fenced(connection, locator))),
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function receivedParts(connection, key, count) {
|
|
410
|
+
return connection
|
|
411
|
+
.rows('SELECT value FROM replica_received_parts WHERE key = ? AND part < ? ORDER BY part', [
|
|
412
|
+
key,
|
|
413
|
+
count,
|
|
414
|
+
])
|
|
415
|
+
.map((row) => JSON.parse(text(row.value)));
|
|
416
|
+
}
|
|
417
|
+
function receive(connection, { key, head, part }) {
|
|
418
|
+
connection.run('INSERT OR REPLACE INTO replica_received (key, head) VALUES (?, ?)', [key, head]);
|
|
419
|
+
if (part !== undefined) {
|
|
420
|
+
connection.run('INSERT OR REPLACE INTO replica_received_parts (key, part, value) VALUES (?, ?, ?)', [key, part.index, part.value]);
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
function unreceive(connection, keys) {
|
|
425
|
+
for (const key of keys) {
|
|
426
|
+
connection.run('DELETE FROM replica_received WHERE key = ?', [key]);
|
|
427
|
+
connection.run('DELETE FROM replica_received_parts WHERE key = ?', [key]);
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
353
431
|
export function answerRuntime(connection, request, spool) {
|
|
354
432
|
switch (request.kind) {
|
|
355
433
|
case 'authored.queues':
|
|
@@ -366,8 +444,6 @@ export function answerRuntime(connection, request, spool) {
|
|
|
366
444
|
return fact(connection, request.name);
|
|
367
445
|
case 'authored.file':
|
|
368
446
|
return spooled(connection, spool, request);
|
|
369
|
-
case 'authored.keep':
|
|
370
|
-
return kept(connection, request);
|
|
371
447
|
case 'authored.amend':
|
|
372
448
|
return amended(connection, request);
|
|
373
449
|
case 'authored.roomDraft':
|
|
@@ -376,18 +452,73 @@ export function answerRuntime(connection, request, spool) {
|
|
|
376
452
|
return chatDraft(connection, request);
|
|
377
453
|
case 'authored.call':
|
|
378
454
|
return call(connection, request);
|
|
379
|
-
case 'authored.fence':
|
|
380
|
-
return fence(connection, request.locators);
|
|
381
|
-
case 'authored.unfence':
|
|
382
|
-
return unfence(connection, request.locators);
|
|
383
|
-
case 'authored.discard':
|
|
384
|
-
return discard(connection, request.locator);
|
|
385
455
|
case 'authored.remember':
|
|
386
456
|
return remember(connection, request.name, request.value);
|
|
387
457
|
case 'authored.claim':
|
|
388
458
|
return claim(connection, request.holder);
|
|
389
459
|
case 'authored.end':
|
|
390
460
|
return end(connection, request.holder);
|
|
461
|
+
case 'replica.open':
|
|
462
|
+
return opened(connection);
|
|
463
|
+
case 'replica.query':
|
|
464
|
+
return answerQuery(connection, request.plan, request.rooms, request.budget);
|
|
465
|
+
case 'replica.entries':
|
|
466
|
+
return entries(connection, request.key, request.view, request.paths);
|
|
467
|
+
case 'replica.typed':
|
|
468
|
+
return typed(connection, request.key, request.view, request.paths);
|
|
469
|
+
case 'replica.referrers':
|
|
470
|
+
return referrers(connection, request.key, request.view, request.targets, request.kinds);
|
|
471
|
+
case 'replica.walk':
|
|
472
|
+
return walk(connection, request.key, request.view, request.after, request.bytes);
|
|
473
|
+
case 'replica.files':
|
|
474
|
+
return files(connection, request.key, request.view, request.after, request.limit);
|
|
475
|
+
case 'replica.typedWithin':
|
|
476
|
+
return typedWithin(connection, request.key, request.view, request.roots, request.within);
|
|
477
|
+
case 'replica.counts':
|
|
478
|
+
return counts(connection, request.rooms);
|
|
479
|
+
case 'replica.searched':
|
|
480
|
+
return searched(connection, request.key, request.locator, request.after, request.limit, request.paths);
|
|
481
|
+
case 'replica.received':
|
|
482
|
+
return connection.rows('SELECT key, head FROM replica_received').map((row) => ({
|
|
483
|
+
key: text(row.key),
|
|
484
|
+
head: JSON.parse(text(row.head)),
|
|
485
|
+
}));
|
|
486
|
+
case 'replica.receivedParts':
|
|
487
|
+
return receivedParts(connection, request.key, request.count);
|
|
488
|
+
case 'replica.stage':
|
|
489
|
+
return fenced(connection, request.locator) ? null : stage(connection, request);
|
|
490
|
+
case 'replica.refresh':
|
|
491
|
+
return refreshing(connection, request);
|
|
492
|
+
case 'replica.unrefresh':
|
|
493
|
+
return unrefresh(connection, request.key);
|
|
494
|
+
case 'replica.commit':
|
|
495
|
+
return committed(connection, request);
|
|
496
|
+
case 'replica.fence':
|
|
497
|
+
return fence(connection, request.locators);
|
|
498
|
+
case 'replica.erase':
|
|
499
|
+
return erased(connection, request);
|
|
500
|
+
case 'replica.abandon':
|
|
501
|
+
return abandon(connection, request.locator, request.kept);
|
|
502
|
+
case 'replica.release':
|
|
503
|
+
return release(connection, request.key);
|
|
504
|
+
case 'replica.rederive':
|
|
505
|
+
return rederive(connection, request.key, request.limit);
|
|
506
|
+
case 'replica.fact':
|
|
507
|
+
connection.run('INSERT OR REPLACE INTO replica_facts (name, value) VALUES (?, ?)', [
|
|
508
|
+
request.name,
|
|
509
|
+
request.value,
|
|
510
|
+
]);
|
|
511
|
+
return null;
|
|
512
|
+
case 'replica.present':
|
|
513
|
+
connection.run('INSERT OR REPLACE INTO replica_presentation (app, value) VALUES (?, ?)', [
|
|
514
|
+
request.app,
|
|
515
|
+
request.value,
|
|
516
|
+
]);
|
|
517
|
+
return null;
|
|
518
|
+
case 'replica.receive':
|
|
519
|
+
return receive(connection, request);
|
|
520
|
+
case 'replica.unreceive':
|
|
521
|
+
return unreceive(connection, request.keys);
|
|
391
522
|
case 'opened.find':
|
|
392
523
|
return openedFile(connection, request);
|
|
393
524
|
case 'opened.begin':
|
package/dist/turn.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export declare function yielded(): Promise<void>;
|
|
|
2
2
|
export declare const ROW_WEIGHT = 256;
|
|
3
3
|
export type Later<T> = T | Promise<T>;
|
|
4
4
|
export declare function after<T, R>(value: Later<T>, next: (value: T) => Later<R>): Later<R>;
|
|
5
|
+
export declare function paced(): (weight: number) => Later<void>;
|
|
5
6
|
export declare function inUnits<T>(items: Iterable<T>, each: (item: T) => number, ended?: () => void, paused?: () => Promise<void>): Later<void>;
|
|
6
7
|
export declare function finished<R>(steps: Generator<number, R, void>): R;
|
|
7
8
|
export declare function stepped<R>(steps: Generator<number, R, void>): Later<R>;
|
|
8
|
-
export declare function inChunks<T>(items: Iterable<T>, weigh: (item: T) => number, each: (chunk: readonly T[]) => Later<void>): Promise<void>;
|
|
9
9
|
//# sourceMappingURL=turn.d.ts.map
|
package/dist/turn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../src/turn.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CASvC;
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../src/turn.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CASvC;AAOD,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAEnF;AAmBD,wBAAgB,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,CAGvD;AAsBD,wBAAgB,OAAO,CAAC,CAAC,EACvB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAClB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EACzB,KAAK,GAAE,MAAM,IAAe,EAC5B,MAAM,GAAE,MAAM,OAAO,CAAC,IAAI,CAAW,GACpC,KAAK,CAAC,IAAI,CAAC,CAUb;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAIhE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAStE"}
|
package/dist/turn.js
CHANGED
|
@@ -9,31 +9,51 @@ export function yielded() {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
const UNIT = 1 << 20;
|
|
12
|
+
// A unit of runtime work ends within one 60 Hz frame so a port's next message waits at most a frame.
|
|
13
|
+
const SLICE_MS = 16;
|
|
12
14
|
export const ROW_WEIGHT = 256;
|
|
13
15
|
export function after(value, next) {
|
|
14
16
|
return value instanceof Promise ? value.then(next) : next(value);
|
|
15
17
|
}
|
|
18
|
+
function spending() {
|
|
19
|
+
let spent = 0;
|
|
20
|
+
let since = performance.now();
|
|
21
|
+
return {
|
|
22
|
+
spend(weight) {
|
|
23
|
+
spent += weight;
|
|
24
|
+
return spent >= UNIT || performance.now() - since >= SLICE_MS;
|
|
25
|
+
},
|
|
26
|
+
restart() {
|
|
27
|
+
spent = 0;
|
|
28
|
+
since = performance.now();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function paced() {
|
|
33
|
+
const spent = spending();
|
|
34
|
+
return (weight) => (spent.spend(weight) ? yielded().then(() => spent.restart()) : undefined);
|
|
35
|
+
}
|
|
16
36
|
async function resumed(iterator, each, ended, paused) {
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
const spent = spending();
|
|
38
|
+
for (let due = true;;) {
|
|
39
|
+
if (due) {
|
|
19
40
|
await paused();
|
|
20
|
-
spent
|
|
41
|
+
spent.restart();
|
|
21
42
|
}
|
|
22
43
|
const next = iterator.next();
|
|
23
44
|
if (next.done === true)
|
|
24
45
|
break;
|
|
25
|
-
|
|
26
|
-
if (
|
|
46
|
+
due = spent.spend(each(next.value));
|
|
47
|
+
if (due)
|
|
27
48
|
ended();
|
|
28
49
|
}
|
|
29
50
|
ended();
|
|
30
51
|
}
|
|
31
52
|
export function inUnits(items, each, ended = () => { }, paused = yielded) {
|
|
32
53
|
const iterator = items[Symbol.iterator]();
|
|
33
|
-
|
|
54
|
+
const spent = spending();
|
|
34
55
|
for (let next = iterator.next(); next.done !== true; next = iterator.next()) {
|
|
35
|
-
spent
|
|
36
|
-
if (spent >= UNIT) {
|
|
56
|
+
if (spent.spend(each(next.value))) {
|
|
37
57
|
ended();
|
|
38
58
|
return resumed(iterator, each, ended, paused);
|
|
39
59
|
}
|
|
@@ -53,15 +73,3 @@ export function stepped(steps) {
|
|
|
53
73
|
};
|
|
54
74
|
return after(inUnits(driven(), (weight) => weight), () => result);
|
|
55
75
|
}
|
|
56
|
-
export async function inChunks(items, weigh, each) {
|
|
57
|
-
const iterator = items[Symbol.iterator]();
|
|
58
|
-
for (let next = iterator.next(); next.done !== true;) {
|
|
59
|
-
await yielded();
|
|
60
|
-
const chunk = [];
|
|
61
|
-
for (let spent = 0; next.done !== true && spent < UNIT; next = iterator.next()) {
|
|
62
|
-
chunk.push(next.value);
|
|
63
|
-
spent += weigh(next.value);
|
|
64
|
-
}
|
|
65
|
-
await each(chunk);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Validation } from '@agentshouse/mdmodel';
|
|
2
|
+
import { type Composition } from './collection.js';
|
|
3
|
+
type Examined = {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly content: string | null;
|
|
6
|
+
};
|
|
7
|
+
export type Typed = {
|
|
8
|
+
readonly type: string | undefined;
|
|
9
|
+
readonly binary: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type Walk = (after: string | null) => Promise<{
|
|
12
|
+
readonly entries: readonly Examined[];
|
|
13
|
+
readonly next: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
export type Lookup = (paths: readonly string[]) => Promise<ReadonlyMap<string, Typed>>;
|
|
16
|
+
export declare function validatedCollection(walk: Walk, lookup: Lookup, composition: Composition): Promise<Validation>;
|
|
17
|
+
export type Changed = {
|
|
18
|
+
readonly path: string;
|
|
19
|
+
readonly was: string | null | undefined;
|
|
20
|
+
readonly now: string | null | undefined;
|
|
21
|
+
};
|
|
22
|
+
type CleanSource = {
|
|
23
|
+
readonly lookup: Lookup;
|
|
24
|
+
readonly texts: (paths: readonly string[]) => Promise<ReadonlyMap<string, string | null>>;
|
|
25
|
+
readonly referrers: ((targets: readonly string[]) => Promise<readonly string[]>) | null;
|
|
26
|
+
};
|
|
27
|
+
export declare function sameComposition(left: Composition, right: Composition): boolean;
|
|
28
|
+
export declare function changedCleanly(changes: readonly Changed[], previous: Composition, composition: Composition, source: CleanSource): Promise<boolean>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,UAAU,EAGhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAMxE,KAAK,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,IAAI,GAAG,CACjB,KAAK,EAAE,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC;AAEtF,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAyBvF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1F,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;CACzF,CAAC;AAaF,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAQ9E;AAqCD,wBAAsB,cAAc,CAClC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,QAAQ,EAAE,WAAW,EACrB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,OAAO,CAAC,CAsDlB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { assess, checkDocument, parse, parseFrontmatter, resolves, verdicts, } from '@agentshouse/mdmodel';
|
|
2
|
+
import { governing, selected } from './collection.js';
|
|
3
|
+
import { sameTyping } from './model.js';
|
|
4
|
+
import { paced, ROW_WEIGHT, yielded } from './turn.js';
|
|
5
|
+
const NO_TYPES = { types: {} };
|
|
6
|
+
function modelOf(model) {
|
|
7
|
+
return model.status === 'unavailable' ? NO_TYPES : { types: model.types };
|
|
8
|
+
}
|
|
9
|
+
function typedText(content) {
|
|
10
|
+
const read = parse(content);
|
|
11
|
+
return read.ok && read.document.type !== undefined && read.document.type !== 'any';
|
|
12
|
+
}
|
|
13
|
+
function partVerdict(part) {
|
|
14
|
+
return part.unmodeled !== null
|
|
15
|
+
? { verdict: 'refuse', rule: 'model-unavailable', file: part.unmodeled }
|
|
16
|
+
: part.judged.verdict();
|
|
17
|
+
}
|
|
18
|
+
export async function validatedCollection(walk, lookup, composition) {
|
|
19
|
+
const collection = { model: composition.model, judged: verdicts(), unmodeled: null };
|
|
20
|
+
const selection = composition.selection === null
|
|
21
|
+
? null
|
|
22
|
+
: { model: composition.selection.model, judged: verdicts(), unmodeled: null };
|
|
23
|
+
const partOf = (path) => selection !== null && selected(composition, path) ? selection : collection;
|
|
24
|
+
const pace = paced();
|
|
25
|
+
for (let after = null;;) {
|
|
26
|
+
const { entries, next } = await walk(after);
|
|
27
|
+
const assessed = [];
|
|
28
|
+
for (const { path, content } of entries) {
|
|
29
|
+
if (content === null)
|
|
30
|
+
continue;
|
|
31
|
+
const part = partOf(path);
|
|
32
|
+
if (part.model.status === 'unavailable' && part.unmodeled === null && typedText(content)) {
|
|
33
|
+
part.unmodeled = path;
|
|
34
|
+
}
|
|
35
|
+
const assessment = assess(path, content, false, modelOf(part.model), { anyRoom: true });
|
|
36
|
+
assessed.push({ part, assessment });
|
|
37
|
+
await pace(content.length + assessment.targets.length * ROW_WEIGHT);
|
|
38
|
+
}
|
|
39
|
+
const targets = [...new Set(assessed.flatMap(({ assessment }) => assessment.targets))];
|
|
40
|
+
const known = await lookup(targets);
|
|
41
|
+
for (const { part, assessment } of assessed) {
|
|
42
|
+
const within = (path) => partOf(path) === part;
|
|
43
|
+
part.judged.add(assessment, (path) => (within(path) ? known.get(path)?.type : undefined), (path) => within(path) && known.get(path)?.binary === true);
|
|
44
|
+
await pace((assessment.targets.length + 1) * ROW_WEIGHT);
|
|
45
|
+
}
|
|
46
|
+
if (next === null)
|
|
47
|
+
break;
|
|
48
|
+
after = next;
|
|
49
|
+
await yielded();
|
|
50
|
+
}
|
|
51
|
+
const judged = [partVerdict(collection), ...(selection === null ? [] : [partVerdict(selection)])];
|
|
52
|
+
const refusals = judged.filter((verdict) => verdict.verdict === 'refuse');
|
|
53
|
+
if (refusals.length === 0)
|
|
54
|
+
return judged[0];
|
|
55
|
+
return refusals.find((refusal) => refusal.rule !== 'model-unavailable') ?? refusals[0];
|
|
56
|
+
}
|
|
57
|
+
function declared(content) {
|
|
58
|
+
if (content === undefined || content === null)
|
|
59
|
+
return undefined;
|
|
60
|
+
const read = parseFrontmatter(content);
|
|
61
|
+
return read.ok ? (read.frontmatter.type ?? 'any') : undefined;
|
|
62
|
+
}
|
|
63
|
+
function typedIn(content) {
|
|
64
|
+
const type = declared(content);
|
|
65
|
+
return type !== undefined && type !== 'any';
|
|
66
|
+
}
|
|
67
|
+
export function sameComposition(left, right) {
|
|
68
|
+
return (sameTyping(left.model, right.model) &&
|
|
69
|
+
(left.selection === null || right.selection === null
|
|
70
|
+
? left.selection === right.selection
|
|
71
|
+
: sameTyping(left.selection.model, right.selection.model)) &&
|
|
72
|
+
JSON.stringify(left.selection?.roots ?? null) === JSON.stringify(right.selection?.roots ?? null));
|
|
73
|
+
}
|
|
74
|
+
function checked(path, content, composition) {
|
|
75
|
+
const model = governing(composition, path);
|
|
76
|
+
return checkDocument(path, content, modelOf(model), { anyRoom: true });
|
|
77
|
+
}
|
|
78
|
+
async function reachingAll(checks, composition, next) {
|
|
79
|
+
const targets = [
|
|
80
|
+
...new Set(checks.flatMap(({ check }) => check.ok ? check.references.flatMap(({ target }) => (target === null ? [] : [target])) : [])),
|
|
81
|
+
];
|
|
82
|
+
const known = await next(targets);
|
|
83
|
+
const pace = paced();
|
|
84
|
+
for (const { path, check } of checks) {
|
|
85
|
+
if (!check.ok)
|
|
86
|
+
return false;
|
|
87
|
+
const part = (other) => selected(composition, other) === selected(composition, path);
|
|
88
|
+
const resolved = check.references.every((reference) => resolves(reference, (other) => (part(other) ? known.get(other)?.type : undefined), (other) => part(other) && known.get(other)?.binary === true));
|
|
89
|
+
if (!resolved)
|
|
90
|
+
return false;
|
|
91
|
+
await pace((check.references.length + 1) * ROW_WEIGHT);
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
export async function changedCleanly(changes, previous, composition, source) {
|
|
96
|
+
if (!sameComposition(previous, composition))
|
|
97
|
+
return false;
|
|
98
|
+
const changedAt = new Map(changes.map((change) => [change.path, change]));
|
|
99
|
+
const next = async (paths) => {
|
|
100
|
+
const asked = paths.filter((path) => !changedAt.has(path));
|
|
101
|
+
const known = new Map(await source.lookup(asked));
|
|
102
|
+
for (const path of paths) {
|
|
103
|
+
const change = changedAt.get(path);
|
|
104
|
+
if (change === undefined)
|
|
105
|
+
continue;
|
|
106
|
+
if (change.now === undefined)
|
|
107
|
+
known.delete(path);
|
|
108
|
+
else
|
|
109
|
+
known.set(path, { type: declared(change.now), binary: change.now === null });
|
|
110
|
+
}
|
|
111
|
+
return known;
|
|
112
|
+
};
|
|
113
|
+
const shifted = [];
|
|
114
|
+
const checks = [];
|
|
115
|
+
const pace = paced();
|
|
116
|
+
for (const { path, was, now } of changes) {
|
|
117
|
+
await pace((now?.length ?? 0) + (was?.length ?? 0) + ROW_WEIGHT);
|
|
118
|
+
const modeled = governing(composition, path).status !== 'unavailable';
|
|
119
|
+
if ((now === undefined) !== (was === undefined) ||
|
|
120
|
+
declared(now) !== declared(was) ||
|
|
121
|
+
(now === null) !== (was === null)) {
|
|
122
|
+
shifted.push(path);
|
|
123
|
+
}
|
|
124
|
+
if (!modeled && typedIn(was) && !typedIn(now))
|
|
125
|
+
return false;
|
|
126
|
+
if (now === undefined)
|
|
127
|
+
continue;
|
|
128
|
+
if (now === null)
|
|
129
|
+
return false;
|
|
130
|
+
if (!modeled) {
|
|
131
|
+
if (declared(now) === undefined)
|
|
132
|
+
return false;
|
|
133
|
+
if (typedIn(now))
|
|
134
|
+
continue;
|
|
135
|
+
const check = checked(path, now, composition);
|
|
136
|
+
if (!check.ok)
|
|
137
|
+
return false;
|
|
138
|
+
checks.push({ path, check });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
checks.push({ path, check: checked(path, now, composition) });
|
|
142
|
+
}
|
|
143
|
+
if (!(await reachingAll(checks, composition, next)))
|
|
144
|
+
return false;
|
|
145
|
+
if (shifted.length === 0)
|
|
146
|
+
return true;
|
|
147
|
+
if (source.referrers === null)
|
|
148
|
+
return false;
|
|
149
|
+
const files = (await source.referrers(shifted)).filter((file) => !changedAt.has(file));
|
|
150
|
+
if (files.length === 0)
|
|
151
|
+
return true;
|
|
152
|
+
const texts = await source.texts(files);
|
|
153
|
+
const rechecked = [];
|
|
154
|
+
for (const file of files) {
|
|
155
|
+
const content = texts.get(file);
|
|
156
|
+
if (content === undefined || content === null)
|
|
157
|
+
return false;
|
|
158
|
+
await pace(content.length + ROW_WEIGHT);
|
|
159
|
+
rechecked.push({ path: file, check: checked(file, content, composition) });
|
|
160
|
+
}
|
|
161
|
+
return reachingAll(rechecked, composition, next);
|
|
162
|
+
}
|
package/dist/windows.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ interface Placed {
|
|
|
14
14
|
}
|
|
15
15
|
export declare function messageOrder(left: Placed, right: Placed): number;
|
|
16
16
|
export declare function precedes(message: Placed, before: readonly [string, string] | null): boolean;
|
|
17
|
-
export declare function
|
|
17
|
+
export declare function byCodePoint(left: string, right: string): number;
|
|
18
|
+
export declare function compared(left: unknown, right: unknown, ordering: Ordering): number;
|
|
18
19
|
export declare function cursorOf(values: readonly unknown[]): string;
|
|
19
20
|
export declare function decodedCursor(text: string): readonly unknown[] | null;
|
|
20
21
|
export {};
|
package/dist/windows.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../src/windows.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,eAAO,MAAM,UAAU,OAAO,CAAC;AAE/B,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE/D;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;CAC1D,CAAC;AAEF,UAAU,MAAM;IACd,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,OAAO,CAE3F;
|
|
1
|
+
{"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../src/windows.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,eAAO,MAAM,UAAU,OAAO,CAAC;AAE/B,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE/D;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;CAC1D,CAAC;AAEF,UAAU,MAAM;IACd,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,OAAO,CAE3F;AAaD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO/D;AA4BD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAMlF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE,GAAG,IAAI,CAOrE"}
|