@gmickel/gno 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +256 -0
  2. package/assets/skill/SKILL.md +112 -0
  3. package/assets/skill/cli-reference.md +327 -0
  4. package/assets/skill/examples.md +234 -0
  5. package/assets/skill/mcp-reference.md +159 -0
  6. package/package.json +90 -0
  7. package/src/app/constants.ts +313 -0
  8. package/src/cli/colors.ts +65 -0
  9. package/src/cli/commands/ask.ts +545 -0
  10. package/src/cli/commands/cleanup.ts +105 -0
  11. package/src/cli/commands/collection/add.ts +120 -0
  12. package/src/cli/commands/collection/index.ts +10 -0
  13. package/src/cli/commands/collection/list.ts +108 -0
  14. package/src/cli/commands/collection/remove.ts +64 -0
  15. package/src/cli/commands/collection/rename.ts +95 -0
  16. package/src/cli/commands/context/add.ts +67 -0
  17. package/src/cli/commands/context/check.ts +153 -0
  18. package/src/cli/commands/context/index.ts +10 -0
  19. package/src/cli/commands/context/list.ts +109 -0
  20. package/src/cli/commands/context/rm.ts +52 -0
  21. package/src/cli/commands/doctor.ts +393 -0
  22. package/src/cli/commands/embed.ts +462 -0
  23. package/src/cli/commands/get.ts +356 -0
  24. package/src/cli/commands/index-cmd.ts +119 -0
  25. package/src/cli/commands/index.ts +102 -0
  26. package/src/cli/commands/init.ts +328 -0
  27. package/src/cli/commands/ls.ts +217 -0
  28. package/src/cli/commands/mcp/config.ts +300 -0
  29. package/src/cli/commands/mcp/index.ts +24 -0
  30. package/src/cli/commands/mcp/install.ts +203 -0
  31. package/src/cli/commands/mcp/paths.ts +470 -0
  32. package/src/cli/commands/mcp/status.ts +222 -0
  33. package/src/cli/commands/mcp/uninstall.ts +158 -0
  34. package/src/cli/commands/mcp.ts +20 -0
  35. package/src/cli/commands/models/clear.ts +103 -0
  36. package/src/cli/commands/models/index.ts +32 -0
  37. package/src/cli/commands/models/list.ts +214 -0
  38. package/src/cli/commands/models/path.ts +51 -0
  39. package/src/cli/commands/models/pull.ts +199 -0
  40. package/src/cli/commands/models/use.ts +85 -0
  41. package/src/cli/commands/multi-get.ts +400 -0
  42. package/src/cli/commands/query.ts +220 -0
  43. package/src/cli/commands/ref-parser.ts +108 -0
  44. package/src/cli/commands/reset.ts +191 -0
  45. package/src/cli/commands/search.ts +136 -0
  46. package/src/cli/commands/shared.ts +156 -0
  47. package/src/cli/commands/skill/index.ts +19 -0
  48. package/src/cli/commands/skill/install.ts +197 -0
  49. package/src/cli/commands/skill/paths-cmd.ts +81 -0
  50. package/src/cli/commands/skill/paths.ts +191 -0
  51. package/src/cli/commands/skill/show.ts +73 -0
  52. package/src/cli/commands/skill/uninstall.ts +141 -0
  53. package/src/cli/commands/status.ts +205 -0
  54. package/src/cli/commands/update.ts +68 -0
  55. package/src/cli/commands/vsearch.ts +188 -0
  56. package/src/cli/context.ts +64 -0
  57. package/src/cli/errors.ts +64 -0
  58. package/src/cli/format/search-results.ts +211 -0
  59. package/src/cli/options.ts +183 -0
  60. package/src/cli/program.ts +1330 -0
  61. package/src/cli/run.ts +213 -0
  62. package/src/cli/ui.ts +92 -0
  63. package/src/config/defaults.ts +20 -0
  64. package/src/config/index.ts +55 -0
  65. package/src/config/loader.ts +161 -0
  66. package/src/config/paths.ts +87 -0
  67. package/src/config/saver.ts +153 -0
  68. package/src/config/types.ts +280 -0
  69. package/src/converters/adapters/markitdownTs/adapter.ts +140 -0
  70. package/src/converters/adapters/officeparser/adapter.ts +126 -0
  71. package/src/converters/canonicalize.ts +89 -0
  72. package/src/converters/errors.ts +218 -0
  73. package/src/converters/index.ts +51 -0
  74. package/src/converters/mime.ts +163 -0
  75. package/src/converters/native/markdown.ts +115 -0
  76. package/src/converters/native/plaintext.ts +56 -0
  77. package/src/converters/path.ts +48 -0
  78. package/src/converters/pipeline.ts +159 -0
  79. package/src/converters/registry.ts +74 -0
  80. package/src/converters/types.ts +123 -0
  81. package/src/converters/versions.ts +24 -0
  82. package/src/index.ts +27 -0
  83. package/src/ingestion/chunker.ts +238 -0
  84. package/src/ingestion/index.ts +32 -0
  85. package/src/ingestion/language.ts +276 -0
  86. package/src/ingestion/sync.ts +671 -0
  87. package/src/ingestion/types.ts +219 -0
  88. package/src/ingestion/walker.ts +235 -0
  89. package/src/llm/cache.ts +467 -0
  90. package/src/llm/errors.ts +191 -0
  91. package/src/llm/index.ts +58 -0
  92. package/src/llm/nodeLlamaCpp/adapter.ts +133 -0
  93. package/src/llm/nodeLlamaCpp/embedding.ts +165 -0
  94. package/src/llm/nodeLlamaCpp/generation.ts +88 -0
  95. package/src/llm/nodeLlamaCpp/lifecycle.ts +317 -0
  96. package/src/llm/nodeLlamaCpp/rerank.ts +94 -0
  97. package/src/llm/registry.ts +86 -0
  98. package/src/llm/types.ts +129 -0
  99. package/src/mcp/resources/index.ts +151 -0
  100. package/src/mcp/server.ts +229 -0
  101. package/src/mcp/tools/get.ts +220 -0
  102. package/src/mcp/tools/index.ts +160 -0
  103. package/src/mcp/tools/multi-get.ts +263 -0
  104. package/src/mcp/tools/query.ts +226 -0
  105. package/src/mcp/tools/search.ts +119 -0
  106. package/src/mcp/tools/status.ts +81 -0
  107. package/src/mcp/tools/vsearch.ts +198 -0
  108. package/src/pipeline/chunk-lookup.ts +44 -0
  109. package/src/pipeline/expansion.ts +256 -0
  110. package/src/pipeline/explain.ts +115 -0
  111. package/src/pipeline/fusion.ts +185 -0
  112. package/src/pipeline/hybrid.ts +535 -0
  113. package/src/pipeline/index.ts +64 -0
  114. package/src/pipeline/query-language.ts +118 -0
  115. package/src/pipeline/rerank.ts +223 -0
  116. package/src/pipeline/search.ts +261 -0
  117. package/src/pipeline/types.ts +328 -0
  118. package/src/pipeline/vsearch.ts +348 -0
  119. package/src/store/index.ts +41 -0
  120. package/src/store/migrations/001-initial.ts +196 -0
  121. package/src/store/migrations/index.ts +20 -0
  122. package/src/store/migrations/runner.ts +187 -0
  123. package/src/store/sqlite/adapter.ts +1242 -0
  124. package/src/store/sqlite/index.ts +7 -0
  125. package/src/store/sqlite/setup.ts +129 -0
  126. package/src/store/sqlite/types.ts +28 -0
  127. package/src/store/types.ts +506 -0
  128. package/src/store/vector/index.ts +13 -0
  129. package/src/store/vector/sqlite-vec.ts +373 -0
  130. package/src/store/vector/stats.ts +152 -0
  131. package/src/store/vector/types.ts +115 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Store layer exports.
