sensemaking 0.24.4 → 0.24.6
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 +16 -12
- package/dist/cjs/cli/status.js +14 -24
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/search.js +22 -0
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/lib/watch-notification.d.cts +1 -0
- package/dist/cjs/lib/watch-notification.d.ts +1 -0
- package/dist/cjs/lib/watch-notification.js +15 -0
- package/dist/cjs/lib/watch-notification.js.map +1 -0
- package/dist/cjs/lib/worker-file.d.cts +1 -0
- package/dist/cjs/lib/worker-file.d.ts +1 -0
- package/dist/cjs/lib/worker-file.js +34 -0
- package/dist/cjs/lib/worker-file.js.map +1 -0
- package/dist/cjs/output/search-error.js +38 -0
- package/dist/cjs/output/search-error.js.map +1 -1
- package/dist/cjs/scan/pool.js +2 -23
- package/dist/cjs/scan/pool.js.map +1 -1
- package/dist/cjs/store/builder.d.cts +2 -1
- package/dist/cjs/store/builder.d.ts +2 -1
- package/dist/cjs/store/builder.js +4 -4
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/duckdb/lexical.d.cts +1 -0
- package/dist/cjs/store/duckdb/lexical.d.ts +1 -0
- package/dist/cjs/store/duckdb/lexical.js +28 -9
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +2 -0
- package/dist/cjs/store/duckdb/native.d.ts +2 -0
- package/dist/cjs/store/duckdb/native.js +11 -1
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/ordered-bm25.d.cts +17 -0
- package/dist/cjs/store/duckdb/ordered-bm25.d.ts +17 -0
- package/dist/cjs/store/duckdb/ordered-bm25.js +238 -0
- package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -0
- package/dist/cjs/store/lock-wait.d.cts +2 -2
- package/dist/cjs/store/lock-wait.d.ts +2 -2
- package/dist/cjs/store/lock-wait.js +14 -11
- package/dist/cjs/store/lock-wait.js.map +1 -1
- package/dist/cjs/store/native.d.cts +4 -0
- package/dist/cjs/store/native.d.ts +4 -0
- package/dist/cjs/store/native.js +64 -9
- package/dist/cjs/store/native.js.map +1 -1
- package/dist/cjs/store/open.js +11 -7
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/reconcile.d.cts +5 -1
- package/dist/cjs/store/reconcile.d.ts +5 -1
- package/dist/cjs/store/reconcile.js +5 -4
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/turso/lexical.js +5 -1
- package/dist/cjs/store/turso/lexical.js.map +1 -1
- package/dist/cjs/text/segment.js +168 -3
- package/dist/cjs/text/segment.js.map +1 -1
- package/dist/cjs/watch-claim.d.cts +39 -0
- package/dist/cjs/watch-claim.d.ts +39 -0
- package/dist/cjs/watch-claim.js +446 -0
- package/dist/cjs/watch-claim.js.map +1 -0
- package/dist/cjs/watch.js +246 -147
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/watch-heartbeat.d.cts +1 -0
- package/dist/cjs/workers/watch-heartbeat.d.ts +1 -0
- package/dist/cjs/workers/watch-heartbeat.js +308 -0
- package/dist/cjs/workers/watch-heartbeat.js.map +1 -0
- package/dist/esm/cli/status.js +6 -5
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/search.js +21 -0
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/lib/watch-notification.d.ts +1 -0
- package/dist/esm/lib/watch-notification.js +4 -0
- package/dist/esm/lib/watch-notification.js.map +1 -0
- package/dist/esm/lib/worker-file.d.ts +1 -0
- package/dist/esm/lib/worker-file.js +24 -0
- package/dist/esm/lib/worker-file.js.map +1 -0
- package/dist/esm/output/search-error.js +21 -0
- package/dist/esm/output/search-error.js.map +1 -1
- package/dist/esm/scan/pool.js +2 -22
- package/dist/esm/scan/pool.js.map +1 -1
- package/dist/esm/store/builder.d.ts +2 -1
- package/dist/esm/store/builder.js +4 -4
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/duckdb/lexical.d.ts +1 -0
- package/dist/esm/store/duckdb/lexical.js +16 -7
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +2 -0
- package/dist/esm/store/duckdb/native.js +5 -1
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/ordered-bm25.d.ts +17 -0
- package/dist/esm/store/duckdb/ordered-bm25.js +56 -0
- package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -0
- package/dist/esm/store/lock-wait.d.ts +2 -2
- package/dist/esm/store/lock-wait.js +17 -14
- package/dist/esm/store/lock-wait.js.map +1 -1
- package/dist/esm/store/native.d.ts +4 -0
- package/dist/esm/store/native.js +60 -6
- package/dist/esm/store/native.js.map +1 -1
- package/dist/esm/store/open.js +9 -6
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/reconcile.d.ts +5 -1
- package/dist/esm/store/reconcile.js +4 -3
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/turso/lexical.js +5 -1
- package/dist/esm/store/turso/lexical.js.map +1 -1
- package/dist/esm/text/segment.js +130 -4
- package/dist/esm/text/segment.js.map +1 -1
- package/dist/esm/watch-claim.d.ts +39 -0
- package/dist/esm/watch-claim.js +176 -0
- package/dist/esm/watch-claim.js.map +1 -0
- package/dist/esm/watch.js +169 -118
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/watch-heartbeat.d.ts +1 -0
- package/dist/esm/workers/watch-heartbeat.js +106 -0
- package/dist/esm/workers/watch-heartbeat.js.map +1 -0
- package/package.json +2 -2
- package/skills/sense/SKILL.md +105 -104
- package/skills/sense/references/search.md +47 -0
- package/skills/sense/references/sql.md +120 -0
- package/skills/sense/references/stores/duckdb.md +35 -0
- package/skills/sense/references/stores/sqlite.md +66 -0
- package/skills/sense/references/stores/turso.md +36 -0
- package/skills/sense-setup/SKILL.md +93 -34
- package/skills/sense-setup/references/embeddings.md +51 -0
- package/skills/sense-setup/references/store-benchmarks.md +16 -0
- package/skills/sense-setup/references/stores/duckdb.md +28 -0
- package/skills/sense-setup/references/stores/sqlite.md +21 -0
- package/skills/sense-setup/references/stores/turso.md +25 -0
package/dist/cjs/watch.js
CHANGED
|
@@ -9,10 +9,11 @@ Object.defineProperty(exports, "runWatch", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
var _nodefs = require("node:fs");
|
|
12
|
-
var _indexts = require("./config/index.js");
|
|
13
12
|
var _errorsts = require("./errors.js");
|
|
14
13
|
var _guardedtickts = require("./lib/guarded-tick.js");
|
|
15
|
-
var
|
|
14
|
+
var _watchnotificationts = require("./lib/watch-notification.js");
|
|
15
|
+
var _indexts = require("./store/index.js");
|
|
16
|
+
var _watchclaimts = require("./watch-claim.js");
|
|
16
17
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
17
18
|
try {
|
|
18
19
|
var info = gen[key](arg);
|
|
@@ -39,6 +40,12 @@ function _async_to_generator(fn) {
|
|
|
39
40
|
});
|
|
40
41
|
};
|
|
41
42
|
}
|
|
43
|
+
function _instanceof(left, right) {
|
|
44
|
+
"@swc/helpers - instanceof";
|
|
45
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
46
|
+
return !!right[Symbol.hasInstance](left);
|
|
47
|
+
} else return left instanceof right;
|
|
48
|
+
}
|
|
42
49
|
function _ts_generator(thisArg, body) {
|
|
43
50
|
var f, y, t, _ = {
|
|
44
51
|
label: 0,
|
|
@@ -140,11 +147,9 @@ function _ts_generator(thisArg, body) {
|
|
|
140
147
|
}
|
|
141
148
|
// Watch is a cache pre-warmer, not a correctness mechanism: open() always reconciles anyway, so any fs event just triggers a debounced full reconcile.
|
|
142
149
|
var DEBOUNCE_MS = 200;
|
|
143
|
-
var HEARTBEAT_INTERVAL_MS = 5000;
|
|
144
|
-
var STALE_HEARTBEAT_MS = 15000;
|
|
145
150
|
function runWatch(_0) {
|
|
146
151
|
return _async_to_generator(function(cfg) {
|
|
147
|
-
var opts, _opts_onEvent, _opts_debounceMs, _opts_heartbeatIntervalMs, _cfg_rootDir, onEvent, debounceMs,
|
|
152
|
+
var opts, _opts_onEvent, _opts_debounceMs, _opts_heartbeatIntervalMs, _cfg_rootDir, _cfg_configDir, _opts_force, onEvent, debounceMs, reconcileIntervalMs, claimIntervalMs, rootDir, configDir, claimFailure, requestShutdown, claim, claimCloseStarted, closeClaim, _ref, initialStore, dbPath, initialWarnings, initialParsed, initialTotal, _tmp, stopping, running, queuedAlways, tick, startCycle, requestCycle, debounceTimer, scheduleReconcile, watcher, reconcileTimer, err, closeError;
|
|
148
153
|
var _arguments = arguments;
|
|
149
154
|
return _ts_generator(this, function(_state) {
|
|
150
155
|
switch(_state.label){
|
|
@@ -152,45 +157,57 @@ function runWatch(_0) {
|
|
|
152
157
|
opts = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
|
|
153
158
|
onEvent = (_opts_onEvent = opts.onEvent) !== null && _opts_onEvent !== void 0 ? _opts_onEvent : function() {};
|
|
154
159
|
debounceMs = (_opts_debounceMs = opts.debounceMs) !== null && _opts_debounceMs !== void 0 ? _opts_debounceMs : DEBOUNCE_MS;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
];
|
|
160
|
-
case 1:
|
|
161
|
-
_ref = _state.sent(), initialStore = _ref.store, dbPath = _ref.dbPath, initialWarnings = _ref.warnings, initialParsed = _ref.parsed;
|
|
162
|
-
// openStore normalizes the legacy direct-API baseDir before a watcher touches the filesystem.
|
|
160
|
+
reconcileIntervalMs = (_opts_heartbeatIntervalMs = opts.heartbeatIntervalMs) !== null && _opts_heartbeatIntervalMs !== void 0 ? _opts_heartbeatIntervalMs : _watchclaimts.WATCH_HEARTBEAT_INTERVAL_MS;
|
|
161
|
+
if (!Number.isFinite(reconcileIntervalMs) || reconcileIntervalMs <= 0) throw new _errorsts.SenseError('CONFIG_INVALID', 'watch heartbeatIntervalMs must be a finite positive number');
|
|
162
|
+
// Reconciliation may be parked for a caller, but live ownership must renew before fixed expiry.
|
|
163
|
+
claimIntervalMs = Math.min(reconcileIntervalMs, _watchclaimts.WATCH_HEARTBEAT_INTERVAL_MS);
|
|
163
164
|
rootDir = (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir;
|
|
165
|
+
configDir = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : rootDir;
|
|
166
|
+
claimFailure = null;
|
|
164
167
|
return [
|
|
165
168
|
4,
|
|
166
|
-
(0,
|
|
169
|
+
(0, _watchclaimts.startWatchClaim)(configDir, (_opts_force = opts.force) !== null && _opts_force !== void 0 ? _opts_force : false, claimIntervalMs, function(err) {
|
|
170
|
+
claimFailure !== null && claimFailure !== void 0 ? claimFailure : claimFailure = err;
|
|
171
|
+
requestShutdown === null || requestShutdown === void 0 ? void 0 : requestShutdown(err);
|
|
172
|
+
})
|
|
167
173
|
];
|
|
174
|
+
case 1:
|
|
175
|
+
claim = _state.sent();
|
|
176
|
+
claimCloseStarted = false;
|
|
177
|
+
closeClaim = function closeClaim() {
|
|
178
|
+
claimCloseStarted = true;
|
|
179
|
+
return claim.close();
|
|
180
|
+
};
|
|
181
|
+
_state.label = 2;
|
|
168
182
|
case 2:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!(age >= 0 && age < STALE_HEARTBEAT_MS)) return [
|
|
176
|
-
3,
|
|
177
|
-
4
|
|
178
|
-
];
|
|
183
|
+
_state.trys.push([
|
|
184
|
+
2,
|
|
185
|
+
12,
|
|
186
|
+
17,
|
|
187
|
+
18
|
|
188
|
+
]);
|
|
179
189
|
return [
|
|
180
190
|
4,
|
|
181
|
-
|
|
191
|
+
(0, _indexts.openStore)(cfg)
|
|
182
192
|
];
|
|
183
193
|
case 3:
|
|
184
|
-
_state.sent();
|
|
185
|
-
|
|
194
|
+
_ref = _state.sent(), initialStore = _ref.store, dbPath = _ref.dbPath, initialWarnings = _ref.warnings, initialParsed = _ref.parsed;
|
|
195
|
+
initialTotal = 0;
|
|
196
|
+
_state.label = 4;
|
|
186
197
|
case 4:
|
|
198
|
+
_state.trys.push([
|
|
199
|
+
4,
|
|
200
|
+
,
|
|
201
|
+
8,
|
|
202
|
+
10
|
|
203
|
+
]);
|
|
187
204
|
if (!(initialWarnings.length > 0 || initialParsed > 0)) return [
|
|
188
205
|
3,
|
|
189
206
|
6
|
|
190
207
|
];
|
|
191
208
|
return [
|
|
192
209
|
4,
|
|
193
|
-
(0,
|
|
210
|
+
(0, _indexts.docCount)(initialStore)
|
|
194
211
|
];
|
|
195
212
|
case 5:
|
|
196
213
|
_tmp = _state.sent();
|
|
@@ -202,38 +219,24 @@ function runWatch(_0) {
|
|
|
202
219
|
_tmp = 0;
|
|
203
220
|
_state.label = 7;
|
|
204
221
|
case 7:
|
|
222
|
+
// total is read before close: an event fires only once nothing is held open again.
|
|
205
223
|
initialTotal = _tmp;
|
|
206
224
|
return [
|
|
207
|
-
|
|
208
|
-
|
|
225
|
+
3,
|
|
226
|
+
10
|
|
209
227
|
];
|
|
210
228
|
case 8:
|
|
211
|
-
_state.sent();
|
|
212
229
|
return [
|
|
213
230
|
4,
|
|
214
|
-
|
|
231
|
+
initialStore.close()
|
|
215
232
|
];
|
|
216
233
|
case 9:
|
|
217
234
|
_state.sent();
|
|
218
235
|
return [
|
|
219
|
-
|
|
220
|
-
initialStore.close()
|
|
236
|
+
7
|
|
221
237
|
];
|
|
222
238
|
case 10:
|
|
223
|
-
|
|
224
|
-
onEvent({
|
|
225
|
-
type: 'started',
|
|
226
|
-
rootDir: rootDir,
|
|
227
|
-
dbPath: dbPath
|
|
228
|
-
});
|
|
229
|
-
if (initialWarnings.length > 0 || initialParsed > 0) {
|
|
230
|
-
onEvent({
|
|
231
|
-
type: 'reconciled',
|
|
232
|
-
parsed: initialParsed,
|
|
233
|
-
total: initialTotal,
|
|
234
|
-
warnings: initialWarnings
|
|
235
|
-
});
|
|
236
|
-
}
|
|
239
|
+
if (claimFailure) throw claimFailure;
|
|
237
240
|
stopping = false;
|
|
238
241
|
// At most one open+reconcile+close cycle runs at a time; a trigger that arrives mid-cycle is
|
|
239
242
|
// coalesced into a single rerun instead of opening a second, overlapping connection.
|
|
@@ -247,13 +250,13 @@ function runWatch(_0) {
|
|
|
247
250
|
case 0:
|
|
248
251
|
_state.trys.push([
|
|
249
252
|
0,
|
|
250
|
-
|
|
253
|
+
8,
|
|
251
254
|
,
|
|
252
|
-
|
|
255
|
+
9
|
|
253
256
|
]);
|
|
254
257
|
return [
|
|
255
258
|
4,
|
|
256
|
-
(0,
|
|
259
|
+
(0, _indexts.openStore)(cfg)
|
|
257
260
|
];
|
|
258
261
|
case 1:
|
|
259
262
|
_ref = _state.sent(), store = _ref.store, parsed = _ref.parsed, warnings = _ref.warnings;
|
|
@@ -262,24 +265,12 @@ function runWatch(_0) {
|
|
|
262
265
|
_state.trys.push([
|
|
263
266
|
2,
|
|
264
267
|
,
|
|
265
|
-
|
|
266
|
-
|
|
268
|
+
5,
|
|
269
|
+
7
|
|
267
270
|
]);
|
|
268
|
-
return [
|
|
269
|
-
4,
|
|
270
|
-
(0, _indexts1.setMeta)(store, 'watch_heartbeat', new Date().toISOString())
|
|
271
|
-
];
|
|
272
|
-
case 3:
|
|
273
|
-
_state.sent();
|
|
274
|
-
return [
|
|
275
|
-
4,
|
|
276
|
-
(0, _indexts1.setMeta)(store, 'watch_pid', String(process.pid))
|
|
277
|
-
];
|
|
278
|
-
case 4:
|
|
279
|
-
_state.sent();
|
|
280
271
|
if (!(alwaysEmit || parsed > 0 || warnings.length > 0)) return [
|
|
281
272
|
3,
|
|
282
|
-
|
|
273
|
+
4
|
|
283
274
|
];
|
|
284
275
|
_tmp = {
|
|
285
276
|
type: 'reconciled',
|
|
@@ -287,34 +278,34 @@ function runWatch(_0) {
|
|
|
287
278
|
};
|
|
288
279
|
return [
|
|
289
280
|
4,
|
|
290
|
-
(0,
|
|
281
|
+
(0, _indexts.docCount)(store)
|
|
291
282
|
];
|
|
292
|
-
case
|
|
283
|
+
case 3:
|
|
293
284
|
onEvent.apply(void 0, [
|
|
294
285
|
(_tmp.total = _state.sent(), _tmp.warnings = warnings, _tmp)
|
|
295
286
|
]);
|
|
296
|
-
_state.label =
|
|
297
|
-
case
|
|
287
|
+
_state.label = 4;
|
|
288
|
+
case 4:
|
|
298
289
|
return [
|
|
299
290
|
3,
|
|
300
|
-
|
|
291
|
+
7
|
|
301
292
|
];
|
|
302
|
-
case
|
|
293
|
+
case 5:
|
|
303
294
|
return [
|
|
304
295
|
4,
|
|
305
296
|
store.close()
|
|
306
297
|
];
|
|
307
|
-
case
|
|
298
|
+
case 6:
|
|
308
299
|
_state.sent();
|
|
309
300
|
return [
|
|
310
301
|
7
|
|
311
302
|
];
|
|
312
|
-
case
|
|
303
|
+
case 7:
|
|
313
304
|
return [
|
|
314
305
|
3,
|
|
315
|
-
|
|
306
|
+
9
|
|
316
307
|
];
|
|
317
|
-
case
|
|
308
|
+
case 8:
|
|
318
309
|
err = _state.sent();
|
|
319
310
|
onEvent({
|
|
320
311
|
type: 'reconcile-error',
|
|
@@ -322,9 +313,9 @@ function runWatch(_0) {
|
|
|
322
313
|
});
|
|
323
314
|
return [
|
|
324
315
|
3,
|
|
325
|
-
|
|
316
|
+
9
|
|
326
317
|
];
|
|
327
|
-
case
|
|
318
|
+
case 9:
|
|
328
319
|
return [
|
|
329
320
|
2
|
|
330
321
|
];
|
|
@@ -358,15 +349,15 @@ function runWatch(_0) {
|
|
|
358
349
|
requestCycle(true);
|
|
359
350
|
}, debounceMs);
|
|
360
351
|
};
|
|
361
|
-
// Ignore our own state
|
|
362
|
-
//
|
|
352
|
+
// Ignore our own state files, or cache and claim writes would retrigger reconciliation forever.
|
|
353
|
+
// An unresolvable filename reconciles because parsing nothing costs less than missing a real edit.
|
|
363
354
|
watcher = (0, _nodefs.watch)(rootDir, {
|
|
364
355
|
recursive: true
|
|
365
356
|
}, function(_event, filename) {
|
|
366
|
-
if (
|
|
357
|
+
if (!(0, _watchnotificationts.shouldReconcileWatchNotification)(filename)) return;
|
|
367
358
|
scheduleReconcile();
|
|
368
359
|
});
|
|
369
|
-
|
|
360
|
+
reconcileTimer = setInterval((0, _guardedtickts.guardedTick)(function() {
|
|
370
361
|
return _async_to_generator(function() {
|
|
371
362
|
return _ts_generator(this, function(_state) {
|
|
372
363
|
return [
|
|
@@ -377,75 +368,183 @@ function runWatch(_0) {
|
|
|
377
368
|
})();
|
|
378
369
|
}, function() {
|
|
379
370
|
return stopping;
|
|
380
|
-
}),
|
|
371
|
+
}), reconcileIntervalMs);
|
|
381
372
|
return [
|
|
382
|
-
|
|
383
|
-
new Promise(function(resolveShutdown) {
|
|
384
|
-
var _opts_signal
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
373
|
+
4,
|
|
374
|
+
new Promise(function(resolveShutdown, rejectShutdown) {
|
|
375
|
+
var _opts_signal;
|
|
376
|
+
var shutdownReason = null;
|
|
377
|
+
var shutdown = function shutdown(reason) {
|
|
378
|
+
shutdownReason !== null && shutdownReason !== void 0 ? shutdownReason : shutdownReason = reason !== null && reason !== void 0 ? reason : null;
|
|
379
|
+
if (stopping) return;
|
|
380
|
+
stopping = true;
|
|
381
|
+
var shutdownTask = function() {
|
|
382
|
+
return _async_to_generator(function() {
|
|
383
|
+
var _opts_signal, finalError, _ref, finalStore, err, err1;
|
|
384
|
+
return _ts_generator(this, function(_state) {
|
|
385
|
+
switch(_state.label){
|
|
386
|
+
case 0:
|
|
387
|
+
process.off('SIGINT', stopNormally);
|
|
388
|
+
process.off('SIGTERM', stopNormally);
|
|
389
|
+
(_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.removeEventListener('abort', stopNormally);
|
|
390
|
+
clearInterval(reconcileTimer);
|
|
391
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
392
|
+
watcher.close();
|
|
393
|
+
return [
|
|
394
|
+
4,
|
|
395
|
+
running
|
|
396
|
+
];
|
|
397
|
+
case 1:
|
|
398
|
+
_state.sent();
|
|
399
|
+
_state.label = 2;
|
|
400
|
+
case 2:
|
|
401
|
+
_state.trys.push([
|
|
402
|
+
2,
|
|
403
|
+
6,
|
|
404
|
+
,
|
|
405
|
+
7
|
|
406
|
+
]);
|
|
407
|
+
if (!!shutdownReason) return [
|
|
408
|
+
3,
|
|
409
|
+
5
|
|
410
|
+
];
|
|
411
|
+
return [
|
|
412
|
+
4,
|
|
413
|
+
(0, _indexts.openStore)(cfg)
|
|
414
|
+
];
|
|
415
|
+
case 3:
|
|
416
|
+
_ref = _state.sent(), finalStore = _ref.store;
|
|
417
|
+
return [
|
|
418
|
+
4,
|
|
419
|
+
finalStore.close()
|
|
420
|
+
];
|
|
421
|
+
case 4:
|
|
422
|
+
_state.sent();
|
|
423
|
+
_state.label = 5;
|
|
424
|
+
case 5:
|
|
425
|
+
return [
|
|
426
|
+
3,
|
|
427
|
+
7
|
|
428
|
+
];
|
|
429
|
+
case 6:
|
|
430
|
+
err = _state.sent();
|
|
431
|
+
finalError = err;
|
|
432
|
+
return [
|
|
433
|
+
3,
|
|
434
|
+
7
|
|
435
|
+
];
|
|
436
|
+
case 7:
|
|
437
|
+
_state.trys.push([
|
|
438
|
+
7,
|
|
439
|
+
9,
|
|
440
|
+
,
|
|
441
|
+
10
|
|
442
|
+
]);
|
|
443
|
+
return [
|
|
444
|
+
4,
|
|
445
|
+
closeClaim()
|
|
446
|
+
];
|
|
447
|
+
case 8:
|
|
448
|
+
_state.sent();
|
|
449
|
+
return [
|
|
450
|
+
3,
|
|
451
|
+
10
|
|
452
|
+
];
|
|
453
|
+
case 9:
|
|
454
|
+
err1 = _state.sent();
|
|
455
|
+
if (finalError) throw new AggregateError([
|
|
456
|
+
finalError,
|
|
457
|
+
err1
|
|
458
|
+
], 'watch shutdown and claim cleanup both failed');
|
|
459
|
+
throw err1;
|
|
460
|
+
case 10:
|
|
461
|
+
if (finalError) throw finalError;
|
|
462
|
+
if (shutdownReason) throw shutdownReason;
|
|
463
|
+
return [
|
|
464
|
+
2
|
|
465
|
+
];
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
})();
|
|
469
|
+
}();
|
|
470
|
+
shutdownTask.then(resolveShutdown, rejectShutdown);
|
|
440
471
|
};
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
472
|
+
var stopNormally = function stopNormally() {
|
|
473
|
+
return shutdown();
|
|
474
|
+
};
|
|
475
|
+
requestShutdown = shutdown;
|
|
476
|
+
process.once('SIGINT', stopNormally);
|
|
477
|
+
process.once('SIGTERM', stopNormally);
|
|
478
|
+
if (claimFailure) shutdown(claimFailure);
|
|
479
|
+
else if ((_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.aborted) shutdown();
|
|
480
|
+
else {
|
|
481
|
+
var _opts_signal1;
|
|
482
|
+
(_opts_signal1 = opts.signal) === null || _opts_signal1 === void 0 ? void 0 : _opts_signal1.addEventListener('abort', stopNormally, {
|
|
483
|
+
once: true
|
|
484
|
+
});
|
|
485
|
+
try {
|
|
486
|
+
onEvent({
|
|
487
|
+
type: 'started',
|
|
488
|
+
rootDir: rootDir,
|
|
489
|
+
dbPath: dbPath
|
|
490
|
+
});
|
|
491
|
+
if (!stopping && (initialWarnings.length > 0 || initialParsed > 0)) {
|
|
492
|
+
onEvent({
|
|
493
|
+
type: 'reconciled',
|
|
494
|
+
parsed: initialParsed,
|
|
495
|
+
total: initialTotal,
|
|
496
|
+
warnings: initialWarnings
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
} catch (err) {
|
|
500
|
+
shutdown(_instanceof(err, Error) ? err : new Error(String(err)));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
447
503
|
})
|
|
448
504
|
];
|
|
505
|
+
case 11:
|
|
506
|
+
return [
|
|
507
|
+
2,
|
|
508
|
+
_state.sent()
|
|
509
|
+
];
|
|
510
|
+
case 12:
|
|
511
|
+
err = _state.sent();
|
|
512
|
+
if (claimCloseStarted) throw err;
|
|
513
|
+
_state.label = 13;
|
|
514
|
+
case 13:
|
|
515
|
+
_state.trys.push([
|
|
516
|
+
13,
|
|
517
|
+
15,
|
|
518
|
+
,
|
|
519
|
+
16
|
|
520
|
+
]);
|
|
521
|
+
return [
|
|
522
|
+
4,
|
|
523
|
+
closeClaim()
|
|
524
|
+
];
|
|
525
|
+
case 14:
|
|
526
|
+
_state.sent();
|
|
527
|
+
return [
|
|
528
|
+
3,
|
|
529
|
+
16
|
|
530
|
+
];
|
|
531
|
+
case 15:
|
|
532
|
+
closeError = _state.sent();
|
|
533
|
+
throw new AggregateError([
|
|
534
|
+
err,
|
|
535
|
+
closeError
|
|
536
|
+
], 'watch setup and claim cleanup both failed');
|
|
537
|
+
case 16:
|
|
538
|
+
throw err;
|
|
539
|
+
case 17:
|
|
540
|
+
requestShutdown = undefined;
|
|
541
|
+
return [
|
|
542
|
+
7
|
|
543
|
+
];
|
|
544
|
+
case 18:
|
|
545
|
+
return [
|
|
546
|
+
2
|
|
547
|
+
];
|
|
449
548
|
}
|
|
450
549
|
});
|
|
451
550
|
}).apply(this, arguments);
|
package/dist/cjs/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { STATE_DIR } from './config/index.ts';\nimport { SenseError } from './errors.ts';\nimport { guardedTick } from './lib/guarded-tick.ts';\nimport { docCount, getMeta, openStore, setMeta } from './store/index.ts';\n\n// Watch is a cache pre-warmer, not a correctness mechanism: open() always reconciles anyway, so any fs event just triggers a debounced full reconcile.\nconst DEBOUNCE_MS = 200;\nconst HEARTBEAT_INTERVAL_MS = 5000;\nconst STALE_HEARTBEAT_MS = 15000;\n\nexport type WatchEvent = { type: 'started'; rootDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n // Aborting runs the same shutdown path as SIGINT/SIGTERM.\n signal?: AbortSignal;\n debounceMs?: number;\n heartbeatIntervalMs?: number;\n}\n\n// Runs in the foreground until SIGINT/SIGTERM/signal abort. duckdb/turso hand the cache file to\n// one process at a time, so every cycle opens, reconciles, writes the heartbeat/pid rows, and closes.\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n const onEvent = opts.onEvent ?? (() => {});\n const debounceMs = opts.debounceMs ?? DEBOUNCE_MS;\n const heartbeatIntervalMs = opts.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS;\n const { store: initialStore, dbPath, warnings: initialWarnings, parsed: initialParsed } = await openStore(cfg);\n // openStore normalizes the legacy direct-API baseDir before a watcher touches the filesystem.\n const rootDir = cfg.rootDir ?? cfg.baseDir;\n const existingHeartbeat = await getMeta(initialStore, 'watch_heartbeat');\n if (existingHeartbeat && !opts.force) {\n const age = Date.now() - Date.parse(existingHeartbeat);\n if (age >= 0 && age < STALE_HEARTBEAT_MS) {\n await initialStore.close();\n throw new SenseError('WATCH_ACTIVE', `another watcher appears active (heartbeat ${Math.round(age / 1000)}s ago); use --force to override`);\n }\n }\n\n // total is read before close: an event fires only once nothing is held open again.\n const initialTotal = initialWarnings.length > 0 || initialParsed > 0 ? await docCount(initialStore) : 0;\n await setMeta(initialStore, 'watch_heartbeat', new Date().toISOString());\n await setMeta(initialStore, 'watch_pid', String(process.pid));\n await initialStore.close();\n\n onEvent({ type: 'started', rootDir, dbPath });\n if (initialWarnings.length > 0 || initialParsed > 0) {\n onEvent({ type: 'reconciled', parsed: initialParsed, total: initialTotal, warnings: initialWarnings });\n }\n\n let stopping = false;\n // At most one open+reconcile+close cycle runs at a time; a trigger that arrives mid-cycle is\n // coalesced into a single rerun instead of opening a second, overlapping connection.\n let running: Promise<void> | null = null;\n let queuedAlways: boolean | null = null;\n\n const tick = async (alwaysEmit: boolean): Promise<void> => {\n try {\n const { store, parsed, warnings } = await openStore(cfg);\n try {\n await setMeta(store, 'watch_heartbeat', new Date().toISOString());\n await setMeta(store, 'watch_pid', String(process.pid));\n if (alwaysEmit || parsed > 0 || warnings.length > 0) {\n onEvent({ type: 'reconciled', parsed, total: await docCount(store), warnings });\n }\n } finally {\n await store.close();\n }\n } catch (err) {\n onEvent({ type: 'reconcile-error', message: (err as Error).message });\n }\n };\n\n const startCycle = (alwaysEmit: boolean) => {\n running = tick(alwaysEmit).then(() => {\n running = null;\n if (queuedAlways !== null && !stopping) {\n const again = queuedAlways;\n queuedAlways = null;\n startCycle(again);\n }\n });\n };\n\n const requestCycle = (alwaysEmit: boolean) => {\n if (stopping) return;\n if (running) {\n queuedAlways = queuedAlways || alwaysEmit;\n return;\n }\n startCycle(alwaysEmit);\n };\n\n let debounceTimer: NodeJS.Timeout | null = null;\n const scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n requestCycle(true);\n }, debounceMs);\n };\n\n // Ignore our own state dir, or the heartbeat write would retrigger itself forever. An event with\n // an unresolvable filename (null, which fs.watch delivers under load) reconciles: parsing nothing costs less than missing a real edit.\n const watcher = fsWatch(rootDir, { recursive: true }, (_event, filename) => {\n if (typeof filename === 'string' && filename.startsWith(STATE_DIR)) return;\n scheduleReconcile();\n });\n const heartbeatTimer = setInterval(\n guardedTick(\n async () => requestCycle(false),\n () => stopping\n ),\n heartbeatIntervalMs\n );\n\n return new Promise<void>((resolveShutdown) => {\n // SIGINT/SIGTERM and an aborted signal all run this same path exactly once; each is\n // unregistered here too so a second runWatch call in the same process starts clean.\n const shutdown = async () => {\n if (stopping) return;\n stopping = true;\n process.off('SIGINT', shutdown);\n process.off('SIGTERM', shutdown);\n opts.signal?.removeEventListener('abort', shutdown);\n clearInterval(heartbeatTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n await running;\n const { store: finalStore } = await openStore(cfg);\n await setMeta(finalStore, 'watch_heartbeat', null);\n await setMeta(finalStore, 'watch_pid', null);\n await finalStore.close();\n resolveShutdown();\n };\n process.once('SIGINT', shutdown);\n process.once('SIGTERM', shutdown);\n if (opts.signal?.aborted) shutdown();\n else opts.signal?.addEventListener('abort', shutdown, { once: true });\n });\n}\n"],"names":["runWatch","DEBOUNCE_MS","HEARTBEAT_INTERVAL_MS","STALE_HEARTBEAT_MS","cfg","opts","onEvent","debounceMs","heartbeatIntervalMs","initialStore","dbPath","initialWarnings","initialParsed","rootDir","existingHeartbeat","age","initialTotal","stopping","running","queuedAlways","tick","startCycle","requestCycle","debounceTimer","scheduleReconcile","watcher","heartbeatTimer","openStore","store","warnings","parsed","baseDir","getMeta","force","Date","now","parse","close","SenseError","Math","round","length","docCount","setMeta","toISOString","String","process","pid","type","total","alwaysEmit","err","message","then","again","clearTimeout","setTimeout","fsWatch","recursive","_event","filename","startsWith","STATE_DIR","setInterval","guardedTick","Promise","resolveShutdown","shutdown","finalStore","off","signal","removeEventListener","clearInterval","once","aborted","addEventListener"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { SenseError } from './errors.ts';\nimport { guardedTick } from './lib/guarded-tick.ts';\nimport { shouldReconcileWatchNotification } from './lib/watch-notification.ts';\nimport { docCount, openStore } from './store/index.ts';\nimport { startWatchClaim, WATCH_HEARTBEAT_INTERVAL_MS } from './watch-claim.ts';\n\n// Watch is a cache pre-warmer, not a correctness mechanism: open() always reconciles anyway, so any fs event just triggers a debounced full reconcile.\nconst DEBOUNCE_MS = 200;\n\nexport type WatchEvent = { type: 'started'; rootDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n // Aborting runs the same shutdown path as SIGINT/SIGTERM.\n signal?: AbortSignal;\n debounceMs?: number;\n heartbeatIntervalMs?: number;\n}\n\n// Runs in the foreground until SIGINT/SIGTERM/signal abort. DuckDB and Turso hand the cache file to\n// one process at a time, so every reconcile cycle opens and closes instead of holding an idle lock.\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n const onEvent = opts.onEvent ?? (() => {});\n const debounceMs = opts.debounceMs ?? DEBOUNCE_MS;\n const reconcileIntervalMs = opts.heartbeatIntervalMs ?? WATCH_HEARTBEAT_INTERVAL_MS;\n if (!Number.isFinite(reconcileIntervalMs) || reconcileIntervalMs <= 0) throw new SenseError('CONFIG_INVALID', 'watch heartbeatIntervalMs must be a finite positive number');\n // Reconciliation may be parked for a caller, but live ownership must renew before fixed expiry.\n const claimIntervalMs = Math.min(reconcileIntervalMs, WATCH_HEARTBEAT_INTERVAL_MS);\n const rootDir = cfg.rootDir ?? cfg.baseDir;\n const configDir = cfg.configDir ?? rootDir;\n let claimFailure: Error | null = null;\n let requestShutdown: ((reason: Error) => void) | undefined;\n const claim = await startWatchClaim(configDir, opts.force ?? false, claimIntervalMs, (err) => {\n claimFailure ??= err;\n requestShutdown?.(err);\n });\n let claimCloseStarted = false;\n const closeClaim = (): Promise<void> => {\n claimCloseStarted = true;\n return claim.close();\n };\n try {\n const { store: initialStore, dbPath, warnings: initialWarnings, parsed: initialParsed } = await openStore(cfg);\n let initialTotal = 0;\n try {\n // total is read before close: an event fires only once nothing is held open again.\n initialTotal = initialWarnings.length > 0 || initialParsed > 0 ? await docCount(initialStore) : 0;\n } finally {\n await initialStore.close();\n }\n if (claimFailure) throw claimFailure;\n\n let stopping = false;\n // At most one open+reconcile+close cycle runs at a time; a trigger that arrives mid-cycle is\n // coalesced into a single rerun instead of opening a second, overlapping connection.\n let running: Promise<void> | null = null;\n let queuedAlways: boolean | null = null;\n\n const tick = async (alwaysEmit: boolean): Promise<void> => {\n try {\n const { store, parsed, warnings } = await openStore(cfg);\n try {\n if (alwaysEmit || parsed > 0 || warnings.length > 0) {\n onEvent({ type: 'reconciled', parsed, total: await docCount(store), warnings });\n }\n } finally {\n await store.close();\n }\n } catch (err) {\n onEvent({ type: 'reconcile-error', message: (err as Error).message });\n }\n };\n\n const startCycle = (alwaysEmit: boolean) => {\n running = tick(alwaysEmit).then(() => {\n running = null;\n if (queuedAlways !== null && !stopping) {\n const again = queuedAlways;\n queuedAlways = null;\n startCycle(again);\n }\n });\n };\n\n const requestCycle = (alwaysEmit: boolean) => {\n if (stopping) return;\n if (running) {\n queuedAlways = queuedAlways || alwaysEmit;\n return;\n }\n startCycle(alwaysEmit);\n };\n\n let debounceTimer: NodeJS.Timeout | null = null;\n const scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n requestCycle(true);\n }, debounceMs);\n };\n\n // Ignore our own state files, or cache and claim writes would retrigger reconciliation forever.\n // An unresolvable filename reconciles because parsing nothing costs less than missing a real edit.\n const watcher = fsWatch(rootDir, { recursive: true }, (_event, filename) => {\n if (!shouldReconcileWatchNotification(filename)) return;\n scheduleReconcile();\n });\n const reconcileTimer = setInterval(\n guardedTick(\n async () => requestCycle(false),\n () => stopping\n ),\n reconcileIntervalMs\n );\n\n return await new Promise<void>((resolveShutdown, rejectShutdown) => {\n let shutdownReason: Error | null = null;\n const shutdown = (reason?: Error) => {\n shutdownReason ??= reason ?? null;\n if (stopping) return;\n stopping = true;\n const shutdownTask = (async () => {\n process.off('SIGINT', stopNormally);\n process.off('SIGTERM', stopNormally);\n opts.signal?.removeEventListener('abort', stopNormally);\n clearInterval(reconcileTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher.close();\n await running;\n let finalError: unknown;\n try {\n // A normal stop performs one final freshness pass. Ownership loss drains existing work\n // but starts nothing new because the replacement watcher now owns that responsibility.\n if (!shutdownReason) {\n const { store: finalStore } = await openStore(cfg);\n await finalStore.close();\n }\n } catch (err) {\n finalError = err;\n }\n try {\n await closeClaim();\n } catch (err) {\n if (finalError) throw new AggregateError([finalError, err], 'watch shutdown and claim cleanup both failed');\n throw err;\n }\n if (finalError) throw finalError;\n if (shutdownReason) throw shutdownReason;\n })();\n shutdownTask.then(resolveShutdown, rejectShutdown);\n };\n const stopNormally = () => shutdown();\n requestShutdown = shutdown;\n process.once('SIGINT', stopNormally);\n process.once('SIGTERM', stopNormally);\n if (claimFailure) shutdown(claimFailure);\n else if (opts.signal?.aborted) shutdown();\n else {\n opts.signal?.addEventListener('abort', stopNormally, { once: true });\n try {\n onEvent({ type: 'started', rootDir, dbPath });\n if (!stopping && (initialWarnings.length > 0 || initialParsed > 0)) {\n onEvent({ type: 'reconciled', parsed: initialParsed, total: initialTotal, warnings: initialWarnings });\n }\n } catch (err) {\n shutdown(err instanceof Error ? err : new Error(String(err)));\n }\n }\n });\n } catch (err) {\n if (claimCloseStarted) throw err;\n try {\n await closeClaim();\n } catch (closeError) {\n throw new AggregateError([err, closeError], 'watch setup and claim cleanup both failed');\n }\n throw err;\n } finally {\n requestShutdown = undefined;\n }\n}\n"],"names":["runWatch","DEBOUNCE_MS","cfg","opts","onEvent","debounceMs","reconcileIntervalMs","claimIntervalMs","rootDir","configDir","claimFailure","requestShutdown","claim","claimCloseStarted","closeClaim","initialStore","dbPath","initialWarnings","initialParsed","initialTotal","stopping","running","queuedAlways","tick","startCycle","requestCycle","debounceTimer","scheduleReconcile","watcher","reconcileTimer","err","closeError","heartbeatIntervalMs","WATCH_HEARTBEAT_INTERVAL_MS","Number","isFinite","SenseError","Math","min","baseDir","startWatchClaim","force","close","openStore","store","warnings","parsed","length","docCount","alwaysEmit","type","total","message","then","again","clearTimeout","setTimeout","fsWatch","recursive","_event","filename","shouldReconcileWatchNotification","setInterval","guardedTick","Promise","resolveShutdown","rejectShutdown","shutdownReason","shutdown","reason","shutdownTask","finalError","finalStore","process","off","stopNormally","signal","removeEventListener","clearInterval","AggregateError","once","aborted","addEventListener","Error","String","undefined"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|