sensemaking 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/find.js +2 -2
- package/dist/cjs/commands/find.js.map +1 -1
- package/dist/cjs/commands/map.js +3 -3
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/named.js +2 -2
- package/dist/cjs/commands/named.js.map +1 -1
- package/dist/cjs/commands/peek.js +2 -2
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/query.js +2 -2
- package/dist/cjs/commands/query.js.map +1 -1
- package/dist/cjs/commands/rebuild.js +2 -2
- package/dist/cjs/commands/rebuild.js.map +1 -1
- package/dist/cjs/commands/{vault.d.cts → shared.d.cts} +1 -1
- package/dist/cjs/commands/{vault.d.ts → shared.d.ts} +1 -1
- package/dist/cjs/commands/{vault.js → shared.js} +3 -3
- package/dist/cjs/commands/shared.js.map +1 -0
- package/dist/cjs/commands/status.js +2 -2
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/commands/watch.js +2 -2
- package/dist/cjs/commands/watch.js.map +1 -1
- package/dist/cjs/config.js +36 -3
- package/dist/cjs/config.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/links.js +1 -1
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/index.d.cts +4 -11
- package/dist/cjs/index.d.ts +4 -11
- package/dist/cjs/index.js +5 -55
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/verbs.d.cts +2 -2
- package/dist/cjs/verbs.d.ts +2 -2
- package/dist/cjs/verbs.js +10 -6
- package/dist/cjs/verbs.js.map +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/find.js +2 -2
- package/dist/esm/commands/find.js.map +1 -1
- package/dist/esm/commands/map.js +4 -4
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/named.js +1 -1
- package/dist/esm/commands/named.js.map +1 -1
- package/dist/esm/commands/peek.js +2 -2
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/query.js +1 -1
- package/dist/esm/commands/query.js.map +1 -1
- package/dist/esm/commands/rebuild.js +1 -1
- package/dist/esm/commands/rebuild.js.map +1 -1
- package/dist/esm/commands/{vault.d.ts → shared.d.ts} +1 -1
- package/dist/esm/commands/{vault.js → shared.js} +2 -2
- package/dist/esm/commands/shared.js.map +1 -0
- package/dist/esm/commands/status.js +1 -1
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/commands/watch.js +1 -1
- package/dist/esm/commands/watch.js.map +1 -1
- package/dist/esm/config.js +26 -3
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/links.js +1 -1
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/types.js +1 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/index.d.ts +4 -11
- package/dist/esm/index.js +5 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/verbs.d.ts +2 -2
- package/dist/esm/verbs.js +8 -4
- package/dist/esm/verbs.js.map +1 -1
- package/package.json +1 -1
- package/schema.json +1 -1
- package/skills/sense/EXAMPLES.md +12 -13
- package/skills/sense/SKILL.md +28 -16
- package/dist/cjs/commands/vault.js.map +0 -1
- package/dist/esm/commands/vault.js.map +0 -1
package/dist/cjs/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// Public library API.
|
|
1
|
+
// Public library API. Deliberately small: every export is a stability promise;
|
|
2
|
+
// internals (feature registry, graph, scan, meta) stay module-private.
|
|
2
3
|
"use strict";
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
@@ -13,15 +14,6 @@ _export(exports, {
|
|
|
13
14
|
get CONFIG_FILENAME () {
|
|
14
15
|
return _configts.CONFIG_FILENAME;
|
|
15
16
|
},
|
|
16
|
-
get DB_FILENAME () {
|
|
17
|
-
return _dbts.DB_FILENAME;
|
|
18
|
-
},
|
|
19
|
-
get FEATURES () {
|
|
20
|
-
return _indexts.FEATURES;
|
|
21
|
-
},
|
|
22
|
-
get FEATURE_NAMES () {
|
|
23
|
-
return _configts.FEATURE_NAMES;
|
|
24
|
-
},
|
|
25
17
|
get STATE_DIR () {
|
|
26
18
|
return _configts.STATE_DIR;
|
|
27
19
|
},
|
|
@@ -31,83 +23,41 @@ _export(exports, {
|
|
|
31
23
|
get SenseError () {
|
|
32
24
|
return _errorsts.SenseError;
|
|
33
25
|
},
|
|
34
|
-
get activeFeatures () {
|
|
35
|
-
return _indexts.activeFeatures;
|
|
36
|
-
},
|
|
37
|
-
get docCount () {
|
|
38
|
-
return _dbts.docCount;
|
|
39
|
-
},
|
|
40
|
-
get enabledFeatures () {
|
|
41
|
-
return _configts.enabledFeatures;
|
|
42
|
-
},
|
|
43
|
-
get featureEnabled () {
|
|
44
|
-
return _configts.featureEnabled;
|
|
45
|
-
},
|
|
46
26
|
get find () {
|
|
47
27
|
return _verbsts.find;
|
|
48
28
|
},
|
|
49
|
-
get findConfigPath () {
|
|
50
|
-
return _configts.findConfigPath;
|
|
51
|
-
},
|
|
52
|
-
get getMeta () {
|
|
53
|
-
return _dbts.getMeta;
|
|
54
|
-
},
|
|
55
29
|
get initConfig () {
|
|
56
30
|
return _configts.initConfig;
|
|
57
31
|
},
|
|
58
|
-
get linkEdges () {
|
|
59
|
-
return _indexts.linkEdges;
|
|
60
|
-
},
|
|
61
|
-
get listFiles () {
|
|
62
|
-
return _scants.listFiles;
|
|
63
|
-
},
|
|
64
32
|
get loadConfig () {
|
|
65
33
|
return _configts.loadConfig;
|
|
66
34
|
},
|
|
35
|
+
get mapTree () {
|
|
36
|
+
return _verbsts.mapTree;
|
|
37
|
+
},
|
|
67
38
|
get migrateConfig () {
|
|
68
39
|
return _configts.migrateConfig;
|
|
69
40
|
},
|
|
70
41
|
get open () {
|
|
71
42
|
return _dbts.open;
|
|
72
43
|
},
|
|
73
|
-
get pagerank () {
|
|
74
|
-
return _graphts.pagerank;
|
|
75
|
-
},
|
|
76
|
-
get parseFile () {
|
|
77
|
-
return _scants.parseFile;
|
|
78
|
-
},
|
|
79
44
|
get peek () {
|
|
80
45
|
return _verbsts.peek;
|
|
81
46
|
},
|
|
82
|
-
get personalizedRank () {
|
|
83
|
-
return _graphts.personalizedRank;
|
|
84
|
-
},
|
|
85
47
|
get printRows () {
|
|
86
48
|
return _outputts.printRows;
|
|
87
49
|
},
|
|
88
50
|
get rebuild () {
|
|
89
51
|
return _dbts.rebuild;
|
|
90
52
|
},
|
|
91
|
-
get reconcile () {
|
|
92
|
-
return _dbts.reconcile;
|
|
93
|
-
},
|
|
94
53
|
get runWatch () {
|
|
95
54
|
return _watchts.runWatch;
|
|
96
|
-
},
|
|
97
|
-
get setMeta () {
|
|
98
|
-
return _dbts.setMeta;
|
|
99
|
-
},
|
|
100
|
-
get vaultMap () {
|
|
101
|
-
return _verbsts.vaultMap;
|
|
102
55
|
}
|
|
103
56
|
});
|
|
104
57
|
var _configts = require("./config.js");
|
|
105
58
|
var _dbts = require("./db.js");
|
|
106
59
|
var _errorsts = require("./errors.js");
|
|
107
|
-
var _indexts = require("./features/index.js");
|
|
108
|
-
var _graphts = require("./graph.js");
|
|
109
60
|
var _outputts = require("./output.js");
|
|
110
|
-
var _scants = require("./scan.js");
|
|
111
61
|
var _verbsts = require("./verbs.js");
|
|
112
62
|
var _watchts = require("./watch.js");
|
|
113
63
|
/* 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; }
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API.\n\nexport type { Config, FeatureName, ResolvedConfig } from './config.ts';\nexport { CONFIG_FILENAME,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type { Config, FeatureName, ResolvedConfig } from './config.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config.ts';\n\nexport type { OpenResult } from './db.ts';\nexport { open, rebuild } from './db.ts';\n\nexport type { SenseErrorCode } from './errors.ts';\nexport { SenseError } from './errors.ts';\n\nexport type { Row } from './output.ts';\nexport { printRows } from './output.ts';\n\nexport type { FindOptions, Peek, TreeMap } from './verbs.ts';\nexport { find, mapTree, peek } from './verbs.ts';\n\nexport type { WatchEvent, WatchOptions } from './watch.ts';\nexport { runWatch } from './watch.ts';\n"],"names":["CONFIG_FILENAME","STATE_DIR","SUPPORTED_CONFIG_VERSION","SenseError","find","initConfig","loadConfig","mapTree","migrateConfig","open","peek","printRows","rebuild","runWatch"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;;;;;;;;;;;;QAG9DA;eAAAA,yBAAe;;QAAyCC;eAAAA,mBAAS;;QAAEC;eAAAA,kCAAwB;;QAM3FC;eAAAA,oBAAU;;QAMVC;eAAAA,aAAI;;QAZaC;eAAAA,oBAAU;;QAAEC;eAAAA,oBAAU;;QAYjCC;eAAAA,gBAAO;;QAZ4BC;eAAAA,uBAAa;;QAGtDC;eAAAA,UAAI;;QASWC;eAAAA,aAAI;;QAHnBC;eAAAA,mBAAS;;QANHC;eAAAA,aAAO;;QAYbC;eAAAA,iBAAQ;;;wBAf2F;oBAG9E;wBAGH;wBAGD;uBAGU;uBAGX"}
|
package/dist/cjs/verbs.d.cts
CHANGED
|
@@ -6,7 +6,7 @@ export interface FindOptions {
|
|
|
6
6
|
where?: string;
|
|
7
7
|
}
|
|
8
8
|
export declare function find(db: DatabaseSync, cfg: Config, terms: string, opts?: FindOptions): Row[];
|
|
9
|
-
export interface
|
|
9
|
+
export interface TreeMap {
|
|
10
10
|
docs: {
|
|
11
11
|
count: number;
|
|
12
12
|
bytes: number;
|
|
@@ -16,7 +16,7 @@ export interface VaultMap {
|
|
|
16
16
|
hubs: Row[];
|
|
17
17
|
recent: Row[];
|
|
18
18
|
}
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function mapTree(db: DatabaseSync, cfg: Config): TreeMap;
|
|
20
20
|
export interface Peek {
|
|
21
21
|
path: string;
|
|
22
22
|
tokens: number;
|
package/dist/cjs/verbs.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface FindOptions {
|
|
|
6
6
|
where?: string;
|
|
7
7
|
}
|
|
8
8
|
export declare function find(db: DatabaseSync, cfg: Config, terms: string, opts?: FindOptions): Row[];
|
|
9
|
-
export interface
|
|
9
|
+
export interface TreeMap {
|
|
10
10
|
docs: {
|
|
11
11
|
count: number;
|
|
12
12
|
bytes: number;
|
|
@@ -16,7 +16,7 @@ export interface VaultMap {
|
|
|
16
16
|
hubs: Row[];
|
|
17
17
|
recent: Row[];
|
|
18
18
|
}
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function mapTree(db: DatabaseSync, cfg: Config): TreeMap;
|
|
20
20
|
export interface Peek {
|
|
21
21
|
path: string;
|
|
22
22
|
tokens: number;
|
package/dist/cjs/verbs.js
CHANGED
|
@@ -12,11 +12,11 @@ _export(exports, {
|
|
|
12
12
|
get find () {
|
|
13
13
|
return find;
|
|
14
14
|
},
|
|
15
|
+
get mapTree () {
|
|
16
|
+
return mapTree;
|
|
17
|
+
},
|
|
15
18
|
get peek () {
|
|
16
19
|
return peek;
|
|
17
|
-
},
|
|
18
|
-
get vaultMap () {
|
|
19
|
-
return vaultMap;
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
22
|
var _posix = /*#__PURE__*/ _interop_require_default(require("node:path/posix"));
|
|
@@ -87,7 +87,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
87
87
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
88
88
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
89
89
|
}
|
|
90
|
-
// The three layer verbs:
|
|
90
|
+
// The three layer verbs: mapTree (orient), find (locate), peek (structure).
|
|
91
91
|
// Each returns data; cli.ts renders. All of them degrade when a feature is off.
|
|
92
92
|
var WEIGHTED_BM25 = 'bm25(content, 10.0, 5.0, 1.0)';
|
|
93
93
|
var RRF_K = 60;
|
|
@@ -98,7 +98,11 @@ function find(db, cfg, terms) {
|
|
|
98
98
|
var fetch = Math.max(k * 3, 30);
|
|
99
99
|
// Terms pass verbatim to FTS5 MATCH: bare words AND-join, operators are the caller's.
|
|
100
100
|
// Invalid syntax propagates as an error, zero matches return zero -- no silent rewrites.
|
|
101
|
-
|
|
101
|
+
// --where applies inside the candidate query (a post-filter over the top-N would drop
|
|
102
|
+
// matches ranked past the pool) and again on the final select for link-derived rows.
|
|
103
|
+
var whereJoin = opts.where ? 'JOIN frontmatter f ON f."path" = content.path' : '';
|
|
104
|
+
var whereCond = opts.where ? "AND (".concat(opts.where, ")") : '';
|
|
105
|
+
var 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);
|
|
102
106
|
var matchRows = db.prepare(matchSql).all(terms);
|
|
103
107
|
var hits = new Map(matchRows.map(function(r) {
|
|
104
108
|
return [
|
|
@@ -175,7 +179,7 @@ var INTERNAL_COLUMNS = new Set([
|
|
|
175
179
|
'_size',
|
|
176
180
|
'_rank'
|
|
177
181
|
]);
|
|
178
|
-
function
|
|
182
|
+
function mapTree(db, cfg) {
|
|
179
183
|
var docs = db.prepare('SELECT COUNT(*) AS count, COALESCE(SUM("_size"), 0) AS bytes FROM frontmatter').get();
|
|
180
184
|
var columns = db.prepare('PRAGMA table_info(frontmatter)').all().map(function(r) {
|
|
181
185
|
return r.name;
|
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 } 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: vaultMap (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 VaultMap {\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 vault. Fixed-size output regardless of vault size.\nexport function vaultMap(db: DatabaseSync, cfg: Config): VaultMap {\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","peek","vaultMap","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 } 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 // --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 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","whereJoin","where","whereCond","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","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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"}
|
package/dist/esm/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { parseArgs } from 'node:util';
|
|
|
3
3
|
import { COMMANDS } from './commands/index.js';
|
|
4
4
|
import { loadConfig, SUPPORTED_CONFIG_VERSION } from './config.js';
|
|
5
5
|
// Parsing and dispatch only. Commands live in src/commands/, one file each, lazy-loaded --
|
|
6
|
-
// nothing
|
|
6
|
+
// nothing tree- or dependency-heavy may be imported at the top of this file.
|
|
7
7
|
// Works from dist/cjs and dist/esm alike: walk up past the dist type-marker package.json.
|
|
8
8
|
function packageVersion() {
|
|
9
9
|
const load = createRequire(import.meta.url);
|
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
|
|
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,12 +1,12 @@
|
|
|
1
1
|
import { printRows } from '../output.js';
|
|
2
2
|
import { find } from '../verbs.js';
|
|
3
|
-
import {
|
|
3
|
+
import { withDb } from './shared.js';
|
|
4
4
|
const findCmd = (ctx)=>{
|
|
5
5
|
const [terms] = ctx.rest;
|
|
6
6
|
if (!terms) ctx.usageError(`usage: ${ctx.name} find "<terms>" [--where "<sql>"] [--k n]`);
|
|
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
|
-
|
|
9
|
+
withDb(ctx, (db, cfg)=>printRows(find(db, cfg, terms, {
|
|
10
10
|
k,
|
|
11
11
|
where: ctx.values.where
|
|
12
12
|
}), ctx.format));
|
|
@@ -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
|
|
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"}
|
package/dist/esm/commands/map.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { renderMap } from '../output.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { mapTree } from '../verbs.js';
|
|
3
|
+
import { withDb } from './shared.js';
|
|
4
4
|
const map = (ctx)=>{
|
|
5
|
-
|
|
6
|
-
const result =
|
|
5
|
+
withDb(ctx, (db, cfg)=>{
|
|
6
|
+
const result = mapTree(db, cfg);
|
|
7
7
|
console.log(ctx.format === 'json' ? JSON.stringify(result, null, 2) : renderMap(result));
|
|
8
8
|
});
|
|
9
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/map.ts"],"sourcesContent":["import { renderMap } from '../output.ts';\nimport {
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/named.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/named.ts"],"sourcesContent":["import { runSql } from './shared.ts';\nimport type { Ctx } from './types.ts';\n\n// Fallback when the first positional is not a command: a named query from config.\nexport default function named(ctx: Ctx, queryName: string, params: string[]): void {\n const cfg = ctx.resolveConfig();\n const sql = cfg.queries[queryName];\n if (!sql) {\n console.error(`unknown query: \"${queryName}\"`);\n console.error(`valid queries: ${Object.keys(cfg.queries).sort().join(', ')}`);\n process.exit(2);\n }\n runSql(cfg, sql, params, ctx.format, `query \"${queryName}\"`);\n}\n"],"names":["runSql","named","ctx","queryName","params","cfg","resolveConfig","sql","queries","console","error","Object","keys","sort","join","process","exit","format"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AAGrC,kFAAkF;AAClF,eAAe,SAASC,MAAMC,GAAQ,EAAEC,SAAiB,EAAEC,MAAgB;IACzE,MAAMC,MAAMH,IAAII,aAAa;IAC7B,MAAMC,MAAMF,IAAIG,OAAO,CAACL,UAAU;IAClC,IAAI,CAACI,KAAK;QACRE,QAAQC,KAAK,CAAC,CAAC,gBAAgB,EAAEP,UAAU,CAAC,CAAC;QAC7CM,QAAQC,KAAK,CAAC,CAAC,eAAe,EAAEC,OAAOC,IAAI,CAACP,IAAIG,OAAO,EAAEK,IAAI,GAAGC,IAAI,CAAC,OAAO;QAC5EC,QAAQC,IAAI,CAAC;IACf;IACAhB,OAAOK,KAAKE,KAAKH,QAAQF,IAAIe,MAAM,EAAE,CAAC,OAAO,EAAEd,UAAU,CAAC,CAAC;AAC7D"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { renderPeek } from '../output.js';
|
|
2
2
|
import { peek } from '../verbs.js';
|
|
3
|
-
import {
|
|
3
|
+
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
|
-
|
|
7
|
+
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
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/query.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/query.ts"],"sourcesContent":["import { runSql } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst query: Command = (ctx) => {\n const [sql, ...params] = ctx.rest;\n if (!sql) ctx.usageError(`usage: ${ctx.name} query \"<sql>\" [params...]`);\n runSql(ctx.resolveConfig(), sql, params, ctx.format, 'ad-hoc query');\n};\nexport default query;\n"],"names":["runSql","query","ctx","sql","params","rest","usageError","name","resolveConfig","format"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AAGrC,MAAMC,QAAiB,CAACC;IACtB,MAAM,CAACC,KAAK,GAAGC,OAAO,GAAGF,IAAIG,IAAI;IACjC,IAAI,CAACF,KAAKD,IAAII,UAAU,CAAC,CAAC,OAAO,EAAEJ,IAAIK,IAAI,CAAC,0BAA0B,CAAC;IACvEP,OAAOE,IAAIM,aAAa,IAAIL,KAAKC,QAAQF,IAAIO,MAAM,EAAE;AACvD;AACA,eAAeR,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/rebuild.ts"],"sourcesContent":["import { docCount, rebuild } from '../db.ts';\nimport
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/rebuild.ts"],"sourcesContent":["import { docCount, rebuild } from '../db.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst rebuildCmd: Command = (ctx) => {\n const result = rebuild(ctx.resolveConfig());\n printWarnings(result.warnings);\n console.log(`rebuilt: ${docCount(result.db)} docs`);\n result.db.close();\n};\nexport default rebuildCmd;\n"],"names":["docCount","rebuild","printWarnings","rebuildCmd","ctx","result","resolveConfig","warnings","console","log","db","close"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,OAAO,QAAQ,WAAW;AAC7C,SAASC,aAAa,QAAQ,cAAc;AAG5C,MAAMC,aAAsB,CAACC;IAC3B,MAAMC,SAASJ,QAAQG,IAAIE,aAAa;IACxCJ,cAAcG,OAAOE,QAAQ;IAC7BC,QAAQC,GAAG,CAAC,CAAC,SAAS,EAAET,SAASK,OAAOK,EAAE,EAAE,KAAK,CAAC;IAClDL,OAAOK,EAAE,CAACC,KAAK;AACjB;AACA,eAAeR,WAAW"}
|
|
@@ -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
|
|
5
|
+
export declare function withDb(ctx: Ctx, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void): void;
|
|
6
6
|
export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { open } from '../db.js';
|
|
2
2
|
import { printRows } from '../output.js';
|
|
3
|
-
// Shared open-query-close envelope for commands that touch the
|
|
3
|
+
// Shared open-query-close envelope for commands that touch the tree.
|
|
4
4
|
export function printWarnings(warnings) {
|
|
5
5
|
for (const w of warnings)console.warn(w);
|
|
6
6
|
}
|
|
7
|
-
export function
|
|
7
|
+
export function withDb(ctx, fn) {
|
|
8
8
|
const cfg = ctx.resolveConfig();
|
|
9
9
|
const { db, warnings } = open(cfg);
|
|
10
10
|
printWarnings(warnings);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/shared.ts"],"sourcesContent":["import type { ResolvedConfig } from '../config.ts';\nimport type { OpenResult } from '../db.ts';\nimport { open } from '../db.ts';\nimport type { Row } from '../output.ts';\nimport { printRows } from '../output.ts';\nimport type { Ctx } from './types.ts';\n\n// Shared open-query-close envelope for commands that touch the tree.\n\nexport function printWarnings(warnings: string[]): void {\n for (const w of warnings) console.warn(w);\n}\n\nexport function withDb(ctx: Ctx, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void): void {\n const cfg = ctx.resolveConfig();\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n try {\n fn(db, cfg);\n } finally {\n db.close();\n }\n}\n\n// An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.\nexport function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void {\n const placeholderCount = (sql.match(/\\?/g) ?? []).length;\n if (params.length !== placeholderCount) {\n console.error(`${label} expects ${placeholderCount} parameter(s), got ${params.length}`);\n process.exit(2);\n }\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n printRows(db.prepare(sql).all(...params) as Row[], format);\n db.close();\n}\n"],"names":["open","printRows","printWarnings","warnings","w","console","warn","withDb","ctx","fn","cfg","resolveConfig","db","close","runSql","sql","params","format","label","placeholderCount","match","length","error","process","exit","prepare","all"],"mappings":"AAEA,SAASA,IAAI,QAAQ,WAAW;AAEhC,SAASC,SAAS,QAAQ,eAAe;AAGzC,qEAAqE;AAErE,OAAO,SAASC,cAAcC,QAAkB;IAC9C,KAAK,MAAMC,KAAKD,SAAUE,QAAQC,IAAI,CAACF;AACzC;AAEA,OAAO,SAASG,OAAOC,GAAQ,EAAEC,EAAuD;IACtF,MAAMC,MAAMF,IAAIG,aAAa;IAC7B,MAAM,EAAEC,EAAE,EAAET,QAAQ,EAAE,GAAGH,KAAKU;IAC9BR,cAAcC;IACd,IAAI;QACFM,GAAGG,IAAIF;IACT,SAAU;QACRE,GAAGC,KAAK;IACV;AACF;AAEA,sFAAsF;AACtF,OAAO,SAASC,OAAOJ,GAAmB,EAAEK,GAAW,EAAEC,MAAgB,EAAEC,MAAwB,EAAEC,KAAa;QACtFH;IAA1B,MAAMI,mBAAmB,EAACJ,aAAAA,IAAIK,KAAK,CAAC,oBAAVL,wBAAAA,aAAoB,EAAE,EAAEM,MAAM;IACxD,IAAIL,OAAOK,MAAM,KAAKF,kBAAkB;QACtCd,QAAQiB,KAAK,CAAC,GAAGJ,MAAM,SAAS,EAAEC,iBAAiB,mBAAmB,EAAEH,OAAOK,MAAM,EAAE;QACvFE,QAAQC,IAAI,CAAC;IACf;IACA,MAAM,EAAEZ,EAAE,EAAET,QAAQ,EAAE,GAAGH,KAAKU;IAC9BR,cAAcC;IACdF,UAAUW,GAAGa,OAAO,CAACV,KAAKW,GAAG,IAAIV,SAAkBC;IACnDL,GAAGC,KAAK;AACV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/status.ts"],"sourcesContent":["import { docCount, getMeta, open } from '../db.ts';\nimport
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/status.ts"],"sourcesContent":["import { docCount, getMeta, open } from '../db.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst status: Command = (ctx) => {\n const { db, dbPath, warnings } = open(ctx.resolveConfig());\n printWarnings(warnings);\n console.log(`db: ${dbPath}`);\n console.log(`docs: ${docCount(db)}`);\n const heartbeat = getMeta(db, 'watch_heartbeat');\n if (heartbeat) console.log(`watcher: last heartbeat ${Math.round((Date.now() - Date.parse(heartbeat)) / 1000)}s ago`);\n else console.log('watcher: no watcher');\n db.close();\n};\nexport default status;\n"],"names":["docCount","getMeta","open","printWarnings","status","ctx","db","dbPath","warnings","resolveConfig","console","log","heartbeat","Math","round","Date","now","parse","close"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,OAAO,EAAEC,IAAI,QAAQ,WAAW;AACnD,SAASC,aAAa,QAAQ,cAAc;AAG5C,MAAMC,SAAkB,CAACC;IACvB,MAAM,EAAEC,EAAE,EAAEC,MAAM,EAAEC,QAAQ,EAAE,GAAGN,KAAKG,IAAII,aAAa;IACvDN,cAAcK;IACdE,QAAQC,GAAG,CAAC,CAAC,IAAI,EAAEJ,QAAQ;IAC3BG,QAAQC,GAAG,CAAC,CAAC,MAAM,EAAEX,SAASM,KAAK;IACnC,MAAMM,YAAYX,QAAQK,IAAI;IAC9B,IAAIM,WAAWF,QAAQC,GAAG,CAAC,CAAC,wBAAwB,EAAEE,KAAKC,KAAK,CAAC,AAACC,CAAAA,KAAKC,GAAG,KAAKD,KAAKE,KAAK,CAACL,UAAS,IAAK,MAAM,KAAK,CAAC;SAC/GF,QAAQC,GAAG,CAAC;IACjBL,GAAGY,KAAK;AACV;AACA,eAAed,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/watch.ts"],"sourcesContent":["import type { WatchEvent } from '../watch.ts';\nimport { runWatch } from '../watch.ts';\nimport
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/watch.ts"],"sourcesContent":["import type { WatchEvent } from '../watch.ts';\nimport { runWatch } from '../watch.ts';\nimport { printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst watch: Command = async (ctx) => {\n await runWatch(ctx.resolveConfig(), {\n force: ctx.values.force,\n onEvent: (event: WatchEvent) => {\n if (event.type === 'started') {\n console.log(`${ctx.name} watch: watching ${event.baseDir}`);\n console.log(`${ctx.name} watch: db ${event.dbPath}`);\n } else if (event.type === 'reconciled') {\n printWarnings(event.warnings);\n if (event.parsed > 0) console.log(`${ctx.name} watch: reconciled, ${event.parsed} file(s) reparsed (${event.total} total)`);\n } else {\n console.error(`${ctx.name} watch: reconcile error: ${event.message}`);\n }\n },\n });\n};\nexport default watch;\n"],"names":["runWatch","printWarnings","watch","ctx","resolveConfig","force","values","onEvent","event","type","console","log","name","baseDir","dbPath","warnings","parsed","total","error","message"],"mappings":"AACA,SAASA,QAAQ,QAAQ,cAAc;AACvC,SAASC,aAAa,QAAQ,cAAc;AAG5C,MAAMC,QAAiB,OAAOC;IAC5B,MAAMH,SAASG,IAAIC,aAAa,IAAI;QAClCC,OAAOF,IAAIG,MAAM,CAACD,KAAK;QACvBE,SAAS,CAACC;YACR,IAAIA,MAAMC,IAAI,KAAK,WAAW;gBAC5BC,QAAQC,GAAG,CAAC,GAAGR,IAAIS,IAAI,CAAC,iBAAiB,EAAEJ,MAAMK,OAAO,EAAE;gBAC1DH,QAAQC,GAAG,CAAC,GAAGR,IAAIS,IAAI,CAAC,WAAW,EAAEJ,MAAMM,MAAM,EAAE;YACrD,OAAO,IAAIN,MAAMC,IAAI,KAAK,cAAc;gBACtCR,cAAcO,MAAMO,QAAQ;gBAC5B,IAAIP,MAAMQ,MAAM,GAAG,GAAGN,QAAQC,GAAG,CAAC,GAAGR,IAAIS,IAAI,CAAC,oBAAoB,EAAEJ,MAAMQ,MAAM,CAAC,mBAAmB,EAAER,MAAMS,KAAK,CAAC,OAAO,CAAC;YAC5H,OAAO;gBACLP,QAAQQ,KAAK,CAAC,GAAGf,IAAIS,IAAI,CAAC,yBAAyB,EAAEJ,MAAMW,OAAO,EAAE;YACtE;QACF;IACF;AACF;AACA,eAAejB,MAAM"}
|
package/dist/esm/config.js
CHANGED
|
@@ -82,8 +82,28 @@ export function findConfigPath(startDir) {
|
|
|
82
82
|
dir = parent;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
// Shape check for hand-edited files: a typo'd config fails with a named error, not a
|
|
86
|
+
// TypeError from whatever code touched the missing field first. `queries` is optional
|
|
87
|
+
// on disk (absent = none); `scan.include` has no usable default.
|
|
88
|
+
function validateConfig(parsed, configPath) {
|
|
89
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
90
|
+
throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);
|
|
91
|
+
}
|
|
92
|
+
const cfg = parsed;
|
|
93
|
+
const scan = cfg.scan;
|
|
94
|
+
if (!scan || !Array.isArray(scan.include) || scan.include.length === 0 || !scan.include.every((g)=>typeof g === 'string')) {
|
|
95
|
+
throw new SenseError('CONFIG_INVALID', `${configPath}: scan.include must be a non-empty array of glob strings`);
|
|
96
|
+
}
|
|
97
|
+
if (cfg.queries === undefined) cfg.queries = {};
|
|
98
|
+
if (typeof cfg.queries !== 'object' || cfg.queries === null || Array.isArray(cfg.queries) || !Object.values(cfg.queries).every((q)=>typeof q === 'string')) {
|
|
99
|
+
throw new SenseError('CONFIG_INVALID', `${configPath}: queries must be an object of name -> SQL string`);
|
|
100
|
+
}
|
|
101
|
+
if (cfg.features !== undefined && (typeof cfg.features !== 'object' || cfg.features === null || Array.isArray(cfg.features) || !Object.values(cfg.features).every((v)=>typeof v === 'boolean'))) {
|
|
102
|
+
throw new SenseError('CONFIG_INVALID', `${configPath}: features must be an object of name -> boolean`);
|
|
103
|
+
}
|
|
104
|
+
return cfg;
|
|
105
|
+
}
|
|
85
106
|
export function loadConfig(explicitPath) {
|
|
86
|
-
var _cfg_version;
|
|
87
107
|
let configPath;
|
|
88
108
|
if (explicitPath) {
|
|
89
109
|
configPath = resolve(process.cwd(), explicitPath);
|
|
@@ -96,11 +116,14 @@ export function loadConfig(explicitPath) {
|
|
|
96
116
|
configPath = found;
|
|
97
117
|
}
|
|
98
118
|
const raw = readFileSync(configPath, 'utf8');
|
|
99
|
-
|
|
100
|
-
|
|
119
|
+
const parsed = JSON.parse(raw);
|
|
120
|
+
// Version gate before shape validation: a config written by a newer sense should fail
|
|
121
|
+
// with "requires a newer sense", not with shape errors its own version may not have.
|
|
122
|
+
const version = typeof parsed === 'object' && parsed !== null && typeof parsed.version === 'number' ? parsed.version : 1;
|
|
101
123
|
if (version > SUPPORTED_CONFIG_VERSION) {
|
|
102
124
|
throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `config version ${version} requires a newer sense`);
|
|
103
125
|
}
|
|
126
|
+
let cfg = validateConfig(parsed, configPath);
|
|
104
127
|
let migratedFrom;
|
|
105
128
|
if (version < SUPPORTED_CONFIG_VERSION) {
|
|
106
129
|
const result = migrateConfig(cfg);
|