sensemaking 0.4.0 → 0.6.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.
Files changed (93) hide show
  1. package/README.md +16 -7
  2. package/dist/cjs/cli.js +5 -1
  3. package/dist/cjs/cli.js.map +1 -1
  4. package/dist/cjs/commands/find.js +173 -10
  5. package/dist/cjs/commands/find.js.map +1 -1
  6. package/dist/cjs/commands/map.js +1 -1
  7. package/dist/cjs/commands/map.js.map +1 -1
  8. package/dist/cjs/commands/peek.js +1 -1
  9. package/dist/cjs/commands/peek.js.map +1 -1
  10. package/dist/cjs/commands/shared.d.cts +1 -1
  11. package/dist/cjs/commands/shared.d.ts +1 -1
  12. package/dist/cjs/commands/shared.js +166 -8
  13. package/dist/cjs/commands/shared.js.map +1 -1
  14. package/dist/cjs/commands/status.js +10 -1
  15. package/dist/cjs/commands/status.js.map +1 -1
  16. package/dist/cjs/commands/types.d.cts +1 -0
  17. package/dist/cjs/commands/types.d.ts +1 -0
  18. package/dist/cjs/config.d.cts +26 -2
  19. package/dist/cjs/config.d.ts +26 -2
  20. package/dist/cjs/config.js +171 -10
  21. package/dist/cjs/config.js.map +1 -1
  22. package/dist/cjs/db.js +46 -16
  23. package/dist/cjs/db.js.map +1 -1
  24. package/dist/cjs/errors.d.cts +1 -1
  25. package/dist/cjs/errors.d.ts +1 -1
  26. package/dist/cjs/errors.js.map +1 -1
  27. package/dist/cjs/features/embed.d.cts +14 -0
  28. package/dist/cjs/features/embed.d.ts +14 -0
  29. package/dist/cjs/features/embed.js +840 -0
  30. package/dist/cjs/features/embed.js.map +1 -0
  31. package/dist/cjs/features/index.js +3 -1
  32. package/dist/cjs/features/index.js.map +1 -1
  33. package/dist/cjs/features/types.d.cts +4 -1
  34. package/dist/cjs/features/types.d.ts +4 -1
  35. package/dist/cjs/index.d.cts +3 -10
  36. package/dist/cjs/index.d.ts +3 -10
  37. package/dist/cjs/index.js +2 -52
  38. package/dist/cjs/index.js.map +1 -1
  39. package/dist/cjs/output.d.cts +5 -0
  40. package/dist/cjs/output.d.ts +5 -0
  41. package/dist/cjs/output.js +14 -1
  42. package/dist/cjs/output.js.map +1 -1
  43. package/dist/cjs/scan.js +9 -8
  44. package/dist/cjs/scan.js.map +1 -1
  45. package/dist/cjs/verbs.d.cts +8 -2
  46. package/dist/cjs/verbs.d.ts +8 -2
  47. package/dist/cjs/verbs.js +263 -76
  48. package/dist/cjs/verbs.js.map +1 -1
  49. package/dist/esm/cli.js +5 -1
  50. package/dist/esm/cli.js.map +1 -1
  51. package/dist/esm/commands/find.js +5 -4
  52. package/dist/esm/commands/find.js.map +1 -1
  53. package/dist/esm/commands/map.js +1 -3
  54. package/dist/esm/commands/map.js.map +1 -1
  55. package/dist/esm/commands/peek.js +1 -1
  56. package/dist/esm/commands/peek.js.map +1 -1
  57. package/dist/esm/commands/shared.d.ts +1 -1
  58. package/dist/esm/commands/shared.js +2 -2
  59. package/dist/esm/commands/shared.js.map +1 -1
  60. package/dist/esm/commands/status.js +8 -1
  61. package/dist/esm/commands/status.js.map +1 -1
  62. package/dist/esm/commands/types.d.ts +1 -0
  63. package/dist/esm/commands/types.js.map +1 -1
  64. package/dist/esm/config.d.ts +26 -2
  65. package/dist/esm/config.js +88 -10
  66. package/dist/esm/config.js.map +1 -1
  67. package/dist/esm/db.js +19 -10
  68. package/dist/esm/db.js.map +1 -1
  69. package/dist/esm/errors.d.ts +1 -1
  70. package/dist/esm/errors.js.map +1 -1
  71. package/dist/esm/features/embed.d.ts +14 -0
  72. package/dist/esm/features/embed.js +290 -0
  73. package/dist/esm/features/embed.js.map +1 -0
  74. package/dist/esm/features/index.js +3 -1
  75. package/dist/esm/features/index.js.map +1 -1
  76. package/dist/esm/features/types.d.ts +4 -1
  77. package/dist/esm/features/types.js.map +1 -1
  78. package/dist/esm/index.d.ts +3 -10
  79. package/dist/esm/index.js +4 -6
  80. package/dist/esm/index.js.map +1 -1
  81. package/dist/esm/output.d.ts +5 -0
  82. package/dist/esm/output.js +11 -1
  83. package/dist/esm/output.js.map +1 -1
  84. package/dist/esm/scan.js +9 -8
  85. package/dist/esm/scan.js.map +1 -1
  86. package/dist/esm/verbs.d.ts +8 -2
  87. package/dist/esm/verbs.js +51 -13
  88. package/dist/esm/verbs.js.map +1 -1
  89. package/package.json +2 -1
  90. package/schema.json +17 -1
  91. package/skills/sense/EXAMPLES.md +16 -0
  92. package/skills/sense/SKILL.md +41 -19
  93. package/skills/sense-setup/SKILL.md +73 -0
