sensemaking 0.11.4 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +4 -3
  2. package/bin/cli.js +5 -2
  3. package/dist/cjs/cli/index.d.cts +3 -3
  4. package/dist/cjs/cli/index.d.ts +3 -3
  5. package/dist/cjs/cli/index.js +3 -3
  6. package/dist/cjs/cli/index.js.map +1 -1
  7. package/dist/cjs/cli/named.js +2 -2
  8. package/dist/cjs/cli/named.js.map +1 -1
  9. package/dist/cjs/cli/related.js +1 -1
  10. package/dist/cjs/cli/related.js.map +1 -1
  11. package/dist/cjs/cli/search.js +1 -1
  12. package/dist/cjs/cli/search.js.map +1 -1
  13. package/dist/cjs/cli/shared.d.cts +3 -1
  14. package/dist/cjs/cli/shared.d.ts +3 -1
  15. package/dist/cjs/cli/shared.js +35 -5
  16. package/dist/cjs/cli/shared.js.map +1 -1
  17. package/dist/cjs/cli/sql.js +1 -1
  18. package/dist/cjs/cli/sql.js.map +1 -1
  19. package/dist/cjs/cli.js +14 -1
  20. package/dist/cjs/cli.js.map +1 -1
  21. package/dist/cjs/commands.js +19 -5
  22. package/dist/cjs/commands.js.map +1 -1
  23. package/dist/cjs/config.d.cts +4 -0
  24. package/dist/cjs/config.d.ts +4 -0
  25. package/dist/cjs/config.js +39 -4
  26. package/dist/cjs/config.js.map +1 -1
  27. package/dist/cjs/db.d.cts +1 -1
  28. package/dist/cjs/db.d.ts +1 -1
  29. package/dist/cjs/db.js +158 -14
  30. package/dist/cjs/db.js.map +1 -1
  31. package/dist/cjs/output.d.cts +4 -1
  32. package/dist/cjs/output.d.ts +4 -1
  33. package/dist/cjs/output.js +158 -6
  34. package/dist/cjs/output.js.map +1 -1
  35. package/dist/cjs/segment.d.cts +2 -0
  36. package/dist/cjs/segment.d.ts +2 -0
  37. package/dist/cjs/segment.js +98 -0
  38. package/dist/cjs/segment.js.map +1 -0
  39. package/dist/esm/cli/index.d.ts +3 -3
  40. package/dist/esm/cli/index.js +3 -3
  41. package/dist/esm/cli/index.js.map +1 -1
  42. package/dist/esm/cli/named.js +3 -3
  43. package/dist/esm/cli/named.js.map +1 -1
  44. package/dist/esm/cli/related.js +2 -2
  45. package/dist/esm/cli/related.js.map +1 -1
  46. package/dist/esm/cli/search.js +2 -2
  47. package/dist/esm/cli/search.js.map +1 -1
  48. package/dist/esm/cli/shared.d.ts +3 -1
  49. package/dist/esm/cli/shared.js +32 -5
  50. package/dist/esm/cli/shared.js.map +1 -1
  51. package/dist/esm/cli/sql.js +2 -2
  52. package/dist/esm/cli/sql.js.map +1 -1
  53. package/dist/esm/cli.js +14 -1
  54. package/dist/esm/cli.js.map +1 -1
  55. package/dist/esm/commands.js +19 -5
  56. package/dist/esm/commands.js.map +1 -1
  57. package/dist/esm/config.d.ts +4 -0
  58. package/dist/esm/config.js +37 -4
  59. package/dist/esm/config.js.map +1 -1
  60. package/dist/esm/db.d.ts +1 -1
  61. package/dist/esm/db.js +140 -15
  62. package/dist/esm/db.js.map +1 -1
  63. package/dist/esm/output.d.ts +4 -1
  64. package/dist/esm/output.js +104 -4
  65. package/dist/esm/output.js.map +1 -1
  66. package/dist/esm/segment.d.ts +2 -0
  67. package/dist/esm/segment.js +65 -0
  68. package/dist/esm/segment.js.map +1 -0
  69. package/package.json +4 -1
  70. package/schema.json +12 -1
  71. package/skills/sense/SKILL.md +7 -6
  72. package/skills/sense-setup/SKILL.md +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db.ts"],"sourcesContent":["// The Node floor (>=22.20) is explained here and nowhere else: 22.20 is the first release with\n// both FTS5 and row-returning INSERT ... RETURNING. Raise it only for a load-bearing capability.\nimport { 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// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_size', '_parse_error']);\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`. Bumping it rebuilds\n// existing trees on first query.\nexport const SCHEMA_VERSION = '10';\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, \"_parse_error\" TEXT)`);\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. path leads the PK so the\n // per-doc delete is an index hit -- keyed the other way, cold builds went quadratic.\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 the config names an embedding model).\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 // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\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 // Only for docs that have rows: an unconditional delete made cold crawls quadratic.\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 // A preset edit forces a full rebuild, so an unchanged doc's coverage is already\n // correct; new docs have nothing to clear, which 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 (~5s for 500 files at 26k notes). A query\n // 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 clearCache(cfg);\n return open(cfg);\n }\n\n ensureSchema(db, cfg);\n\n // 3x the largest reconcile this cache has recorded, floored at 30s and capped at 10min.\n // Installed before reconcile() -- that call is the one that races a watcher's transaction.\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// Deletes the cache directory, and only that. The rebuild is not this function's job: the next\n// open() reconciles, which is what running any command already does, so a verb that bundled the\n// two described the half that was not its own. Manual reset for a doubted cache; the schema and\n// config-signature mismatches below reset themselves.\nexport function clearCache(cfg: ResolvedConfig): void {\n rmSync(join(cfg.baseDir, STATE_DIR), { recursive: true, force: true });\n}\n"],"names":["DB_FILENAME","SCHEMA_VERSION","clearCache","docCount","getMeta","open","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","parseError","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","recordedMaxMs","Math","min","max","rmSync","force"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db.ts"],"sourcesContent":["// The Node floor (>=22.20) is explained here and nowhere else: 22.20 is the first release with\n// both FTS5 and row-returning INSERT ... RETURNING. Raise it only for a load-bearing capability.\nimport { mkdirSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { DatabaseSync, type StatementSync } from 'node:sqlite';\nimport type { Config, ResolvedConfig } from './config.ts';\nimport { contentTokenize, 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';\nimport { segmentField, segmentMatch } from './segment.ts';\n\n// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_size', '_parse_error']);\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`. Bumping it rebuilds\n// existing trees on first query.\nexport const SCHEMA_VERSION = '12';\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, segmenting: boolean): 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 // Raw `content MATCH '<unspaced text>'` cannot be rewritten behind the author's back, and\n // matches nothing, so the same transform is available to hand-written SQL by name. `segmenting`\n // is the same config predicate commands.ts's search() gates on (contentTokenize(cfg) ===\n // undefined), passed in by open() rather than read back from persisted state.\n db.function('segment', { deterministic: true, varargs: false }, (terms: unknown): string => {\n const text = terms === null || terms === undefined ? '' : String(terms);\n return segmenting ? segmentMatch(text) : text;\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// Stemming is English-only, but the segmentation underneath it is what decides coverage:\n// unicode61 splits on spaces, so a language written without them (Chinese, Japanese, Thai)\n// indexes a whole run as one token and word search finds nothing. `content.tokenize` is how\n// such a tree picks trigram instead.\nconst DEFAULT_TOKENIZE = 'porter unicode61';\n\n// FTS5 takes its tokenizer as a string literal inside DDL, where nothing can bind, so a\n// configured value has to be concatenated. Probing a throwaway table is what makes that safe\n// and is also the whole validation: anything the linked SQLite accepts passes, anything else\n// fails here with SQLite's own message rather than against the real table. It means no table\n// of which version added which tokenizer has to be maintained.\nfunction resolveTokenize(db: DatabaseSync, cfg: Config): string {\n const configured = contentTokenize(cfg);\n if (configured === undefined) return DEFAULT_TOKENIZE;\n const literal = configured.replace(/'/g, \"''\");\n try {\n db.exec('DROP TABLE IF EXISTS temp.sense_tokenize_probe');\n db.exec(`CREATE VIRTUAL TABLE temp.sense_tokenize_probe USING fts5(x, tokenize = '${literal}')`);\n db.exec('DROP TABLE IF EXISTS temp.sense_tokenize_probe');\n } catch (err) {\n throw new SenseError('CONFIG_INVALID', `content.tokenize \"${configured}\" is not a tokenizer this SQLite accepts (${(err as Error).message}); the built-in choices are unicode61, ascii, porter, and trigram, each with their own options`);\n }\n return literal;\n}\n\n// The tokenizer the content table was actually built with, from its own DDL -- the one\n// record that cannot desynchronize from the table. NULL when the table does not exist yet.\nfunction storedTokenize(db: DatabaseSync): string | null {\n const row = db.prepare(`SELECT sql FROM sqlite_master WHERE name = 'content'`).get() as { sql: string } | undefined;\n if (!row) return null;\n const m = row.sql.match(/tokenize = '((?:[^']|'')*)'/);\n return m ? m[1] : null;\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, tokenize: string): void {\n db.exec(`CREATE TABLE IF NOT EXISTS frontmatter (\"path\" TEXT PRIMARY KEY, \"_mtime\" REAL, \"_size\" INTEGER, \"_parse_error\" TEXT)`);\n // IF NOT EXISTS is safe against a tokenizer change: open() compares the table's own DDL\n // against the resolved tokenizer before this runs, so a stale table is already gone by now.\n // The three `_seg` sidecars are appended after path, never inserted: bm25(content, ...) and\n // snippet(content, 2, ...) are documented against the first three columns and keep working\n // (FTS5 defaults the weights it was not given). Each carries its field's exploded unspaced\n // runs for text that needs it, and an empty string for text that does not.\n db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS content USING fts5(title, summary, text, path UNINDEXED, title_seg, summary_seg, text_seg, tokenize = '${tokenize}')`);\n // Coverage, not ownership: a path can appear under several presets. path leads the PK so the\n // per-doc delete is an index hit -- keyed the other way, cold builds went quadratic.\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\n// Shared by reconcile() and the tokenize-only rebuild in open(), so both prepare the same\n// literal instead of two copies drifting apart.\nconst INSERT_CONTENT_SQL = `INSERT INTO content (rowid, title, summary, text, \"path\", title_seg, summary_seg, text_seg) VALUES ((SELECT rowid FROM frontmatter WHERE \"path\" = ?), ?, ?, ?, ?, ?, ?, ?)`;\n\n// Shared by reconcile() and the tokenize-only rebuild in open(), so content population is\n// defined once. Assumes the frontmatter row for doc.relPath already exists (rowid lookup).\nfunction insertContentRow(insertBody: StatementSync, doc: ParsedDoc, segmenting: boolean): void {\n insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath, segmenting ? segmentField(doc.search.title) : '', segmenting ? segmentField(doc.search.summary) : '', segmenting ? segmentField(doc.search.text) : '');\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 the config names an embedding model).\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_CONTENT_SQL);\n // A non-default tokenizer means the tree has chosen its own scheme; a phrase query over\n // grapheme runs would be nonsense against trigram, so the sidecars stay empty.\n const segmenting = contentTokenize(cfg) === undefined;\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 // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\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 // Only for docs that have rows: an unconditional delete made cold crawls quadratic.\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 insertContentRow(insertBody, doc, segmenting);\n // A preset edit forces a full rebuild, so an unchanged doc's coverage is already\n // correct; new docs have nothing to clear, which 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// Segment keys that moved between two feature signatures (see config.featureSignature's\n// format: global features, embed provider, tokenize, then one segment per preset).\nfunction changedSignatureKeys(before: string, after: string): Set<string> {\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 return changed;\n}\n\n// Names what moved, for the rebuild notice.\nfunction signatureDiff(before: string, after: string): string {\n const changed = changedSignatureKeys(before, after);\n const label = (key: string) => (key === 'embed' ? 'embed settings' : key === 'tokenize' ? 'content tokenizer' : key.startsWith('preset:') ? `preset \"${key.slice(7)}\"` : 'features');\n return changed.size === 0 ? 'features' : [...changed].map(label).join(', ');\n}\n\n// The tokenize-only rebuild in open(): content is dropped and repopulated from files already\n// listed in frontmatter, which itself is untouched. Frontmatter, links, sections, and\n// embeddings are file-derived and tokenizer-independent, so they survive. No feature extractors\n// run here -- doc.search (title/summary/text) is all content population needs. Returns\n// parseFile's per-file warnings (e.g. a bad date) so open() can surface them -- mtimes are\n// untouched, so reconcile() never reparses these files and would otherwise never emit them again.\nfunction rebuildContentTable(db: DatabaseSync, cfg: Config, baseDir: string): string[] {\n const known = new Set((db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path));\n const files = listFiles(cfg, baseDir).filter((f) => known.has(f.relPath));\n const segmenting = contentTokenize(cfg) === undefined;\n const insertBody = db.prepare(INSERT_CONTENT_SQL);\n const warnings: string[] = [];\n db.exec('BEGIN');\n try {\n for (const file of files) {\n const { doc, warnings: fileWarnings } = parseFile(file);\n warnings.push(...fileWarnings);\n insertContentRow(insertBody, doc, segmenting);\n }\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n return 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 (~5s for 500 files at 26k notes). A query\n // that outwaits it still fails loudly.\n db.exec('PRAGMA busy_timeout = 30000');\n registerFunctions(db, contentTokenize(cfg) === undefined);\n\n db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n // Before the rebuild branch below, never after: that branch deletes the cache, so a typo'd\n // tokenizer validated later would cost a full re-index (and re-embed) to reach its own error.\n const tokenize = resolveTokenize(db, cfg);\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 let tokenizeOnlyRebuild = false;\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 db.close();\n clearCache(cfg);\n return open(cfg);\n }\n const changedKeys = changedSignatureKeys(features ?? '', wantFeatures);\n // Only the tokenizer moved: frontmatter, links, sections, and embeddings are file-derived\n // and tokenizer-independent, so they don't need re-deriving. Everything else -- a preset\n // edit, an embed model change -- still takes the full clear/reopen below.\n if (changedKeys.size === 1 && changedKeys.has('tokenize')) {\n console.error('sense: config change (content tokenizer) rebuilds the text index; vectors, links, and sections are kept');\n db.exec('DROP TABLE content');\n tokenizeOnlyRebuild = true;\n } else {\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) rebuilds the index`);\n db.close();\n clearCache(cfg);\n return open(cfg);\n }\n }\n\n // Meta can lie after a crash between table creation and the signature write; the table's\n // own DDL cannot. A mismatch here rebuilds no matter what meta says. A tokenize-only rebuild\n // just dropped content above, so storedTokenize sees no table and this guard is skipped\n // naturally rather than needing its own case.\n const stored = storedTokenize(db);\n if (stored !== null && stored !== tokenize) {\n console.error('sense: cache was built with a different content tokenizer; rebuilding the index');\n db.close();\n clearCache(cfg);\n return open(cfg);\n }\n\n ensureSchema(db, cfg, tokenize);\n\n let rebuildWarnings: string[] = [];\n if (tokenizeOnlyRebuild) {\n rebuildWarnings = rebuildContentTable(db, cfg, cfg.baseDir);\n setMeta(db, 'features', wantFeatures);\n }\n\n // 3x the largest reconcile this cache has recorded, floored at 30s and capped at 10min.\n // Installed before reconcile() -- that call is the one that races a watcher's transaction.\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: [...rebuildWarnings, ...warnings] };\n}\n\n// Deletes the cache directory, and only that. The rebuild is not this function's job: the next\n// open() reconciles, which is what running any command already does, so a verb that bundled the\n// two described the half that was not its own. Manual reset for a doubted cache; the schema and\n// config-signature mismatches below reset themselves.\nexport function clearCache(cfg: ResolvedConfig): void {\n rmSync(join(cfg.baseDir, STATE_DIR), { recursive: true, force: true });\n}\n"],"names":["DB_FILENAME","SCHEMA_VERSION","clearCache","docCount","getMeta","open","reconcile","setMeta","CORE_FRONTMATTER_COLUMNS","Set","MAX_FRONTMATTER_COLUMNS","quoteIdent","name","split","join","registerFunctions","db","segmenting","function","deterministic","varargs","field","value","undefined","needle","String","startsWith","parsed","JSON","parse","Array","isArray","some","item","includes","terms","text","segmentMatch","getColumns","rows","prepare","all","map","r","DEFAULT_TOKENIZE","resolveTokenize","cfg","configured","contentTokenize","literal","replace","exec","err","SenseError","message","storedTokenize","row","get","m","sql","match","ensureSchema","tokenize","activeFeatures","feature","schema","featureSignature","key","run","INSERT_CONTENT_SQL","insertContentRow","insertBody","doc","relPath","search","title","summary","segmentField","n","baseDir","files","listFiles","currentSet","f","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","fileWarnings","tick","push","Object","keys","data","add","finish","allColumns","writableColumns","c","RESERVED_COLUMNS","insertSql","added","delta","reparsed","d","txStart","Date","now","col","delBody","delPresetFiles","insertPresetFile","del","remove","insert","values","parseError","presets","presetName","store","extracted","afterReconcile","durationMs","prevRaw","prevMax","Number","changedSignatureKeys","before","after","keyOf","part","slice","sig","a","b","changed","val","signatureDiff","label","rebuildContentTable","known","stateDir","STATE_DIR","mkdirSync","recursive","dbPath","DatabaseSync","version","wantFeatures","tokenizeOnlyRebuild","console","error","close","changedKeys","stored","rebuildWarnings","recordedMaxMs","Math","min","max","rmSync","force"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  export type Row = Record<string, unknown>;
