sensemaking 0.2.0 → 0.3.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 (182) hide show
  1. package/README.md +107 -126
  2. package/dist/cjs/cli.js +172 -182
  3. package/dist/cjs/cli.js.map +1 -1
  4. package/dist/cjs/commands/find.d.cts +3 -0
  5. package/dist/cjs/commands/find.d.ts +3 -0
  6. package/dist/cjs/commands/find.js +73 -0
  7. package/dist/cjs/commands/find.js.map +1 -0
  8. package/dist/cjs/commands/index.d.cts +5 -0
  9. package/dist/cjs/commands/index.d.ts +5 -0
  10. package/dist/cjs/commands/index.js +94 -0
  11. package/dist/cjs/commands/index.js.map +1 -0
  12. package/dist/cjs/commands/init.d.cts +3 -0
  13. package/dist/cjs/commands/init.d.ts +3 -0
  14. package/dist/cjs/commands/init.js +18 -0
  15. package/dist/cjs/commands/init.js.map +1 -0
  16. package/dist/cjs/commands/map.d.cts +3 -0
  17. package/dist/cjs/commands/map.d.ts +3 -0
  18. package/dist/cjs/commands/map.js +21 -0
  19. package/dist/cjs/commands/map.js.map +1 -0
  20. package/dist/cjs/commands/named.d.cts +2 -0
  21. package/dist/cjs/commands/named.d.ts +2 -0
  22. package/dist/cjs/commands/named.js +23 -0
  23. package/dist/cjs/commands/named.js.map +1 -0
  24. package/dist/cjs/commands/peek.d.cts +3 -0
  25. package/dist/cjs/commands/peek.d.ts +3 -0
  26. package/dist/cjs/commands/peek.js +69 -0
  27. package/dist/cjs/commands/peek.js.map +1 -0
  28. package/dist/cjs/commands/query.d.cts +3 -0
  29. package/dist/cjs/commands/query.d.ts +3 -0
  30. package/dist/cjs/commands/query.js +43 -0
  31. package/dist/cjs/commands/query.js.map +1 -0
  32. package/dist/cjs/commands/rebuild.d.cts +3 -0
  33. package/dist/cjs/commands/rebuild.d.ts +3 -0
  34. package/dist/cjs/commands/rebuild.js +20 -0
  35. package/dist/cjs/commands/rebuild.js.map +1 -0
  36. package/dist/cjs/commands/status.d.cts +3 -0
  37. package/dist/cjs/commands/status.d.ts +3 -0
  38. package/dist/cjs/commands/status.js +24 -0
  39. package/dist/cjs/commands/status.js.map +1 -0
  40. package/dist/cjs/commands/types.d.cts +15 -0
  41. package/dist/cjs/commands/types.d.ts +15 -0
  42. package/dist/cjs/commands/types.js +5 -0
  43. package/dist/cjs/commands/types.js.map +1 -0
  44. package/dist/cjs/commands/vault.d.cts +6 -0
  45. package/dist/cjs/commands/vault.d.ts +6 -0
  46. package/dist/cjs/commands/vault.js +94 -0
  47. package/dist/cjs/commands/vault.js.map +1 -0
  48. package/dist/cjs/commands/watch.d.cts +3 -0
  49. package/dist/cjs/commands/watch.d.ts +3 -0
  50. package/dist/cjs/commands/watch.js +173 -0
  51. package/dist/cjs/commands/watch.js.map +1 -0
  52. package/dist/cjs/config.d.cts +11 -1
  53. package/dist/cjs/config.d.ts +11 -1
  54. package/dist/cjs/config.js +82 -9
  55. package/dist/cjs/config.js.map +1 -1
  56. package/dist/cjs/db.d.cts +1 -1
  57. package/dist/cjs/db.d.ts +1 -1
  58. package/dist/cjs/db.js +107 -16
  59. package/dist/cjs/db.js.map +1 -1
  60. package/dist/cjs/errors.d.cts +1 -1
  61. package/dist/cjs/errors.d.ts +1 -1
  62. package/dist/cjs/errors.js.map +1 -1
  63. package/dist/cjs/features/index.d.cts +7 -0
  64. package/dist/cjs/features/index.d.ts +7 -0
  65. package/dist/cjs/features/index.js +36 -0
  66. package/dist/cjs/features/index.js.map +1 -0
  67. package/dist/cjs/features/links.d.cts +4 -0
  68. package/dist/cjs/features/links.d.ts +4 -0
  69. package/dist/cjs/features/links.js +217 -0
  70. package/dist/cjs/features/links.js.map +1 -0
  71. package/dist/cjs/features/rank.d.cts +2 -0
  72. package/dist/cjs/features/rank.d.ts +2 -0
  73. package/dist/cjs/features/rank.js +95 -0
  74. package/dist/cjs/features/rank.js.map +1 -0
  75. package/dist/cjs/features/sections.d.cts +9 -0
  76. package/dist/cjs/features/sections.d.ts +9 -0
  77. package/dist/cjs/features/sections.js +54 -0
  78. package/dist/cjs/features/sections.js.map +1 -0
  79. package/dist/cjs/features/types.d.cts +11 -0
  80. package/dist/cjs/features/types.d.ts +11 -0
  81. package/dist/cjs/features/types.js +5 -0
  82. package/dist/cjs/features/types.js.map +1 -0
  83. package/dist/cjs/graph.d.cts +7 -0
  84. package/dist/cjs/graph.d.ts +7 -0
  85. package/dist/cjs/graph.js +237 -0
  86. package/dist/cjs/graph.js.map +1 -0
  87. package/dist/cjs/index.d.cts +9 -2
  88. package/dist/cjs/index.d.ts +9 -2
  89. package/dist/cjs/index.js +39 -0
  90. package/dist/cjs/index.js.map +1 -1
  91. package/dist/cjs/output.d.cts +21 -0
  92. package/dist/cjs/output.d.ts +21 -0
  93. package/dist/cjs/output.js +112 -3
  94. package/dist/cjs/output.js.map +1 -1
  95. package/dist/cjs/scan.d.cts +3 -1
  96. package/dist/cjs/scan.d.ts +3 -1
  97. package/dist/cjs/scan.js +62 -14
  98. package/dist/cjs/scan.js.map +1 -1
  99. package/dist/cjs/verbs.d.cts +31 -0
  100. package/dist/cjs/verbs.d.ts +31 -0
  101. package/dist/cjs/verbs.js +284 -0
  102. package/dist/cjs/verbs.js.map +1 -0
  103. package/dist/esm/cli.js +63 -107
  104. package/dist/esm/cli.js.map +1 -1
  105. package/dist/esm/commands/find.d.ts +3 -0
  106. package/dist/esm/commands/find.js +14 -0
  107. package/dist/esm/commands/find.js.map +1 -0
  108. package/dist/esm/commands/index.d.ts +5 -0
  109. package/dist/esm/commands/index.js +13 -0
  110. package/dist/esm/commands/index.js.map +1 -0
  111. package/dist/esm/commands/init.d.ts +3 -0
  112. package/dist/esm/commands/init.js +7 -0
  113. package/dist/esm/commands/init.js.map +1 -0
  114. package/dist/esm/commands/map.d.ts +3 -0
  115. package/dist/esm/commands/map.js +10 -0
  116. package/dist/esm/commands/map.js.map +1 -0
  117. package/dist/esm/commands/named.d.ts +2 -0
  118. package/dist/esm/commands/named.js +12 -0
  119. package/dist/esm/commands/named.js.map +1 -0
  120. package/dist/esm/commands/peek.d.ts +3 -0
  121. package/dist/esm/commands/peek.js +12 -0
  122. package/dist/esm/commands/peek.js.map +1 -0
  123. package/dist/esm/commands/query.d.ts +3 -0
  124. package/dist/esm/commands/query.js +7 -0
  125. package/dist/esm/commands/query.js.map +1 -0
  126. package/dist/esm/commands/rebuild.d.ts +3 -0
  127. package/dist/esm/commands/rebuild.js +9 -0
  128. package/dist/esm/commands/rebuild.js.map +1 -0
  129. package/dist/esm/commands/status.d.ts +3 -0
  130. package/dist/esm/commands/status.js +13 -0
  131. package/dist/esm/commands/status.js.map +1 -0
  132. package/dist/esm/commands/types.d.ts +15 -0
  133. package/dist/esm/commands/types.js +1 -0
  134. package/dist/esm/commands/types.js.map +1 -0
  135. package/dist/esm/commands/vault.d.ts +6 -0
  136. package/dist/esm/commands/vault.js +29 -0
  137. package/dist/esm/commands/vault.js.map +1 -0
  138. package/dist/esm/commands/watch.d.ts +3 -0
  139. package/dist/esm/commands/watch.js +19 -0
  140. package/dist/esm/commands/watch.js.map +1 -0
  141. package/dist/esm/config.d.ts +11 -1
  142. package/dist/esm/config.js +68 -12
  143. package/dist/esm/config.js.map +1 -1
  144. package/dist/esm/db.d.ts +1 -1
  145. package/dist/esm/db.js +27 -9
  146. package/dist/esm/db.js.map +1 -1
  147. package/dist/esm/errors.d.ts +1 -1
  148. package/dist/esm/errors.js.map +1 -1
  149. package/dist/esm/features/index.d.ts +7 -0
  150. package/dist/esm/features/index.js +14 -0
  151. package/dist/esm/features/index.js.map +1 -0
  152. package/dist/esm/features/links.d.ts +4 -0
  153. package/dist/esm/features/links.js +81 -0
  154. package/dist/esm/features/links.js.map +1 -0
  155. package/dist/esm/features/rank.d.ts +2 -0
  156. package/dist/esm/features/rank.js +17 -0
  157. package/dist/esm/features/rank.js.map +1 -0
  158. package/dist/esm/features/sections.d.ts +9 -0
  159. package/dist/esm/features/sections.js +41 -0
  160. package/dist/esm/features/sections.js.map +1 -0
  161. package/dist/esm/features/types.d.ts +11 -0
  162. package/dist/esm/features/types.js +3 -0
  163. package/dist/esm/features/types.js.map +1 -0
  164. package/dist/esm/graph.d.ts +7 -0
  165. package/dist/esm/graph.js +79 -0
  166. package/dist/esm/graph.js.map +1 -0
  167. package/dist/esm/index.d.ts +9 -2
  168. package/dist/esm/index.js +4 -1
  169. package/dist/esm/index.js.map +1 -1
  170. package/dist/esm/output.d.ts +21 -0
  171. package/dist/esm/output.js +28 -0
  172. package/dist/esm/output.js.map +1 -1
  173. package/dist/esm/scan.d.ts +3 -1
  174. package/dist/esm/scan.js +56 -7
  175. package/dist/esm/scan.js.map +1 -1
  176. package/dist/esm/verbs.d.ts +31 -0
  177. package/dist/esm/verbs.js +139 -0
  178. package/dist/esm/verbs.js.map +1 -0
  179. package/package.json +4 -4
  180. package/schema.json +23 -4
  181. package/skills/sense/EXAMPLES.md +46 -81
  182. package/skills/sense/SKILL.md +58 -92