3
+ * Provides StorePort interface and SQLite implementation.
4
+ *
5
+ * @module src/store
6
+ */
7
+
8
+ export type { Migration } from './migrations';
9
+ // Migrations
10
+ export {
11
+ getDbFtsTokenizer,
12
+ getSchemaVersion,
13
+ migrations,
14
+ needsFtsRebuild,
15
+ runMigrations,
16
+ } from './migrations';
17
+
18
+ // SQLite adapter
19
+ export { SqliteAdapter } from './sqlite';
20
+ // Types and interfaces
21
+ export type {
22
+ ChunkInput,
23
+ ChunkRow,
24
+ CleanupStats,
25
+ CollectionRow,
26
+ CollectionStatus,
27
+ ContextRow,
28
+ DocumentInput,
29
+ DocumentRow,
30
+ FtsResult,
31
+ FtsSearchOptions,
32
+ IndexStatus,
33
+ IngestErrorInput,
34
+ IngestErrorRow,
35
+ MigrationResult,
36
+ StoreError,
37
+ StoreErrorCode,
38
+ StorePort,
39
+ StoreResult,
40
+ } from './types';
41
+ export { err, ok } from './types';
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Initial schema migration.
3
+ * Creates all core tables for GNO.
4
+ *
5
+ * @module src/store/migrations/001_initial
6
+ */
7
+
8
+ import type { Database } from 'bun:sqlite';
9
+ import type { FtsTokenizer } from '../../config/types';
10
+ import type { Migration } from './runner';
11
+
12
+ export const migration: Migration = {
13
+ version: 1,
14
+ name: 'initial_schema',
15
+
16
+ up(db: Database, ftsTokenizer: FtsTokenizer): void {
17
+ // Collections (synced from YAML config)
18
+ db.exec(`
19
+ CREATE TABLE IF NOT EXISTS collections (
20
+ name TEXT PRIMARY KEY,
21
+ path TEXT NOT NULL,
22
+ pattern TEXT NOT NULL DEFAULT '**/*',
23
+ include TEXT,
24
+ exclude TEXT,
25
+ update_cmd TEXT,
26
+ language_hint TEXT,
27
+ synced_at TEXT NOT NULL DEFAULT (datetime('now'))
28
+ )
29
+ `);
30
+
31
+ // Contexts (synced from YAML config)
32
+ db.exec(`
33
+ CREATE TABLE IF NOT EXISTS contexts (
34
+ scope_type TEXT NOT NULL CHECK (scope_type IN ('global', 'collection', 'prefix')),
35
+ scope_key TEXT NOT NULL,
36
+ text TEXT NOT NULL,
37
+ synced_at TEXT NOT NULL DEFAULT (datetime('now')),
38
+ PRIMARY KEY (scope_type, scope_key)
39
+ )
40
+ `);
41
+
42
+ // Documents (source file identity)
43
+ db.exec(`
44
+ CREATE TABLE IF NOT EXISTS documents (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ collection TEXT NOT NULL,
47
+ rel_path TEXT NOT NULL,
48
+
49
+ source_hash TEXT NOT NULL,
50
+ source_mime TEXT NOT NULL,
51
+ source_ext TEXT NOT NULL,
52
+ source_size INTEGER NOT NULL,
53
+ source_mtime TEXT NOT NULL,
54
+
55
+ docid TEXT NOT NULL,
56
+ uri TEXT NOT NULL,
57
+
58
+ title TEXT,
59
+ mirror_hash TEXT,
60
+ converter_id TEXT,
61
+ converter_version TEXT,
62
+ language_hint TEXT,
63
+
64
+ active INTEGER NOT NULL DEFAULT 1,
65
+
66
+ last_error_code TEXT,
67
+ last_error_message TEXT,
68
+ last_error_at TEXT,
69
+
70
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
71
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
72
+
73
+ UNIQUE (collection, rel_path),
74
+ FOREIGN KEY (collection) REFERENCES collections(name) ON DELETE CASCADE
75
+ -- Note: mirror_hash is NOT an FK - documents are tracked before content exists
76
+ -- Cleanup via cleanupOrphans() handles orphaned content
77
+ )
78
+ `);
79
+
80
+ db.exec(
81
+ 'CREATE INDEX IF NOT EXISTS idx_documents_collection ON documents(collection)'
82
+ );
83
+ db.exec(
84
+ 'CREATE INDEX IF NOT EXISTS idx_documents_active ON documents(active)'
85
+ );
86
+ db.exec(
87
+ 'CREATE INDEX IF NOT EXISTS idx_documents_mirror_hash ON documents(mirror_hash)'
88
+ );
89
+ db.exec(
90
+ 'CREATE INDEX IF NOT EXISTS idx_documents_docid ON documents(docid)'
91
+ );
92
+ db.exec('CREATE INDEX IF NOT EXISTS idx_documents_uri ON documents(uri)');
93
+
94
+ // Content (content-addressed markdown mirrors)
95
+ db.exec(`
96
+ CREATE TABLE IF NOT EXISTS content (
97
+ mirror_hash TEXT PRIMARY KEY,
98
+ markdown TEXT NOT NULL,
99
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
100
+ )
101
+ `);
102
+
103
+ // Content chunks (for FTS and vectors)
104
+ db.exec(`
105
+ CREATE TABLE IF NOT EXISTS content_chunks (
106
+ mirror_hash TEXT NOT NULL,
107
+ seq INTEGER NOT NULL,
108
+ pos INTEGER NOT NULL,
109
+ text TEXT NOT NULL,
110
+ start_line INTEGER NOT NULL,
111
+ end_line INTEGER NOT NULL,
112
+ language TEXT,
113
+ token_count INTEGER,
114
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
115
+ PRIMARY KEY (mirror_hash, seq),
116
+ FOREIGN KEY (mirror_hash) REFERENCES content(mirror_hash) ON DELETE CASCADE
117
+ )
118
+ `);
119
+
120
+ db.exec(
121
+ 'CREATE INDEX IF NOT EXISTS idx_chunks_mirror_hash ON content_chunks(mirror_hash)'
122
+ );
123
+
124
+ // FTS5 virtual table with configurable tokenizer
125
+ db.exec(`
126
+ CREATE VIRTUAL TABLE IF NOT EXISTS content_fts USING fts5(
127
+ text,
128
+ tokenize='${ftsTokenizer}'
129
+ )
130
+ `);
131
+
132
+ // Content vectors (EPIC 7)
133
+ db.exec(`
134
+ CREATE TABLE IF NOT EXISTS content_vectors (
135
+ mirror_hash TEXT NOT NULL,
136
+ seq INTEGER NOT NULL,
137
+ model TEXT NOT NULL,
138
+ embedding BLOB NOT NULL,
139
+ embedded_at TEXT NOT NULL DEFAULT (datetime('now')),
140
+ PRIMARY KEY (mirror_hash, seq, model),
141
+ FOREIGN KEY (mirror_hash, seq) REFERENCES content_chunks(mirror_hash, seq) ON DELETE CASCADE
142
+ )
143
+ `);
144
+
145
+ db.exec(
146
+ 'CREATE INDEX IF NOT EXISTS idx_vectors_model ON content_vectors(model)'
147
+ );
148
+
149
+ // LLM cache (EPIC 6+)
150
+ db.exec(`
151
+ CREATE TABLE IF NOT EXISTS llm_cache (
152
+ key TEXT PRIMARY KEY,
153
+ value TEXT NOT NULL,
154
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
155
+ expires_at TEXT
156
+ )
157
+ `);
158
+
159
+ db.exec(
160
+ 'CREATE INDEX IF NOT EXISTS idx_llm_cache_expires ON llm_cache(expires_at)'
161
+ );
162
+
163
+ // Ingest errors
164
+ db.exec(`
165
+ CREATE TABLE IF NOT EXISTS ingest_errors (
166
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
167
+ collection TEXT NOT NULL,
168
+ rel_path TEXT NOT NULL,
169
+ occurred_at TEXT NOT NULL DEFAULT (datetime('now')),
170
+ code TEXT NOT NULL,
171
+ message TEXT NOT NULL,
172
+ details_json TEXT
173
+ )
174
+ `);
175
+
176
+ db.exec(
177
+ 'CREATE INDEX IF NOT EXISTS idx_ingest_errors_occurred ON ingest_errors(occurred_at DESC)'
178
+ );
179
+ db.exec(
180
+ 'CREATE INDEX IF NOT EXISTS idx_ingest_errors_collection ON ingest_errors(collection, rel_path)'
181
+ );
182
+ },
183
+
184
+ down(db: Database): void {
185
+ // Drop in reverse order of creation
186
+ db.exec('DROP TABLE IF EXISTS ingest_errors');
187
+ db.exec('DROP TABLE IF EXISTS llm_cache');
188
+ db.exec('DROP TABLE IF EXISTS content_vectors');
189
+ db.exec('DROP TABLE IF EXISTS content_fts');
190
+ db.exec('DROP TABLE IF EXISTS content_chunks');
191
+ db.exec('DROP TABLE IF EXISTS content');
192
+ db.exec('DROP TABLE IF EXISTS documents');
193
+ db.exec('DROP TABLE IF EXISTS contexts');
194
+ db.exec('DROP TABLE IF EXISTS collections');
195
+ },
196
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Migration registry.
3
+ * Exports all migrations in order.
4
+ *
5
+ * @module src/store/migrations
6
+ */
7
+
8
+ export type { Migration } from './runner';
9
+ export {
10
+ getDbFtsTokenizer,
11
+ getSchemaVersion,
12
+ needsFtsRebuild,
13
+ runMigrations,
14
+ } from './runner';
15
+
16
+ // Import all migrations
17
+ import { migration as m001 } from './001-initial';
18
+
19
+ /** All migrations in order */
20
+ export const migrations = [m001];
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Database migration runner.
3
+ * Tracks applied migrations in schema_meta table.
4
+ *
5
+ * @module src/store/migrations/runner
6
+ */
7
+
8
+ import type { Database } from 'bun:sqlite';
9
+ import type { FtsTokenizer } from '../../config/types';
10
+ import type { MigrationResult, StoreResult } from '../types';
11
+ import { err, ok } from '../types';
12
+
13
+ // ─────────────────────────────────────────────────────────────────────────────
14
+ // Types
15
+ // ─────────────────────────────────────────────────────────────────────────────
16
+
17
+ /** Migration definition */
18
+ export interface Migration {
19
+ /** Version number (must be unique and sequential) */
20
+ version: number;
21
+ /** Human-readable name */
22
+ name: string;
23
+ /** Apply migration */
24
+ up(db: Database, ftsTokenizer: FtsTokenizer): void;
25
+ /** Rollback migration (optional) */
26
+ down?(db: Database): void;
27
+ }
28
+
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+ // Schema Meta Queries
31
+ // ─────────────────────────────────────────────────────────────────────────────
32
+
33
+ const BOOTSTRAP_META_TABLE = `
34
+ CREATE TABLE IF NOT EXISTS schema_meta (
35
+ key TEXT PRIMARY KEY,
36
+ value TEXT NOT NULL,
37
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
38
+ )
39
+ `;
40
+
41
+ const GET_META = 'SELECT value FROM schema_meta WHERE key = ?';
42
+
43
+ const SET_META = `
44
+ INSERT INTO schema_meta (key, value, updated_at)
45
+ VALUES (?, ?, datetime('now'))
46
+ ON CONFLICT(key) DO UPDATE SET
47
+ value = excluded.value,
48
+ updated_at = datetime('now')
49
+ `;
50
+
51
+ // ─────────────────────────────────────────────────────────────────────────────
52
+ // Migration Runner
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+
55
+ /**
56
+ * Get current schema version from database.
57
+ * Returns 0 if no version is set.
58
+ */
59
+ export function getSchemaVersion(db: Database): number {
60
+ try {
61
+ const row = db.query<{ value: string }, [string]>(GET_META).get('version');
62
+ return row ? Number.parseInt(row.value, 10) : 0;
63
+ } catch {
64
+ // Table doesn't exist yet
65
+ return 0;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Get current FTS tokenizer from database.
71
+ * Returns null if not set.
72
+ */
73
+ export function getDbFtsTokenizer(db: Database): FtsTokenizer | null {
74
+ try {
75
+ const row = db
76
+ .query<{ value: string }, [string]>(GET_META)
77
+ .get('fts_tokenizer');
78
+ return row ? (row.value as FtsTokenizer) : null;
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Set metadata value.
86
+ */
87
+ function setMeta(db: Database, key: string, value: string): void {
88
+ db.run(SET_META, [key, value]);
89
+ }
90
+
91
+ /**
92
+ * Run pending migrations.
93
+ *
94
+ * @param db - Open database connection
95
+ * @param migrations - Array of migrations to apply
96
+ * @param ftsTokenizer - FTS tokenizer from config
97
+ * @returns Migration result with applied versions
98
+ */
99
+ export function runMigrations(
100
+ db: Database,
101
+ migrations: Migration[],
102
+ ftsTokenizer: FtsTokenizer
103
+ ): StoreResult<MigrationResult> {
104
+ try {
105
+ // Bootstrap schema_meta table
106
+ db.exec(BOOTSTRAP_META_TABLE);
107
+
108
+ // Get current version
109
+ const currentVersion = getSchemaVersion(db);
110
+
111
+ // Check FTS tokenizer consistency
112
+ const dbTokenizer = getDbFtsTokenizer(db);
113
+ if (dbTokenizer !== null && dbTokenizer !== ftsTokenizer) {
114
+ // Tokenizer mismatch - this requires special handling
115
+ // For now, we error out. EPIC 5 will handle FTS rebuild.
116
+ return err(
117
+ 'MIGRATION_FAILED',
118
+ `FTS tokenizer mismatch: DB has '${dbTokenizer}', config has '${ftsTokenizer}'. ` +
119
+ 'Run `gno index --rebuild-fts` to recreate FTS index with new tokenizer.'
120
+ );
121
+ }
122
+
123
+ // Sort migrations by version
124
+ const sorted = [...migrations].sort((a, b) => a.version - b.version);
125
+
126
+ // Validate sequential versions
127
+ for (let i = 0; i < sorted.length; i++) {
128
+ const migration = sorted[i];
129
+ if (migration && migration.version !== i + 1) {
130
+ return err(
131
+ 'MIGRATION_FAILED',
132
+ `Migration versions must be sequential. Expected ${i + 1}, got ${migration.version}`
133
+ );
134
+ }
135
+ }
136
+
137
+ // Filter pending migrations
138
+ const pending = sorted.filter((m) => m.version > currentVersion);
139
+
140
+ if (pending.length === 0) {
141
+ return ok({
142
+ applied: [],
143
+ currentVersion,
144
+ ftsTokenizer: dbTokenizer ?? ftsTokenizer,
145
+ });
146
+ }
147
+
148
+ // Apply migrations in a transaction
149
+ const applied: number[] = [];
150
+ const transaction = db.transaction(() => {
151
+ for (const migration of pending) {
152
+ migration.up(db, ftsTokenizer);
153
+ setMeta(db, 'version', migration.version.toString());
154
+ applied.push(migration.version);
155
+ }
156
+
157
+ // Set FTS tokenizer if not already set
158
+ if (dbTokenizer === null) {
159
+ setMeta(db, 'fts_tokenizer', ftsTokenizer);
160
+ setMeta(db, 'created_at', new Date().toISOString());
161
+ }
162
+ });
163
+
164
+ transaction();
165
+
166
+ return ok({
167
+ applied,
168
+ currentVersion: pending.at(-1)?.version ?? currentVersion,
169
+ ftsTokenizer,
170
+ });
171
+ } catch (cause) {
172
+ const message =
173
+ cause instanceof Error ? cause.message : 'Unknown migration error';
174
+ return err('MIGRATION_FAILED', message, cause);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Check if FTS tokenizer change is needed.
180
+ */
181
+ export function needsFtsRebuild(
182
+ db: Database,
183
+ configTokenizer: FtsTokenizer
184
+ ): boolean {
185
+ const dbTokenizer = getDbFtsTokenizer(db);
186
+ return dbTokenizer !== null && dbTokenizer !== configTokenizer;
187
+ }