sensemaking 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/bin/cli.js +5 -0
  4. package/dist/cjs/cli.d.cts +1 -0
  5. package/dist/cjs/cli.d.ts +1 -0
  6. package/dist/cjs/cli.js +422 -0
  7. package/dist/cjs/cli.js.map +1 -0
  8. package/dist/cjs/config.d.cts +18 -0
  9. package/dist/cjs/config.d.ts +18 -0
  10. package/dist/cjs/config.js +147 -0
  11. package/dist/cjs/config.js.map +1 -0
  12. package/dist/cjs/db.d.cts +20 -0
  13. package/dist/cjs/db.d.ts +20 -0
  14. package/dist/cjs/db.js +326 -0
  15. package/dist/cjs/db.js.map +1 -0
  16. package/dist/cjs/errors.d.cts +5 -0
  17. package/dist/cjs/errors.d.ts +5 -0
  18. package/dist/cjs/errors.js +134 -0
  19. package/dist/cjs/errors.js.map +1 -0
  20. package/dist/cjs/index.d.cts +12 -0
  21. package/dist/cjs/index.d.ts +12 -0
  22. package/dist/cjs/index.js +76 -0
  23. package/dist/cjs/index.js.map +1 -0
  24. package/dist/cjs/output.d.cts +2 -0
  25. package/dist/cjs/output.d.ts +2 -0
  26. package/dist/cjs/output.js +90 -0
  27. package/dist/cjs/output.js.map +1 -0
  28. package/dist/cjs/package.json +1 -0
  29. package/dist/cjs/scan.d.cts +18 -0
  30. package/dist/cjs/scan.d.ts +18 -0
  31. package/dist/cjs/scan.js +113 -0
  32. package/dist/cjs/scan.js.map +1 -0
  33. package/dist/cjs/watch.d.cts +19 -0
  34. package/dist/cjs/watch.d.ts +19 -0
  35. package/dist/cjs/watch.js +237 -0
  36. package/dist/cjs/watch.js.map +1 -0
  37. package/dist/esm/cli.d.ts +1 -0
  38. package/dist/esm/cli.js +171 -0
  39. package/dist/esm/cli.js.map +1 -0
  40. package/dist/esm/config.d.ts +18 -0
  41. package/dist/esm/config.js +78 -0
  42. package/dist/esm/config.js.map +1 -0
  43. package/dist/esm/db.d.ts +20 -0
  44. package/dist/esm/db.js +176 -0
  45. package/dist/esm/db.js.map +1 -0
  46. package/dist/esm/errors.d.ts +5 -0
  47. package/dist/esm/errors.js +10 -0
  48. package/dist/esm/errors.js.map +1 -0
  49. package/dist/esm/index.d.ts +12 -0
  50. package/dist/esm/index.js +9 -0
  51. package/dist/esm/index.js.map +1 -0
  52. package/dist/esm/output.d.ts +2 -0
  53. package/dist/esm/output.js +25 -0
  54. package/dist/esm/output.js.map +1 -0
  55. package/dist/esm/package.json +1 -0
  56. package/dist/esm/scan.d.ts +18 -0
  57. package/dist/esm/scan.js +69 -0
  58. package/dist/esm/scan.js.map +1 -0
  59. package/dist/esm/watch.d.ts +19 -0
  60. package/dist/esm/watch.js +93 -0
  61. package/dist/esm/watch.js.map +1 -0
  62. package/package.json +63 -0
  63. package/schema.json +38 -0
  64. package/skills/sense/SKILL.md +95 -0
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get CONFIG_FILENAME () {
13
+ return CONFIG_FILENAME;
14
+ },
15
+ get STATE_DIR () {
16
+ return STATE_DIR;
17
+ },
18
+ get SUPPORTED_CONFIG_VERSION () {
19
+ return SUPPORTED_CONFIG_VERSION;
20
+ },
21
+ get findConfigPath () {
22
+ return findConfigPath;
23
+ },
24
+ get initConfig () {
25
+ return initConfig;
26
+ },
27
+ get loadConfig () {
28
+ return loadConfig;
29
+ }
30
+ });
31
+ var _nodefs = require("node:fs");
32
+ var _nodepath = require("node:path");
33
+ var _errorsts = require("./errors.js");
34
+ function _define_property(obj, key, value) {
35
+ if (key in obj) {
36
+ Object.defineProperty(obj, key, {
37
+ value: value,
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true
41
+ });
42
+ } else {
43
+ obj[key] = value;
44
+ }
45
+ return obj;
46
+ }
47
+ function _object_spread(target) {
48
+ for(var i = 1; i < arguments.length; i++){
49
+ var source = arguments[i] != null ? arguments[i] : {};
50
+ var ownKeys = Object.keys(source);
51
+ if (typeof Object.getOwnPropertySymbols === "function") {
52
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
53
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
54
+ }));
55
+ }
56
+ ownKeys.forEach(function(key) {
57
+ _define_property(target, key, source[key]);
58
+ });
59
+ }
60
+ return target;
61
+ }
62
+ function ownKeys(object, enumerableOnly) {
63
+ var keys = Object.keys(object);
64
+ if (Object.getOwnPropertySymbols) {
65
+ var symbols = Object.getOwnPropertySymbols(object);
66
+ if (enumerableOnly) {
67
+ symbols = symbols.filter(function(sym) {
68
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
69
+ });
70
+ }
71
+ keys.push.apply(keys, symbols);
72
+ }
73
+ return keys;
74
+ }
75
+ function _object_spread_props(target, source) {
76
+ source = source != null ? source : {};
77
+ if (Object.getOwnPropertyDescriptors) {
78
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
79
+ } else {
80
+ ownKeys(Object(source)).forEach(function(key) {
81
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
82
+ });
83
+ }
84
+ return target;
85
+ }
86
+ var CONFIG_FILENAME = 'sense.config.json';
87
+ var STATE_DIR = '.sense';
88
+ var SUPPORTED_CONFIG_VERSION = 1;
89
+ function initConfig(dir) {
90
+ var configPath = (0, _nodepath.join)(dir, CONFIG_FILENAME);
91
+ if ((0, _nodefs.existsSync)(configPath)) {
92
+ throw new _errorsts.SenseError('CONFIG_EXISTS', "".concat(CONFIG_FILENAME, " already exists in ").concat(dir));
93
+ }
94
+ var starter = {
95
+ $schema: 'https://unpkg.com/sensemaking/schema.json',
96
+ version: 1,
97
+ scan: {
98
+ include: [
99
+ '**/*.md'
100
+ ]
101
+ },
102
+ queries: {
103
+ all: 'SELECT path, title FROM docs ORDER BY path',
104
+ 'by-tag': 'SELECT path, title FROM docs WHERE has(tags, ?) ORDER BY path'
105
+ }
106
+ };
107
+ (0, _nodefs.writeFileSync)(configPath, "".concat(JSON.stringify(starter, null, 2), "\n"));
108
+ return configPath;
109
+ }
110
+ function findConfigPath(startDir) {
111
+ var dir = (0, _nodepath.resolve)(startDir);
112
+ for(;;){
113
+ var candidate = (0, _nodepath.join)(dir, CONFIG_FILENAME);
114
+ if ((0, _nodefs.existsSync)(candidate)) return candidate;
115
+ var parent = (0, _nodepath.dirname)(dir);
116
+ if (parent === dir) return null;
117
+ dir = parent;
118
+ }
119
+ }
120
+ function loadConfig(explicitPath) {
121
+ var _cfg_version;
122
+ var configPath;
123
+ if (explicitPath) {
124
+ configPath = (0, _nodepath.resolve)(process.cwd(), explicitPath);
125
+ if (!(0, _nodefs.existsSync)(configPath)) throw new _errorsts.SenseError('CONFIG_NOT_FOUND', "config not found: ".concat(configPath));
126
+ } else {
127
+ var found = findConfigPath(process.cwd());
128
+ if (!found) {
129
+ throw new _errorsts.SenseError('CONFIG_NOT_FOUND', "could not find ".concat(CONFIG_FILENAME, " in ").concat(process.cwd(), " or any parent directory"));
130
+ }
131
+ configPath = found;
132
+ }
133
+ var raw = (0, _nodefs.readFileSync)(configPath, 'utf8');
134
+ var cfg = JSON.parse(raw);
135
+ // Missing `version` is treated as 1. A version newer than this build
136
+ // supports is a hard error -- misinterpreting a future config format
137
+ // silently would be worse than refusing to run.
138
+ var version = (_cfg_version = cfg.version) !== null && _cfg_version !== void 0 ? _cfg_version : 1;
139
+ if (version > SUPPORTED_CONFIG_VERSION) {
140
+ throw new _errorsts.SenseError('CONFIG_VERSION_UNSUPPORTED', "config version ".concat(version, " requires a newer sense"));
141
+ }
142
+ return _object_spread_props(_object_spread({}, cfg), {
143
+ baseDir: (0, _nodepath.dirname)(configPath),
144
+ configPath: configPath
145
+ });
146
+ }
147
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { SenseError } from './errors.ts';\n\n// All config concerns live here: the file name, discovery, parsing, and\n// version gating. db.ts consumes only the result -- it does no discovery\n// and no version logic of its own.\n\nexport const CONFIG_FILENAME = 'sense.config.json';\nexport const STATE_DIR = '.sense';\n\n// The highest `sense.config.json` `version` this build understands. Bumped\n// only when the config *format* changes in a breaking way -- unrelated to\n// the package's own semver.\nexport const SUPPORTED_CONFIG_VERSION = 1;\n\n// sense.config.json's on-disk shape.\nexport interface Config {\n // Editor-only pointer to schema.json; never read by sense.\n $schema?: string;\n // Config format version. Omitted = 1.\n version?: number;\n scan: { include: string[] };\n queries: Record<string, string>;\n}\n\n// A Config resolved to where it lives on disk (or, for tests, a baseDir\n// supplied directly with no backing file). `scan.include` globs and the\n// `.sense/` state dir both resolve relative to `baseDir`, never process cwd.\nexport interface ResolvedConfig extends Config {\n baseDir: string;\n configPath: string | null;\n}\n\n// `sense init`: write a starter config into `dir` — the example doubles as\n// the documentation of the format. Refuses to overwrite an existing one.\nexport function initConfig(dir: string): string {\n const configPath = join(dir, CONFIG_FILENAME);\n if (existsSync(configPath)) {\n throw new SenseError('CONFIG_EXISTS', `${CONFIG_FILENAME} already exists in ${dir}`);\n }\n const starter: Config = {\n $schema: 'https://unpkg.com/sensemaking/schema.json',\n version: 1,\n scan: { include: ['**/*.md'] },\n queries: {\n all: 'SELECT path, title FROM docs ORDER BY path',\n 'by-tag': 'SELECT path, title FROM docs WHERE has(tags, ?) ORDER BY path',\n },\n };\n writeFileSync(configPath, `${JSON.stringify(starter, null, 2)}\\n`);\n return configPath;\n}\n\n// Find sense.config.json by walking up from startDir, git-style.\nexport function findConfigPath(startDir: string): string | null {\n let dir = resolve(startDir);\n for (;;) {\n const candidate = join(dir, CONFIG_FILENAME);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n// Resolve + load sense.config.json: `explicitPath` bypasses walk-up\n// discovery (as `--config` does on the CLI); otherwise discovery starts at\n// process cwd. Throws on a missing config, invalid JSON, or a `version`\n// newer than this build supports -- callers surface the message and exit 1.\nexport function loadConfig(explicitPath?: string): ResolvedConfig {\n let configPath: string;\n if (explicitPath) {\n configPath = resolve(process.cwd(), explicitPath);\n if (!existsSync(configPath)) throw new SenseError('CONFIG_NOT_FOUND', `config not found: ${configPath}`);\n } else {\n const found = findConfigPath(process.cwd());\n if (!found) {\n throw new SenseError('CONFIG_NOT_FOUND', `could not find ${CONFIG_FILENAME} in ${process.cwd()} or any parent directory`);\n }\n configPath = found;\n }\n\n const raw = readFileSync(configPath, 'utf8');\n const cfg = JSON.parse(raw) as Config;\n\n // Missing `version` is treated as 1. A version newer than this build\n // supports is a hard error -- misinterpreting a future config format\n // silently would be worse than refusing to run.\n const version = cfg.version ?? 1;\n if (version > SUPPORTED_CONFIG_VERSION) {\n throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `config version ${version} requires a newer sense`);\n }\n\n return { ...cfg, baseDir: dirname(configPath), configPath };\n}\n"],"names":["CONFIG_FILENAME","STATE_DIR","SUPPORTED_CONFIG_VERSION","findConfigPath","initConfig","loadConfig","dir","configPath","join","existsSync","SenseError","starter","$schema","version","scan","include","queries","all","writeFileSync","JSON","stringify","startDir","resolve","candidate","parent","dirname","explicitPath","cfg","process","cwd","found","raw","readFileSync","parse","baseDir"],"mappings":";;;;;;;;;;;QAQaA;eAAAA;;QACAC;eAAAA;;QAKAC;eAAAA;;QAyCGC;eAAAA;;QAnBAC;eAAAA;;QAkCAC;eAAAA;;;sBAtEwC;wBACjB;wBACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMpB,IAAML,kBAAkB;AACxB,IAAMC,YAAY;AAKlB,IAAMC,2BAA2B;AAsBjC,SAASE,WAAWE,GAAW;IACpC,IAAMC,aAAaC,IAAAA,cAAI,EAACF,KAAKN;IAC7B,IAAIS,IAAAA,kBAAU,EAACF,aAAa;QAC1B,MAAM,IAAIG,oBAAU,CAAC,iBAAiB,AAAC,GAAuCJ,OAArCN,iBAAgB,uBAAyB,OAAJM;IAChF;IACA,IAAMK,UAAkB;QACtBC,SAAS;QACTC,SAAS;QACTC,MAAM;YAAEC,SAAS;gBAAC;aAAU;QAAC;QAC7BC,SAAS;YACPC,KAAK;YACL,UAAU;QACZ;IACF;IACAC,IAAAA,qBAAa,EAACX,YAAY,AAAC,GAAmC,OAAjCY,KAAKC,SAAS,CAACT,SAAS,MAAM,IAAG;IAC9D,OAAOJ;AACT;AAGO,SAASJ,eAAekB,QAAgB;IAC7C,IAAIf,MAAMgB,IAAAA,iBAAO,EAACD;IAClB,OAAS;QACP,IAAME,YAAYf,IAAAA,cAAI,EAACF,KAAKN;QAC5B,IAAIS,IAAAA,kBAAU,EAACc,YAAY,OAAOA;QAClC,IAAMC,SAASC,IAAAA,iBAAO,EAACnB;QACvB,IAAIkB,WAAWlB,KAAK,OAAO;QAC3BA,MAAMkB;IACR;AACF;AAMO,SAASnB,WAAWqB,YAAqB;QAmB9BC;IAlBhB,IAAIpB;IACJ,IAAImB,cAAc;QAChBnB,aAAae,IAAAA,iBAAO,EAACM,QAAQC,GAAG,IAAIH;QACpC,IAAI,CAACjB,IAAAA,kBAAU,EAACF,aAAa,MAAM,IAAIG,oBAAU,CAAC,oBAAoB,AAAC,qBAA+B,OAAXH;IAC7F,OAAO;QACL,IAAMuB,QAAQ3B,eAAeyB,QAAQC,GAAG;QACxC,IAAI,CAACC,OAAO;YACV,MAAM,IAAIpB,oBAAU,CAAC,oBAAoB,AAAC,kBAAuCkB,OAAtB5B,iBAAgB,QAAoB,OAAd4B,QAAQC,GAAG,IAAG;QACjG;QACAtB,aAAauB;IACf;IAEA,IAAMC,MAAMC,IAAAA,oBAAY,EAACzB,YAAY;IACrC,IAAMoB,MAAMR,KAAKc,KAAK,CAACF;IAEvB,qEAAqE;IACrE,qEAAqE;IACrE,gDAAgD;IAChD,IAAMlB,WAAUc,eAAAA,IAAId,OAAO,cAAXc,0BAAAA,eAAe;IAC/B,IAAId,UAAUX,0BAA0B;QACtC,MAAM,IAAIQ,oBAAU,CAAC,8BAA8B,AAAC,kBAAyB,OAARG,SAAQ;IAC/E;IAEA,OAAO,wCAAKc;QAAKO,SAAST,IAAAA,iBAAO,EAAClB;QAAaA,YAAAA;;AACjD"}
@@ -0,0 +1,20 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import type { Config, ResolvedConfig } from './config.js';
3
+ export declare const DB_FILENAME = "cache.db";
4
+ export declare const SCHEMA_VERSION = "1";
5
+ export interface OpenResult {
6
+ db: DatabaseSync;
7
+ cfg: ResolvedConfig;
8
+ dbPath: string;
9
+ parsed: number;
10
+ warnings: string[];
11
+ }
12
+ export declare function getMeta(db: DatabaseSync, key: string): string | null;
13
+ export declare function setMeta(db: DatabaseSync, key: string, value: string | null): void;
14
+ export declare function docCount(db: DatabaseSync): number;
15
+ export declare function reconcile(db: DatabaseSync, cfg: Config, baseDir: string): {
16
+ parsed: number;
17
+ warnings: string[];
18
+ };
19
+ export declare function open(cfg: ResolvedConfig): OpenResult;
20
+ export declare function rebuild(cfg: ResolvedConfig): OpenResult;
@@ -0,0 +1,20 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import type { Config, ResolvedConfig } from './config.js';
3
+ export declare const DB_FILENAME = "cache.db";
4
+ export declare const SCHEMA_VERSION = "1";
5
+ export interface OpenResult {
6
+ db: DatabaseSync;
7
+ cfg: ResolvedConfig;
8
+ dbPath: string;
9
+ parsed: number;
10
+ warnings: string[];
11
+ }
12
+ export declare function getMeta(db: DatabaseSync, key: string): string | null;
13
+ export declare function setMeta(db: DatabaseSync, key: string, value: string | null): void;
14
+ export declare function docCount(db: DatabaseSync): number;
15
+ export declare function reconcile(db: DatabaseSync, cfg: Config, baseDir: string): {
16
+ parsed: number;
17
+ warnings: string[];
18
+ };
19
+ export declare function open(cfg: ResolvedConfig): OpenResult;
20
+ export declare function rebuild(cfg: ResolvedConfig): OpenResult;
package/dist/cjs/db.js ADDED
@@ -0,0 +1,326 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get DB_FILENAME () {
13
+ return DB_FILENAME;
14
+ },
15
+ get SCHEMA_VERSION () {
16
+ return SCHEMA_VERSION;
17
+ },
18
+ get docCount () {
19
+ return docCount;
20
+ },
21
+ get getMeta () {
22
+ return getMeta;
23
+ },
24
+ get open () {
25
+ return open;
26
+ },
27
+ get rebuild () {
28
+ return rebuild;
29
+ },
30
+ get reconcile () {
31
+ return reconcile;
32
+ },
33
+ get setMeta () {
34
+ return setMeta;
35
+ }
36
+ });
37
+ var _nodefs = require("node:fs");
38
+ var _nodepath = require("node:path");
39
+ var _nodesqlite = require("node:sqlite");
40
+ var _configts = require("./config.js");
41
+ var _scants = require("./scan.js");
42
+ function _array_like_to_array(arr, len) {
43
+ if (len == null || len > arr.length) len = arr.length;
44
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
45
+ return arr2;
46
+ }
47
+ function _array_without_holes(arr) {
48
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
49
+ }
50
+ function _iterable_to_array(iter) {
51
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
52
+ }
53
+ function _non_iterable_spread() {
54
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
55
+ }
56
+ function _to_consumable_array(arr) {
57
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
58
+ }
59
+ function _unsupported_iterable_to_array(o, minLen) {
60
+ if (!o) return;
61
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
62
+ var n = Object.prototype.toString.call(o).slice(8, -1);
63
+ if (n === "Object" && o.constructor) n = o.constructor.name;
64
+ if (n === "Map" || n === "Set") return Array.from(n);
65
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
66
+ }
67
+ var DB_FILENAME = 'cache.db';
68
+ var SCHEMA_VERSION = '1';
69
+ // Quote a SQL identifier, escaping embedded double quotes so an unusual
70
+ // frontmatter key (however unlikely) can't break out of the identifier.
71
+ function quoteIdent(name) {
72
+ return '"'.concat(name.split('"').join('""'), '"');
73
+ }
74
+ // The one custom SQL function in the whole tool: has(field, value).
75
+ // - JSON-array field (stored as JSON text, e.g. `["a","b"]`) -> membership
76
+ // - string field -> substring
77
+ // - NULL -> false
78
+ function registerFunctions(db) {
79
+ db.function('has', {
80
+ deterministic: true,
81
+ varargs: false
82
+ }, function(field, value) {
83
+ if (field === null || field === undefined) return 0;
84
+ var needle = String(value);
85
+ if (typeof field === 'string') {
86
+ // Try JSON array first (arrays are stored as JSON text).
87
+ if (field.startsWith('[')) {
88
+ try {
89
+ var parsed = JSON.parse(field);
90
+ if (Array.isArray(parsed)) {
91
+ return parsed.some(function(item) {
92
+ return String(item) === needle;
93
+ }) ? 1 : 0;
94
+ }
95
+ } catch (unused) {
96
+ // fall through to substring match
97
+ }
98
+ }
99
+ return field.includes(needle) ? 1 : 0;
100
+ }
101
+ // Numbers, etc: coerce to string and substring-match.
102
+ return String(field).includes(needle) ? 1 : 0;
103
+ });
104
+ }
105
+ function getColumns(db) {
106
+ var rows = db.prepare('PRAGMA table_info(docs)').all();
107
+ return new Set(rows.map(function(r) {
108
+ return r.name;
109
+ }));
110
+ }
111
+ function ensureSchema(db) {
112
+ db.exec('CREATE TABLE IF NOT EXISTS docs ("path" TEXT PRIMARY KEY, "_mtime" REAL, "_size" INTEGER)');
113
+ db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');
114
+ if (getMeta(db, 'schema_version') === null) setMeta(db, 'schema_version', SCHEMA_VERSION);
115
+ }
116
+ function getMeta(db, key) {
117
+ var row = db.prepare('SELECT value FROM meta WHERE key = ?').get(key);
118
+ return row ? row.value : null;
119
+ }
120
+ function setMeta(db, key, value) {
121
+ if (value === null) {
122
+ db.prepare('DELETE FROM meta WHERE key = ?').run(key);
123
+ return;
124
+ }
125
+ db.prepare('INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value').run(key, value);
126
+ }
127
+ function docCount(db) {
128
+ var row = db.prepare('SELECT COUNT(*) AS n FROM docs').get();
129
+ return row.n;
130
+ }
131
+ function reconcile(db, cfg, baseDir) {
132
+ var files = (0, _scants.listFiles)(cfg, baseDir);
133
+ var currentSet = new Set(files.map(function(f) {
134
+ return f.relPath;
135
+ }));
136
+ var existingRows = db.prepare('SELECT "path", "_mtime", "_size" FROM docs').all();
137
+ var existing = new Map(existingRows.map(function(r) {
138
+ return [
139
+ r.path,
140
+ r
141
+ ];
142
+ }));
143
+ var vanished = existingRows.filter(function(r) {
144
+ return !currentSet.has(r.path);
145
+ }).map(function(r) {
146
+ return r.path;
147
+ });
148
+ var toReparse = files.filter(function(f) {
149
+ var row = existing.get(f.relPath);
150
+ return !row || row._mtime !== f.mtimeMs || row._size !== f.size;
151
+ });
152
+ if (vanished.length === 0 && toReparse.length === 0) return {
153
+ parsed: 0,
154
+ warnings: []
155
+ };
156
+ var seenColumns = getColumns(db);
157
+ var newColumns = [];
158
+ var parsedDocs = [];
159
+ var warnings = [];
160
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
161
+ try {
162
+ for(var _iterator = toReparse[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
163
+ var file = _step.value;
164
+ var _warnings;
165
+ var _parseFile = (0, _scants.parseFile)(file), doc = _parseFile.doc, fileWarnings = _parseFile.warnings;
166
+ (_warnings = warnings).push.apply(_warnings, _to_consumable_array(fileWarnings));
167
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
168
+ try {
169
+ for(var _iterator1 = Object.keys(doc.data)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
170
+ var key = _step1.value;
171
+ if (!seenColumns.has(key)) {
172
+ seenColumns.add(key);
173
+ newColumns.push(key);
174
+ }
175
+ }
176
+ } catch (err) {
177
+ _didIteratorError1 = true;
178
+ _iteratorError1 = err;
179
+ } finally{
180
+ try {
181
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
182
+ _iterator1.return();
183
+ }
184
+ } finally{
185
+ if (_didIteratorError1) {
186
+ throw _iteratorError1;
187
+ }
188
+ }
189
+ }
190
+ parsedDocs.push(doc);
191
+ }
192
+ } catch (err) {
193
+ _didIteratorError = true;
194
+ _iteratorError = err;
195
+ } finally{
196
+ try {
197
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
198
+ _iterator.return();
199
+ }
200
+ } finally{
201
+ if (_didIteratorError) {
202
+ throw _iteratorError;
203
+ }
204
+ }
205
+ }
206
+ // seenColumns already contains the reserved columns (they're real columns
207
+ // of `docs`), so spreading it alone avoids duplicate names in the INSERT.
208
+ var allColumns = _to_consumable_array(seenColumns);
209
+ var insertSql = "INSERT OR REPLACE INTO docs (".concat(allColumns.map(quoteIdent).join(', '), ") VALUES (").concat(allColumns.map(function() {
210
+ return '?';
211
+ }).join(', '), ")");
212
+ db.exec('BEGIN');
213
+ try {
214
+ var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
215
+ try {
216
+ for(var _iterator2 = newColumns[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
217
+ var col = _step2.value;
218
+ db.exec("ALTER TABLE docs ADD COLUMN ".concat(quoteIdent(col)));
219
+ }
220
+ } catch (err) {
221
+ _didIteratorError2 = true;
222
+ _iteratorError2 = err;
223
+ } finally{
224
+ try {
225
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
226
+ _iterator2.return();
227
+ }
228
+ } finally{
229
+ if (_didIteratorError2) {
230
+ throw _iteratorError2;
231
+ }
232
+ }
233
+ }
234
+ if (vanished.length > 0) {
235
+ var del = db.prepare('DELETE FROM docs WHERE "path" = ?');
236
+ var _iteratorNormalCompletion3 = true, _didIteratorError3 = false, _iteratorError3 = undefined;
237
+ try {
238
+ for(var _iterator3 = vanished[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true){
239
+ var path = _step3.value;
240
+ del.run(path);
241
+ }
242
+ } catch (err) {
243
+ _didIteratorError3 = true;
244
+ _iteratorError3 = err;
245
+ } finally{
246
+ try {
247
+ if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
248
+ _iterator3.return();
249
+ }
250
+ } finally{
251
+ if (_didIteratorError3) {
252
+ throw _iteratorError3;
253
+ }
254
+ }
255
+ }
256
+ }
257
+ if (parsedDocs.length > 0) {
258
+ var insert = db.prepare(insertSql);
259
+ var _iteratorNormalCompletion4 = true, _didIteratorError4 = false, _iteratorError4 = undefined;
260
+ try {
261
+ var _loop = function() {
262
+ var doc = _step4.value;
263
+ var _insert;
264
+ var values = allColumns.map(function(col) {
265
+ var _doc_data_col;
266
+ if (col === 'path') return doc.relPath;
267
+ if (col === '_mtime') return doc.mtimeMs;
268
+ if (col === '_size') return doc.size;
269
+ return (_doc_data_col = doc.data[col]) !== null && _doc_data_col !== void 0 ? _doc_data_col : null;
270
+ });
271
+ (_insert = insert).run.apply(_insert, _to_consumable_array(values));
272
+ };
273
+ for(var _iterator4 = parsedDocs[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true)_loop();
274
+ } catch (err) {
275
+ _didIteratorError4 = true;
276
+ _iteratorError4 = err;
277
+ } finally{
278
+ try {
279
+ if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
280
+ _iterator4.return();
281
+ }
282
+ } finally{
283
+ if (_didIteratorError4) {
284
+ throw _iteratorError4;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ db.exec('COMMIT');
290
+ } catch (err) {
291
+ db.exec('ROLLBACK');
292
+ throw err;
293
+ }
294
+ return {
295
+ parsed: parsedDocs.length,
296
+ warnings: warnings
297
+ };
298
+ }
299
+ function open(cfg) {
300
+ var stateDir = (0, _nodepath.join)(cfg.baseDir, _configts.STATE_DIR);
301
+ (0, _nodefs.mkdirSync)(stateDir, {
302
+ recursive: true
303
+ });
304
+ var dbPath = (0, _nodepath.join)(stateDir, DB_FILENAME);
305
+ var db = new _nodesqlite.DatabaseSync(dbPath);
306
+ db.exec('PRAGMA journal_mode = WAL');
307
+ db.exec('PRAGMA busy_timeout = 5000');
308
+ registerFunctions(db);
309
+ ensureSchema(db);
310
+ var _reconcile = reconcile(db, cfg, cfg.baseDir), parsed = _reconcile.parsed, warnings = _reconcile.warnings;
311
+ return {
312
+ db: db,
313
+ cfg: cfg,
314
+ dbPath: dbPath,
315
+ parsed: parsed,
316
+ warnings: warnings
317
+ };
318
+ }
319
+ function rebuild(cfg) {
320
+ (0, _nodefs.rmSync)((0, _nodepath.join)(cfg.baseDir, _configts.STATE_DIR), {
321
+ recursive: true,
322
+ force: true
323
+ });
324
+ return open(cfg);
325
+ }
326
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db.ts"],"sourcesContent":["import { mkdirSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { DatabaseSync } from 'node:sqlite';\nimport type { Config, ResolvedConfig } from './config.ts';\nimport { STATE_DIR } from './config.ts';\nimport type { ParsedDoc } from './scan.ts';\nimport { listFiles, parseFile } from './scan.ts';\n\n// Rows -> SQLite only: schema/ALTER, the reconcile diff + transaction,\n// pragmas, the meta table, has() registration. Filesystem reading and\n// frontmatter parsing live in scan.ts; this module never touches\n// node:fs/gray-matter directly and never prints (throws are for callers).\n\nexport const DB_FILENAME = 'cache.db';\nexport const SCHEMA_VERSION = '1';\n\nexport interface OpenResult {\n db: DatabaseSync;\n cfg: ResolvedConfig;\n dbPath: string;\n // Number of files (re)parsed by this open's reconcile -- 0 on a fully\n // warm cache. Tests use this as reconcile instrumentation.\n parsed: number;\n warnings: string[];\n}\n\n// Quote a SQL identifier, escaping embedded double quotes so an unusual\n// frontmatter key (however unlikely) can't break out of the identifier.\nfunction quoteIdent(name: string): string {\n return `\"${name.split('\"').join('\"\"')}\"`;\n}\n\n// The one custom SQL function in the whole tool: has(field, value).\n// - JSON-array field (stored as JSON text, e.g. `[\"a\",\"b\"]`) -> membership\n// - string field -> substring\n// - NULL -> false\nfunction registerFunctions(db: DatabaseSync): void {\n db.function('has', { deterministic: true, varargs: false }, (field: unknown, value: unknown): number => {\n if (field === null || field === undefined) return 0;\n\n const needle = String(value);\n\n if (typeof field === 'string') {\n // Try JSON array first (arrays are stored as JSON text).\n if (field.startsWith('[')) {\n try {\n const parsed = JSON.parse(field);\n if (Array.isArray(parsed)) {\n return parsed.some((item) => String(item) === needle) ? 1 : 0;\n }\n } catch {\n // fall through to substring match\n }\n }\n return field.includes(needle) ? 1 : 0;\n }\n\n // Numbers, etc: coerce to string and substring-match.\n return String(field).includes(needle) ? 1 : 0;\n });\n}\n\nfunction getColumns(db: DatabaseSync): Set<string> {\n const rows = db.prepare('PRAGMA table_info(docs)').all() as Array<{ name: string }>;\n return new Set(rows.map((r) => r.name));\n}\n\nfunction ensureSchema(db: DatabaseSync): void {\n db.exec(`CREATE TABLE IF NOT EXISTS docs (\"path\" TEXT PRIMARY KEY, \"_mtime\" REAL, \"_size\" INTEGER)`);\n db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n if (getMeta(db, 'schema_version') === null) setMeta(db, 'schema_version', SCHEMA_VERSION);\n}\n\nexport function getMeta(db: DatabaseSync, key: string): string | null {\n const row = db.prepare('SELECT value FROM meta WHERE key = ?').get(key) as { value: string } | undefined;\n return row ? row.value : null;\n}\n\nexport function setMeta(db: DatabaseSync, key: string, value: string | null): void {\n if (value === null) {\n db.prepare('DELETE FROM meta WHERE key = ?').run(key);\n return;\n }\n db.prepare('INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value').run(key, value);\n}\n\nexport function docCount(db: DatabaseSync): number {\n const row = db.prepare('SELECT COUNT(*) AS n FROM docs').get() as { n: number };\n return row.n;\n}\n\n// Reconcile the `docs` table against the filesystem: glob current files via\n// scan.ts, reparse stale (mtime/size changed) + new files in one\n// transaction, DELETE vanished paths, ALTER TABLE ADD COLUMN for newly\n// discovered frontmatter keys. Returns the number of files (re)parsed and\n// any warnings scan.ts collected (e.g. reserved-key collisions).\nexport function reconcile(db: DatabaseSync, cfg: Config, baseDir: string): { parsed: number; warnings: string[] } {\n const files = listFiles(cfg, baseDir);\n const currentSet = new Set(files.map((f) => f.relPath));\n\n const existingRows = db.prepare(`SELECT \"path\", \"_mtime\", \"_size\" FROM docs`).all() as Array<{\n path: string;\n _mtime: number;\n _size: number;\n }>;\n const existing = new Map(existingRows.map((r) => [r.path, r]));\n const vanished = existingRows.filter((r) => !currentSet.has(r.path)).map((r) => r.path);\n\n const toReparse = files.filter((f) => {\n const row = existing.get(f.relPath);\n return !row || row._mtime !== f.mtimeMs || row._size !== f.size;\n });\n\n if (vanished.length === 0 && toReparse.length === 0) return { parsed: 0, warnings: [] };\n\n const seenColumns = getColumns(db);\n const newColumns: string[] = [];\n const parsedDocs: ParsedDoc[] = [];\n const warnings: string[] = [];\n\n for (const file of toReparse) {\n const { doc, warnings: fileWarnings } = parseFile(file);\n warnings.push(...fileWarnings);\n for (const key of Object.keys(doc.data)) {\n if (!seenColumns.has(key)) {\n seenColumns.add(key);\n newColumns.push(key);\n }\n }\n parsedDocs.push(doc);\n }\n\n // seenColumns already contains the reserved columns (they're real columns\n // of `docs`), so spreading it alone avoids duplicate names in the INSERT.\n const allColumns = [...seenColumns];\n const insertSql = `INSERT OR REPLACE INTO docs (${allColumns.map(quoteIdent).join(', ')}) VALUES (${allColumns.map(() => '?').join(', ')})`;\n\n db.exec('BEGIN');\n try {\n for (const col of newColumns) db.exec(`ALTER TABLE docs ADD COLUMN ${quoteIdent(col)}`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM docs WHERE \"path\" = ?`);\n for (const path of vanished) del.run(path);\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n for (const doc of parsedDocs) {\n const values = allColumns.map((col) => {\n if (col === 'path') return doc.relPath;\n if (col === '_mtime') return doc.mtimeMs;\n if (col === '_size') return doc.size;\n return doc.data[col] ?? null;\n });\n insert.run(...values);\n }\n }\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n return { parsed: parsedDocs.length, warnings };\n}\n\n// open(resolved config): open (or create) the on-disk SQLite cache at\n// `<baseDir>/.sense/cache.db`, reconcile against the filesystem, and return\n// a live handle. The DB is a warm start, never a source of truth -- the\n// `.md` files remain truth. Takes only an already-resolved config; discovery\n// and version-gating are config.ts's job, not this one's.\nexport function open(cfg: ResolvedConfig): OpenResult {\n const stateDir = join(cfg.baseDir, STATE_DIR);\n mkdirSync(stateDir, { recursive: true });\n const dbPath = join(stateDir, DB_FILENAME);\n\n const db = new DatabaseSync(dbPath);\n db.exec('PRAGMA journal_mode = WAL');\n db.exec('PRAGMA busy_timeout = 5000');\n registerFunctions(db);\n\n ensureSchema(db);\n const { parsed, warnings } = reconcile(db, cfg, cfg.baseDir);\n\n return { db, cfg, dbPath, parsed, warnings };\n}\n\n// Delete the `.sense/` state dir entirely and reconcile fresh -- the manual\n// reset for lingering columns or a doubted cache.\nexport function rebuild(cfg: ResolvedConfig): OpenResult {\n rmSync(join(cfg.baseDir, STATE_DIR), { recursive: true, force: true });\n return open(cfg);\n}\n"],"names":["DB_FILENAME","SCHEMA_VERSION","docCount","getMeta","open","rebuild","reconcile","setMeta","quoteIdent","name","split","join","registerFunctions","db","function","deterministic","varargs","field","value","undefined","needle","String","startsWith","parsed","JSON","parse","Array","isArray","some","item","includes","getColumns","rows","prepare","all","Set","map","r","ensureSchema","exec","key","row","get","run","n","cfg","baseDir","files","listFiles","currentSet","f","relPath","existingRows","existing","Map","path","vanished","filter","has","toReparse","_mtime","mtimeMs","_size","size","length","warnings","seenColumns","newColumns","parsedDocs","file","parseFile","doc","fileWarnings","push","Object","keys","data","add","allColumns","insertSql","col","del","insert","values","err","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","rmSync","force"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE';
2
+ export declare class SenseError extends Error {
3
+ code: SenseErrorCode;
4
+ constructor(code: SenseErrorCode, message: string);
5
+ }
@@ -0,0 +1,5 @@
1
+ export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE';
2
+ export declare class SenseError extends Error {
3
+ code: SenseErrorCode;
4
+ constructor(code: SenseErrorCode, message: string);
5
+ }