@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,221 @@
1
+ /**
2
+ * Local Search - Regex/pattern search in local source files
3
+ *
4
+ * Provides grep-like functionality for searching source content
5
+ * stored in the data directory. Tries ripgrep first for speed,
6
+ * falls back to native JavaScript regex.
7
+ */
8
+ import { spawn } from 'child_process';
9
+ import { readdir, readFile } from 'fs/promises';
10
+ import path from 'path';
11
+ import { existsSync } from 'fs';
12
+ /**
13
+ * Check if ripgrep is available
14
+ */
15
+ async function hasRipgrep() {
16
+ return new Promise((resolve) => {
17
+ const proc = spawn('rg', ['--version']);
18
+ proc.on('error', () => resolve(false));
19
+ proc.on('close', (code) => resolve(code === 0));
20
+ });
21
+ }
22
+ /**
23
+ * Search using ripgrep (fast)
24
+ */
25
+ async function searchWithRipgrep(sourcesDir, pattern, options) {
26
+ const { maxMatchesPerFile = 10, maxTotalResults = 100, ignoreCase = false, contextBefore = 0, contextAfter = 0, } = options;
27
+ return new Promise((resolve, reject) => {
28
+ const args = [
29
+ '--json',
30
+ '--max-count', String(maxMatchesPerFile),
31
+ '--glob', 'content.md',
32
+ ];
33
+ if (ignoreCase) {
34
+ args.push('--ignore-case');
35
+ }
36
+ if (contextBefore > 0) {
37
+ args.push('-B', String(contextBefore));
38
+ }
39
+ if (contextAfter > 0) {
40
+ args.push('-A', String(contextAfter));
41
+ }
42
+ args.push(pattern, sourcesDir);
43
+ const proc = spawn('rg', args);
44
+ let stdout = '';
45
+ let stderr = '';
46
+ proc.stdout.on('data', (data) => {
47
+ stdout += data.toString();
48
+ });
49
+ proc.stderr.on('data', (data) => {
50
+ stderr += data.toString();
51
+ });
52
+ proc.on('error', (err) => {
53
+ reject(err);
54
+ });
55
+ proc.on('close', (code) => {
56
+ // ripgrep returns 1 if no matches, 0 if matches, 2 if error
57
+ if (code === 2) {
58
+ reject(new Error(`ripgrep error: ${stderr}`));
59
+ return;
60
+ }
61
+ const results = [];
62
+ const resultMap = new Map();
63
+ // Parse JSON lines output
64
+ const lines = stdout.split('\n').filter((l) => l.trim());
65
+ for (const line of lines) {
66
+ try {
67
+ const entry = JSON.parse(line);
68
+ if (entry.type === 'match') {
69
+ const filePath = entry.data.path.text;
70
+ // Extract source_id from path (e.g., /path/sources/{source_id}/content.md)
71
+ const parts = filePath.split(path.sep);
72
+ const contentIdx = parts.findIndex((p) => p === 'content.md');
73
+ const sourceId = contentIdx > 0 ? parts[contentIdx - 1] : path.basename(path.dirname(filePath));
74
+ let result = resultMap.get(sourceId);
75
+ if (!result) {
76
+ result = {
77
+ source_id: sourceId,
78
+ file_path: filePath,
79
+ matches: [],
80
+ };
81
+ resultMap.set(sourceId, result);
82
+ }
83
+ // Process submatches
84
+ for (const submatch of entry.data.submatches || []) {
85
+ result.matches.push({
86
+ line_number: entry.data.line_number,
87
+ line_content: entry.data.lines.text.replace(/\n$/, ''),
88
+ match_start: submatch.start,
89
+ match_end: submatch.end,
90
+ });
91
+ }
92
+ }
93
+ }
94
+ catch {
95
+ // Skip invalid JSON lines
96
+ }
97
+ }
98
+ // Convert map to array and limit total results
99
+ for (const result of resultMap.values()) {
100
+ if (results.length >= maxTotalResults)
101
+ break;
102
+ results.push(result);
103
+ }
104
+ resolve(results);
105
+ });
106
+ });
107
+ }
108
+ /**
109
+ * Search using native JavaScript regex (fallback)
110
+ */
111
+ async function searchWithNative(sourcesDir, pattern, options) {
112
+ const { maxMatchesPerFile = 10, maxTotalResults = 100, ignoreCase = false, } = options;
113
+ const results = [];
114
+ // Create regex
115
+ let regex;
116
+ try {
117
+ regex = new RegExp(pattern, ignoreCase ? 'gi' : 'g');
118
+ }
119
+ catch (err) {
120
+ throw new Error(`Invalid regex pattern: ${pattern}`);
121
+ }
122
+ // Read all source directories
123
+ if (!existsSync(sourcesDir)) {
124
+ return [];
125
+ }
126
+ const entries = await readdir(sourcesDir, { withFileTypes: true });
127
+ for (const entry of entries) {
128
+ if (results.length >= maxTotalResults)
129
+ break;
130
+ if (!entry.isDirectory())
131
+ continue;
132
+ const contentPath = path.join(sourcesDir, entry.name, 'content.md');
133
+ if (!existsSync(contentPath))
134
+ continue;
135
+ try {
136
+ const content = await readFile(contentPath, 'utf-8');
137
+ const lines = content.split('\n');
138
+ const matches = [];
139
+ for (let i = 0; i < lines.length && matches.length < maxMatchesPerFile; i++) {
140
+ const line = lines[i];
141
+ regex.lastIndex = 0; // Reset regex state
142
+ let match;
143
+ while ((match = regex.exec(line)) !== null && matches.length < maxMatchesPerFile) {
144
+ matches.push({
145
+ line_number: i + 1,
146
+ line_content: line,
147
+ match_start: match.index,
148
+ match_end: match.index + match[0].length,
149
+ });
150
+ // Prevent infinite loop on zero-length matches
151
+ if (match[0].length === 0) {
152
+ regex.lastIndex++;
153
+ }
154
+ }
155
+ }
156
+ if (matches.length > 0) {
157
+ results.push({
158
+ source_id: entry.name,
159
+ file_path: contentPath,
160
+ matches,
161
+ });
162
+ }
163
+ }
164
+ catch {
165
+ // Skip files that can't be read
166
+ }
167
+ }
168
+ return results;
169
+ }
170
+ /**
171
+ * Search local source files using regex pattern
172
+ *
173
+ * @param dataDir - The lore data directory
174
+ * @param pattern - Regex pattern to search for
175
+ * @param options - Search options
176
+ * @returns Array of search results with matches
177
+ */
178
+ export async function searchLocalFiles(dataDir, pattern, options = {}) {
179
+ const sourcesDir = path.join(dataDir, 'sources');
180
+ if (!existsSync(sourcesDir)) {
181
+ return [];
182
+ }
183
+ // Try ripgrep first, fall back to native
184
+ const useRipgrep = await hasRipgrep();
185
+ if (useRipgrep) {
186
+ try {
187
+ return await searchWithRipgrep(sourcesDir, pattern, options);
188
+ }
189
+ catch {
190
+ // Fall back to native on error
191
+ return await searchWithNative(sourcesDir, pattern, options);
192
+ }
193
+ }
194
+ return await searchWithNative(sourcesDir, pattern, options);
195
+ }
196
+ /**
197
+ * Get a snippet of text around a match for display
198
+ */
199
+ export function getMatchSnippet(lineContent, matchStart, matchEnd, maxLength = 100) {
200
+ const matchText = lineContent.slice(matchStart, matchEnd);
201
+ // Calculate window around match
202
+ const halfWindow = Math.floor((maxLength - matchText.length) / 2);
203
+ let start = Math.max(0, matchStart - halfWindow);
204
+ let end = Math.min(lineContent.length, matchEnd + halfWindow);
205
+ // Adjust if we're near edges
206
+ if (start === 0) {
207
+ end = Math.min(lineContent.length, maxLength);
208
+ }
209
+ else if (end === lineContent.length) {
210
+ start = Math.max(0, lineContent.length - maxLength);
211
+ }
212
+ let snippet = lineContent.slice(start, end);
213
+ // Add ellipses
214
+ if (start > 0) {
215
+ snippet = '...' + snippet;
216
+ }
217
+ if (end < lineContent.length) {
218
+ snippet = snippet + '...';
219
+ }
220
+ return snippet;
221
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Lore - Theme Definitions
3
+ *
4
+ * Pre-defined themes for insight extraction from sources.
5
+ * Adapted from granola-extractor.
6
+ */
7
+ export interface ThemeDefinition {
8
+ id: string;
9
+ name: string;
10
+ prompt: string;
11
+ }
12
+ export declare const THEMES: ThemeDefinition[];
13
+ export declare function getThemeById(id: string): ThemeDefinition | undefined;
14
+ export declare function getThemeNames(): string[];
15
+ export declare function getThemePromptList(): string;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Lore - Theme Definitions
3
+ *
4
+ * Pre-defined themes for insight extraction from sources.
5
+ * Adapted from granola-extractor.
6
+ */
7
+ export const THEMES = [
8
+ {
9
+ id: 'pain-points',
10
+ name: 'Pain Points',
11
+ prompt: 'Problems, frustrations, difficulties, blockers, challenges, risks identified',
12
+ },
13
+ {
14
+ id: 'feature-requests',
15
+ name: 'Feature Requests',
16
+ prompt: 'Desired features, wishlist items, suggestions, improvements, capabilities needed',
17
+ },
18
+ {
19
+ id: 'positive-feedback',
20
+ name: 'Positive Feedback',
21
+ prompt: 'Strengths, what works well, advantages, praise, value delivered',
22
+ },
23
+ {
24
+ id: 'pricing',
25
+ name: 'Pricing & Value',
26
+ prompt: 'Cost, pricing, value perception, ROI, budget, willingness to pay, financial considerations',
27
+ },
28
+ {
29
+ id: 'competition',
30
+ name: 'Competition',
31
+ prompt: 'Competitors, alternatives, market comparison, competitive advantages/disadvantages',
32
+ },
33
+ {
34
+ id: 'workflow',
35
+ name: 'Workflow & Process',
36
+ prompt: 'How things work, processes, workarounds, current state, tools and methods used',
37
+ },
38
+ {
39
+ id: 'decisions',
40
+ name: 'Decisions',
41
+ prompt: 'Key decisions, conclusions, action items, next steps, agreements, choices made',
42
+ },
43
+ {
44
+ id: 'questions',
45
+ name: 'Open Questions',
46
+ prompt: 'Unanswered questions, uncertainties, things needing clarification, follow-ups',
47
+ },
48
+ {
49
+ id: 'requirements',
50
+ name: 'Requirements',
51
+ prompt: 'Must-haves, specifications, constraints, acceptance criteria, needs, dependencies',
52
+ },
53
+ {
54
+ id: 'insights',
55
+ name: 'Key Insights',
56
+ prompt: 'Important learnings, discoveries, observations, patterns, strategic insights',
57
+ },
58
+ {
59
+ id: 'data-points',
60
+ name: 'Data & Metrics',
61
+ prompt: 'Statistics, numbers, measurements, KPIs, benchmarks, quantitative findings',
62
+ },
63
+ {
64
+ id: 'opportunities',
65
+ name: 'Opportunities',
66
+ prompt: 'Market opportunities, growth areas, untapped potential, strategic openings',
67
+ },
68
+ ];
69
+ export function getThemeById(id) {
70
+ return THEMES.find((t) => t.id === id);
71
+ }
72
+ export function getThemeNames() {
73
+ return THEMES.map((t) => t.id);
74
+ }
75
+ export function getThemePromptList() {
76
+ return THEMES.map((t) => `- ${t.id}: ${t.prompt}`).join('\n');
77
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Lore - Core Types
3
+ *
4
+ * A three-layer knowledge architecture:
5
+ * 1. Source Documents - Immutable original content (interviews, transcripts, docs)
6
+ * 2. Extracted Insights - Quotes, themes, decisions with links back to sources
7
+ * 3. Working Memory - Synthesized context for agent consumption
8
+ */
9
+ export type SourceType = string;
10
+ export type SearchMode = 'semantic' | 'keyword' | 'hybrid' | 'regex';
11
+ export type ContentType = 'interview' | 'meeting' | 'conversation' | 'document' | 'note' | 'analysis' | 'survey' | 'research' | 'decision' | 'insight' | 'requirement';
12
+ export interface SourceDocument {
13
+ id: string;
14
+ source_type: SourceType;
15
+ source_id: string;
16
+ source_path?: string;
17
+ title: string;
18
+ content: string;
19
+ content_type: ContentType;
20
+ created_at: string;
21
+ imported_at: string;
22
+ participants?: string[];
23
+ projects: string[];
24
+ tags: string[];
25
+ }
26
+ export interface Citation {
27
+ source_id: string;
28
+ location?: string;
29
+ context?: string;
30
+ }
31
+ export interface Quote {
32
+ id: string;
33
+ text: string;
34
+ speaker?: 'user' | 'participant' | 'ai' | 'unknown';
35
+ speaker_name?: string;
36
+ timestamp?: string;
37
+ theme?: string;
38
+ citation: Citation;
39
+ }
40
+ export interface Theme {
41
+ name: string;
42
+ evidence: Quote[];
43
+ summary?: string;
44
+ }
45
+ export type ThemeName = 'pain-points' | 'feature-requests' | 'positive-feedback' | 'pricing' | 'competition' | 'workflow' | 'decisions' | 'requirements' | 'insights';
46
+ export interface Decision {
47
+ id: string;
48
+ decision: string;
49
+ rationale: string;
50
+ alternatives_considered?: string[];
51
+ made_at: string;
52
+ citation: Citation;
53
+ project_id: string;
54
+ }
55
+ export interface Requirement {
56
+ id: string;
57
+ description: string;
58
+ priority: 'must' | 'should' | 'could' | 'wont';
59
+ source_quotes: Quote[];
60
+ project_id: string;
61
+ }
62
+ export type ProjectStatus = 'active' | 'paused' | 'completed' | 'archived';
63
+ export interface Project {
64
+ id: string;
65
+ name: string;
66
+ description: string;
67
+ status: ProjectStatus;
68
+ created_at: string;
69
+ updated_at: string;
70
+ parent_id?: string;
71
+ source_count?: number;
72
+ quote_count?: number;
73
+ decision_count?: number;
74
+ }
75
+ export type LineageEventType = 'created' | 'decision' | 'pivot' | 'milestone' | 'insight' | 'delegation';
76
+ export interface LineageEvent {
77
+ id: string;
78
+ project_id: string;
79
+ event_type: LineageEventType;
80
+ title: string;
81
+ description: string;
82
+ timestamp: string;
83
+ source_ids: string[];
84
+ }
85
+ export interface SourceRecord {
86
+ id: string;
87
+ title: string;
88
+ source_type: SourceType;
89
+ content_type: ContentType;
90
+ projects: string;
91
+ tags: string;
92
+ created_at: string;
93
+ summary: string;
94
+ themes_json: string;
95
+ quotes_json: string;
96
+ has_full_content: boolean;
97
+ vector: number[];
98
+ source_url?: string;
99
+ source_name?: string;
100
+ }
101
+ export interface ChunkRecord {
102
+ id: string;
103
+ source_id: string;
104
+ content: string;
105
+ type: 'quote' | 'theme' | 'summary' | 'decision' | 'requirement' | 'note' | 'insight';
106
+ theme_name?: string;
107
+ speaker?: string;
108
+ timestamp?: string;
109
+ vector: number[];
110
+ }
111
+ export interface SearchResult {
112
+ source_id: string;
113
+ title: string;
114
+ source_type: SourceType;
115
+ content_type: ContentType;
116
+ projects: string[];
117
+ summary: string;
118
+ relevance_score: number;
119
+ matching_quotes: Quote[];
120
+ matching_themes: string[];
121
+ }
122
+ /**
123
+ * Extended search result with ranking information from hybrid search
124
+ */
125
+ export interface SearchResultWithRanks extends SearchResult {
126
+ /** Rank in semantic (vector) search results, null if not in semantic results */
127
+ semantic_rank?: number;
128
+ /** Rank in keyword (full-text) search results, null if not in keyword results */
129
+ keyword_rank?: number;
130
+ }
131
+ export interface ResearchPackage {
132
+ query: string;
133
+ project?: string;
134
+ generated_at: string;
135
+ summary: string;
136
+ key_findings: string[];
137
+ conflicts_resolved?: string[];
138
+ supporting_quotes: Quote[];
139
+ related_decisions: Decision[];
140
+ sources_consulted: Array<{
141
+ id: string;
142
+ title: string;
143
+ source_type: SourceType;
144
+ relevance: number;
145
+ }>;
146
+ gaps_identified?: string[];
147
+ suggested_queries?: string[];
148
+ }
149
+ export interface SearchArgs {
150
+ query: string;
151
+ project?: string;
152
+ source_type?: SourceType;
153
+ content_type?: ContentType;
154
+ limit?: number;
155
+ mode?: SearchMode;
156
+ }
157
+ export interface RetainArgs {
158
+ content: string;
159
+ project: string;
160
+ type: 'insight' | 'decision' | 'requirement' | 'note';
161
+ source_context?: string;
162
+ tags?: string[];
163
+ }
164
+ export interface ResearchArgs {
165
+ task: string;
166
+ project?: string;
167
+ depth?: 'quick' | 'thorough' | 'exhaustive';
168
+ include_sources?: boolean;
169
+ }
170
+ export interface IngestArgs {
171
+ path: string;
172
+ source_type: SourceType;
173
+ project?: string;
174
+ tags?: string[];
175
+ source_url?: string;
176
+ source_name?: string;
177
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Lore - Core Types
3
+ *
4
+ * A three-layer knowledge architecture:
5
+ * 1. Source Documents - Immutable original content (interviews, transcripts, docs)
6
+ * 2. Extracted Insights - Quotes, themes, decisions with links back to sources
7
+ * 3. Working Memory - Synthesized context for agent consumption
8
+ */
9
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Lore - User Settings (Supabase key-value store)
3
+ *
4
+ * Generic per-user settings stored in Supabase for cross-machine discovery.
5
+ * Uses the user_settings table with RLS for data isolation.
6
+ */
7
+ export declare const SETTING_DATA_REPO_URL = "data_repo_url";
8
+ /**
9
+ * Get a user setting by key. Returns null if not found.
10
+ */
11
+ export declare function getUserSetting(key: string): Promise<string | null>;
12
+ /**
13
+ * Set a user setting (upsert). Creates or updates the value for the given key.
14
+ */
15
+ export declare function setUserSetting(key: string, value: string): Promise<void>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Lore - User Settings (Supabase key-value store)
3
+ *
4
+ * Generic per-user settings stored in Supabase for cross-machine discovery.
5
+ * Uses the user_settings table with RLS for data isolation.
6
+ */
7
+ import { getSupabase } from './vector-store.js';
8
+ // ============================================================================
9
+ // Well-known setting keys
10
+ // ============================================================================
11
+ export const SETTING_DATA_REPO_URL = 'data_repo_url';
12
+ // ============================================================================
13
+ // CRUD
14
+ // ============================================================================
15
+ /**
16
+ * Get a user setting by key. Returns null if not found.
17
+ */
18
+ export async function getUserSetting(key) {
19
+ const client = await getSupabase();
20
+ const { data, error } = await client
21
+ .from('user_settings')
22
+ .select('value')
23
+ .eq('key', key)
24
+ .single();
25
+ if (error || !data) {
26
+ return null;
27
+ }
28
+ return data.value;
29
+ }
30
+ /**
31
+ * Set a user setting (upsert). Creates or updates the value for the given key.
32
+ */
33
+ export async function setUserSetting(key, value) {
34
+ const client = await getSupabase();
35
+ const { error } = await client
36
+ .from('user_settings')
37
+ .upsert({ key, value, updated_at: new Date().toISOString() }, { onConflict: 'user_id,key' });
38
+ if (error) {
39
+ console.error(`[setUserSetting] Error setting '${key}':`, error);
40
+ throw error;
41
+ }
42
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Lore - Vector Store
3
+ *
4
+ * LanceDB-based vector storage for semantic search across sources and chunks.
5
+ * Adapted from granola-extractor with expanded schema for projects and citations.
6
+ */
7
+ import * as lancedb from '@lancedb/lancedb';
8
+ import type { SourceRecord, ChunkRecord, Quote, Theme, SourceType, ContentType } from './types.js';
9
+ export declare function getDatabase(dbPath: string): Promise<lancedb.Connection>;
10
+ /**
11
+ * Reset the database connection to force a fresh read
12
+ */
13
+ export declare function resetDatabaseConnection(): void;
14
+ export declare function closeDatabase(): Promise<void>;
15
+ export declare function indexExists(dbPath: string): Promise<boolean>;
16
+ export declare function initializeTables(dbPath: string): Promise<void>;
17
+ /**
18
+ * Add a single source to the existing index (for retain operations)
19
+ */
20
+ export declare function addSource(dbPath: string, source: SourceRecord, vector: number[]): Promise<void>;
21
+ /**
22
+ * Add chunks to the existing index
23
+ */
24
+ export declare function addChunks(dbPath: string, chunks: ChunkRecord[]): Promise<void>;
25
+ export declare function storeSources(dbPath: string, sources: Array<{
26
+ source: SourceRecord;
27
+ vector: number[];
28
+ }>): Promise<void>;
29
+ export declare function storeChunks(dbPath: string, chunks: ChunkRecord[]): Promise<void>;
30
+ export declare function searchSources(dbPath: string, queryVector: number[], options?: {
31
+ limit?: number;
32
+ project?: string;
33
+ source_type?: SourceType;
34
+ content_type?: ContentType;
35
+ recency_boost?: number;
36
+ }): Promise<Array<{
37
+ id: string;
38
+ title: string;
39
+ source_type: SourceType;
40
+ content_type: ContentType;
41
+ projects: string[];
42
+ tags: string[];
43
+ created_at: string;
44
+ summary: string;
45
+ themes: Theme[];
46
+ quotes: Quote[];
47
+ score: number;
48
+ }>>;
49
+ export declare function searchChunks(dbPath: string, queryVector: number[], options?: {
50
+ limit?: number;
51
+ type?: ChunkRecord['type'];
52
+ theme_name?: string;
53
+ source_id?: string;
54
+ }): Promise<Array<{
55
+ id: string;
56
+ source_id: string;
57
+ content: string;
58
+ type: string;
59
+ theme_name: string;
60
+ speaker: string;
61
+ timestamp: string;
62
+ score: number;
63
+ }>>;
64
+ export declare function getAllSources(dbPath: string, options?: {
65
+ project?: string;
66
+ source_type?: SourceType;
67
+ limit?: number;
68
+ }): Promise<Array<{
69
+ id: string;
70
+ title: string;
71
+ source_type: SourceType;
72
+ content_type: ContentType;
73
+ projects: string[];
74
+ created_at: string;
75
+ summary: string;
76
+ }>>;
77
+ export declare function getSourceById(dbPath: string, sourceId: string): Promise<{
78
+ id: string;
79
+ title: string;
80
+ source_type: SourceType;
81
+ content_type: ContentType;
82
+ projects: string[];
83
+ tags: string[];
84
+ created_at: string;
85
+ summary: string;
86
+ themes: Theme[];
87
+ quotes: Quote[];
88
+ } | null>;
89
+ export declare function getThemeStats(dbPath: string, project?: string): Promise<Map<string, {
90
+ source_count: number;
91
+ quote_count: number;
92
+ }>>;
93
+ export declare function getProjectStats(dbPath: string): Promise<Array<{
94
+ project: string;
95
+ source_count: number;
96
+ quote_count: number;
97
+ latest_activity: string;
98
+ }>>;