sensemaking 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.js +3 -0
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/check.d.cts +3 -0
- package/dist/cjs/commands/check.d.ts +3 -0
- package/dist/cjs/commands/check.js +130 -0
- package/dist/cjs/commands/check.js.map +1 -0
- package/dist/cjs/commands/index.js +5 -0
- package/dist/cjs/commands/index.js.map +1 -1
- package/dist/cjs/commands/status.js +67 -9
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config.d.cts +6 -0
- package/dist/cjs/config.d.ts +6 -0
- package/dist/cjs/config.js +61 -1
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/db.d.cts +1 -1
- package/dist/cjs/db.d.ts +1 -1
- package/dist/cjs/db.js +1 -1
- package/dist/cjs/db.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.d.cts +1 -0
- package/dist/cjs/features/embed.d.ts +1 -0
- package/dist/cjs/features/embed.js +6 -2
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/output.js +34 -8
- package/dist/cjs/output.js.map +1 -1
- package/dist/cjs/scan.d.cts +1 -1
- package/dist/cjs/scan.d.ts +1 -1
- package/dist/cjs/scan.js +8 -2
- package/dist/cjs/scan.js.map +1 -1
- package/dist/cjs/verbs.js +56 -12
- package/dist/cjs/verbs.js.map +1 -1
- package/dist/esm/cli.js +3 -0
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/check.d.ts +3 -0
- package/dist/esm/commands/check.js +56 -0
- package/dist/esm/commands/check.js.map +1 -0
- package/dist/esm/commands/index.js +1 -0
- package/dist/esm/commands/index.js.map +1 -1
- package/dist/esm/commands/status.js +38 -7
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config.d.ts +6 -0
- package/dist/esm/config.js +35 -1
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/db.d.ts +1 -1
- package/dist/esm/db.js +1 -1
- package/dist/esm/db.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.d.ts +1 -0
- package/dist/esm/features/embed.js +11 -2
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/output.js +29 -7
- package/dist/esm/output.js.map +1 -1
- package/dist/esm/scan.d.ts +1 -1
- package/dist/esm/scan.js +8 -2
- package/dist/esm/scan.js.map +1 -1
- package/dist/esm/verbs.js +52 -12
- package/dist/esm/verbs.js.map +1 -1
- package/package.json +1 -1
- package/schema.json +19 -1
- package/skills/sense/SKILL.md +23 -2
- package/skills/sense-setup/SKILL.md +22 -4
package/dist/cjs/verbs.js
CHANGED
|
@@ -220,9 +220,39 @@ function _ts_generator(thisArg, body) {
|
|
|
220
220
|
// Each returns data; cli.ts renders. All of them degrade when a feature is off.
|
|
221
221
|
var WEIGHTED_BM25 = 'bm25(content, 10.0, 5.0, 1.0)';
|
|
222
222
|
var RRF_K = 60;
|
|
223
|
+
// FTS5 reads these as operators, so a bare term containing one is a syntax error or --
|
|
224
|
+
// worse -- a column filter: `end-to-end` parses as a filter on column `to`, and SQLite
|
|
225
|
+
// reports `no such column: to`, which is a true statement about the parse and a false
|
|
226
|
+
// one about the input. Both field reports on 0.6.0 misdiagnosed that message.
|
|
227
|
+
var FTS5_OPERATORS = /[-'"/.:^*()]/;
|
|
228
|
+
function searchError(err, terms, scope) {
|
|
229
|
+
var _terms_match;
|
|
230
|
+
var _exec;
|
|
231
|
+
var message = err.message;
|
|
232
|
+
if (!/no such column|fts5: syntax error|malformed MATCH/.test(message)) return err;
|
|
233
|
+
var suspects = ((_terms_match = terms.match(/\S+/g)) !== null && _terms_match !== void 0 ? _terms_match : []).filter(function(t) {
|
|
234
|
+
return !t.startsWith('"') && FTS5_OPERATORS.test(t);
|
|
235
|
+
});
|
|
236
|
+
// Blame the terms only when the failing token actually came from one -- a typo'd column
|
|
237
|
+
// in --where (or the tree's default scope) raises "no such column" through this same
|
|
238
|
+
// statement, and naming a term for it would state a false fact about the input.
|
|
239
|
+
var col = (_exec = /no such column: (\S+)/.exec(message)) === null || _exec === void 0 ? void 0 : _exec[1];
|
|
240
|
+
var fromTerms = col === undefined ? suspects.length > 0 : suspects.some(function(t) {
|
|
241
|
+
return t.split(RegExp("[^\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376-\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E-\\u066F\\u0671-\\u06D3\\u06D5\\u06E5-\\u06E6\\u06EE-\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4-\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F-\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC-\\u09DD\\u09DF-\\u09E1\\u09F0-\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F-\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32-\\u0A33\\u0A35-\\u0A36\\u0A38-\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2-\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0-\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F-\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32-\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C-\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99-\\u0B9A\\u0B9C\\u0B9E-\\u0B9F\\u0BA3-\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C-\\u0C5D\\u0C60-\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0-\\u0CE1\\u0CF1-\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32-\\u0E33\\u0E40-\\u0E46\\u0E81-\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2-\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065-\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE-\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5-\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183-\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2-\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3006\\u3031-\\u3035\\u303B-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A-\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7DC\\uA7F1-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD-\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5-\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40-\\uFB41\\uFB43-\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10000}-\\u{1000B}\\u{1000D}-\\u{10026}\\u{10028}-\\u{1003A}\\u{1003C}-\\u{1003D}\\u{1003F}-\\u{1004D}\\u{10050}-\\u{1005D}\\u{10080}-\\u{100FA}\\u{10280}-\\u{1029C}\\u{102A0}-\\u{102D0}\\u{10300}-\\u{1031F}\\u{1032D}-\\u{10340}\\u{10342}-\\u{10349}\\u{10350}-\\u{10375}\\u{10380}-\\u{1039D}\\u{103A0}-\\u{103C3}\\u{103C8}-\\u{103CF}\\u{10400}-\\u{1049D}\\u{104B0}-\\u{104D3}\\u{104D8}-\\u{104FB}\\u{10500}-\\u{10527}\\u{10530}-\\u{10563}\\u{10570}-\\u{1057A}\\u{1057C}-\\u{1058A}\\u{1058C}-\\u{10592}\\u{10594}-\\u{10595}\\u{10597}-\\u{105A1}\\u{105A3}-\\u{105B1}\\u{105B3}-\\u{105B9}\\u{105BB}-\\u{105BC}\\u{105C0}-\\u{105F3}\\u{10600}-\\u{10736}\\u{10740}-\\u{10755}\\u{10760}-\\u{10767}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10800}-\\u{10805}\\u{10808}\\u{1080A}-\\u{10835}\\u{10837}-\\u{10838}\\u{1083C}\\u{1083F}-\\u{10855}\\u{10860}-\\u{10876}\\u{10880}-\\u{1089E}\\u{108E0}-\\u{108F2}\\u{108F4}-\\u{108F5}\\u{10900}-\\u{10915}\\u{10920}-\\u{10939}\\u{10940}-\\u{10959}\\u{10980}-\\u{109B7}\\u{109BE}-\\u{109BF}\\u{10A00}\\u{10A10}-\\u{10A13}\\u{10A15}-\\u{10A17}\\u{10A19}-\\u{10A35}\\u{10A60}-\\u{10A7C}\\u{10A80}-\\u{10A9C}\\u{10AC0}-\\u{10AC7}\\u{10AC9}-\\u{10AE4}\\u{10B00}-\\u{10B35}\\u{10B40}-\\u{10B55}\\u{10B60}-\\u{10B72}\\u{10B80}-\\u{10B91}\\u{10C00}-\\u{10C48}\\u{10C80}-\\u{10CB2}\\u{10CC0}-\\u{10CF2}\\u{10D00}-\\u{10D23}\\u{10D4A}-\\u{10D65}\\u{10D6F}-\\u{10D85}\\u{10E80}-\\u{10EA9}\\u{10EB0}-\\u{10EB1}\\u{10EC2}-\\u{10EC7}\\u{10F00}-\\u{10F1C}\\u{10F27}\\u{10F30}-\\u{10F45}\\u{10F70}-\\u{10F81}\\u{10FB0}-\\u{10FC4}\\u{10FE0}-\\u{10FF6}\\u{11003}-\\u{11037}\\u{11071}-\\u{11072}\\u{11075}\\u{11083}-\\u{110AF}\\u{110D0}-\\u{110E8}\\u{11103}-\\u{11126}\\u{11144}\\u{11147}\\u{11150}-\\u{11172}\\u{11176}\\u{11183}-\\u{111B2}\\u{111C1}-\\u{111C4}\\u{111DA}\\u{111DC}\\u{11200}-\\u{11211}\\u{11213}-\\u{1122B}\\u{1123F}-\\u{11240}\\u{11280}-\\u{11286}\\u{11288}\\u{1128A}-\\u{1128D}\\u{1128F}-\\u{1129D}\\u{1129F}-\\u{112A8}\\u{112B0}-\\u{112DE}\\u{11305}-\\u{1130C}\\u{1130F}-\\u{11310}\\u{11313}-\\u{11328}\\u{1132A}-\\u{11330}\\u{11332}-\\u{11333}\\u{11335}-\\u{11339}\\u{1133D}\\u{11350}\\u{1135D}-\\u{11361}\\u{11380}-\\u{11389}\\u{1138B}\\u{1138E}\\u{11390}-\\u{113B5}\\u{113B7}\\u{113D1}\\u{113D3}\\u{11400}-\\u{11434}\\u{11447}-\\u{1144A}\\u{1145F}-\\u{11461}\\u{11480}-\\u{114AF}\\u{114C4}-\\u{114C5}\\u{114C7}\\u{11580}-\\u{115AE}\\u{115D8}-\\u{115DB}\\u{11600}-\\u{1162F}\\u{11644}\\u{11680}-\\u{116AA}\\u{116B8}\\u{11700}-\\u{1171A}\\u{11740}-\\u{11746}\\u{11800}-\\u{1182B}\\u{118A0}-\\u{118DF}\\u{118FF}-\\u{11906}\\u{11909}\\u{1190C}-\\u{11913}\\u{11915}-\\u{11916}\\u{11918}-\\u{1192F}\\u{1193F}\\u{11941}\\u{119A0}-\\u{119A7}\\u{119AA}-\\u{119D0}\\u{119E1}\\u{119E3}\\u{11A00}\\u{11A0B}-\\u{11A32}\\u{11A3A}\\u{11A50}\\u{11A5C}-\\u{11A89}\\u{11A9D}\\u{11AB0}-\\u{11AF8}\\u{11BC0}-\\u{11BE0}\\u{11C00}-\\u{11C08}\\u{11C0A}-\\u{11C2E}\\u{11C40}\\u{11C72}-\\u{11C8F}\\u{11D00}-\\u{11D06}\\u{11D08}-\\u{11D09}\\u{11D0B}-\\u{11D30}\\u{11D46}\\u{11D60}-\\u{11D65}\\u{11D67}-\\u{11D68}\\u{11D6A}-\\u{11D89}\\u{11D98}\\u{11DB0}-\\u{11DDB}\\u{11EE0}-\\u{11EF2}\\u{11F02}\\u{11F04}-\\u{11F10}\\u{11F12}-\\u{11F33}\\u{11FB0}\\u{12000}-\\u{12399}\\u{12480}-\\u{12543}\\u{12F90}-\\u{12FF0}\\u{13000}-\\u{1342F}\\u{13441}-\\u{13446}\\u{13460}-\\u{143FA}\\u{14400}-\\u{14646}\\u{16100}-\\u{1611D}\\u{16800}-\\u{16A38}\\u{16A40}-\\u{16A5E}\\u{16A70}-\\u{16ABE}\\u{16AD0}-\\u{16AED}\\u{16B00}-\\u{16B2F}\\u{16B40}-\\u{16B43}\\u{16B63}-\\u{16B77}\\u{16B7D}-\\u{16B8F}\\u{16D40}-\\u{16D6C}\\u{16E40}-\\u{16E7F}\\u{16EA0}-\\u{16EB8}\\u{16EBB}-\\u{16ED3}\\u{16F00}-\\u{16F4A}\\u{16F50}\\u{16F93}-\\u{16F9F}\\u{16FE0}-\\u{16FE1}\\u{16FE3}\\u{16FF2}-\\u{16FF3}\\u{17000}-\\u{18CD5}\\u{18CFF}-\\u{18D1E}\\u{18D80}-\\u{18DF2}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}-\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1B170}-\\u{1B2FB}\\u{1BC00}-\\u{1BC6A}\\u{1BC70}-\\u{1BC7C}\\u{1BC80}-\\u{1BC88}\\u{1BC90}-\\u{1BC99}\\u{1D400}-\\u{1D454}\\u{1D456}-\\u{1D49C}\\u{1D49E}-\\u{1D49F}\\u{1D4A2}\\u{1D4A5}-\\u{1D4A6}\\u{1D4A9}-\\u{1D4AC}\\u{1D4AE}-\\u{1D4B9}\\u{1D4BB}\\u{1D4BD}-\\u{1D4C3}\\u{1D4C5}-\\u{1D505}\\u{1D507}-\\u{1D50A}\\u{1D50D}-\\u{1D514}\\u{1D516}-\\u{1D51C}\\u{1D51E}-\\u{1D539}\\u{1D53B}-\\u{1D53E}\\u{1D540}-\\u{1D544}\\u{1D546}\\u{1D54A}-\\u{1D550}\\u{1D552}-\\u{1D6A5}\\u{1D6A8}-\\u{1D6C0}\\u{1D6C2}-\\u{1D6DA}\\u{1D6DC}-\\u{1D6FA}\\u{1D6FC}-\\u{1D714}\\u{1D716}-\\u{1D734}\\u{1D736}-\\u{1D74E}\\u{1D750}-\\u{1D76E}\\u{1D770}-\\u{1D788}\\u{1D78A}-\\u{1D7A8}\\u{1D7AA}-\\u{1D7C2}\\u{1D7C4}-\\u{1D7CB}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E100}-\\u{1E12C}\\u{1E137}-\\u{1E13D}\\u{1E14E}\\u{1E290}-\\u{1E2AD}\\u{1E2C0}-\\u{1E2EB}\\u{1E4D0}-\\u{1E4EB}\\u{1E5D0}-\\u{1E5ED}\\u{1E5F0}\\u{1E6C0}-\\u{1E6DE}\\u{1E6E0}-\\u{1E6E2}\\u{1E6E4}-\\u{1E6E5}\\u{1E6E7}-\\u{1E6ED}\\u{1E6F0}-\\u{1E6F4}\\u{1E6FE}-\\u{1E6FF}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}-\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1E800}-\\u{1E8C4}\\u{1E900}-\\u{1E943}\\u{1E94B}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}-\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}-\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}-\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}\\u0030-\\u0039\\u00B2-\\u00B3\\u00B9\\u00BC-\\u00BE\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u09F4-\\u09F9\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0B72-\\u0B77\\u0BE6-\\u0BF2\\u0C66-\\u0C6F\\u0C78-\\u0C7E\\u0CE6-\\u0CEF\\u0D58-\\u0D5E\\u0D66-\\u0D78\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F33\\u1040-\\u1049\\u1090-\\u1099\\u1369-\\u137C\\u16EE-\\u16F0\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19DA\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\u2070\\u2074-\\u2079\\u2080-\\u2089\\u2150-\\u2182\\u2185-\\u2189\\u2460-\\u249B\\u24EA-\\u24FF\\u2776-\\u2793\\u2CFD\\u3007\\u3021-\\u3029\\u3038-\\u303A\\u3192-\\u3195\\u3220-\\u3229\\u3248-\\u324F\\u3251-\\u325F\\u3280-\\u3289\\u32B1-\\u32BF\\uA620-\\uA629\\uA6E6-\\uA6EF\\uA830-\\uA835\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19\\u{10107}-\\u{10133}\\u{10140}-\\u{10178}\\u{1018A}-\\u{1018B}\\u{102E1}-\\u{102FB}\\u{10320}-\\u{10323}\\u{10341}\\u{1034A}\\u{103D1}-\\u{103D5}\\u{104A0}-\\u{104A9}\\u{10858}-\\u{1085F}\\u{10879}-\\u{1087F}\\u{108A7}-\\u{108AF}\\u{108FB}-\\u{108FF}\\u{10916}-\\u{1091B}\\u{109BC}-\\u{109BD}\\u{109C0}-\\u{109CF}\\u{109D2}-\\u{109FF}\\u{10A40}-\\u{10A48}\\u{10A7D}-\\u{10A7E}\\u{10A9D}-\\u{10A9F}\\u{10AEB}-\\u{10AEF}\\u{10B58}-\\u{10B5F}\\u{10B78}-\\u{10B7F}\\u{10BA9}-\\u{10BAF}\\u{10CFA}-\\u{10CFF}\\u{10D30}-\\u{10D39}\\u{10D40}-\\u{10D49}\\u{10E60}-\\u{10E7E}\\u{10F1D}-\\u{10F26}\\u{10F51}-\\u{10F54}\\u{10FC5}-\\u{10FCB}\\u{11052}-\\u{1106F}\\u{110F0}-\\u{110F9}\\u{11136}-\\u{1113F}\\u{111D0}-\\u{111D9}\\u{111E1}-\\u{111F4}\\u{112F0}-\\u{112F9}\\u{11450}-\\u{11459}\\u{114D0}-\\u{114D9}\\u{11650}-\\u{11659}\\u{116C0}-\\u{116C9}\\u{116D0}-\\u{116E3}\\u{11730}-\\u{1173B}\\u{118E0}-\\u{118F2}\\u{11950}-\\u{11959}\\u{11BF0}-\\u{11BF9}\\u{11C50}-\\u{11C6C}\\u{11D50}-\\u{11D59}\\u{11DA0}-\\u{11DA9}\\u{11DE0}-\\u{11DE9}\\u{11F50}-\\u{11F59}\\u{11FC0}-\\u{11FD4}\\u{12400}-\\u{1246E}\\u{16130}-\\u{16139}\\u{16A60}-\\u{16A69}\\u{16AC0}-\\u{16AC9}\\u{16B50}-\\u{16B59}\\u{16B5B}-\\u{16B61}\\u{16D70}-\\u{16D79}\\u{16E80}-\\u{16E96}\\u{16FF4}-\\u{16FF6}\\u{1CCF0}-\\u{1CCF9}\\u{1D2C0}-\\u{1D2D3}\\u{1D2E0}-\\u{1D2F3}\\u{1D360}-\\u{1D378}\\u{1D7CE}-\\u{1D7FF}\\u{1E140}-\\u{1E149}\\u{1E2F0}-\\u{1E2F9}\\u{1E4F0}-\\u{1E4F9}\\u{1E5F1}-\\u{1E5FA}\\u{1E8C7}-\\u{1E8CF}\\u{1E950}-\\u{1E959}\\u{1EC71}-\\u{1ECAB}\\u{1ECAD}-\\u{1ECAF}\\u{1ECB1}-\\u{1ECB4}\\u{1ED01}-\\u{1ED2D}\\u{1ED2F}-\\u{1ED3D}\\u{1F100}-\\u{1F10C}\\u{1FBF0}-\\u{1FBF9}]+", "u")).includes(col);
|
|
242
|
+
});
|
|
243
|
+
if (fromTerms && suspects.length > 0) {
|
|
244
|
+
return new _errorsts.SenseError('SEARCH_SYNTAX', "".concat(message, " -- the punctuation in ").concat(suspects.map(function(t) {
|
|
245
|
+
return "`".concat(t, "`");
|
|
246
|
+
}).join(', '), " is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"").concat(suspects[0], "\"'. Searchable columns are title, summary, text."));
|
|
247
|
+
}
|
|
248
|
+
if (col !== undefined && scope !== undefined) {
|
|
249
|
+
return new _errorsts.SenseError('SEARCH_SYNTAX', "".concat(message, " -- the where condition (").concat(scope, ") references it; frontmatter columns are listed by sense query \"SELECT name FROM pragma_table_info('frontmatter')\"."));
|
|
250
|
+
}
|
|
251
|
+
return new _errorsts.SenseError('SEARCH_SYNTAX', "".concat(message, " -- searchable columns are title, summary, text; frontmatter fields are queried with --where or sense query (list them with pragma_table_info('frontmatter'))."));
|
|
252
|
+
}
|
|
223
253
|
function find(_0, _1, _2) {
|
|
224
254
|
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;
|
|
255
|
+
var opts, _opts_k, _opts_where, _hits_get, _chunkLines_get, _chunkSimilarity_get, _cfg_defaults_find, _cfg_defaults, k, fetch, scope, whereJoin, whereCond, matchSql, matchRows, hits, candidates, edges, linked, nodes, seeds, ranked, chunkLines, chunkSimilarity, vec, insert, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step_value, path, c, where, linesCol;
|
|
226
256
|
var _arguments = arguments;
|
|
227
257
|
return _ts_generator(this, function(_state) {
|
|
228
258
|
switch(_state.label){
|
|
@@ -234,10 +264,17 @@ function find(_0, _1, _2) {
|
|
|
234
264
|
// Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.
|
|
235
265
|
// --where applies inside the candidate query (a post-filter over the top-N would drop
|
|
236
266
|
// matches ranked past the pool) and again on the final select for link-derived rows.
|
|
237
|
-
|
|
238
|
-
|
|
267
|
+
// An explicit --where replaces the tree's declared default rather than ANDing with it,
|
|
268
|
+
// so a caller can always widen back to the whole tree.
|
|
269
|
+
scope = (_opts_where = opts.where) !== null && _opts_where !== void 0 ? _opts_where : (_cfg_defaults = cfg.defaults) === null || _cfg_defaults === void 0 ? void 0 : (_cfg_defaults_find = _cfg_defaults.find) === null || _cfg_defaults_find === void 0 ? void 0 : _cfg_defaults_find.where;
|
|
270
|
+
whereJoin = scope ? 'JOIN frontmatter f ON f."path" = content.path' : '';
|
|
271
|
+
whereCond = scope ? "AND (".concat(scope, ")") : '';
|
|
239
272
|
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
|
-
|
|
273
|
+
try {
|
|
274
|
+
matchRows = db.prepare(matchSql).all(terms);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
throw searchError(err, terms, scope);
|
|
277
|
+
}
|
|
241
278
|
hits = new Map(matchRows.map(function(r) {
|
|
242
279
|
return [
|
|
243
280
|
r.path,
|
|
@@ -290,6 +327,7 @@ function find(_0, _1, _2) {
|
|
|
290
327
|
// Vector expansion, invoked only: a third RRF list at the swept flat-region constants
|
|
291
328
|
// (weight 1, pool = fetch). Each row carries its best chunk's line range.
|
|
292
329
|
chunkLines = new Map();
|
|
330
|
+
chunkSimilarity = new Map();
|
|
293
331
|
if (!opts.semantic) return [
|
|
294
332
|
3,
|
|
295
333
|
2
|
|
@@ -301,8 +339,9 @@ function find(_0, _1, _2) {
|
|
|
301
339
|
case 1:
|
|
302
340
|
vec = _state.sent();
|
|
303
341
|
vec.forEach(function(param, i) {
|
|
304
|
-
var path = param.path, lines = param.lines;
|
|
342
|
+
var path = param.path, lines = param.lines, similarity = param.similarity;
|
|
305
343
|
chunkLines.set(path, lines);
|
|
344
|
+
chunkSimilarity.set(path, similarity);
|
|
306
345
|
var existing = candidates.get(path);
|
|
307
346
|
if (existing) {
|
|
308
347
|
existing.score += 1 / (RRF_K + i);
|
|
@@ -317,13 +356,13 @@ function find(_0, _1, _2) {
|
|
|
317
356
|
_state.label = 2;
|
|
318
357
|
case 2:
|
|
319
358
|
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 (?, ?, ?, ?, ?)');
|
|
359
|
+
db.exec('CREATE TEMP TABLE _find ("path" TEXT PRIMARY KEY, score REAL, via TEXT, hit TEXT, lines TEXT, similarity REAL)');
|
|
360
|
+
insert = db.prepare('INSERT INTO _find ("path", score, via, hit, lines, similarity) VALUES (?, ?, ?, ?, ?, ?)');
|
|
322
361
|
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
323
362
|
try {
|
|
324
363
|
for(_iterator = candidates[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
325
364
|
_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);
|
|
365
|
+
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, (_chunkSimilarity_get = chunkSimilarity.get(path)) !== null && _chunkSimilarity_get !== void 0 ? _chunkSimilarity_get : null);
|
|
327
366
|
}
|
|
328
367
|
} catch (err) {
|
|
329
368
|
_didIteratorError = true;
|
|
@@ -339,8 +378,8 @@ function find(_0, _1, _2) {
|
|
|
339
378
|
}
|
|
340
379
|
}
|
|
341
380
|
}
|
|
342
|
-
where =
|
|
343
|
-
linesCol = opts.semantic ? ', _find.lines' : '';
|
|
381
|
+
where = scope ? "WHERE ".concat(scope) : '';
|
|
382
|
+
linesCol = opts.semantic ? ', _find.lines, _find.similarity' : '';
|
|
344
383
|
return [
|
|
345
384
|
2,
|
|
346
385
|
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)
|
|
@@ -363,10 +402,15 @@ function mapTree(db, cfg) {
|
|
|
363
402
|
return !INTERNAL_COLUMNS.has(name);
|
|
364
403
|
});
|
|
365
404
|
var allFields = columns.map(function(name) {
|
|
366
|
-
var
|
|
405
|
+
var quoted = '"'.concat(name.split('"').join('""'), '"');
|
|
406
|
+
// Observed storage class, not a declared one: these columns are added dynamically and
|
|
407
|
+
// SQLite types per value, so a field can be text in most notes and numeric in a few.
|
|
408
|
+
// Listing every distinct type makes both the type and any drift visible.
|
|
409
|
+
var _db_prepare_get = db.prepare("SELECT COUNT(".concat(quoted, ") AS n, GROUP_CONCAT(DISTINCT typeof(").concat(quoted, ")) AS types FROM frontmatter WHERE ").concat(quoted, " IS NOT NULL")).get(), n = _db_prepare_get.n, types = _db_prepare_get.types;
|
|
367
410
|
return {
|
|
368
411
|
field: name,
|
|
369
|
-
coverage: n
|
|
412
|
+
coverage: n,
|
|
413
|
+
type: types !== null && types !== void 0 ? types : ''
|
|
370
414
|
};
|
|
371
415
|
}).sort(function(a, b) {
|
|
372
416
|
return b.coverage - a.coverage;
|
package/dist/cjs/verbs.js.map
CHANGED
|
@@ -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, 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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"}
|
|
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\n// FTS5 reads these as operators, so a bare term containing one is a syntax error or --\n// worse -- a column filter: `end-to-end` parses as a filter on column `to`, and SQLite\n// reports `no such column: to`, which is a true statement about the parse and a false\n// one about the input. Both field reports on 0.6.0 misdiagnosed that message.\nconst FTS5_OPERATORS = /[-'\"/.:^*()]/;\n\nfunction searchError(err: Error, terms: string, scope?: string): Error {\n const message = err.message;\n if (!/no such column|fts5: syntax error|malformed MATCH/.test(message)) return err;\n const suspects = (terms.match(/\\S+/g) ?? []).filter((t) => !t.startsWith('\"') && FTS5_OPERATORS.test(t));\n // Blame the terms only when the failing token actually came from one -- a typo'd column\n // in --where (or the tree's default scope) raises \"no such column\" through this same\n // statement, and naming a term for it would state a false fact about the input.\n const col = /no such column: (\\S+)/.exec(message)?.[1];\n const fromTerms = col === undefined ? suspects.length > 0 : suspects.some((t) => t.split(/[^\\p{L}\\p{N}]+/u).includes(col));\n if (fromTerms && suspects.length > 0) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the punctuation in ${suspects.map((t) => `\\`${t}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n }\n if (col !== undefined && scope !== undefined) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the where condition (${scope}) references it; frontmatter columns are listed by sense query \"SELECT name FROM pragma_table_info('frontmatter')\".`);\n }\n return new SenseError('SEARCH_SYNTAX', `${message} -- searchable columns are title, summary, text; frontmatter fields are queried with --where or sense query (list them with pragma_table_info('frontmatter')).`);\n}\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 // An explicit --where replaces the tree's declared default rather than ANDing with it,\n // so a caller can always widen back to the whole tree.\n const scope = opts.where ?? cfg.defaults?.find?.where;\n const whereJoin = scope ? `JOIN frontmatter f ON f.\"path\" = content.path` : '';\n const whereCond = scope ? `AND (${scope})` : '';\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 let matchRows: Array<{ path: string; hit: string }>;\n try {\n matchRows = db.prepare(matchSql).all(terms) as Array<{ path: string; hit: string }>;\n } catch (err) {\n throw searchError(err as Error, terms, scope);\n }\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 const chunkSimilarity = new Map<string, number>();\n if (opts.semantic) {\n const vec = await semanticCandidates(db, cfg, terms, fetch);\n vec.forEach(({ path, lines, similarity }, i) => {\n chunkLines.set(path, lines);\n chunkSimilarity.set(path, similarity);\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, similarity REAL)');\n const insert = db.prepare('INSERT INTO _find (\"path\", score, via, hit, lines, similarity) VALUES (?, ?, ?, ?, ?, ?)');\n for (const [path, c] of candidates) insert.run(path, c.score, c.via, hits.get(path) ?? null, chunkLines.get(path) ?? null, chunkSimilarity.get(path) ?? null);\n\n const where = scope ? `WHERE ${scope}` : '';\n const linesCol = opts.semantic ? ', _find.lines, _find.similarity' : '';\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 quoted = `\"${name.split('\"').join('\"\"')}\"`;\n // Observed storage class, not a declared one: these columns are added dynamically and\n // SQLite types per value, so a field can be text in most notes and numeric in a few.\n // Listing every distinct type makes both the type and any drift visible.\n const { n, types } = db.prepare(`SELECT COUNT(${quoted}) AS n, GROUP_CONCAT(DISTINCT typeof(${quoted})) AS types FROM frontmatter WHERE ${quoted} IS NOT NULL`).get() as { n: number; types: string | null };\n return { field: name, coverage: n, type: types ?? '' };\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","FTS5_OPERATORS","searchError","err","terms","scope","message","test","suspects","match","filter","t","startsWith","col","exec","fromTerms","undefined","length","some","split","includes","SenseError","map","join","db","cfg","opts","hits","chunkLines","chunkSimilarity","k","fetch","whereJoin","whereCond","matchSql","matchRows","candidates","edges","linked","nodes","seeds","ranked","vec","insert","path","c","where","linesCol","Math","max","defaults","prepare","all","Map","r","hit","forEach","i","set","score","via","featureEnabled","linkEdges","Set","flat","personalizedRank","sort","a","b","slice","existing","get","has","semantic","semanticCandidates","lines","similarity","run","INTERNAL_COLUMNS","docs","columns","name","allFields","quoted","n","types","field","coverage","type","fields","hubs","recent","fieldsTotal","features","featureStates","PEEK_LINK_LIMIT","pathArg","row","paths","p","base","posix","basename","replace","toLowerCase","matches","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
|
@@ -91,6 +91,9 @@ export default async function cli(argv, name) {
|
|
|
91
91
|
if (cfg.migratedFrom !== undefined) {
|
|
92
92
|
console.warn(`${name}: migrated ${cfg.configPath} from config version ${cfg.migratedFrom} to ${SUPPORTED_CONFIG_VERSION}`);
|
|
93
93
|
}
|
|
94
|
+
if (cfg.unknownKeys !== undefined) {
|
|
95
|
+
console.warn(`${name}: ${cfg.configPath} sets ${cfg.unknownKeys.join(', ')}, which this build does not read (no effect); see schema.json for the keys it does`);
|
|
96
|
+
}
|
|
94
97
|
return cfg;
|
|
95
98
|
},
|
|
96
99
|
usageError (message) {
|
package/dist/esm/cli.js.map
CHANGED
|
@@ -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] [--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":"AAAA,SAASA,aAAa,QAAQ,cAAc;AAC5C,SAASC,SAAS,QAAQ,YAAY;AACtC,SAASC,QAAQ,QAAQ,sBAAsB;AAE/C,SAASC,UAAU,EAAEC,wBAAwB,QAAQ,cAAc;AAEnE,2FAA2F;AAC3F,6EAA6E;AAE7E,0FAA0F;AAC1F,SAASC;IACP,MAAMC,OAAON,cAAc,YAAYO,GAAG;IAC1C,KAAK,MAAMC,OAAO;QAAC;QAAmB;QAAsB;KAAwB,CAAE;QACpF,IAAI;YACF,MAAMC,MAAMH,KAAKE;YACjB,IAAIC,IAAIC,IAAI,KAAK,iBAAiBD,IAAIE,OAAO,EAAE,OAAOF,IAAIE,OAAO;QACnE,EAAE,OAAM,CAAC;IACX;IACA,OAAO;AACT;AAEA,SAASC,MAAMF,IAAY;IACzB,OACE,CAAC,OAAO,EAAEA,KAAK,2DAA2D,CAAC,GAC3E,CAAC,OAAO,EAAEA,KAAK,4BAA4B,CAAC,GAC5C,CAAC,OAAO,EAAEA,KAAK,wDAAwD,CAAC,GACxE,CAAC,OAAO,EAAEA,KAAK,MAAM,CAAC,GACtB,CAAC,OAAO,EAAEA,KAAK,cAAc,CAAC,GAC9B,CAAC,OAAO,EAAEA,KAAK,SAAS,CAAC,GACzB,CAAC,OAAO,EAAEA,KAAK,OAAO,CAAC,GACvB,CAAC,OAAO,EAAEA,KAAK,kBAAkB,CAAC,GAClC,CAAC,OAAO,EAAEA,KAAK,SAAS,CAAC,GACzB,CAAC,OAAO,EAAEA,KAAK,UAAU,CAAC,GAC1B,CAAC,OAAO,EAAEA,KAAK,UAAU,CAAC;AAE9B;AAEA,mFAAmF;AACnF,eAAe,eAAeG,IAAIC,IAAc,EAAEJ,IAAY;IAC5D,IAAIK;IACJ,IAAIC;IACJ,IAAI;QACD,CAAA,EAAED,MAAM,EAAEC,WAAW,EAAE,GAAGf,UAAU;YACnCgB,MAAMH;YACNI,SAAS;gBACPC,QAAQ;oBAAEC,MAAM;oBAAUC,SAAS;gBAAQ;gBAC3CC,QAAQ;oBAAEF,MAAM;gBAAS;gBACzBG,OAAO;oBAAEH,MAAM;gBAAS;gBACxBI,GAAG;oBAAEJ,MAAM;gBAAS;gBACpBK,UAAU;oBAAEL,MAAM;oBAAWC,SAAS;gBAAM;gBAC5CK,MAAM;oBAAEN,MAAM;oBAAWC,SAAS;gBAAM;gBACxCM,OAAO;oBAAEP,MAAM;oBAAWC,SAAS;gBAAM;gBACzCV,SAAS;oBAAES,MAAM;oBAAWC,SAAS;oBAAOO,OAAO;gBAAI;gBACvDC,MAAM;oBAAET,MAAM;oBAAWC,SAAS;oBAAOO,OAAO;gBAAI;YACtD;YACAE,kBAAkB;QACpB,EAAC;IACH,EAAE,OAAOC,KAAK;QACZC,QAAQC,KAAK,CAAC,AAACF,IAAcG,OAAO;QACpCF,QAAQC,KAAK,CAACrB,MAAMF;QACpByB,QAAQC,IAAI,CAAC;IACf;IAEA,IAAIrB,OAAOJ,OAAO,EAAE;QAClBqB,QAAQK,GAAG,CAAC,CAAC,CAAC,EAAEhC,kBAAkB;QAClC;IACF;IACA,IAAIU,OAAOc,IAAI,EAAE;QACfG,QAAQK,GAAG,CAACzB,MAAMF;QAClB;IACF;IAEA,MAAM4B,MAAW;QACf5B;QACA6B,MAAMvB,YAAYwB,KAAK,CAAC;QACxBrB,QAAQJ,OAAOI,MAAM,KAAK,SAAS,SAAS;QAC5CJ,QAAQA;QACR0B;YACE,MAAMC,MAAMvC,WAAWY,OAAOO,MAAM;YACpC,IAAIoB,IAAIC,YAAY,KAAKC,WAAW;gBAClCZ,QAAQa,IAAI,CAAC,GAAGnC,KAAK,WAAW,EAAEgC,IAAII,UAAU,CAAC,qBAAqB,EAAEJ,IAAIC,YAAY,CAAC,IAAI,EAAEvC,0BAA0B;YAC3H;YACA,
|
|
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 if (cfg.unknownKeys !== undefined) {\n console.warn(`${name}: ${cfg.configPath} sets ${cfg.unknownKeys.join(', ')}, which this build does not read (no effect); see schema.json for the keys it does`);\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","unknownKeys","join","usageError","queryName","Object","keys","queries","sort","first","params"],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { open } from '../db.js';
|
|
2
|
+
import { printRows } from '../output.js';
|
|
3
|
+
import { printWarnings } from './shared.js';
|
|
4
|
+
// A saved query that returns zero rows looks identical to a true empty result, so a broken
|
|
5
|
+
// one can sit unnoticed -- one field report had `WHERE flag = 'true'` against a numeric
|
|
6
|
+
// column reading as "nothing tagged yet" for hours. Preparing each query catches syntax and
|
|
7
|
+
// unknown-column errors without executing it; queries that take no parameters are also run
|
|
8
|
+
// for a row count. Parameterised queries are validated but not counted: inventing arguments
|
|
9
|
+
// would report a count for a query nobody ran.
|
|
10
|
+
const check = (ctx)=>{
|
|
11
|
+
var _cfg_queries;
|
|
12
|
+
const cfg = ctx.resolveConfig();
|
|
13
|
+
const { db, warnings } = open(cfg);
|
|
14
|
+
printWarnings(warnings);
|
|
15
|
+
const rows = [];
|
|
16
|
+
let failed = 0;
|
|
17
|
+
for (const [name, sql] of Object.entries((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {})){
|
|
18
|
+
var _sql_match;
|
|
19
|
+
const params = ((_sql_match = sql.match(/\?/g)) !== null && _sql_match !== void 0 ? _sql_match : []).length;
|
|
20
|
+
try {
|
|
21
|
+
const statement = db.prepare(sql);
|
|
22
|
+
if (params > 0) {
|
|
23
|
+
rows.push({
|
|
24
|
+
query: name,
|
|
25
|
+
params,
|
|
26
|
+
rows: '—',
|
|
27
|
+
status: 'ok (not run: needs parameters)'
|
|
28
|
+
});
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const count = statement.all().length;
|
|
32
|
+
rows.push({
|
|
33
|
+
query: name,
|
|
34
|
+
params,
|
|
35
|
+
rows: count,
|
|
36
|
+
status: count === 0 ? 'ok, but returns 0 rows' : 'ok'
|
|
37
|
+
});
|
|
38
|
+
} catch (err) {
|
|
39
|
+
failed++;
|
|
40
|
+
rows.push({
|
|
41
|
+
query: name,
|
|
42
|
+
params,
|
|
43
|
+
rows: '—',
|
|
44
|
+
status: `FAILED: ${err.message}`
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
db.close();
|
|
49
|
+
if (rows.length === 0) {
|
|
50
|
+
console.log('no saved queries in config');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
printRows(rows, ctx.format);
|
|
54
|
+
if (failed > 0) process.exit(1);
|
|
55
|
+
};
|
|
56
|
+
export default check;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/check.ts"],"sourcesContent":["import { open } from '../db.ts';\nimport type { Row } from '../output.ts';\nimport { printRows } from '../output.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// A saved query that returns zero rows looks identical to a true empty result, so a broken\n// one can sit unnoticed -- one field report had `WHERE flag = 'true'` against a numeric\n// column reading as \"nothing tagged yet\" for hours. Preparing each query catches syntax and\n// unknown-column errors without executing it; queries that take no parameters are also run\n// for a row count. Parameterised queries are validated but not counted: inventing arguments\n// would report a count for a query nobody ran.\nconst check: Command = (ctx) => {\n const cfg = ctx.resolveConfig();\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n\n const rows: Row[] = [];\n let failed = 0;\n for (const [name, sql] of Object.entries(cfg.queries ?? {})) {\n const params = (sql.match(/\\?/g) ?? []).length;\n try {\n const statement = db.prepare(sql);\n if (params > 0) {\n rows.push({ query: name, params, rows: '—', status: 'ok (not run: needs parameters)' });\n continue;\n }\n const count = (statement.all() as unknown[]).length;\n rows.push({ query: name, params, rows: count, status: count === 0 ? 'ok, but returns 0 rows' : 'ok' });\n } catch (err) {\n failed++;\n rows.push({ query: name, params, rows: '—', status: `FAILED: ${(err as Error).message}` });\n }\n }\n\n db.close();\n if (rows.length === 0) {\n console.log('no saved queries in config');\n return;\n }\n printRows(rows, ctx.format);\n if (failed > 0) process.exit(1);\n};\nexport default check;\n"],"names":["open","printRows","printWarnings","check","ctx","cfg","resolveConfig","db","warnings","rows","failed","name","sql","Object","entries","queries","params","match","length","statement","prepare","push","query","status","count","all","err","message","close","console","log","format","process","exit"],"mappings":"AAAA,SAASA,IAAI,QAAQ,WAAW;AAEhC,SAASC,SAAS,QAAQ,eAAe;AACzC,SAASC,aAAa,QAAQ,cAAc;AAG5C,2FAA2F;AAC3F,wFAAwF;AACxF,4FAA4F;AAC5F,2FAA2F;AAC3F,4FAA4F;AAC5F,+CAA+C;AAC/C,MAAMC,QAAiB,CAACC;QAOmBC;IANzC,MAAMA,MAAMD,IAAIE,aAAa;IAC7B,MAAM,EAAEC,EAAE,EAAEC,QAAQ,EAAE,GAAGR,KAAKK;IAC9BH,cAAcM;IAEd,MAAMC,OAAc,EAAE;IACtB,IAAIC,SAAS;IACb,KAAK,MAAM,CAACC,MAAMC,IAAI,IAAIC,OAAOC,OAAO,EAACT,eAAAA,IAAIU,OAAO,cAAXV,0BAAAA,eAAe,CAAC,GAAI;YAC3CO;QAAhB,MAAMI,SAAS,EAACJ,aAAAA,IAAIK,KAAK,CAAC,oBAAVL,wBAAAA,aAAoB,EAAE,EAAEM,MAAM;QAC9C,IAAI;YACF,MAAMC,YAAYZ,GAAGa,OAAO,CAACR;YAC7B,IAAII,SAAS,GAAG;gBACdP,KAAKY,IAAI,CAAC;oBAAEC,OAAOX;oBAAMK;oBAAQP,MAAM;oBAAKc,QAAQ;gBAAiC;gBACrF;YACF;YACA,MAAMC,QAAQ,AAACL,UAAUM,GAAG,GAAiBP,MAAM;YACnDT,KAAKY,IAAI,CAAC;gBAAEC,OAAOX;gBAAMK;gBAAQP,MAAMe;gBAAOD,QAAQC,UAAU,IAAI,2BAA2B;YAAK;QACtG,EAAE,OAAOE,KAAK;YACZhB;YACAD,KAAKY,IAAI,CAAC;gBAAEC,OAAOX;gBAAMK;gBAAQP,MAAM;gBAAKc,QAAQ,CAAC,QAAQ,EAAE,AAACG,IAAcC,OAAO,EAAE;YAAC;QAC1F;IACF;IAEApB,GAAGqB,KAAK;IACR,IAAInB,KAAKS,MAAM,KAAK,GAAG;QACrBW,QAAQC,GAAG,CAAC;QACZ;IACF;IACA7B,UAAUQ,MAAML,IAAI2B,MAAM;IAC1B,IAAIrB,SAAS,GAAGsB,QAAQC,IAAI,CAAC;AAC/B;AACA,eAAe9B,MAAM"}
|
|
@@ -5,6 +5,7 @@ export const COMMANDS = {
|
|
|
5
5
|
init: ()=>import('./init.js'),
|
|
6
6
|
watch: ()=>import('./watch.js'),
|
|
7
7
|
status: ()=>import('./status.js'),
|
|
8
|
+
check: ()=>import('./check.js'),
|
|
8
9
|
rebuild: ()=>import('./rebuild.js'),
|
|
9
10
|
query: ()=>import('./query.js'),
|
|
10
11
|
find: ()=>import('./find.js'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/index.ts"],"sourcesContent":["import type { Command } from './types.ts';\n\n// Lazy registry: a command's imports load only when it runs, so a heavy dependency in one\n// command never taxes the others (or --version/--help). These names are reserved: a named\n// query in config can never shadow them.\nexport const COMMANDS: Record<string, () => Promise<{ default: Command }>> = {\n init: () => import('./init.ts'),\n watch: () => import('./watch.ts'),\n status: () => import('./status.ts'),\n rebuild: () => import('./rebuild.ts'),\n query: () => import('./query.ts'),\n find: () => import('./find.ts'),\n map: () => import('./map.ts'),\n peek: () => import('./peek.ts'),\n};\n\nexport type { Command, Ctx } from './types.ts';\n"],"names":["COMMANDS","init","watch","status","rebuild","query","find","map","peek"],"mappings":"AAEA,0FAA0F;AAC1F,0FAA0F;AAC1F,yCAAyC;AACzC,OAAO,MAAMA,WAAgE;IAC3EC,MAAM,IAAM,MAAM,CAAC;IACnBC,OAAO,IAAM,MAAM,CAAC;IACpBC,QAAQ,IAAM,MAAM,CAAC;IACrBC,SAAS,IAAM,MAAM,CAAC;IACtBC,OAAO,IAAM,MAAM,CAAC;IACpBC,MAAM,IAAM,MAAM,CAAC;IACnBC,KAAK,IAAM,MAAM,CAAC;IAClBC,MAAM,IAAM,MAAM,CAAC;AACrB,EAAE"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/index.ts"],"sourcesContent":["import type { Command } from './types.ts';\n\n// Lazy registry: a command's imports load only when it runs, so a heavy dependency in one\n// command never taxes the others (or --version/--help). These names are reserved: a named\n// query in config can never shadow them.\nexport const COMMANDS: Record<string, () => Promise<{ default: Command }>> = {\n init: () => import('./init.ts'),\n watch: () => import('./watch.ts'),\n status: () => import('./status.ts'),\n check: () => import('./check.ts'),\n rebuild: () => import('./rebuild.ts'),\n query: () => import('./query.ts'),\n find: () => import('./find.ts'),\n map: () => import('./map.ts'),\n peek: () => import('./peek.ts'),\n};\n\nexport type { Command, Ctx } from './types.ts';\n"],"names":["COMMANDS","init","watch","status","check","rebuild","query","find","map","peek"],"mappings":"AAEA,0FAA0F;AAC1F,0FAA0F;AAC1F,yCAAyC;AACzC,OAAO,MAAMA,WAAgE;IAC3EC,MAAM,IAAM,MAAM,CAAC;IACnBC,OAAO,IAAM,MAAM,CAAC;IACpBC,QAAQ,IAAM,MAAM,CAAC;IACrBC,OAAO,IAAM,MAAM,CAAC;IACpBC,SAAS,IAAM,MAAM,CAAC;IACtBC,OAAO,IAAM,MAAM,CAAC;IACpBC,MAAM,IAAM,MAAM,CAAC;IACnBC,KAAK,IAAM,MAAM,CAAC;IAClBC,MAAM,IAAM,MAAM,CAAC;AACrB,EAAE"}
|
|
@@ -1,20 +1,51 @@
|
|
|
1
1
|
import { embedConfig, featureStates } from '../config.js';
|
|
2
2
|
import { docCount, getMeta, open } from '../db.js';
|
|
3
3
|
import { printWarnings } from './shared.js';
|
|
4
|
+
// Vectors are computed on the first semantic query, not at reconcile, so a tree can be
|
|
5
|
+
// embed-enabled with nothing embedded yet -- reported here because a fast `rebuild` on an
|
|
6
|
+
// embed tree otherwise reads as "the feature isn't on".
|
|
7
|
+
function vectorState(db) {
|
|
8
|
+
try {
|
|
9
|
+
const row = db.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings').get();
|
|
10
|
+
return row;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
const status = (ctx)=>{
|
|
16
|
+
var _ref;
|
|
17
|
+
var _cfg_defaults_find, _cfg_defaults;
|
|
5
18
|
const cfg = ctx.resolveConfig();
|
|
6
19
|
const { db, dbPath, warnings } = open(cfg);
|
|
7
20
|
printWarnings(warnings);
|
|
8
|
-
console.log(`db: ${dbPath}`);
|
|
9
|
-
console.log(`docs: ${docCount(db)}`);
|
|
10
21
|
const features = featureStates(cfg);
|
|
11
|
-
const off = features.off.length > 0 ? ` · off: ${features.off.map((name)=>`${name} (features.${name})`).join(', ')}` : '';
|
|
12
|
-
console.log(`features: ${features.on.join(', ')}${off}`);
|
|
13
22
|
const e = embedConfig(cfg);
|
|
14
|
-
|
|
23
|
+
const vectors = e ? vectorState(db) : null;
|
|
15
24
|
const heartbeat = getMeta(db, 'watch_heartbeat');
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
const result = {
|
|
26
|
+
db: dbPath,
|
|
27
|
+
docs: docCount(db),
|
|
28
|
+
features: features.on,
|
|
29
|
+
featuresOff: features.off,
|
|
30
|
+
embed: e ? {
|
|
31
|
+
type: e.type,
|
|
32
|
+
model: e.model,
|
|
33
|
+
...vectors !== null && vectors !== void 0 ? vectors : {}
|
|
34
|
+
} : null,
|
|
35
|
+
findDefaultWhere: (_ref = (_cfg_defaults = cfg.defaults) === null || _cfg_defaults === void 0 ? void 0 : (_cfg_defaults_find = _cfg_defaults.find) === null || _cfg_defaults_find === void 0 ? void 0 : _cfg_defaults_find.where) !== null && _ref !== void 0 ? _ref : null,
|
|
36
|
+
watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null
|
|
37
|
+
};
|
|
38
|
+
if (ctx.format === 'json') {
|
|
39
|
+
console.log(JSON.stringify(result, null, 2));
|
|
40
|
+
} else {
|
|
41
|
+
console.log(`db: ${result.db}`);
|
|
42
|
+
console.log(`docs: ${result.docs}`);
|
|
43
|
+
const off = features.off.length > 0 ? ` · off: ${features.off.map((name)=>`${name} (features.${name})`).join(', ')}` : '';
|
|
44
|
+
console.log(`features: ${features.on.join(', ')}${off}`);
|
|
45
|
+
if (e) console.log(`embed: ${e.type} ${e.model}${vectors ? ` (vectors: ${vectors.embedded} embedded, ${vectors.pending} pending — embedded on first --semantic query)` : ''}`);
|
|
46
|
+
if (result.findDefaultWhere) console.log(`find default scope: ${result.findDefaultWhere} (--where replaces it)`);
|
|
47
|
+
console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: no watcher' : `watcher: last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);
|
|
48
|
+
}
|
|
18
49
|
db.close();
|
|
19
50
|
};
|
|
20
51
|
export default status;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/status.ts"],"sourcesContent":["import { embedConfig, featureStates } from '../config.ts';\nimport { docCount, getMeta, open } from '../db.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst status: Command = (ctx) => {\n const cfg = ctx.resolveConfig();\n const { db, dbPath, warnings } = open(cfg);\n printWarnings(warnings);\n console.log(`db: ${
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/status.ts"],"sourcesContent":["import { embedConfig, featureStates } from '../config.ts';\nimport { docCount, getMeta, open } from '../db.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can be\n// embed-enabled with nothing embedded yet -- reported here because a fast `rebuild` on an\n// embed tree otherwise reads as \"the feature isn't on\".\nfunction vectorState(db: ReturnType<typeof open>['db']): { embedded: number; pending: number } | null {\n try {\n const row = db.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings').get() as { embedded: number; pending: number };\n return row;\n } catch {\n return null;\n }\n}\n\nconst status: Command = (ctx) => {\n const cfg = ctx.resolveConfig();\n const { db, dbPath, warnings } = open(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const vectors = e ? vectorState(db) : null;\n const heartbeat = getMeta(db, 'watch_heartbeat');\n const result = {\n db: dbPath,\n docs: docCount(db),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { type: e.type, model: e.model, ...(vectors ?? {}) } : null,\n findDefaultWhere: cfg.defaults?.find?.where ?? null,\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n };\n\n if (ctx.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`db: ${result.db}`);\n console.log(`docs: ${result.docs}`);\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (features.${name})`).join(', ')}` : '';\n console.log(`features: ${features.on.join(', ')}${off}`);\n if (e) console.log(`embed: ${e.type} ${e.model}${vectors ? ` (vectors: ${vectors.embedded} embedded, ${vectors.pending} pending — embedded on first --semantic query)` : ''}`);\n if (result.findDefaultWhere) console.log(`find default scope: ${result.findDefaultWhere} (--where replaces it)`);\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: no watcher' : `watcher: last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n }\n db.close();\n};\nexport default status;\n"],"names":["embedConfig","featureStates","docCount","getMeta","open","printWarnings","vectorState","db","row","prepare","get","status","ctx","cfg","resolveConfig","dbPath","warnings","features","e","vectors","heartbeat","result","docs","on","featuresOff","off","embed","type","model","findDefaultWhere","defaults","find","where","watcherHeartbeatSecondsAgo","Math","round","Date","now","parse","format","console","log","JSON","stringify","length","map","name","join","embedded","pending","close"],"mappings":"AAAA,SAASA,WAAW,EAAEC,aAAa,QAAQ,eAAe;AAC1D,SAASC,QAAQ,EAAEC,OAAO,EAAEC,IAAI,QAAQ,WAAW;AACnD,SAASC,aAAa,QAAQ,cAAc;AAG5C,uFAAuF;AACvF,0FAA0F;AAC1F,wDAAwD;AACxD,SAASC,YAAYC,EAAiC;IACpD,IAAI;QACF,MAAMC,MAAMD,GAAGE,OAAO,CAAC,yFAAyFC,GAAG;QACnH,OAAOF;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,MAAMG,SAAkB,CAACC;;QAeHC,oBAAAA;IAdpB,MAAMA,MAAMD,IAAIE,aAAa;IAC7B,MAAM,EAAEP,EAAE,EAAEQ,MAAM,EAAEC,QAAQ,EAAE,GAAGZ,KAAKS;IACtCR,cAAcW;IAEd,MAAMC,WAAWhB,cAAcY;IAC/B,MAAMK,IAAIlB,YAAYa;IACtB,MAAMM,UAAUD,IAAIZ,YAAYC,MAAM;IACtC,MAAMa,YAAYjB,QAAQI,IAAI;IAC9B,MAAMc,SAAS;QACbd,IAAIQ;QACJO,MAAMpB,SAASK;QACfU,UAAUA,SAASM,EAAE;QACrBC,aAAaP,SAASQ,GAAG;QACzBC,OAAOR,IAAI;YAAES,MAAMT,EAAES,IAAI;YAAEC,OAAOV,EAAEU,KAAK;eAAMT,oBAAAA,qBAAAA,UAAW,CAAC,CAAhB;QAAmB,IAAI;QAClEU,gBAAgB,WAAEhB,gBAAAA,IAAIiB,QAAQ,cAAZjB,qCAAAA,qBAAAA,cAAckB,IAAI,cAAlBlB,yCAAAA,mBAAoBmB,KAAK,uCAAI;QAC/CC,4BAA4Bb,YAAYc,KAAKC,KAAK,CAAC,AAACC,CAAAA,KAAKC,GAAG,KAAKD,KAAKE,KAAK,CAAClB,UAAS,IAAK,QAAQ;IACpG;IAEA,IAAIR,IAAI2B,MAAM,KAAK,QAAQ;QACzBC,QAAQC,GAAG,CAACC,KAAKC,SAAS,CAACtB,QAAQ,MAAM;IAC3C,OAAO;QACLmB,QAAQC,GAAG,CAAC,CAAC,IAAI,EAAEpB,OAAOd,EAAE,EAAE;QAC9BiC,QAAQC,GAAG,CAAC,CAAC,MAAM,EAAEpB,OAAOC,IAAI,EAAE;QAClC,MAAMG,MAAMR,SAASQ,GAAG,CAACmB,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE3B,SAASQ,GAAG,CAACoB,GAAG,CAAC,CAACC,OAAS,GAAGA,KAAK,WAAW,EAAEA,KAAK,CAAC,CAAC,EAAEC,IAAI,CAAC,OAAO,GAAG;QACzHP,QAAQC,GAAG,CAAC,CAAC,UAAU,EAAExB,SAASM,EAAE,CAACwB,IAAI,CAAC,QAAQtB,KAAK;QACvD,IAAIP,GAAGsB,QAAQC,GAAG,CAAC,CAAC,OAAO,EAAEvB,EAAES,IAAI,CAAC,CAAC,EAAET,EAAEU,KAAK,GAAGT,UAAU,CAAC,WAAW,EAAEA,QAAQ6B,QAAQ,CAAC,WAAW,EAAE7B,QAAQ8B,OAAO,CAAC,8CAA8C,CAAC,GAAG,IAAI;QAC7K,IAAI5B,OAAOQ,gBAAgB,EAAEW,QAAQC,GAAG,CAAC,CAAC,oBAAoB,EAAEpB,OAAOQ,gBAAgB,CAAC,sBAAsB,CAAC;QAC/GW,QAAQC,GAAG,CAACpB,OAAOY,0BAA0B,KAAK,OAAO,wBAAwB,CAAC,wBAAwB,EAAEZ,OAAOY,0BAA0B,CAAC,KAAK,CAAC;IACtJ;IACA1B,GAAG2C,KAAK;AACV;AACA,eAAevC,OAAO"}
|
package/dist/esm/config.d.ts
CHANGED
|
@@ -22,11 +22,17 @@ export interface Config {
|
|
|
22
22
|
rank?: boolean;
|
|
23
23
|
embed?: boolean | EmbedConfig;
|
|
24
24
|
};
|
|
25
|
+
defaults?: {
|
|
26
|
+
find?: {
|
|
27
|
+
where?: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
25
30
|
queries: Record<string, string>;
|
|
26
31
|
}
|
|
27
32
|
export interface ResolvedConfig extends Config {
|
|
28
33
|
baseDir: string;
|
|
29
34
|
configPath: string | null;
|
|
35
|
+
unknownKeys?: string[];
|
|
30
36
|
migratedFrom?: number;
|
|
31
37
|
}
|
|
32
38
|
export declare function featureEnabled(cfg: Config, name: FeatureName): boolean;
|
package/dist/esm/config.js
CHANGED
|
@@ -126,8 +126,36 @@ export function findConfigPath(startDir) {
|
|
|
126
126
|
// Shape check for hand-edited files: a typo'd config fails with a named error, not a
|
|
127
127
|
// TypeError from whatever code touched the missing field first. `queries` is optional
|
|
128
128
|
// on disk (absent = none); `scan.include` has no usable default.
|
|
129
|
+
// Keys each block actually reads. A key outside these sets is accepted and ignored, which
|
|
130
|
+
// looks identical to working -- one field report set `scan.exclude`, saw no change in doc
|
|
131
|
+
// count and no warning, and reasonably concluded the filter had applied. Reported as a
|
|
132
|
+
// warning rather than an error so a config carrying an unknown key still runs.
|
|
133
|
+
const KNOWN_KEYS = new Set([
|
|
134
|
+
'$schema',
|
|
135
|
+
'version',
|
|
136
|
+
'scan',
|
|
137
|
+
'features',
|
|
138
|
+
'defaults',
|
|
139
|
+
'queries'
|
|
140
|
+
]);
|
|
141
|
+
const KNOWN_SCAN_KEYS = new Set([
|
|
142
|
+
'include'
|
|
143
|
+
]);
|
|
144
|
+
function unknownConfigKeys(cfg) {
|
|
145
|
+
const unknown = Object.keys(cfg).filter((k)=>!KNOWN_KEYS.has(k)).map((k)=>k);
|
|
146
|
+
const scan = cfg.scan;
|
|
147
|
+
if (scan && typeof scan === 'object' && !Array.isArray(scan)) {
|
|
148
|
+
unknown.push(...Object.keys(scan).filter((k)=>!KNOWN_SCAN_KEYS.has(k)).map((k)=>`scan.${k}`));
|
|
149
|
+
}
|
|
150
|
+
const features = cfg.features;
|
|
151
|
+
if (features && typeof features === 'object' && !Array.isArray(features)) {
|
|
152
|
+
unknown.push(...Object.keys(features).filter((k)=>!FEATURE_NAMES.includes(k)).map((k)=>`features.${k}`));
|
|
153
|
+
}
|
|
154
|
+
return unknown;
|
|
155
|
+
}
|
|
129
156
|
function validateConfig(parsed, configPath) {
|
|
130
157
|
var _cfg_features;
|
|
158
|
+
var _defaults_find;
|
|
131
159
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
132
160
|
throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);
|
|
133
161
|
}
|
|
@@ -140,6 +168,10 @@ function validateConfig(parsed, configPath) {
|
|
|
140
168
|
if (typeof cfg.queries !== 'object' || cfg.queries === null || Array.isArray(cfg.queries) || !Object.values(cfg.queries).every((q)=>typeof q === 'string')) {
|
|
141
169
|
throw new SenseError('CONFIG_INVALID', `${configPath}: queries must be an object of name -> SQL string`);
|
|
142
170
|
}
|
|
171
|
+
const defaults = cfg.defaults;
|
|
172
|
+
if (defaults !== undefined && (typeof defaults !== 'object' || defaults === null || Array.isArray(defaults) || defaults.find !== undefined && typeof ((_defaults_find = defaults.find) === null || _defaults_find === void 0 ? void 0 : _defaults_find.where) !== 'string')) {
|
|
173
|
+
throw new SenseError('CONFIG_INVALID', `${configPath}: defaults.find.where must be a SQL condition string`);
|
|
174
|
+
}
|
|
143
175
|
if (cfg.features !== undefined && (typeof cfg.features !== 'object' || cfg.features === null || Array.isArray(cfg.features))) {
|
|
144
176
|
throw new SenseError('CONFIG_INVALID', `${configPath}: features must be an object of name -> boolean`);
|
|
145
177
|
}
|
|
@@ -186,10 +218,12 @@ export function loadConfig(explicitPath) {
|
|
|
186
218
|
migratedFrom = result.from;
|
|
187
219
|
writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
188
220
|
}
|
|
221
|
+
const unknownKeys = unknownConfigKeys(cfg);
|
|
189
222
|
return {
|
|
190
223
|
...cfg,
|
|
191
224
|
baseDir: dirname(configPath),
|
|
192
225
|
configPath,
|
|
193
|
-
migratedFrom
|
|
226
|
+
migratedFrom,
|
|
227
|
+
unknownKeys: unknownKeys.length > 0 ? unknownKeys : undefined
|
|
194
228
|
};
|
|
195
229
|
}
|