sensemaking 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -39
- package/dist/cjs/cli/check.js +24 -43
- package/dist/cjs/cli/check.js.map +1 -1
- package/dist/cjs/cli/index.js +2 -2
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/named.js +18 -8
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/search.d.cts +3 -0
- package/dist/cjs/cli/search.d.ts +3 -0
- package/dist/cjs/cli/{find.js → search.js} +7 -5
- package/dist/cjs/cli/search.js.map +1 -0
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/status.js +29 -12
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/cli/types.d.cts +3 -1
- package/dist/cjs/cli/types.d.ts +3 -1
- package/dist/cjs/cli.js +25 -5
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands.d.cts +11 -2
- package/dist/cjs/commands.d.ts +11 -2
- package/dist/cjs/commands.js +86 -21
- package/dist/cjs/commands.js.map +1 -1
- package/dist/cjs/config.d.cts +41 -14
- package/dist/cjs/config.d.ts +41 -14
- package/dist/cjs/config.js +448 -160
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/db.d.cts +1 -1
- package/dist/cjs/db.d.ts +1 -1
- package/dist/cjs/db.js +208 -62
- package/dist/cjs/db.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.js +12 -2
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/types.d.cts +2 -1
- package/dist/cjs/features/types.d.ts +2 -1
- package/dist/cjs/index.d.cts +3 -3
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +6 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output.d.cts +15 -0
- package/dist/cjs/output.d.ts +15 -0
- package/dist/cjs/output.js +26 -5
- package/dist/cjs/output.js.map +1 -1
- package/dist/cjs/scan.d.cts +3 -0
- package/dist/cjs/scan.d.ts +3 -0
- package/dist/cjs/scan.js +84 -4
- package/dist/cjs/scan.js.map +1 -1
- package/dist/esm/cli/check.js +20 -41
- package/dist/esm/cli/check.js.map +1 -1
- package/dist/esm/cli/index.js +1 -1
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/named.js +17 -9
- package/dist/esm/cli/named.js.map +1 -1
- package/dist/esm/cli/search.d.ts +3 -0
- package/dist/esm/cli/search.js +16 -0
- package/dist/esm/cli/search.js.map +1 -0
- package/dist/esm/cli/shared.js +1 -1
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/status.js +10 -10
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/cli/types.d.ts +3 -1
- package/dist/esm/cli/types.js.map +1 -1
- package/dist/esm/cli.js +20 -4
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands.d.ts +11 -2
- package/dist/esm/commands.js +76 -24
- package/dist/esm/commands.js.map +1 -1
- package/dist/esm/config.d.ts +41 -14
- package/dist/esm/config.js +354 -114
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/db.d.ts +1 -1
- package/dist/esm/db.js +53 -6
- package/dist/esm/db.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.js +12 -2
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/features/types.d.ts +2 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output.d.ts +15 -0
- package/dist/esm/output.js +19 -5
- package/dist/esm/output.js.map +1 -1
- package/dist/esm/scan.d.ts +3 -0
- package/dist/esm/scan.js +32 -4
- package/dist/esm/scan.js.map +1 -1
- package/package.json +9 -3
- package/schema.json +74 -54
- package/skills/sense/EXAMPLES.md +8 -6
- package/skills/sense/SKILL.md +51 -48
- package/skills/sense-setup/EXAMPLES.md +121 -0
- package/skills/sense-setup/SKILL.md +71 -66
- package/dist/cjs/cli/find.d.cts +0 -3
- package/dist/cjs/cli/find.d.ts +0 -3
- package/dist/cjs/cli/find.js.map +0 -1
- package/dist/esm/cli/find.d.ts +0 -3
- package/dist/esm/cli/find.js +0 -14
- package/dist/esm/cli/find.js.map +0 -1
package/dist/cjs/db.js.map
CHANGED
|
@@ -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 { featureSignature, STATE_DIR } from './config.ts';\nimport { SenseError } from './errors.ts';\nimport { activeFeatures } from './features/index.ts';\nimport type { ReconcileDelta } from './features/types.ts';\nimport { progress } from './progress.ts';\nimport type { ParsedDoc } from './scan.ts';\nimport { listFiles, parseFile, RESERVED_COLUMNS } from './scan.ts';\n\n// path/_mtime/_size are core: every reparse legitimately rewrites them. Every other\n// RESERVED_COLUMNS entry that shows up as a real frontmatter column (currently only\n// rank's `_rank`) is feature-owned -- scan.ts already refuses to let frontmatter set it,\n// so it must never appear in the upsert below, or a reparse would blow its last computed\n// value away with NULL on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_size']);\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`.\n// 5: frontmatter upsert is ON CONFLICT UPDATE (was OR REPLACE) so rowid is stable, and\n// content is coupled to that rowid instead of an UNINDEXED path column (was: 4 -- scalars\n// store as INTEGER/REAL/TEXT by YAML type).\nexport const SCHEMA_VERSION = '5';\n\n// SQLite's compile-time SQLITE_MAX_COLUMN, default 2000 (https://www.sqlite.org/limits.html).\nconst MAX_FRONTMATTER_COLUMNS = 2000;\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', featureSignature(cfg));\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 // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n let parsedCount = 0;\n for (const file of toReparse) {\n const { doc, warnings: fileWarnings } = parseFile(file, features);\n report.tick(++parsedCount);\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 report.finish();\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: SQLite's own failure past this point is a raw\n // \"too many columns on sqlite_altertab_frontmatter\" with no indication of the boundary or the levers.\n if (allColumns.length > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError(\n 'COLUMN_LIMIT',\n `frontmatter would need ${allColumns.length} columns, crossing SQLite's compile-time SQLITE_MAX_COLUMN limit (default ${MAX_FRONTMATTER_COLUMNS}; see https://www.sqlite.org/limits.html). Narrow scan.include so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`\n );\n }\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // content rows are coupled to that rowid below.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n\n const txStart = Date.now();\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`; coupled to the\n // frontmatter rowid (indexed via its PRIMARY KEY) instead of the UNINDEXED `path`\n // column, which a per-row DELETE would otherwise scan the whole table to find.\n const delBody = db.prepare(`DELETE FROM content WHERE rowid = (SELECT rowid FROM frontmatter WHERE \"path\" = ?)`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n // content delete must run first: it looks up the frontmatter rowid by path, which\n // the frontmatter delete below would otherwise have already removed.\n delBody.run(path);\n del.run(path);\n for (const feature of features) feature.remove?.(db, path, delta);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(`INSERT INTO content (rowid, title, summary, text, \"path\") VALUES ((SELECT rowid FROM frontmatter WHERE \"path\" = ?), ?, ?, ?, ?)`);\n for (const doc of parsedDocs) {\n const values = writableColumns.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 // Frontmatter upsert first: content's rowid lookup below depends on this row existing.\n insert.run(...values);\n // Delete-before-insert only for docs that have rows: an FTS5 DELETE by rowid on a\n // cold build (empty table, nothing to delete) is wasted work, and doing it\n // unconditionally previously made the crawl quadratic when it scanned by column --\n // measured 4x time per note-count doubling at 13k/26k notes.\n if (existing.has(doc.relPath)) {\n delBody.run(doc.relPath);\n for (const feature of features) feature.remove?.(db, doc.relPath, delta);\n }\n insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath);\n for (const feature of features) feature.store?.(db, doc.relPath, doc.extracted[feature.name], delta);\n }\n }\n for (const feature of features) feature.afterReconcile?.(db, delta);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n // Reconcile's own write-transaction duration, for open()'s derived busy_timeout (F):\n // keep the observed max so a big watcher reconcile's lock hold is what the next open bounds its wait against.\n const durationMs = Date.now() - txStart;\n const prevRaw = getMeta(db, 'reconcile_max_ms');\n // -1, not 0, so a genuinely 0ms first reconcile (sub-millisecond, common on a tiny tree)\n // still gets recorded instead of losing to the \"nothing recorded yet\" default.\n const prevMax = prevRaw === null ? -1 : Number(prevRaw);\n if (durationMs > prevMax) setMeta(db, 'reconcile_max_ms', String(durationMs));\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 // Covers a concurrent watcher's bulk reconcile: the write transaction for 500 changed\n // files measures ~5s at 26k notes, so 5s expired exactly at the boundary and queries\n // racing the watcher got SQLITE_BUSY. 30s bounds the wait at ~3x the largest measured\n // reconcile; a query that outwaits it still fails loudly.\n db.exec('PRAGMA busy_timeout = 30000');\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 = featureSignature(cfg);\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\n // Derived from reconcile's own recorded max (F): 3x the largest reconcile this cache has\n // ever held its write transaction for, floored at the 30s default and capped at 10min so\n // one pathological build can't pin every later open to an unbounded wait. Installed\n // before reconcile() below -- this open's own reconcile is exactly the operation that\n // races a concurrent watcher's transaction and needs the derived wait.\n const recordedMaxMs = Number(getMeta(db, 'reconcile_max_ms') ?? '0');\n db.exec(`PRAGMA busy_timeout = ${Math.min(Math.max(30000, 3 * recordedMaxMs), 600_000)}`);\n\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","CORE_FRONTMATTER_COLUMNS","Set","MAX_FRONTMATTER_COLUMNS","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","map","r","ensureSchema","cfg","exec","activeFeatures","feature","schema","featureSignature","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","report","progress","parsedCount","file","parseFile","doc","fileWarnings","tick","push","Object","keys","data","add","finish","allColumns","SenseError","writableColumns","c","RESERVED_COLUMNS","insertSql","added","delta","reparsed","d","txStart","Date","now","col","delBody","del","remove","insert","insertBody","values","search","title","summary","text","store","extracted","afterReconcile","err","durationMs","prevRaw","prevMax","Number","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","version","wantFeatures","close","rmSync","force","recordedMaxMs","Math","min","max"],"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 { featureSignature, STATE_DIR } from './config.ts';\nimport { SenseError } from './errors.ts';\nimport { activeFeatures } from './features/index.ts';\nimport type { ReconcileDelta } from './features/types.ts';\nimport { progress } from './progress.ts';\nimport type { ParsedDoc } from './scan.ts';\nimport { listFiles, parseFile, RESERVED_COLUMNS } from './scan.ts';\n\n// path/_mtime/_size are core: every reparse legitimately rewrites them. Every other\n// RESERVED_COLUMNS entry that shows up as a real frontmatter column (currently only\n// rank's `_rank`) is feature-owned -- scan.ts already refuses to let frontmatter set it,\n// so it must never appear in the upsert below, or a reparse would blow its last computed\n// value away with NULL on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_size']);\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`.\n// 7: presets replace layers -- frontmatter drops the `layer` column, a new\n// preset_files(preset, path) table tracks per-preset coverage for status/map (was: 6,\n// frontmatter gains the `layer` column).\nexport const SCHEMA_VERSION = '8';\n\n// SQLite's compile-time SQLITE_MAX_COLUMN, default 2000 (https://www.sqlite.org/limits.html).\nconst MAX_FRONTMATTER_COLUMNS = 2000;\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 // Coverage, not ownership: a path can appear under several presets. Rebuilt per-file\n // alongside frontmatter/content at reconcile so status/map can report matched/embedded\n // counts per preset without recomputing globs at read time.\n // path leads the PK so the per-doc delete in reconcile is an index hit -- keyed the other\n // way it scans the whole table per doc, which made cold builds quadratic (measured 3x cost\n // per note-count doubling at 13k/26k). Coverage-by-preset reads get their own index.\n db.exec(`CREATE TABLE IF NOT EXISTS preset_files (\"path\" TEXT, preset TEXT, PRIMARY KEY (\"path\", preset))`);\n db.exec('CREATE INDEX IF NOT EXISTS preset_files_preset ON preset_files(preset)');\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', featureSignature(cfg));\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 // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n let parsedCount = 0;\n for (const file of toReparse) {\n // A doc only gets extract/store from features that apply to it (currently: embed, via\n // FileStat.embed -- true iff a covering preset has semantic on).\n const fileFeatures = features.filter((feature) => !feature.enabledForFile || feature.enabledForFile(cfg, file));\n const { doc, warnings: fileWarnings } = parseFile(file, fileFeatures);\n report.tick(++parsedCount);\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 report.finish();\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: SQLite's own failure past this point is a raw\n // \"too many columns on sqlite_altertab_frontmatter\" with no indication of the boundary or the levers.\n if (allColumns.length > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError(\n 'COLUMN_LIMIT',\n `frontmatter would need ${allColumns.length} columns, crossing SQLite's compile-time SQLITE_MAX_COLUMN limit (default ${MAX_FRONTMATTER_COLUMNS}; see https://www.sqlite.org/limits.html). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`\n );\n }\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // content rows are coupled to that rowid below.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n\n const txStart = Date.now();\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`; coupled to the\n // frontmatter rowid (indexed via its PRIMARY KEY) instead of the UNINDEXED `path`\n // column, which a per-row DELETE would otherwise scan the whole table to find.\n const delBody = db.prepare(`DELETE FROM content WHERE rowid = (SELECT rowid FROM frontmatter WHERE \"path\" = ?)`);\n const delPresetFiles = db.prepare(`DELETE FROM preset_files WHERE \"path\" = ?`);\n const insertPresetFile = db.prepare(`INSERT INTO preset_files (\"path\", preset) VALUES (?, ?)`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n // content delete must run first: it looks up the frontmatter rowid by path, which\n // the frontmatter delete below would otherwise have already removed.\n delBody.run(path);\n del.run(path);\n delPresetFiles.run(path);\n for (const feature of features) feature.remove?.(db, path, delta);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(`INSERT INTO content (rowid, title, summary, text, \"path\") VALUES ((SELECT rowid FROM frontmatter WHERE \"path\" = ?), ?, ?, ?, ?)`);\n for (const doc of parsedDocs) {\n const values = writableColumns.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 // Frontmatter upsert first: content's rowid lookup below depends on this row existing.\n insert.run(...values);\n // Delete-before-insert only for docs that have rows: an FTS5 DELETE by rowid on a\n // cold build (empty table, nothing to delete) is wasted work, and doing it\n // unconditionally previously made the crawl quadratic when it scanned by column --\n // measured 4x time per note-count doubling at 13k/26k notes.\n if (existing.has(doc.relPath)) {\n delBody.run(doc.relPath);\n for (const feature of features) feature.remove?.(db, doc.relPath, delta);\n }\n insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath);\n // Coverage is glob-derived, not content-derived, but only reparsed/added docs are\n // touched here: a preset edit changes featureSignature and forces a full rebuild\n // (see open()), so an unchanged doc's coverage is already correct on disk. New docs\n // have no rows to clear -- skipping the delete keeps cold builds linear.\n if (existing.has(doc.relPath)) delPresetFiles.run(doc.relPath);\n for (const presetName of doc.presets) insertPresetFile.run(doc.relPath, presetName);\n for (const feature of features) feature.store?.(db, doc.relPath, doc.extracted[feature.name], delta);\n }\n }\n for (const feature of features) feature.afterReconcile?.(db, delta);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n // Reconcile's own write-transaction duration, for open()'s derived busy_timeout (F):\n // keep the observed max so a big watcher reconcile's lock hold is what the next open bounds its wait against.\n const durationMs = Date.now() - txStart;\n const prevRaw = getMeta(db, 'reconcile_max_ms');\n // -1, not 0, so a genuinely 0ms first reconcile (sub-millisecond, common on a tiny tree)\n // still gets recorded instead of losing to the \"nothing recorded yet\" default.\n const prevMax = prevRaw === null ? -1 : Number(prevRaw);\n if (durationMs > prevMax) setMeta(db, 'reconcile_max_ms', String(durationMs));\n\n return { parsed: parsedDocs.length, warnings };\n}\n\n// Names what moved between two feature signatures (see config.featureSignature's format:\n// global features, embed provider, then one segment per preset) for the rebuild notice.\nfunction signatureDiff(before: string, after: string): string {\n // Segment keys: `features`, `embed`, `preset:<name>` (config.featureSignature's format).\n const keyOf = (part: string) => (part.startsWith('preset:') ? part.split(':').slice(0, 2).join(':') : part.split(':')[0]);\n const parse = (sig: string) => new Map(sig.split('|').map((part) => [keyOf(part), part]));\n const a = parse(before);\n const b = parse(after);\n const changed = new Set<string>();\n for (const [key, val] of b) if (a.get(key) !== val) changed.add(key);\n for (const key of a.keys()) if (!b.has(key)) changed.add(key);\n const label = (key: string) => (key === 'embed' ? 'embed settings' : key.startsWith('preset:') ? `preset \"${key.slice(7)}\"` : 'features');\n return changed.size === 0 ? 'features' : [...changed].map(label).join(', ');\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 // Covers a concurrent watcher's bulk reconcile: the write transaction for 500 changed\n // files measures ~5s at 26k notes, so 5s expired exactly at the boundary and queries\n // racing the watcher got SQLITE_BUSY. 30s bounds the wait at ~3x the largest measured\n // reconcile; a query that outwaits it still fails loudly.\n db.exec('PRAGMA busy_timeout = 30000');\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 = featureSignature(cfg);\n if ((version !== null && version !== SCHEMA_VERSION) || (features !== null && features !== wantFeatures)) {\n // Indexing derives from presets, so a config edit rebuilding the cache must say so and\n // name what changed -- silent rebuilds make derived indexing look like a hang or a bug.\n if (version !== null && version !== SCHEMA_VERSION) {\n console.error('sense: cache format changed (new sensemaking version); rebuilding the index');\n } else {\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) rebuilds the index`);\n }\n db.close();\n rmSync(stateDir, { recursive: true, force: true });\n return open(cfg);\n }\n\n ensureSchema(db, cfg);\n\n // Derived from reconcile's own recorded max (F): 3x the largest reconcile this cache has\n // ever held its write transaction for, floored at the 30s default and capped at 10min so\n // one pathological build can't pin every later open to an unbounded wait. Installed\n // before reconcile() below -- this open's own reconcile is exactly the operation that\n // races a concurrent watcher's transaction and needs the derived wait.\n const recordedMaxMs = Number(getMeta(db, 'reconcile_max_ms') ?? '0');\n db.exec(`PRAGMA busy_timeout = ${Math.min(Math.max(30000, 3 * recordedMaxMs), 600_000)}`);\n\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","CORE_FRONTMATTER_COLUMNS","Set","MAX_FRONTMATTER_COLUMNS","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","map","r","ensureSchema","cfg","exec","activeFeatures","feature","schema","featureSignature","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","report","progress","parsedCount","file","fileFeatures","enabledForFile","parseFile","doc","fileWarnings","tick","push","Object","keys","data","add","finish","allColumns","SenseError","writableColumns","c","RESERVED_COLUMNS","insertSql","added","delta","reparsed","d","txStart","Date","now","col","delBody","delPresetFiles","insertPresetFile","del","remove","insert","insertBody","values","search","title","summary","text","presets","presetName","store","extracted","afterReconcile","err","durationMs","prevRaw","prevMax","Number","signatureDiff","before","after","keyOf","part","slice","sig","a","b","changed","val","label","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","version","wantFeatures","console","error","close","rmSync","force","recordedMaxMs","Math","min","max"],"mappings":"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"}
|
package/dist/cjs/errors.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT';
|
|
1
|
+
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT' | 'PRESET_UNKNOWN';
|
|
2
2
|
export declare class SenseError extends Error {
|
|
3
3
|
code: SenseErrorCode;
|
|
4
4
|
constructor(code: SenseErrorCode, message: string);
|
package/dist/cjs/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT';
|
|
1
|
+
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT' | 'PRESET_UNKNOWN';
|
|
2
2
|
export declare class SenseError extends Error {
|
|
3
3
|
code: SenseErrorCode;
|
|
4
4
|
constructor(code: SenseErrorCode, message: string);
|
package/dist/cjs/errors.js.map
CHANGED
|
@@ -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_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT';\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_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT' | 'PRESET_UNKNOWN';\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"}
|
|
@@ -322,11 +322,17 @@ var embed = {
|
|
|
322
322
|
remove: function remove(db, path) {
|
|
323
323
|
db.prepare('DELETE FROM embeddings WHERE "path" = ?').run(path);
|
|
324
324
|
},
|
|
325
|
+
// A doc covered only by semantic-false presets never had extract() run for it (db.ts's
|
|
326
|
+
// per-file filter skips it), so extracted is undefined here -- store nothing, i.e. no rows.
|
|
325
327
|
store: function store(db, path, extracted) {
|
|
328
|
+
if (!extracted) return;
|
|
326
329
|
var insert = db.prepare('INSERT INTO embeddings ("path", chunk, start_line, end_line, scale, vector) VALUES (?, ?, ?, ?, NULL, NULL)');
|
|
327
330
|
extracted.forEach(function(c, idx) {
|
|
328
331
|
return insert.run(path, idx, c.startLine, c.endLine);
|
|
329
332
|
});
|
|
333
|
+
},
|
|
334
|
+
enabledForFile: function enabledForFile(_cfg, file) {
|
|
335
|
+
return file.embed;
|
|
330
336
|
}
|
|
331
337
|
};
|
|
332
338
|
// --- static type: Model2Vec safetensors + pure-JS tokenizer, model cached in ~/.cache ---
|
|
@@ -567,7 +573,7 @@ var providers = new Map();
|
|
|
567
573
|
function getProvider(cfg) {
|
|
568
574
|
var _e_url;
|
|
569
575
|
var e = (0, _configts.embedConfig)(cfg);
|
|
570
|
-
if (!e) throw new _errorsts.SenseError('EMBED_DISABLED', 'semantic
|
|
576
|
+
if (!e) throw new _errorsts.SenseError('EMBED_DISABLED', 'semantic search needs at least one preset with vectors on (semantic !== false); every declared preset in sense.config.json has "semantic": false');
|
|
571
577
|
var sig = "".concat(e.type, ":").concat(e.model, ":").concat((_e_url = e.url) !== null && _e_url !== void 0 ? _e_url : '');
|
|
572
578
|
var p = providers.get(sig);
|
|
573
579
|
if (!p) {
|
|
@@ -676,11 +682,15 @@ function embedPending(db, cfg, baseDir) {
|
|
|
676
682
|
_step_value = _sliced_to_array(_step1.value, 2), path = _step_value[0], chunkIdxs = _step_value[1];
|
|
677
683
|
chunks = void 0;
|
|
678
684
|
try {
|
|
685
|
+
// presets/embed are irrelevant here -- re-deriving chunk text for a doc that already
|
|
686
|
+
// has embeddings rows means it was covered by a semantic-on preset at reconcile time.
|
|
679
687
|
chunks = (0, _scants.parseFile)({
|
|
680
688
|
relPath: path,
|
|
681
689
|
absPath: (0, _nodepath.join)(baseDir, path),
|
|
682
690
|
mtimeMs: 0,
|
|
683
|
-
size: 0
|
|
691
|
+
size: 0,
|
|
692
|
+
presets: [],
|
|
693
|
+
embed: true
|
|
684
694
|
}, [
|
|
685
695
|
embed
|
|
686
696
|
]).doc.extracted.embed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/embed.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { Config, ResolvedConfig } from '../config.ts';\nimport { embedConfig } from '../config.ts';\nimport { SenseError } from '../errors.ts';\nimport { progress } from '../progress.ts';\nimport { parseFile } from '../scan.ts';\nimport type { Feature } from './types.ts';\n\n// embeddings(path, chunk, start_line, end_line, scale, vector): heading-based chunks,\n// int8 vectors with a per-vector dequantization scale, vector NULL = not yet embedded.\n// Reconcile stores dirty rows inside its transaction; embedding tops up on the next\n// semantic query (embedPending), so staleness costs recall, never correctness.\n\n// Storage lever fixed by the bake-off (BENCHMARKING.md): int8 at 256 dims is\n// quality-free vs f32-512 when fused. Queries stay f32 at the same dims.\nconst STORE_DIMS = 256;\nconst BATCH = 64;\n\nexport interface EmbedProvider {\n id: string; // model identity; participates in the cache key, change -> re-embed\n dims: number;\n embed(texts: string[]): Promise<Float32Array[]>;\n}\n\ninterface Chunk {\n startLine: number;\n endLine: number;\n text: string;\n}\n\n// Deterministic chunker used at reconcile (line ranges stored) and at embed time (text\n// re-derived from the file -- chunk text is never stored). Heading-delimited with the\n// preamble kept; whole file when no headings. The title/summary prefix mirrors the\n// bm25 column weighting.\nfunction chunksOf(raw: string, search?: { title: string; summary: string }): Chunk[] {\n const lines = raw.split('\\n');\n const starts: number[] = [];\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 && /^#{1,6} +/.test(lines[i])) starts.push(i + 1);\n }\n const bounds = starts.length === 0 ? [1] : starts[0] > 1 ? [1, ...starts] : starts;\n const prefix = [search?.title, search?.summary].filter(Boolean).join('\\n');\n const chunks: Chunk[] = [];\n bounds.forEach((start, i) => {\n const end = i + 1 < bounds.length ? bounds[i + 1] - 1 : lines.length;\n const text = lines\n .slice(start - 1, end)\n .join('\\n')\n .trim();\n if (text.length > 0) chunks.push({ startLine: start, endLine: end, text: prefix ? `${prefix}\\n${text}` : text });\n });\n return chunks;\n}\n\nexport const embed: Feature = {\n name: 'embed',\n schema(db) {\n db.exec(`CREATE TABLE IF NOT EXISTS embeddings (\"path\" TEXT, chunk INTEGER, start_line INTEGER, end_line INTEGER, scale REAL, vector BLOB, PRIMARY KEY (\"path\", chunk))`);\n },\n extract(raw, _body, search) {\n return chunksOf(raw, search);\n },\n remove(db, path) {\n db.prepare('DELETE FROM embeddings WHERE \"path\" = ?').run(path);\n },\n store(db, path, extracted) {\n const insert = db.prepare('INSERT INTO embeddings (\"path\", chunk, start_line, end_line, scale, vector) VALUES (?, ?, ?, ?, NULL, NULL)');\n (extracted as Chunk[]).forEach((c, idx) => insert.run(path, idx, c.startLine, c.endLine));\n },\n};\n\n// --- static type: Model2Vec safetensors + pure-JS tokenizer, model cached in ~/.cache ---\n// Encode convention from model2vec/model.py: no special tokens, drop unk ids, mean-pool,\n// L2-normalize.\n\nfunction fetchToFile(url: string, dest: string): Promise<void> {\n return fetch(url).then(async (res) => {\n if (!res.ok) throw new SenseError('EMBED_MODEL', `model download failed: ${url} -> HTTP ${res.status}`);\n writeFileSync(`${dest}.part`, Buffer.from(await res.arrayBuffer()));\n renameSync(`${dest}.part`, dest);\n });\n}\n\nasync function staticProvider(model: string): Promise<EmbedProvider> {\n let dir = model;\n if (!existsSync(join(dir, 'model.safetensors'))) {\n dir = join(homedir(), '.cache', 'sensemaking', 'models', model.replace(/\\//g, '--'));\n mkdirSync(dir, { recursive: true });\n for (const file of ['model.safetensors', 'tokenizer.json']) {\n if (!existsSync(join(dir, file))) {\n console.error(`fetching ${model}/${file} into ${dir} (once; delete to refetch)`);\n await fetchToFile(`https://huggingface.co/${model}/resolve/main/${file}`, join(dir, file));\n }\n }\n }\n\n const raw = readFileSync(join(dir, 'model.safetensors'));\n const headerLen = Number(raw.readBigUInt64LE(0));\n const header = JSON.parse(raw.subarray(8, 8 + headerLen).toString('utf8')) as Record<string, { dtype: string; shape: number[]; data_offsets: number[] }>;\n const entry = Object.entries(header).find(([k]) => k !== '__metadata__');\n if (!entry || entry[1].dtype !== 'F32') throw new SenseError('EMBED_MODEL', `${model}: expected an F32 safetensors matrix`);\n const spec = entry[1];\n const dims = spec.shape[1];\n const dataStart = raw.byteOffset + 8 + headerLen + spec.data_offsets[0];\n const matrix = dataStart % 4 === 0 ? new Float32Array(raw.buffer, dataStart, spec.shape[0] * dims) : new Float32Array(raw.buffer.slice(dataStart, dataStart + spec.shape[0] * dims * 4));\n\n const tokenizerJson = JSON.parse(readFileSync(join(dir, 'tokenizer.json'), 'utf8'));\n // Lazy import: the tokenizer loads only on the semantic path, never at CLI startup.\n const { Tokenizer } = await import('@huggingface/tokenizers');\n const tok = new Tokenizer(tokenizerJson, {});\n const unkId = tokenizerJson.model?.vocab?.[tokenizerJson.model?.unk_token] ?? -1;\n\n function one(text: string): Float32Array {\n // The tokenizer yields undefined (not the unk id) for tokens outside the vocab; an\n // undefined id would index the matrix at NaN and poison the whole mean-pool -- and the\n // int8 conversion then stores the NaN vector as all zeros, silently. Keep integers only.\n const ids = (tok.encode(text, { add_special_tokens: false }).ids as number[]).filter((id) => Number.isInteger(id) && id !== unkId);\n const v = new Float32Array(dims);\n if (ids.length === 0) return v;\n for (const id of ids) {\n const off = id * dims;\n for (let d = 0; d < dims; d++) v[d] += matrix[off + d];\n }\n let norm = 0;\n for (let d = 0; d < dims; d++) {\n v[d] /= ids.length;\n norm += v[d] * v[d];\n }\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] /= norm;\n return v;\n }\n\n return { id: `static:${model}`, dims, embed: async (texts) => texts.map(one) };\n}\n\n// --- api type: one POST against any OpenAI-compatible /embeddings endpoint ---\n\nasync function apiProvider(model: string, url: string | undefined, keyEnv: string | undefined): Promise<EmbedProvider> {\n if (!url) throw new SenseError('EMBED_MODEL', 'features.embed.type \"api\" requires a url');\n const base = url.replace(/\\/+$/, '');\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n const key = keyEnv ? process.env[keyEnv] : undefined;\n if (key) headers.authorization = `Bearer ${key}`;\n\n async function post(texts: string[]): Promise<Float32Array[]> {\n const res = await fetch(`${base}/embeddings`, { method: 'POST', headers, body: JSON.stringify({ model, input: texts }) });\n if (!res.ok) throw new SenseError('EMBED_MODEL', `${base}/embeddings -> HTTP ${res.status}`);\n const body = (await res.json()) as { data: Array<{ embedding: number[] }> };\n return body.data.map((d) => Float32Array.from(d.embedding));\n }\n\n const dims = (await post(['dimension probe']))[0].length;\n return { id: `api:${base}:${model}`, dims, embed: post };\n}\n\nconst providers = new Map<string, Promise<EmbedProvider>>();\n\nfunction getProvider(cfg: Config): Promise<EmbedProvider> {\n const e = embedConfig(cfg);\n if (!e) throw new SenseError('EMBED_DISABLED', 'semantic expansion needs features.embed in sense.config.json (e.g. \"features\": { \"embed\": true })');\n const sig = `${e.type}:${e.model}:${e.url ?? ''}`;\n let p = providers.get(sig);\n if (!p) {\n p = e.type === 'api' ? apiProvider(e.model, e.url, e.key) : staticProvider(e.model);\n providers.set(sig, p);\n }\n return p;\n}\n\n// Slice + re-normalize (Matryoshka); optionally round through int8 storage.\nfunction toStore(full: Float32Array, dims: number, int8: boolean): { v: Float32Array; scale: number } {\n const v = new Float32Array(dims);\n let norm = 0;\n for (let d = 0; d < dims; d++) norm += full[d] * full[d];\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] = full[d] / norm;\n if (!int8) return { v, scale: 1 };\n let max = 0;\n for (let d = 0; d < dims; d++) max = Math.max(max, Math.abs(v[d]));\n return { v, scale: max / 127 || 1 };\n}\n\n// Embed rows whose vector is NULL, re-deriving chunk text from the files through the\n// same parse + chunker that stored the rows.\nexport async function embedPending(db: DatabaseSync, cfg: Config, baseDir: string): Promise<void> {\n const provider = await getProvider(cfg); // throws EMBED_DISABLED before touching the table\n const dirty = db.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk').all() as Array<{ path: string; chunk: number }>;\n if (dirty.length === 0) return;\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n\n const byPath = new Map<string, number[]>();\n for (const row of dirty) {\n const list = byPath.get(row.path) ?? [];\n list.push(row.chunk);\n byPath.set(row.path, list);\n }\n\n const jobs: Array<{ path: string; chunk: number; text: string }> = [];\n for (const [path, chunkIdxs] of byPath) {\n let chunks: Chunk[];\n try {\n chunks = parseFile({ relPath: path, absPath: join(baseDir, path), mtimeMs: 0, size: 0 }, [embed]).doc.extracted.embed as Chunk[];\n } catch {\n continue; // vanished since reconcile; the next reconcile removes its rows\n }\n for (const idx of chunkIdxs) if (chunks[idx]) jobs.push({ path, chunk: idx, text: chunks[idx].text });\n }\n\n const update = db.prepare('UPDATE embeddings SET scale = ?, vector = ? WHERE \"path\" = ? AND chunk = ?');\n // The lazy build is the one long silence a first --semantic query hits (measured 23s at\n // 26k notes); progress makes it distinguishable from a hang.\n const report = progress('embedding chunks', jobs.length);\n for (let i = 0; i < jobs.length; i += BATCH) {\n const batch = jobs.slice(i, i + BATCH);\n const vectors = await provider.embed(batch.map((j) => j.text));\n db.exec('BEGIN');\n try {\n batch.forEach((job, j) => {\n const { v, scale } = toStore(vectors[j], storeDims, true);\n const q = new Int8Array(storeDims);\n for (let d = 0; d < storeDims; d++) q[d] = Math.round(v[d] / scale);\n update.run(scale, Buffer.from(q.buffer), job.path, job.chunk);\n });\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n report.tick(Math.min(i + BATCH, jobs.length));\n }\n report.finish();\n}\n\n// Top candidates by cosine for a semantic find: best chunk per file, its line range\n// riding along. FTS5 operators in the terms are lexical syntax, not meaning -- stripped\n// before embedding.\n// Returns the cosine similarity alongside each candidate: stored and query vectors are both\n// L2-normalised before quantisation, so the dot product is cosine in [-1, 1]. `find` surfaces\n// it because the fused rank score cannot express match quality -- nearest-neighbour search\n// always returns a nearest neighbour, so without a magnitude an agent cannot tell a real hit\n// from the best of a bad lot.\nexport async function semanticCandidates(db: DatabaseSync, cfg: Config, terms: string, fetch: number): Promise<Array<{ path: string; lines: string; similarity: number }>> {\n const baseDir = (cfg as Partial<ResolvedConfig>).baseDir;\n if (!baseDir) throw new SenseError('EMBED_MODEL', 'semantic expansion needs a config with baseDir (use loadConfig/open)');\n await embedPending(db, cfg, baseDir);\n\n const provider = await getProvider(cfg);\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n const text = (terms.match(/[\\p{L}\\p{N}]+/gu) ?? []).filter((t) => !['AND', 'OR', 'NOT', 'NEAR'].includes(t)).join(' ');\n const { v: qv } = toStore((await provider.embed([text]))[0], storeDims, false);\n\n const rows = db.prepare('SELECT \"path\", start_line, end_line, scale, vector FROM embeddings WHERE vector IS NOT NULL').all() as Array<{\n path: string;\n start_line: number;\n end_line: number;\n scale: number;\n vector: Uint8Array;\n }>;\n\n const best = new Map<string, { score: number; lines: string }>();\n for (const row of rows) {\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, Math.min(storeDims, row.vector.byteLength));\n let dot = 0;\n for (let d = 0; d < q.length; d++) dot += q[d] * qv[d];\n const score = dot * row.scale;\n const existing = best.get(row.path);\n if (!existing || score > existing.score) best.set(row.path, { score, lines: `L${row.start_line}-${row.end_line}` });\n }\n return [...best.entries()]\n .sort((a, b) => b[1].score - a[1].score)\n .slice(0, fetch)\n .map(([path, b]) => ({ path, lines: b.lines, similarity: Math.round(b.score * 1000) / 1000 }));\n}\n"],"names":["embed","embedPending","semanticCandidates","STORE_DIMS","BATCH","chunksOf","raw","search","lines","split","starts","inFence","i","length","test","push","bounds","prefix","title","summary","filter","Boolean","join","chunks","forEach","start","end","text","slice","trim","startLine","endLine","name","schema","db","exec","extract","_body","remove","path","prepare","run","store","extracted","insert","c","idx","fetchToFile","url","dest","fetch","then","res","ok","SenseError","status","Buffer","from","arrayBuffer","writeFileSync","renameSync","staticProvider","model","tokenizerJson","dir","file","headerLen","header","entry","spec","dims","dataStart","matrix","Tokenizer","tok","unkId","one","ids","encode","add_special_tokens","id","Number","isInteger","v","Float32Array","off","d","norm","Math","sqrt","existsSync","homedir","replace","mkdirSync","recursive","console","error","readFileSync","readBigUInt64LE","JSON","parse","subarray","toString","Object","entries","find","k","dtype","shape","byteOffset","data_offsets","buffer","vocab","unk_token","texts","map","apiProvider","keyEnv","base","headers","key","post","body","method","stringify","input","json","data","embedding","process","env","undefined","authorization","providers","Map","getProvider","cfg","e","embedConfig","sig","type","p","get","set","toStore","full","int8","scale","max","abs","baseDir","provider","dirty","storeDims","byPath","row","list","jobs","chunkIdxs","update","report","batch","vectors","j","job","q","Int8Array","round","chunk","err","tick","min","all","parseFile","relPath","absPath","mtimeMs","size","doc","progress","finish","terms","qv","rows","best","dot","score","existing","match","t","includes","vector","byteLength","start_line","end_line","sort","a","b","similarity"],"mappings":";;;;;;;;;;;QA8DaA;eAAAA;;QAmISC;eAAAA;;QAyDAC;eAAAA;;;sBA1PyD;sBACvD;wBACH;wBAGO;wBACD;0BACF;sBACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG1B,sFAAsF;AACtF,uFAAuF;AACvF,oFAAoF;AACpF,+EAA+E;AAE/E,6EAA6E;AAC7E,yEAAyE;AACzE,IAAMC,aAAa;AACnB,IAAMC,QAAQ;AAcd,uFAAuF;AACvF,sFAAsF;AACtF,mFAAmF;AACnF,yBAAyB;AACzB,SAASC,SAASC,GAAW,EAAEC,MAA2C;IACxE,IAAMC,QAAQF,IAAIG,KAAK,CAAC;IACxB,IAAMC,SAAmB,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,IAAI,CAACA,WAAW,YAAYG,IAAI,CAACN,KAAK,CAACI,EAAE,GAAGF,OAAOK,IAAI,CAACH,IAAI;IAC9D;IACA,IAAMI,SAASN,OAAOG,MAAM,KAAK,IAAI;QAAC;KAAE,GAAGH,MAAM,CAAC,EAAE,GAAG,IAAI;QAAC;KAAa,CAAd,OAAI,qBAAGA,WAAUA;IAC5E,IAAMO,SAAS;QAACV,mBAAAA,6BAAAA,OAAQW,KAAK;QAAEX,mBAAAA,6BAAAA,OAAQY,OAAO;KAAC,CAACC,MAAM,CAACC,SAASC,IAAI,CAAC;IACrE,IAAMC,SAAkB,EAAE;IAC1BP,OAAOQ,OAAO,CAAC,SAACC,OAAOb;QACrB,IAAMc,MAAMd,IAAI,IAAII,OAAOH,MAAM,GAAGG,MAAM,CAACJ,IAAI,EAAE,GAAG,IAAIJ,MAAMK,MAAM;QACpE,IAAMc,OAAOnB,MACVoB,KAAK,CAACH,QAAQ,GAAGC,KACjBJ,IAAI,CAAC,MACLO,IAAI;QACP,IAAIF,KAAKd,MAAM,GAAG,GAAGU,OAAOR,IAAI,CAAC;YAAEe,WAAWL;YAAOM,SAASL;YAAKC,MAAMV,SAAS,AAAC,GAAaU,OAAXV,QAAO,MAAS,OAALU,QAASA;QAAK;IAChH;IACA,OAAOJ;AACT;AAEO,IAAMvB,QAAiB;IAC5BgC,MAAM;IACNC,QAAAA,SAAAA,OAAOC,EAAE;QACPA,GAAGC,IAAI,CAAC;IACV;IACAC,SAAAA,SAAAA,QAAQ9B,GAAG,EAAE+B,KAAK,EAAE9B,MAAM;QACxB,OAAOF,SAASC,KAAKC;IACvB;IACA+B,QAAAA,SAAAA,OAAOJ,EAAE,EAAEK,IAAI;QACbL,GAAGM,OAAO,CAAC,2CAA2CC,GAAG,CAACF;IAC5D;IACAG,OAAAA,SAAAA,MAAMR,EAAE,EAAEK,IAAI,EAAEI,SAAS;QACvB,IAAMC,SAASV,GAAGM,OAAO,CAAC;QACzBG,UAAsBnB,OAAO,CAAC,SAACqB,GAAGC;mBAAQF,OAAOH,GAAG,CAACF,MAAMO,KAAKD,EAAEf,SAAS,EAAEe,EAAEd,OAAO;;IACzF;AACF;AAEA,2FAA2F;AAC3F,yFAAyF;AACzF,gBAAgB;AAEhB,SAASgB,YAAYC,GAAW,EAAEC,IAAY;IAC5C,OAAOC,MAAMF,KAAKG,IAAI,CAAC,SAAOC;;;;;;wBAC5B,IAAI,CAACA,IAAIC,EAAE,EAAE,MAAM,IAAIC,oBAAU,CAAC,eAAe,AAAC,0BAAwCF,OAAfJ,KAAI,aAAsB,OAAXI,IAAIG,MAAM;;4BACrF,GAAO,OAALN,MAAK;;4BAAQO,OAAOC,IAAI;wBAAC;;4BAAML,IAAIM,WAAW;;;wBAA/DC,qBAAa;4BAAiBH,QAAAA;gCAAY;;;wBAC1CI,IAAAA,kBAAU,EAAC,AAAC,GAAO,OAALX,MAAK,UAAQA;;;;;;QAC7B;;AACF;AAEA,SAAeY,eAAeC,KAAa;;kBA2BEC,sBAA7BA,4BAAAA,uBA1BVC,SAIiB,OAARC,MAQP3D,KACA4D,WACAC,QACAC,OAEAC,MACAC,MACAC,WACAC,QAEAT,eAEEU,WACFC,KACAC;QAEN,SAASC,IAAIjD,IAAY;YACvB,mFAAmF;YACnF,uFAAuF;YACvF,yFAAyF;YACzF,IAAMkD,MAAM,AAACH,IAAII,MAAM,CAACnD,MAAM;gBAAEoD,oBAAoB;YAAM,GAAGF,GAAG,CAAczD,MAAM,CAAC,SAAC4D;uBAAOC,OAAOC,SAAS,CAACF,OAAOA,OAAOL;;YAC5H,IAAMQ,IAAI,IAAIC,aAAad;YAC3B,IAAIO,IAAIhE,MAAM,KAAK,GAAG,OAAOsE;gBACxB,kCAAA,2BAAA;;gBAAL,QAAK,YAAYN,wBAAZ,SAAA,6BAAA,QAAA,yBAAA,iCAAiB;oBAAjB,IAAMG,KAAN;oBACH,IAAMK,MAAML,KAAKV;oBACjB,IAAK,IAAIgB,IAAI,GAAGA,IAAIhB,MAAMgB,IAAKH,CAAC,CAACG,EAAE,IAAId,MAAM,CAACa,MAAMC,EAAE;gBACxD;;gBAHK;gBAAA;;;yBAAA,6BAAA;wBAAA;;;wBAAA;8BAAA;;;;YAIL,IAAIC,OAAO;YACX,IAAK,IAAID,KAAI,GAAGA,KAAIhB,MAAMgB,KAAK;gBAC7BH,CAAC,CAACG,GAAE,IAAIT,IAAIhE,MAAM;gBAClB0E,QAAQJ,CAAC,CAACG,GAAE,GAAGH,CAAC,CAACG,GAAE;YACrB;YACAC,OAAOC,KAAKC,IAAI,CAACF,QAAQ;YACzB,IAAK,IAAID,KAAI,GAAGA,KAAIhB,MAAMgB,KAAKH,CAAC,CAACG,GAAE,IAAIC;YACvC,OAAOJ;QACT;;;;oBA/CInB,MAAMF;yBACN,CAAC4B,IAAAA,kBAAU,EAACpE,IAAAA,cAAI,EAAC0C,KAAK,uBAAtB;;;;oBACFA,MAAM1C,IAAAA,cAAI,EAACqE,IAAAA,eAAO,KAAI,UAAU,eAAe,UAAU7B,MAAM8B,OAAO,CAAC,OAAO;oBAC9EC,IAAAA,iBAAS,EAAC7B,KAAK;wBAAE8B,WAAW;oBAAK;4BACd;wBAAC;wBAAqB;;;;+BAAtB;;;;oBAAR7B,OAAQ;yBACb,CAACyB,IAAAA,kBAAU,EAACpE,IAAAA,cAAI,EAAC0C,KAAKC,QAAtB;;;;oBACF8B,QAAQC,KAAK,CAAC,AAAC,YAAoB/B,OAATH,OAAM,KAAgBE,OAAbC,MAAK,UAAY,OAAJD,KAAI;oBACpD;;wBAAMjB,YAAY,AAAC,0BAA+CkB,OAAtBH,OAAM,kBAAqB,OAALG,OAAQ3C,IAAAA,cAAI,EAAC0C,KAAKC;;;oBAApF;;;;;;;;;oBAKA3D,MAAM2F,IAAAA,oBAAY,EAAC3E,IAAAA,cAAI,EAAC0C,KAAK;oBAC7BE,YAAYe,OAAO3E,IAAI4F,eAAe,CAAC;oBACvC/B,SAASgC,KAAKC,KAAK,CAAC9F,IAAI+F,QAAQ,CAAC,GAAG,IAAInC,WAAWoC,QAAQ,CAAC;oBAC5DlC,QAAQmC,OAAOC,OAAO,CAACrC,QAAQsC,IAAI,CAAC;iEAAEC;+BAAOA,MAAM;;oBACzD,IAAI,CAACtC,SAASA,KAAK,CAAC,EAAE,CAACuC,KAAK,KAAK,OAAO,MAAM,IAAIrD,oBAAU,CAAC,eAAe,AAAC,GAAQ,OAANQ,OAAM;oBAC/EO,OAAOD,KAAK,CAAC,EAAE;oBACfE,OAAOD,KAAKuC,KAAK,CAAC,EAAE;oBACpBrC,YAAYjE,IAAIuG,UAAU,GAAG,IAAI3C,YAAYG,KAAKyC,YAAY,CAAC,EAAE;oBACjEtC,SAASD,YAAY,MAAM,IAAI,IAAIa,aAAa9E,IAAIyG,MAAM,EAAExC,WAAWF,KAAKuC,KAAK,CAAC,EAAE,GAAGtC,QAAQ,IAAIc,aAAa9E,IAAIyG,MAAM,CAACnF,KAAK,CAAC2C,WAAWA,YAAYF,KAAKuC,KAAK,CAAC,EAAE,GAAGtC,OAAO;oBAE/KP,gBAAgBoC,KAAKC,KAAK,CAACH,IAAAA,oBAAY,EAAC3E,IAAAA,cAAI,EAAC0C,KAAK,mBAAmB;oBAErD;;wBAAM;2EAAA,QAAO;;;;oBAA3BS,YAAc,cAAdA;oBACFC,MAAM,IAAID,UAAUV,eAAe,CAAC;oBACpCY,iBAAQZ,wBAAAA,cAAcD,KAAK,cAAnBC,6CAAAA,6BAAAA,sBAAqBiD,KAAK,cAA1BjD,iDAAAA,0BAA4B,EAACA,uBAAAA,cAAcD,KAAK,cAAnBC,2CAAAA,qBAAqBkD,SAAS,CAAC,uCAAI,CAAC;oBAuB/E;;wBAAO;4BAAEjC,IAAI,AAAC,UAAe,OAANlB;4BAASQ,MAAAA;4BAAMtE,OAAO,SAAPA,MAAckH;;;;;4CAAUA,MAAMC,GAAG,CAACvC;;;;;wBAAK;;;;IAC/E;;AAEA,gFAAgF;AAEhF,SAAewC,YAAYtD,KAAa,EAAEd,GAAuB,EAAEqE,MAA0B;;YAErFC,MACAC,SACAC,KAUAlD;QAPN,SAAemD,KAAKP,KAAe;;oBAC3B9D,KAEAsE;;;;4BAFM;;gCAAMxE,MAAM,AAAC,GAAO,OAALoE,MAAK,gBAAc;oCAAEK,QAAQ;oCAAQJ,SAAAA;oCAASG,MAAMvB,KAAKyB,SAAS,CAAC;wCAAE9D,OAAAA;wCAAO+D,OAAOX;oCAAM;gCAAG;;;4BAAjH9D,MAAM;4BACZ,IAAI,CAACA,IAAIC,EAAE,EAAE,MAAM,IAAIC,oBAAU,CAAC,eAAe,AAAC,GAA6BF,OAA3BkE,MAAK,wBAAiC,OAAXlE,IAAIG,MAAM;4BAC3E;;gCAAMH,IAAI0E,IAAI;;;4BAAtBJ,OAAQ;4BACd;;gCAAOA,KAAKK,IAAI,CAACZ,GAAG,CAAC,SAAC7B;2CAAMF,aAAa3B,IAAI,CAAC6B,EAAE0C,SAAS;;;;;YAC3D;;;;;oBAXA,IAAI,CAAChF,KAAK,MAAM,IAAIM,oBAAU,CAAC,eAAe;oBACxCgE,OAAOtE,IAAI4C,OAAO,CAAC,QAAQ;oBAC3B2B,UAAkC;wBAAE,gBAAgB;oBAAmB;oBACvEC,MAAMH,SAASY,QAAQC,GAAG,CAACb,OAAO,GAAGc;oBAC3C,IAAIX,KAAKD,QAAQa,aAAa,GAAG,AAAC,UAAa,OAAJZ;oBAS7B;;wBAAMC;4BAAM;;;;oBAApBnD,OAAO,AAAC,aAAgC,CAAC,EAAE,CAACzD,MAAM;oBACxD;;wBAAO;4BAAEmE,IAAI,AAAC,OAAclB,OAARwD,MAAK,KAAS,OAANxD;4BAASQ,MAAAA;4BAAMtE,OAAOyH;wBAAK;;;;IACzD;;AAEA,IAAMY,YAAY,IAAIC;AAEtB,SAASC,YAAYC,GAAW;QAGMC;IAFpC,IAAMA,IAAIC,IAAAA,qBAAW,EAACF;IACtB,IAAI,CAACC,GAAG,MAAM,IAAInF,oBAAU,CAAC,kBAAkB;IAC/C,IAAMqF,MAAM,AAzKd,AAyKe,GAAYF,OAAVA,EAAEG,IAAI,EAAC,YAAGH,EAAE3E,KAAK,EAAC,KAAe,QAAZ2E,SAAAA,EAAEzF,GAAG,cAALyF,oBAAAA,SAAS;IAC7C,IAAII,IAAIR,UAAUS,GAAG,CAACH;IACtB,IAAI,CAACE,GAAG;QACNA,IAAIJ,EAAEG,IAAI,KAAK,QAAQxB,YAAYqB,EAAE3E,KAAK,EAAE2E,EAAEzF,GAAG,EAAEyF,EAAEjB,GAAG,IAAI3D,eAAe4E,EAAE3E,KAAK;QAClFuE,UAAUU,GAAG,CAACJ,KAAKE;IACrB;IACA,OAAOA;AACT;AAEA,4EAA4E;AAC5E,SAASG,QAAQC,IAAkB,EAAE3E,IAAY,EAAE4E,IAAa;IAC9D,IAAM/D,IAAI,IAAIC,aAAad;IAC3B,IAAIiB,OAAO;IACX,IAAK,IAAID,IAAI,GAAGA,IAAIhB,MAAMgB,IAAKC,QAAQ0D,IAAI,CAAC3D,EAAE,GAAG2D,IAAI,CAAC3D,EAAE;IACxDC,OAAOC,KAAKC,IAAI,CAACF,QAAQ;IACzB,IAAK,IAAID,KAAI,GAAGA,KAAIhB,MAAMgB,KAAKH,CAAC,CAACG,GAAE,GAAG2D,IAAI,CAAC3D,GAAE,GAAGC;IAChD,IAAI,CAAC2D,MAAM,OAAO;QAAE/D,GAAAA;QAAGgE,OAAO;IAAE;IAChC,IAAIC,MAAM;IACV,IAAK,IAAI9D,KAAI,GAAGA,KAAIhB,MAAMgB,KAAK8D,MAAM5D,KAAK4D,GAAG,CAACA,KAAK5D,KAAK6D,GAAG,CAAClE,CAAC,CAACG,GAAE;IAChE,OAAO;QAAEH,GAAAA;QAAGgE,OAAOC,MAAM,OAAO;IAAE;AACpC;AAIO,SAAenJ,aAAaiC,EAAgB,EAAEsG,GAAW,EAAEc,OAAe;;mBACzEC,UACAC,OAEAC,WAEAC,QACD,2BAAA,mBAAA,gBAAA,WAAA,OAAMC,KACID,aAAPE,MAKFC,MACD,4BAAA,oBAAA,iBAAA,YAAA,qBAAOtH,MAAMuH,WACZvI,QAMC,4BAAA,oBAAA,iBAAA,YAAA,QAAMuB,KAGPiH,QAGAC,QACGpJ;;;;;4BACDqJ,OACAC;;;;oCADAD,QAAQJ,KAAKjI,KAAK,CAAChB,GAAGA,IAAIR;oCAChB;;wCAAMmJ,SAASvJ,KAAK,CAACiK,MAAM9C,GAAG,CAAC,SAACgD;mDAAMA,EAAExI,IAAI;;;;oCAAtDuI,UAAU;oCAChBhI,GAAGC,IAAI,CAAC;oCACR,IAAI;wCACF8H,MAAMzI,OAAO,CAAC,SAAC4I,KAAKD;4CAClB,IAAqBnB,WAAAA,QAAQkB,OAAO,CAACC,EAAE,EAAEV,WAAW,OAA5CtE,IAAa6D,SAAb7D,GAAGgE,QAAUH,SAAVG;4CACX,IAAMkB,IAAI,IAAIC,UAAUb;4CACxB,IAAK,IAAInE,IAAI,GAAGA,IAAImE,WAAWnE,IAAK+E,CAAC,CAAC/E,EAAE,GAAGE,KAAK+E,KAAK,CAACpF,CAAC,CAACG,EAAE,GAAG6D;4CAC7DY,OAAOtH,GAAG,CAAC0G,OAAO3F,OAAOC,IAAI,CAAC4G,EAAEtD,MAAM,GAAGqD,IAAI7H,IAAI,EAAE6H,IAAII,KAAK;wCAC9D;wCACAtI,GAAGC,IAAI,CAAC;oCACV,EAAE,OAAOsI,KAAK;wCACZvI,GAAGC,IAAI,CAAC;wCACR,MAAMsI;oCACR;oCACAT,OAAOU,IAAI,CAAClF,KAAKmF,GAAG,CAAC/J,IAAIR,OAAOyJ,KAAKhJ,MAAM;;;;;;oBAC7C;oBA5CiB;;wBAAM0H,YAAYC;;;oBAA7Be,WAAW;oBACXC,QAAQtH,GAAGM,OAAO,CAAC,oFAAoFoI,GAAG;oBAChH,IAAIpB,MAAM3I,MAAM,KAAK,GAAG;;;oBAClB4I,YAAYjE,KAAKmF,GAAG,CAACxK,YAAYoJ,SAASjF,IAAI;oBAE9CoF,SAAS,IAAIpB;oBACd,kCAAA,2BAAA;;wBAAL,IAAK,YAAakB,4BAAb,6BAAA,QAAA,yBAAA,iCAAoB;4BAAdG,MAAN;;4BACGC,QAAOF,cAAAA,OAAOZ,GAAG,CAACa,IAAIpH,IAAI,eAAnBmH,yBAAAA;4BACbE,KAAK7I,IAAI,CAAC4I,IAAIa,KAAK;4BACnBd,OAAOX,GAAG,CAACY,IAAIpH,IAAI,EAAEqH;wBACvB;;wBAJK;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAMCC;oBACD,mCAAA,4BAAA;;wBAAL,IAAK,aAA2BH,6BAA3B,8BAAA,SAAA,0BAAA,kCAAmC;2DAAnC,kBAAOnH,uBAAMuH;4BACZvI,SAAAA,KAAAA;4BACJ,IAAI;gCACFA,SAASsJ,IAAAA,iBAAS,EAAC;oCAAEC,SAASvI;oCAAMwI,SAASzJ,IAAAA,cAAI,EAACgI,SAAS/G;oCAAOyI,SAAS;oCAAGC,MAAM;gCAAE;oCAAIjL;mCAAQkL,GAAG,CAACvI,SAAS,CAAC3C,KAAK;4BACvH,EAAE,eAAM;gCACN,UAAU,gEAAgE;4BAC5E;4BACK,mCAAA,4BAAA;;gCAAL,IAAK,aAAa8J,gCAAb,8BAAA,SAAA,0BAAA;oCAAMhH,MAAN;oCAAwB,IAAIvB,MAAM,CAACuB,IAAI,EAAE+G,KAAK9I,IAAI,CAAC;wCAAEwB,MAAAA;wCAAMiI,OAAO1H;wCAAKnB,MAAMJ,MAAM,CAACuB,IAAI,CAACnB,IAAI;oCAAC;;;gCAA9F;gCAAA;;;yCAAA,8BAAA;wCAAA;;;wCAAA;8CAAA;;;;wBACP;;wBARK;wBAAA;;;iCAAA,8BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAUCoI,SAAS7H,GAAGM,OAAO,CAAC;oBAC1B,wFAAwF;oBACxF,6DAA6D;oBACvDwH,SAASmB,IAAAA,oBAAQ,EAAC,oBAAoBtB,KAAKhJ,MAAM;oBAC9CD,IAAI;;;yBAAGA,CAAAA,IAAIiJ,KAAKhJ,MAAM,AAAD;;;;;;;;;;;;oBAAGD,KAAKR;;;;;;oBAkBtC4J,OAAOoB,MAAM;;;;;;IACf;;AAUO,SAAelL,mBAAmBgC,EAAgB,EAAEsG,GAAW,EAAE6C,KAAa,EAAEnI,MAAa;;YAOpFmI,cANR/B,SAIAC,UACAE,WACA9H,MACYqH,UAAPsC,IAELC,MAQAC,MACD,2BAAA,mBAAA,gBAAA,WAAA,OAAM7B,KACHU,GACFoB,KACKnG,GACHoG,OACAC;;;;oBAvBFrC,UAAU,AAACd,IAAgCc,OAAO;oBACxD,IAAI,CAACA,SAAS,MAAM,IAAIhG,oBAAU,CAAC,eAAe;oBAClD;;wBAAMrD,aAAaiC,IAAIsG,KAAKc;;;oBAA5B;oBAEiB;;wBAAMf,YAAYC;;;oBAA7Be,WAAW;oBACXE,YAAYjE,KAAKmF,GAAG,CAACxK,YAAYoJ,SAASjF,IAAI;oBAC9C3C,OAAO,EAAC0J,eAAAA,MAAMO,KAAK,CAAC,2naAAZP,0BAAAA,mBAAsCjK,MAAM,CAAC,SAACyK;+BAAM,CAAC;4BAAC;4BAAO;4BAAM;4BAAO;yBAAO,CAACC,QAAQ,CAACD;uBAAIvK,IAAI,CAAC;oBACvF;;wBAAMiI,SAASvJ,KAAK;4BAAE2B;;;;oBAA/BqH,WAAAA;wBAAS,aAA6B,CAAC,EAAE;wBAAES;wBAAW;wBAA7D6B,KAAOtC,SAAV7D;oBAEFoG,OAAOrJ,GAAGM,OAAO,CAAC,+FAA+FoI,GAAG;oBAQpHY,OAAO,IAAIlD;oBACZ,kCAAA,2BAAA;;wBAAL,IAAK,YAAaiD,2BAAb,6BAAA,QAAA,yBAAA,iCAAmB;4BAAb5B,MAAN;4BACGU,IAAI,IAAIC,UAAUX,IAAIoC,MAAM,CAAChF,MAAM,EAAE4C,IAAIoC,MAAM,CAAClF,UAAU,EAAErB,KAAKmF,GAAG,CAAClB,WAAWE,IAAIoC,MAAM,CAACC,UAAU;4BACvGP,MAAM;4BACV,IAASnG,IAAI,GAAGA,IAAI+E,EAAExJ,MAAM,EAAEyE,IAAKmG,OAAOpB,CAAC,CAAC/E,EAAE,GAAGgG,EAAE,CAAChG,EAAE;4BAChDoG,QAAQD,MAAM9B,IAAIR,KAAK;4BACvBwC,WAAWH,KAAK1C,GAAG,CAACa,IAAIpH,IAAI;4BAClC,IAAI,CAACoJ,YAAYD,QAAQC,SAASD,KAAK,EAAEF,KAAKzC,GAAG,CAACY,IAAIpH,IAAI,EAAE;gCAAEmJ,OAAAA;gCAAOlL,OAAO,AAAC,IAAqBmJ,OAAlBA,IAAIsC,UAAU,EAAC,KAAgB,OAAbtC,IAAIuC,QAAQ;4BAAG;wBACnH;;wBAPK;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAQL;;wBAAQ,qBAAGV,KAAKhF,OAAO,IACpB2F,IAAI,CAAC,SAACC,GAAGC;mCAAMA,CAAC,CAAC,EAAE,CAACX,KAAK,GAAGU,CAAC,CAAC,EAAE,CAACV,KAAK;2BACtC9J,KAAK,CAAC,GAAGsB,QACTiE,GAAG,CAAC;qEAAE5E,kBAAM8J;mCAAQ;gCAAE9J,MAAAA;gCAAM/B,OAAO6L,EAAE7L,KAAK;gCAAE8L,YAAY9G,KAAK+E,KAAK,CAAC8B,EAAEX,KAAK,GAAG,QAAQ;4BAAK;;;;;IAC/F"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/embed.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { Config, ResolvedConfig } from '../config.ts';\nimport { embedConfig } from '../config.ts';\nimport { SenseError } from '../errors.ts';\nimport { progress } from '../progress.ts';\nimport { parseFile } from '../scan.ts';\nimport type { Feature } from './types.ts';\n\n// embeddings(path, chunk, start_line, end_line, scale, vector): heading-based chunks,\n// int8 vectors with a per-vector dequantization scale, vector NULL = not yet embedded.\n// Reconcile stores dirty rows inside its transaction; embedding tops up on the next\n// semantic query (embedPending), so staleness costs recall, never correctness.\n\n// Storage lever fixed by the bake-off (BENCHMARKING.md): int8 at 256 dims is\n// quality-free vs f32-512 when fused. Queries stay f32 at the same dims.\nconst STORE_DIMS = 256;\nconst BATCH = 64;\n\nexport interface EmbedProvider {\n id: string; // model identity; participates in the cache key, change -> re-embed\n dims: number;\n embed(texts: string[]): Promise<Float32Array[]>;\n}\n\ninterface Chunk {\n startLine: number;\n endLine: number;\n text: string;\n}\n\n// Deterministic chunker used at reconcile (line ranges stored) and at embed time (text\n// re-derived from the file -- chunk text is never stored). Heading-delimited with the\n// preamble kept; whole file when no headings. The title/summary prefix mirrors the\n// bm25 column weighting.\nfunction chunksOf(raw: string, search?: { title: string; summary: string }): Chunk[] {\n const lines = raw.split('\\n');\n const starts: number[] = [];\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 && /^#{1,6} +/.test(lines[i])) starts.push(i + 1);\n }\n const bounds = starts.length === 0 ? [1] : starts[0] > 1 ? [1, ...starts] : starts;\n const prefix = [search?.title, search?.summary].filter(Boolean).join('\\n');\n const chunks: Chunk[] = [];\n bounds.forEach((start, i) => {\n const end = i + 1 < bounds.length ? bounds[i + 1] - 1 : lines.length;\n const text = lines\n .slice(start - 1, end)\n .join('\\n')\n .trim();\n if (text.length > 0) chunks.push({ startLine: start, endLine: end, text: prefix ? `${prefix}\\n${text}` : text });\n });\n return chunks;\n}\n\nexport const embed: Feature = {\n name: 'embed',\n schema(db) {\n db.exec(`CREATE TABLE IF NOT EXISTS embeddings (\"path\" TEXT, chunk INTEGER, start_line INTEGER, end_line INTEGER, scale REAL, vector BLOB, PRIMARY KEY (\"path\", chunk))`);\n },\n extract(raw, _body, search) {\n return chunksOf(raw, search);\n },\n remove(db, path) {\n db.prepare('DELETE FROM embeddings WHERE \"path\" = ?').run(path);\n },\n // A doc covered only by semantic-false presets never had extract() run for it (db.ts's\n // per-file filter skips it), so extracted is undefined here -- store nothing, i.e. no rows.\n store(db, path, extracted) {\n if (!extracted) return;\n const insert = db.prepare('INSERT INTO embeddings (\"path\", chunk, start_line, end_line, scale, vector) VALUES (?, ?, ?, ?, NULL, NULL)');\n (extracted as Chunk[]).forEach((c, idx) => insert.run(path, idx, c.startLine, c.endLine));\n },\n enabledForFile(_cfg, file) {\n return file.embed;\n },\n};\n\n// --- static type: Model2Vec safetensors + pure-JS tokenizer, model cached in ~/.cache ---\n// Encode convention from model2vec/model.py: no special tokens, drop unk ids, mean-pool,\n// L2-normalize.\n\nfunction fetchToFile(url: string, dest: string): Promise<void> {\n return fetch(url).then(async (res) => {\n if (!res.ok) throw new SenseError('EMBED_MODEL', `model download failed: ${url} -> HTTP ${res.status}`);\n writeFileSync(`${dest}.part`, Buffer.from(await res.arrayBuffer()));\n renameSync(`${dest}.part`, dest);\n });\n}\n\nasync function staticProvider(model: string): Promise<EmbedProvider> {\n let dir = model;\n if (!existsSync(join(dir, 'model.safetensors'))) {\n dir = join(homedir(), '.cache', 'sensemaking', 'models', model.replace(/\\//g, '--'));\n mkdirSync(dir, { recursive: true });\n for (const file of ['model.safetensors', 'tokenizer.json']) {\n if (!existsSync(join(dir, file))) {\n console.error(`fetching ${model}/${file} into ${dir} (once; delete to refetch)`);\n await fetchToFile(`https://huggingface.co/${model}/resolve/main/${file}`, join(dir, file));\n }\n }\n }\n\n const raw = readFileSync(join(dir, 'model.safetensors'));\n const headerLen = Number(raw.readBigUInt64LE(0));\n const header = JSON.parse(raw.subarray(8, 8 + headerLen).toString('utf8')) as Record<string, { dtype: string; shape: number[]; data_offsets: number[] }>;\n const entry = Object.entries(header).find(([k]) => k !== '__metadata__');\n if (!entry || entry[1].dtype !== 'F32') throw new SenseError('EMBED_MODEL', `${model}: expected an F32 safetensors matrix`);\n const spec = entry[1];\n const dims = spec.shape[1];\n const dataStart = raw.byteOffset + 8 + headerLen + spec.data_offsets[0];\n const matrix = dataStart % 4 === 0 ? new Float32Array(raw.buffer, dataStart, spec.shape[0] * dims) : new Float32Array(raw.buffer.slice(dataStart, dataStart + spec.shape[0] * dims * 4));\n\n const tokenizerJson = JSON.parse(readFileSync(join(dir, 'tokenizer.json'), 'utf8'));\n // Lazy import: the tokenizer loads only on the semantic path, never at CLI startup.\n const { Tokenizer } = await import('@huggingface/tokenizers');\n const tok = new Tokenizer(tokenizerJson, {});\n const unkId = tokenizerJson.model?.vocab?.[tokenizerJson.model?.unk_token] ?? -1;\n\n function one(text: string): Float32Array {\n // The tokenizer yields undefined (not the unk id) for tokens outside the vocab; an\n // undefined id would index the matrix at NaN and poison the whole mean-pool -- and the\n // int8 conversion then stores the NaN vector as all zeros, silently. Keep integers only.\n const ids = (tok.encode(text, { add_special_tokens: false }).ids as number[]).filter((id) => Number.isInteger(id) && id !== unkId);\n const v = new Float32Array(dims);\n if (ids.length === 0) return v;\n for (const id of ids) {\n const off = id * dims;\n for (let d = 0; d < dims; d++) v[d] += matrix[off + d];\n }\n let norm = 0;\n for (let d = 0; d < dims; d++) {\n v[d] /= ids.length;\n norm += v[d] * v[d];\n }\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] /= norm;\n return v;\n }\n\n return { id: `static:${model}`, dims, embed: async (texts) => texts.map(one) };\n}\n\n// --- api type: one POST against any OpenAI-compatible /embeddings endpoint ---\n\nasync function apiProvider(model: string, url: string | undefined, keyEnv: string | undefined): Promise<EmbedProvider> {\n if (!url) throw new SenseError('EMBED_MODEL', 'features.embed.type \"api\" requires a url');\n const base = url.replace(/\\/+$/, '');\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n const key = keyEnv ? process.env[keyEnv] : undefined;\n if (key) headers.authorization = `Bearer ${key}`;\n\n async function post(texts: string[]): Promise<Float32Array[]> {\n const res = await fetch(`${base}/embeddings`, { method: 'POST', headers, body: JSON.stringify({ model, input: texts }) });\n if (!res.ok) throw new SenseError('EMBED_MODEL', `${base}/embeddings -> HTTP ${res.status}`);\n const body = (await res.json()) as { data: Array<{ embedding: number[] }> };\n return body.data.map((d) => Float32Array.from(d.embedding));\n }\n\n const dims = (await post(['dimension probe']))[0].length;\n return { id: `api:${base}:${model}`, dims, embed: post };\n}\n\nconst providers = new Map<string, Promise<EmbedProvider>>();\n\nfunction getProvider(cfg: Config): Promise<EmbedProvider> {\n const e = embedConfig(cfg);\n if (!e) throw new SenseError('EMBED_DISABLED', 'semantic search needs at least one preset with vectors on (semantic !== false); every declared preset in sense.config.json has \"semantic\": false');\n const sig = `${e.type}:${e.model}:${e.url ?? ''}`;\n let p = providers.get(sig);\n if (!p) {\n p = e.type === 'api' ? apiProvider(e.model, e.url, e.key) : staticProvider(e.model);\n providers.set(sig, p);\n }\n return p;\n}\n\n// Slice + re-normalize (Matryoshka); optionally round through int8 storage.\nfunction toStore(full: Float32Array, dims: number, int8: boolean): { v: Float32Array; scale: number } {\n const v = new Float32Array(dims);\n let norm = 0;\n for (let d = 0; d < dims; d++) norm += full[d] * full[d];\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] = full[d] / norm;\n if (!int8) return { v, scale: 1 };\n let max = 0;\n for (let d = 0; d < dims; d++) max = Math.max(max, Math.abs(v[d]));\n return { v, scale: max / 127 || 1 };\n}\n\n// Embed rows whose vector is NULL, re-deriving chunk text from the files through the\n// same parse + chunker that stored the rows.\nexport async function embedPending(db: DatabaseSync, cfg: Config, baseDir: string): Promise<void> {\n const provider = await getProvider(cfg); // throws EMBED_DISABLED before touching the table\n const dirty = db.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk').all() as Array<{ path: string; chunk: number }>;\n if (dirty.length === 0) return;\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n\n const byPath = new Map<string, number[]>();\n for (const row of dirty) {\n const list = byPath.get(row.path) ?? [];\n list.push(row.chunk);\n byPath.set(row.path, list);\n }\n\n const jobs: Array<{ path: string; chunk: number; text: string }> = [];\n for (const [path, chunkIdxs] of byPath) {\n let chunks: Chunk[];\n try {\n // presets/embed are irrelevant here -- re-deriving chunk text for a doc that already\n // has embeddings rows means it was covered by a semantic-on preset at reconcile time.\n chunks = parseFile({ relPath: path, absPath: join(baseDir, path), mtimeMs: 0, size: 0, presets: [], embed: true }, [embed]).doc.extracted.embed as Chunk[];\n } catch {\n continue; // vanished since reconcile; the next reconcile removes its rows\n }\n for (const idx of chunkIdxs) if (chunks[idx]) jobs.push({ path, chunk: idx, text: chunks[idx].text });\n }\n\n const update = db.prepare('UPDATE embeddings SET scale = ?, vector = ? WHERE \"path\" = ? AND chunk = ?');\n // The lazy build is the one long silence a first --semantic query hits (measured 23s at\n // 26k notes); progress makes it distinguishable from a hang.\n const report = progress('embedding chunks', jobs.length);\n for (let i = 0; i < jobs.length; i += BATCH) {\n const batch = jobs.slice(i, i + BATCH);\n const vectors = await provider.embed(batch.map((j) => j.text));\n db.exec('BEGIN');\n try {\n batch.forEach((job, j) => {\n const { v, scale } = toStore(vectors[j], storeDims, true);\n const q = new Int8Array(storeDims);\n for (let d = 0; d < storeDims; d++) q[d] = Math.round(v[d] / scale);\n update.run(scale, Buffer.from(q.buffer), job.path, job.chunk);\n });\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n report.tick(Math.min(i + BATCH, jobs.length));\n }\n report.finish();\n}\n\n// Top candidates by cosine for a semantic find: best chunk per file, its line range\n// riding along. FTS5 operators in the terms are lexical syntax, not meaning -- stripped\n// before embedding.\n// Returns the cosine similarity alongside each candidate: stored and query vectors are both\n// L2-normalised before quantisation, so the dot product is cosine in [-1, 1]. `find` surfaces\n// it because the fused rank score cannot express match quality -- nearest-neighbour search\n// always returns a nearest neighbour, so without a magnitude an agent cannot tell a real hit\n// from the best of a bad lot.\nexport async function semanticCandidates(db: DatabaseSync, cfg: Config, terms: string, fetch: number): Promise<Array<{ path: string; lines: string; similarity: number }>> {\n const baseDir = (cfg as Partial<ResolvedConfig>).baseDir;\n if (!baseDir) throw new SenseError('EMBED_MODEL', 'semantic expansion needs a config with baseDir (use loadConfig/open)');\n await embedPending(db, cfg, baseDir);\n\n const provider = await getProvider(cfg);\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n const text = (terms.match(/[\\p{L}\\p{N}]+/gu) ?? []).filter((t) => !['AND', 'OR', 'NOT', 'NEAR'].includes(t)).join(' ');\n const { v: qv } = toStore((await provider.embed([text]))[0], storeDims, false);\n\n const rows = db.prepare('SELECT \"path\", start_line, end_line, scale, vector FROM embeddings WHERE vector IS NOT NULL').all() as Array<{\n path: string;\n start_line: number;\n end_line: number;\n scale: number;\n vector: Uint8Array;\n }>;\n\n const best = new Map<string, { score: number; lines: string }>();\n for (const row of rows) {\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, Math.min(storeDims, row.vector.byteLength));\n let dot = 0;\n for (let d = 0; d < q.length; d++) dot += q[d] * qv[d];\n const score = dot * row.scale;\n const existing = best.get(row.path);\n if (!existing || score > existing.score) best.set(row.path, { score, lines: `L${row.start_line}-${row.end_line}` });\n }\n return [...best.entries()]\n .sort((a, b) => b[1].score - a[1].score)\n .slice(0, fetch)\n .map(([path, b]) => ({ path, lines: b.lines, similarity: Math.round(b.score * 1000) / 1000 }));\n}\n"],"names":["embed","embedPending","semanticCandidates","STORE_DIMS","BATCH","chunksOf","raw","search","lines","split","starts","inFence","i","length","test","push","bounds","prefix","title","summary","filter","Boolean","join","chunks","forEach","start","end","text","slice","trim","startLine","endLine","name","schema","db","exec","extract","_body","remove","path","prepare","run","store","extracted","insert","c","idx","enabledForFile","_cfg","file","fetchToFile","url","dest","fetch","then","res","ok","SenseError","status","Buffer","from","arrayBuffer","writeFileSync","renameSync","staticProvider","model","tokenizerJson","dir","headerLen","header","entry","spec","dims","dataStart","matrix","Tokenizer","tok","unkId","one","ids","encode","add_special_tokens","id","Number","isInteger","v","Float32Array","off","d","norm","Math","sqrt","existsSync","homedir","replace","mkdirSync","recursive","console","error","readFileSync","readBigUInt64LE","JSON","parse","subarray","toString","Object","entries","find","k","dtype","shape","byteOffset","data_offsets","buffer","vocab","unk_token","texts","map","apiProvider","keyEnv","base","headers","key","post","body","method","stringify","input","json","data","embedding","process","env","undefined","authorization","providers","Map","getProvider","cfg","e","embedConfig","sig","type","p","get","set","toStore","full","int8","scale","max","abs","baseDir","provider","dirty","storeDims","byPath","row","list","jobs","chunkIdxs","update","report","batch","vectors","j","job","q","Int8Array","round","chunk","err","tick","min","all","parseFile","relPath","absPath","mtimeMs","size","presets","doc","progress","finish","terms","qv","rows","best","dot","score","existing","match","t","includes","vector","byteLength","start_line","end_line","sort","a","b","similarity"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
import type { FeatureName } from '../config.js';
|
|
2
|
+
import type { Config, FeatureName } from '../config.js';
|
|
3
3
|
import type { FileStat } from '../scan.js';
|
|
4
4
|
export interface ReconcileDelta {
|
|
5
5
|
files: FileStat[];
|
|
@@ -18,4 +18,5 @@ export interface Feature {
|
|
|
18
18
|
remove?(db: DatabaseSync, path: string, delta: ReconcileDelta): void;
|
|
19
19
|
store?(db: DatabaseSync, path: string, extracted: unknown, delta: ReconcileDelta): void;
|
|
20
20
|
afterReconcile?(db: DatabaseSync, delta: ReconcileDelta): void;
|
|
21
|
+
enabledForFile?(cfg: Config, file: FileStat): boolean;
|
|
21
22
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
import type { FeatureName } from '../config.js';
|
|
2
|
+
import type { Config, FeatureName } from '../config.js';
|
|
3
3
|
import type { FileStat } from '../scan.js';
|
|
4
4
|
export interface ReconcileDelta {
|
|
5
5
|
files: FileStat[];
|
|
@@ -18,4 +18,5 @@ export interface Feature {
|
|
|
18
18
|
remove?(db: DatabaseSync, path: string, delta: ReconcileDelta): void;
|
|
19
19
|
store?(db: DatabaseSync, path: string, extracted: unknown, delta: ReconcileDelta): void;
|
|
20
20
|
afterReconcile?(db: DatabaseSync, delta: ReconcileDelta): void;
|
|
21
|
+
enabledForFile?(cfg: Config, file: FileStat): boolean;
|
|
21
22
|
}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
export {
|
|
3
|
-
export type { Config, EmbedConfig, FeatureName, ResolvedConfig,
|
|
1
|
+
export type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands.js';
|
|
2
|
+
export { mapTree, peek, presetCoverage, search } from './commands.js';
|
|
3
|
+
export type { Config, EmbedConfig, FeatureName, Preset, ResolvedConfig, SavedQuery, SavedSearch } from './config.js';
|
|
4
4
|
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config.js';
|
|
5
5
|
export type { OpenResult } from './db.js';
|
|
6
6
|
export { open, rebuild } from './db.js';
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
export {
|
|
3
|
-
export type { Config, EmbedConfig, FeatureName, ResolvedConfig,
|
|
1
|
+
export type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands.js';
|
|
2
|
+
export { mapTree, peek, presetCoverage, search } from './commands.js';
|
|
3
|
+
export type { Config, EmbedConfig, FeatureName, Preset, ResolvedConfig, SavedQuery, SavedSearch } from './config.js';
|
|
4
4
|
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config.js';
|
|
5
5
|
export type { OpenResult } from './db.js';
|
|
6
6
|
export { open, rebuild } from './db.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -23,9 +23,6 @@ _export(exports, {
|
|
|
23
23
|
get SenseError () {
|
|
24
24
|
return _errorsts.SenseError;
|
|
25
25
|
},
|
|
26
|
-
get find () {
|
|
27
|
-
return _commandsts.find;
|
|
28
|
-
},
|
|
29
26
|
get initConfig () {
|
|
30
27
|
return _configts.initConfig;
|
|
31
28
|
},
|
|
@@ -44,6 +41,9 @@ _export(exports, {
|
|
|
44
41
|
get peek () {
|
|
45
42
|
return _commandsts.peek;
|
|
46
43
|
},
|
|
44
|
+
get presetCoverage () {
|
|
45
|
+
return _commandsts.presetCoverage;
|
|
46
|
+
},
|
|
47
47
|
get printRows () {
|
|
48
48
|
return _outputts.printRows;
|
|
49
49
|
},
|
|
@@ -52,6 +52,9 @@ _export(exports, {
|
|
|
52
52
|
},
|
|
53
53
|
get runWatch () {
|
|
54
54
|
return _watchts.runWatch;
|
|
55
|
+
},
|
|
56
|
+
get search () {
|
|
57
|
+
return _commandsts.search;
|
|
55
58
|
}
|
|
56
59
|
});
|
|
57
60
|
var _commandsts = require("./commands.js");
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type {
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands.ts';\nexport { mapTree, peek, presetCoverage, search } from './commands.ts';\nexport type { Config, EmbedConfig, FeatureName, Preset, ResolvedConfig, SavedQuery, SavedSearch } from './config.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config.ts';\nexport type { OpenResult } from './db.ts';\nexport { open, rebuild } from './db.ts';\nexport type { SenseErrorCode } from './errors.ts';\nexport { SenseError } from './errors.ts';\nexport type { Row } from './output.ts';\nexport { printRows } from './output.ts';\n\nexport type { WatchEvent, WatchOptions } from './watch.ts';\nexport { runWatch } from './watch.ts';\n"],"names":["CONFIG_FILENAME","STATE_DIR","SUPPORTED_CONFIG_VERSION","SenseError","initConfig","loadConfig","mapTree","migrateConfig","open","peek","presetCoverage","printRows","rebuild","runWatch","search"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;;;;;;;;;;;;QAK9DA;eAAAA,yBAAe;;QAAyCC;eAAAA,mBAAS;;QAAEC;eAAAA,kCAAwB;;QAI3FC;eAAAA,oBAAU;;QAJOC;eAAAA,oBAAU;;QAAEC;eAAAA,oBAAU;;QAFvCC;eAAAA,mBAAO;;QAEkCC;eAAAA,uBAAa;;QAEtDC;eAAAA,UAAI;;QAJKC;eAAAA,gBAAI;;QAAEC;eAAAA,0BAAc;;QAQ7BC;eAAAA,mBAAS;;QAJHC;eAAAA,aAAO;;QAObC;eAAAA,iBAAQ;;QAXuBC;eAAAA,kBAAM;;;0BAAQ;wBAEsD;oBAE9E;wBAEH;wBAED;uBAGD"}
|
package/dist/cjs/output.d.cts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export type Row = Record<string, unknown>;
|
|
2
2
|
export declare function printRows(rows: Row[], format: 'table' | 'json'): void;
|
|
3
|
+
export declare function featureOffHint(name: string): string;
|
|
4
|
+
export declare function featuresLine(features: {
|
|
5
|
+
on: string[];
|
|
6
|
+
off: string[];
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function presetsLines(presets: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
files: number;
|
|
11
|
+
embedded: number;
|
|
12
|
+
}>): string[];
|
|
3
13
|
export declare function renderMap(result: {
|
|
4
14
|
docs: {
|
|
5
15
|
count: number;
|
|
@@ -11,6 +21,11 @@ export declare function renderMap(result: {
|
|
|
11
21
|
on: string[];
|
|
12
22
|
off: string[];
|
|
13
23
|
};
|
|
24
|
+
presets: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
files: number;
|
|
27
|
+
embedded: number;
|
|
28
|
+
}>;
|
|
14
29
|
hubs: Row[];
|
|
15
30
|
recent: Row[];
|
|
16
31
|
}): string;
|
package/dist/cjs/output.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export type Row = Record<string, unknown>;
|
|
2
2
|
export declare function printRows(rows: Row[], format: 'table' | 'json'): void;
|
|
3
|
+
export declare function featureOffHint(name: string): string;
|
|
4
|
+
export declare function featuresLine(features: {
|
|
5
|
+
on: string[];
|
|
6
|
+
off: string[];
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function presetsLines(presets: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
files: number;
|
|
11
|
+
embedded: number;
|
|
12
|
+
}>): string[];
|
|
3
13
|
export declare function renderMap(result: {
|
|
4
14
|
docs: {
|
|
5
15
|
count: number;
|
|
@@ -11,6 +21,11 @@ export declare function renderMap(result: {
|
|
|
11
21
|
on: string[];
|
|
12
22
|
off: string[];
|
|
13
23
|
};
|
|
24
|
+
presets: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
files: number;
|
|
27
|
+
embedded: number;
|
|
28
|
+
}>;
|
|
14
29
|
hubs: Row[];
|
|
15
30
|
recent: Row[];
|
|
16
31
|
}): string;
|
package/dist/cjs/output.js
CHANGED
|
@@ -10,6 +10,15 @@ function _export(target, all) {
|
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
12
|
_export(exports, {
|
|
13
|
+
get featureOffHint () {
|
|
14
|
+
return featureOffHint;
|
|
15
|
+
},
|
|
16
|
+
get featuresLine () {
|
|
17
|
+
return featuresLine;
|
|
18
|
+
},
|
|
19
|
+
get presetsLines () {
|
|
20
|
+
return presetsLines;
|
|
21
|
+
},
|
|
13
22
|
get printRows () {
|
|
14
23
|
return printRows;
|
|
15
24
|
},
|
|
@@ -146,22 +155,34 @@ function renderRows(rows, format) {
|
|
|
146
155
|
}).join(' ')
|
|
147
156
|
].concat(_to_consumable_array(cells.map(formatRow))).join('\n');
|
|
148
157
|
}
|
|
149
|
-
|
|
158
|
+
function featureOffHint(name) {
|
|
159
|
+
return name === 'embed' ? 'no preset has semantic on' : "features.".concat(name);
|
|
160
|
+
}
|
|
150
161
|
function featuresLine(features) {
|
|
151
162
|
var off = features.off.length > 0 ? " \xb7 off: ".concat(features.off.map(function(name) {
|
|
152
|
-
return "".concat(name, " (
|
|
163
|
+
return "".concat(name, " (").concat(featureOffHint(name), ")");
|
|
153
164
|
}).join(', ')) : '';
|
|
154
165
|
return "features: ".concat(features.on.join(', ')).concat(off);
|
|
155
166
|
}
|
|
167
|
+
function presetsLines(presets) {
|
|
168
|
+
return [
|
|
169
|
+
'presets:'
|
|
170
|
+
].concat(_to_consumable_array(presets.map(function(p) {
|
|
171
|
+
return " ".concat(p.name, ": ").concat(p.files, " file(s), ").concat(p.embedded, " embedded");
|
|
172
|
+
})));
|
|
173
|
+
}
|
|
156
174
|
function renderMap(result) {
|
|
157
175
|
var parts = [
|
|
158
176
|
"docs: ".concat(result.docs.count, " (").concat(Math.round(result.docs.bytes / 1024), " KB)"),
|
|
159
|
-
|
|
177
|
+
featuresLine(result.features),
|
|
178
|
+
''
|
|
179
|
+
].concat(_to_consumable_array(presetsLines(result.presets)), [
|
|
180
|
+
'',
|
|
160
181
|
renderRows(result.fields, 'table')
|
|
161
|
-
];
|
|
182
|
+
]);
|
|
162
183
|
if (result.fieldsTotal > result.fields.length) parts.push("(+".concat(result.fieldsTotal - result.fields.length, " more fields)"));
|
|
163
184
|
if (result.hubs.length > 0) parts.push('\nhubs (by link rank):', renderRows(result.hubs, 'table'));
|
|
164
|
-
else if (result.features.off.includes('rank')) parts.push(
|
|
185
|
+
else if (result.features.off.includes('rank')) parts.push("\nhubs: off (".concat(featureOffHint('rank'), ")"));
|
|
165
186
|
parts.push('\nrecent:', renderRows(result.recent, 'table'));
|
|
166
187
|
return parts.join('\n');
|
|
167
188
|
}
|