@agentshouse/mdruntime-adapter 0.1.0-cf9ab9b7cbbca → 0.1.0-cfd2dc1938a2c
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/README.md +2 -2
- package/dist/actions.d.ts +6 -66
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +23 -340
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +245 -366
- package/dist/app-reference.d.ts +2 -0
- package/dist/app-reference.d.ts.map +1 -0
- package/dist/app-reference.js +2 -0
- package/dist/authored-path.d.ts +11 -0
- package/dist/authored-path.d.ts.map +1 -0
- package/dist/authored-path.js +35 -0
- package/dist/chunks.d.ts +38 -0
- package/dist/chunks.d.ts.map +1 -0
- package/dist/chunks.js +247 -0
- package/dist/crockford.d.ts +4 -0
- package/dist/crockford.d.ts.map +1 -0
- package/dist/crockford.js +3 -0
- package/dist/discovery.d.ts +23 -15
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +92 -55
- package/dist/history.d.ts +12 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +92 -0
- package/dist/house-model.d.ts +682 -0
- package/dist/house-model.d.ts.map +1 -0
- package/dist/house-model.js +397 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/model.d.ts +5 -4
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +34 -41
- package/dist/read.d.ts +57 -64
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +154 -318
- package/dist/refusal.d.ts +1 -3
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +4 -5
- package/dist/room-types.d.ts +5 -0
- package/dist/room-types.d.ts.map +1 -0
- package/dist/room-types.js +120 -0
- package/dist/search.d.ts +5 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +47 -0
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +102 -202
- package/dist/space-schema.d.ts +7 -0
- package/dist/space-schema.d.ts.map +1 -0
- package/dist/space-schema.js +18 -0
- package/dist/stream.d.ts +16 -15
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +261 -421
- package/dist/transport.d.ts +66 -43
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +54 -11
- package/dist/upload.d.ts +12 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +63 -0
- package/dist/write.d.ts +18 -2
- package/dist/write.d.ts.map +1 -1
- package/dist/write.js +108 -80
- package/package.json +8 -4
- package/AGENTS.md +0 -299
- package/dist/gather.d.ts +0 -4
- package/dist/gather.d.ts.map +0 -1
- package/dist/gather.js +0 -45
- package/dist/handed.d.ts +0 -15
- package/dist/handed.d.ts.map +0 -1
- package/dist/handed.js +0 -38
- package/dist/referrer.d.ts +0 -7
- package/dist/referrer.d.ts.map +0 -1
- package/dist/referrer.js +0 -35
package/dist/stream.js
CHANGED
|
@@ -1,117 +1,129 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { ROW_WEIGHT, stepped, } from '@agentshouse/mdruntime';
|
|
2
|
+
import { acceptedMessage, cursorPosition, houseHistory } from './history.js';
|
|
3
|
+
import { keptSpaceSchemas, streamedModels } from './model.js';
|
|
4
|
+
import { answered, answering, binaryFileOf, createdOf, folded, forgotten, headChange, revised, } from './read.js';
|
|
5
|
+
import { classifyDoor } from './refusal.js';
|
|
6
|
+
import { houseDoorRoute, } from './transport.js';
|
|
7
|
+
import { DECIMAL, logPosition, presented, roomVersion } from './version.js';
|
|
6
8
|
function turnOperation(frame) {
|
|
7
9
|
const { type: _type, conversation_id: _conversation, turn_id: _turn, ...operation } = frame;
|
|
8
10
|
return structuredClone(operation);
|
|
9
11
|
}
|
|
12
|
+
async function houseAgents(transport) {
|
|
13
|
+
const answer = await transport.door(houseDoorRoute('agents/list'), {});
|
|
14
|
+
if (classifyDoor(answer.status, answer.body, 'agents/list')?.kind === 'transport-uncertainty') {
|
|
15
|
+
throw new Error('agents/list reached no answer');
|
|
16
|
+
}
|
|
17
|
+
const agents = answer.status === 200 ? answer.body?.agents : null;
|
|
18
|
+
if (!Array.isArray(agents))
|
|
19
|
+
return null;
|
|
20
|
+
return agents.flatMap((one) => {
|
|
21
|
+
const { id, name, retired_at: retired } = (one ?? {});
|
|
22
|
+
return typeof id === 'string' && typeof name === 'string'
|
|
23
|
+
? [{ agent: id, name, retired: retired !== null && retired !== undefined }]
|
|
24
|
+
: [];
|
|
25
|
+
});
|
|
26
|
+
}
|
|
10
27
|
function listedConversation(listed) {
|
|
11
28
|
return {
|
|
12
29
|
conversation: listed.conversation_id,
|
|
13
30
|
agent: listed.agent_id,
|
|
31
|
+
agentName: listed.agent_name,
|
|
32
|
+
agentRetired: listed.agent_retired,
|
|
14
33
|
name: listed.name,
|
|
15
34
|
created: listed.created_at,
|
|
16
35
|
finished: listed.finished_at,
|
|
17
36
|
outcome: listed.outcome,
|
|
37
|
+
waiting: listed.waiting,
|
|
38
|
+
newest: listed.newest === null ? null : cursorPosition(listed.newest),
|
|
39
|
+
processEnded: listed.process_ended_at,
|
|
18
40
|
};
|
|
19
41
|
}
|
|
20
42
|
function position(value) {
|
|
21
|
-
if (
|
|
43
|
+
if (!DECIMAL.test(value))
|
|
22
44
|
return null;
|
|
23
45
|
return BigInt(value);
|
|
24
46
|
}
|
|
25
|
-
function
|
|
26
|
-
const
|
|
27
|
-
let open = null;
|
|
47
|
+
function* changed(tracked, entries, version, schemas) {
|
|
48
|
+
const answer = answering();
|
|
28
49
|
for (const entry of entries) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
yield ROW_WEIGHT + (entry.text?.length ?? 0);
|
|
51
|
+
if (entry.kind === 'folder') {
|
|
52
|
+
folded(answer, entry.path, entry.removed === true);
|
|
53
|
+
continue;
|
|
33
54
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
if (entry.text === undefined)
|
|
42
|
-
return null;
|
|
43
|
-
open = { entry, texts: [entry.text] };
|
|
55
|
+
if (entry.path === tracked.schema)
|
|
56
|
+
schemas.set(entry.path, entry);
|
|
57
|
+
forgotten(answer, entry.path);
|
|
58
|
+
if (entry.space !== undefined) {
|
|
59
|
+
answer.removals.add(entry.path);
|
|
60
|
+
continue;
|
|
44
61
|
}
|
|
45
|
-
if (entry.
|
|
62
|
+
if (entry.kind === 'removed') {
|
|
63
|
+
answer.removals.add(entry.path);
|
|
46
64
|
continue;
|
|
47
|
-
const { continued: _continued, ...head } = open.entry;
|
|
48
|
-
whole.push({ ...head, text: open.texts.join('') });
|
|
49
|
-
open = null;
|
|
50
|
-
}
|
|
51
|
-
return open === null ? whole : null;
|
|
52
|
-
}
|
|
53
|
-
async function verified(entries) {
|
|
54
|
-
try {
|
|
55
|
-
for (const entry of entries) {
|
|
56
|
-
if (entry.text === undefined || entry.sha256 === undefined)
|
|
57
|
-
continue;
|
|
58
|
-
if ((await sha256Hex(entry.text)) !== entry.sha256)
|
|
59
|
-
return false;
|
|
60
65
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
const binary = binaryFileOf(entry);
|
|
67
|
+
if (binary === undefined)
|
|
68
|
+
answer.documents.set(entry.path, entry.text ?? '');
|
|
69
|
+
else if (binary !== null)
|
|
70
|
+
answer.binaryFiles.set(entry.path, binary);
|
|
71
|
+
if (binary === undefined && entry.facts !== undefined)
|
|
72
|
+
answer.facts.set(entry.path, entry.facts);
|
|
73
|
+
const revision = entry.revision ?? binary?.sha256;
|
|
74
|
+
if (revision !== undefined)
|
|
75
|
+
revised(answer, entry.path, revision);
|
|
76
|
+
const head = headChange(entry);
|
|
77
|
+
if (head)
|
|
78
|
+
answer.changes.set(entry.path, head);
|
|
79
|
+
const created = createdOf(entry);
|
|
80
|
+
if (created)
|
|
81
|
+
answer.created.set(entry.path, created);
|
|
65
82
|
}
|
|
83
|
+
return { kind: 'net-advancement', roomVersion: version, ...(yield* answered(answer)) };
|
|
66
84
|
}
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const text = last.text?.length ?? 0;
|
|
73
|
-
if (last.kind !== 'piece') {
|
|
74
|
-
return last.sha256 === undefined
|
|
75
|
-
? kept.resume
|
|
76
|
-
: { ...point, handled: frame.handled, piece: { sha256: last.sha256, offset: text } };
|
|
77
|
-
}
|
|
78
|
-
const piece = kept.resume?.piece ?? null;
|
|
79
|
-
if (piece === null)
|
|
80
|
-
return kept.resume;
|
|
81
|
-
const pieces = frame.entries.reduce((sum, entry) => sum + (entry.kind === 'piece' ? (entry.text?.length ?? 0) : 0), 0);
|
|
82
|
-
return {
|
|
83
|
-
...point,
|
|
84
|
-
handled: frame.handled,
|
|
85
|
-
piece: { sha256: piece.sha256, offset: piece.offset + pieces },
|
|
86
|
-
};
|
|
85
|
+
async function changePage(tracked, entries, version, mode, spaces, whole) {
|
|
86
|
+
const schemas = new Map();
|
|
87
|
+
const page = await stepped(changed(tracked, entries, version, schemas));
|
|
88
|
+
const models = await streamedModels(schemas, tracked, mode, spaces, whole);
|
|
89
|
+
return models === undefined ? page : { ...page, models };
|
|
87
90
|
}
|
|
88
|
-
export function houseNotifications(transport, mode) {
|
|
91
|
+
export function houseNotifications(transport, mode, discovering, spaces) {
|
|
89
92
|
const stream = transport.stream;
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
let loaded = Promise.resolve();
|
|
94
|
-
let acknowledging = null;
|
|
95
|
-
let receiving = Promise.resolve();
|
|
96
|
-
let verifying = 0;
|
|
97
|
-
const locators = new Map();
|
|
93
|
+
const staged = new Map();
|
|
94
|
+
let socket = null;
|
|
95
|
+
const tracking = new Map();
|
|
98
96
|
const observers = new Set();
|
|
97
|
+
const replaying = new Map();
|
|
99
98
|
const conversationObservers = new Set();
|
|
100
99
|
const modeObservers = new Set();
|
|
101
100
|
let replicated = [];
|
|
101
|
+
let listedCursor = null;
|
|
102
|
+
const unanswered = [];
|
|
103
|
+
const heldAtZero = new Set();
|
|
102
104
|
const live = new Set();
|
|
103
105
|
let opening = null;
|
|
106
|
+
let announced = null;
|
|
104
107
|
const runtime = crypto.randomUUID();
|
|
105
108
|
function emit(event) {
|
|
106
|
-
for (const observer of observers)
|
|
107
|
-
observer
|
|
109
|
+
for (const observer of observers) {
|
|
110
|
+
const held = replaying.get(observer);
|
|
111
|
+
if (held === undefined)
|
|
112
|
+
observer(event);
|
|
113
|
+
else
|
|
114
|
+
held.push(event);
|
|
115
|
+
}
|
|
108
116
|
}
|
|
109
117
|
function emitConversation(event) {
|
|
110
118
|
if (event.kind === 'turn' ||
|
|
111
119
|
event.kind === 'questions' ||
|
|
112
120
|
event.kind === 'process' ||
|
|
113
121
|
event.kind === 'commands' ||
|
|
114
|
-
event.kind === 'options'
|
|
122
|
+
event.kind === 'options' ||
|
|
123
|
+
event.kind === 'starting' ||
|
|
124
|
+
event.kind === 'subagents' ||
|
|
125
|
+
event.kind === 'link' ||
|
|
126
|
+
event.kind === 'deliveries') {
|
|
115
127
|
live.add(event.conversation);
|
|
116
128
|
}
|
|
117
129
|
for (const observer of conversationObservers)
|
|
@@ -119,12 +131,33 @@ export function houseNotifications(transport, mode) {
|
|
|
119
131
|
}
|
|
120
132
|
function reopened(next) {
|
|
121
133
|
opening = next;
|
|
122
|
-
|
|
134
|
+
announced = null;
|
|
135
|
+
socket = next;
|
|
136
|
+
staged.clear();
|
|
137
|
+
unanswered.length = 0;
|
|
138
|
+
heldAtZero.clear();
|
|
123
139
|
const gapped = new Set([...replicated, ...live]);
|
|
124
140
|
live.clear();
|
|
125
141
|
for (const conversation of gapped)
|
|
126
142
|
emitConversation({ kind: 'gap', conversation });
|
|
127
143
|
emit({ kind: 'opened' });
|
|
144
|
+
if (mode === 'site')
|
|
145
|
+
announce(next, null);
|
|
146
|
+
}
|
|
147
|
+
function announce(via, frame) {
|
|
148
|
+
void discovering.opened(frame).then((discovery) => {
|
|
149
|
+
if (socket !== via)
|
|
150
|
+
return;
|
|
151
|
+
if (discovery === null) {
|
|
152
|
+
via.close();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
announced = { kind: 'discovered', discovery };
|
|
156
|
+
emit(announced);
|
|
157
|
+
}, () => {
|
|
158
|
+
if (socket === via)
|
|
159
|
+
via.close();
|
|
160
|
+
});
|
|
128
161
|
}
|
|
129
162
|
function converse(frame) {
|
|
130
163
|
const conversation = frame.conversation_id;
|
|
@@ -143,6 +176,7 @@ export function houseNotifications(transport, mode) {
|
|
|
143
176
|
return;
|
|
144
177
|
emitConversation({ kind: 'commands', conversation, commands: [] });
|
|
145
178
|
emitConversation({ kind: 'options', conversation, options: [] });
|
|
179
|
+
emitConversation({ kind: 'subagents', conversation, subagents: [] });
|
|
146
180
|
return;
|
|
147
181
|
}
|
|
148
182
|
if (frame.type === 'commands') {
|
|
@@ -157,6 +191,26 @@ export function houseNotifications(transport, mode) {
|
|
|
157
191
|
emitConversation({ kind: 'options', conversation, options: structuredClone(frame.options) });
|
|
158
192
|
return;
|
|
159
193
|
}
|
|
194
|
+
if (frame.type === 'starting') {
|
|
195
|
+
emitConversation({ kind: 'starting', conversation, step: frame.step });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (frame.type === 'subagents') {
|
|
199
|
+
emitConversation({
|
|
200
|
+
kind: 'subagents',
|
|
201
|
+
conversation,
|
|
202
|
+
subagents: structuredClone(frame.subagents),
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (frame.type === 'link') {
|
|
207
|
+
emitConversation({ kind: 'link', conversation, connected: frame.connected });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (frame.type === 'deliveries') {
|
|
211
|
+
emitConversation({ kind: 'deliveries', conversation, unknown: [...frame.unknown] });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
160
214
|
if (frame.type === 'interactions') {
|
|
161
215
|
emitConversation({
|
|
162
216
|
kind: 'questions',
|
|
@@ -170,171 +224,31 @@ export function houseNotifications(transport, mode) {
|
|
|
170
224
|
return;
|
|
171
225
|
emitConversation({ kind: 'accepted-message', conversation, message });
|
|
172
226
|
}
|
|
173
|
-
function
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function interrupt(authority) {
|
|
180
|
-
const line = lines.get(authority);
|
|
181
|
-
if (line !== undefined)
|
|
182
|
-
lines.set(authority, { ...line, frames: [] });
|
|
183
|
-
}
|
|
184
|
-
async function forget(carries) {
|
|
185
|
-
const held = carries.filter((carry) => kept.delete(carry));
|
|
186
|
-
if (held.length > 0)
|
|
187
|
-
await receipts?.drop(held).catch(() => { });
|
|
188
|
-
}
|
|
189
|
-
async function lost(authority, carry) {
|
|
190
|
-
interrupt(authority);
|
|
191
|
-
await forget([carry]);
|
|
192
|
-
}
|
|
193
|
-
async function stage(frame, via) {
|
|
194
|
-
await loaded;
|
|
195
|
-
const port = receipts;
|
|
196
|
-
if (port === null)
|
|
197
|
-
return;
|
|
198
|
-
const held = kept.get(frame.carry);
|
|
199
|
-
if (held === undefined && frame.index !== 0) {
|
|
200
|
-
interrupt(frame.authority);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (held !== undefined &&
|
|
204
|
-
(held.fenced !== null || frame.index > held.parts || frame.index < (held.resume?.parts ?? 0))) {
|
|
205
|
-
await lost(frame.authority, frame.carry);
|
|
227
|
+
function stage(frame, via) {
|
|
228
|
+
const held = staged.get(frame.carry);
|
|
229
|
+
if (frame.index !== (held?.parts ?? 0)) {
|
|
230
|
+
staged.delete(frame.carry);
|
|
206
231
|
return;
|
|
207
232
|
}
|
|
208
233
|
if (held === undefined) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const start = held ?? {
|
|
214
|
-
authority: frame.authority,
|
|
215
|
-
carry: frame.carry,
|
|
216
|
-
logEpoch: lines.get(frame.authority)?.logEpoch ?? null,
|
|
217
|
-
after: frame.after,
|
|
218
|
-
parts: 0,
|
|
219
|
-
resume: null,
|
|
220
|
-
fenced: null,
|
|
221
|
-
};
|
|
222
|
-
const next = { ...start, parts: frame.index + 1, resume: resumed(start, frame) };
|
|
223
|
-
const part = { entries: frame.entries };
|
|
224
|
-
try {
|
|
225
|
-
await port.keep(frame.carry, next, { index: frame.index, value: part });
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
await lost(frame.authority, frame.carry);
|
|
229
|
-
return;
|
|
234
|
+
for (const [carry, other] of staged) {
|
|
235
|
+
if (other.authority === frame.authority)
|
|
236
|
+
staged.delete(carry);
|
|
237
|
+
}
|
|
230
238
|
}
|
|
231
|
-
|
|
239
|
+
const next = held ?? { authority: frame.authority, parts: 0, entries: [] };
|
|
240
|
+
keptSpaceSchemas(frame.entries, spaces);
|
|
241
|
+
next.entries.push(...frame.entries);
|
|
242
|
+
next.parts += 1;
|
|
243
|
+
staged.set(frame.carry, next);
|
|
232
244
|
via?.received(frame.authority, frame.carry, frame.index);
|
|
233
245
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (
|
|
238
|
-
return null;
|
|
239
|
-
const read = (await receipts.parts(carry, parts));
|
|
240
|
-
if (read.length !== parts)
|
|
241
|
-
return null;
|
|
242
|
-
const entries = assembled(read.flatMap((part) => part.entries));
|
|
243
|
-
return entries !== null && (await verified(entries)) ? entries : null;
|
|
244
|
-
}
|
|
245
|
-
async function carried(frame) {
|
|
246
|
-
await loaded;
|
|
247
|
-
const held = kept.get(frame.carry);
|
|
248
|
-
if (frame.parts > 0 && held?.parts !== frame.parts) {
|
|
249
|
-
await lost(frame.authority, frame.carry);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
const entries = await keptEntries(frame.carry, frame.parts).catch(() => null);
|
|
253
|
-
if (entries === null) {
|
|
254
|
-
await lost(frame.authority, frame.carry);
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
const fenced = {
|
|
258
|
-
...(held ?? {
|
|
259
|
-
authority: frame.authority,
|
|
260
|
-
carry: frame.carry,
|
|
261
|
-
logEpoch: frame.log_epoch,
|
|
262
|
-
after: frame.after,
|
|
263
|
-
parts: 0,
|
|
264
|
-
resume: null,
|
|
265
|
-
}),
|
|
266
|
-
after: frame.after,
|
|
267
|
-
fenced: { position: frame.position, logEpoch: frame.log_epoch },
|
|
268
|
-
};
|
|
269
|
-
try {
|
|
270
|
-
await receipts?.keep(frame.carry, fenced);
|
|
271
|
-
}
|
|
272
|
-
catch {
|
|
273
|
-
await lost(frame.authority, frame.carry);
|
|
246
|
+
function carried(frame) {
|
|
247
|
+
const held = staged.get(frame.carry);
|
|
248
|
+
staged.delete(frame.carry);
|
|
249
|
+
if ((held?.parts ?? 0) !== frame.parts)
|
|
274
250
|
return;
|
|
275
|
-
|
|
276
|
-
kept.set(frame.carry, fenced);
|
|
277
|
-
publish(frame, entries);
|
|
278
|
-
}
|
|
279
|
-
async function load(port) {
|
|
280
|
-
try {
|
|
281
|
-
for (const { key, head } of await port.heads())
|
|
282
|
-
kept.set(key, head);
|
|
283
|
-
}
|
|
284
|
-
catch {
|
|
285
|
-
kept.clear();
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
async function restored(room) {
|
|
289
|
-
const line = lines.get(room.authority);
|
|
290
|
-
let at = room.position;
|
|
291
|
-
const chain = [];
|
|
292
|
-
for (;;) {
|
|
293
|
-
const next = [...kept.values()].find((carry) => carry.authority === room.authority &&
|
|
294
|
-
carry.after === at &&
|
|
295
|
-
carry.fenced?.logEpoch === room.log_epoch);
|
|
296
|
-
if (next?.fenced == null)
|
|
297
|
-
break;
|
|
298
|
-
const entries = await keptEntries(next.carry, next.parts).catch(() => null);
|
|
299
|
-
if (entries === null)
|
|
300
|
-
break;
|
|
301
|
-
chain.push({ carry: next, entries });
|
|
302
|
-
at = next.fenced.position;
|
|
303
|
-
}
|
|
304
|
-
const partial = [...kept.values()].find((carry) => carry.authority === room.authority &&
|
|
305
|
-
carry.fenced === null &&
|
|
306
|
-
carry.logEpoch === room.log_epoch &&
|
|
307
|
-
carry.after === at &&
|
|
308
|
-
carry.resume !== null &&
|
|
309
|
-
carry.resume.parts > 0);
|
|
310
|
-
const stale = [...kept.values()].filter((carry) => carry.authority === room.authority &&
|
|
311
|
-
carry !== partial &&
|
|
312
|
-
!chain.some((link) => link.carry === carry));
|
|
313
|
-
await forget(stale.map((carry) => carry.carry));
|
|
314
|
-
if (line !== undefined && line.logEpoch === room.log_epoch && chain.length > 0) {
|
|
315
|
-
const frames = chain.map(({ carry, entries }) => ({
|
|
316
|
-
after: BigInt(carry.after),
|
|
317
|
-
position: BigInt(carry.fenced.position),
|
|
318
|
-
entries,
|
|
319
|
-
}));
|
|
320
|
-
lines.set(room.authority, { ...line, frames: [...line.frames, ...frames] });
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
...room,
|
|
324
|
-
position: at,
|
|
325
|
-
...(partial?.resume == null
|
|
326
|
-
? {}
|
|
327
|
-
: {
|
|
328
|
-
carry: {
|
|
329
|
-
id: partial.carry,
|
|
330
|
-
parts: partial.resume.parts,
|
|
331
|
-
from: partial.resume.from,
|
|
332
|
-
target: partial.resume.target,
|
|
333
|
-
handled: partial.resume.handled,
|
|
334
|
-
...(partial.resume.piece === null ? {} : { piece: partial.resume.piece }),
|
|
335
|
-
},
|
|
336
|
-
}),
|
|
337
|
-
};
|
|
251
|
+
publish(frame, held?.entries ?? []);
|
|
338
252
|
}
|
|
339
253
|
function handle(frame, via) {
|
|
340
254
|
if (frame.type === 'signal') {
|
|
@@ -346,14 +260,35 @@ export function houseNotifications(transport, mode) {
|
|
|
346
260
|
return;
|
|
347
261
|
}
|
|
348
262
|
if (frame.type === 'opening') {
|
|
263
|
+
if (via !== null && mode === 'credential')
|
|
264
|
+
announce(via, frame);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (frame.type === 'caught_up') {
|
|
268
|
+
discovering.expired?.(frame.expired);
|
|
349
269
|
emit({
|
|
350
|
-
kind: '
|
|
351
|
-
expired:
|
|
270
|
+
kind: 'caught-up',
|
|
271
|
+
expired: [
|
|
272
|
+
...frame.expired.flatMap((authority) => (tracking.get(authority) ?? []).map((tracked) => tracked.locator)),
|
|
273
|
+
...(unanswered.shift() ?? []),
|
|
274
|
+
],
|
|
352
275
|
});
|
|
353
276
|
return;
|
|
354
277
|
}
|
|
278
|
+
if (frame.type === 'authority_changed') {
|
|
279
|
+
const change = discovering.changed(frame);
|
|
280
|
+
if (change !== null)
|
|
281
|
+
emit(change);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
355
284
|
if (frame.type === 'conversations') {
|
|
356
|
-
emitConversation({
|
|
285
|
+
emitConversation({
|
|
286
|
+
kind: 'list',
|
|
287
|
+
entries: frame.conversations.map(listedConversation),
|
|
288
|
+
whole: frame.whole,
|
|
289
|
+
more: frame.more,
|
|
290
|
+
cursor: frame.cursor,
|
|
291
|
+
});
|
|
357
292
|
return;
|
|
358
293
|
}
|
|
359
294
|
if (frame.type === 'conversation') {
|
|
@@ -368,63 +303,49 @@ export function houseNotifications(transport, mode) {
|
|
|
368
303
|
frame.type === 'process' ||
|
|
369
304
|
frame.type === 'commands' ||
|
|
370
305
|
frame.type === 'options' ||
|
|
306
|
+
frame.type === 'starting' ||
|
|
307
|
+
frame.type === 'subagents' ||
|
|
308
|
+
frame.type === 'link' ||
|
|
309
|
+
frame.type === 'deliveries' ||
|
|
371
310
|
frame.type === 'interactions' ||
|
|
372
311
|
frame.type === 'message') {
|
|
373
312
|
converse(frame);
|
|
374
313
|
return;
|
|
375
314
|
}
|
|
376
315
|
if (frame.type === 'part')
|
|
377
|
-
|
|
378
|
-
if (frame.type === 'carried')
|
|
379
|
-
|
|
316
|
+
stage(frame, via);
|
|
317
|
+
else if (frame.type === 'carried')
|
|
318
|
+
carried(frame);
|
|
380
319
|
}
|
|
381
320
|
function publish(frame, entries) {
|
|
382
321
|
const at = position(frame.position);
|
|
383
322
|
const after = position(frame.after);
|
|
384
|
-
if (at === null || after === null || after >= at)
|
|
385
|
-
interrupt(frame.authority);
|
|
323
|
+
if (at === null || after === null || after >= at)
|
|
386
324
|
return;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
interrupt(frame.authority);
|
|
401
|
-
}
|
|
402
|
-
announce(frame.authority, { position: frame.position, logEpoch: frame.log_epoch });
|
|
403
|
-
}
|
|
404
|
-
stream.observe((frame) => {
|
|
405
|
-
const via = acknowledging;
|
|
406
|
-
if (verifying === 0) {
|
|
407
|
-
const handled = handle(frame, via);
|
|
408
|
-
if (handled === undefined)
|
|
409
|
-
return;
|
|
410
|
-
verifying += 1;
|
|
411
|
-
receiving = handled.finally(() => {
|
|
412
|
-
verifying -= 1;
|
|
325
|
+
const from = after === 0n && !heldAtZero.has(frame.authority)
|
|
326
|
+
? null
|
|
327
|
+
: roomVersion({ position: frame.after, logEpoch: frame.log_epoch });
|
|
328
|
+
const version = roomVersion({ position: frame.position, logEpoch: frame.log_epoch });
|
|
329
|
+
for (const tracked of tracking.get(frame.authority) ?? []) {
|
|
330
|
+
emit({
|
|
331
|
+
kind: 'room-change',
|
|
332
|
+
locator: tracked.locator,
|
|
333
|
+
from,
|
|
334
|
+
roomVersion: version,
|
|
335
|
+
read: () => changePage(tracked, entries, version, mode, spaces, from === null),
|
|
413
336
|
});
|
|
414
|
-
return;
|
|
415
337
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
.then(() => handle(frame, via))
|
|
419
|
-
.finally(() => {
|
|
420
|
-
verifying -= 1;
|
|
421
|
-
});
|
|
422
|
-
});
|
|
338
|
+
}
|
|
339
|
+
stream.observe((frame) => handle(frame, socket));
|
|
423
340
|
stream.opened(reopened);
|
|
424
|
-
stream.closed(({ revoked, lost }) => {
|
|
341
|
+
stream.closed(({ revoked, lost, authorityChanged }) => {
|
|
425
342
|
opening = null;
|
|
426
|
-
|
|
427
|
-
|
|
343
|
+
announced = null;
|
|
344
|
+
socket = null;
|
|
345
|
+
staged.clear();
|
|
346
|
+
unanswered.length = 0;
|
|
347
|
+
heldAtZero.clear();
|
|
348
|
+
emit({ kind: 'closed', revoked, lost, authorityChanged });
|
|
428
349
|
});
|
|
429
350
|
return {
|
|
430
351
|
runtime,
|
|
@@ -440,175 +361,94 @@ export function houseNotifications(transport, mode) {
|
|
|
440
361
|
replicate(next) {
|
|
441
362
|
replicated = [...next];
|
|
442
363
|
},
|
|
364
|
+
hold(cursor) {
|
|
365
|
+
listedCursor = cursor;
|
|
366
|
+
},
|
|
443
367
|
observe(notify) {
|
|
444
368
|
conversationObservers.add(notify);
|
|
445
369
|
return () => {
|
|
446
370
|
conversationObservers.delete(notify);
|
|
447
371
|
};
|
|
448
372
|
},
|
|
373
|
+
...(mode === 'credential'
|
|
374
|
+
? {
|
|
375
|
+
agents: () => houseAgents(transport),
|
|
376
|
+
history: (request) => houseHistory(transport, request),
|
|
377
|
+
}
|
|
378
|
+
: {}),
|
|
449
379
|
},
|
|
450
|
-
observe(notify
|
|
380
|
+
observe(notify) {
|
|
451
381
|
observers.add(notify);
|
|
452
|
-
if (receipts === null) {
|
|
453
|
-
receipts = port;
|
|
454
|
-
loaded = load(port);
|
|
455
|
-
}
|
|
456
382
|
if (opening !== null) {
|
|
383
|
+
const replayed = [{ kind: 'opened' }];
|
|
384
|
+
if (announced !== null)
|
|
385
|
+
replayed.push(announced);
|
|
386
|
+
replaying.set(notify, replayed);
|
|
457
387
|
queueMicrotask(() => {
|
|
458
|
-
|
|
459
|
-
|
|
388
|
+
replaying.delete(notify);
|
|
389
|
+
for (const event of replayed)
|
|
390
|
+
if (observers.has(notify))
|
|
391
|
+
notify(event);
|
|
460
392
|
});
|
|
461
393
|
}
|
|
462
394
|
return () => {
|
|
463
395
|
observers.delete(notify);
|
|
464
396
|
};
|
|
465
397
|
},
|
|
466
|
-
send(rooms
|
|
467
|
-
for (const room of rooms) {
|
|
468
|
-
const line = lines.get(room.authority);
|
|
469
|
-
const held = position(room.position);
|
|
470
|
-
if (line === undefined || held === null || line.logEpoch !== room.log_epoch)
|
|
471
|
-
continue;
|
|
472
|
-
lines.set(room.authority, { ...line, frames: [], held });
|
|
473
|
-
}
|
|
474
|
-
const current = opening;
|
|
398
|
+
send(rooms) {
|
|
475
399
|
opening = null;
|
|
476
|
-
|
|
400
|
+
announced = null;
|
|
401
|
+
if (socket === null)
|
|
477
402
|
return;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
.
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if (room.position === rooms[index].position)
|
|
484
|
-
continue;
|
|
485
|
-
announce(room.authority, { position: room.position, logEpoch: room.log_epoch });
|
|
486
|
-
}
|
|
403
|
+
const entries = new Map([...tracking.values()].flat().map((tracked) => [tracked.locator, tracked]));
|
|
404
|
+
const named = rooms.flatMap((room) => {
|
|
405
|
+
const entry = entries.get(room.locator);
|
|
406
|
+
const at = room.roomVersion === null ? null : logPosition(room.roomVersion);
|
|
407
|
+
return entry === undefined || at === null ? [] : [{ entry, at }];
|
|
487
408
|
});
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
409
|
+
const unheld = rooms.flatMap((room) => {
|
|
410
|
+
const entry = entries.get(room.locator);
|
|
411
|
+
return entry === undefined || room.roomVersion !== null ? [] : [entry];
|
|
412
|
+
});
|
|
413
|
+
for (const { entry, at } of named) {
|
|
414
|
+
if (at.position === '0')
|
|
415
|
+
heldAtZero.add(entry.authority);
|
|
416
|
+
else
|
|
417
|
+
heldAtZero.delete(entry.authority);
|
|
418
|
+
}
|
|
419
|
+
for (const entry of unheld)
|
|
420
|
+
heldAtZero.delete(entry.authority);
|
|
421
|
+
const site = mode === 'site';
|
|
422
|
+
unanswered.push(site ? unheld.map((entry) => entry.locator) : []);
|
|
423
|
+
socket.hold([
|
|
424
|
+
...named.map(({ entry, at }) => presented(entry.authority, at)),
|
|
425
|
+
...(site ? [] : unheld).map((entry) => presented(entry.authority, { position: '0', logEpoch: entry.logEpoch })),
|
|
426
|
+
], runtime, listedCursor);
|
|
427
|
+
if (site)
|
|
493
428
|
return;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
429
|
+
const made = unheld.filter((entry) => entry.position === '0');
|
|
430
|
+
queueMicrotask(() => {
|
|
431
|
+
for (const entry of made) {
|
|
432
|
+
const version = roomVersion(entry);
|
|
433
|
+
emit({
|
|
434
|
+
kind: 'room-change',
|
|
435
|
+
locator: entry.locator,
|
|
436
|
+
from: null,
|
|
437
|
+
roomVersion: version,
|
|
438
|
+
read: () => changePage(entry, [], version, mode, spaces, true),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
505
442
|
},
|
|
506
443
|
track(entries) {
|
|
507
|
-
|
|
444
|
+
tracking.clear();
|
|
508
445
|
for (const entry of entries) {
|
|
509
|
-
|
|
510
|
-
if (lines.get(entry.authority)?.logEpoch !== entry.logEpoch) {
|
|
511
|
-
lines.set(entry.authority, { logEpoch: entry.logEpoch, frames: [], held: null });
|
|
512
|
-
}
|
|
446
|
+
tracking.set(entry.authority, [...(tracking.get(entry.authority) ?? []), entry]);
|
|
513
447
|
}
|
|
514
|
-
for (const
|
|
515
|
-
if (!
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
void loaded.then(() => forget([...kept.values()]
|
|
519
|
-
.filter((carry) => !locators.has(carry.authority))
|
|
520
|
-
.map((carry) => carry.carry)));
|
|
521
|
-
},
|
|
522
|
-
reach(authority, at) {
|
|
523
|
-
const line = lines.get(authority);
|
|
524
|
-
const held = position(at.position);
|
|
525
|
-
if (line === undefined || held === null || line.logEpoch !== at.logEpoch)
|
|
526
|
-
return;
|
|
527
|
-
if (line.held !== null && held <= line.held)
|
|
528
|
-
return;
|
|
529
|
-
lines.set(authority, {
|
|
530
|
-
...line,
|
|
531
|
-
frames: line.frames.filter((frame) => frame.position > held),
|
|
532
|
-
held,
|
|
533
|
-
});
|
|
534
|
-
},
|
|
535
|
-
advance(tracked, from, holds) {
|
|
536
|
-
const line = lines.get(tracked.authority);
|
|
537
|
-
const start = position(from.position);
|
|
538
|
-
if (line === undefined || start === null || line.logEpoch !== from.logEpoch)
|
|
539
|
-
return null;
|
|
540
|
-
const pending = line.frames.filter((frame) => frame.position > start);
|
|
541
|
-
const first = pending[0];
|
|
542
|
-
if (first === undefined || first.after > start)
|
|
543
|
-
return null;
|
|
544
|
-
const documents = {};
|
|
545
|
-
const revisions = {};
|
|
546
|
-
const changes = {};
|
|
547
|
-
const binaryFiles = {};
|
|
548
|
-
const removals = [];
|
|
549
|
-
const applied = [];
|
|
550
|
-
const schemas = new Map();
|
|
551
|
-
const forget = (path) => {
|
|
552
|
-
delete documents[path];
|
|
553
|
-
delete revisions[path];
|
|
554
|
-
delete changes[path];
|
|
555
|
-
delete binaryFiles[path];
|
|
556
|
-
const removed = removals.indexOf(path);
|
|
557
|
-
if (removed !== -1)
|
|
558
|
-
removals.splice(removed, 1);
|
|
559
|
-
};
|
|
560
|
-
for (const frame of pending) {
|
|
561
|
-
for (const entry of frame.entries) {
|
|
562
|
-
if (entry.kind === 'edited' &&
|
|
563
|
-
entry.revision !== undefined &&
|
|
564
|
-
holds?.(entry.path, entry.revision) === true) {
|
|
565
|
-
forget(entry.path);
|
|
566
|
-
continue;
|
|
567
|
-
}
|
|
568
|
-
applied.push(entry);
|
|
569
|
-
if (tracked.schemas.includes(entry.path))
|
|
570
|
-
schemas.set(entry.path, entry);
|
|
571
|
-
if (entry.kind === 'removed') {
|
|
572
|
-
forget(entry.path);
|
|
573
|
-
removals.push(entry.path);
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
const binary = binaryFileOf(entry);
|
|
577
|
-
if (binary === null || (binary === undefined && entry.text === undefined))
|
|
578
|
-
return null;
|
|
579
|
-
if (mode === 'credential' && entry.revision === undefined)
|
|
580
|
-
return null;
|
|
581
|
-
const head = headChange(entry);
|
|
582
|
-
if (head === null)
|
|
583
|
-
return null;
|
|
584
|
-
forget(entry.path);
|
|
585
|
-
if (binary === undefined)
|
|
586
|
-
documents[entry.path] = entry.text;
|
|
587
|
-
else
|
|
588
|
-
binaryFiles[entry.path] = binary;
|
|
589
|
-
const revision = entry.revision ?? binary?.sha256;
|
|
590
|
-
if (revision !== undefined)
|
|
591
|
-
revisions[entry.path] = revision;
|
|
592
|
-
if (head !== undefined)
|
|
593
|
-
changes[entry.path] = head;
|
|
594
|
-
}
|
|
448
|
+
for (const [carry, held] of staged) {
|
|
449
|
+
if (!tracking.has(held.authority))
|
|
450
|
+
staged.delete(carry);
|
|
595
451
|
}
|
|
596
|
-
const last = pending.at(-1);
|
|
597
|
-
lines.set(tracked.authority, { ...line, frames: pending, held: last.position });
|
|
598
|
-
return {
|
|
599
|
-
page: {
|
|
600
|
-
kind: 'net-advancement',
|
|
601
|
-
roomVersion: roomVersion({ position: last.position.toString(), logEpoch: line.logEpoch }),
|
|
602
|
-
documents,
|
|
603
|
-
revisions,
|
|
604
|
-
...identities(revisions),
|
|
605
|
-
changes,
|
|
606
|
-
binaryFiles,
|
|
607
|
-
removals: removals.sort(),
|
|
608
|
-
},
|
|
609
|
-
entries: applied,
|
|
610
|
-
schemas,
|
|
611
|
-
};
|
|
612
452
|
},
|
|
613
453
|
};
|
|
614
454
|
}
|