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.
Files changed (130) hide show
  1. package/README.md +16 -12
  2. package/dist/cjs/cli/status.js +14 -24
  3. package/dist/cjs/cli/status.js.map +1 -1
  4. package/dist/cjs/commands/search.js +22 -0
  5. package/dist/cjs/commands/search.js.map +1 -1
  6. package/dist/cjs/config/types.js.map +1 -1
  7. package/dist/cjs/errors.d.cts +1 -1
  8. package/dist/cjs/errors.d.ts +1 -1
  9. package/dist/cjs/errors.js.map +1 -1
  10. package/dist/cjs/lib/watch-notification.d.cts +1 -0
  11. package/dist/cjs/lib/watch-notification.d.ts +1 -0
  12. package/dist/cjs/lib/watch-notification.js +15 -0
  13. package/dist/cjs/lib/watch-notification.js.map +1 -0
  14. package/dist/cjs/lib/worker-file.d.cts +1 -0
  15. package/dist/cjs/lib/worker-file.d.ts +1 -0
  16. package/dist/cjs/lib/worker-file.js +34 -0
  17. package/dist/cjs/lib/worker-file.js.map +1 -0
  18. package/dist/cjs/output/search-error.js +38 -0
  19. package/dist/cjs/output/search-error.js.map +1 -1
  20. package/dist/cjs/scan/pool.js +2 -23
  21. package/dist/cjs/scan/pool.js.map +1 -1
  22. package/dist/cjs/store/builder.d.cts +2 -1
  23. package/dist/cjs/store/builder.d.ts +2 -1
  24. package/dist/cjs/store/builder.js +4 -4
  25. package/dist/cjs/store/builder.js.map +1 -1
  26. package/dist/cjs/store/duckdb/lexical.d.cts +1 -0
  27. package/dist/cjs/store/duckdb/lexical.d.ts +1 -0
  28. package/dist/cjs/store/duckdb/lexical.js +28 -9
  29. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  30. package/dist/cjs/store/duckdb/native.d.cts +2 -0
  31. package/dist/cjs/store/duckdb/native.d.ts +2 -0
  32. package/dist/cjs/store/duckdb/native.js +11 -1
  33. package/dist/cjs/store/duckdb/native.js.map +1 -1
  34. package/dist/cjs/store/duckdb/ordered-bm25.d.cts +17 -0
  35. package/dist/cjs/store/duckdb/ordered-bm25.d.ts +17 -0
  36. package/dist/cjs/store/duckdb/ordered-bm25.js +238 -0
  37. package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -0
  38. package/dist/cjs/store/lock-wait.d.cts +2 -2
  39. package/dist/cjs/store/lock-wait.d.ts +2 -2
  40. package/dist/cjs/store/lock-wait.js +14 -11
  41. package/dist/cjs/store/lock-wait.js.map +1 -1
  42. package/dist/cjs/store/native.d.cts +4 -0
  43. package/dist/cjs/store/native.d.ts +4 -0
  44. package/dist/cjs/store/native.js +64 -9
  45. package/dist/cjs/store/native.js.map +1 -1
  46. package/dist/cjs/store/open.js +11 -7
  47. package/dist/cjs/store/open.js.map +1 -1
  48. package/dist/cjs/store/reconcile.d.cts +5 -1
  49. package/dist/cjs/store/reconcile.d.ts +5 -1
  50. package/dist/cjs/store/reconcile.js +5 -4
  51. package/dist/cjs/store/reconcile.js.map +1 -1
  52. package/dist/cjs/store/turso/lexical.js +5 -1
  53. package/dist/cjs/store/turso/lexical.js.map +1 -1
  54. package/dist/cjs/text/segment.js +168 -3
  55. package/dist/cjs/text/segment.js.map +1 -1
  56. package/dist/cjs/watch-claim.d.cts +39 -0
  57. package/dist/cjs/watch-claim.d.ts +39 -0
  58. package/dist/cjs/watch-claim.js +446 -0
  59. package/dist/cjs/watch-claim.js.map +1 -0
  60. package/dist/cjs/watch.js +246 -147
  61. package/dist/cjs/watch.js.map +1 -1
  62. package/dist/cjs/workers/watch-heartbeat.d.cts +1 -0
  63. package/dist/cjs/workers/watch-heartbeat.d.ts +1 -0
  64. package/dist/cjs/workers/watch-heartbeat.js +308 -0
  65. package/dist/cjs/workers/watch-heartbeat.js.map +1 -0
  66. package/dist/esm/cli/status.js +6 -5
  67. package/dist/esm/cli/status.js.map +1 -1
  68. package/dist/esm/commands/search.js +21 -0
  69. package/dist/esm/commands/search.js.map +1 -1
  70. package/dist/esm/config/types.js.map +1 -1
  71. package/dist/esm/errors.d.ts +1 -1
  72. package/dist/esm/errors.js.map +1 -1
  73. package/dist/esm/lib/watch-notification.d.ts +1 -0
  74. package/dist/esm/lib/watch-notification.js +4 -0
  75. package/dist/esm/lib/watch-notification.js.map +1 -0
  76. package/dist/esm/lib/worker-file.d.ts +1 -0
  77. package/dist/esm/lib/worker-file.js +24 -0
  78. package/dist/esm/lib/worker-file.js.map +1 -0
  79. package/dist/esm/output/search-error.js +21 -0
  80. package/dist/esm/output/search-error.js.map +1 -1
  81. package/dist/esm/scan/pool.js +2 -22
  82. package/dist/esm/scan/pool.js.map +1 -1
  83. package/dist/esm/store/builder.d.ts +2 -1
  84. package/dist/esm/store/builder.js +4 -4
  85. package/dist/esm/store/builder.js.map +1 -1
  86. package/dist/esm/store/duckdb/lexical.d.ts +1 -0
  87. package/dist/esm/store/duckdb/lexical.js +16 -7
  88. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  89. package/dist/esm/store/duckdb/native.d.ts +2 -0
  90. package/dist/esm/store/duckdb/native.js +5 -1
  91. package/dist/esm/store/duckdb/native.js.map +1 -1
  92. package/dist/esm/store/duckdb/ordered-bm25.d.ts +17 -0
  93. package/dist/esm/store/duckdb/ordered-bm25.js +56 -0
  94. package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -0
  95. package/dist/esm/store/lock-wait.d.ts +2 -2
  96. package/dist/esm/store/lock-wait.js +17 -14
  97. package/dist/esm/store/lock-wait.js.map +1 -1
  98. package/dist/esm/store/native.d.ts +4 -0
  99. package/dist/esm/store/native.js +60 -6
  100. package/dist/esm/store/native.js.map +1 -1
  101. package/dist/esm/store/open.js +9 -6
  102. package/dist/esm/store/open.js.map +1 -1
  103. package/dist/esm/store/reconcile.d.ts +5 -1
  104. package/dist/esm/store/reconcile.js +4 -3
  105. package/dist/esm/store/reconcile.js.map +1 -1
  106. package/dist/esm/store/turso/lexical.js +5 -1
  107. package/dist/esm/store/turso/lexical.js.map +1 -1
  108. package/dist/esm/text/segment.js +130 -4
  109. package/dist/esm/text/segment.js.map +1 -1
  110. package/dist/esm/watch-claim.d.ts +39 -0
  111. package/dist/esm/watch-claim.js +176 -0
  112. package/dist/esm/watch-claim.js.map +1 -0
  113. package/dist/esm/watch.js +169 -118
  114. package/dist/esm/watch.js.map +1 -1
  115. package/dist/esm/workers/watch-heartbeat.d.ts +1 -0
  116. package/dist/esm/workers/watch-heartbeat.js +106 -0
  117. package/dist/esm/workers/watch-heartbeat.js.map +1 -0
  118. package/package.json +2 -2
  119. package/skills/sense/SKILL.md +105 -104
  120. package/skills/sense/references/search.md +47 -0
  121. package/skills/sense/references/sql.md +120 -0
  122. package/skills/sense/references/stores/duckdb.md +35 -0
  123. package/skills/sense/references/stores/sqlite.md +66 -0
  124. package/skills/sense/references/stores/turso.md +36 -0
  125. package/skills/sense-setup/SKILL.md +93 -34
  126. package/skills/sense-setup/references/embeddings.md +51 -0
  127. package/skills/sense-setup/references/store-benchmarks.md +16 -0
  128. package/skills/sense-setup/references/stores/duckdb.md +28 -0
  129. package/skills/sense-setup/references/stores/sqlite.md +21 -0
  130. package/skills/sense-setup/references/stores/turso.md +25 -0
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ var _nodeworker_threads = require("node:worker_threads");
6
+ var _errorsts = require("../errors.js");
7
+ var _workererrorts = require("../scan/worker-error.js");
8
+ var _watchclaimts = require("../watch-claim.js");
9
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10
+ try {
11
+ var info = gen[key](arg);
12
+ var value = info.value;
13
+ } catch (error) {
14
+ reject(error);
15
+ return;
16
+ }
17
+ if (info.done) resolve(value);
18
+ else Promise.resolve(value).then(_next, _throw);
19
+ }
20
+ function _async_to_generator(fn) {
21
+ return function() {
22
+ var self = this, args = arguments;
23
+ return new Promise(function(resolve, reject) {
24
+ var gen = fn.apply(self, args);
25
+ function _next(value) {
26
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
27
+ }
28
+ function _throw(err) {
29
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
30
+ }
31
+ _next(undefined);
32
+ });
33
+ };
34
+ }
35
+ function _instanceof(left, right) {
36
+ "@swc/helpers - instanceof";
37
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
38
+ return !!right[Symbol.hasInstance](left);
39
+ } else return left instanceof right;
40
+ }
41
+ function _ts_generator(thisArg, body) {
42
+ var f, y, t, _ = {
43
+ label: 0,
44
+ sent: function() {
45
+ if (t[0] & 1) throw t[1];
46
+ return t[1];
47
+ },
48
+ trys: [],
49
+ ops: []
50
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
51
+ return d(g, "next", {
52
+ value: verb(0)
53
+ }), d(g, "throw", {
54
+ value: verb(1)
55
+ }), d(g, "return", {
56
+ value: verb(2)
57
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
58
+ value: function() {
59
+ return this;
60
+ }
61
+ }), g;
62
+ function verb(n) {
63
+ return function(v) {
64
+ return step([
65
+ n,
66
+ v
67
+ ]);
68
+ };
69
+ }
70
+ function step(op) {
71
+ if (f) throw new TypeError("Generator is already executing.");
72
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
73
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
74
+ if (y = 0, t) op = [
75
+ op[0] & 2,
76
+ t.value
77
+ ];
78
+ switch(op[0]){
79
+ case 0:
80
+ case 1:
81
+ t = op;
82
+ break;
83
+ case 4:
84
+ _.label++;
85
+ return {
86
+ value: op[1],
87
+ done: false
88
+ };
89
+ case 5:
90
+ _.label++;
91
+ y = op[1];
92
+ op = [
93
+ 0
94
+ ];
95
+ continue;
96
+ case 7:
97
+ op = _.ops.pop();
98
+ _.trys.pop();
99
+ continue;
100
+ default:
101
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
102
+ _ = 0;
103
+ continue;
104
+ }
105
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
106
+ _.label = op[1];
107
+ break;
108
+ }
109
+ if (op[0] === 6 && _.label < t[1]) {
110
+ _.label = t[1];
111
+ t = op;
112
+ break;
113
+ }
114
+ if (t && _.label < t[2]) {
115
+ _.label = t[2];
116
+ _.ops.push(op);
117
+ break;
118
+ }
119
+ if (t[2]) _.ops.pop();
120
+ _.trys.pop();
121
+ continue;
122
+ }
123
+ op = body.call(thisArg, _);
124
+ } catch (e) {
125
+ op = [
126
+ 6,
127
+ e
128
+ ];
129
+ y = 0;
130
+ } finally{
131
+ f = t = 0;
132
+ }
133
+ if (op[0] & 5) throw op[1];
134
+ return {
135
+ value: op[0] ? op[1] : void 0,
136
+ done: true
137
+ };
138
+ }
139
+ }
140
+ function requireParentPort() {
141
+ var port = _nodeworker_threads.parentPort;
142
+ if (!port) throw new Error('watch heartbeat worker requires a parent port');
143
+ return port;
144
+ }
145
+ var port = requireParentPort();
146
+ var data = _nodeworker_threads.workerData;
147
+ var database;
148
+ var timer;
149
+ var stopping = false;
150
+ var renewing = Promise.resolve();
151
+ function send(message) {
152
+ port.postMessage(message);
153
+ }
154
+ function asError(value) {
155
+ return _instanceof(value, Error) ? value : new Error(String(value));
156
+ }
157
+ function closeDatabase() {
158
+ if (timer) clearInterval(timer);
159
+ timer = undefined;
160
+ try {
161
+ database === null || database === void 0 ? void 0 : database.close();
162
+ database = undefined;
163
+ return undefined;
164
+ } catch (err) {
165
+ return asError(err);
166
+ }
167
+ }
168
+ function addFailure(primary, secondary, message) {
169
+ return secondary ? new AggregateError([
170
+ primary,
171
+ secondary
172
+ ], message) : primary;
173
+ }
174
+ function fail(err) {
175
+ if (stopping) return;
176
+ stopping = true;
177
+ var failure = asError(err);
178
+ try {
179
+ database === null || database === void 0 ? void 0 : database.release(data.token);
180
+ } catch (releaseError) {
181
+ failure = addFailure(failure, asError(releaseError), 'watch heartbeat and claim release both failed');
182
+ }
183
+ var closeError = closeDatabase();
184
+ failure = addFailure(failure, closeError, 'watch heartbeat and database cleanup both failed');
185
+ try {
186
+ send({
187
+ type: 'failure',
188
+ error: (0, _workererrorts.serializeError)(failure)
189
+ });
190
+ } finally{
191
+ port.close();
192
+ }
193
+ }
194
+ function stop() {
195
+ return _async_to_generator(function() {
196
+ var failure, err, closeError;
197
+ return _ts_generator(this, function(_state) {
198
+ switch(_state.label){
199
+ case 0:
200
+ if (stopping) return [
201
+ 2
202
+ ];
203
+ stopping = true;
204
+ if (timer) clearInterval(timer);
205
+ _state.label = 1;
206
+ case 1:
207
+ _state.trys.push([
208
+ 1,
209
+ 3,
210
+ 4,
211
+ 5
212
+ ]);
213
+ return [
214
+ 4,
215
+ renewing
216
+ ];
217
+ case 2:
218
+ _state.sent();
219
+ if (!(database === null || database === void 0 ? void 0 : database.release(data.token))) throw new _errorsts.SenseError('WATCH_ACTIVE', 'watch ownership was replaced by another watcher');
220
+ return [
221
+ 3,
222
+ 5
223
+ ];
224
+ case 3:
225
+ err = _state.sent();
226
+ failure = asError(err);
227
+ return [
228
+ 3,
229
+ 5
230
+ ];
231
+ case 4:
232
+ closeError = closeDatabase();
233
+ if (closeError) failure = failure ? addFailure(failure, closeError, 'watch heartbeat shutdown and database cleanup both failed') : closeError;
234
+ try {
235
+ if (failure) send({
236
+ type: 'failure',
237
+ error: (0, _workererrorts.serializeError)(failure)
238
+ });
239
+ else send({
240
+ type: 'stopped'
241
+ });
242
+ } finally{
243
+ port.close();
244
+ }
245
+ return [
246
+ 7
247
+ ];
248
+ case 5:
249
+ return [
250
+ 2
251
+ ];
252
+ }
253
+ });
254
+ })();
255
+ }
256
+ function main() {
257
+ return _async_to_generator(function() {
258
+ var err;
259
+ return _ts_generator(this, function(_state) {
260
+ switch(_state.label){
261
+ case 0:
262
+ _state.trys.push([
263
+ 0,
264
+ 2,
265
+ ,
266
+ 3
267
+ ]);
268
+ database = new _watchclaimts.WatchClaimDatabase(data.configDir);
269
+ return [
270
+ 4,
271
+ database.acquire(data.token, data.pid, data.force)
272
+ ];
273
+ case 1:
274
+ _state.sent();
275
+ send({
276
+ type: 'acquired'
277
+ });
278
+ timer = setInterval(function() {
279
+ if (stopping) return;
280
+ renewing = renewing.then(function() {
281
+ if (!(database === null || database === void 0 ? void 0 : database.renew(data.token))) throw new _errorsts.SenseError('WATCH_ACTIVE', 'watch ownership was replaced by another watcher');
282
+ });
283
+ renewing.catch(fail);
284
+ }, data.heartbeatIntervalMs);
285
+ port.on('message', function(message) {
286
+ if (message.type === 'stop') void stop();
287
+ });
288
+ return [
289
+ 3,
290
+ 3
291
+ ];
292
+ case 2:
293
+ err = _state.sent();
294
+ fail(err);
295
+ return [
296
+ 3,
297
+ 3
298
+ ];
299
+ case 3:
300
+ return [
301
+ 2
302
+ ];
303
+ }
304
+ });
305
+ })();
306
+ }
307
+ void main();
308
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/workers/watch-heartbeat.ts"],"sourcesContent":["import { parentPort, workerData } from 'node:worker_threads';\nimport { SenseError } from '../errors.ts';\nimport { serializeError } from '../scan/worker-error.ts';\nimport { WatchClaimDatabase, type WatchClaimWorkerData, type WatchClaimWorkerMessage } from '../watch-claim.ts';\n\nfunction requireParentPort() {\n const port = parentPort;\n if (!port) throw new Error('watch heartbeat worker requires a parent port');\n return port;\n}\n\nconst port = requireParentPort();\nconst data = workerData as WatchClaimWorkerData;\nlet database: WatchClaimDatabase | undefined;\nlet timer: NodeJS.Timeout | undefined;\nlet stopping = false;\nlet renewing = Promise.resolve();\n\nfunction send(message: WatchClaimWorkerMessage): void {\n port.postMessage(message);\n}\n\nfunction asError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\nfunction closeDatabase(): Error | undefined {\n if (timer) clearInterval(timer);\n timer = undefined;\n try {\n database?.close();\n database = undefined;\n return undefined;\n } catch (err) {\n return asError(err);\n }\n}\n\nfunction addFailure(primary: Error, secondary: Error | undefined, message: string): Error {\n return secondary ? new AggregateError([primary, secondary], message) : primary;\n}\n\nfunction fail(err: unknown): void {\n if (stopping) return;\n stopping = true;\n let failure = asError(err);\n try {\n database?.release(data.token);\n } catch (releaseError) {\n failure = addFailure(failure, asError(releaseError), 'watch heartbeat and claim release both failed');\n }\n const closeError = closeDatabase();\n failure = addFailure(failure, closeError, 'watch heartbeat and database cleanup both failed');\n try {\n send({ type: 'failure', error: serializeError(failure) });\n } finally {\n port.close();\n }\n}\n\nasync function stop(): Promise<void> {\n if (stopping) return;\n stopping = true;\n if (timer) clearInterval(timer);\n let failure: Error | undefined;\n try {\n await renewing;\n if (!database?.release(data.token)) throw new SenseError('WATCH_ACTIVE', 'watch ownership was replaced by another watcher');\n } catch (err) {\n failure = asError(err);\n } finally {\n const closeError = closeDatabase();\n if (closeError) failure = failure ? addFailure(failure, closeError, 'watch heartbeat shutdown and database cleanup both failed') : closeError;\n try {\n if (failure) send({ type: 'failure', error: serializeError(failure) });\n else send({ type: 'stopped' });\n } finally {\n port.close();\n }\n }\n}\n\nasync function main(): Promise<void> {\n try {\n database = new WatchClaimDatabase(data.configDir);\n await database.acquire(data.token, data.pid, data.force);\n send({ type: 'acquired' });\n timer = setInterval(() => {\n if (stopping) return;\n renewing = renewing.then(() => {\n if (!database?.renew(data.token)) throw new SenseError('WATCH_ACTIVE', 'watch ownership was replaced by another watcher');\n });\n renewing.catch(fail);\n }, data.heartbeatIntervalMs);\n port.on('message', (message: { type?: string }) => {\n if (message.type === 'stop') void stop();\n });\n } catch (err) {\n fail(err);\n }\n}\n\nvoid main();\n"],"names":["requireParentPort","port","parentPort","Error","data","workerData","database","timer","stopping","renewing","Promise","resolve","send","message","postMessage","asError","value","String","closeDatabase","clearInterval","undefined","close","err","addFailure","primary","secondary","AggregateError","fail","failure","release","token","releaseError","closeError","type","error","serializeError","stop","SenseError","main","WatchClaimDatabase","configDir","acquire","pid","force","setInterval","then","renew","catch","heartbeatIntervalMs","on"],"mappings":"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"}
@@ -6,6 +6,7 @@ import { probeReachable } from '../embed/http.js';
6
6
  import { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.js';
7
7
  import { featuresLine, presetsLines, stringifyJson } from '../output/output.js';
8
8
  import { docCount, getMeta, openStore } from '../store/index.js';
9
+ import { readWatchClaim } from '../watch-claim.js';
9
10
  import { USAGE } from './index.js';
10
11
  import { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.js';
11
12
  // status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.
@@ -76,7 +77,7 @@ function languagesInfo(e) {
76
77
  };
77
78
  }
78
79
  const status = async (ctx)=>{
79
- var _ref, _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1, _cfg_configDir, _cfg_queries;
80
+ var _ref, _ref1, _cfg_configDir, _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1, _cfg_configDir1, _cfg_queries;
80
81
  const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, {
81
82
  ...FORMAT,
82
83
  ...CONFIG
@@ -97,13 +98,13 @@ const status = async (ctx)=>{
97
98
  source: null
98
99
  };
99
100
  const detectedLanguages = (_ref = await languageDistribution(store)) !== null && _ref !== void 0 ? _ref : null;
100
- const heartbeat = await getMeta(store, 'watch_heartbeat');
101
101
  // Written by the store's open() on every open, so it is this cache's true version on either
102
102
  // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.
103
103
  const cacheSchema = await getMeta(store, 'schema_version');
104
104
  // Each store owns what it reports and how it is worded (Store.engineStatus); this command
105
105
  // prints entries generically, without branching on any store's name.
106
106
  const engine = await store.engineStatus();
107
+ const watcher = readWatchClaim((_ref1 = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.rootDir) !== null && _ref1 !== void 0 ? _ref1 : cfg.baseDir);
107
108
  // The env var holds the token; only its name and whether it is set are ever reported.
108
109
  const keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
109
110
  name: e.key,
@@ -116,7 +117,7 @@ const status = async (ctx)=>{
116
117
  unknownConfigKeys: (_cfg_unknownKeys = cfg.unknownKeys) !== null && _cfg_unknownKeys !== void 0 ? _cfg_unknownKeys : null,
117
118
  tree: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
118
119
  treeRoot: (_cfg_rootDir1 = cfg.rootDir) !== null && _cfg_rootDir1 !== void 0 ? _cfg_rootDir1 : cfg.baseDir,
119
- configDir: (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.baseDir,
120
+ configDir: (_cfg_configDir1 = cfg.configDir) !== null && _cfg_configDir1 !== void 0 ? _cfg_configDir1 : cfg.baseDir,
120
121
  cache: dirname(dbPath),
121
122
  db: dbPath,
122
123
  cacheSchema,
@@ -139,8 +140,8 @@ const status = async (ctx)=>{
139
140
  } : null,
140
141
  presets,
141
142
  queries: Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length,
142
- watcherPid: await getMeta(store, 'watch_pid'),
143
- watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,
143
+ watcherPid: watcher ? String(watcher.pid) : null,
144
+ watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null,
144
145
  engine
145
146
  };
146
147
  if (format === 'json') {
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a semantic-on preset with nothing embedded yet.\n// Reported here because a fast reconcile on such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\ntype LanguagesState = 'declared' | 'none' | 'unresolved' | null;\n\n// Config-declared languages win over the model card, for every provider, as registry.ts does.\n// A local-path model has no card by design, so it is never \"unresolved\": that means an HF id.\nfunction languagesInfo(e: NonNullable<ReturnType<typeof embedConfig>>): { languages: string[] | null; state: LanguagesState; source: 'config' | 'card' | null } {\n if (e.languages) return { languages: e.languages, state: 'declared', source: 'config' };\n if (e.provider !== 'static' || !isDownloadable(e.model)) return { languages: null, state: null, source: null };\n const cardLanguages = readLanguages(e.model);\n if (cardLanguages === undefined) return { languages: null, state: 'unresolved', source: null };\n if (cardLanguages.length === 0) return { languages: null, state: 'none', source: null };\n return { languages: cardLanguages, state: 'declared', source: 'card' };\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : { languages: null, state: null, source: null };\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n const heartbeat = await getMeta(store, 'watch_heartbeat');\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Each store owns what it reports and how it is worded (Store.engineStatus); this command\n // prints entries generically, without branching on any store's name.\n const engine = await store.engineStatus();\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.rootDir ?? cfg.baseDir,\n treeRoot: cfg.rootDir ?? cfg.baseDir,\n configDir: cfg.configDir ?? cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, languagesState, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: await getMeta(store, 'watch_pid'),\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n engine,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree root: ${result.treeRoot}`);\n console.log(`configDir: ${result.configDir}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches automatically at first search, or run \\`${ctx.name} download\\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);\n if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);\n else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n else if (languagesState === 'none') console.log(' languages: none declared by the model card');\n else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \\`${ctx.name} download\\`)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n for (const [key, value] of Object.entries(result.engine)) console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["dirname","presetCoverage","embedConfig","featureStates","SUPPORTED_CONFIG_VERSION","languageDistribution","probeReachable","isDownloadable","MODEL_FILENAMES","modelDir","modelPresent","readLanguages","featuresLine","presetsLines","stringifyJson","docCount","getMeta","openStore","USAGE","CONFIG","FORMAT","formatOf","parse","printWarnings","vectorState","store","stmt","prepare","get","parseErrorCount","n","redactUrl","url","parsed","URL","username","password","toString","replace","embedReachable","e","provider","base","languagesInfo","languages","state","source","model","cardLanguages","undefined","length","status","ctx","process","cfg","values","argv","name","format","resolveConfig","config","dbPath","warnings","features","hasModel","reachable","vectors","presets","declaredLanguages","languagesState","languagesSource","detectedLanguages","heartbeat","cacheSchema","engine","engineStatus","keyEnv","key","set","env","result","configPath","configVersion","migratedFrom","unknownConfigKeys","unknownKeys","tree","rootDir","baseDir","treeRoot","configDir","cache","db","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","downloaded","queries","Object","keys","watcherPid","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","migrated","join","shown","embedded","pending","total","reduce","a","b","breakdown","entries","sort","map","code","line","pid","value","padEnd","close"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { readWatchClaim } from '../watch-claim.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a semantic-on preset with nothing embedded yet.\n// Reported here because a fast reconcile on such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\ntype LanguagesState = 'declared' | 'none' | 'unresolved' | null;\n\n// Config-declared languages win over the model card, for every provider, as registry.ts does.\n// A local-path model has no card by design, so it is never \"unresolved\": that means an HF id.\nfunction languagesInfo(e: NonNullable<ReturnType<typeof embedConfig>>): { languages: string[] | null; state: LanguagesState; source: 'config' | 'card' | null } {\n if (e.languages) return { languages: e.languages, state: 'declared', source: 'config' };\n if (e.provider !== 'static' || !isDownloadable(e.model)) return { languages: null, state: null, source: null };\n const cardLanguages = readLanguages(e.model);\n if (cardLanguages === undefined) return { languages: null, state: 'unresolved', source: null };\n if (cardLanguages.length === 0) return { languages: null, state: 'none', source: null };\n return { languages: cardLanguages, state: 'declared', source: 'card' };\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : { languages: null, state: null, source: null };\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Each store owns what it reports and how it is worded (Store.engineStatus); this command\n // prints entries generically, without branching on any store's name.\n const engine = await store.engineStatus();\n const watcher = readWatchClaim(cfg.configDir ?? cfg.rootDir ?? cfg.baseDir);\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.rootDir ?? cfg.baseDir,\n treeRoot: cfg.rootDir ?? cfg.baseDir,\n configDir: cfg.configDir ?? cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, languagesState, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: watcher ? String(watcher.pid) : null,\n watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null,\n engine,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree root: ${result.treeRoot}`);\n console.log(`configDir: ${result.configDir}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches automatically at first search, or run \\`${ctx.name} download\\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);\n if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);\n else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n else if (languagesState === 'none') console.log(' languages: none declared by the model card');\n else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \\`${ctx.name} download\\`)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n for (const [key, value] of Object.entries(result.engine)) console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["dirname","presetCoverage","embedConfig","featureStates","SUPPORTED_CONFIG_VERSION","languageDistribution","probeReachable","isDownloadable","MODEL_FILENAMES","modelDir","modelPresent","readLanguages","featuresLine","presetsLines","stringifyJson","docCount","getMeta","openStore","readWatchClaim","USAGE","CONFIG","FORMAT","formatOf","parse","printWarnings","vectorState","store","stmt","prepare","get","parseErrorCount","n","redactUrl","url","parsed","URL","username","password","toString","replace","embedReachable","e","provider","base","languagesInfo","languages","state","source","model","cardLanguages","undefined","length","status","ctx","cfg","process","values","argv","name","format","resolveConfig","config","dbPath","warnings","features","hasModel","reachable","vectors","presets","declaredLanguages","languagesState","languagesSource","detectedLanguages","cacheSchema","engine","engineStatus","watcher","configDir","rootDir","baseDir","keyEnv","key","set","env","result","configPath","configVersion","migratedFrom","unknownConfigKeys","unknownKeys","tree","treeRoot","cache","db","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","downloaded","queries","Object","keys","watcherPid","String","pid","watcherHeartbeatSecondsAgo","Math","round","Date","now","heartbeatMs","console","log","migrated","join","shown","embedded","pending","total","reduce","a","b","breakdown","entries","sort","map","code","line","value","padEnd","close"],"mappings":"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"}
@@ -270,6 +270,26 @@ async function lineRangeFor(store, path, line) {
270
270
  const row = await stmt.get(path, line, line);
271
271
  return row ? `L${row.start_line}-${row.end_line}` : null;
272
272
  }
273
+ function validateSearchOptions(opts) {
274
+ for (const [name, value] of [
275
+ [
276
+ 'k',
277
+ opts.k
278
+ ],
279
+ [
280
+ 'snippetCharLimit',
281
+ opts.snippetCharLimit
282
+ ],
283
+ [
284
+ 'snippetCountLimit',
285
+ opts.snippetCountLimit
286
+ ]
287
+ ]){
288
+ if (value !== undefined && (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0)) {
289
+ throw new SenseError('SEARCH_OPTION_INVALID', `search option "${name}" must be a positive finite integer, got ${String(value)}`);
290
+ }
291
+ }
292
+ }
273
293
  // Hydrates already-ranked rows with snippets and containing-section ranges without reranking.
274
294
  export async function hydrateSearchRows(store, cfg, rows, matchedPaths, terms, opts = {}) {
275
295
  var _opts_snippetCharLimit, _opts_snippetCountLimit;
@@ -294,6 +314,7 @@ export async function hydrateSearchRows(store, cfg, rows, matchedPaths, terms, o
294
314
  // The declared or defaulted signals compose via RRF; `via` names which ones produced each row.
295
315
  // `opts` arrives already resolved (config.ts:resolveSearch).
296
316
  export async function search(store, cfg, terms, opts = {}) {
317
+ validateSearchOptions(opts);
297
318
  const effective = resolveSearch(cfg, opts);
298
319
  const { k, signals } = effective;
299
320
  const allPaths = (await (await store.prepare('SELECT "path" FROM frontmatter')).all()).map((r)=>r.path);