crbro-memory 2.4.0 → 2.5.0
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 +42 -3
- package/bin/crbro.mjs +234 -0
- package/dist/daemon/daemon.d.ts +25 -0
- package/dist/daemon/daemon.d.ts.map +1 -0
- package/dist/daemon/daemon.js +387 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/daemon/endpoint.d.ts +65 -0
- package/dist/daemon/endpoint.d.ts.map +1 -0
- package/dist/daemon/endpoint.js +308 -0
- package/dist/daemon/endpoint.js.map +1 -0
- package/dist/daemon/lines.d.ts +55 -0
- package/dist/daemon/lines.d.ts.map +1 -0
- package/dist/daemon/lines.js +142 -0
- package/dist/daemon/lines.js.map +1 -0
- package/dist/daemon/proxy.d.ts +55 -0
- package/dist/daemon/proxy.d.ts.map +1 -0
- package/dist/daemon/proxy.js +412 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/engine/backup.d.ts +68 -0
- package/dist/engine/backup.d.ts.map +1 -0
- package/dist/engine/backup.js +224 -0
- package/dist/engine/backup.js.map +1 -0
- package/dist/engine/brain.d.ts.map +1 -1
- package/dist/engine/brain.js +6 -2
- package/dist/engine/brain.js.map +1 -1
- package/dist/engine/cortex.d.ts +76 -2
- package/dist/engine/cortex.d.ts.map +1 -1
- package/dist/engine/cortex.js +169 -9
- package/dist/engine/cortex.js.map +1 -1
- package/dist/engine/dates.d.ts +28 -0
- package/dist/engine/dates.d.ts.map +1 -0
- package/dist/engine/dates.js +121 -0
- package/dist/engine/dates.js.map +1 -0
- package/dist/engine/maintenance.d.ts +85 -0
- package/dist/engine/maintenance.d.ts.map +1 -1
- package/dist/engine/maintenance.js +340 -0
- package/dist/engine/maintenance.js.map +1 -1
- package/dist/engine/triggers.d.ts +46 -0
- package/dist/engine/triggers.d.ts.map +1 -0
- package/dist/engine/triggers.js +198 -0
- package/dist/engine/triggers.js.map +1 -0
- package/dist/index.js +33 -5
- package/dist/index.js.map +1 -1
- package/dist/search/index.d.ts +56 -3
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +244 -12
- package/dist/search/index.js.map +1 -1
- package/dist/server.d.ts +32 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +151 -19
- package/dist/server.js.map +1 -1
- package/hooks/crbro-guard.mjs +155 -0
- package/package.json +1 -1
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── The proxy: what a client actually launches in daemon mode ────
|
|
3
|
+
//
|
|
4
|
+
// An MCP client starts `crbro-memory` and speaks JSON-RPC on stdio, as it
|
|
5
|
+
// always has. In daemon mode that process loads no index and no model: it
|
|
6
|
+
// finds the daemon (or starts it), proves who it is, and from then on copies
|
|
7
|
+
// lines — client to daemon, daemon to client. It reads each line only to keep
|
|
8
|
+
// three things it needs on the worst day:
|
|
9
|
+
//
|
|
10
|
+
// · the client's `initialize`, so that if the daemon dies the handshake can
|
|
11
|
+
// be replayed against its replacement without the client ever knowing;
|
|
12
|
+
// · which requests are in flight, so each gets an error instead of a
|
|
13
|
+
// silence that would hang the conversation until a timeout;
|
|
14
|
+
// · nothing else.
|
|
15
|
+
//
|
|
16
|
+
// And if no daemon can be had at all, the backend is a server inside this
|
|
17
|
+
// process — CRBRO exactly as it was before 2.5. The daemon is an optimisation;
|
|
18
|
+
// the memory is not allowed to depend on it.
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.connectDaemon = connectDaemon;
|
|
24
|
+
exports.controlDaemon = controlDaemon;
|
|
25
|
+
exports.spawnDetachedDaemon = spawnDetachedDaemon;
|
|
26
|
+
exports.runProxy = runProxy;
|
|
27
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
28
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
29
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
30
|
+
const node_child_process_1 = require("node:child_process");
|
|
31
|
+
const lines_js_1 = require("./lines.js");
|
|
32
|
+
const endpoint_js_1 = require("./endpoint.js");
|
|
33
|
+
const CONNECT_TIMEOUT_MS = 1_500;
|
|
34
|
+
const HANDSHAKE_TIMEOUT_MS = 4_000;
|
|
35
|
+
const SPAWN_WAIT_MS = 12_000;
|
|
36
|
+
const POLL_MS = 200;
|
|
37
|
+
/** Daemon connections lost inside this window before the proxy stops trusting daemons for the rest of its life. */
|
|
38
|
+
const FLAP_WINDOW_MS = 60_000;
|
|
39
|
+
const FLAP_LIMIT = 3;
|
|
40
|
+
/** After the client closes its end: how long calls already accepted may take to finish before we leave anyway. */
|
|
41
|
+
const DRAIN_TIMEOUT_MS = 30_000;
|
|
42
|
+
/**
|
|
43
|
+
* Connect to the daemon of this brain and build, and get through the
|
|
44
|
+
* handshake. Null on any failure; 'config-mismatch' when the daemon is
|
|
45
|
+
* genuine but was started with settings that are not this client's.
|
|
46
|
+
*/
|
|
47
|
+
async function connectDaemon(brainRoot, build = (0, endpoint_js_1.buildId)(), options = {}) {
|
|
48
|
+
const state = await (0, endpoint_js_1.readState)(brainRoot, build);
|
|
49
|
+
if (!state)
|
|
50
|
+
return null;
|
|
51
|
+
const socket = await new Promise(resolve => {
|
|
52
|
+
const s = node_net_1.default.connect(state.endpoint);
|
|
53
|
+
const t = setTimeout(() => { s.destroy(); resolve(null); }, CONNECT_TIMEOUT_MS);
|
|
54
|
+
s.once('connect', () => { clearTimeout(t); resolve(s); });
|
|
55
|
+
s.once('error', () => { clearTimeout(t); resolve(null); });
|
|
56
|
+
});
|
|
57
|
+
if (!socket)
|
|
58
|
+
return null;
|
|
59
|
+
socket.setNoDelay(true);
|
|
60
|
+
let sink = () => undefined;
|
|
61
|
+
const lines = new lines_js_1.LineReader(line => sink(line), () => socket.destroy());
|
|
62
|
+
socket.on('data', chunk => lines.push(typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : chunk));
|
|
63
|
+
socket.on('error', () => undefined);
|
|
64
|
+
const next = () => new Promise(resolve => {
|
|
65
|
+
const t = setTimeout(() => resolve(null), HANDSHAKE_TIMEOUT_MS);
|
|
66
|
+
const done = (v) => { clearTimeout(t); socket.off('close', onClose); resolve(v); };
|
|
67
|
+
const onClose = () => done(null);
|
|
68
|
+
socket.once('close', onClose);
|
|
69
|
+
sink = line => { sink = () => undefined; try {
|
|
70
|
+
done(JSON.parse(line));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
done(null);
|
|
74
|
+
} };
|
|
75
|
+
});
|
|
76
|
+
const fail = () => { socket.destroy(); return null; };
|
|
77
|
+
const nonce = (0, endpoint_js_1.newNonce)();
|
|
78
|
+
socket.write(`${JSON.stringify({ crbro: 'hello', protocol: endpoint_js_1.DAEMON_PROTOCOL, nonce })}\n`);
|
|
79
|
+
const hello = await next();
|
|
80
|
+
// The daemon proves itself FIRST: a process that merely took the pipe's name learns nothing from us.
|
|
81
|
+
if (!hello || hello.crbro !== 'hello' || !(0, endpoint_js_1.sameProof)(String(hello.proof || ''), (0, endpoint_js_1.proof)(state.token, 'daemon', nonce)))
|
|
82
|
+
return fail();
|
|
83
|
+
// Its nonce is what our proof is bound to: one we could be talked into reusing is no nonce at all.
|
|
84
|
+
if (typeof hello.nonce !== 'string' || !/^[0-9a-f]{32,128}$/.test(hello.nonce) || hello.nonce === nonce)
|
|
85
|
+
return fail();
|
|
86
|
+
if (options.checkConfig !== false && typeof hello.config === 'string' && hello.config !== (0, endpoint_js_1.configFingerprint)()) {
|
|
87
|
+
socket.destroy();
|
|
88
|
+
return 'config-mismatch';
|
|
89
|
+
}
|
|
90
|
+
socket.write(`${JSON.stringify({ crbro: 'auth', proof: (0, endpoint_js_1.proof)(state.token, 'client', hello.nonce), ...(options.resumed ? { resumed: true } : {}) })}\n`);
|
|
91
|
+
const ready = await next();
|
|
92
|
+
if (!ready || ready.crbro !== 'ready')
|
|
93
|
+
return fail();
|
|
94
|
+
return { socket, reader: on => { sink = on; }, state, hello };
|
|
95
|
+
}
|
|
96
|
+
/** One control exchange: `status` or `stop`. Null when there is no daemon to talk to. */
|
|
97
|
+
async function controlDaemon(brainRoot, op, build) {
|
|
98
|
+
const c = await connectDaemon(brainRoot, build, { checkConfig: false });
|
|
99
|
+
if (!c || c === 'config-mismatch')
|
|
100
|
+
return null;
|
|
101
|
+
return new Promise(resolve => {
|
|
102
|
+
const t = setTimeout(() => { c.socket.destroy(); resolve(null); }, HANDSHAKE_TIMEOUT_MS);
|
|
103
|
+
c.reader(line => { clearTimeout(t); try {
|
|
104
|
+
resolve(JSON.parse(line));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
resolve(null);
|
|
108
|
+
} c.socket.end(); });
|
|
109
|
+
c.socket.write(`${JSON.stringify({ crbro: 'control', op })}\n`);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** The production way to start a daemon: detached, silent, surviving this process. */
|
|
113
|
+
function spawnDetachedDaemon(brainRoot) {
|
|
114
|
+
const entry = node_path_1.default.join(__dirname, '..', 'index.js');
|
|
115
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [entry, '--daemon'], {
|
|
116
|
+
detached: true, stdio: 'ignore', windowsHide: true,
|
|
117
|
+
// Not the client's working directory: on Windows a process pins its cwd,
|
|
118
|
+
// and the project the client was opened in could not be renamed or
|
|
119
|
+
// deleted for as long as the daemon lived.
|
|
120
|
+
cwd: node_os_1.default.homedir(),
|
|
121
|
+
env: { ...process.env, CRBRO_PATH: brainRoot, CRBRO_DAEMON: '' },
|
|
122
|
+
});
|
|
123
|
+
child.on('error', () => undefined);
|
|
124
|
+
child.unref();
|
|
125
|
+
}
|
|
126
|
+
/** 'unusable': a daemon exists but is not for us, or cannot be had — do not wait for one, and do not ask again. */
|
|
127
|
+
async function daemonBackend(o, ev, resumed) {
|
|
128
|
+
const build = o.build ?? (0, endpoint_js_1.buildId)();
|
|
129
|
+
let c = await connectDaemon(o.brainRoot, build, { resumed });
|
|
130
|
+
if (!c && o.spawnDaemon) {
|
|
131
|
+
const since = Date.now() - 1_000;
|
|
132
|
+
try {
|
|
133
|
+
await o.spawnDaemon();
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
o.log?.(`could not start a daemon: ${err.message}`);
|
|
137
|
+
}
|
|
138
|
+
const until = Date.now() + (o.spawnWaitMs ?? SPAWN_WAIT_MS);
|
|
139
|
+
while (!c && Date.now() < until) {
|
|
140
|
+
await new Promise(r => setTimeout(r, POLL_MS));
|
|
141
|
+
c = await connectDaemon(o.brainRoot, build, { resumed });
|
|
142
|
+
if (!c) {
|
|
143
|
+
const why = await (0, endpoint_js_1.blockedSince)(o.brainRoot, build, since);
|
|
144
|
+
if (why) {
|
|
145
|
+
o.log?.(`the daemon could not take its endpoint (${why}): serving from this process`);
|
|
146
|
+
return 'unusable';
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (c === 'config-mismatch') {
|
|
152
|
+
o.log?.('a daemon is running with other settings than this client\'s (CRBRO_SEMANTIC, CRBRO_BACKUP_DIR…): serving from this process so they keep their meaning');
|
|
153
|
+
return 'unusable';
|
|
154
|
+
}
|
|
155
|
+
if (!c)
|
|
156
|
+
return null;
|
|
157
|
+
const { socket, reader } = c;
|
|
158
|
+
let closing = false;
|
|
159
|
+
reader(ev.onLine);
|
|
160
|
+
socket.on('close', () => { if (!closing)
|
|
161
|
+
ev.onClose(); });
|
|
162
|
+
return {
|
|
163
|
+
kind: 'daemon',
|
|
164
|
+
send: line => { if (!socket.destroyed)
|
|
165
|
+
socket.write(`${line}\n`); },
|
|
166
|
+
// Wait for the pipe to really close: the caller exits the process next, and
|
|
167
|
+
// an exit right after end() can cut the last write on a Windows pipe.
|
|
168
|
+
close: () => new Promise(resolve => {
|
|
169
|
+
closing = true;
|
|
170
|
+
if (socket.destroyed)
|
|
171
|
+
return resolve();
|
|
172
|
+
socket.once('close', () => resolve());
|
|
173
|
+
socket.end();
|
|
174
|
+
setTimeout(() => { socket.destroy(); resolve(); }, 2_000).unref();
|
|
175
|
+
}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** CRBRO as it was before daemons: the whole server, in this process. */
|
|
179
|
+
async function localBackend(ev, resumed) {
|
|
180
|
+
const { createEngines, createServer } = await import('../server.js');
|
|
181
|
+
const { sessionScope, newTally } = await import('../engine/cortex.js');
|
|
182
|
+
const engines = createEngines();
|
|
183
|
+
const transport = new lines_js_1.LoopbackTransport(ev.onLine);
|
|
184
|
+
await createServer(engines).connect(transport);
|
|
185
|
+
// After a lost daemon this server starts with an empty tally that the
|
|
186
|
+
// conversation's earlier writes are not in: mark it, so consolidate says so.
|
|
187
|
+
const scope = resumed ? { tally: newTally(), resumed: true } : null;
|
|
188
|
+
return {
|
|
189
|
+
kind: 'local',
|
|
190
|
+
send: line => (scope ? sessionScope.run(scope, () => transport.receive(line)) : transport.receive(line)),
|
|
191
|
+
close: async () => {
|
|
192
|
+
await new Promise(r => setImmediate(r)); // let a notification that was just delivered run
|
|
193
|
+
try {
|
|
194
|
+
await engines.searchEngine.flush();
|
|
195
|
+
}
|
|
196
|
+
catch { /* derived data */ }
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function runProxy(o) {
|
|
201
|
+
const log = o.log ?? (() => undefined);
|
|
202
|
+
const isEnabled = o.isEnabled ?? (() => true);
|
|
203
|
+
const makeLocal = o.local ?? localBackend;
|
|
204
|
+
let backend = null;
|
|
205
|
+
let connecting = true;
|
|
206
|
+
let inputEnded = false; // the client closed its end: no more requests, but what it asked for is still owed
|
|
207
|
+
let ended = false; // we are done: nothing more is written, nothing more is started
|
|
208
|
+
let reconnects = 0;
|
|
209
|
+
let trustDaemons = true;
|
|
210
|
+
const losses = [];
|
|
211
|
+
let initialize = null;
|
|
212
|
+
let initialized = null;
|
|
213
|
+
const inflight = new Set();
|
|
214
|
+
const waiting = []; // client lines held while there is no usable backend
|
|
215
|
+
let replayId = null; // id of the initialize we are replaying, while its answer is pending
|
|
216
|
+
let replays = 0;
|
|
217
|
+
let drainTimer = null;
|
|
218
|
+
let resolveClosed;
|
|
219
|
+
let rejectClosed;
|
|
220
|
+
const closed = new Promise((res, rej) => { resolveClosed = res; rejectClosed = rej; });
|
|
221
|
+
const toClient = (line) => { if (!ended)
|
|
222
|
+
o.output.write(`${line}\n`); };
|
|
223
|
+
/** Leave — but only once every call the client made has been answered and written out. */
|
|
224
|
+
const maybeFinish = () => {
|
|
225
|
+
if (ended || !inputEnded || connecting || waiting.length > 0 || inflight.size > 0)
|
|
226
|
+
return;
|
|
227
|
+
void shutdown();
|
|
228
|
+
};
|
|
229
|
+
const shutdown = async () => {
|
|
230
|
+
if (ended)
|
|
231
|
+
return;
|
|
232
|
+
if (drainTimer)
|
|
233
|
+
clearTimeout(drainTimer);
|
|
234
|
+
try {
|
|
235
|
+
await backend?.close();
|
|
236
|
+
}
|
|
237
|
+
catch { /* leaving anyway */ }
|
|
238
|
+
// stdout on a Windows pipe is asynchronous: the caller exits the process
|
|
239
|
+
// next, and the last answer must be out of our hands before it does.
|
|
240
|
+
await new Promise(resolve => { try {
|
|
241
|
+
o.output.write('', () => resolve());
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
resolve();
|
|
245
|
+
} });
|
|
246
|
+
ended = true;
|
|
247
|
+
resolveClosed();
|
|
248
|
+
};
|
|
249
|
+
const fromBackend = (line) => {
|
|
250
|
+
let m = null;
|
|
251
|
+
try {
|
|
252
|
+
m = JSON.parse(line);
|
|
253
|
+
}
|
|
254
|
+
catch { /* not ours to judge: pass it on */ }
|
|
255
|
+
if (m && replayId !== null && m.id === replayId && m.method === undefined) {
|
|
256
|
+
// The replacement answered the replayed handshake. The client already
|
|
257
|
+
// has the original answer; this one stops here.
|
|
258
|
+
replayId = null;
|
|
259
|
+
if (initialized && backend)
|
|
260
|
+
backend.send(initialized);
|
|
261
|
+
connecting = false;
|
|
262
|
+
drain();
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (m && m.id !== undefined && m.id !== null && m.method === undefined)
|
|
266
|
+
inflight.delete(m.id);
|
|
267
|
+
toClient(line);
|
|
268
|
+
maybeFinish();
|
|
269
|
+
};
|
|
270
|
+
const drain = () => {
|
|
271
|
+
while (backend && !connecting && waiting.length)
|
|
272
|
+
backend.send(waiting.shift());
|
|
273
|
+
maybeFinish();
|
|
274
|
+
};
|
|
275
|
+
const fromClient = (line) => {
|
|
276
|
+
let m = null;
|
|
277
|
+
try {
|
|
278
|
+
m = JSON.parse(line);
|
|
279
|
+
}
|
|
280
|
+
catch { /* the backend will answer the parse error */ }
|
|
281
|
+
if (m?.method === 'initialize')
|
|
282
|
+
initialize = m;
|
|
283
|
+
else if (m?.method === 'notifications/initialized')
|
|
284
|
+
initialized = line;
|
|
285
|
+
if (m && m.method !== undefined && m.id !== undefined && m.id !== null)
|
|
286
|
+
inflight.add(m.id);
|
|
287
|
+
if (backend && !connecting)
|
|
288
|
+
backend.send(line);
|
|
289
|
+
else
|
|
290
|
+
waiting.push(line);
|
|
291
|
+
};
|
|
292
|
+
const events = {
|
|
293
|
+
onLine: fromBackend,
|
|
294
|
+
onClose: () => { void lost(); },
|
|
295
|
+
};
|
|
296
|
+
/** No backend of any kind could be had. Say so on every call that is owed an answer, and stop — as the classic server does when it cannot start. */
|
|
297
|
+
const fatal = (err) => {
|
|
298
|
+
if (ended)
|
|
299
|
+
return;
|
|
300
|
+
log(`no backend could be started: ${err.message}`);
|
|
301
|
+
const ids = new Set(inflight);
|
|
302
|
+
for (const l of waiting) {
|
|
303
|
+
try {
|
|
304
|
+
const q = JSON.parse(l);
|
|
305
|
+
if (q?.method !== undefined && q.id !== undefined && q.id !== null)
|
|
306
|
+
ids.add(q.id);
|
|
307
|
+
}
|
|
308
|
+
catch { /* not a request */ }
|
|
309
|
+
}
|
|
310
|
+
for (const id of ids)
|
|
311
|
+
toClient(JSON.stringify({ jsonrpc: '2.0', id, error: { code: -32000, message: `CRBRO could not start: ${err.message}` } }));
|
|
312
|
+
inflight.clear();
|
|
313
|
+
waiting.length = 0;
|
|
314
|
+
ended = true;
|
|
315
|
+
rejectClosed(err);
|
|
316
|
+
};
|
|
317
|
+
async function acquire(first) {
|
|
318
|
+
connecting = true;
|
|
319
|
+
backend = null;
|
|
320
|
+
let b = null;
|
|
321
|
+
// Asked every time, not once at launch: `crbro daemon off` removes the
|
|
322
|
+
// flag and stops the daemon, and a proxy that only knew how to respawn one
|
|
323
|
+
// undid it within 200 ms.
|
|
324
|
+
if (trustDaemons && isEnabled()) {
|
|
325
|
+
const d = await daemonBackend(o, events, !first);
|
|
326
|
+
if (d === 'unusable')
|
|
327
|
+
trustDaemons = false;
|
|
328
|
+
else
|
|
329
|
+
b = d;
|
|
330
|
+
}
|
|
331
|
+
if (!b) {
|
|
332
|
+
if (trustDaemons && isEnabled())
|
|
333
|
+
log('no daemon reachable: serving from this process');
|
|
334
|
+
b = await makeLocal(events, !first);
|
|
335
|
+
}
|
|
336
|
+
if (ended) {
|
|
337
|
+
await b.close();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
backend = b;
|
|
341
|
+
if (!first && initialize) {
|
|
342
|
+
// Same request the client once sent, under an id of our own.
|
|
343
|
+
replayId = `crbro-replay-${++replays}`;
|
|
344
|
+
b.send(JSON.stringify({ ...initialize, id: replayId }));
|
|
345
|
+
return; // `connecting` stays true until the replayed handshake is answered
|
|
346
|
+
}
|
|
347
|
+
connecting = false;
|
|
348
|
+
drain();
|
|
349
|
+
}
|
|
350
|
+
async function lost() {
|
|
351
|
+
if (ended)
|
|
352
|
+
return;
|
|
353
|
+
reconnects++;
|
|
354
|
+
const now = Date.now();
|
|
355
|
+
losses.push(now);
|
|
356
|
+
while (losses.length && now - losses[0] > FLAP_WINDOW_MS)
|
|
357
|
+
losses.shift();
|
|
358
|
+
if (losses.length >= FLAP_LIMIT) {
|
|
359
|
+
trustDaemons = false;
|
|
360
|
+
log('daemon lost three times in a minute: staying in-process');
|
|
361
|
+
}
|
|
362
|
+
// Whatever was waiting for an answer will not get one from a dead process.
|
|
363
|
+
// What never left this proxy is not in that position: it is still queued,
|
|
364
|
+
// and answering it here too would hand the client two replies to one id.
|
|
365
|
+
const queued = new Set();
|
|
366
|
+
for (const line of waiting) {
|
|
367
|
+
try {
|
|
368
|
+
const q = JSON.parse(line);
|
|
369
|
+
if (q?.id !== undefined && q.id !== null)
|
|
370
|
+
queued.add(q.id);
|
|
371
|
+
}
|
|
372
|
+
catch { /* not a request */ }
|
|
373
|
+
}
|
|
374
|
+
for (const id of [...inflight]) {
|
|
375
|
+
if (queued.has(id))
|
|
376
|
+
continue;
|
|
377
|
+
inflight.delete(id);
|
|
378
|
+
toClient(JSON.stringify({ jsonrpc: '2.0', id, error: { code: -32000, message: 'CRBRO restarted while this call was running. Nothing was lost on disk; call it again.' } }));
|
|
379
|
+
}
|
|
380
|
+
replayId = null;
|
|
381
|
+
backend = null;
|
|
382
|
+
// The client has gone and is owed nothing more: a replacement would serve nobody.
|
|
383
|
+
if (inputEnded && waiting.length === 0 && inflight.size === 0) {
|
|
384
|
+
connecting = false;
|
|
385
|
+
void shutdown();
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
await acquire(false);
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
fatal(err);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const reader = new lines_js_1.LineReader(fromClient, () => undefined);
|
|
396
|
+
o.input.on('data', (chunk) => reader.push(typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : chunk));
|
|
397
|
+
const onInputEnd = () => {
|
|
398
|
+
if (inputEnded)
|
|
399
|
+
return;
|
|
400
|
+
inputEnded = true;
|
|
401
|
+
// A client that sends its last crbro_learn and closes stdin at once is
|
|
402
|
+
// still owed that write and its answer — the classic server gives both.
|
|
403
|
+
drainTimer = setTimeout(() => { log('gave up waiting for the last answers'); void shutdown(); }, o.drainTimeoutMs ?? DRAIN_TIMEOUT_MS);
|
|
404
|
+
drainTimer.unref();
|
|
405
|
+
maybeFinish();
|
|
406
|
+
};
|
|
407
|
+
o.input.on('end', onInputEnd);
|
|
408
|
+
o.input.on('close', onInputEnd);
|
|
409
|
+
void acquire(true).catch(err => fatal(err));
|
|
410
|
+
return { closed, backendKind: () => (backend ? backend.kind : 'none'), reconnects: () => reconnects };
|
|
411
|
+
}
|
|
412
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/daemon/proxy.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,0CAA0C;AAC1C,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,uEAAuE;AACvE,gEAAgE;AAChE,oBAAoB;AACpB,EAAE;AACF,0EAA0E;AAC1E,+EAA+E;AAC/E,6CAA6C;;;;;AAgE7C,sCA+CC;AAGD,sCAQC;AAGD,kDAYC;AA+DD,4BAiKC;AAvWD,wDAA2B;AAC3B,sDAAyB;AACzB,0DAA6B;AAC7B,2DAA2C;AAE3C,yCAA2D;AAC3D,+CAEuB;AAEvB,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,aAAa,GAAG,MAAM,CAAC;AAC7B,MAAM,OAAO,GAAG,GAAG,CAAC;AACpB,mHAAmH;AACnH,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,kHAAkH;AAClH,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAuChC;;;;GAIG;AACI,KAAK,UAAU,aAAa,CACjC,SAAiB,EACjB,QAAgB,IAAA,qBAAO,GAAE,EACzB,UAAwD,EAAE;IAE1D,MAAM,KAAK,GAAG,MAAM,IAAA,uBAAS,EAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAoB,OAAO,CAAC,EAAE;QAC5D,MAAM,CAAC,GAAG,kBAAG,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAChF,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAExB,IAAI,IAAI,GAA2B,GAAG,EAAE,CAAC,SAAS,CAAC;IACnD,MAAM,KAAK,GAAG,IAAI,qBAAU,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACvG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAEpC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,OAAO,CAAa,OAAO,CAAC,EAAE;QACnD,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,CAAC,CAAa,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/F,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAG,IAAA,sBAAQ,GAAE,CAAC;IACzB,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,6BAAe,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;IAC3B,qGAAqG;IACrG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,IAAA,uBAAS,EAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,IAAA,mBAAK,EAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IACnI,mGAAmG;IACnG,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,EAAE,CAAC;IACvH,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,IAAA,+BAAiB,GAAE,EAAE,CAAC;QAC9G,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAA,mBAAK,EAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACxJ,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO;QAAE,OAAO,IAAI,EAAE,CAAC;IAErD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAChE,CAAC;AAED,yFAAyF;AAClF,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,EAAqB,EAAE,KAAc;IAC1F,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACxE,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;QACzF,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnH,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sFAAsF;AACtF,SAAgB,mBAAmB,CAAC,SAAiB;IACnD,MAAM,KAAK,GAAG,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,IAAA,0BAAK,EAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE;QACzD,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI;QAClD,yEAAyE;QACzE,mEAAmE;QACnE,2CAA2C;QAC3C,GAAG,EAAE,iBAAE,CAAC,OAAO,EAAE;QACjB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE;KACjE,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,mHAAmH;AACnH,KAAK,UAAU,aAAa,CAAC,CAAe,EAAE,EAAiB,EAAE,OAAgB;IAC/E,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,IAAA,qBAAO,GAAE,CAAC;IACnC,IAAI,CAAC,GAAG,MAAM,aAAa,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACjC,IAAI,CAAC;YAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAAC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,CAAC,CAAC,GAAG,EAAE,CAAC,6BAA8B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAAC,CAAC;QAC9G,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,aAAa,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;YAChC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC/C,CAAC,GAAG,MAAM,aAAa,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YACzD,IAAI,CAAC,CAAC,EAAE,CAAC;gBACP,MAAM,GAAG,GAAG,MAAM,IAAA,0BAAY,EAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;gBAC1D,IAAI,GAAG,EAAE,CAAC;oBAAC,CAAC,CAAC,GAAG,EAAE,CAAC,2CAA2C,GAAG,8BAA8B,CAAC,CAAC;oBAAC,OAAO,UAAU,CAAC;gBAAC,CAAC;YACxH,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,KAAK,iBAAiB,EAAE,CAAC;QAC5B,CAAC,CAAC,GAAG,EAAE,CAAC,uJAAuJ,CAAC,CAAC;QACjK,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO;QAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,4EAA4E;QAC5E,sEAAsE;QACtE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;YACvC,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,MAAM,CAAC,SAAS;gBAAE,OAAO,OAAO,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,EAAE,CAAC;YACb,UAAU,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;QACpE,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,KAAK,UAAU,YAAY,CAAC,EAAiB,EAAE,OAAgB;IAC7D,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IACrE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,4BAAiB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/C,sEAAsE;IACtE,6EAA6E;IAC7E,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxG,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAG,iDAAiD;YAC5F,IAAI,CAAC;gBAAC,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAC1E,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAgB,QAAQ,CAAC,CAAe;IACtC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC;IAC1C,IAAI,OAAO,GAAmB,IAAI,CAAC;IACnC,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,IAAI,UAAU,GAAG,KAAK,CAAC,CAAG,mFAAmF;IAC7G,IAAI,KAAK,GAAG,KAAK,CAAC,CAAQ,gEAAgE;IAC1F,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,YAAY,GAAG,IAAI,CAAC;IACxB,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,UAAU,GAAe,IAAI,CAAC;IAClC,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC5C,MAAM,OAAO,GAAa,EAAE,CAAC,CAAU,qDAAqD;IAC5F,IAAI,QAAQ,GAAkB,IAAI,CAAC,CAAI,qEAAqE;IAC5G,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,UAAU,GAA0B,IAAI,CAAC;IAE7C,IAAI,aAA0B,CAAC;IAC/B,IAAI,YAAiC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,aAAa,GAAG,GAAG,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7F,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK;QAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhF,0FAA0F;IAC1F,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,KAAK,IAAI,CAAC,UAAU,IAAI,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC;YAAE,OAAO;QAC1F,KAAK,QAAQ,EAAE,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,KAAK;YAAE,OAAO;QAClB,IAAI,UAAU;YAAE,YAAY,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC;YAAC,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC9D,yEAAyE;QACzE,qEAAqE;QACrE,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;YAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,KAAK,GAAG,IAAI,CAAC;QACb,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,CAAC,GAAQ,IAAI,CAAC;QAClB,IAAI,CAAC;YAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,mCAAmC,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1E,sEAAsE;YACtE,gDAAgD;YAChD,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,WAAW,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACtD,UAAU,GAAG,KAAK,CAAC;YACnB,KAAK,EAAE,CAAC;YACR,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9F,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,OAAO,OAAO,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC,CAAC;QAChF,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,CAAC,GAAQ,IAAI,CAAC;QAClB,IAAI,CAAC;YAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,6CAA6C,CAAC,CAAC;QACrF,IAAI,CAAC,EAAE,MAAM,KAAK,YAAY;YAAE,UAAU,GAAG,CAAC,CAAC;aAC1C,IAAI,CAAC,EAAE,MAAM,KAAK,2BAA2B;YAAE,WAAW,GAAG,IAAI,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3F,IAAI,OAAO,IAAI,CAAC,UAAU;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YAC1C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,MAAM,GAAkB;QAC5B,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;KAChC,CAAC;IAEF,oJAAoJ;IACpJ,MAAM,KAAK,GAAG,CAAC,GAAU,EAAE,EAAE;QAC3B,IAAI,KAAK;YAAE,OAAO;QAClB,GAAG,CAAC,gCAAgC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAkB,QAAQ,CAAC,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YAAC,IAAI,CAAC;gBAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;oBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAAC,CAAC;QAC9K,KAAK,MAAM,EAAE,IAAI,GAAG;YAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,0BAA0B,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAClJ,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,KAAK,GAAG,IAAI,CAAC;QACb,YAAY,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,KAAK,UAAU,OAAO,CAAC,KAAc;QACnC,UAAU,GAAG,IAAI,CAAC;QAClB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC,GAAmB,IAAI,CAAC;QAC7B,uEAAuE;QACvE,2EAA2E;QAC3E,0BAA0B;QAC1B,IAAI,YAAY,IAAI,SAAS,EAAE,EAAE,CAAC;YAChC,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,CAAC,KAAK,UAAU;gBAAE,YAAY,GAAG,KAAK,CAAC;;gBACtC,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;QACD,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,IAAI,YAAY,IAAI,SAAS,EAAE;gBAAE,GAAG,CAAC,gDAAgD,CAAC,CAAC;YACvF,CAAC,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QACvC,OAAO,GAAG,CAAC,CAAC;QACZ,IAAI,CAAC,KAAK,IAAI,UAAU,EAAE,CAAC;YACzB,6DAA6D;YAC7D,QAAQ,GAAG,gBAAgB,EAAE,OAAO,EAAE,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YACxD,OAAO,CAAG,mEAAmE;QAC/E,CAAC;QACD,UAAU,GAAG,KAAK,CAAC;QACnB,KAAK,EAAE,CAAC;IACV,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,IAAI,KAAK;YAAE,OAAO;QAClB,UAAU,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc;YAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACzE,IAAI,MAAM,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;YAAC,YAAY,GAAG,KAAK,CAAC;YAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAAC,CAAC;QAC1H,2EAA2E;QAC3E,0EAA0E;QAC1E,yEAAyE;QACzE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;QAC1C,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAAC,IAAI,CAAC;gBAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAAC,IAAI,CAAC,EAAE,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAAC,CAAC;QAC7J,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,uFAAuF,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9K,CAAC;QACD,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,GAAG,IAAI,CAAC;QACf,kFAAkF;QAClF,IAAI,UAAU,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAAC,UAAU,GAAG,KAAK,CAAC;YAAC,KAAK,QAAQ,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAC/G,IAAI,CAAC;YAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,KAAK,CAAC,GAAY,CAAC,CAAC;QAAC,CAAC;IACpE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,qBAAU,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5H,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,UAAU;YAAE,OAAO;QACvB,UAAU,GAAG,IAAI,CAAC;QAClB,uEAAuE;QACvE,wEAAwE;QACxE,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,sCAAsC,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,IAAI,gBAAgB,CAAC,CAAC;QACvI,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC;IACF,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC9B,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAEhC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAY,CAAC,CAAC,CAAC;IAErD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;AACxG,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { BrainPaths } from './brain.js';
|
|
2
|
+
export declare const BACKUP_FORMAT = 1;
|
|
3
|
+
export declare const DEFAULT_KEEP = 7;
|
|
4
|
+
/** consolidate makes one on its own when the newest is older than this. */
|
|
5
|
+
export declare const AUTO_BACKUP_INTERVAL_MS: number;
|
|
6
|
+
export interface BackupBundle {
|
|
7
|
+
format: number;
|
|
8
|
+
created: string;
|
|
9
|
+
brain_path: string;
|
|
10
|
+
counts: {
|
|
11
|
+
files: number;
|
|
12
|
+
neurons: number;
|
|
13
|
+
sessions: number;
|
|
14
|
+
synapses: number;
|
|
15
|
+
bytes: number;
|
|
16
|
+
};
|
|
17
|
+
/** POSIX-style relative path → file content. */
|
|
18
|
+
files: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export interface BackupInfo {
|
|
21
|
+
file: string;
|
|
22
|
+
path: string;
|
|
23
|
+
created: string;
|
|
24
|
+
size_bytes: number;
|
|
25
|
+
}
|
|
26
|
+
export interface BackupResult extends BackupInfo {
|
|
27
|
+
counts: BackupBundle['counts'];
|
|
28
|
+
rotated_out: string[];
|
|
29
|
+
dir: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Where backups go: a sibling of the brain they belong to — `~/.crbro` →
|
|
33
|
+
* `~/.crbro-backups/brain`.
|
|
34
|
+
*
|
|
35
|
+
* Outside the brain, so deleting the brain does not delete its backups. And
|
|
36
|
+
* derived from the brain's own path rather than fixed under the home folder,
|
|
37
|
+
* because rotation keeps the newest N of whatever is in the folder: two brains
|
|
38
|
+
* (CRBRO_PATH, or a test's temporary one) sharing a folder would rotate each
|
|
39
|
+
* other's backups out.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveBackupDir(brainRoot: string, env?: NodeJS.ProcessEnv, home?: string): string;
|
|
42
|
+
export declare function listBackups(dir: string): Promise<BackupInfo[]>;
|
|
43
|
+
export declare function createBackup(paths: BrainPaths, opts?: {
|
|
44
|
+
dir?: string;
|
|
45
|
+
keep?: number;
|
|
46
|
+
now?: Date;
|
|
47
|
+
}): Promise<BackupResult>;
|
|
48
|
+
export declare function readBackup(file: string): Promise<BackupBundle>;
|
|
49
|
+
/**
|
|
50
|
+
* Unpack a backup into a directory that must not already hold a brain.
|
|
51
|
+
* Never writes over a live brain: swapping directories is a decision a person
|
|
52
|
+
* makes with both of them in front of them.
|
|
53
|
+
*/
|
|
54
|
+
export declare function restoreBackup(file: string, into: string): Promise<{
|
|
55
|
+
into: string;
|
|
56
|
+
files: number;
|
|
57
|
+
}>;
|
|
58
|
+
/** Called by consolidate: a backup nobody has to remember to make. Never throws. */
|
|
59
|
+
export declare function autoBackupIfDue(paths: BrainPaths, opts?: {
|
|
60
|
+
dir?: string;
|
|
61
|
+
now?: Date;
|
|
62
|
+
env?: NodeJS.ProcessEnv;
|
|
63
|
+
}): Promise<{
|
|
64
|
+
made: boolean;
|
|
65
|
+
reason: string;
|
|
66
|
+
file?: string;
|
|
67
|
+
}>;
|
|
68
|
+
//# sourceMappingURL=backup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../src/engine/backup.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKxC,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,QAAsB,CAAC;AAO3D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9F,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAqB,GAC1B,MAAM,CAOR;AA8BD,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAkBpE;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CAAO,GACrD,OAAO,CAAC,YAAY,CAAC,CA4CvB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAUpE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBxG;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CACnC,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,GAC/D,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAe3D"}
|