package/dist/cjs/verbs.js CHANGED
@@ -22,6 +22,7 @@ _export(exports, {
22
22
  var _posix = /*#__PURE__*/ _interop_require_default(require("node:path/posix"));
23
23
  var _configts = require("./config.js");
24
24
  var _errorsts = require("./errors.js");
25
+ var _embedts = require("./features/embed.js");
25
26
  var _indexts = require("./features/index.js");
26
27
  var _graphts = require("./graph.js");
27
28
  function _array_like_to_array(arr, len) {
@@ -35,6 +36,35 @@ function _array_with_holes(arr) {
35
36
  function _array_without_holes(arr) {
36
37
  if (Array.isArray(arr)) return _array_like_to_array(arr);
37
38
  }
39
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
40
+ try {
41
+ var info = gen[key](arg);
42
+ var value = info.value;
43
+ } catch (error) {
44
+ reject(error);
45
+ return;
46
+ }
47
+ if (info.done) {
48
+ resolve(value);
49
+ } else {
50
+ Promise.resolve(value).then(_next, _throw);
51
+ }
52
+ }
53
+ function _async_to_generator(fn) {
54
+ return function() {
55
+ var self = this, args = arguments;
56
+ return new Promise(function(resolve, reject) {
57
+ var gen = fn.apply(self, args);
58
+ function _next(value) {
59
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
60
+ }
61
+ function _throw(err) {
62
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
63
+ }
64
+ _next(undefined);
65
+ });
66
+ };
67
+ }
38
68
  function _interop_require_default(obj) {
39
69
  return obj && obj.__esModule ? obj : {
40
70
  default: obj
@@ -87,87 +117,237 @@ function _unsupported_iterable_to_array(o, minLen) {
87
117
  if (n === "Map" || n === "Set") return Array.from(n);
88
118
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
89
119
  }
120
+ function _ts_generator(thisArg, body) {
121
+ var f, y, t, _ = {
122
+ label: 0,
123
+ sent: function() {
124
+ if (t[0] & 1) throw t[1];
125
+ return t[1];
126
+ },
127
+ trys: [],
128
+ ops: []
129
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
130
+ return d(g, "next", {
131
+ value: verb(0)
132
+ }), d(g, "throw", {
133
+ value: verb(1)
134
+ }), d(g, "return", {
135
+ value: verb(2)
136
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
137
+ value: function() {
138
+ return this;
139
+ }
140
+ }), g;
141
+ function verb(n) {
142
+ return function(v) {
143
+ return step([
144
+ n,
145
+ v
146
+ ]);
147
+ };
148
+ }
149
+ function step(op) {
150
+ if (f) throw new TypeError("Generator is already executing.");
151
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
152
+ 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;
153
+ if (y = 0, t) op = [
154
+ op[0] & 2,
155
+ t.value
156
+ ];
157
+ switch(op[0]){
158
+ case 0:
159
+ case 1:
160
+ t = op;
161
+ break;
162
+ case 4:
163
+ _.label++;
164
+ return {
165
+ value: op[1],
166
+ done: false
167
+ };
168
+ case 5:
169
+ _.label++;
170
+ y = op[1];
171
+ op = [
172
+ 0
173
+ ];
174
+ continue;
175
+ case 7:
176
+ op = _.ops.pop();
177
+ _.trys.pop();
178
+ continue;
179
+ default:
180
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
181
+ _ = 0;
182
+ continue;
183
+ }
184
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
185
+ _.label = op[1];
186
+ break;
187
+ }
188
+ if (op[0] === 6 && _.label < t[1]) {
189
+ _.label = t[1];
190
+ t = op;
191
+ break;
192
+ }
193
+ if (t && _.label < t[2]) {
194
+ _.label = t[2];
195
+ _.ops.push(op);
196
+ break;
197
+ }
198
+ if (t[2]) _.ops.pop();
199
+ _.trys.pop();
200
+ continue;
201
+ }
202
+ op = body.call(thisArg, _);
203
+ } catch (e) {
204
+ op = [
205
+ 6,
206
+ e
207
+ ];
208
+ y = 0;
209
+ } finally{
210
+ f = t = 0;
211
+ }
212
+ if (op[0] & 5) throw op[1];
213
+ return {
214
+ value: op[0] ? op[1] : void 0,
215
+ done: true
216
+ };
217
+ }
218
+ }
90
219
  // The three layer verbs: mapTree (orient), find (locate), peek (structure).
91
220
  // Each returns data; cli.ts renders. All of them degrade when a feature is off.
92
221
  var WEIGHTED_BM25 = 'bm25(content, 10.0, 5.0, 1.0)';
93
222
  var RRF_K = 60;
94
- function find(db, cfg, terms) {
95
- var opts = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
96
- var _opts_k, _hits_get;
97
- var k = (_opts_k = opts.k) !== null && _opts_k !== void 0 ? _opts_k : 10;
98
- var fetch = Math.max(k * 3, 30);
99
- // Terms pass verbatim to FTS5 MATCH: bare words AND-join, operators are the caller's.
100
- // Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.
101
- var matchSql = "SELECT content.path AS path, snippet(content, -1, '\xab', '\xbb', '…', 10) AS hit FROM content WHERE content MATCH ? ORDER BY ".concat(WEIGHTED_BM25, " LIMIT ").concat(fetch);
102
- var matchRows = db.prepare(matchSql).all(terms);
103
- var hits = new Map(matchRows.map(function(r) {
104
- return [
105
- r.path,
106
- r.hit
107
- ];
108
- }));
109
- var candidates = new Map();
110
- matchRows.forEach(function(r, i) {
111
- candidates.set(r.path, {
112
- score: 1 / (RRF_K + i),
113
- via: 'match'
114
- });
115
- });
116
- if ((0, _configts.featureEnabled)(cfg, 'links') && matchRows.length > 0) {
117
- var nodes = db.prepare('SELECT "path" FROM frontmatter').all().map(function(r) {
118
- return r.path;
119
- });
120
- var seeds = new Map(matchRows.map(function(r, i) {
121
- return [
122
- r.path,
123
- 1 / (i + 1)
124
- ];
125
- }));
126
- var ranked = _to_consumable_array((0, _graphts.personalizedRank)(nodes, (0, _indexts.linkEdges)(db), seeds)).filter(function(param) {
127
- var _param = _sliced_to_array(param, 2), score = _param[1];
128
- return score > 1e-9;
129
- }).sort(function(a, b) {
130
- return b[1] - a[1];
131
- }).slice(0, fetch);
132
- ranked.forEach(function(param, i) {
133
- var _param = _sliced_to_array(param, 1), path = _param[0];
134
- var existing = candidates.get(path);
135
- if (existing) {
136
- existing.score += 1 / (RRF_K + i);
137
- existing.via = 'match+link';
138
- } else {
139
- candidates.set(path, {
140
- score: 1 / (RRF_K + i),
141
- via: 'link'
142
- });
223
+ function find(_0, _1, _2) {
224
+ return _async_to_generator(function(db, cfg, terms) {
225
+ var opts, _opts_k, _hits_get, _chunkLines_get, k, fetch, whereJoin, whereCond, matchSql, matchRows, hits, candidates, edges, linked, nodes, seeds, ranked, chunkLines, vec, insert, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step_value, path, c, where, linesCol;
226
+ var _arguments = arguments;
227
+ return _ts_generator(this, function(_state) {
228
+ switch(_state.label){
229
+ case 0:
230
+ opts = _arguments.length > 3 && _arguments[3] !== void 0 ? _arguments[3] : {};
231
+ k = (_opts_k = opts.k) !== null && _opts_k !== void 0 ? _opts_k : 10;
232
+ fetch = Math.max(k * 3, 30);
233
+ // Terms pass verbatim to FTS5 MATCH: bare words AND-join, operators are the caller's.
234
+ // Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.
235
+ // --where applies inside the candidate query (a post-filter over the top-N would drop
236
+ // matches ranked past the pool) and again on the final select for link-derived rows.
237
+ whereJoin = opts.where ? 'JOIN frontmatter f ON f."path" = content.path' : '';
238
+ whereCond = opts.where ? "AND (".concat(opts.where, ")") : '';
239
+ matchSql = "SELECT content.path AS path, snippet(content, -1, '\xab', '\xbb', '…', 10) AS hit FROM content ".concat(whereJoin, " WHERE content MATCH ? ").concat(whereCond, " ORDER BY ").concat(WEIGHTED_BM25, " LIMIT ").concat(fetch);
240
+ matchRows = db.prepare(matchSql).all(terms);
241
+ hits = new Map(matchRows.map(function(r) {
242
+ return [
243
+ r.path,
244
+ r.hit
245
+ ];
246
+ }));
247
+ candidates = new Map();
248
+ matchRows.forEach(function(r, i) {
249
+ candidates.set(r.path, {
250
+ score: 1 / (RRF_K + i),
251
+ via: 'match'
252
+ });
253
+ });
254
+ edges = (0, _configts.featureEnabled)(cfg, 'links') && matchRows.length > 0 ? (0, _indexts.linkEdges)(db) : [];
255
+ if (edges.length > 0) {
256
+ // `linked` gates the label only, not the score: PPR restart mass gives every seed a
257
+ // nonzero rank even without an incident edge, which is not link evidence — but dropping
258
+ // that mass from the score list reweights fusion toward connectivity and measurably
259
+ // wrecks ranking on link-dense corpora (FEVER hit@10 0.997 -> 0.907; fusion-tuning.md).
260
+ linked = new Set(edges.flat());
261
+ nodes = db.prepare('SELECT "path" FROM frontmatter').all().map(function(r) {
262
+ return r.path;
263
+ });
264
+ seeds = new Map(matchRows.map(function(r, i) {
265
+ return [
266
+ r.path,
267
+ 1 / (i + 1)
268
+ ];
269
+ }));
270
+ ranked = _to_consumable_array((0, _graphts.personalizedRank)(nodes, edges, seeds)).filter(function(param) {
271
+ var _param = _sliced_to_array(param, 2), score = _param[1];
272
+ return score > 1e-9;
273
+ }).sort(function(a, b) {
274
+ return b[1] - a[1];
275
+ }).slice(0, fetch);
276
+ ranked.forEach(function(param, i) {
277
+ var _param = _sliced_to_array(param, 1), path = _param[0];
278
+ var existing = candidates.get(path);
279
+ if (existing) {
280
+ existing.score += 1 / (RRF_K + i);
281
+ if (linked.has(path)) existing.via = 'match+link';
282
+ } else {
283
+ candidates.set(path, {
284
+ score: 1 / (RRF_K + i),
285
+ via: 'link'
286
+ });
287
+ }
288
+ });
289
+ }
290
+ // Vector expansion, invoked only: a third RRF list at the swept flat-region constants
291
+ // (weight 1, pool = fetch). Each row carries its best chunk's line range.
292
+ chunkLines = new Map();
293
+ if (!opts.semantic) return [
294
+ 3,
295
+ 2
296
+ ];
297
+ return [
298
+ 4,
299
+ (0, _embedts.semanticCandidates)(db, cfg, terms, fetch)
300
+ ];
301
+ case 1:
302
+ vec = _state.sent();
303
+ vec.forEach(function(param, i) {
304
+ var path = param.path, lines = param.lines;
305
+ chunkLines.set(path, lines);
306
+ var existing = candidates.get(path);
307
+ if (existing) {
308
+ existing.score += 1 / (RRF_K + i);
309
+ existing.via = "".concat(existing.via, "+vector");
310
+ } else {
311
+ candidates.set(path, {
312
+ score: 1 / (RRF_K + i),
313
+ via: 'vector'
314
+ });
315
+ }
316
+ });
317
+ _state.label = 2;
318
+ case 2:
319
+ db.exec('DROP TABLE IF EXISTS _find');
320
+ db.exec('CREATE TEMP TABLE _find ("path" TEXT PRIMARY KEY, score REAL, via TEXT, hit TEXT, lines TEXT)');
321
+ insert = db.prepare('INSERT INTO _find ("path", score, via, hit, lines) VALUES (?, ?, ?, ?, ?)');
322
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
323
+ try {
324
+ for(_iterator = candidates[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
325
+ _step_value = _sliced_to_array(_step.value, 2), path = _step_value[0], c = _step_value[1];
326
+ insert.run(path, c.score, c.via, (_hits_get = hits.get(path)) !== null && _hits_get !== void 0 ? _hits_get : null, (_chunkLines_get = chunkLines.get(path)) !== null && _chunkLines_get !== void 0 ? _chunkLines_get : null);
327
+ }
328
+ } catch (err) {
329
+ _didIteratorError = true;
330
+ _iteratorError = err;
331
+ } finally{
332
+ try {
333
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
334
+ _iterator.return();
335
+ }
336
+ } finally{
337
+ if (_didIteratorError) {
338
+ throw _iteratorError;
339
+ }
340
+ }
341
+ }
342
+ where = opts.where ? "WHERE ".concat(opts.where) : '';
343
+ linesCol = opts.semantic ? ', _find.lines' : '';
344
+ return [
345
+ 2,
346
+ db.prepare('SELECT f."path" AS path, content.title, content.summary, _find.hit, _find.via, round(_find.score, 4) AS score'.concat(linesCol, '\n FROM _find JOIN frontmatter f ON f."path" = _find."path" JOIN content ON content.path = _find."path"\n ').concat(where, " ORDER BY _find.score DESC LIMIT ?")).all(k)
347
+ ];
143
348
  }
144
349
  });
145
- }
146
- db.exec('CREATE TEMP TABLE IF NOT EXISTS _find ("path" TEXT PRIMARY KEY, score REAL, via TEXT, hit TEXT)');
147
- db.exec('DELETE FROM _find');
148
- var insert = db.prepare('INSERT INTO _find ("path", score, via, hit) VALUES (?, ?, ?, ?)');
149
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
150
- try {
151
- for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
152
- var _step_value = _sliced_to_array(_step.value, 2), path = _step_value[0], c = _step_value[1];
153
- insert.run(path, c.score, c.via, (_hits_get = hits.get(path)) !== null && _hits_get !== void 0 ? _hits_get : null);
154
- }
155
- } catch (err) {
156
- _didIteratorError = true;
157
- _iteratorError = err;
158
- } finally{
159
- try {
160
- if (!_iteratorNormalCompletion && _iterator.return != null) {
161
- _iterator.return();
162
- }
163
- } finally{
164
- if (_didIteratorError) {
165
- throw _iteratorError;
166
- }
167
- }
168
- }
169
- var where = opts.where ? "WHERE ".concat(opts.where) : '';
170
- return db.prepare('SELECT f."path" AS path, content.title, content.summary, _find.hit, _find.via, round(_find.score, 4) AS score\n FROM _find JOIN frontmatter f ON f."path" = _find."path" JOIN content ON content.path = _find."path"\n '.concat(where, " ORDER BY _find.score DESC LIMIT ?")).all(k);
350
+ }).apply(this, arguments);
171
351
  }
172
352
  var INTERNAL_COLUMNS = new Set([
173
353
  'path',
@@ -198,6 +378,7 @@ function mapTree(db, cfg) {
198
378
  docs: docs,
199
379
  fields: fields,
200
380
  fieldsTotal: allFields.length,
381
+ features: (0, _configts.featureStates)(cfg),
201
382
  hubs: hubs,
202
383
  recent: recent
203
384
  };
@@ -274,7 +455,13 @@ function peek(db, cfg, pathArg) {
274
455
  unresolved: unresolved.slice(0, PEEK_LINK_LIMIT),
275
456
  outboundTotal: outbound.length,
276
457
  backlinksTotal: backlinksTotal,
277
- unresolvedTotal: unresolved.length
458
+ unresolvedTotal: unresolved.length,
459
+ off: [
460
+ 'sections',
461
+ 'links'
462
+ ].filter(function(name) {
463
+ return !(0, _configts.featureEnabled)(cfg, name);
464
+ })
278
465
  };
279
466
  }
280
467
  /* 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; }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/verbs.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { Config } from './config.ts';\nimport { featureEnabled } from './config.ts';\nimport { SenseError } from './errors.ts';\nimport { linkEdges } from './features/index.ts';\nimport { personalizedRank } from './graph.ts';\nimport type { Row } from './output.ts';\n\n// The three layer verbs: mapTree (orient), find (locate), peek (structure).\n// Each returns data; cli.ts renders. All of them degrade when a feature is off.\n\nconst WEIGHTED_BM25 = 'bm25(content, 10.0, 5.0, 1.0)';\nconst RRF_K = 60;\n\nexport interface FindOptions {\n k?: number;\n where?: string; // SQL fragment against frontmatter alias `f`, e.g. \"f.status = 'active'\"\n}\n\n// Layer 1: BM25 + link-graph expansion, fused by reciprocal rank. `via` says which\n// signal produced each row so the agent knows what evidence it is trusting.\nexport function find(db: DatabaseSync, cfg: Config, terms: string, opts: FindOptions = {}): Row[] {\n const k = opts.k ?? 10;\n const fetch = Math.max(k * 3, 30);\n\n // Terms pass verbatim to FTS5 MATCH: bare words AND-join, operators are the caller's.\n // Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.\n const matchSql = `SELECT content.path AS path, snippet(content, -1, '«', '»', '…', 10) AS hit FROM content WHERE content MATCH ? ORDER BY ${WEIGHTED_BM25} LIMIT ${fetch}`;\n const matchRows = db.prepare(matchSql).all(terms) as Array<{ path: string; hit: string }>;\n\n const hits = new Map(matchRows.map((r) => [r.path, r.hit]));\n const candidates = new Map<string, { score: number; via: string }>();\n matchRows.forEach((r, i) => {\n candidates.set(r.path, { score: 1 / (RRF_K + i), via: 'match' });\n });\n\n if (featureEnabled(cfg, 'links') && matchRows.length > 0) {\n const nodes = (db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path);\n const seeds = new Map(matchRows.map((r, i) => [r.path, 1 / (i + 1)]));\n const ranked = [...personalizedRank(nodes, linkEdges(db), seeds)]\n .filter(([, score]) => score > 1e-9)\n .sort((a, b) => b[1] - a[1])\n .slice(0, fetch);\n ranked.forEach(([path], i) => {\n const existing = candidates.get(path);\n if (existing) {\n existing.score += 1 / (RRF_K + i);\n existing.via = 'match+link';\n } else {\n candidates.set(path, { score: 1 / (RRF_K + i), via: 'link' });\n }\n });\n }\n\n db.exec('CREATE TEMP TABLE IF NOT EXISTS _find (\"path\" TEXT PRIMARY KEY, score REAL, via TEXT, hit TEXT)');\n db.exec('DELETE FROM _find');\n const insert = db.prepare('INSERT INTO _find (\"path\", score, via, hit) VALUES (?, ?, ?, ?)');\n for (const [path, c] of candidates) insert.run(path, c.score, c.via, hits.get(path) ?? null);\n\n const where = opts.where ? `WHERE ${opts.where}` : '';\n return db\n .prepare(\n `SELECT f.\"path\" AS path, content.title, content.summary, _find.hit, _find.via, round(_find.score, 4) AS score\n FROM _find JOIN frontmatter f ON f.\"path\" = _find.\"path\" JOIN content ON content.path = _find.\"path\"\n ${where} ORDER BY _find.score DESC LIMIT ?`\n )\n .all(k) as Row[];\n}\n\nexport interface TreeMap {\n docs: { count: number; bytes: number };\n fields: Row[]; // top 20 by coverage; fieldsTotal carries the real count\n fieldsTotal: number;\n hubs: Row[];\n recent: Row[];\n}\n\nconst INTERNAL_COLUMNS = new Set(['path', '_mtime', '_size', '_rank']);\n\n// Layer 0: what is this tree. Fixed-size output regardless of tree size.\nexport function mapTree(db: DatabaseSync, cfg: Config): TreeMap {\n const docs = db.prepare('SELECT COUNT(*) AS count, COALESCE(SUM(\"_size\"), 0) AS bytes FROM frontmatter').get() as { count: number; bytes: number };\n\n const columns = (db.prepare('PRAGMA table_info(frontmatter)').all() as Array<{ name: string }>).map((r) => r.name).filter((name) => !INTERNAL_COLUMNS.has(name));\n const allFields = columns\n .map((name) => {\n const { n } = db.prepare(`SELECT COUNT(\"${name.split('\"').join('\"\"')}\") AS n FROM frontmatter`).get() as { n: number };\n return { field: name, coverage: n };\n })\n .sort((a, b) => (b.coverage as number) - (a.coverage as number)) as Row[];\n const fields = allFields.slice(0, 20);\n\n const hubs = featureEnabled(cfg, 'rank') ? (db.prepare(`SELECT f.\"path\" AS path, round(f.\"_rank\" * 100, 2) AS rank, content.title FROM frontmatter f JOIN content ON content.path = f.\"path\" WHERE f.\"_rank\" IS NOT NULL ORDER BY f.\"_rank\" DESC LIMIT 8`).all() as Row[]) : [];\n\n const recent = db.prepare(`SELECT \"path\", datetime(\"_mtime\" / 1000, 'unixepoch') AS modified FROM frontmatter ORDER BY \"_mtime\" DESC LIMIT 5`).all() as Row[];\n\n return { docs, fields, fieldsTotal: allFields.length, hubs, recent };\n}\n\nexport interface Peek {\n path: string;\n tokens: number;\n frontmatter: Row;\n sections: Row[];\n outbound: string[];\n backlinks: string[];\n unresolved: string[];\n // Totals before truncation: a hub can have thousands of backlinks, and peek's whole\n // point is bounded output. Query the links table directly for the full list.\n outboundTotal: number;\n backlinksTotal: number;\n unresolvedTotal: number;\n}\n\nconst PEEK_LINK_LIMIT = 20;\n\n// Layer 2: everything about one note except its prose -- frontmatter, outline with line\n// ranges + token estimates (so the follow-up Read is a range, not the file), links both ways.\nexport function peek(db: DatabaseSync, cfg: Config, pathArg: string): Peek {\n const paths = (db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path);\n let path = paths.find((p) => p === pathArg);\n if (!path) {\n const base = posix.basename(pathArg).replace(/\\.md$/i, '').toLowerCase();\n const matches = paths.filter((p) => posix.basename(p).replace(/\\.md$/i, '').toLowerCase() === base);\n if (matches.length === 1) path = matches[0];\n else if (matches.length > 1) throw new SenseError('NOTE_AMBIGUOUS', `\"${pathArg}\" is ambiguous: ${matches.join(', ')}`);\n else throw new SenseError('NOTE_NOT_FOUND', `no note matches \"${pathArg}\"`);\n }\n\n const row = db.prepare('SELECT * FROM frontmatter WHERE \"path\" = ?').get(path) as Row;\n const frontmatter: Row = {};\n for (const [key, value] of Object.entries(row)) {\n if (!INTERNAL_COLUMNS.has(key) && value !== null) frontmatter[key] = value;\n }\n\n const sections = featureEnabled(cfg, 'sections') ? (db.prepare('SELECT level, heading, start_line, end_line, tokens FROM sections WHERE \"path\" = ? ORDER BY idx').all(path) as Row[]) : [];\n\n let outbound: string[] = [];\n let backlinks: string[] = [];\n let unresolved: string[] = [];\n let backlinksTotal = 0;\n if (featureEnabled(cfg, 'links')) {\n const out = db.prepare('SELECT target, dst FROM links WHERE src = ? ORDER BY target').all(path) as Array<{ target: string; dst: string | null }>;\n outbound = [...new Set(out.filter((l) => l.dst !== null).map((l) => l.dst as string))];\n unresolved = out.filter((l) => l.dst === null).map((l) => l.target);\n backlinksTotal = (db.prepare('SELECT COUNT(DISTINCT src) AS n FROM links WHERE dst = ?').get(path) as { n: number }).n;\n backlinks = (db.prepare('SELECT DISTINCT src FROM links WHERE dst = ? ORDER BY src LIMIT ?').all(path, PEEK_LINK_LIMIT) as Array<{ src: string }>).map((r) => r.src);\n }\n\n return {\n path,\n tokens: Math.ceil(((row._size as number) ?? 0) / 4),\n frontmatter,\n sections,\n outbound: outbound.slice(0, PEEK_LINK_LIMIT),\n backlinks,\n unresolved: unresolved.slice(0, PEEK_LINK_LIMIT),\n outboundTotal: outbound.length,\n backlinksTotal,\n unresolvedTotal: unresolved.length,\n };\n}\n"],"names":["find","mapTree","peek","WEIGHTED_BM25","RRF_K","db","cfg","terms","opts","hits","k","fetch","Math","max","matchSql","matchRows","prepare","all","Map","map","r","path","hit","candidates","forEach","i","set","score","via","featureEnabled","length","nodes","seeds","ranked","personalizedRank","linkEdges","filter","sort","a","b","slice","existing","get","exec","insert","c","run","where","INTERNAL_COLUMNS","Set","docs","columns","name","has","allFields","n","split","join","field","coverage","fields","hubs","recent","fieldsTotal","PEEK_LINK_LIMIT","pathArg","row","paths","p","base","posix","basename","replace","toLowerCase","matches","SenseError","frontmatter","Object","entries","key","value","sections","outbound","backlinks","unresolved","backlinksTotal","out","l","dst","target","src","tokens","ceil","_size","outboundTotal","unresolvedTotal"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/verbs.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { Config, FeatureName } from './config.ts';\nimport { featureEnabled, featureStates } from './config.ts';\nimport { SenseError } from './errors.ts';\nimport { semanticCandidates } from './features/embed.ts';\nimport { linkEdges } from './features/index.ts';\nimport { personalizedRank } from './graph.ts';\nimport type { Row } from './output.ts';\n\n// The three layer verbs: mapTree (orient), find (locate), peek (structure).\n// Each returns data; cli.ts renders. All of them degrade when a feature is off.\n\nconst WEIGHTED_BM25 = 'bm25(content, 10.0, 5.0, 1.0)';\nconst RRF_K = 60;\n\nexport interface FindOptions {\n k?: number;\n where?: string; // SQL fragment against frontmatter alias `f`, e.g. \"f.status = 'active'\"\n semantic?: boolean; // invoke vector expansion (requires features.embed); rows gain via 'vector' and a lines column\n}\n\n// Layer 1: BM25 + link-graph expansion, fused by reciprocal rank. `via` says which\n// signal produced each row so the agent knows what evidence it is trusting.\n// Semantic expansion is per-query opt-in: without opts.semantic the result is\n// byte-for-byte independent of the embed feature.\nexport async function find(db: DatabaseSync, cfg: Config, terms: string, opts: FindOptions = {}): Promise<Row[]> {\n const k = opts.k ?? 10;\n const fetch = Math.max(k * 3, 30);\n\n // Terms pass verbatim to FTS5 MATCH: bare words AND-join, operators are the caller's.\n // Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.\n // --where applies inside the candidate query (a post-filter over the top-N would drop\n // matches ranked past the pool) and again on the final select for link-derived rows.\n const whereJoin = opts.where ? `JOIN frontmatter f ON f.\"path\" = content.path` : '';\n const whereCond = opts.where ? `AND (${opts.where})` : '';\n const matchSql = `SELECT content.path AS path, snippet(content, -1, '«', '»', '…', 10) AS hit FROM content ${whereJoin} WHERE content MATCH ? ${whereCond} ORDER BY ${WEIGHTED_BM25} LIMIT ${fetch}`;\n const matchRows = db.prepare(matchSql).all(terms) as Array<{ path: string; hit: string }>;\n\n const hits = new Map(matchRows.map((r) => [r.path, r.hit]));\n const candidates = new Map<string, { score: number; via: string }>();\n matchRows.forEach((r, i) => {\n candidates.set(r.path, { score: 1 / (RRF_K + i), via: 'match' });\n });\n\n const edges = featureEnabled(cfg, 'links') && matchRows.length > 0 ? linkEdges(db) : [];\n if (edges.length > 0) {\n // `linked` gates the label only, not the score: PPR restart mass gives every seed a\n // nonzero rank even without an incident edge, which is not link evidence — but dropping\n // that mass from the score list reweights fusion toward connectivity and measurably\n // wrecks ranking on link-dense corpora (FEVER hit@10 0.997 -> 0.907; fusion-tuning.md).\n const linked = new Set(edges.flat());\n const nodes = (db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path);\n const seeds = new Map(matchRows.map((r, i) => [r.path, 1 / (i + 1)]));\n const ranked = [...personalizedRank(nodes, edges, seeds)]\n .filter(([, score]) => score > 1e-9)\n .sort((a, b) => b[1] - a[1])\n .slice(0, fetch);\n ranked.forEach(([path], i) => {\n const existing = candidates.get(path);\n if (existing) {\n existing.score += 1 / (RRF_K + i);\n if (linked.has(path)) existing.via = 'match+link';\n } else {\n candidates.set(path, { score: 1 / (RRF_K + i), via: 'link' });\n }\n });\n }\n\n // Vector expansion, invoked only: a third RRF list at the swept flat-region constants\n // (weight 1, pool = fetch). Each row carries its best chunk's line range.\n const chunkLines = new Map<string, string>();\n if (opts.semantic) {\n const vec = await semanticCandidates(db, cfg, terms, fetch);\n vec.forEach(({ path, lines }, i) => {\n chunkLines.set(path, lines);\n const existing = candidates.get(path);\n if (existing) {\n existing.score += 1 / (RRF_K + i);\n existing.via = `${existing.via}+vector`;\n } else {\n candidates.set(path, { score: 1 / (RRF_K + i), via: 'vector' });\n }\n });\n }\n\n db.exec('DROP TABLE IF EXISTS _find');\n db.exec('CREATE TEMP TABLE _find (\"path\" TEXT PRIMARY KEY, score REAL, via TEXT, hit TEXT, lines TEXT)');\n const insert = db.prepare('INSERT INTO _find (\"path\", score, via, hit, lines) VALUES (?, ?, ?, ?, ?)');\n for (const [path, c] of candidates) insert.run(path, c.score, c.via, hits.get(path) ?? null, chunkLines.get(path) ?? null);\n\n const where = opts.where ? `WHERE ${opts.where}` : '';\n const linesCol = opts.semantic ? ', _find.lines' : '';\n return db\n .prepare(\n `SELECT f.\"path\" AS path, content.title, content.summary, _find.hit, _find.via, round(_find.score, 4) AS score${linesCol}\n FROM _find JOIN frontmatter f ON f.\"path\" = _find.\"path\" JOIN content ON content.path = _find.\"path\"\n ${where} ORDER BY _find.score DESC LIMIT ?`\n )\n .all(k) as Row[];\n}\n\nexport interface TreeMap {\n docs: { count: number; bytes: number };\n fields: Row[]; // top 20 by coverage; fieldsTotal carries the real count\n fieldsTotal: number;\n features: { on: FeatureName[]; off: FeatureName[] };\n hubs: Row[];\n recent: Row[];\n}\n\nconst INTERNAL_COLUMNS = new Set(['path', '_mtime', '_size', '_rank']);\n\n// Layer 0: what is this tree. Fixed-size output regardless of tree size.\nexport function mapTree(db: DatabaseSync, cfg: Config): TreeMap {\n const docs = db.prepare('SELECT COUNT(*) AS count, COALESCE(SUM(\"_size\"), 0) AS bytes FROM frontmatter').get() as { count: number; bytes: number };\n\n const columns = (db.prepare('PRAGMA table_info(frontmatter)').all() as Array<{ name: string }>).map((r) => r.name).filter((name) => !INTERNAL_COLUMNS.has(name));\n const allFields = columns\n .map((name) => {\n const { n } = db.prepare(`SELECT COUNT(\"${name.split('\"').join('\"\"')}\") AS n FROM frontmatter`).get() as { n: number };\n return { field: name, coverage: n };\n })\n .sort((a, b) => (b.coverage as number) - (a.coverage as number)) as Row[];\n const fields = allFields.slice(0, 20);\n\n const hubs = featureEnabled(cfg, 'rank') ? (db.prepare(`SELECT f.\"path\" AS path, round(f.\"_rank\" * 100, 2) AS rank, content.title FROM frontmatter f JOIN content ON content.path = f.\"path\" WHERE f.\"_rank\" IS NOT NULL ORDER BY f.\"_rank\" DESC LIMIT 8`).all() as Row[]) : [];\n\n const recent = db.prepare(`SELECT \"path\", datetime(\"_mtime\" / 1000, 'unixepoch') AS modified FROM frontmatter ORDER BY \"_mtime\" DESC LIMIT 5`).all() as Row[];\n\n return { docs, fields, fieldsTotal: allFields.length, features: featureStates(cfg), hubs, recent };\n}\n\nexport interface Peek {\n path: string;\n tokens: number;\n frontmatter: Row;\n sections: Row[];\n outbound: string[];\n backlinks: string[];\n unresolved: string[];\n // Totals before truncation: a hub can have thousands of backlinks, and peek's whole\n // point is bounded output. Query the links table directly for the full list.\n outboundTotal: number;\n backlinksTotal: number;\n unresolvedTotal: number;\n off: FeatureName[]; // disabled features whose blocks are omitted (not empty)\n}\n\nconst PEEK_LINK_LIMIT = 20;\n\n// Layer 2: everything about one note except its prose -- frontmatter, outline with line\n// ranges + token estimates (so the follow-up Read is a range, not the file), links both ways.\nexport function peek(db: DatabaseSync, cfg: Config, pathArg: string): Peek {\n const paths = (db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path);\n let path = paths.find((p) => p === pathArg);\n if (!path) {\n const base = posix.basename(pathArg).replace(/\\.md$/i, '').toLowerCase();\n const matches = paths.filter((p) => posix.basename(p).replace(/\\.md$/i, '').toLowerCase() === base);\n if (matches.length === 1) path = matches[0];\n else if (matches.length > 1) throw new SenseError('NOTE_AMBIGUOUS', `\"${pathArg}\" is ambiguous: ${matches.join(', ')}`);\n else throw new SenseError('NOTE_NOT_FOUND', `no note matches \"${pathArg}\"`);\n }\n\n const row = db.prepare('SELECT * FROM frontmatter WHERE \"path\" = ?').get(path) as Row;\n const frontmatter: Row = {};\n for (const [key, value] of Object.entries(row)) {\n if (!INTERNAL_COLUMNS.has(key) && value !== null) frontmatter[key] = value;\n }\n\n const sections = featureEnabled(cfg, 'sections') ? (db.prepare('SELECT level, heading, start_line, end_line, tokens FROM sections WHERE \"path\" = ? ORDER BY idx').all(path) as Row[]) : [];\n\n let outbound: string[] = [];\n let backlinks: string[] = [];\n let unresolved: string[] = [];\n let backlinksTotal = 0;\n if (featureEnabled(cfg, 'links')) {\n const out = db.prepare('SELECT target, dst FROM links WHERE src = ? ORDER BY target').all(path) as Array<{ target: string; dst: string | null }>;\n outbound = [...new Set(out.filter((l) => l.dst !== null).map((l) => l.dst as string))];\n unresolved = out.filter((l) => l.dst === null).map((l) => l.target);\n backlinksTotal = (db.prepare('SELECT COUNT(DISTINCT src) AS n FROM links WHERE dst = ?').get(path) as { n: number }).n;\n backlinks = (db.prepare('SELECT DISTINCT src FROM links WHERE dst = ? ORDER BY src LIMIT ?').all(path, PEEK_LINK_LIMIT) as Array<{ src: string }>).map((r) => r.src);\n }\n\n return {\n path,\n tokens: Math.ceil(((row._size as number) ?? 0) / 4),\n frontmatter,\n sections,\n outbound: outbound.slice(0, PEEK_LINK_LIMIT),\n backlinks,\n unresolved: unresolved.slice(0, PEEK_LINK_LIMIT),\n outboundTotal: outbound.length,\n backlinksTotal,\n unresolvedTotal: unresolved.length,\n off: (['sections', 'links'] as FeatureName[]).filter((name) => !featureEnabled(cfg, name)),\n };\n}\n"],"names":["find","mapTree","peek","WEIGHTED_BM25","RRF_K","db","cfg","terms","opts","hits","chunkLines","k","fetch","whereJoin","whereCond","matchSql","matchRows","candidates","edges","linked","nodes","seeds","ranked","vec","insert","path","c","where","linesCol","Math","max","prepare","all","Map","map","r","hit","forEach","i","set","score","via","featureEnabled","length","linkEdges","Set","flat","personalizedRank","filter","sort","a","b","slice","existing","get","has","semantic","semanticCandidates","lines","exec","run","INTERNAL_COLUMNS","docs","columns","name","allFields","n","split","join","field","coverage","fields","hubs","recent","fieldsTotal","features","featureStates","PEEK_LINK_LIMIT","pathArg","row","paths","p","base","posix","basename","replace","toLowerCase","matches","SenseError","frontmatter","Object","entries","key","value","sections","outbound","backlinks","unresolved","backlinksTotal","out","l","dst","target","src","tokens","ceil","_size","outboundTotal","unresolvedTotal","off"],"mappings":"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"}
package/dist/esm/cli.js CHANGED
@@ -20,7 +20,7 @@ function packageVersion() {
20
20
  return 'unknown';
21
21
  }
22
22
  function usage(name) {
23
- return `usage: ${name} <name> [params...] [--format table|json] [--config path]\n` + ` ${name} query "<sql>" [params...]\n` + ` ${name} find "<terms>" [--where "<sql>"] [--k n]\n` + ` ${name} map\n` + ` ${name} peek <path>\n` + ` ${name} --list\n` + ` ${name} init\n` + ` ${name} watch [--force]\n` + ` ${name} status\n` + ` ${name} rebuild\n` + ` ${name} --version`;
23
+ return `usage: ${name} <name> [params...] [--format table|json] [--config path]\n` + ` ${name} query "<sql>" [params...]\n` + ` ${name} find "<terms>" [--where "<sql>"] [--k n] [--semantic]\n` + ` ${name} map\n` + ` ${name} peek <path>\n` + ` ${name} --list\n` + ` ${name} init\n` + ` ${name} watch [--force]\n` + ` ${name} status\n` + ` ${name} rebuild\n` + ` ${name} --version`;
24
24
  }
25
25
  // Thrown errors -> exit 1 with the message verbatim; usage errors exit 2 directly.
26
26
  export default async function cli(argv, name) {
@@ -43,6 +43,10 @@ export default async function cli(argv, name) {
43
43
  k: {
44
44
  type: 'string'
45
45
  },
46
+ semantic: {
47
+ type: 'boolean',
48
+ default: false
49
+ },
46
50
  list: {
47
51
  type: 'boolean',
48
52
  default: false
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { parseArgs } from 'node:util';\nimport { COMMANDS } from './commands/index.ts';\nimport type { Ctx } from './commands/types.ts';\nimport { loadConfig, SUPPORTED_CONFIG_VERSION } from './config.ts';\n\n// Parsing and dispatch only. Commands live in src/commands/, one file each, lazy-loaded --\n// nothing tree- or dependency-heavy may be imported at the top of this file.\n\n// Works from dist/cjs and dist/esm alike: walk up past the dist type-marker package.json.\nfunction packageVersion(): string {\n const load = createRequire(import.meta.url);\n for (const rel of ['../package.json', '../../package.json', '../../../package.json']) {\n try {\n const pkg = load(rel) as { name?: string; version?: string };\n if (pkg.name === 'sensemaking' && pkg.version) return pkg.version;\n } catch {}\n }\n return 'unknown';\n}\n\nfunction usage(name: string): string {\n return (\n `usage: ${name} <name> [params...] [--format table|json] [--config path]\\n` +\n ` ${name} query \"<sql>\" [params...]\\n` +\n ` ${name} find \"<terms>\" [--where \"<sql>\"] [--k n]\\n` +\n ` ${name} map\\n` +\n ` ${name} peek <path>\\n` +\n ` ${name} --list\\n` +\n ` ${name} init\\n` +\n ` ${name} watch [--force]\\n` +\n ` ${name} status\\n` +\n ` ${name} rebuild\\n` +\n ` ${name} --version`\n );\n}\n\n// Thrown errors -> exit 1 with the message verbatim; usage errors exit 2 directly.\nexport default async function cli(argv: string[], name: string): Promise<void> {\n let values: Record<string, string | boolean | undefined>;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: {\n format: { type: 'string', default: 'table' },\n config: { type: 'string' },\n where: { type: 'string' },\n k: { type: 'string' },\n list: { type: 'boolean', default: false },\n force: { type: 'boolean', default: false },\n version: { type: 'boolean', default: false, short: 'v' },\n help: { type: 'boolean', default: false, short: 'h' },\n },\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage(name));\n process.exit(2);\n }\n\n if (values.version) {\n console.log(`v${packageVersion()}`);\n return;\n }\n if (values.help) {\n console.log(usage(name));\n return;\n }\n\n const ctx: Ctx = {\n name,\n rest: positionals.slice(1),\n format: values.format === 'json' ? 'json' : 'table',\n values: values as Ctx['values'],\n resolveConfig() {\n const cfg = loadConfig(values.config as string | undefined);\n if (cfg.migratedFrom !== undefined) {\n console.warn(`${name}: migrated ${cfg.configPath} from config version ${cfg.migratedFrom} to ${SUPPORTED_CONFIG_VERSION}`);\n }\n return cfg;\n },\n usageError(message) {\n console.error(message);\n process.exit(2);\n },\n };\n\n try {\n if (values.list) {\n for (const queryName of Object.keys(ctx.resolveConfig().queries).sort()) console.log(queryName);\n return;\n }\n\n const [first, ...params] = positionals;\n if (!first) {\n console.error(usage(name));\n process.exit(2);\n }\n\n const load = COMMANDS[first];\n if (load) await (await load()).default(ctx);\n else (await import('./commands/named.ts')).default(ctx, first, params);\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n}\n"],"names":["createRequire","parseArgs","COMMANDS","loadConfig","SUPPORTED_CONFIG_VERSION","packageVersion","load","url","rel","pkg","name","version","usage","cli","argv","values","positionals","args","options","format","type","default","config","where","k","list","force","short","help","allowPositionals","err","console","error","message","process","exit","log","ctx","rest","slice","resolveConfig","cfg","migratedFrom","undefined","warn","configPath","usageError","queryName","Object","keys","queries","sort","first","params"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { parseArgs } from 'node:util';\nimport { COMMANDS } from './commands/index.ts';\nimport type { Ctx } from './commands/types.ts';\nimport { loadConfig, SUPPORTED_CONFIG_VERSION } from './config.ts';\n\n// Parsing and dispatch only. Commands live in src/commands/, one file each, lazy-loaded --\n// nothing tree- or dependency-heavy may be imported at the top of this file.\n\n// Works from dist/cjs and dist/esm alike: walk up past the dist type-marker package.json.\nfunction packageVersion(): string {\n const load = createRequire(import.meta.url);\n for (const rel of ['../package.json', '../../package.json', '../../../package.json']) {\n try {\n const pkg = load(rel) as { name?: string; version?: string };\n if (pkg.name === 'sensemaking' && pkg.version) return pkg.version;\n } catch {}\n }\n return 'unknown';\n}\n\nfunction usage(name: string): string {\n return (\n `usage: ${name} <name> [params...] [--format table|json] [--config path]\\n` +\n ` ${name} query \"<sql>\" [params...]\\n` +\n ` ${name} find \"<terms>\" [--where \"<sql>\"] [--k n] [--semantic]\\n` +\n ` ${name} map\\n` +\n ` ${name} peek <path>\\n` +\n ` ${name} --list\\n` +\n ` ${name} init\\n` +\n ` ${name} watch [--force]\\n` +\n ` ${name} status\\n` +\n ` ${name} rebuild\\n` +\n ` ${name} --version`\n );\n}\n\n// Thrown errors -> exit 1 with the message verbatim; usage errors exit 2 directly.\nexport default async function cli(argv: string[], name: string): Promise<void> {\n let values: Record<string, string | boolean | undefined>;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: {\n format: { type: 'string', default: 'table' },\n config: { type: 'string' },\n where: { type: 'string' },\n k: { type: 'string' },\n semantic: { type: 'boolean', default: false },\n list: { type: 'boolean', default: false },\n force: { type: 'boolean', default: false },\n version: { type: 'boolean', default: false, short: 'v' },\n help: { type: 'boolean', default: false, short: 'h' },\n },\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage(name));\n process.exit(2);\n }\n\n if (values.version) {\n console.log(`v${packageVersion()}`);\n return;\n }\n if (values.help) {\n console.log(usage(name));\n return;\n }\n\n const ctx: Ctx = {\n name,\n rest: positionals.slice(1),\n format: values.format === 'json' ? 'json' : 'table',\n values: values as Ctx['values'],\n resolveConfig() {\n const cfg = loadConfig(values.config as string | undefined);\n if (cfg.migratedFrom !== undefined) {\n console.warn(`${name}: migrated ${cfg.configPath} from config version ${cfg.migratedFrom} to ${SUPPORTED_CONFIG_VERSION}`);\n }\n return cfg;\n },\n usageError(message) {\n console.error(message);\n process.exit(2);\n },\n };\n\n try {\n if (values.list) {\n for (const queryName of Object.keys(ctx.resolveConfig().queries).sort()) console.log(queryName);\n return;\n }\n\n const [first, ...params] = positionals;\n if (!first) {\n console.error(usage(name));\n process.exit(2);\n }\n\n const load = COMMANDS[first];\n if (load) await (await load()).default(ctx);\n else (await import('./commands/named.ts')).default(ctx, first, params);\n } catch (err) {\n console.error((err as Error).message);\n process.exit(1);\n }\n}\n"],"names":["createRequire","parseArgs","COMMANDS","loadConfig","SUPPORTED_CONFIG_VERSION","packageVersion","load","url","rel","pkg","name","version","usage","cli","argv","values","positionals","args","options","format","type","default","config","where","k","semantic","list","force","short","help","allowPositionals","err","console","error","message","process","exit","log","ctx","rest","slice","resolveConfig","cfg","migratedFrom","undefined","warn","configPath","usageError","queryName","Object","keys","queries","sort","first","params"],"mappings":"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"}
@@ -1,14 +1,15 @@
1
1
  import { printRows } from '../output.js';
2
2
  import { find } from '../verbs.js';
3
3
  import { withDb } from './shared.js';
4
- const findCmd = (ctx)=>{
4
+ const findCmd = async (ctx)=>{
5
5
  const [terms] = ctx.rest;
6
- if (!terms) ctx.usageError(`usage: ${ctx.name} find "<terms>" [--where "<sql>"] [--k n]`);
6
+ if (!terms) ctx.usageError(`usage: ${ctx.name} find "<terms>" [--where "<sql>"] [--k n] [--semantic]`);
7
7
  const k = ctx.values.k === undefined ? undefined : Number.parseInt(ctx.values.k, 10);
8
8
  if (ctx.values.k !== undefined && !Number.isInteger(k)) ctx.usageError(`--k expects an integer, got "${ctx.values.k}"`);
9
- withDb(ctx, (db, cfg)=>printRows(find(db, cfg, terms, {
9
+ await withDb(ctx, async (db, cfg)=>printRows(await find(db, cfg, terms, {
10
10
  k,
11
- where: ctx.values.where
11
+ where: ctx.values.where,
12
+ semantic: ctx.values.semantic
12
13
  }), ctx.format));
13
14
  };
14
15
  export default findCmd;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/find.ts"],"sourcesContent":["import { printRows } from '../output.ts';\nimport { find } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst findCmd: Command = (ctx) => {\n const [terms] = ctx.rest;\n if (!terms) ctx.usageError(`usage: ${ctx.name} find \"<terms>\" [--where \"<sql>\"] [--k n]`);\n const k = ctx.values.k === undefined ? undefined : Number.parseInt(ctx.values.k, 10);\n if (ctx.values.k !== undefined && !Number.isInteger(k)) ctx.usageError(`--k expects an integer, got \"${ctx.values.k}\"`);\n withDb(ctx, (db, cfg) => printRows(find(db, cfg, terms, { k, where: ctx.values.where }), ctx.format));\n};\nexport default findCmd;\n"],"names":["printRows","find","withDb","findCmd","ctx","terms","rest","usageError","name","k","values","undefined","Number","parseInt","isInteger","db","cfg","where","format"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAe;AACzC,SAASC,IAAI,QAAQ,cAAc;AACnC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,UAAmB,CAACC;IACxB,MAAM,CAACC,MAAM,GAAGD,IAAIE,IAAI;IACxB,IAAI,CAACD,OAAOD,IAAIG,UAAU,CAAC,CAAC,OAAO,EAAEH,IAAII,IAAI,CAAC,yCAAyC,CAAC;IACxF,MAAMC,IAAIL,IAAIM,MAAM,CAACD,CAAC,KAAKE,YAAYA,YAAYC,OAAOC,QAAQ,CAACT,IAAIM,MAAM,CAACD,CAAC,EAAE;IACjF,IAAIL,IAAIM,MAAM,CAACD,CAAC,KAAKE,aAAa,CAACC,OAAOE,SAAS,CAACL,IAAIL,IAAIG,UAAU,CAAC,CAAC,6BAA6B,EAAEH,IAAIM,MAAM,CAACD,CAAC,CAAC,CAAC,CAAC;IACtHP,OAAOE,KAAK,CAACW,IAAIC,MAAQhB,UAAUC,KAAKc,IAAIC,KAAKX,OAAO;YAAEI;YAAGQ,OAAOb,IAAIM,MAAM,CAACO,KAAK;QAAC,IAAIb,IAAIc,MAAM;AACrG;AACA,eAAef,QAAQ"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/find.ts"],"sourcesContent":["import { printRows } from '../output.ts';\nimport { find } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst findCmd: Command = async (ctx) => {\n const [terms] = ctx.rest;\n if (!terms) ctx.usageError(`usage: ${ctx.name} find \"<terms>\" [--where \"<sql>\"] [--k n] [--semantic]`);\n const k = ctx.values.k === undefined ? undefined : Number.parseInt(ctx.values.k, 10);\n if (ctx.values.k !== undefined && !Number.isInteger(k)) ctx.usageError(`--k expects an integer, got \"${ctx.values.k}\"`);\n await withDb(ctx, async (db, cfg) => printRows(await find(db, cfg, terms, { k, where: ctx.values.where, semantic: ctx.values.semantic }), ctx.format));\n};\nexport default findCmd;\n"],"names":["printRows","find","withDb","findCmd","ctx","terms","rest","usageError","name","k","values","undefined","Number","parseInt","isInteger","db","cfg","where","semantic","format"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAe;AACzC,SAASC,IAAI,QAAQ,cAAc;AACnC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,UAAmB,OAAOC;IAC9B,MAAM,CAACC,MAAM,GAAGD,IAAIE,IAAI;IACxB,IAAI,CAACD,OAAOD,IAAIG,UAAU,CAAC,CAAC,OAAO,EAAEH,IAAII,IAAI,CAAC,sDAAsD,CAAC;IACrG,MAAMC,IAAIL,IAAIM,MAAM,CAACD,CAAC,KAAKE,YAAYA,YAAYC,OAAOC,QAAQ,CAACT,IAAIM,MAAM,CAACD,CAAC,EAAE;IACjF,IAAIL,IAAIM,MAAM,CAACD,CAAC,KAAKE,aAAa,CAACC,OAAOE,SAAS,CAACL,IAAIL,IAAIG,UAAU,CAAC,CAAC,6BAA6B,EAAEH,IAAIM,MAAM,CAACD,CAAC,CAAC,CAAC,CAAC;IACtH,MAAMP,OAAOE,KAAK,OAAOW,IAAIC,MAAQhB,UAAU,MAAMC,KAAKc,IAAIC,KAAKX,OAAO;YAAEI;YAAGQ,OAAOb,IAAIM,MAAM,CAACO,KAAK;YAAEC,UAAUd,IAAIM,MAAM,CAACQ,QAAQ;QAAC,IAAId,IAAIe,MAAM;AACtJ;AACA,eAAehB,QAAQ"}
@@ -1,10 +1,8 @@
1
1
  import { renderMap } from '../output.js';
2
2
  import { mapTree } from '../verbs.js';
3
3
  import { withDb } from './shared.js';
4
- const map = (ctx)=>{
5
- withDb(ctx, (db, cfg)=>{
4
+ const map = (ctx)=>withDb(ctx, (db, cfg)=>{
6
5
  const result = mapTree(db, cfg);
7
6
  console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderMap(result));
8
7
  });
9
- };
10
8
  export default map;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/map.ts"],"sourcesContent":["import { renderMap } from '../output.ts';\nimport { mapTree } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst map: Command = (ctx) => {\n withDb(ctx, (db, cfg) => {\n const result = mapTree(db, cfg);\n console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderMap(result));\n });\n};\nexport default map;\n"],"names":["renderMap","mapTree","withDb","map","ctx","db","cfg","result","console","log","format","JSON","stringify"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAe;AACzC,SAASC,OAAO,QAAQ,cAAc;AACtC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,MAAe,CAACC;IACpBF,OAAOE,KAAK,CAACC,IAAIC;QACf,MAAMC,SAASN,QAAQI,IAAIC;QAC3BE,QAAQC,GAAG,CAACL,IAAIM,MAAM,KAAK,SAASC,KAAKC,SAAS,CAACL,QAAQ,MAAM,KAAKP,UAAUO;IAClF;AACF;AACA,eAAeJ,IAAI"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/map.ts"],"sourcesContent":["import { renderMap } from '../output.ts';\nimport { mapTree } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst map: Command = (ctx) =>\n withDb(ctx, (db, cfg) => {\n const result = mapTree(db, cfg);\n console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderMap(result));\n });\nexport default map;\n"],"names":["renderMap","mapTree","withDb","map","ctx","db","cfg","result","console","log","format","JSON","stringify"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAe;AACzC,SAASC,OAAO,QAAQ,cAAc;AACtC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,MAAe,CAACC,MACpBF,OAAOE,KAAK,CAACC,IAAIC;QACf,MAAMC,SAASN,QAAQI,IAAIC;QAC3BE,QAAQC,GAAG,CAACL,IAAIM,MAAM,KAAK,SAASC,KAAKC,SAAS,CAACL,QAAQ,MAAM,KAAKP,UAAUO;IAClF;AACF,eAAeJ,IAAI"}
@@ -4,7 +4,7 @@ import { withDb } from './shared.js';
4
4
  const peekCmd = (ctx)=>{
5
5
  const [pathArg] = ctx.rest;
6
6
  if (!pathArg) ctx.usageError(`usage: ${ctx.name} peek <path>`);
7
- withDb(ctx, (db, cfg)=>{
7
+ return withDb(ctx, (db, cfg)=>{
8
8
  const result = peek(db, cfg, pathArg);
9
9
  console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderPeek(result));
10
10
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/peek.ts"],"sourcesContent":["import { renderPeek } from '../output.ts';\nimport { peek } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst peekCmd: Command = (ctx) => {\n const [pathArg] = ctx.rest;\n if (!pathArg) ctx.usageError(`usage: ${ctx.name} peek <path>`);\n withDb(ctx, (db, cfg) => {\n const result = peek(db, cfg, pathArg);\n console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderPeek(result));\n });\n};\nexport default peekCmd;\n"],"names":["renderPeek","peek","withDb","peekCmd","ctx","pathArg","rest","usageError","name","db","cfg","result","console","log","format","JSON","stringify"],"mappings":"AAAA,SAASA,UAAU,QAAQ,eAAe;AAC1C,SAASC,IAAI,QAAQ,cAAc;AACnC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,UAAmB,CAACC;IACxB,MAAM,CAACC,QAAQ,GAAGD,IAAIE,IAAI;IAC1B,IAAI,CAACD,SAASD,IAAIG,UAAU,CAAC,CAAC,OAAO,EAAEH,IAAII,IAAI,CAAC,YAAY,CAAC;IAC7DN,OAAOE,KAAK,CAACK,IAAIC;QACf,MAAMC,SAASV,KAAKQ,IAAIC,KAAKL;QAC7BO,QAAQC,GAAG,CAACT,IAAIU,MAAM,KAAK,SAASC,KAAKC,SAAS,CAACL,QAAQ,MAAM,KAAKX,WAAWW;IACnF;AACF;AACA,eAAeR,QAAQ"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/peek.ts"],"sourcesContent":["import { renderPeek } from '../output.ts';\nimport { peek } from '../verbs.ts';\nimport { withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst peekCmd: Command = (ctx) => {\n const [pathArg] = ctx.rest;\n if (!pathArg) ctx.usageError(`usage: ${ctx.name} peek <path>`);\n return withDb(ctx, (db, cfg) => {\n const result = peek(db, cfg, pathArg);\n console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderPeek(result));\n });\n};\nexport default peekCmd;\n"],"names":["renderPeek","peek","withDb","peekCmd","ctx","pathArg","rest","usageError","name","db","cfg","result","console","log","format","JSON","stringify"],"mappings":"AAAA,SAASA,UAAU,QAAQ,eAAe;AAC1C,SAASC,IAAI,QAAQ,cAAc;AACnC,SAASC,MAAM,QAAQ,cAAc;AAGrC,MAAMC,UAAmB,CAACC;IACxB,MAAM,CAACC,QAAQ,GAAGD,IAAIE,IAAI;IAC1B,IAAI,CAACD,SAASD,IAAIG,UAAU,CAAC,CAAC,OAAO,EAAEH,IAAII,IAAI,CAAC,YAAY,CAAC;IAC7D,OAAON,OAAOE,KAAK,CAACK,IAAIC;QACtB,MAAMC,SAASV,KAAKQ,IAAIC,KAAKL;QAC7BO,QAAQC,GAAG,CAACT,IAAIU,MAAM,KAAK,SAASC,KAAKC,SAAS,CAACL,QAAQ,MAAM,KAAKX,WAAWW;IACnF;AACF;AACA,eAAeR,QAAQ"}
@@ -2,5 +2,5 @@ import type { ResolvedConfig } from '../config.js';
2
2
  import type { OpenResult } from '../db.js';
3
3
  import type { Ctx } from './types.js';
4
4
  export declare function printWarnings(warnings: string[]): void;
5
- export declare function withDb(ctx: Ctx, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void): void;
5
+ export declare function withDb(ctx: Ctx, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void>;
6
6
  export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void;
@@ -4,12 +4,12 @@ import { printRows } from '../output.js';
4
4
  export function printWarnings(warnings) {
5
5
  for (const w of warnings)console.warn(w);
6
6
  }
7
- export function withDb(ctx, fn) {
7
+ export async function withDb(ctx, fn) {
8
8
  const cfg = ctx.resolveConfig();
9
9
  const { db, warnings } = open(cfg);
10
10
  printWarnings(warnings);
11
11
  try {
12
- fn(db, cfg);
12
+ await fn(db, cfg);
13
13
  } finally{
14
14
  db.close();
15
15
  }