2
- export declare function printRows(rows: Row[], format: 'table' | 'json'): void;
2
+ export type Format = 'table' | 'json';
3
+ export type RowFormat = Format | 'csv';
4
+ export declare function printRows(rows: Row[], format: RowFormat, columns?: string[]): void;
5
+ export declare function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void;
3
6
  export declare function featureOffHint(name: string): string;
4
7
  export declare function featuresLine(features: {
5
8
  on: string[];
@@ -1,5 +1,8 @@
1
1
  export type Row = Record<string, unknown>;
2
- export declare function printRows(rows: Row[], format: 'table' | 'json'): void;
2
+ export type Format = 'table' | 'json';
3
+ export type RowFormat = Format | 'csv';
4
+ export declare function printRows(rows: Row[], format: RowFormat, columns?: string[]): void;
5
+ export declare function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void;
3
6
  export declare function featureOffHint(name: string): string;
4
7
  export declare function featuresLine(features: {
5
8
  on: string[];
@@ -1,4 +1,4 @@
1
- // rows -> table (default) | json
1
+ // rows -> table (default) | json | csv
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
@@ -19,6 +19,9 @@ _export(exports, {
19
19
  get presetsLines () {
20
20
  return presetsLines;
21
21
  },
22
+ get printRowStream () {
23
+ return printRowStream;
24
+ },
22
25
  get printRows () {
23
26
  return printRows;
24
27
  },
@@ -40,6 +43,19 @@ function _array_with_holes(arr) {
40
43
  function _array_without_holes(arr) {
41
44
  if (Array.isArray(arr)) return _array_like_to_array(arr);
42
45
  }
46
+ function _define_property(obj, key, value) {
47
+ if (key in obj) {
48
+ Object.defineProperty(obj, key, {
49
+ value: value,
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true
53
+ });
54
+ } else {
55
+ obj[key] = value;
56
+ }
57
+ return obj;
58
+ }
43
59
  function _iterable_to_array(iter) {
44
60
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
45
61
  }
@@ -79,6 +95,10 @@ function _sliced_to_array(arr, i) {
79
95
  function _to_consumable_array(arr) {
80
96
  return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
81
97
  }
98
+ function _type_of(obj) {
99
+ "@swc/helpers - typeof";
100
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
101
+ }
82
102
  function _unsupported_iterable_to_array(o, minLen) {
83
103
  if (!o) return;
84
104
  if (typeof o === "string") return _array_like_to_array(o, minLen);
@@ -93,12 +113,144 @@ var OVERSIZE_BYTES = 50000;
93
113
  function cell(value) {
94
114
  return String(value !== null && value !== void 0 ? value : '').replace(/\s*\n\s*/g, ' ');
95
115
  }
96
- function printRows(rows, format) {
97
- var rendered = renderRows(rows, format);
98
- console.log(rendered);
99
- if (rendered.length > OVERSIZE_BYTES) {
100
- console.warn("warning: result is ".concat(Math.round(rendered.length / 1000), " KB across ").concat(rows.length, " row(s); consider a LIMIT, fewer columns, or snippet() instead of whole values"));
116
+ // RFC 4180, and deliberately not cell(): csv is the format for redirecting a result to a
117
+ // file, so it keeps every character, embedded newlines included. What it cannot carry is
118
+ // NULL vs empty string, or a value's type -- that is what json is for.
119
+ function csvField(value) {
120
+ var text = value === null || value === undefined ? '' : String(value);
121
+ return /["\r\n,]/.test(text) ? '"'.concat(text.replace(/"/g, '""'), '"') : text;
122
+ }
123
+ function csvLine(values) {
124
+ return values.map(csvField).join(',');
125
+ }
126
+ function warnOversize(bytes, rowCount) {
127
+ if (bytes <= OVERSIZE_BYTES) return;
128
+ console.warn("warning: result is ".concat(Math.round(bytes / 1000), " KB across ").concat(rowCount, " row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file"));
129
+ }
130
+ function printRows(rows, format, columns) {
131
+ if (format === 'csv') {
132
+ // Collapsed the same way a row object collapses them, so a statement naming a column
133
+ // twice describes itself identically whether it matched anything or not.
134
+ var names = rows.length > 0 ? Object.keys(rows[0]) : _to_consumable_array(new Set(columns !== null && columns !== void 0 ? columns : []));
135
+ if (names.length === 0) return;
136
+ var rendered = [
137
+ csvLine(names)
138
+ ].concat(_to_consumable_array(rows.map(function(row) {
139
+ return csvLine(names.map(function(name) {
140
+ return row[name];
141
+ }));
142
+ }))).join('\n');
143
+ console.log(rendered);
144
+ // Bytes, not code units -- CJK is 3 bytes per character.
145
+ warnOversize(Buffer.byteLength(rendered), rows.length);
146
+ return;
147
+ }
148
+ var rendered1 = renderRows(rows, format);
149
+ console.log(rendered1);
150
+ warnOversize(Buffer.byteLength(rendered1), rows.length);
151
+ }
152
+ function printRowStream(rows, format, columns) {
153
+ var iterator = rows[Symbol.iterator]();
154
+ // One step before any write. FTS5 parses a MATCH expression at step time rather than at
155
+ // prepare time, so a bad search string throws here, with stdout still clean for the error.
156
+ var first = iterator.next();
157
+ var rest = _define_property({}, Symbol.iterator, function() {
158
+ return iterator;
159
+ });
160
+ if (format === 'table') {
161
+ printRows(first.done ? [] : [
162
+ first.value
163
+ ].concat(_to_consumable_array(rest)), format, columns);
164
+ return;
165
+ }
166
+ var bytes = 0;
167
+ var rowCount = 0;
168
+ var write = function write(text) {
169
+ // Bytes, not code units -- CJK is 3 bytes per character.
170
+ bytes += Buffer.byteLength(text);
171
+ process.stdout.write(text);
172
+ };
173
+ if (format === 'json') {
174
+ // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one
175
+ // level, comma-joined, inside the array brackets written here.
176
+ // JSON.stringify throws on BigInt, so a row with an int64 past 2^53 (setReadBigInts) is
177
+ // converted via the replacer: a value that fits a safe integer stays a number, a larger one
178
+ // becomes its decimal string, since a JSON number cannot carry it losslessly.
179
+ var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
180
+ var bigintSafe = function bigintSafe(_key, value) {
181
+ return (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'bigint' ? value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString() : value;
182
+ };
183
+ var indent = function indent(row) {
184
+ return JSON.stringify(row, bigintSafe, 2).split('\n').map(function(line) {
185
+ return " ".concat(line);
186
+ }).join('\n');
187
+ };
188
+ if (first.done) {
189
+ write('[]\n');
190
+ } else {
191
+ write('[\n');
192
+ write(indent(first.value));
193
+ rowCount = 1;
194
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
195
+ try {
196
+ for(var _iterator = rest[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
197
+ var row = _step.value;
198
+ write(',\n');
199
+ write(indent(row));
200
+ rowCount++;
201
+ }
202
+ } catch (err) {
203
+ _didIteratorError = true;
204
+ _iteratorError = err;
205
+ } finally{
206
+ try {
207
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
208
+ _iterator.return();
209
+ }
210
+ } finally{
211
+ if (_didIteratorError) {
212
+ throw _iteratorError;
213
+ }
214
+ }
215
+ }
216
+ write('\n]\n');
217
+ }
218
+ } else if (first.done) {
219
+ var names = _to_consumable_array(new Set(columns));
220
+ if (names.length > 0) write("".concat(csvLine(names), "\n"));
221
+ } else {
222
+ var names1 = Object.keys(first.value);
223
+ write("".concat(csvLine(names1), "\n"));
224
+ write("".concat(csvLine(names1.map(function(name) {
225
+ return first.value[name];
226
+ })), "\n"));
227
+ rowCount = 1;
228
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
229
+ try {
230
+ var _loop = function() {
231
+ var row = _step1.value;
232
+ write("".concat(csvLine(names1.map(function(name) {
233
+ return row[name];
234
+ })), "\n"));
235
+ rowCount++;
236
+ };
237
+ for(var _iterator1 = rest[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true)_loop();
238
+ } catch (err) {
239
+ _didIteratorError1 = true;
240
+ _iteratorError1 = err;
241
+ } finally{
242
+ try {
243
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
244
+ _iterator1.return();
245
+ }
246
+ } finally{
247
+ if (_didIteratorError1) {
248
+ throw _iteratorError1;
249
+ }
250
+ }
251
+ }
101
252
  }
253
+ warnOversize(bytes, rowCount);
102
254
  }
103
255
  // Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns
104
256
  // give up space first, down to a floor. --format json is never truncated.
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output.ts"],"sourcesContent":["// rows -> table (default) | json\n\nexport type Row = Record<string, unknown>;\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output is left alone.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\nexport function printRows(rows: Row[], format: 'table' | 'json'): void {\n const rendered = renderRows(rows, format);\n console.log(rendered);\n if (rendered.length > OVERSIZE_BYTES) {\n console.warn(`warning: result is ${Math.round(rendered.length / 1000)} KB across ${rows.length} row(s); consider a LIMIT, fewer columns, or snippet() instead of whole values`);\n }\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\nfunction renderRows(rows: Row[], format: 'table' | 'json', width = process.stdout.columns): string {\n if (format === 'json') return JSON.stringify(rows, null, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const cells = rows.map((row) => columns.map((col) => cell(row[col])));\n const natural = columns.map((col, i) => Math.max(col.length, ...cells.map((row) => row[i].length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...cells.map(formatRow)].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a semantic-off preset says which.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.semantic === false ? ' (semantic: false)' : ''}`)];\n}\n\nexport function renderMap(result: { docs: { count: number; bytes: number }; fields: Row[]; fieldsTotal: number; features: { on: string[]; off: string[] }; presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>; hubs: Row[]; recent: Row[] }): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:', renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: { path: string; tokens: number; frontmatter: Row; parseError?: string | null; sections: Row[]; outbound: string[]; backlinks: string[]; unresolved: string[]; sectionsTotal: number; outboundTotal: number; backlinksTotal: number; unresolvedTotal: number; off: string[] }): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level as number)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRows","renderMap","renderPeek","OVERSIZE_BYTES","cell","value","String","replace","rows","format","rendered","renderRows","console","log","length","warn","Math","round","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","width","process","stdout","columns","JSON","stringify","Object","keys","cells","map","row","col","natural","i","clip","w","padEnd","slice","formatRow","values","join","trimEnd","repeat","name","features","off","on","presets","p","files","embedded","semantic","result","parts","docs","count","bytes","fields","fieldsTotal","push","hubs","includes","recent","lines","path","tokens","parseError","entries","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output.ts"],"sourcesContent":["// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output is left alone.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, and deliberately not cell(): csv is the format for redirecting a result to a\n// file, so it keeps every character, embedded newlines included. What it cannot carry is\n// NULL vs empty string, or a value's type -- that is what json is for.\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// Header names come from a row wherever there is one: a statement's column list keeps\n// duplicates that the row object has already collapsed, so `SELECT a AS x, b AS x` would print\n// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with\n// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --\n// a bare newline would read to a csv parser as one empty record.\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Collapsed the same way a row object collapses them, so a statement naming a column\n // twice describes itself identically whether it matched anything or not.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an\n// iterator, so a large result is never held here as rows and again as a rendered string.\n// Table buffers by necessity (a column is as wide as its widest cell, which the last row can\n// change); json and csv write row by row. The writes are synchronous, so when stdout is a pipe\n// Node buffers what the reader has not taken yet -- the saving is this module's copies, not\n// the operating system's.\nexport function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void {\n const iterator = rows[Symbol.iterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = iterator.next();\n const rest: Iterable<Row> = { [Symbol.iterator]: () => iterator };\n\n if (format === 'table') {\n printRows(first.done ? [] : [first.value, ...rest], format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n // JSON.stringify throws on BigInt, so a row with an int64 past 2^53 (setReadBigInts) is\n // converted via the replacer: a value that fits a safe integer stays a number, a larger one\n // becomes its decimal string, since a JSON number cannot carry it losslessly.\n const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n const bigintSafe = (_key: string, value: unknown) => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n const indent = (row: Row) =>\n JSON.stringify(row, bigintSafe, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\nfunction renderRows(rows: Row[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return JSON.stringify(rows, null, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const cells = rows.map((row) => columns.map((col) => cell(row[col])));\n const natural = columns.map((col, i) => Math.max(col.length, ...cells.map((row) => row[i].length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...cells.map(formatRow)].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a semantic-off preset says which.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.semantic === false ? ' (semantic: false)' : ''}`)];\n}\n\nexport function renderMap(result: { docs: { count: number; bytes: number }; fields: Row[]; fieldsTotal: number; features: { on: string[]; off: string[] }; presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>; hubs: Row[]; recent: Row[] }): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:', renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: { path: string; tokens: number; frontmatter: Row; parseError?: string | null; sections: Row[]; outbound: string[]; backlinks: string[]; unresolved: string[]; sectionsTotal: number; outboundTotal: number; backlinksTotal: number; unresolvedTotal: number; off: string[] }): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level as number)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","test","csvLine","values","map","join","warnOversize","bytes","rowCount","console","warn","Math","round","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","Symbol","first","next","rest","done","write","process","stdout","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","width","cells","col","natural","i","clip","w","padEnd","slice","formatRow","trimEnd","repeat","features","off","on","presets","p","files","embedded","semantic","result","parts","docs","count","fields","fieldsTotal","push","hubs","includes","recent","lines","path","tokens","parseError","entries","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function segmentField(text: string): string;
2
+ export declare function segmentMatch(terms: string): string;
@@ -0,0 +1,2 @@
1
+ export declare function segmentField(text: string): string;
2
+ export declare function segmentMatch(terms: string): string;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get segmentField () {
13
+ return segmentField;
14
+ },
15
+ get segmentMatch () {
16
+ return segmentMatch;
17
+ }
18
+ });
19
+ // Word boundaries FTS5's tokenizers cannot find on their own.
20
+ //
21
+ // Segmentation is context-free: seg(query) appears inside seg(document) whenever the query is
22
+ // a substring of the document. That is the contract -- substring semantics, what `grep` and
23
+ // `LIKE '%..%'` give -- and it is what makes index and query agree on every input, always.
24
+ // Earlier attempts used ICU word segmentation (Intl.Segmenter), which is context-dependent:
25
+ // `东京都政府` splits as `东 | 京都 | 政府` while the query `东京` splits as one word, so the
26
+ // index and the query disagree about identical text. No ICU here. No dictionary.
27
+ // Scripts written without word spaces: a closed set of writing systems.
28
+ // Script_Extensions, not Script: the katakana long-vowel mark ー is Script=Common.
29
+ var SCRIPTS = '\\p{scx=Han}\\p{scx=Hiragana}\\p{scx=Katakana}\\p{scx=Thai}\\p{scx=Khmer}\\p{scx=Lao}\\p{scx=Myanmar}';
30
+ // A run is script BASE characters with their combining marks attached; a bare mark after a
31
+ // Latin letter (decomposed é) never starts one.
32
+ var RUN = new RegExp("((?:[".concat(SCRIPTS, "]\\p{M}*)+)"), 'gu');
33
+ var HAS_RUN = new RegExp("[".concat(SCRIPTS, "]"), 'u');
34
+ // Grapheme = base char plus its marks. Context-free: index and query can never disagree.
35
+ var GRAPHEME = RegExp("([^\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1-\\u05C2\\u05C4-\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7-\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962-\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7-\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2-\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47-\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70-\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2-\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47-\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62-\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55-\\u0C56\\u0C62-\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5-\\u0CD6\\u0CE2-\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B-\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62-\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2-\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18-\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E-\\u0F3F\\u0F71-\\u0F84\\u0F86-\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752-\\u1753\\u1772-\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885-\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099-\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E-\\uA69F\\uA6F0-\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880-\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C-\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7-\\uAAB8\\uAABE-\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5-\\uAAF6\\uABE3-\\uABEA\\uABEC-\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}-\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}-\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}-\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}-\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}-\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}-\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}-\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}-\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}-\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}-\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}-\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}-\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}-\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}-\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}-\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}-\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}-\\u{16FF1}\\u{1BC9D}-\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}-\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}-\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}-\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}][\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1-\\u05C2\\u05C4-\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7-\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962-\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7-\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2-\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47-\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70-\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2-\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47-\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62-\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55-\\u0C56\\u0C62-\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5-\\u0CD6\\u0CE2-\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B-\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62-\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2-\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18-\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E-\\u0F3F\\u0F71-\\u0F84\\u0F86-\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752-\\u1753\\u1772-\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885-\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099-\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E-\\uA69F\\uA6F0-\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880-\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C-\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7-\\uAAB8\\uAABE-\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5-\\uAAF6\\uABE3-\\uABEA\\uABEC-\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}-\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}-\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}-\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}-\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}-\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}-\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}-\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}-\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}-\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}-\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}-\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}-\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}-\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}-\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}-\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}-\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}-\\u{16FF1}\\u{1BC9D}-\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}-\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}-\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}-\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}]*)", "gu");
36
+ // Token barrier between separate runs so their graphemes are never phrase-adjacent.
37
+ // U+A7F7: a letter (so FTS5 keeps it as a token) that no one types into a search.
38
+ var BARRIER = 'ꟷ';
39
+ function graphemes(run) {
40
+ var _run_match;
41
+ return (_run_match = run.match(GRAPHEME)) !== null && _run_match !== void 0 ? _run_match : [];
42
+ }
43
+ function segmentField(text) {
44
+ if (!HAS_RUN.test(text)) return '';
45
+ var out = text.replace(RUN, function(run) {
46
+ return " ".concat(BARRIER, " ").concat(graphemes(run).join(' '), " ").concat(BARRIER, " ");
47
+ });
48
+ return out.replace(/\s+/g, ' ').trim();
49
+ }
50
+ // A `title:`/`summary:`/`text:` qualifier directly before a run that is about to become a
51
+ // quoted grapheme phrase, so the rewrite can retarget it at the matching `_seg` column.
52
+ var QUALIFIER = /(^|[\s(])(-?)(title|summary|text)\s*:\s*$/;
53
+ function segmentMatch(terms) {
54
+ if (!HAS_RUN.test(terms)) return terms;
55
+ var out = '';
56
+ var quoted = false;
57
+ var pieces = terms.split(RUN); // split keeps captured runs at odd indices
58
+ for(var i = 0; i < pieces.length; i++){
59
+ if (i % 2 === 0) {
60
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
61
+ try {
62
+ for(var _iterator = pieces[i][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
63
+ var ch = _step.value;
64
+ if (ch === '"') quoted = !quoted;
65
+ }
66
+ } catch (err) {
67
+ _didIteratorError = true;
68
+ _iteratorError = err;
69
+ } finally{
70
+ try {
71
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
72
+ _iterator.return();
73
+ }
74
+ } finally{
75
+ if (_didIteratorError) {
76
+ throw _iteratorError;
77
+ }
78
+ }
79
+ }
80
+ out += pieces[i];
81
+ continue;
82
+ }
83
+ if (quoted) {
84
+ out += pieces[i]; // an author's phrase is matched as written
85
+ continue;
86
+ }
87
+ var g = graphemes(pieces[i]);
88
+ var phrase = g.length > 1 ? '"'.concat(g.join(' '), '"') : g[0];
89
+ var m = out.match(QUALIFIER);
90
+ if (m) {
91
+ out = "".concat(out.slice(0, m.index)).concat(m[1]).concat(m[2]).concat(m[3], "_seg:").concat(phrase);
92
+ } else {
93
+ out += phrase;
94
+ }
95
+ }
96
+ return out;
97
+ }
98
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/segment.ts"],"sourcesContent":["// Word boundaries FTS5's tokenizers cannot find on their own.\n//\n// Segmentation is context-free: seg(query) appears inside seg(document) whenever the query is\n// a substring of the document. That is the contract -- substring semantics, what `grep` and\n// `LIKE '%..%'` give -- and it is what makes index and query agree on every input, always.\n// Earlier attempts used ICU word segmentation (Intl.Segmenter), which is context-dependent:\n// `东京都政府` splits as `东 | 京都 | 政府` while the query `东京` splits as one word, so the\n// index and the query disagree about identical text. No ICU here. No dictionary.\n\n// Scripts written without word spaces: a closed set of writing systems.\n// Script_Extensions, not Script: the katakana long-vowel mark ー is Script=Common.\nconst SCRIPTS = '\\\\p{scx=Han}\\\\p{scx=Hiragana}\\\\p{scx=Katakana}\\\\p{scx=Thai}\\\\p{scx=Khmer}\\\\p{scx=Lao}\\\\p{scx=Myanmar}';\n// A run is script BASE characters with their combining marks attached; a bare mark after a\n// Latin letter (decomposed é) never starts one.\nconst RUN = new RegExp(`((?:[${SCRIPTS}]\\\\p{M}*)+)`, 'gu');\nconst HAS_RUN = new RegExp(`[${SCRIPTS}]`, 'u');\n// Grapheme = base char plus its marks. Context-free: index and query can never disagree.\nconst GRAPHEME = /(\\P{M}\\p{M}*)/gu;\n// Token barrier between separate runs so their graphemes are never phrase-adjacent.\n// U+A7F7: a letter (so FTS5 keeps it as a token) that no one types into a search.\nconst BARRIER = 'ꟷ';\n\nfunction graphemes(run: string): string[] {\n return run.match(GRAPHEME) ?? [];\n}\n\n// Index side: '' when the field has no unspaced-script run (the common case, paid for by\n// nothing). Otherwise each run explodes into its graphemes, barrier-delimited from its\n// neighbors so graphemes from separate runs are never phrase-adjacent, and whitespace collapses.\nexport function segmentField(text: string): string {\n if (!HAS_RUN.test(text)) return '';\n const out = text.replace(RUN, (run) => ` ${BARRIER} ${graphemes(run).join(' ')} ${BARRIER} `);\n return out.replace(/\\s+/g, ' ').trim();\n}\n\n// A `title:`/`summary:`/`text:` qualifier directly before a run that is about to become a\n// quoted grapheme phrase, so the rewrite can retarget it at the matching `_seg` column.\nconst QUALIFIER = /(^|[\\s(])(-?)(title|summary|text)\\s*:\\s*$/;\n\n// Query side: each unspaced run becomes a quoted phrase of its graphemes, matching how\n// segmentField indexed it. A qualifier ahead of such a run maps to its `_seg` column, since\n// segmented text lives only there. An author's own quoted phrase, and everything else, pass\n// through byte-identical.\nexport function segmentMatch(terms: string): string {\n if (!HAS_RUN.test(terms)) return terms;\n let out = '';\n let quoted = false;\n const pieces = terms.split(RUN); // split keeps captured runs at odd indices\n for (let i = 0; i < pieces.length; i++) {\n if (i % 2 === 0) {\n for (const ch of pieces[i]) if (ch === '\"') quoted = !quoted;\n out += pieces[i];\n continue;\n }\n if (quoted) {\n out += pieces[i]; // an author's phrase is matched as written\n continue;\n }\n const g = graphemes(pieces[i]);\n const phrase = g.length > 1 ? `\"${g.join(' ')}\"` : g[0];\n const m = out.match(QUALIFIER);\n if (m) {\n out = `${out.slice(0, m.index)}${m[1]}${m[2]}${m[3]}_seg:${phrase}`;\n } else {\n out += phrase;\n }\n }\n return out;\n}\n"],"names":["segmentField","segmentMatch","SCRIPTS","RUN","RegExp","HAS_RUN","GRAPHEME","BARRIER","graphemes","run","match","text","test","out","replace","join","trim","QUALIFIER","terms","quoted","pieces","split","i","length","ch","g","phrase","m","slice","index"],"mappings":";;;;;;;;;;;QA6BgBA;eAAAA;;QAcAC;eAAAA;;;AA3ChB,8DAA8D;AAC9D,EAAE;AACF,8FAA8F;AAC9F,4FAA4F;AAC5F,2FAA2F;AAC3F,4FAA4F;AAC5F,kFAAkF;AAClF,iFAAiF;AAEjF,wEAAwE;AACxE,kFAAkF;AAClF,IAAMC,UAAU;AAChB,2FAA2F;AAC3F,gDAAgD;AAChD,IAAMC,MAAM,IAAIC,OAAO,AAAC,QAAe,OAARF,SAAQ,gBAAc;AACrD,IAAMG,UAAU,IAAID,OAAO,AAAC,IAAW,OAARF,SAAQ,MAAI;AAC3C,yFAAyF;AACzF,IAAMI,WAAW;AACjB,oFAAoF;AACpF,kFAAkF;AAClF,IAAMC,UAAU;AAEhB,SAASC,UAAUC,GAAW;QACrBA;IAAP,QAAOA,aAAAA,IAAIC,KAAK,CAACJ,uBAAVG,wBAAAA,aAAuB,EAAE;AAClC;AAKO,SAAST,aAAaW,IAAY;IACvC,IAAI,CAACN,QAAQO,IAAI,CAACD,OAAO,OAAO;IAChC,IAAME,MAAMF,KAAKG,OAAO,CAACX,KAAK,SAACM;eAAQ,AAAC,IAAcD,OAAXD,SAAQ,KAA+BA,OAA5BC,UAAUC,KAAKM,IAAI,CAAC,MAAK,KAAW,OAARR,SAAQ;;IAC1F,OAAOM,IAAIC,OAAO,CAAC,QAAQ,KAAKE,IAAI;AACtC;AAEA,0FAA0F;AAC1F,wFAAwF;AACxF,IAAMC,YAAY;AAMX,SAAShB,aAAaiB,KAAa;IACxC,IAAI,CAACb,QAAQO,IAAI,CAACM,QAAQ,OAAOA;IACjC,IAAIL,MAAM;IACV,IAAIM,SAAS;IACb,IAAMC,SAASF,MAAMG,KAAK,CAAClB,MAAM,2CAA2C;IAC5E,IAAK,IAAImB,IAAI,GAAGA,IAAIF,OAAOG,MAAM,EAAED,IAAK;QACtC,IAAIA,IAAI,MAAM,GAAG;gBACV,kCAAA,2BAAA;;gBAAL,QAAK,YAAYF,MAAM,CAACE,EAAE,qBAArB,SAAA,6BAAA,QAAA,yBAAA;oBAAA,IAAME,KAAN;oBAAuB,IAAIA,OAAO,KAAKL,SAAS,CAACA;;;gBAAjD;gBAAA;;;yBAAA,6BAAA;wBAAA;;;wBAAA;8BAAA;;;;YACLN,OAAOO,MAAM,CAACE,EAAE;YAChB;QACF;QACA,IAAIH,QAAQ;YACVN,OAAOO,MAAM,CAACE,EAAE,EAAE,2CAA2C;YAC7D;QACF;QACA,IAAMG,IAAIjB,UAAUY,MAAM,CAACE,EAAE;QAC7B,IAAMI,SAASD,EAAEF,MAAM,GAAG,IAAI,AAAC,IAAe,OAAZE,EAAEV,IAAI,CAAC,MAAK,OAAKU,CAAC,CAAC,EAAE;QACvD,IAAME,IAAId,IAAIH,KAAK,CAACO;QACpB,IAAIU,GAAG;YACLd,MAAM,AAAC,GAA0Bc,OAAxBd,IAAIe,KAAK,CAAC,GAAGD,EAAEE,KAAK,GAAWF,OAAPA,CAAC,CAAC,EAAE,EAAUA,OAAPA,CAAC,CAAC,EAAE,EAAeD,OAAZC,CAAC,CAAC,EAAE,EAAC,SAAc,OAAPD;QAC7D,OAAO;YACLb,OAAOa;QACT;IACF;IACA,OAAOb;AACT"}