@getlore/cli 0.2.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 (148) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +80 -0
  3. package/dist/cli/colors.d.ts +48 -0
  4. package/dist/cli/colors.js +48 -0
  5. package/dist/cli/commands/ask.d.ts +7 -0
  6. package/dist/cli/commands/ask.js +97 -0
  7. package/dist/cli/commands/auth.d.ts +10 -0
  8. package/dist/cli/commands/auth.js +484 -0
  9. package/dist/cli/commands/daemon.d.ts +22 -0
  10. package/dist/cli/commands/daemon.js +244 -0
  11. package/dist/cli/commands/docs.d.ts +7 -0
  12. package/dist/cli/commands/docs.js +188 -0
  13. package/dist/cli/commands/extensions.d.ts +7 -0
  14. package/dist/cli/commands/extensions.js +204 -0
  15. package/dist/cli/commands/misc.d.ts +7 -0
  16. package/dist/cli/commands/misc.js +172 -0
  17. package/dist/cli/commands/pending.d.ts +7 -0
  18. package/dist/cli/commands/pending.js +63 -0
  19. package/dist/cli/commands/projects.d.ts +7 -0
  20. package/dist/cli/commands/projects.js +136 -0
  21. package/dist/cli/commands/search.d.ts +7 -0
  22. package/dist/cli/commands/search.js +102 -0
  23. package/dist/cli/commands/skills.d.ts +24 -0
  24. package/dist/cli/commands/skills.js +447 -0
  25. package/dist/cli/commands/sources.d.ts +7 -0
  26. package/dist/cli/commands/sources.js +121 -0
  27. package/dist/cli/commands/sync.d.ts +31 -0
  28. package/dist/cli/commands/sync.js +768 -0
  29. package/dist/cli/helpers.d.ts +30 -0
  30. package/dist/cli/helpers.js +119 -0
  31. package/dist/core/auth.d.ts +62 -0
  32. package/dist/core/auth.js +330 -0
  33. package/dist/core/config.d.ts +41 -0
  34. package/dist/core/config.js +96 -0
  35. package/dist/core/data-repo.d.ts +31 -0
  36. package/dist/core/data-repo.js +146 -0
  37. package/dist/core/embedder.d.ts +22 -0
  38. package/dist/core/embedder.js +104 -0
  39. package/dist/core/git.d.ts +37 -0
  40. package/dist/core/git.js +140 -0
  41. package/dist/core/index.d.ts +4 -0
  42. package/dist/core/index.js +5 -0
  43. package/dist/core/insight-extractor.d.ts +26 -0
  44. package/dist/core/insight-extractor.js +114 -0
  45. package/dist/core/local-search.d.ts +43 -0
  46. package/dist/core/local-search.js +221 -0
  47. package/dist/core/themes.d.ts +15 -0
  48. package/dist/core/themes.js +77 -0
  49. package/dist/core/types.d.ts +177 -0
  50. package/dist/core/types.js +9 -0
  51. package/dist/core/user-settings.d.ts +15 -0
  52. package/dist/core/user-settings.js +42 -0
  53. package/dist/core/vector-store-lance.d.ts +98 -0
  54. package/dist/core/vector-store-lance.js +384 -0
  55. package/dist/core/vector-store-supabase.d.ts +89 -0
  56. package/dist/core/vector-store-supabase.js +295 -0
  57. package/dist/core/vector-store.d.ts +131 -0
  58. package/dist/core/vector-store.js +503 -0
  59. package/dist/daemon-runner.d.ts +8 -0
  60. package/dist/daemon-runner.js +246 -0
  61. package/dist/extensions/config.d.ts +22 -0
  62. package/dist/extensions/config.js +102 -0
  63. package/dist/extensions/proposals.d.ts +30 -0
  64. package/dist/extensions/proposals.js +178 -0
  65. package/dist/extensions/registry.d.ts +35 -0
  66. package/dist/extensions/registry.js +309 -0
  67. package/dist/extensions/sandbox.d.ts +16 -0
  68. package/dist/extensions/sandbox.js +17 -0
  69. package/dist/extensions/types.d.ts +114 -0
  70. package/dist/extensions/types.js +4 -0
  71. package/dist/extensions/worker.d.ts +1 -0
  72. package/dist/extensions/worker.js +49 -0
  73. package/dist/index.d.ts +17 -0
  74. package/dist/index.js +105 -0
  75. package/dist/mcp/handlers/archive-project.d.ts +51 -0
  76. package/dist/mcp/handlers/archive-project.js +112 -0
  77. package/dist/mcp/handlers/get-quotes.d.ts +27 -0
  78. package/dist/mcp/handlers/get-quotes.js +61 -0
  79. package/dist/mcp/handlers/get-source.d.ts +9 -0
  80. package/dist/mcp/handlers/get-source.js +40 -0
  81. package/dist/mcp/handlers/ingest.d.ts +25 -0
  82. package/dist/mcp/handlers/ingest.js +305 -0
  83. package/dist/mcp/handlers/list-projects.d.ts +4 -0
  84. package/dist/mcp/handlers/list-projects.js +16 -0
  85. package/dist/mcp/handlers/list-sources.d.ts +11 -0
  86. package/dist/mcp/handlers/list-sources.js +20 -0
  87. package/dist/mcp/handlers/research-agent.d.ts +21 -0
  88. package/dist/mcp/handlers/research-agent.js +369 -0
  89. package/dist/mcp/handlers/research.d.ts +22 -0
  90. package/dist/mcp/handlers/research.js +225 -0
  91. package/dist/mcp/handlers/retain.d.ts +18 -0
  92. package/dist/mcp/handlers/retain.js +92 -0
  93. package/dist/mcp/handlers/search.d.ts +52 -0
  94. package/dist/mcp/handlers/search.js +145 -0
  95. package/dist/mcp/handlers/sync.d.ts +47 -0
  96. package/dist/mcp/handlers/sync.js +211 -0
  97. package/dist/mcp/server.d.ts +10 -0
  98. package/dist/mcp/server.js +268 -0
  99. package/dist/mcp/tools.d.ts +16 -0
  100. package/dist/mcp/tools.js +297 -0
  101. package/dist/sync/config.d.ts +26 -0
  102. package/dist/sync/config.js +140 -0
  103. package/dist/sync/discover.d.ts +51 -0
  104. package/dist/sync/discover.js +190 -0
  105. package/dist/sync/index.d.ts +11 -0
  106. package/dist/sync/index.js +11 -0
  107. package/dist/sync/process.d.ts +50 -0
  108. package/dist/sync/process.js +285 -0
  109. package/dist/sync/processors.d.ts +24 -0
  110. package/dist/sync/processors.js +351 -0
  111. package/dist/tui/browse-handlers-ask.d.ts +30 -0
  112. package/dist/tui/browse-handlers-ask.js +372 -0
  113. package/dist/tui/browse-handlers-autocomplete.d.ts +49 -0
  114. package/dist/tui/browse-handlers-autocomplete.js +270 -0
  115. package/dist/tui/browse-handlers-extensions.d.ts +18 -0
  116. package/dist/tui/browse-handlers-extensions.js +107 -0
  117. package/dist/tui/browse-handlers-pending.d.ts +22 -0
  118. package/dist/tui/browse-handlers-pending.js +100 -0
  119. package/dist/tui/browse-handlers-research.d.ts +32 -0
  120. package/dist/tui/browse-handlers-research.js +363 -0
  121. package/dist/tui/browse-handlers-tools.d.ts +42 -0
  122. package/dist/tui/browse-handlers-tools.js +289 -0
  123. package/dist/tui/browse-handlers.d.ts +239 -0
  124. package/dist/tui/browse-handlers.js +1944 -0
  125. package/dist/tui/browse-render-extensions.d.ts +14 -0
  126. package/dist/tui/browse-render-extensions.js +114 -0
  127. package/dist/tui/browse-render-tools.d.ts +18 -0
  128. package/dist/tui/browse-render-tools.js +259 -0
  129. package/dist/tui/browse-render.d.ts +51 -0
  130. package/dist/tui/browse-render.js +599 -0
  131. package/dist/tui/browse-types.d.ts +142 -0
  132. package/dist/tui/browse-types.js +70 -0
  133. package/dist/tui/browse-ui.d.ts +10 -0
  134. package/dist/tui/browse-ui.js +432 -0
  135. package/dist/tui/browse.d.ts +17 -0
  136. package/dist/tui/browse.js +625 -0
  137. package/dist/tui/markdown.d.ts +22 -0
  138. package/dist/tui/markdown.js +223 -0
  139. package/package.json +71 -0
  140. package/plugins/claude-code/.claude-plugin/plugin.json +10 -0
  141. package/plugins/claude-code/.mcp.json +6 -0
  142. package/plugins/claude-code/skills/lore/SKILL.md +63 -0
  143. package/plugins/codex/SKILL.md +36 -0
  144. package/plugins/codex/agents/openai.yaml +10 -0
  145. package/plugins/gemini/GEMINI.md +31 -0
  146. package/plugins/gemini/gemini-extension.json +11 -0
  147. package/skills/generic-agent.md +99 -0
  148. package/skills/openclaw.md +67 -0
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Lore - Vector Store (Supabase + pgvector)
3
+ *
4
+ * Cloud-hosted vector storage for semantic search across sources and chunks.
5
+ * Replaces LanceDB for multi-machine, multi-agent support.
6
+ */
7
+ import { createClient } from '@supabase/supabase-js';
8
+ let supabase = null;
9
+ function getSupabase() {
10
+ if (!supabase) {
11
+ const url = process.env.SUPABASE_URL;
12
+ const key = process.env.SUPABASE_SERVICE_KEY || process.env.SUPABASE_ANON_KEY;
13
+ if (!url || !key) {
14
+ throw new Error('SUPABASE_URL and SUPABASE_SERVICE_KEY (or SUPABASE_ANON_KEY) are required');
15
+ }
16
+ supabase = createClient(url, key);
17
+ }
18
+ return supabase;
19
+ }
20
+ // ============================================================================
21
+ // Index Management (compatibility layer - not needed for Supabase)
22
+ // ============================================================================
23
+ export async function indexExists(_dbPath) {
24
+ // With Supabase, the index always "exists" if we can connect
25
+ try {
26
+ const client = getSupabase();
27
+ const { error } = await client.from('sources').select('id').limit(1);
28
+ return !error;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ export async function initializeTables(_dbPath) {
35
+ // Tables are managed via migrations in Supabase
36
+ // This is a no-op for compatibility
37
+ }
38
+ export function resetDatabaseConnection() {
39
+ // Reset the client to force reconnection
40
+ supabase = null;
41
+ }
42
+ export async function closeDatabase() {
43
+ supabase = null;
44
+ }
45
+ // For compatibility - Supabase doesn't use a local path
46
+ export async function getDatabase(_dbPath) {
47
+ return getSupabase();
48
+ }
49
+ // ============================================================================
50
+ // Source Storage
51
+ // ============================================================================
52
+ export async function addSource(_dbPath, source, vector) {
53
+ const client = getSupabase();
54
+ const { error } = await client.from('sources').upsert({
55
+ id: source.id,
56
+ title: source.title,
57
+ source_type: source.source_type,
58
+ content_type: source.content_type,
59
+ projects: JSON.parse(source.projects),
60
+ tags: JSON.parse(source.tags),
61
+ created_at: source.created_at,
62
+ summary: source.summary,
63
+ themes_json: JSON.parse(source.themes_json),
64
+ quotes_json: JSON.parse(source.quotes_json),
65
+ has_full_content: source.has_full_content,
66
+ embedding: vector,
67
+ indexed_at: new Date().toISOString(),
68
+ });
69
+ if (error) {
70
+ console.error('[addSource] Error:', error);
71
+ throw error;
72
+ }
73
+ }
74
+ export async function addChunks(_dbPath, chunks) {
75
+ if (chunks.length === 0)
76
+ return;
77
+ const client = getSupabase();
78
+ const records = chunks.map((chunk) => ({
79
+ id: chunk.id,
80
+ source_id: chunk.source_id,
81
+ content: chunk.content,
82
+ type: chunk.type,
83
+ theme_name: chunk.theme_name || null,
84
+ speaker: chunk.speaker || null,
85
+ timestamp: chunk.timestamp || null,
86
+ embedding: chunk.vector,
87
+ indexed_at: new Date().toISOString(),
88
+ }));
89
+ const { error } = await client.from('chunks').upsert(records);
90
+ if (error) {
91
+ console.error('[addChunks] Error:', error);
92
+ throw error;
93
+ }
94
+ }
95
+ export async function storeSources(_dbPath, sources) {
96
+ const client = getSupabase();
97
+ const records = sources.map(({ source, vector }) => ({
98
+ id: source.id,
99
+ title: source.title,
100
+ source_type: source.source_type,
101
+ content_type: source.content_type,
102
+ projects: JSON.parse(source.projects),
103
+ tags: JSON.parse(source.tags),
104
+ created_at: source.created_at,
105
+ summary: source.summary,
106
+ themes_json: JSON.parse(source.themes_json),
107
+ quotes_json: JSON.parse(source.quotes_json),
108
+ has_full_content: source.has_full_content,
109
+ embedding: vector,
110
+ indexed_at: new Date().toISOString(),
111
+ }));
112
+ const { error } = await client.from('sources').upsert(records);
113
+ if (error) {
114
+ console.error('[storeSources] Error:', error);
115
+ throw error;
116
+ }
117
+ }
118
+ export async function storeChunks(_dbPath, chunks) {
119
+ if (chunks.length === 0)
120
+ return;
121
+ await addChunks(_dbPath, chunks);
122
+ }
123
+ // ============================================================================
124
+ // Search Operations
125
+ // ============================================================================
126
+ export async function searchSources(_dbPath, queryVector, options = {}) {
127
+ const { limit = 10, project, source_type, content_type, recency_boost = 0.15 } = options;
128
+ const client = getSupabase();
129
+ const { data, error } = await client.rpc('search_sources', {
130
+ query_embedding: queryVector,
131
+ match_count: limit,
132
+ filter_project: project || null,
133
+ filter_source_type: source_type || null,
134
+ filter_content_type: content_type || null,
135
+ recency_boost,
136
+ });
137
+ if (error) {
138
+ console.error('Error searching sources:', error);
139
+ return [];
140
+ }
141
+ return (data || []).map((row) => ({
142
+ id: row.id,
143
+ title: row.title,
144
+ source_type: row.source_type,
145
+ content_type: row.content_type,
146
+ projects: row.projects,
147
+ tags: row.tags,
148
+ created_at: row.created_at,
149
+ summary: row.summary,
150
+ themes: (row.themes_json || []),
151
+ quotes: (row.quotes_json || []),
152
+ score: row.score,
153
+ }));
154
+ }
155
+ export async function searchChunks(_dbPath, queryVector, options = {}) {
156
+ const { limit = 20, type, theme_name, source_id } = options;
157
+ const client = getSupabase();
158
+ const { data, error } = await client.rpc('search_chunks', {
159
+ query_embedding: queryVector,
160
+ match_count: limit,
161
+ filter_type: type || null,
162
+ filter_theme_name: theme_name || null,
163
+ filter_source_id: source_id || null,
164
+ });
165
+ if (error) {
166
+ console.error('Error searching chunks:', error);
167
+ return [];
168
+ }
169
+ return (data || []).map((row) => ({
170
+ id: row.id,
171
+ source_id: row.source_id,
172
+ content: row.content,
173
+ type: row.type,
174
+ theme_name: (row.theme_name || ''),
175
+ speaker: (row.speaker || ''),
176
+ timestamp: (row.timestamp || ''),
177
+ score: row.score,
178
+ }));
179
+ }
180
+ // ============================================================================
181
+ // Retrieval Operations
182
+ // ============================================================================
183
+ export async function getAllSources(_dbPath, options = {}) {
184
+ const { project, source_type, limit } = options;
185
+ const client = getSupabase();
186
+ let query = client
187
+ .from('sources')
188
+ .select('id, title, source_type, content_type, projects, created_at, summary')
189
+ .order('created_at', { ascending: false });
190
+ if (source_type) {
191
+ query = query.eq('source_type', source_type);
192
+ }
193
+ if (project) {
194
+ query = query.contains('projects', [project]);
195
+ }
196
+ if (limit) {
197
+ query = query.limit(limit);
198
+ }
199
+ const { data, error } = await query;
200
+ if (error) {
201
+ console.error('Error getting all sources:', error);
202
+ return [];
203
+ }
204
+ return (data || []).map((row) => ({
205
+ id: row.id,
206
+ title: row.title,
207
+ source_type: row.source_type,
208
+ content_type: row.content_type,
209
+ projects: row.projects,
210
+ created_at: row.created_at,
211
+ summary: row.summary,
212
+ }));
213
+ }
214
+ export async function getSourceById(_dbPath, sourceId) {
215
+ const client = getSupabase();
216
+ const { data, error } = await client
217
+ .from('sources')
218
+ .select('*')
219
+ .eq('id', sourceId)
220
+ .single();
221
+ if (error || !data) {
222
+ console.error('Error getting source by ID:', error);
223
+ return null;
224
+ }
225
+ return {
226
+ id: data.id,
227
+ title: data.title,
228
+ source_type: data.source_type,
229
+ content_type: data.content_type,
230
+ projects: data.projects,
231
+ tags: data.tags,
232
+ created_at: data.created_at,
233
+ summary: data.summary,
234
+ themes: data.themes_json || [],
235
+ quotes: data.quotes_json || [],
236
+ };
237
+ }
238
+ // ============================================================================
239
+ // Statistics
240
+ // ============================================================================
241
+ export async function getThemeStats(_dbPath, project) {
242
+ const client = getSupabase();
243
+ const stats = new Map();
244
+ let query = client.from('sources').select('themes_json, quotes_json, projects');
245
+ if (project) {
246
+ query = query.contains('projects', [project]);
247
+ }
248
+ const { data, error } = await query;
249
+ if (error) {
250
+ console.error('Error getting theme stats:', error);
251
+ return stats;
252
+ }
253
+ for (const row of data || []) {
254
+ const themes = (row.themes_json || []);
255
+ for (const theme of themes) {
256
+ const existing = stats.get(theme.name) || { source_count: 0, quote_count: 0 };
257
+ existing.source_count++;
258
+ existing.quote_count += theme.evidence?.length || 0;
259
+ stats.set(theme.name, existing);
260
+ }
261
+ }
262
+ return stats;
263
+ }
264
+ export async function getProjectStats(_dbPath) {
265
+ const client = getSupabase();
266
+ const projectMap = new Map();
267
+ const { data, error } = await client
268
+ .from('sources')
269
+ .select('projects, quotes_json, created_at');
270
+ if (error) {
271
+ console.error('Error getting project stats:', error);
272
+ return [];
273
+ }
274
+ for (const row of data || []) {
275
+ const projects = row.projects;
276
+ const quotes = (row.quotes_json || []);
277
+ const created_at = row.created_at;
278
+ for (const project of projects) {
279
+ const existing = projectMap.get(project) || {
280
+ source_count: 0,
281
+ quote_count: 0,
282
+ latest_activity: created_at,
283
+ };
284
+ existing.source_count++;
285
+ existing.quote_count += quotes.length;
286
+ if (new Date(created_at) > new Date(existing.latest_activity)) {
287
+ existing.latest_activity = created_at;
288
+ }
289
+ projectMap.set(project, existing);
290
+ }
291
+ }
292
+ return Array.from(projectMap.entries())
293
+ .map(([project, stats]) => ({ project, ...stats }))
294
+ .sort((a, b) => new Date(b.latest_activity).getTime() - new Date(a.latest_activity).getTime());
295
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Lore - Vector Store (Supabase + pgvector)
3
+ *
4
+ * Cloud-hosted vector storage for semantic search across sources and chunks.
5
+ * Replaces LanceDB for multi-machine, multi-agent support.
6
+ */
7
+ import { SupabaseClient } from '@supabase/supabase-js';
8
+ import type { SourceRecord, Quote, Theme, SourceType, ContentType, SearchMode } from './types.js';
9
+ /**
10
+ * Get an authenticated Supabase client. Three modes:
11
+ * 1. Service key (env var set) → bypasses RLS, backward compatible
12
+ * 2. Authenticated user → publishable key + auth session token → RLS applies
13
+ * 3. Neither → throws with helpful message
14
+ */
15
+ export declare function getSupabase(): Promise<SupabaseClient>;
16
+ export declare function indexExists(_dbPath: string): Promise<boolean>;
17
+ export declare function initializeTables(_dbPath: string): Promise<void>;
18
+ export declare function resetDatabaseConnection(): void;
19
+ export declare function closeDatabase(): Promise<void>;
20
+ export declare function getDatabase(_dbPath: string): Promise<SupabaseClient>;
21
+ export declare function addSource(_dbPath: string, source: SourceRecord, vector: number[], extras?: {
22
+ content_hash?: string;
23
+ source_path?: string;
24
+ source_url?: string;
25
+ source_name?: string;
26
+ }): Promise<void>;
27
+ export declare function storeSources(_dbPath: string, sources: Array<{
28
+ source: SourceRecord;
29
+ vector: number[];
30
+ extras?: {
31
+ content_hash?: string;
32
+ source_path?: string;
33
+ source_url?: string;
34
+ source_name?: string;
35
+ };
36
+ }>): Promise<void>;
37
+ export declare function findSourceByPath(_dbPath: string, sourcePath: string): Promise<{
38
+ id: string;
39
+ content_hash: string;
40
+ } | null>;
41
+ export declare function getSourcePathMappings(_dbPath: string, paths: string[]): Promise<Map<string, {
42
+ id: string;
43
+ content_hash: string;
44
+ }>>;
45
+ export declare function checkContentHashExists(_dbPath: string, contentHash: string): Promise<boolean>;
46
+ export declare function getExistingContentHashes(_dbPath: string, hashes: string[]): Promise<Set<string>>;
47
+ export interface SearchSourcesOptions {
48
+ limit?: number;
49
+ project?: string;
50
+ source_type?: SourceType;
51
+ content_type?: ContentType;
52
+ recency_boost?: number;
53
+ /** Search mode: 'semantic', 'keyword', or 'hybrid' (default) */
54
+ mode?: SearchMode;
55
+ /** Query text for keyword search (required for keyword/hybrid modes) */
56
+ queryText?: string;
57
+ /** RRF constant for hybrid search (default 60) */
58
+ rrf_k?: number;
59
+ }
60
+ export interface SearchSourceResult {
61
+ id: string;
62
+ title: string;
63
+ source_type: SourceType;
64
+ content_type: ContentType;
65
+ projects: string[];
66
+ tags: string[];
67
+ created_at: string;
68
+ summary: string;
69
+ themes: Theme[];
70
+ quotes: Quote[];
71
+ score: number;
72
+ /** Rank in semantic search results (only in hybrid mode) */
73
+ semantic_rank?: number;
74
+ /** Rank in keyword search results (only in hybrid mode) */
75
+ keyword_rank?: number;
76
+ }
77
+ export declare function searchSources(_dbPath: string, queryVector: number[], options?: SearchSourcesOptions): Promise<SearchSourceResult[]>;
78
+ export declare function getAllSources(_dbPath: string, options?: {
79
+ project?: string;
80
+ source_type?: SourceType;
81
+ limit?: number;
82
+ }): Promise<Array<{
83
+ id: string;
84
+ title: string;
85
+ source_type: SourceType;
86
+ content_type: ContentType;
87
+ projects: string[];
88
+ created_at: string;
89
+ summary: string;
90
+ }>>;
91
+ export declare function getSourceById(_dbPath: string, sourceId: string): Promise<{
92
+ id: string;
93
+ title: string;
94
+ source_type: SourceType;
95
+ content_type: ContentType;
96
+ projects: string[];
97
+ tags: string[];
98
+ created_at: string;
99
+ summary: string;
100
+ themes: Theme[];
101
+ quotes: Quote[];
102
+ source_url?: string;
103
+ source_name?: string;
104
+ } | null>;
105
+ export declare function deleteSource(_dbPath: string, sourceId: string): Promise<{
106
+ deleted: boolean;
107
+ contentHash?: string;
108
+ sourcePath?: string;
109
+ }>;
110
+ /**
111
+ * Update a source's projects array
112
+ */
113
+ export declare function updateSourceProjects(_dbPath: string, sourceId: string, projects: string[]): Promise<boolean>;
114
+ /**
115
+ * Update a source's title
116
+ */
117
+ export declare function updateSourceTitle(_dbPath: string, sourceId: string, title: string): Promise<boolean>;
118
+ /**
119
+ * Update a source's content type
120
+ */
121
+ export declare function updateSourceContentType(_dbPath: string, sourceId: string, contentType: string): Promise<boolean>;
122
+ export declare function getThemeStats(_dbPath: string, project?: string): Promise<Map<string, {
123
+ source_count: number;
124
+ quote_count: number;
125
+ }>>;
126
+ export declare function getProjectStats(_dbPath: string): Promise<Array<{
127
+ project: string;
128
+ source_count: number;
129
+ quote_count: number;
130
+ latest_activity: string;
131
+ }>>;