sensemaking 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -4
- package/dist/cjs/cli/index.d.cts +2 -2
- package/dist/cjs/cli/index.d.ts +2 -2
- package/dist/cjs/cli/index.js +2 -2
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/peek.js +43 -2
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/search.js +38 -6
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/commands/index.d.cts +2 -2
- package/dist/cjs/commands/index.d.ts +2 -2
- package/dist/cjs/commands/index.js.map +1 -1
- package/dist/cjs/commands/peek.d.cts +9 -1
- package/dist/cjs/commands/peek.d.ts +9 -1
- package/dist/cjs/commands/peek.js +72 -29
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/search.d.cts +6 -2
- package/dist/cjs/commands/search.d.ts +6 -2
- package/dist/cjs/commands/search.js +31 -4
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +19 -5
- package/dist/cjs/commands/signals.d.ts +19 -5
- package/dist/cjs/commands/signals.js +64 -11
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/config/load.js +6 -0
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/cli/index.d.ts +2 -2
- package/dist/esm/cli/index.js +2 -2
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/peek.js +20 -2
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/search.js +12 -2
- package/dist/esm/cli/search.js.map +1 -1
- package/dist/esm/commands/index.d.ts +2 -2
- package/dist/esm/commands/index.js.map +1 -1
- package/dist/esm/commands/peek.d.ts +9 -1
- package/dist/esm/commands/peek.js +26 -12
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/search.d.ts +6 -2
- package/dist/esm/commands/search.js +11 -3
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +19 -5
- package/dist/esm/commands/signals.js +64 -14
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/config/load.js +6 -0
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/sense/EXAMPLES.md +3 -3
- package/skills/sense/SKILL.md +7 -1
- package/skills/sense/references/search.md +17 -1
- package/skills/sense/references/sql.md +1 -1
- package/skills/sense/references/terminology.md +32 -0
- package/skills/sense-setup/references/store-benchmarks.md +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/load.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { SenseError } from '../errors.ts';\nimport { writeFileAtomic } from '../lib/atomic-write.ts';\nimport type { Config, ResolvedConfig } from './types.ts';\nimport { CONFIG_FILENAME, DEFAULT_EMBED_MODEL, SUPPORTED_CONFIG_VERSION } from './types.ts';\nimport { unknownConfigKeys, validateConfig, validateLegacyScan } from './validate.ts';\n\n// v1 and v2 were `scan`/`find`-shaped; v3 introduced `presets`. Only the former need the\n// legacy shape check before migrating.\nconst FIRST_PRESET_VERSION = 3;\n\n// v1 -> v2 migration only: the features v2 introduced as opt-out (embed was opt-in then).\nconst V2_OPT_OUT_NAMES = ['links', 'sections', 'rank'] as const;\n\n// Pure per-version steps, chained by loadConfig. Intermediate shapes predate the Config type,\n// so steps are loosely typed and only the final result is cast back.\nconst MIGRATIONS: Record<number, (cfg: Record<string, unknown>) => Record<string, unknown>> = {\n // v1 -> v2: features block introduced, opt-out features enabled (matches the old implicit\n // behavior of `links` etc. not existing). embed stays absent -- opt-in.\n 1: (cfg) => ({ ...cfg, version: 2, features: Object.fromEntries(V2_OPT_OUT_NAMES.map((name) => [name, true])) }),\n // v2 -> v3: mechanical-minimal by decision -- only what keeps an existing config loading (no\n // restructuring, no preset inference, no query rewriting); real trees get hand-migrated to use presets.\n 2: (cfg) => {\n const { scan, defaults, features, checks, queries, ...rest } = cfg;\n const scanInclude = (scan as { include: string[] }).include;\n\n const nextQueries: Record<string, unknown> = {};\n for (const [name, value] of Object.entries((queries as Record<string, unknown> | undefined) ?? {})) {\n if (typeof value === 'string') {\n nextQueries[name] = value;\n continue;\n }\n const entry = value as { find: string; k?: number; where?: string; semantic?: boolean };\n // Loosely typed on purpose: this step emits the v3 shape, which still had `semantic`.\n // The v3 -> v4 step below strips it.\n const search: Record<string, unknown> = { search: entry.find };\n if (entry.k !== undefined) search.k = entry.k;\n if (entry.where !== undefined) search.where = entry.where;\n // semantic: true was opt-in; it is now the default, so it drops. semantic: false is kept.\n if (entry.semantic === false) search.semantic = false;\n nextQueries[name] = search;\n }\n\n const prevDefaults = defaults as { find?: { where?: string } } | undefined;\n const defaultWhere = prevDefaults?.find?.where;\n\n // features.embed false becomes semantic:false on every preset produced here.\n const prevFeatures = (features as Record<string, unknown> | undefined) ?? {};\n const embedWasOff = prevFeatures.embed === false;\n // Object form carries provider settings (model/type/url/key), not a toggle -- they move to\n // the v3 top-level `embed` block verbatim; dropping them would silently switch an api tree to the static model.\n const embedProvider = typeof prevFeatures.embed === 'object' && prevFeatures.embed !== null ? prevFeatures.embed : undefined;\n const { embed: _embed, ...restFeatures } = prevFeatures;\n\n const defaultPreset: Record<string, unknown> = { include: scanInclude };\n if (defaultWhere !== undefined) defaultPreset.where = defaultWhere;\n if (embedWasOff) defaultPreset.semantic = false;\n\n if (checks !== undefined) {\n console.error('sense: v2 \"checks\" was removed in v3 (sense check no longer asserts on saved queries); its queries are carried over under \"queries\" -- a returned row set is now the reader\\'s judgment');\n }\n\n const result: Record<string, unknown> = { ...rest, version: 3, presets: { default: defaultPreset }, queries: nextQueries };\n if (embedProvider !== undefined) result.embed = embedProvider;\n if (Object.keys(restFeatures).length > 0) result.features = restFeatures;\n return result;\n },\n // v3 -> v4: write the model into the file, wrap bare-string queries as { sql }, drop a saved\n // search's `semantic` (its preset decides). Same effective model, so nothing re-embeds.\n 3: (cfg) => {\n const presets = cfg.presets as Record<string, Record<string, unknown>>;\n const embedded = Object.values(presets).some((p) => p.semantic !== false);\n\n const nextQueries: Record<string, unknown> = {};\n for (const [name, value] of Object.entries((cfg.queries as Record<string, unknown> | undefined) ?? {})) {\n // v3's bare string meant SQL by inference; v4 makes every entry name its verb.\n if (typeof value === 'string') {\n nextQueries[name] = { sql: value };\n continue;\n }\n if (typeof value !== 'object' || value === null || !('search' in value)) {\n nextQueries[name] = value;\n continue;\n }\n const { semantic: _semantic, ...rest } = value as Record<string, unknown>;\n nextQueries[name] = rest;\n }\n\n const prev = (cfg.embed as Record<string, unknown> | undefined) ?? {};\n const result: Record<string, unknown> = { ...cfg, version: 4, queries: nextQueries };\n if (embedded) {\n result.embed = { model: (prev.model as string | undefined) ?? DEFAULT_EMBED_MODEL, type: (prev.type as string | undefined) ?? 'static', ...(prev.url !== undefined ? { url: prev.url } : {}), ...(prev.key !== undefined ? { key: prev.key } : {}) };\n } else {\n delete result.embed;\n // Dropping settings silently would look like a bug in a tree that configured an api endpoint\n // then turned vectors off; say it, since v4 has no way to carry provider settings for a tree that doesn't embed.\n if (Object.keys(prev).length > 0) console.error('sense: every preset has \"semantic\": false, so v4 drops the \"embed\" block (vectors stay off); re-add it, or set a preset\\'s semantic back to true, to turn them on');\n }\n return result;\n },\n // v4 -> v5: embed.type renames to embed.provider (\"api\" migrates to \"openai\", the wire protocol\n // it always was; other values pass through). A preset's `semantic` also migrates to `signals` (false -> explicit weights, true/absent -> no key).\n 4: (cfg) => {\n const prevEmbed = cfg.embed as Record<string, unknown> | undefined;\n const result: Record<string, unknown> = { ...cfg, version: 5 };\n if (prevEmbed) {\n const { type, ...rest } = prevEmbed;\n result.embed = type === undefined ? rest : { ...rest, provider: type === 'api' ? 'openai' : type };\n }\n\n const linksOn = (cfg.features as Record<string, unknown> | undefined)?.links !== false;\n const presets = cfg.presets as Record<string, Record<string, unknown>> | undefined;\n if (presets) {\n const nextPresets: Record<string, unknown> = {};\n for (const [name, preset] of Object.entries(presets)) {\n const { semantic, ...rest } = preset;\n if (semantic === undefined) {\n nextPresets[name] = preset;\n continue;\n }\n if (typeof semantic !== 'boolean') {\n throw new SenseError('CONFIG_INVALID', `presets.${name}.semantic must be a boolean`);\n }\n nextPresets[name] = semantic === false ? { ...rest, signals: linksOn ? { words: 1, links: 1 } : { words: 1 } } : rest;\n }\n result.presets = nextPresets;\n }\n return result;\n },\n // v5 -> v6: query-triggered builds are on by default. Preserve an explicit opt-out.\n 5: (cfg) => ({ ...cfg, version: 6, build: cfg.build === undefined ? true : cfg.build }),\n};\n\nexport function migrateConfig(cfg: Config): { cfg: Config; from: number } {\n const from = cfg.version ?? 1;\n let current: Record<string, unknown> = cfg as unknown as Record<string, unknown>;\n for (let v = from; v < SUPPORTED_CONFIG_VERSION; v++) {\n const step = MIGRATIONS[v];\n if (!step) throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `no migration from config version ${v}`);\n current = step(current);\n }\n return { cfg: current as unknown as Config, from };\n}\n\n// `sense init`'s flags map onto these three `embed` keys one-to-one; an absent field\n// keeps the built-in default rather than merging partial input.\nexport interface InitOverrides {\n model?: string;\n provider?: string;\n url?: string;\n}\n\nfunction starterConfig(overrides?: InitOverrides): Config {\n const embed: Record<string, unknown> = { model: DEFAULT_EMBED_MODEL, provider: 'static' };\n if (overrides?.model !== undefined) embed.model = overrides.model;\n if (overrides?.provider !== undefined) embed.provider = overrides.provider;\n if (overrides?.url !== undefined) embed.url = overrides.url;\n return {\n $schema: 'https://unpkg.com/sensemaking/schema.json',\n version: SUPPORTED_CONFIG_VERSION,\n build: true,\n presets: {\n default: { include: ['**/*.md'], k: 10 },\n large: { include: ['**/*.md'], k: 20 },\n },\n // Written out rather than defaulted in code: this line is what makes `sense download`\n // fetch a model, so it belongs where it can be read and changed.\n embed: embed as Config['embed'],\n queries: {},\n };\n}\n\n// Refuses to overwrite an existing config. `overrides` come from `sense init`'s flags; an\n// invalid --provider fails validateConfig's own shape check before anything is written.\nexport function initConfig(dir: string, overrides?: InitOverrides): string {\n const configPath = join(dir, CONFIG_FILENAME);\n if (existsSync(configPath)) {\n throw new SenseError('CONFIG_EXISTS', `${CONFIG_FILENAME} already exists in ${dir}`);\n }\n const cfg = starterConfig(overrides);\n validateConfig(cfg, configPath);\n writeFileAtomic(configPath, `${JSON.stringify(cfg, null, 2)}\\n`);\n return configPath;\n}\n\nexport function findConfigPath(startDir: string): string | null {\n let dir = resolve(startDir);\n for (;;) {\n const candidate = join(dir, CONFIG_FILENAME);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/** Controls whether loading an older config may persist its in-memory migration. */\nexport interface LoadConfigOptions {\n /** Write a successful migration back to the config file. Defaults to true. */\n writeMigration?: boolean;\n}\n\nexport function loadConfig(explicitPath?: string, options: LoadConfigOptions = {}): ResolvedConfig {\n let configPath: string;\n if (explicitPath) {\n configPath = resolve(process.cwd(), explicitPath);\n if (!existsSync(configPath)) throw new SenseError('CONFIG_NOT_FOUND', `config not found: ${configPath}`);\n } else {\n const found = findConfigPath(process.cwd());\n if (!found) {\n throw new SenseError('CONFIG_NOT_FOUND', `could not find ${CONFIG_FILENAME} in ${process.cwd()} or any parent directory`);\n }\n configPath = found;\n }\n\n const raw = readFileSync(configPath, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n\n // Ahead of both the version gate and shape checks: a non-object file (or array -- typeof []\n // is also 'object') is malformed at every version, so it gets one error regardless of branch.\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);\n }\n\n // Version gate before shape validation: a config written by a newer sense should fail\n // with \"requires a newer sense\", not with shape errors its own version may not have.\n const version = typeof parsed === 'object' && parsed !== null && typeof (parsed as { version?: unknown }).version === 'number' ? (parsed as { version: number }).version : 1;\n if (version > SUPPORTED_CONFIG_VERSION) {\n throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `config version ${version} requires a newer sense`);\n }\n\n // validateConfig only knows the current shape, so scan-shaped files (pre-v3) get a minimal\n // check, migrate, then the full one on the result.\n let cfg: Config;\n let migratedFrom: number | undefined;\n if (version < SUPPORTED_CONFIG_VERSION) {\n if (version < FIRST_PRESET_VERSION) validateLegacyScan(parsed, configPath);\n const result = migrateConfig(parsed as unknown as Config);\n cfg = validateConfig(result.cfg, configPath);\n migratedFrom = result.from;\n if (options.writeMigration !== false) {\n const migrated = `${JSON.stringify(cfg, null, 2)}\\n`;\n try {\n writeFileAtomic(configPath, migrated);\n } catch (err) {\n // Only a rename-contention error might already be published by a racing writer.\n // Any other failure, including a failed initial write, rethrows immediately.\n const errno = err as NodeJS.ErrnoException;\n if (!(err instanceof Error) || errno.syscall !== 'rename' || !['EPERM', 'EACCES', 'EBUSY'].includes(errno.code ?? '')) throw err;\n let existing: string;\n try {\n existing = readFileSync(configPath, 'utf8');\n } catch {\n throw err;\n }\n if (existing !== migrated) throw err;\n }\n }\n } else {\n cfg = validateConfig(parsed, configPath);\n }\n\n const unknownKeys = unknownConfigKeys(cfg as unknown as Record<string, unknown>);\n const configDir = dirname(configPath);\n const rootDir = resolve(configDir, cfg.root ?? '.');\n return { ...cfg, configDir, rootDir, baseDir: rootDir, configPath, migratedFrom, unknownKeys: unknownKeys.length > 0 ? unknownKeys : undefined };\n}\n"],"names":["existsSync","readFileSync","dirname","join","resolve","SenseError","writeFileAtomic","CONFIG_FILENAME","DEFAULT_EMBED_MODEL","SUPPORTED_CONFIG_VERSION","unknownConfigKeys","validateConfig","validateLegacyScan","FIRST_PRESET_VERSION","V2_OPT_OUT_NAMES","MIGRATIONS","cfg","version","features","Object","fromEntries","map","name","prevDefaults","scan","defaults","checks","queries","rest","scanInclude","include","nextQueries","value","entries","entry","search","find","k","undefined","where","semantic","defaultWhere","prevFeatures","embedWasOff","embed","embedProvider","_embed","restFeatures","defaultPreset","console","error","result","presets","default","keys","length","embedded","values","some","p","sql","_semantic","prev","model","type","url","key","prevEmbed","provider","linksOn","links","nextPresets","preset","signals","words","build","migrateConfig","from","current","v","step","starterConfig","overrides","$schema","large","initConfig","dir","configPath","JSON","stringify","findConfigPath","startDir","candidate","parent","loadConfig","explicitPath","options","process","cwd","found","raw","parsed","parse","Array","isArray","migratedFrom","writeMigration","migrated","err","errno","Error","syscall","includes","code","existing","unknownKeys","configDir","rootDir","root","baseDir"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/load.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { SenseError } from '../errors.ts';\nimport { writeFileAtomic } from '../lib/atomic-write.ts';\nimport type { Config, ResolvedConfig } from './types.ts';\nimport { CONFIG_FILENAME, DEFAULT_EMBED_MODEL, SUPPORTED_CONFIG_VERSION } from './types.ts';\nimport { unknownConfigKeys, validateConfig, validateLegacyScan } from './validate.ts';\n\n// v1 and v2 were `scan`/`find`-shaped; v3 introduced `presets`. Only the former need the\n// legacy shape check before migrating.\nconst FIRST_PRESET_VERSION = 3;\nconst migrationReady = channel('sensemaking.config.migration-ready');\n\n// v1 -> v2 migration only: the features v2 introduced as opt-out (embed was opt-in then).\nconst V2_OPT_OUT_NAMES = ['links', 'sections', 'rank'] as const;\n\n// Pure per-version steps, chained by loadConfig. Intermediate shapes predate the Config type,\n// so steps are loosely typed and only the final result is cast back.\nconst MIGRATIONS: Record<number, (cfg: Record<string, unknown>) => Record<string, unknown>> = {\n // v1 -> v2: features block introduced, opt-out features enabled (matches the old implicit\n // behavior of `links` etc. not existing). embed stays absent -- opt-in.\n 1: (cfg) => ({ ...cfg, version: 2, features: Object.fromEntries(V2_OPT_OUT_NAMES.map((name) => [name, true])) }),\n // v2 -> v3: mechanical-minimal by decision -- only what keeps an existing config loading (no\n // restructuring, no preset inference, no query rewriting); real trees get hand-migrated to use presets.\n 2: (cfg) => {\n const { scan, defaults, features, checks, queries, ...rest } = cfg;\n const scanInclude = (scan as { include: string[] }).include;\n\n const nextQueries: Record<string, unknown> = {};\n for (const [name, value] of Object.entries((queries as Record<string, unknown> | undefined) ?? {})) {\n if (typeof value === 'string') {\n nextQueries[name] = value;\n continue;\n }\n const entry = value as { find: string; k?: number; where?: string; semantic?: boolean };\n // Loosely typed on purpose: this step emits the v3 shape, which still had `semantic`.\n // The v3 -> v4 step below strips it.\n const search: Record<string, unknown> = { search: entry.find };\n if (entry.k !== undefined) search.k = entry.k;\n if (entry.where !== undefined) search.where = entry.where;\n // semantic: true was opt-in; it is now the default, so it drops. semantic: false is kept.\n if (entry.semantic === false) search.semantic = false;\n nextQueries[name] = search;\n }\n\n const prevDefaults = defaults as { find?: { where?: string } } | undefined;\n const defaultWhere = prevDefaults?.find?.where;\n\n // features.embed false becomes semantic:false on every preset produced here.\n const prevFeatures = (features as Record<string, unknown> | undefined) ?? {};\n const embedWasOff = prevFeatures.embed === false;\n // Object form carries provider settings (model/type/url/key), not a toggle -- they move to\n // the v3 top-level `embed` block verbatim; dropping them would silently switch an api tree to the static model.\n const embedProvider = typeof prevFeatures.embed === 'object' && prevFeatures.embed !== null ? prevFeatures.embed : undefined;\n const { embed: _embed, ...restFeatures } = prevFeatures;\n\n const defaultPreset: Record<string, unknown> = { include: scanInclude };\n if (defaultWhere !== undefined) defaultPreset.where = defaultWhere;\n if (embedWasOff) defaultPreset.semantic = false;\n\n if (checks !== undefined) {\n console.error('sense: v2 \"checks\" was removed in v3 (sense check no longer asserts on saved queries); its queries are carried over under \"queries\" -- a returned row set is now the reader\\'s judgment');\n }\n\n const result: Record<string, unknown> = { ...rest, version: 3, presets: { default: defaultPreset }, queries: nextQueries };\n if (embedProvider !== undefined) result.embed = embedProvider;\n if (Object.keys(restFeatures).length > 0) result.features = restFeatures;\n return result;\n },\n // v3 -> v4: write the model into the file, wrap bare-string queries as { sql }, drop a saved\n // search's `semantic` (its preset decides). Same effective model, so nothing re-embeds.\n 3: (cfg) => {\n const presets = cfg.presets as Record<string, Record<string, unknown>>;\n const embedded = Object.values(presets).some((p) => p.semantic !== false);\n\n const nextQueries: Record<string, unknown> = {};\n for (const [name, value] of Object.entries((cfg.queries as Record<string, unknown> | undefined) ?? {})) {\n // v3's bare string meant SQL by inference; v4 makes every entry name its verb.\n if (typeof value === 'string') {\n nextQueries[name] = { sql: value };\n continue;\n }\n if (typeof value !== 'object' || value === null || !('search' in value)) {\n nextQueries[name] = value;\n continue;\n }\n const { semantic: _semantic, ...rest } = value as Record<string, unknown>;\n nextQueries[name] = rest;\n }\n\n const prev = (cfg.embed as Record<string, unknown> | undefined) ?? {};\n const result: Record<string, unknown> = { ...cfg, version: 4, queries: nextQueries };\n if (embedded) {\n result.embed = { model: (prev.model as string | undefined) ?? DEFAULT_EMBED_MODEL, type: (prev.type as string | undefined) ?? 'static', ...(prev.url !== undefined ? { url: prev.url } : {}), ...(prev.key !== undefined ? { key: prev.key } : {}) };\n } else {\n delete result.embed;\n // Dropping settings silently would look like a bug in a tree that configured an api endpoint\n // then turned vectors off; say it, since v4 has no way to carry provider settings for a tree that doesn't embed.\n if (Object.keys(prev).length > 0) console.error('sense: every preset has \"semantic\": false, so v4 drops the \"embed\" block (vectors stay off); re-add it, or set a preset\\'s semantic back to true, to turn them on');\n }\n return result;\n },\n // v4 -> v5: embed.type renames to embed.provider (\"api\" migrates to \"openai\", the wire protocol\n // it always was; other values pass through). A preset's `semantic` also migrates to `signals` (false -> explicit weights, true/absent -> no key).\n 4: (cfg) => {\n const prevEmbed = cfg.embed as Record<string, unknown> | undefined;\n const result: Record<string, unknown> = { ...cfg, version: 5 };\n if (prevEmbed) {\n const { type, ...rest } = prevEmbed;\n result.embed = type === undefined ? rest : { ...rest, provider: type === 'api' ? 'openai' : type };\n }\n\n const linksOn = (cfg.features as Record<string, unknown> | undefined)?.links !== false;\n const presets = cfg.presets as Record<string, Record<string, unknown>> | undefined;\n if (presets) {\n const nextPresets: Record<string, unknown> = {};\n for (const [name, preset] of Object.entries(presets)) {\n const { semantic, ...rest } = preset;\n if (semantic === undefined) {\n nextPresets[name] = preset;\n continue;\n }\n if (typeof semantic !== 'boolean') {\n throw new SenseError('CONFIG_INVALID', `presets.${name}.semantic must be a boolean`);\n }\n nextPresets[name] = semantic === false ? { ...rest, signals: linksOn ? { words: 1, links: 1 } : { words: 1 } } : rest;\n }\n result.presets = nextPresets;\n }\n return result;\n },\n // v5 -> v6: query-triggered builds are on by default. Preserve an explicit opt-out.\n 5: (cfg) => ({ ...cfg, version: 6, build: cfg.build === undefined ? true : cfg.build }),\n};\n\nexport function migrateConfig(cfg: Config): { cfg: Config; from: number } {\n const from = cfg.version ?? 1;\n let current: Record<string, unknown> = cfg as unknown as Record<string, unknown>;\n for (let v = from; v < SUPPORTED_CONFIG_VERSION; v++) {\n const step = MIGRATIONS[v];\n if (!step) throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `no migration from config version ${v}`);\n current = step(current);\n }\n return { cfg: current as unknown as Config, from };\n}\n\n// `sense init`'s flags map onto these three `embed` keys one-to-one; an absent field\n// keeps the built-in default rather than merging partial input.\nexport interface InitOverrides {\n model?: string;\n provider?: string;\n url?: string;\n}\n\nfunction starterConfig(overrides?: InitOverrides): Config {\n const embed: Record<string, unknown> = { model: DEFAULT_EMBED_MODEL, provider: 'static' };\n if (overrides?.model !== undefined) embed.model = overrides.model;\n if (overrides?.provider !== undefined) embed.provider = overrides.provider;\n if (overrides?.url !== undefined) embed.url = overrides.url;\n return {\n $schema: 'https://unpkg.com/sensemaking/schema.json',\n version: SUPPORTED_CONFIG_VERSION,\n build: true,\n presets: {\n default: { include: ['**/*.md'], k: 10 },\n large: { include: ['**/*.md'], k: 20 },\n },\n // Written out rather than defaulted in code: this line is what makes `sense download`\n // fetch a model, so it belongs where it can be read and changed.\n embed: embed as Config['embed'],\n queries: {},\n };\n}\n\n// Refuses to overwrite an existing config. `overrides` come from `sense init`'s flags; an\n// invalid --provider fails validateConfig's own shape check before anything is written.\nexport function initConfig(dir: string, overrides?: InitOverrides): string {\n const configPath = join(dir, CONFIG_FILENAME);\n if (existsSync(configPath)) {\n throw new SenseError('CONFIG_EXISTS', `${CONFIG_FILENAME} already exists in ${dir}`);\n }\n const cfg = starterConfig(overrides);\n validateConfig(cfg, configPath);\n writeFileAtomic(configPath, `${JSON.stringify(cfg, null, 2)}\\n`);\n return configPath;\n}\n\nexport function findConfigPath(startDir: string): string | null {\n let dir = resolve(startDir);\n for (;;) {\n const candidate = join(dir, CONFIG_FILENAME);\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/** Controls whether loading an older config may persist its in-memory migration. */\nexport interface LoadConfigOptions {\n /** Write a successful migration back to the config file. Defaults to true. */\n writeMigration?: boolean;\n}\n\nexport function loadConfig(explicitPath?: string, options: LoadConfigOptions = {}): ResolvedConfig {\n let configPath: string;\n if (explicitPath) {\n configPath = resolve(process.cwd(), explicitPath);\n if (!existsSync(configPath)) throw new SenseError('CONFIG_NOT_FOUND', `config not found: ${configPath}`);\n } else {\n const found = findConfigPath(process.cwd());\n if (!found) {\n throw new SenseError('CONFIG_NOT_FOUND', `could not find ${CONFIG_FILENAME} in ${process.cwd()} or any parent directory`);\n }\n configPath = found;\n }\n\n const raw = readFileSync(configPath, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n\n // Ahead of both the version gate and shape checks: a non-object file (or array -- typeof []\n // is also 'object') is malformed at every version, so it gets one error regardless of branch.\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);\n }\n\n // Version gate before shape validation: a config written by a newer sense should fail\n // with \"requires a newer sense\", not with shape errors its own version may not have.\n const version = typeof parsed === 'object' && parsed !== null && typeof (parsed as { version?: unknown }).version === 'number' ? (parsed as { version: number }).version : 1;\n if (version > SUPPORTED_CONFIG_VERSION) {\n throw new SenseError('CONFIG_VERSION_UNSUPPORTED', `config version ${version} requires a newer sense`);\n }\n\n // validateConfig only knows the current shape, so scan-shaped files (pre-v3) get a minimal\n // check, migrate, then the full one on the result.\n let cfg: Config;\n let migratedFrom: number | undefined;\n if (version < SUPPORTED_CONFIG_VERSION) {\n if (version < FIRST_PRESET_VERSION) validateLegacyScan(parsed, configPath);\n const result = migrateConfig(parsed as unknown as Config);\n cfg = validateConfig(result.cfg, configPath);\n migratedFrom = result.from;\n if (options.writeMigration !== false) {\n const migrated = `${JSON.stringify(cfg, null, 2)}\\n`;\n if (migrationReady.hasSubscribers) migrationReady.publish({ configPath, from: migratedFrom });\n try {\n writeFileAtomic(configPath, migrated);\n } catch (err) {\n // Only a rename-contention error might already be published by a racing writer.\n // Any other failure, including a failed initial write, rethrows immediately.\n const errno = err as NodeJS.ErrnoException;\n if (!(err instanceof Error) || errno.syscall !== 'rename' || !['EPERM', 'EACCES', 'EBUSY'].includes(errno.code ?? '')) throw err;\n let existing: string;\n try {\n existing = readFileSync(configPath, 'utf8');\n } catch {\n throw err;\n }\n if (existing !== migrated) throw err;\n }\n }\n } else {\n cfg = validateConfig(parsed, configPath);\n }\n\n const unknownKeys = unknownConfigKeys(cfg as unknown as Record<string, unknown>);\n const configDir = dirname(configPath);\n const rootDir = resolve(configDir, cfg.root ?? '.');\n return { ...cfg, configDir, rootDir, baseDir: rootDir, configPath, migratedFrom, unknownKeys: unknownKeys.length > 0 ? unknownKeys : undefined };\n}\n"],"names":["channel","existsSync","readFileSync","dirname","join","resolve","SenseError","writeFileAtomic","CONFIG_FILENAME","DEFAULT_EMBED_MODEL","SUPPORTED_CONFIG_VERSION","unknownConfigKeys","validateConfig","validateLegacyScan","FIRST_PRESET_VERSION","migrationReady","V2_OPT_OUT_NAMES","MIGRATIONS","cfg","version","features","Object","fromEntries","map","name","prevDefaults","scan","defaults","checks","queries","rest","scanInclude","include","nextQueries","value","entries","entry","search","find","k","undefined","where","semantic","defaultWhere","prevFeatures","embedWasOff","embed","embedProvider","_embed","restFeatures","defaultPreset","console","error","result","presets","default","keys","length","embedded","values","some","p","sql","_semantic","prev","model","type","url","key","prevEmbed","provider","linksOn","links","nextPresets","preset","signals","words","build","migrateConfig","from","current","v","step","starterConfig","overrides","$schema","large","initConfig","dir","configPath","JSON","stringify","findConfigPath","startDir","candidate","parent","loadConfig","explicitPath","options","process","cwd","found","raw","parsed","parse","Array","isArray","migratedFrom","writeMigration","migrated","hasSubscribers","publish","err","errno","Error","syscall","includes","code","existing","unknownKeys","configDir","rootDir","root","baseDir"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { PathOptions, Peek, PeekSection, PresetCoverage, RelatedOptions, RelatedResult, SearchOptions, SearchResult, SearchResultVia, TreeMap, TreeMapField, TreeMapHub, TreeMapRecent } from './commands/index.js';
|
|
1
|
+
export type { PathOptions, Peek, PeekOptions, PeekSection, PresetCoverage, RelatedOptions, RelatedResult, SearchOptions, SearchResult, SearchResultVia, SearchSignalContribution, TreeMap, TreeMapField, TreeMapHub, TreeMapRecent } from './commands/index.js';
|
|
2
2
|
export { findPath, mapTree, peek, presetCoverage, relatedNotes, search } from './commands/index.js';
|
|
3
3
|
export type { Config, EmbedConfig, FeatureName, InitOverrides, LoadConfigOptions, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.js';
|
|
4
4
|
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type { PathOptions, Peek, PeekSection, PresetCoverage, RelatedOptions, RelatedResult, SearchOptions, SearchResult, SearchResultVia, TreeMap, TreeMapField, TreeMapHub, TreeMapRecent } from './commands/index.ts';\nexport { findPath, mapTree, peek, presetCoverage, relatedNotes, search } from './commands/index.ts';\nexport type { Config, EmbedConfig, FeatureName, InitOverrides, LoadConfigOptions, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.ts';\nexport type { SenseErrorCode } from './errors.ts';\nexport { SenseError } from './errors.ts';\nexport type { Format, Row, RowFormat } from './output/output.ts';\nexport { printRows } from './output/output.ts';\nexport type { BuildOptions, BuildResult, OpenOptions, OpenResult, Stages } from './store/index.ts';\nexport { buildIndex as build, CAPABILITY_NAMES, clearCache, openStore as open } from './store/index.ts';\nexport type { Capability, DocumentStore, FieldStat, LexicalHit, LexicalIndex, LexicalQueryOptions, RawStatement, RunResult, SqlSession, Statement, Store, VectorCandidate, VectorSimilar, VectorStore, VectorWriteRow } from './store/types.ts';\n\nexport type { WatchEvent, WatchOptions } from './watch.ts';\nexport { runWatch } from './watch.ts';\n"],"names":["findPath","mapTree","peek","presetCoverage","relatedNotes","search","CONFIG_FILENAME","initConfig","loadConfig","migrateConfig","SIGNAL_NAMES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION","SenseError","printRows","buildIndex","build","CAPABILITY_NAMES","clearCache","openStore","open","runWatch"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;AAGvE,SAASA,QAAQ,EAAEC,OAAO,EAAEC,IAAI,EAAEC,cAAc,EAAEC,YAAY,EAAEC,MAAM,QAAQ,sBAAsB;AAEpG,SAASC,eAAe,EAAEC,UAAU,EAAEC,UAAU,EAAEC,aAAa,EAAEC,YAAY,EAAEC,SAAS,EAAEC,WAAW,EAAEC,wBAAwB,QAAQ,oBAAoB;AAE3J,SAASC,UAAU,QAAQ,cAAc;AAEzC,SAASC,SAAS,QAAQ,qBAAqB;AAE/C,SAASC,cAAcC,KAAK,EAAEC,gBAAgB,EAAEC,UAAU,EAAEC,aAAaC,IAAI,QAAQ,mBAAmB;AAIxG,SAASC,QAAQ,QAAQ,aAAa"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type { PathOptions, Peek, PeekOptions, PeekSection, PresetCoverage, RelatedOptions, RelatedResult, SearchOptions, SearchResult, SearchResultVia, SearchSignalContribution, TreeMap, TreeMapField, TreeMapHub, TreeMapRecent } from './commands/index.ts';\nexport { findPath, mapTree, peek, presetCoverage, relatedNotes, search } from './commands/index.ts';\nexport type { Config, EmbedConfig, FeatureName, InitOverrides, LoadConfigOptions, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.ts';\nexport type { SenseErrorCode } from './errors.ts';\nexport { SenseError } from './errors.ts';\nexport type { Format, Row, RowFormat } from './output/output.ts';\nexport { printRows } from './output/output.ts';\nexport type { BuildOptions, BuildResult, OpenOptions, OpenResult, Stages } from './store/index.ts';\nexport { buildIndex as build, CAPABILITY_NAMES, clearCache, openStore as open } from './store/index.ts';\nexport type { Capability, DocumentStore, FieldStat, LexicalHit, LexicalIndex, LexicalQueryOptions, RawStatement, RunResult, SqlSession, Statement, Store, VectorCandidate, VectorSimilar, VectorStore, VectorWriteRow } from './store/types.ts';\n\nexport type { WatchEvent, WatchOptions } from './watch.ts';\nexport { runWatch } from './watch.ts';\n"],"names":["findPath","mapTree","peek","presetCoverage","relatedNotes","search","CONFIG_FILENAME","initConfig","loadConfig","migrateConfig","SIGNAL_NAMES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION","SenseError","printRows","buildIndex","build","CAPABILITY_NAMES","clearCache","openStore","open","runWatch"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;AAGvE,SAASA,QAAQ,EAAEC,OAAO,EAAEC,IAAI,EAAEC,cAAc,EAAEC,YAAY,EAAEC,MAAM,QAAQ,sBAAsB;AAEpG,SAASC,eAAe,EAAEC,UAAU,EAAEC,UAAU,EAAEC,aAAa,EAAEC,YAAY,EAAEC,SAAS,EAAEC,WAAW,EAAEC,wBAAwB,QAAQ,oBAAoB;AAE3J,SAASC,UAAU,QAAQ,cAAc;AAEzC,SAASC,SAAS,QAAQ,qBAAqB;AAE/C,SAASC,cAAcC,KAAK,EAAEC,gBAAgB,EAAEC,UAAU,EAAEC,aAAaC,IAAI,QAAQ,mBAAmB;AAIxG,SAASC,QAAQ,QAAQ,aAAa"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sensemaking",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Query and search your markdown notes with context-aware progressive disclosure: SQL over frontmatter, links, and text, plus semantic search and link-graph ranking. No server, no build step.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
package/skills/sense/EXAMPLES.md
CHANGED
|
@@ -17,7 +17,7 @@ sense search "pricing OR billing OR invoicing" --k 10 --format json
|
|
|
17
17
|
]
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Tens of tokens per row; often the `summary` answers the question with no read at all. A row with `via: "link"`
|
|
20
|
+
Tens of tokens per row; often the `summary` answers the question with no read at all. A row with `via: "link"` has link evidence rather than a word match. `lines`, when set, is a section or embedding chunk's line range, a direct `Read` range. See [Sense terminology](references/terminology.md) for these distinctions.
|
|
21
21
|
|
|
22
22
|
## B. Known-field filtering (no search)
|
|
23
23
|
|
|
@@ -56,7 +56,7 @@ The note is ~4,400 tokens; the peek is ~500. If only one section matters, `Read`
|
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
sense sql "SELECT src FROM links WHERE dst = ?" notes/pricing-model.md # who cites this
|
|
59
|
-
sense sql "SELECT src, target FROM links WHERE dst IS NULL" #
|
|
59
|
+
sense sql "SELECT src, target FROM links WHERE dst IS NULL" # unresolved links
|
|
60
60
|
sense sql "SELECT path, round(_rank*100,2) r FROM frontmatter ORDER BY _rank DESC LIMIT 5" # load-bearing notes
|
|
61
61
|
```
|
|
62
62
|
|
|
@@ -83,7 +83,7 @@ sense search "children dying from poor nutrition" --k 3 --format json
|
|
|
83
83
|
]
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
A `via: "vector"` row
|
|
86
|
+
A `via: "vector"` row has vector evidence rather than a word match. `similarity` is the cosine against the chunk identified by `lines`, a direct `Read` range. Vector search requires a configured model, enabled vector signal and prepared embeddings. Vector-only results do not prove the query words are absent; use the word-search guidance when absence matters.
|
|
87
87
|
|
|
88
88
|
## Consequences
|
|
89
89
|
|
package/skills/sense/SKILL.md
CHANGED
|
@@ -9,6 +9,8 @@ Use sense to locate evidence in a markdown tree before reading files. With the c
|
|
|
9
9
|
|
|
10
10
|
Setup, store selection, presets, and note design belong to the `sense-setup` skill. Translating an Obsidian Bases file belongs to `sense-bases`.
|
|
11
11
|
|
|
12
|
+
Use the shared [Sense terminology](references/terminology.md) when explaining results or output controls. Read it when distinguishing a snippet, section, section description, outline, chunk or link type; those names are not interchangeable.
|
|
13
|
+
|
|
12
14
|
## Start with the tree
|
|
13
15
|
|
|
14
16
|
Run these when the tree or its configuration is unfamiliar:
|
|
@@ -67,16 +69,20 @@ The tables, `?` placeholders, quoted identifiers, `has()`, `basename()`, and pre
|
|
|
67
69
|
|
|
68
70
|
Combinations such as `match+link` mean that more than one signal produced the row. `score` ranks rows within that result only. Do not compare it across searches. `similarity` ranks vector evidence within the current result and model. Do not carry a fixed similarity cutoff between trees.
|
|
69
71
|
|
|
70
|
-
The `lines` value
|
|
72
|
+
The `lines` value gives a line range in the indexed note. It can identify a section around a word match or an embedding chunk. Read that range when it is present. A null range means the whole note is the reference. A vector-only row has no lexical snippet and is a lead, not proof that the note contains the query terms.
|
|
71
73
|
|
|
72
74
|
Read [search evidence and troubleshooting](references/search.md) when a search will support a factual claim, when absence matters, when results look noisy, or when tuning signal weights.
|
|
73
75
|
|
|
76
|
+
`sense search --explain --format json` adds the actual ranking contributions for returned notes. It does not change ranking or explain every missing result. The search guide describes how contributions differ from the `via` evidence label.
|
|
77
|
+
|
|
74
78
|
## Scope and output
|
|
75
79
|
|
|
76
80
|
Bare commands use the `default` preset. `--preset <name>` chooses another. For `search`, `map`, `peek`, `path`, and `related`, `--include`, `--exclude`, and `--no-exclude` change the query scope for one invocation, but cannot reach files that no preset indexes. `sense status` shows actual coverage. Scope selects results; presets are not a security boundary.
|
|
77
81
|
|
|
78
82
|
`peek` rejects an exact path outside scope before trying a basename, resolves basenames within scope, and shows only scoped resolved links and backlinks; unresolved targets remain as written. `path` resolves its endpoints across the indexed tree and scopes intermediate notes. `related` resolves its seed across the indexed tree and scopes result candidates.
|
|
79
83
|
|
|
84
|
+
`peek --section-count-limit n` bounds section descriptions. `--link-count-limit n` independently bounds each group of outbound links, backlinks and unresolved links. Both default to 20 and require positive safe integers. Request more when the outline or links you need are truncated, or fewer for triage. Totals still describe the full selected groups; the limits do not widen scope. Section descriptions identify where to read; they do not return section prose.
|
|
85
|
+
|
|
80
86
|
`--where` filters search and graph commands against frontmatter alias `f`:
|
|
81
87
|
|
|
82
88
|
```sh
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Read this guide when search results will support a factual claim, when absence matters, when results look noisy, or when changing signal weights.
|
|
4
4
|
|
|
5
|
+
[Sense terminology](terminology.md) defines the result objects. In particular, snippets, sections and embedding chunks are different units.
|
|
6
|
+
|
|
5
7
|
## What each signal establishes
|
|
6
8
|
|
|
7
9
|
`words` ranks literal occurrences after stemming. It is the right signal for identifiers, error strings, names, and quoted phrases. A `match` row is lexical evidence because its `snippets` show the occurrence.
|
|
@@ -22,12 +24,26 @@ Weights are corpus and model choices. Compare representative queries before chan
|
|
|
22
24
|
|
|
23
25
|
- `via` names the evidence that produced the row.
|
|
24
26
|
- `snippets` contains marked lexical passages. It is empty when no word matched.
|
|
25
|
-
- `lines`
|
|
27
|
+
- `lines` is the selected section or embedding chunk's line range in the indexed note. Null means the whole note is the reference.
|
|
26
28
|
- `score` orders the fused result. Its scale changes with the participating signals and ranks, so compare rows only inside one result.
|
|
27
29
|
- `similarity` is cosine similarity against the best chunk. Compare it inside one result and one model. Small trees can give unrelated text a moderately close nearest neighbor.
|
|
28
30
|
|
|
29
31
|
Relay the evidence label when reporting a result. "The note contains these words" and "the note is semantically related" support different claims.
|
|
30
32
|
|
|
33
|
+
## Finite retrieval and paging
|
|
34
|
+
|
|
35
|
+
`k` is the maximum number of notes returned by one finite retrieval. Changing `k` can change the candidate pools, link seeds and fused ranking, including the earlier rows. It starts a new retrieval rather than continuing a stable result set. When you need pages, retain one returned array or JSON result and page that locally.
|
|
36
|
+
|
|
37
|
+
## Explain a ranking
|
|
38
|
+
|
|
39
|
+
Add `--explain` to a direct `sense search` invocation when you need to inspect how the configured signals contributed. With `--format json`, each returned row adds an `explanation` array containing `signal`, `rank`, `weight` and `contribution`. Entries follow words, links, vectors order and include only signals that contributed to that candidate. Without the flag, ordinary output is unchanged.
|
|
40
|
+
|
|
41
|
+
Ranks are one-based within each signal's candidate list. A contribution is `weight / (60 + rank - 1)`, using the actual unrounded value accumulated during ranking. The sum is the fused score before its public display rounding. These values are not native BM25 scores and do not make lexical rankings comparable across stores.
|
|
42
|
+
|
|
43
|
+
An isolated word-match seed can receive link-signal restart mass while its `via` label remains `match`. The explanation reports the numeric contribution; `via` remains the evidence label, not an exhaustive score breakdown. An explanation does not establish that a claim is true or describe why an absent note failed to enter the candidate set.
|
|
44
|
+
|
|
45
|
+
Table and CSV formats encode the explanation cell as JSON text. Table output follows the existing cell clipping rules; use JSON or CSV for the complete values. Explanation reuses the current search and does not make an additional embedding request. It is not a saved-query configuration field.
|
|
46
|
+
|
|
31
47
|
## When a search misses
|
|
32
48
|
|
|
33
49
|
For word search, try concrete terms that the notes may use, widen the selected preset, or raise `--k`. Search grammar depends on the selected store. Read its guide before adding operators.
|
|
@@ -94,7 +94,7 @@ SELECT DISTINCT path FROM hop WHERE d > 0;
|
|
|
94
94
|
|
|
95
95
|
Use `sense path` for the shortest chain between two known notes. Use raw recursion when the task needs a set of neighbors to filter or join.
|
|
96
96
|
|
|
97
|
-
##
|
|
97
|
+
## Unresolved links
|
|
98
98
|
|
|
99
99
|
`dst IS NULL` includes links to attachments that sense never indexes, such as images, PDFs, and `.base` files. Exclude the attachment extensions used by the tree before treating the remaining rows as broken links. Trees with dotted markdown titles need an explicit extension list instead of a blanket "contains a dot" filter.
|
|
100
100
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Sense terminology
|
|
2
|
+
|
|
3
|
+
This is the shared vocabulary for Sense's README, command help, API documentation and skills. Use these names when describing results and output controls.
|
|
4
|
+
|
|
5
|
+
| Term | Meaning |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Note | One Markdown file. A document is the same unit; SQL and some status fields use that name. |
|
|
8
|
+
| Tree | The directory of notes configured as Sense's root. |
|
|
9
|
+
| Frontmatter | The YAML metadata at the beginning of a note, such as its title, tags or status. |
|
|
10
|
+
| Search result | One matching note, returned with its path, ranking information and any snippets. A result is not a section or a chunk. |
|
|
11
|
+
| Snippet | A short passage selected around matching words, marked with `«»`. A note can return multiple snippets. A snippet need not contain a whole section. |
|
|
12
|
+
| Heading | A Markdown heading such as `## Installation`. Its level is its depth, from 1 to 6. |
|
|
13
|
+
| Section | A heading and the content following it until the next heading of any level, or the end of the note. Text before the first heading is not a section in the `sections` table. A parent section does not include subsequent subsections. |
|
|
14
|
+
| Section description | The heading text, level, start and end lines, and estimated token count returned by `peek`. It does not contain the section's prose. |
|
|
15
|
+
| Outline | The section descriptions in document order. It is a view of the note's structure, not another stored type of content. |
|
|
16
|
+
| Chunk | A span of note content prepared for embedding. Chunking follows document structure and a token budget; a chunk is not necessarily one section or one snippet. |
|
|
17
|
+
| Line range | Inclusive, one-based lines in the indexed source note, such as `L12-28`. Search can point to a section or an embedding chunk. A null range provides no narrower location. |
|
|
18
|
+
| Outbound link | A link from the current note to another indexed note. `peek.outbound` returns distinct destination paths. |
|
|
19
|
+
| Backlink | A link from another indexed note to the current note. `peek.backlinks` returns distinct source paths. |
|
|
20
|
+
| Unresolved link | A written link target that did not resolve to an indexed note. This does not establish that the link is broken: attachments and notes outside the index can also be unresolved. `peek.unresolved` returns written targets. |
|
|
21
|
+
| Scope | The indexed notes selected for an operation by its preset and filters. Scope is not an access-control boundary. |
|
|
22
|
+
| Search signal | One source of ranking evidence: word matches, link relationships or vector similarity. A signal's rank is a candidate's position within that signal, not the final combined position. |
|
|
23
|
+
|
|
24
|
+
## Reading a section description
|
|
25
|
+
|
|
26
|
+
The illustrative entry `## Installation [L12-28, ~90t]` describes a section headed “Installation”, starting at line 12 and ending at line 28, with an estimated 90 tokens. `peek` returns that description. Reading the indicated lines retrieves the content. With nested headings, the description ends before the next heading, even when that heading is deeper.
|
|
27
|
+
|
|
28
|
+
## Naming output controls
|
|
29
|
+
|
|
30
|
+
Name the object and the unit: a snippet count is how many passages are returned; a snippet character limit controls passage length; a section count is how many section descriptions are returned; a link count controls link entries. A count limit is not pagination. An offset, when supported by an operation, skips entries before returning the requested count. Raw SQL supports `LIMIT` and `OFFSET`; search and peek do not currently expose offset options.
|
|
31
|
+
|
|
32
|
+
Peek count limits request prefixes of the ordered section and link lists. Each search or peek reads one committed index snapshot; separately issued operations can observe later commits. See [finite retrieval and paging](search.md#finite-retrieval-and-paging) for search budgets and paging retained results.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
<!-- sense-store-benchmark release=0.
|
|
1
|
+
<!-- sense-store-benchmark release=0.27.0 -->
|
|
2
2
|
# Current store benchmark summary
|
|
3
3
|
|
|
4
|
-
The release assessment generated this file for store selection. Release `0.
|
|
4
|
+
The release assessment generated this file for store selection. Release `0.27.0` passed on 2026-10-03, measured on Apple M1 Pro with Node v26.10.0.
|
|
5
5
|
|
|
6
6
|
The timing rows ran on the same 6,566-note tree. They include CLI startup and each store's complete selected path. Ranked candidates and downstream work can differ by store, so these are current operating measurements rather than an isolated database-engine contest.
|
|
7
7
|
|
|
8
8
|
| Store | Cold index | Warm count | Lexical search | Semantic search | Portable semantic nDCG@10 |
|
|
9
9
|
|---|---|---|---|---|---|
|
|
10
|
-
| sqlite | 2,
|
|
11
|
-
| duckdb | 3,
|
|
12
|
-
| turso | 3,
|
|
10
|
+
| sqlite | 2,254 ms | 260 ms | 350 ms | 576 ms | 0.3306 |
|
|
11
|
+
| duckdb | 3,026 ms | 319 ms | 510 ms | 695 ms | 0.3282 |
|
|
12
|
+
| turso | 3,273 ms | 279 ms | 412 ms | 1,081 ms | 0.3299 |
|
|
13
13
|
|
|
14
14
|
Cold index measures core index creation and a count query, excluding document embeddings. Warm count is a no-change `COUNT(*)` query. Lexical and semantic search are steady-state `sense search` commands. Lower timing is faster. Higher nDCG@10 is better; that quality column uses the same NFCorpus queries, judgments, result count, and model on every store.
|
|
15
15
|
|