@geoql/mdr 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/bin/detect-user.sh +0 -0
- package/bin/index-conversations.ts +2 -2
- package/bin/macrodata-daemon.ts +1 -1
- package/bin/macrodata-hook.sh +1 -1
- package/dist/bin/index-conversations.js +0 -0
- package/dist/bin/macrodata-daemon.js +0 -0
- package/dist/opencode/skills/macrodata-distill/SKILL.md +1 -1
- package/opencode/context.ts +44 -44
- package/opencode/conversations.ts +20 -20
- package/opencode/index.ts +26 -26
- package/opencode/journal.ts +24 -24
- package/opencode/logger.ts +8 -8
- package/opencode/search.ts +31 -31
- package/opencode/skills/macrodata-distill/SKILL.md +1 -1
- package/opencode/tools.ts +62 -62
- package/package.json +17 -18
- package/src/config.ts +13 -13
- package/src/conversations.ts +61 -61
- package/src/daemon.ts +71 -71
- package/src/detect-user.ts +24 -24
- package/src/embeddings.ts +25 -25
- package/src/index.ts +129 -129
- package/src/indexer.ts +36 -36
package/src/indexer.ts
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* Uses Vectra for storage and embeddings.ts for vector generation.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { LocalIndex } from
|
|
13
|
-
import { join, basename } from
|
|
14
|
-
import { readFileSync, readdirSync, existsSync, mkdirSync } from
|
|
15
|
-
import { embed, embedBatch, embedQuery, preloadModel as preloadEmbeddings } from
|
|
16
|
-
import { getIndexDir, getEntitiesDir, getJournalDir } from
|
|
12
|
+
import { LocalIndex } from 'vectra';
|
|
13
|
+
import { join, basename } from 'path';
|
|
14
|
+
import { readFileSync, readdirSync, existsSync, mkdirSync } from 'fs';
|
|
15
|
+
import { embed, embedBatch, embedQuery, preloadModel as preloadEmbeddings } from './embeddings.js';
|
|
16
|
+
import { getIndexDir, getEntitiesDir, getJournalDir } from './config.js';
|
|
17
17
|
|
|
18
18
|
// Item types for filtering
|
|
19
|
-
export type MemoryItemType =
|
|
19
|
+
export type MemoryItemType = 'journal' | 'person' | 'project';
|
|
20
20
|
|
|
21
21
|
export interface MemoryItem {
|
|
22
22
|
id: string;
|
|
@@ -46,7 +46,7 @@ let indexPath: string | null = null;
|
|
|
46
46
|
*/
|
|
47
47
|
async function getIndex(): Promise<LocalIndex> {
|
|
48
48
|
const currentIndexDir = getIndexDir();
|
|
49
|
-
const currentIndexPath = join(currentIndexDir,
|
|
49
|
+
const currentIndexPath = join(currentIndexDir, 'vectors');
|
|
50
50
|
|
|
51
51
|
// Invalidate cache if path changed
|
|
52
52
|
if (index && indexPath !== currentIndexPath) {
|
|
@@ -66,7 +66,7 @@ async function getIndex(): Promise<LocalIndex> {
|
|
|
66
66
|
|
|
67
67
|
// Create if doesn't exist
|
|
68
68
|
if (!(await index.isIndexCreated())) {
|
|
69
|
-
console.log(
|
|
69
|
+
console.log('[Indexer] Creating new index...');
|
|
70
70
|
await index.createIndex();
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -139,7 +139,7 @@ export async function searchMemory(
|
|
|
139
139
|
// Check if index has items
|
|
140
140
|
const stats = await idx.listItems();
|
|
141
141
|
if (stats.length === 0) {
|
|
142
|
-
console.log(
|
|
142
|
+
console.log('[Indexer] Index is empty');
|
|
143
143
|
return [];
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -179,19 +179,19 @@ function parseJournalForIndexing(): MemoryItem[] {
|
|
|
179
179
|
|
|
180
180
|
if (!existsSync(journalDir)) return items;
|
|
181
181
|
|
|
182
|
-
const files = readdirSync(journalDir).filter((f) => f.endsWith(
|
|
182
|
+
const files = readdirSync(journalDir).filter((f) => f.endsWith('.jsonl'));
|
|
183
183
|
|
|
184
184
|
for (const file of files) {
|
|
185
185
|
try {
|
|
186
|
-
const content = readFileSync(join(journalDir, file),
|
|
187
|
-
const lines = content.trim().split(
|
|
186
|
+
const content = readFileSync(join(journalDir, file), 'utf-8');
|
|
187
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
188
188
|
|
|
189
189
|
for (let i = 0; i < lines.length; i++) {
|
|
190
190
|
try {
|
|
191
191
|
const entry = JSON.parse(lines[i]);
|
|
192
192
|
items.push({
|
|
193
193
|
id: `journal-${file}-${i}`,
|
|
194
|
-
type:
|
|
194
|
+
type: 'journal',
|
|
195
195
|
content: `[${entry.topic}] ${entry.content}`,
|
|
196
196
|
source: file,
|
|
197
197
|
timestamp: entry.timestamp,
|
|
@@ -212,7 +212,7 @@ function parseJournalForIndexing(): MemoryItem[] {
|
|
|
212
212
|
* Parse entity files (people, projects) for indexing
|
|
213
213
|
*/
|
|
214
214
|
function parseEntitiesForIndexing(
|
|
215
|
-
subdir:
|
|
215
|
+
subdir: 'people' | 'projects',
|
|
216
216
|
type: MemoryItemType,
|
|
217
217
|
): MemoryItem[] {
|
|
218
218
|
const items: MemoryItem[] = [];
|
|
@@ -220,12 +220,12 @@ function parseEntitiesForIndexing(
|
|
|
220
220
|
|
|
221
221
|
if (!existsSync(dir)) return items;
|
|
222
222
|
|
|
223
|
-
const files = readdirSync(dir).filter((f) => f.endsWith(
|
|
223
|
+
const files = readdirSync(dir).filter((f) => f.endsWith('.md'));
|
|
224
224
|
|
|
225
225
|
for (const file of files) {
|
|
226
226
|
try {
|
|
227
|
-
const content = readFileSync(join(dir, file),
|
|
228
|
-
const filename = file.replace(
|
|
227
|
+
const content = readFileSync(join(dir, file), 'utf-8');
|
|
228
|
+
const filename = file.replace('.md', '');
|
|
229
229
|
|
|
230
230
|
// Split by ## headers for section-level indexing
|
|
231
231
|
const sections = content.split(/^## /m);
|
|
@@ -237,14 +237,14 @@ function parseEntitiesForIndexing(
|
|
|
237
237
|
type,
|
|
238
238
|
content: sections[0].trim(),
|
|
239
239
|
source: `${subdir}/${file}`,
|
|
240
|
-
section:
|
|
240
|
+
section: 'preamble',
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
// Each section
|
|
245
245
|
for (let i = 1; i < sections.length; i++) {
|
|
246
246
|
const section = sections[i];
|
|
247
|
-
const firstLine = section.split(
|
|
247
|
+
const firstLine = section.split('\n')[0];
|
|
248
248
|
const sectionTitle = firstLine.trim();
|
|
249
249
|
const sectionContent = section.slice(firstLine.length).trim();
|
|
250
250
|
|
|
@@ -270,22 +270,22 @@ function parseEntitiesForIndexing(
|
|
|
270
270
|
* Rebuild the entire index from scratch
|
|
271
271
|
*/
|
|
272
272
|
export async function rebuildIndex(): Promise<{ itemCount: number }> {
|
|
273
|
-
console.log(
|
|
273
|
+
console.log('[Indexer] Starting full index rebuild...');
|
|
274
274
|
const startTime = Date.now();
|
|
275
275
|
|
|
276
276
|
const allItems: MemoryItem[] = [];
|
|
277
277
|
|
|
278
278
|
// 1. Index journal entries
|
|
279
|
-
console.log(
|
|
279
|
+
console.log('[Indexer] Parsing journal...');
|
|
280
280
|
allItems.push(...parseJournalForIndexing());
|
|
281
281
|
|
|
282
282
|
// 2. Index people
|
|
283
|
-
console.log(
|
|
284
|
-
allItems.push(...parseEntitiesForIndexing(
|
|
283
|
+
console.log('[Indexer] Parsing people...');
|
|
284
|
+
allItems.push(...parseEntitiesForIndexing('people', 'person'));
|
|
285
285
|
|
|
286
286
|
// 3. Index projects
|
|
287
|
-
console.log(
|
|
288
|
-
allItems.push(...parseEntitiesForIndexing(
|
|
287
|
+
console.log('[Indexer] Parsing projects...');
|
|
288
|
+
allItems.push(...parseEntitiesForIndexing('projects', 'project'));
|
|
289
289
|
|
|
290
290
|
// Index all items
|
|
291
291
|
console.log(`[Indexer] Indexing ${allItems.length} items...`);
|
|
@@ -307,9 +307,9 @@ export async function indexJournalEntry(entry: {
|
|
|
307
307
|
}): Promise<void> {
|
|
308
308
|
const item: MemoryItem = {
|
|
309
309
|
id: `journal-${entry.timestamp}`,
|
|
310
|
-
type:
|
|
310
|
+
type: 'journal',
|
|
311
311
|
content: `[${entry.topic}] ${entry.content}`,
|
|
312
|
-
source:
|
|
312
|
+
source: 'journal',
|
|
313
313
|
timestamp: entry.timestamp,
|
|
314
314
|
};
|
|
315
315
|
await indexItem(item);
|
|
@@ -329,23 +329,23 @@ export async function getIndexStats(): Promise<{ itemCount: number }> {
|
|
|
329
329
|
* Called by daemon when files change
|
|
330
330
|
*/
|
|
331
331
|
export async function indexEntityFile(filePath: string): Promise<void> {
|
|
332
|
-
const filename = basename(filePath,
|
|
332
|
+
const filename = basename(filePath, '.md');
|
|
333
333
|
|
|
334
334
|
// Determine type from path
|
|
335
335
|
let type: MemoryItemType;
|
|
336
|
-
if (filePath.includes(
|
|
337
|
-
type =
|
|
338
|
-
} else if (filePath.includes(
|
|
339
|
-
type =
|
|
336
|
+
if (filePath.includes('/people/')) {
|
|
337
|
+
type = 'person';
|
|
338
|
+
} else if (filePath.includes('/projects/')) {
|
|
339
|
+
type = 'project';
|
|
340
340
|
} else {
|
|
341
341
|
console.error(`[Indexer] Unknown entity type for: ${filePath}`);
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
try {
|
|
346
|
-
const content = readFileSync(filePath,
|
|
346
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
347
347
|
const items: MemoryItem[] = [];
|
|
348
|
-
const subdir = type ===
|
|
348
|
+
const subdir = type === 'person' ? 'people' : 'projects';
|
|
349
349
|
|
|
350
350
|
// Split by ## headers for section-level indexing
|
|
351
351
|
const sections = content.split(/^## /m);
|
|
@@ -357,14 +357,14 @@ export async function indexEntityFile(filePath: string): Promise<void> {
|
|
|
357
357
|
type,
|
|
358
358
|
content: sections[0].trim(),
|
|
359
359
|
source: `${subdir}/${basename(filePath)}`,
|
|
360
|
-
section:
|
|
360
|
+
section: 'preamble',
|
|
361
361
|
});
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
// Each section
|
|
365
365
|
for (let i = 1; i < sections.length; i++) {
|
|
366
366
|
const section = sections[i];
|
|
367
|
-
const firstLine = section.split(
|
|
367
|
+
const firstLine = section.split('\n')[0];
|
|
368
368
|
const sectionTitle = firstLine.trim();
|
|
369
369
|
const sectionContent = section.slice(firstLine.length).trim();
|
|
370
370
|
|