@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/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 "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";
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 = "journal" | "person" | "project";
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, "vectors");
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("[Indexer] Creating new index...");
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("[Indexer] Index is empty");
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(".jsonl"));
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), "utf-8");
187
- const lines = content.trim().split("\n").filter(Boolean);
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: "journal",
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: "people" | "projects",
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(".md"));
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), "utf-8");
228
- const filename = file.replace(".md", "");
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: "preamble",
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("\n")[0];
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("[Indexer] Starting full index rebuild...");
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("[Indexer] Parsing journal...");
279
+ console.log('[Indexer] Parsing journal...');
280
280
  allItems.push(...parseJournalForIndexing());
281
281
 
282
282
  // 2. Index people
283
- console.log("[Indexer] Parsing people...");
284
- allItems.push(...parseEntitiesForIndexing("people", "person"));
283
+ console.log('[Indexer] Parsing people...');
284
+ allItems.push(...parseEntitiesForIndexing('people', 'person'));
285
285
 
286
286
  // 3. Index projects
287
- console.log("[Indexer] Parsing projects...");
288
- allItems.push(...parseEntitiesForIndexing("projects", "project"));
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: "journal",
310
+ type: 'journal',
311
311
  content: `[${entry.topic}] ${entry.content}`,
312
- source: "journal",
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, ".md");
332
+ const filename = basename(filePath, '.md');
333
333
 
334
334
  // Determine type from path
335
335
  let type: MemoryItemType;
336
- if (filePath.includes("/people/")) {
337
- type = "person";
338
- } else if (filePath.includes("/projects/")) {
339
- type = "project";
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, "utf-8");
346
+ const content = readFileSync(filePath, 'utf-8');
347
347
  const items: MemoryItem[] = [];
348
- const subdir = type === "person" ? "people" : "projects";
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: "preamble",
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("\n")[0];
367
+ const firstLine = section.split('\n')[0];
368
368
  const sectionTitle = firstLine.trim();
369
369
  const sectionContent = section.slice(firstLine.length).trim();
370
370