@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,140 @@
1
+ /**
2
+ * Lore - Sync Configuration
3
+ *
4
+ * Loads and validates sync-sources.json from ~/.config/lore/sync-sources.json
5
+ * This config is machine-specific (NOT in lore-data).
6
+ */
7
+ import { readFile, writeFile, mkdir } from 'fs/promises';
8
+ import { existsSync } from 'fs';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ // ============================================================================
12
+ // Config Paths
13
+ // ============================================================================
14
+ const CONFIG_DIR = path.join(os.homedir(), '.config', 'lore');
15
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'sync-sources.json');
16
+ export function getConfigPath() {
17
+ return CONFIG_FILE;
18
+ }
19
+ // ============================================================================
20
+ // Path Expansion
21
+ // ============================================================================
22
+ export function expandPath(p) {
23
+ if (p.startsWith('~')) {
24
+ return path.join(os.homedir(), p.slice(1));
25
+ }
26
+ return p;
27
+ }
28
+ // ============================================================================
29
+ // Default Config
30
+ // ============================================================================
31
+ function getDefaultConfig() {
32
+ return {
33
+ version: 1,
34
+ sources: [
35
+ {
36
+ name: 'Example Source',
37
+ path: '~/Documents/notes',
38
+ glob: '**/*.md',
39
+ project: 'notes',
40
+ enabled: false,
41
+ },
42
+ ],
43
+ };
44
+ }
45
+ // ============================================================================
46
+ // Config Loading
47
+ // ============================================================================
48
+ export async function loadSyncConfig() {
49
+ if (!existsSync(CONFIG_FILE)) {
50
+ return getDefaultConfig();
51
+ }
52
+ try {
53
+ const content = await readFile(CONFIG_FILE, 'utf-8');
54
+ const config = JSON.parse(content);
55
+ // Validate version
56
+ if (config.version !== 1) {
57
+ console.warn(`[sync-config] Unknown config version: ${config.version}, expected 1`);
58
+ }
59
+ // Validate sources
60
+ if (!Array.isArray(config.sources)) {
61
+ throw new Error('Invalid config: sources must be an array');
62
+ }
63
+ for (const source of config.sources) {
64
+ if (!source.name || typeof source.name !== 'string') {
65
+ throw new Error(`Invalid source: missing or invalid 'name'`);
66
+ }
67
+ if (!source.path || typeof source.path !== 'string') {
68
+ throw new Error(`Invalid source "${source.name}": missing or invalid 'path'`);
69
+ }
70
+ if (!source.glob || typeof source.glob !== 'string') {
71
+ throw new Error(`Invalid source "${source.name}": missing or invalid 'glob'`);
72
+ }
73
+ if (!source.project || typeof source.project !== 'string') {
74
+ throw new Error(`Invalid source "${source.name}": missing or invalid 'project'`);
75
+ }
76
+ if (typeof source.enabled !== 'boolean') {
77
+ source.enabled = true; // Default to enabled
78
+ }
79
+ }
80
+ return config;
81
+ }
82
+ catch (error) {
83
+ if (error.code === 'ENOENT') {
84
+ return getDefaultConfig();
85
+ }
86
+ throw error;
87
+ }
88
+ }
89
+ export async function saveSyncConfig(config) {
90
+ await mkdir(CONFIG_DIR, { recursive: true });
91
+ await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
92
+ }
93
+ export async function initializeSyncConfig() {
94
+ if (existsSync(CONFIG_FILE)) {
95
+ return loadSyncConfig();
96
+ }
97
+ const config = getDefaultConfig();
98
+ await saveSyncConfig(config);
99
+ return config;
100
+ }
101
+ // ============================================================================
102
+ // Config Manipulation
103
+ // ============================================================================
104
+ export async function addSyncSource(source) {
105
+ const config = await loadSyncConfig();
106
+ // Check for duplicate names
107
+ const existingIndex = config.sources.findIndex(s => s.name === source.name);
108
+ if (existingIndex !== -1) {
109
+ throw new Error(`Source with name "${source.name}" already exists`);
110
+ }
111
+ config.sources.push(source);
112
+ await saveSyncConfig(config);
113
+ return config;
114
+ }
115
+ export async function updateSyncSource(name, updates) {
116
+ const config = await loadSyncConfig();
117
+ const sourceIndex = config.sources.findIndex(s => s.name === name);
118
+ if (sourceIndex === -1) {
119
+ throw new Error(`Source "${name}" not found`);
120
+ }
121
+ config.sources[sourceIndex] = {
122
+ ...config.sources[sourceIndex],
123
+ ...updates,
124
+ };
125
+ await saveSyncConfig(config);
126
+ return config;
127
+ }
128
+ export async function removeSyncSource(name) {
129
+ const config = await loadSyncConfig();
130
+ const sourceIndex = config.sources.findIndex(s => s.name === name);
131
+ if (sourceIndex === -1) {
132
+ throw new Error(`Source "${name}" not found`);
133
+ }
134
+ config.sources.splice(sourceIndex, 1);
135
+ await saveSyncConfig(config);
136
+ return config;
137
+ }
138
+ export function getEnabledSources(config) {
139
+ return config.sources.filter(s => s.enabled);
140
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Lore - File Discovery (Phase 1)
3
+ *
4
+ * Discovers files from configured sources, computes content hashes,
5
+ * and checks against Supabase for deduplication.
6
+ *
7
+ * NO LLM calls in this phase - it's essentially free to run.
8
+ */
9
+ import type { SyncSource } from './config.js';
10
+ export interface DiscoveredFile {
11
+ absolutePath: string;
12
+ relativePath: string;
13
+ contentHash: string;
14
+ size: number;
15
+ modifiedAt: Date;
16
+ sourceName: string;
17
+ project: string;
18
+ existingId?: string;
19
+ }
20
+ export interface DiscoveryResult {
21
+ source: SyncSource;
22
+ totalFiles: number;
23
+ newFiles: DiscoveredFile[];
24
+ editedFiles: DiscoveredFile[];
25
+ existingFiles: number;
26
+ errors: string[];
27
+ }
28
+ export declare function computeFileHash(filePath: string): Promise<string>;
29
+ /**
30
+ * Simple glob pattern matching for common patterns:
31
+ * - "**\/*.md" - any .md file in any subdirectory
32
+ * - "*.md" - .md files in root only
33
+ * - "**\/*.{md,pdf}" - multiple extensions
34
+ */
35
+ export declare function matchesGlob(relativePath: string, glob: string): boolean;
36
+ export declare function checkExistingHashes(hashes: string[]): Promise<Set<string>>;
37
+ export declare function discoverSource(source: SyncSource, options?: {
38
+ onProgress?: (found: number, checked: number) => void;
39
+ }): Promise<DiscoveryResult>;
40
+ export declare function discoverAllSources(sources: SyncSource[], options?: {
41
+ onSourceStart?: (source: SyncSource) => void;
42
+ onSourceComplete?: (result: DiscoveryResult) => void;
43
+ }): Promise<DiscoveryResult[]>;
44
+ export declare function summarizeDiscovery(results: DiscoveryResult[]): {
45
+ totalSources: number;
46
+ totalFiles: number;
47
+ newFiles: number;
48
+ editedFiles: number;
49
+ existingFiles: number;
50
+ errors: number;
51
+ };
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Lore - File Discovery (Phase 1)
3
+ *
4
+ * Discovers files from configured sources, computes content hashes,
5
+ * and checks against Supabase for deduplication.
6
+ *
7
+ * NO LLM calls in this phase - it's essentially free to run.
8
+ */
9
+ import { readFile, readdir, stat } from 'fs/promises';
10
+ import { createHash } from 'crypto';
11
+ import path from 'path';
12
+ import { existsSync } from 'fs';
13
+ import { expandPath } from './config.js';
14
+ import { getSourcePathMappings, getExistingContentHashes } from '../core/vector-store.js';
15
+ // ============================================================================
16
+ // Hash Computation
17
+ // ============================================================================
18
+ export async function computeFileHash(filePath) {
19
+ const content = await readFile(filePath);
20
+ return createHash('sha256').update(content).digest('hex');
21
+ }
22
+ // ============================================================================
23
+ // Glob Matching
24
+ // ============================================================================
25
+ /**
26
+ * Simple glob pattern matching for common patterns:
27
+ * - "**\/*.md" - any .md file in any subdirectory
28
+ * - "*.md" - .md files in root only
29
+ * - "**\/*.{md,pdf}" - multiple extensions
30
+ */
31
+ export function matchesGlob(relativePath, glob) {
32
+ // Handle {ext1,ext2} extension lists
33
+ const extensionMatch = glob.match(/\.\{([^}]+)\}$/);
34
+ if (extensionMatch) {
35
+ const extensions = extensionMatch[1].split(',');
36
+ const baseGlob = glob.replace(/\.\{[^}]+\}$/, '');
37
+ return extensions.some(ext => matchesGlob(relativePath, `${baseGlob}.${ext}`));
38
+ }
39
+ // Convert glob to regex
40
+ // Important: Replace glob wildcards BEFORE inserting regex patterns with special chars
41
+ let pattern = glob
42
+ .replace(/\?/g, '.') // ? matches single char (do first!)
43
+ .replace(/\*\*\//g, '{{DOUBLE_STAR_SLASH}}') // Placeholder for **/
44
+ .replace(/\*\*/g, '{{DOUBLE_STAR}}') // Placeholder for ** (without trailing /)
45
+ .replace(/\*/g, '[^/]*') // * matches anything except /
46
+ .replace(/{{DOUBLE_STAR_SLASH}}/g, '(.*\\/)?') // **/ matches any path including empty
47
+ .replace(/{{DOUBLE_STAR}}/g, '.*'); // ** matches anything including /
48
+ // Anchor the pattern
49
+ const regex = new RegExp(`^${pattern}$`);
50
+ return regex.test(relativePath);
51
+ }
52
+ // ============================================================================
53
+ // File Discovery
54
+ // ============================================================================
55
+ async function discoverFilesRecursive(dir, baseDir, glob, results) {
56
+ const entries = await readdir(dir, { withFileTypes: true });
57
+ for (const entry of entries) {
58
+ const fullPath = path.join(dir, entry.name);
59
+ const relativePath = path.relative(baseDir, fullPath);
60
+ if (entry.isDirectory()) {
61
+ // Skip hidden directories and common non-content dirs
62
+ if (entry.name.startsWith('.') ||
63
+ entry.name === 'node_modules' ||
64
+ entry.name === '__pycache__') {
65
+ continue;
66
+ }
67
+ await discoverFilesRecursive(fullPath, baseDir, glob, results);
68
+ }
69
+ else if (entry.isFile()) {
70
+ // Check if file matches glob pattern
71
+ if (matchesGlob(relativePath, glob)) {
72
+ results.push({ path: fullPath, relativePath });
73
+ }
74
+ }
75
+ }
76
+ }
77
+ // ============================================================================
78
+ // Supabase Deduplication (delegates to vector-store)
79
+ // ============================================================================
80
+ export async function checkExistingHashes(hashes) {
81
+ return getExistingContentHashes('', hashes);
82
+ }
83
+ // ============================================================================
84
+ // Main Discovery Function
85
+ // ============================================================================
86
+ export async function discoverSource(source, options = {}) {
87
+ const { onProgress } = options;
88
+ const expandedPath = expandPath(source.path);
89
+ const result = {
90
+ source,
91
+ totalFiles: 0,
92
+ newFiles: [],
93
+ editedFiles: [],
94
+ existingFiles: 0,
95
+ errors: [],
96
+ };
97
+ // Check if source directory exists
98
+ if (!existsSync(expandedPath)) {
99
+ result.errors.push(`Directory not found: ${expandedPath}`);
100
+ return result;
101
+ }
102
+ // Discover all matching files
103
+ const matchingFiles = [];
104
+ try {
105
+ await discoverFilesRecursive(expandedPath, expandedPath, source.glob, matchingFiles);
106
+ }
107
+ catch (error) {
108
+ result.errors.push(`Error scanning directory: ${error}`);
109
+ return result;
110
+ }
111
+ result.totalFiles = matchingFiles.length;
112
+ if (matchingFiles.length === 0) {
113
+ return result;
114
+ }
115
+ // Compute hashes for all files
116
+ const filesWithHashes = [];
117
+ for (let i = 0; i < matchingFiles.length; i++) {
118
+ const file = matchingFiles[i];
119
+ try {
120
+ const fileStat = await stat(file.path);
121
+ const contentHash = await computeFileHash(file.path);
122
+ filesWithHashes.push({
123
+ absolutePath: file.path,
124
+ relativePath: file.relativePath,
125
+ contentHash,
126
+ size: fileStat.size,
127
+ modifiedAt: fileStat.mtime,
128
+ sourceName: source.name,
129
+ project: source.project,
130
+ });
131
+ onProgress?.(filesWithHashes.length, matchingFiles.length);
132
+ }
133
+ catch (error) {
134
+ result.errors.push(`Error processing ${file.path}: ${error}`);
135
+ }
136
+ }
137
+ // Check which hashes already exist in Supabase (unchanged files)
138
+ const allHashes = filesWithHashes.map(f => f.contentHash);
139
+ const existingHashes = await checkExistingHashes(allHashes);
140
+ // Check which paths already exist in Supabase (for edit detection)
141
+ const allPaths = filesWithHashes.map(f => f.absolutePath);
142
+ const pathMappings = await getSourcePathMappings('', allPaths);
143
+ // Categorize files: existing (unchanged), edited, or new
144
+ for (const file of filesWithHashes) {
145
+ if (existingHashes.has(file.contentHash)) {
146
+ // Content hash matches - file is unchanged
147
+ result.existingFiles++;
148
+ }
149
+ else {
150
+ // Content is different - check if path exists (edit) or not (new)
151
+ const existingSource = pathMappings.get(file.absolutePath);
152
+ if (existingSource) {
153
+ // Same path, different hash = edit
154
+ file.existingId = existingSource.id;
155
+ result.editedFiles.push(file);
156
+ }
157
+ else {
158
+ // New path = new file
159
+ result.newFiles.push(file);
160
+ }
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ export async function discoverAllSources(sources, options = {}) {
166
+ const { onSourceStart, onSourceComplete } = options;
167
+ const results = [];
168
+ for (const source of sources) {
169
+ if (!source.enabled)
170
+ continue;
171
+ onSourceStart?.(source);
172
+ const result = await discoverSource(source);
173
+ onSourceComplete?.(result);
174
+ results.push(result);
175
+ }
176
+ return results;
177
+ }
178
+ // ============================================================================
179
+ // Summary Statistics
180
+ // ============================================================================
181
+ export function summarizeDiscovery(results) {
182
+ return {
183
+ totalSources: results.length,
184
+ totalFiles: results.reduce((sum, r) => sum + r.totalFiles, 0),
185
+ newFiles: results.reduce((sum, r) => sum + r.newFiles.length, 0),
186
+ editedFiles: results.reduce((sum, r) => sum + r.editedFiles.length, 0),
187
+ existingFiles: results.reduce((sum, r) => sum + r.existingFiles, 0),
188
+ errors: results.reduce((sum, r) => sum + r.errors.length, 0),
189
+ };
190
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Lore - Universal Sync Module
3
+ *
4
+ * Two-phase sync system:
5
+ * 1. Discovery: Find files, compute hashes, check for duplicates
6
+ * 2. Processing: Claude extracts metadata, generates embeddings, stores
7
+ */
8
+ export * from './config.js';
9
+ export * from './discover.js';
10
+ export * from './processors.js';
11
+ export * from './process.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Lore - Universal Sync Module
3
+ *
4
+ * Two-phase sync system:
5
+ * 1. Discovery: Find files, compute hashes, check for duplicates
6
+ * 2. Processing: Claude extracts metadata, generates embeddings, stores
7
+ */
8
+ export * from './config.js';
9
+ export * from './discover.js';
10
+ export * from './processors.js';
11
+ export * from './process.js';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Lore - Claude Processing (Phase 2)
3
+ *
4
+ * Uses Claude to extract metadata from new files:
5
+ * - title: Descriptive title
6
+ * - summary: 2-4 sentence summary with key takeaways
7
+ * - date: ISO date if present
8
+ * - participants: List of names if present
9
+ * - content_type: interview|meeting|conversation|document|note|analysis
10
+ *
11
+ * Only called for NEW files (not already in Supabase).
12
+ */
13
+ import type { DiscoveredFile } from './discover.js';
14
+ import type { ContentType } from '../core/types.js';
15
+ import { type ImageMediaType } from './processors.js';
16
+ export interface ExtractedMetadata {
17
+ title: string;
18
+ summary: string;
19
+ date: string | null;
20
+ participants: string[];
21
+ content_type: ContentType;
22
+ }
23
+ export interface ProcessedFile {
24
+ file: DiscoveredFile;
25
+ metadata: ExtractedMetadata;
26
+ sourceId: string;
27
+ }
28
+ export interface ProcessResult {
29
+ processed: ProcessedFile[];
30
+ errors: Array<{
31
+ file: DiscoveredFile;
32
+ error: string;
33
+ }>;
34
+ }
35
+ export declare function extractMetadata(content: string, filePath: string, options?: {
36
+ model?: string;
37
+ image?: {
38
+ base64: string;
39
+ mediaType: ImageMediaType;
40
+ };
41
+ }): Promise<ExtractedMetadata>;
42
+ export declare function processFiles(files: DiscoveredFile[], dataDir: string, options?: {
43
+ onProgress?: (completed: number, total: number, title: string) => void;
44
+ model?: string;
45
+ concurrency?: number;
46
+ gitPush?: boolean;
47
+ hookContext?: {
48
+ mode: 'mcp' | 'cli';
49
+ };
50
+ }): Promise<ProcessResult>;