@@ -1 +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: schema, reconcile, has(). Filesystem/frontmatter parsing lives in scan.ts.\n\nexport const DB_FILENAME = 'cache.db';\n// Cache shape version, independent of the config's own `version`.\nexport const SCHEMA_VERSION = '2';\n\nexport interface OpenResult {\n db: DatabaseSync;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n}\n\nfunction quoteIdent(name: string): string {\n return `\"${name.split('\"').join('\"\"')}\"`;\n}\n\n// has(field, value): JSON-array field -> membership, string field -> substring, 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 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 }\n return field.includes(needle) ? 1 : 0;\n }\n\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(frontmatter)').all() as Array<{ name: string }>;\n return new Set(rows.map((r) => r.name));\n}\n\n// Content is a separate table (not a column on frontmatter) so `SELECT * FROM frontmatter` can't dump file text into context.\nfunction ensureSchema(db: DatabaseSync): void {\n db.exec(`CREATE TABLE IF NOT EXISTS frontmatter (\"path\" TEXT PRIMARY KEY, \"_mtime\" REAL, \"_size\" INTEGER)`);\n db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS content USING fts5(title, summary, text, path UNINDEXED, tokenize = 'porter unicode61')`);\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 frontmatter').get() as { n: number };\n return row.n;\n}\n\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 frontmatter`).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 const allColumns = [...seenColumns];\n const insertSql = `INSERT OR REPLACE INTO frontmatter (${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 frontmatter ADD COLUMN ${quoteIdent(col)}`);\n // FTS5 has no upsert, so delete-before-insert into `content`.\n const delBody = db.prepare(`DELETE FROM content WHERE \"path\" = ?`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n del.run(path);\n delBody.run(path);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(`INSERT INTO content (title, summary, text, \"path\") VALUES (?, ?, ?, ?)`);\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 delBody.run(doc.relPath);\n insertBody.run(doc.search.title, doc.search.summary, doc.search.text, doc.relPath);\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\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 db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n // Schema version mismatch: reconcile only reparses changed files, so an old cache can't be patched up incrementally -- rebuild instead.\n const version = getMeta(db, 'schema_version');\n if (version !== null && version !== SCHEMA_VERSION) {\n db.close();\n rmSync(stateDir, { recursive: true, force: true });\n return open(cfg);\n }\n\n ensureSchema(db);\n const { parsed, warnings } = reconcile(db, cfg, cfg.baseDir);\n\n return { db, cfg, dbPath, parsed, warnings };\n}\n\n// Manual reset for 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","delBody","del","insert","insertBody","values","search","title","summary","text","err","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","version","close","rmSync","force"],"mappings":"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"}
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 { enabledFeatures, STATE_DIR } from './config.ts';\nimport { activeFeatures } from './features/index.ts';\nimport type { ParsedDoc } from './scan.ts';\nimport { listFiles, parseFile } from './scan.ts';\n\n// Rows -> SQLite: core schema, reconcile loop, has(). Parsing lives in scan.ts;\n// everything beyond frontmatter + content lives in src/features/.\n\nexport const DB_FILENAME = 'cache.db';\n// Cache shape version, independent of the config's own `version`.\nexport const SCHEMA_VERSION = '3';\n\nexport interface OpenResult {\n db: DatabaseSync;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n}\n\nfunction quoteIdent(name: string): string {\n return `\"${name.split('\"').join('\"\"')}\"`;\n}\n\n// has(field, value): JSON-array field -> membership, string field -> substring, 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 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 }\n return field.includes(needle) ? 1 : 0;\n }\n\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(frontmatter)').all() as Array<{ name: string }>;\n return new Set(rows.map((r) => r.name));\n}\n\n// Content is a separate table (not a column on frontmatter) so `SELECT * FROM frontmatter`\n// can't dump file text into context. Features add their own tables after the core ones.\nfunction ensureSchema(db: DatabaseSync, cfg: Config): void {\n db.exec(`CREATE TABLE IF NOT EXISTS frontmatter (\"path\" TEXT PRIMARY KEY, \"_mtime\" REAL, \"_size\" INTEGER)`);\n db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS content USING fts5(title, summary, text, path UNINDEXED, tokenize = 'porter unicode61')`);\n for (const feature of activeFeatures(cfg)) feature.schema(db);\n if (getMeta(db, 'schema_version') === null) setMeta(db, 'schema_version', SCHEMA_VERSION);\n if (getMeta(db, 'features') === null) setMeta(db, 'features', enabledFeatures(cfg).join(','));\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 frontmatter').get() as { n: number };\n return row.n;\n}\n\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 frontmatter`).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 features = activeFeatures(cfg);\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, features);\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 const allColumns = [...seenColumns];\n const insertSql = `INSERT OR REPLACE INTO frontmatter (${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 frontmatter ADD COLUMN ${quoteIdent(col)}`);\n // FTS5 has no upsert, so delete-before-insert into `content`.\n const delBody = db.prepare(`DELETE FROM content WHERE \"path\" = ?`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n del.run(path);\n delBody.run(path);\n for (const feature of features) feature.remove?.(db, path);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(`INSERT INTO content (title, summary, text, \"path\") VALUES (?, ?, ?, ?)`);\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 delBody.run(doc.relPath);\n insertBody.run(doc.search.title, doc.search.summary, doc.search.text, doc.relPath);\n for (const feature of features) {\n feature.remove?.(db, doc.relPath);\n feature.store?.(db, doc.relPath, doc.extracted[feature.name]);\n }\n }\n }\n for (const feature of features) feature.afterReconcile?.(db, files);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n return { parsed: parsedDocs.length, warnings };\n}\n\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 db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n // Schema-version or feature-set mismatch: reconcile only reparses changed files, so an\n // old cache can't be patched incrementally -- rebuild instead (cheap: nothing expensive lives here).\n const version = getMeta(db, 'schema_version');\n const features = getMeta(db, 'features');\n const wantFeatures = enabledFeatures(cfg).join(',');\n if ((version !== null && version !== SCHEMA_VERSION) || (features !== null && features !== wantFeatures)) {\n db.close();\n rmSync(stateDir, { recursive: true, force: true });\n return open(cfg);\n }\n\n ensureSchema(db, cfg);\n const { parsed, warnings } = reconcile(db, cfg, cfg.baseDir);\n\n return { db, cfg, dbPath, parsed, warnings };\n}\n\n// Manual reset for 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","cfg","exec","activeFeatures","feature","schema","enabledFeatures","key","row","get","run","n","baseDir","files","listFiles","currentSet","f","relPath","existingRows","existing","Map","path","vanished","filter","has","toReparse","_mtime","mtimeMs","_size","size","length","warnings","features","seenColumns","newColumns","parsedDocs","file","parseFile","doc","fileWarnings","push","Object","keys","data","add","allColumns","insertSql","col","delBody","del","remove","insert","insertBody","values","search","title","summary","text","store","extracted","afterReconcile","err","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","version","wantFeatures","close","rmSync","force"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE';
1
+ export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS';
2
2
  export declare class SenseError extends Error {
3
3
  code: SenseErrorCode;
4
4
  constructor(code: SenseErrorCode, message: string);
@@ -1,4 +1,4 @@
1
- export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE';
1
+ export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS';
2
2
  export declare class SenseError extends Error {
3
3
  code: SenseErrorCode;
4
4
  constructor(code: SenseErrorCode, message: string);
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/errors.ts"],"sourcesContent":["// Library code throws; only cli.ts prints and exits.\nexport type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE';\n\nexport class SenseError extends Error {\n code: SenseErrorCode;\n\n constructor(code: SenseErrorCode, message: string) {\n super(message);\n this.name = 'SenseError';\n this.code = code;\n }\n}\n"],"names":["SenseError","code","message","name","Error"],"mappings":"AAAA,qDAAqD;;;;;+BAGxCA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAN,IAAA,AAAMA,2BAAN;;cAAMA;aAAAA,WAGCC,IAAoB,EAAEC,OAAe;gCAHtCF;;gBAIT,kBAJSA;YAIHE;;QACN,MAAKC,IAAI,GAAG;QACZ,MAAKF,IAAI,GAAGA;;;WANHD;qBAAmBI"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/errors.ts"],"sourcesContent":["// Library code throws; only cli.ts prints and exits.\nexport type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS';\n\nexport class SenseError extends Error {\n code: SenseErrorCode;\n\n constructor(code: SenseErrorCode, message: string) {\n super(message);\n this.name = 'SenseError';\n this.code = code;\n }\n}\n"],"names":["SenseError","code","message","name","Error"],"mappings":"AAAA,qDAAqD;;;;;+BAGxCA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAN,IAAA,AAAMA,2BAAN;;cAAMA;aAAAA,WAGCC,IAAoB,EAAEC,OAAe;gCAHtCF;;gBAIT,kBAJSA;YAIHE;;QACN,MAAKC,IAAI,GAAG;QACZ,MAAKF,IAAI,GAAGA;;;WANHD;qBAAmBI"}
@@ -0,0 +1,7 @@
1
+ import type { Config } from '../config.js';
2
+ import type { Feature } from './types.js';
3
+ export declare const FEATURES: Feature[];
4
+ export declare function activeFeatures(cfg: Config): Feature[];
5
+ export { linkEdges } from './links.js';
6
+ export type { Section } from './sections.js';
7
+ export type { Feature } from './types.js';
@@ -0,0 +1,7 @@
1
+ import type { Config } from '../config.js';
2
+ import type { Feature } from './types.js';
3
+ export declare const FEATURES: Feature[];
4
+ export declare function activeFeatures(cfg: Config): Feature[];
5
+ export { linkEdges } from './links.js';
6
+ export type { Section } from './sections.js';
7
+ export type { Feature } from './types.js';
@@ -0,0 +1,36 @@
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 FEATURES () {
13
+ return FEATURES;
14
+ },
15
+ get activeFeatures () {
16
+ return activeFeatures;
17
+ },
18
+ get linkEdges () {
19
+ return _linksts.linkEdges;
20
+ }
21
+ });
22
+ var _configts = require("../config.js");
23
+ var _linksts = require("./links.js");
24
+ var _rankts = require("./rank.js");
25
+ var _sectionsts = require("./sections.js");
26
+ var FEATURES = [
27
+ _linksts.links,
28
+ _sectionsts.sections,
29
+ _rankts.rank
30
+ ];
31
+ function activeFeatures(cfg) {
32
+ return FEATURES.filter(function(feature) {
33
+ return (0, _configts.featureEnabled)(cfg, feature.name);
34
+ });
35
+ }
36
+ /* 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/features/index.ts"],"sourcesContent":["import type { Config } from '../config.ts';\nimport { featureEnabled } from '../config.ts';\nimport { links } from './links.ts';\nimport { rank } from './rank.ts';\nimport { sections } from './sections.ts';\nimport type { Feature } from './types.ts';\n\n// Registry order matters: rank reads the links table in afterReconcile.\nexport const FEATURES: Feature[] = [links, sections, rank];\n\nexport function activeFeatures(cfg: Config): Feature[] {\n return FEATURES.filter((feature) => featureEnabled(cfg, feature.name));\n}\n\nexport { linkEdges } from './links.ts';\nexport type { Section } from './sections.ts';\nexport type { Feature } from './types.ts';\n"],"names":["FEATURES","activeFeatures","linkEdges","links","sections","rank","cfg","filter","feature","featureEnabled","name"],"mappings":";;;;;;;;;;;QAQaA;eAAAA;;QAEGC;eAAAA;;QAIPC;eAAAA,kBAAS;;;wBAba;uBACT;sBACD;0BACI;AAIlB,IAAMF,WAAsB;IAACG,cAAK;IAAEC,oBAAQ;IAAEC,YAAI;CAAC;AAEnD,SAASJ,eAAeK,GAAW;IACxC,OAAON,SAASO,MAAM,CAAC,SAACC;eAAYC,IAAAA,wBAAc,EAACH,KAAKE,QAAQE,IAAI;;AACtE"}
@@ -0,0 +1,4 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { Feature } from './types.js';
3
+ export declare function linkEdges(db: DatabaseSync): [string, string][];
4
+ export declare const links: Feature;
@@ -0,0 +1,4 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { Feature } from './types.js';
3
+ export declare function linkEdges(db: DatabaseSync): [string, string][];
4
+ export declare const links: Feature;
@@ -0,0 +1,217 @@
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 linkEdges () {
13
+ return linkEdges;
14
+ },
15
+ get links () {
16
+ return links;
17
+ }
18
+ });
19
+ var _posix = /*#__PURE__*/ _interop_require_default(require("node:path/posix"));
20
+ function _array_like_to_array(arr, len) {
21
+ if (len == null || len > arr.length) len = arr.length;
22
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
23
+ return arr2;
24
+ }
25
+ function _array_without_holes(arr) {
26
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
27
+ }
28
+ function _interop_require_default(obj) {
29
+ return obj && obj.__esModule ? obj : {
30
+ default: obj
31
+ };
32
+ }
33
+ function _iterable_to_array(iter) {
34
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
35
+ }
36
+ function _non_iterable_spread() {
37
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
38
+ }
39
+ function _to_consumable_array(arr) {
40
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
41
+ }
42
+ function _unsupported_iterable_to_array(o, minLen) {
43
+ if (!o) return;
44
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
45
+ var n = Object.prototype.toString.call(o).slice(8, -1);
46
+ if (n === "Object" && o.constructor) n = o.constructor.name;
47
+ if (n === "Map" || n === "Set") return Array.from(n);
48
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
49
+ }
50
+ // links(src, target, dst): target as written, dst the resolved path or NULL (a queryable dead link).
51
+ // Wikilinks ([[target]], [[target#anchor|alias]], embeds) plus relative markdown links to .md files.
52
+ function extract(_raw, body) {
53
+ var targets = new Set();
54
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
55
+ try {
56
+ for(var _iterator = body.matchAll(/\[\[([^\]|#]+)(?:#[^\]|]*)?(?:\|[^\]]*)?\]\]/g)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
57
+ var m = _step.value;
58
+ var target = m[1].trim();
59
+ if (target) targets.add(target);
60
+ }
61
+ } catch (err) {
62
+ _didIteratorError = true;
63
+ _iteratorError = err;
64
+ } finally{
65
+ try {
66
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
67
+ _iterator.return();
68
+ }
69
+ } finally{
70
+ if (_didIteratorError) {
71
+ throw _iteratorError;
72
+ }
73
+ }
74
+ }
75
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
76
+ try {
77
+ for(var _iterator1 = body.matchAll(/\]\(([^)]+\.md)(?:#[^)]*)?\)/g)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
78
+ var m1 = _step1.value;
79
+ var target1 = m1[1].trim();
80
+ if (target1 && !/^[a-z]+:\/\//i.test(target1)) targets.add(target1);
81
+ }
82
+ } catch (err) {
83
+ _didIteratorError1 = true;
84
+ _iteratorError1 = err;
85
+ } finally{
86
+ try {
87
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
88
+ _iterator1.return();
89
+ }
90
+ } finally{
91
+ if (_didIteratorError1) {
92
+ throw _iteratorError1;
93
+ }
94
+ }
95
+ }
96
+ return _to_consumable_array(targets);
97
+ }
98
+ function baseKey(path) {
99
+ return _posix.default.basename(path).replace(/\.md$/i, '').toLowerCase();
100
+ }
101
+ // Obsidian-style: exact relative path (with/without .md), path relative to the linking
102
+ // note's directory, then basename match (lexicographically first on ties).
103
+ function resolveTarget(src, target, pathSet, byBase) {
104
+ var _ref;
105
+ var _byBase_get;
106
+ var clean = target.replace(/\\/g, '/').replace(/^\.\//, '');
107
+ var fromSrc = _posix.default.normalize(_posix.default.join(_posix.default.dirname(src), clean));
108
+ for(var _i = 0, _iter = [
109
+ clean,
110
+ "".concat(clean, ".md"),
111
+ fromSrc,
112
+ "".concat(fromSrc, ".md")
113
+ ]; _i < _iter.length; _i++){
114
+ var candidate = _iter[_i];
115
+ if (pathSet.has(candidate)) return candidate;
116
+ }
117
+ return (_ref = (_byBase_get = byBase.get(baseKey(clean))) === null || _byBase_get === void 0 ? void 0 : _byBase_get[0]) !== null && _ref !== void 0 ? _ref : null;
118
+ }
119
+ // A new or deleted file can change any note's resolution, so re-resolve the whole table
120
+ // whenever the vault changes. An in-memory probe per row; writes only on change.
121
+ function resolveAll(db, files) {
122
+ var pathSet = new Set(files.map(function(f) {
123
+ return f.relPath;
124
+ }));
125
+ var byBase = new Map();
126
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
127
+ try {
128
+ for(var _iterator = _to_consumable_array(pathSet).sort()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
129
+ var path = _step.value;
130
+ var list = byBase.get(baseKey(path));
131
+ if (list) list.push(path);
132
+ else byBase.set(baseKey(path), [
133
+ path
134
+ ]);
135
+ }
136
+ } catch (err) {
137
+ _didIteratorError = true;
138
+ _iteratorError = err;
139
+ } finally{
140
+ try {
141
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
142
+ _iterator.return();
143
+ }
144
+ } finally{
145
+ if (_didIteratorError) {
146
+ throw _iteratorError;
147
+ }
148
+ }
149
+ }
150
+ var rows = db.prepare('SELECT src, target, dst FROM links').all();
151
+ var update = db.prepare('UPDATE links SET dst = ? WHERE src = ? AND target = ?');
152
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
153
+ try {
154
+ for(var _iterator1 = rows[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
155
+ var row = _step1.value;
156
+ var dst = resolveTarget(row.src, row.target, pathSet, byBase);
157
+ if (dst !== row.dst) update.run(dst, row.src, row.target);
158
+ }
159
+ } catch (err) {
160
+ _didIteratorError1 = true;
161
+ _iteratorError1 = err;
162
+ } finally{
163
+ try {
164
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
165
+ _iterator1.return();
166
+ }
167
+ } finally{
168
+ if (_didIteratorError1) {
169
+ throw _iteratorError1;
170
+ }
171
+ }
172
+ }
173
+ }
174
+ function linkEdges(db) {
175
+ return db.prepare('SELECT src, dst FROM links WHERE dst IS NOT NULL').all().map(function(r) {
176
+ return [
177
+ r.src,
178
+ r.dst
179
+ ];
180
+ });
181
+ }
182
+ var links = {
183
+ name: 'links',
184
+ schema: function schema(db) {
185
+ db.exec('CREATE TABLE IF NOT EXISTS links (src TEXT, target TEXT, dst TEXT, PRIMARY KEY (src, target))');
186
+ db.exec('CREATE INDEX IF NOT EXISTS links_dst ON links(dst)');
187
+ },
188
+ extract: extract,
189
+ remove: function remove(db, path) {
190
+ db.prepare('DELETE FROM links WHERE src = ?').run(path);
191
+ },
192
+ store: function store(db, path, extracted) {
193
+ var insert = db.prepare('INSERT OR REPLACE INTO links (src, target, dst) VALUES (?, ?, NULL)');
194
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
195
+ try {
196
+ for(var _iterator = extracted[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
197
+ var target = _step.value;
198
+ insert.run(path, target);
199
+ }
200
+ } catch (err) {
201
+ _didIteratorError = true;
202
+ _iteratorError = err;
203
+ } finally{
204
+ try {
205
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
206
+ _iterator.return();
207
+ }
208
+ } finally{
209
+ if (_didIteratorError) {
210
+ throw _iteratorError;
211
+ }
212
+ }
213
+ }
214
+ },
215
+ afterReconcile: resolveAll
216
+ };
217
+ /* 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/features/links.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { FileStat } from '../scan.ts';\nimport type { Feature } from './types.ts';\n\n// links(src, target, dst): target as written, dst the resolved path or NULL (a queryable dead link).\n\n// Wikilinks ([[target]], [[target#anchor|alias]], embeds) plus relative markdown links to .md files.\nfunction extract(_raw: string, body: string): string[] {\n const targets = new Set<string>();\n for (const m of body.matchAll(/\\[\\[([^\\]|#]+)(?:#[^\\]|]*)?(?:\\|[^\\]]*)?\\]\\]/g)) {\n const target = m[1].trim();\n if (target) targets.add(target);\n }\n for (const m of body.matchAll(/\\]\\(([^)]+\\.md)(?:#[^)]*)?\\)/g)) {\n const target = m[1].trim();\n if (target && !/^[a-z]+:\\/\\//i.test(target)) targets.add(target);\n }\n return [...targets];\n}\n\nfunction baseKey(path: string): string {\n return posix.basename(path).replace(/\\.md$/i, '').toLowerCase();\n}\n\n// Obsidian-style: exact relative path (with/without .md), path relative to the linking\n// note's directory, then basename match (lexicographically first on ties).\nfunction resolveTarget(src: string, target: string, pathSet: Set<string>, byBase: Map<string, string[]>): string | null {\n const clean = target.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n const fromSrc = posix.normalize(posix.join(posix.dirname(src), clean));\n for (const candidate of [clean, `${clean}.md`, fromSrc, `${fromSrc}.md`]) {\n if (pathSet.has(candidate)) return candidate;\n }\n return byBase.get(baseKey(clean))?.[0] ?? null;\n}\n\n// A new or deleted file can change any note's resolution, so re-resolve the whole table\n// whenever the vault changes. An in-memory probe per row; writes only on change.\nfunction resolveAll(db: DatabaseSync, files: FileStat[]): void {\n const pathSet = new Set(files.map((f) => f.relPath));\n const byBase = new Map<string, string[]>();\n for (const path of [...pathSet].sort()) {\n const list = byBase.get(baseKey(path));\n if (list) list.push(path);\n else byBase.set(baseKey(path), [path]);\n }\n const rows = db.prepare('SELECT src, target, dst FROM links').all() as Array<{ src: string; target: string; dst: string | null }>;\n const update = db.prepare('UPDATE links SET dst = ? WHERE src = ? AND target = ?');\n for (const row of rows) {\n const dst = resolveTarget(row.src, row.target, pathSet, byBase);\n if (dst !== row.dst) update.run(dst, row.src, row.target);\n }\n}\n\n// Resolved edges, for rank and for find's graph expansion.\nexport function linkEdges(db: DatabaseSync): [string, string][] {\n return (db.prepare('SELECT src, dst FROM links WHERE dst IS NOT NULL').all() as Array<{ src: string; dst: string }>).map((r) => [r.src, r.dst]);\n}\n\nexport const links: Feature = {\n name: 'links',\n schema(db) {\n db.exec('CREATE TABLE IF NOT EXISTS links (src TEXT, target TEXT, dst TEXT, PRIMARY KEY (src, target))');\n db.exec('CREATE INDEX IF NOT EXISTS links_dst ON links(dst)');\n },\n extract,\n remove(db, path) {\n db.prepare('DELETE FROM links WHERE src = ?').run(path);\n },\n store(db, path, extracted) {\n const insert = db.prepare('INSERT OR REPLACE INTO links (src, target, dst) VALUES (?, ?, NULL)');\n for (const target of extracted as string[]) insert.run(path, target);\n },\n afterReconcile: resolveAll,\n};\n"],"names":["linkEdges","links","extract","_raw","body","targets","Set","matchAll","m","target","trim","add","test","baseKey","path","posix","basename","replace","toLowerCase","resolveTarget","src","pathSet","byBase","clean","fromSrc","normalize","join","dirname","candidate","has","get","resolveAll","db","files","map","f","relPath","Map","sort","list","push","set","rows","prepare","all","update","row","dst","run","r","name","schema","exec","remove","store","extracted","insert","afterReconcile"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Feature } from './types.js';
2
+ export declare const rank: Feature;
@@ -0,0 +1,2 @@
1
+ import type { Feature } from './types.js';
2
+ export declare const rank: Feature;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "rank", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return rank;
9
+ }
10
+ });
11
+ var _graphts = require("../graph.js");
12
+ var _linksts = require("./links.js");
13
+ function _array_like_to_array(arr, len) {
14
+ if (len == null || len > arr.length) len = arr.length;
15
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
16
+ return arr2;
17
+ }
18
+ function _array_with_holes(arr) {
19
+ if (Array.isArray(arr)) return arr;
20
+ }
21
+ function _iterable_to_array_limit(arr, i) {
22
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
23
+ if (_i == null) return;
24
+ var _arr = [];
25
+ var _n = true;
26
+ var _d = false;
27
+ var _s, _e;
28
+ try {
29
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
30
+ _arr.push(_s.value);
31
+ if (i && _arr.length === i) break;
32
+ }
33
+ } catch (err) {
34
+ _d = true;
35
+ _e = err;
36
+ } finally{
37
+ try {
38
+ if (!_n && _i["return"] != null) _i["return"]();
39
+ } finally{
40
+ if (_d) throw _e;
41
+ }
42
+ }
43
+ return _arr;
44
+ }
45
+ function _non_iterable_rest() {
46
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
47
+ }
48
+ function _sliced_to_array(arr, i) {
49
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
50
+ }
51
+ function _unsupported_iterable_to_array(o, minLen) {
52
+ if (!o) return;
53
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
54
+ var n = Object.prototype.toString.call(o).slice(8, -1);
55
+ if (n === "Object" && o.constructor) n = o.constructor.name;
56
+ if (n === "Map" || n === "Set") return Array.from(n);
57
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
58
+ }
59
+ var rank = {
60
+ name: 'rank',
61
+ schema: function schema(db) {
62
+ var columns = db.prepare('PRAGMA table_info(frontmatter)').all();
63
+ if (!columns.some(function(c) {
64
+ return c.name === '_rank';
65
+ })) db.exec('ALTER TABLE frontmatter ADD COLUMN "_rank" REAL');
66
+ },
67
+ afterReconcile: function afterReconcile(db) {
68
+ var nodes = db.prepare('SELECT "path" FROM frontmatter').all().map(function(r) {
69
+ return r.path;
70
+ });
71
+ var ranks = (0, _graphts.pagerank)(nodes, (0, _linksts.linkEdges)(db));
72
+ var update = db.prepare('UPDATE frontmatter SET "_rank" = ? WHERE "path" = ?');
73
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
74
+ try {
75
+ for(var _iterator = ranks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
76
+ var _step_value = _sliced_to_array(_step.value, 2), path = _step_value[0], value = _step_value[1];
77
+ update.run(value, path);
78
+ }
79
+ } catch (err) {
80
+ _didIteratorError = true;
81
+ _iteratorError = err;
82
+ } finally{
83
+ try {
84
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
85
+ _iterator.return();
86
+ }
87
+ } finally{
88
+ if (_didIteratorError) {
89
+ throw _iteratorError;
90
+ }
91
+ }
92
+ }
93
+ }
94
+ };
95
+ /* 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/features/rank.ts"],"sourcesContent":["import { pagerank } from '../graph.ts';\nimport { linkEdges } from './links.ts';\nimport type { Feature } from './types.ts';\n\n// frontmatter._rank: PageRank over resolved links -- a static \"how load-bearing is this\n// note\" prior. Depends on links (enforced in config.featureEnabled).\n\nexport const rank: Feature = {\n name: 'rank',\n schema(db) {\n const columns = db.prepare('PRAGMA table_info(frontmatter)').all() as Array<{ name: string }>;\n if (!columns.some((c) => c.name === '_rank')) db.exec('ALTER TABLE frontmatter ADD COLUMN \"_rank\" REAL');\n },\n afterReconcile(db) {\n const nodes = (db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path);\n const ranks = pagerank(nodes, linkEdges(db));\n const update = db.prepare('UPDATE frontmatter SET \"_rank\" = ? WHERE \"path\" = ?');\n for (const [path, value] of ranks) update.run(value, path);\n },\n};\n"],"names":["rank","name","schema","db","columns","prepare","all","some","c","exec","afterReconcile","nodes","map","r","path","ranks","pagerank","linkEdges","update","value","run"],"mappings":";;;;+BAOaA;;;eAAAA;;;uBAPY;uBACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMnB,IAAMA,OAAgB;IAC3BC,MAAM;IACNC,QAAAA,SAAAA,OAAOC,EAAE;QACP,IAAMC,UAAUD,GAAGE,OAAO,CAAC,kCAAkCC,GAAG;QAChE,IAAI,CAACF,QAAQG,IAAI,CAAC,SAACC;mBAAMA,EAAEP,IAAI,KAAK;YAAUE,GAAGM,IAAI,CAAC;IACxD;IACAC,gBAAAA,SAAAA,eAAeP,EAAE;QACf,IAAMQ,QAAQ,AAACR,GAAGE,OAAO,CAAC,kCAAkCC,GAAG,GAA+BM,GAAG,CAAC,SAACC;mBAAMA,EAAEC,IAAI;;QAC/G,IAAMC,QAAQC,IAAAA,iBAAQ,EAACL,OAAOM,IAAAA,kBAAS,EAACd;QACxC,IAAMe,SAASf,GAAGE,OAAO,CAAC;YACrB,kCAAA,2BAAA;;YAAL,QAAK,YAAuBU,0BAAvB,SAAA,6BAAA,QAAA,yBAAA;gBAAA,mCAAA,iBAAOD,uBAAMK;gBAAiBD,OAAOE,GAAG,CAACD,OAAOL;;;YAAhD;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;IACP;AACF"}
@@ -0,0 +1,9 @@
1
+ import type { Feature } from './types.js';
2
+ export interface Section {
3
+ level: number;
4
+ heading: string;
5
+ startLine: number;
6
+ endLine: number;
7
+ tokens: number;
8
+ }
9
+ export declare const sections: Feature;
@@ -0,0 +1,9 @@
1
+ import type { Feature } from './types.js';
2
+ export interface Section {
3
+ level: number;
4
+ heading: string;
5
+ startLine: number;
6
+ endLine: number;
7
+ tokens: number;
8
+ }
9
+ export declare const sections: Feature;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "sections", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return sections;
9
+ }
10
+ });
11
+ // Headings outside fenced code blocks.
12
+ function extract(raw) {
13
+ var lines = raw.split('\n');
14
+ var found = [];
15
+ var inFence = false;
16
+ for(var i = 0; i < lines.length; i++){
17
+ if (/^(```|~~~)/.test(lines[i])) {
18
+ inFence = !inFence;
19
+ continue;
20
+ }
21
+ if (inFence) continue;
22
+ var m = lines[i].match(/^(#{1,6}) +(.*)/);
23
+ if (m) found.push({
24
+ level: m[1].length,
25
+ heading: m[2].trim(),
26
+ startLine: i + 1,
27
+ endLine: lines.length,
28
+ tokens: 0
29
+ });
30
+ }
31
+ for(var s = 0; s < found.length; s++){
32
+ if (s + 1 < found.length) found[s].endLine = found[s + 1].startLine - 1;
33
+ var chars = lines.slice(found[s].startLine - 1, found[s].endLine).join('\n').length;
34
+ found[s].tokens = Math.ceil(chars / 4);
35
+ }
36
+ return found;
37
+ }
38
+ var sections = {
39
+ name: 'sections',
40
+ schema: function schema(db) {
41
+ db.exec('CREATE TABLE IF NOT EXISTS sections ("path" TEXT, idx INTEGER, level INTEGER, heading TEXT, start_line INTEGER, end_line INTEGER, tokens INTEGER, PRIMARY KEY ("path", idx))');
42
+ },
43
+ extract: extract,
44
+ remove: function remove(db, path) {
45
+ db.prepare('DELETE FROM sections WHERE "path" = ?').run(path);
46
+ },
47
+ store: function store(db, path, extracted) {
48
+ var insert = db.prepare('INSERT INTO sections ("path", idx, level, heading, start_line, end_line, tokens) VALUES (?, ?, ?, ?, ?, ?, ?)');
49
+ extracted.forEach(function(s, idx) {
50
+ return insert.run(path, idx, s.level, s.heading, s.startLine, s.endLine, s.tokens);
51
+ });
52
+ }
53
+ };
54
+ /* 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/features/sections.ts"],"sourcesContent":["import type { Feature } from './types.ts';\n\n// sections(path, idx, level, heading, start_line, end_line, tokens): the heading outline,\n// 1-indexed over the raw file so a row is a direct Read range; tokens is a chars/4 estimate.\n\nexport interface Section {\n level: number;\n heading: string;\n startLine: number;\n endLine: number;\n tokens: number;\n}\n\n// Headings outside fenced code blocks.\nfunction extract(raw: string): Section[] {\n const lines = raw.split('\\n');\n const found: Section[] = [];\n let inFence = false;\n for (let i = 0; i < lines.length; i++) {\n if (/^(```|~~~)/.test(lines[i])) {\n inFence = !inFence;\n continue;\n }\n if (inFence) continue;\n const m = lines[i].match(/^(#{1,6}) +(.*)/);\n if (m) found.push({ level: m[1].length, heading: m[2].trim(), startLine: i + 1, endLine: lines.length, tokens: 0 });\n }\n for (let s = 0; s < found.length; s++) {\n if (s + 1 < found.length) found[s].endLine = found[s + 1].startLine - 1;\n const chars = lines.slice(found[s].startLine - 1, found[s].endLine).join('\\n').length;\n found[s].tokens = Math.ceil(chars / 4);\n }\n return found;\n}\n\nexport const sections: Feature = {\n name: 'sections',\n schema(db) {\n db.exec(`CREATE TABLE IF NOT EXISTS sections (\"path\" TEXT, idx INTEGER, level INTEGER, heading TEXT, start_line INTEGER, end_line INTEGER, tokens INTEGER, PRIMARY KEY (\"path\", idx))`);\n },\n extract,\n remove(db, path) {\n db.prepare('DELETE FROM sections WHERE \"path\" = ?').run(path);\n },\n store(db, path, extracted) {\n const insert = db.prepare('INSERT INTO sections (\"path\", idx, level, heading, start_line, end_line, tokens) VALUES (?, ?, ?, ?, ?, ?, ?)');\n (extracted as Section[]).forEach((s, idx) => insert.run(path, idx, s.level, s.heading, s.startLine, s.endLine, s.tokens));\n },\n};\n"],"names":["sections","extract","raw","lines","split","found","inFence","i","length","test","m","match","push","level","heading","trim","startLine","endLine","tokens","s","chars","slice","join","Math","ceil","name","schema","db","exec","remove","path","prepare","run","store","extracted","insert","forEach","idx"],"mappings":";;;;+BAmCaA;;;eAAAA;;;AAtBb,uCAAuC;AACvC,SAASC,QAAQC,GAAW;IAC1B,IAAMC,QAAQD,IAAIE,KAAK,CAAC;IACxB,IAAMC,QAAmB,EAAE;IAC3B,IAAIC,UAAU;IACd,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,MAAMK,MAAM,EAAED,IAAK;QACrC,IAAI,aAAaE,IAAI,CAACN,KAAK,CAACI,EAAE,GAAG;YAC/BD,UAAU,CAACA;YACX;QACF;QACA,IAAIA,SAAS;QACb,IAAMI,IAAIP,KAAK,CAACI,EAAE,CAACI,KAAK,CAAC;QACzB,IAAID,GAAGL,MAAMO,IAAI,CAAC;YAAEC,OAAOH,CAAC,CAAC,EAAE,CAACF,MAAM;YAAEM,SAASJ,CAAC,CAAC,EAAE,CAACK,IAAI;YAAIC,WAAWT,IAAI;YAAGU,SAASd,MAAMK,MAAM;YAAEU,QAAQ;QAAE;IACnH;IACA,IAAK,IAAIC,IAAI,GAAGA,IAAId,MAAMG,MAAM,EAAEW,IAAK;QACrC,IAAIA,IAAI,IAAId,MAAMG,MAAM,EAAEH,KAAK,CAACc,EAAE,CAACF,OAAO,GAAGZ,KAAK,CAACc,IAAI,EAAE,CAACH,SAAS,GAAG;QACtE,IAAMI,QAAQjB,MAAMkB,KAAK,CAAChB,KAAK,CAACc,EAAE,CAACH,SAAS,GAAG,GAAGX,KAAK,CAACc,EAAE,CAACF,OAAO,EAAEK,IAAI,CAAC,MAAMd,MAAM;QACrFH,KAAK,CAACc,EAAE,CAACD,MAAM,GAAGK,KAAKC,IAAI,CAACJ,QAAQ;IACtC;IACA,OAAOf;AACT;AAEO,IAAML,WAAoB;IAC/ByB,MAAM;IACNC,QAAAA,SAAAA,OAAOC,EAAE;QACPA,GAAGC,IAAI,CAAC;IACV;IACA3B,SAAAA;IACA4B,QAAAA,SAAAA,OAAOF,EAAE,EAAEG,IAAI;QACbH,GAAGI,OAAO,CAAC,yCAAyCC,GAAG,CAACF;IAC1D;IACAG,OAAAA,SAAAA,MAAMN,EAAE,EAAEG,IAAI,EAAEI,SAAS;QACvB,IAAMC,SAASR,GAAGI,OAAO,CAAC;QACzBG,UAAwBE,OAAO,CAAC,SAACjB,GAAGkB;mBAAQF,OAAOH,GAAG,CAACF,MAAMO,KAAKlB,EAAEN,KAAK,EAAEM,EAAEL,OAAO,EAAEK,EAAEH,SAAS,EAAEG,EAAEF,OAAO,EAAEE,EAAED,MAAM;;IACzH;AACF"}
@@ -0,0 +1,11 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { FeatureName } from '../config.js';
3
+ import type { FileStat } from '../scan.js';
4
+ export interface Feature {
5
+ name: FeatureName;
6
+ schema(db: DatabaseSync): void;
7
+ extract?(raw: string, body: string): unknown;
8
+ remove?(db: DatabaseSync, path: string): void;
9
+ store?(db: DatabaseSync, path: string, extracted: unknown): void;
10
+ afterReconcile?(db: DatabaseSync, files: FileStat[]): void;
11
+ }
@@ -0,0 +1,11 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { FeatureName } from '../config.js';
3
+ import type { FileStat } from '../scan.js';
4
+ export interface Feature {
5
+ name: FeatureName;
6
+ schema(db: DatabaseSync): void;
7
+ extract?(raw: string, body: string): unknown;
8
+ remove?(db: DatabaseSync, path: string): void;
9
+ store?(db: DatabaseSync, path: string, extracted: unknown): void;
10
+ afterReconcile?(db: DatabaseSync, files: FileStat[]): void;
11
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ /* 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":[],"names":[],"mappings":""}