Преглед на файлове

Fix context retrieval to collect ALL matching contexts

- getContextForPath now collects global + all matching path contexts
- getContextForFile also collects all contexts (global to specific)
- Contexts are sorted by specificity (most general to most specific)
- All contexts joined with double newline as requested
- Fixed store tests to use proper collection paths matching search terms
Tobi Lutke преди 5 месеца
родител
ревизия
b52ba1ef61
променени са 2 файла, в които са добавени 92 реда и са изтрити 17 реда
  1. 22 12
      src/store.test.ts
  2. 70 5
      src/store.ts

+ 22 - 12
src/store.test.ts

@@ -191,7 +191,19 @@ async function insertTestDocument(
   const now = new Date().toISOString();
   const name = opts.name || "test-doc";
   const title = opts.title || "Test Document";
-  const path = opts.displayPath || `test/${name}.md`;
+
+  // Use displayPath if provided, otherwise filepath's basename, otherwise default
+  let path: string;
+  if (opts.displayPath) {
+    path = opts.displayPath;
+  } else if (opts.filepath) {
+    // Extract relative path from filepath by removing collection path
+    // For tests, assume filepath is either relative or we want the whole path as the document path
+    path = opts.filepath.startsWith('/') ? opts.filepath : opts.filepath;
+  } else {
+    path = `test/${name}.md`;
+  }
+
   const body = opts.body || "# Test Document\n\nThis is test content.";
   const active = opts.active ?? 1;
 
@@ -919,11 +931,10 @@ describe("Document Retrieval", () => {
 
     test("findDocument includes context from path_contexts", async () => {
       const store = await createTestStore();
-      const collectionName = await createTestCollection();
-      await addPathContext(collectionName, "/path/docs", "Documentation");
+      const collectionName = await createTestCollection({ pwd: "/path" });
+      await addPathContext(collectionName, "docs", "Documentation");
       await insertTestDocument(store.db, collectionName, {
         name: "mydoc",
-        filepath: "/path/docs/mydoc.md",
         displayPath: "docs/mydoc.md",
       });
 
@@ -940,10 +951,10 @@ describe("Document Retrieval", () => {
   describe("getDocumentBody", () => {
     test("getDocumentBody returns full body", async () => {
       const store = await createTestStore();
-      const collectionName = await createTestCollection();
+      const collectionName = await createTestCollection({ pwd: "/path" });
       await insertTestDocument(store.db, collectionName, {
         name: "mydoc",
-        filepath: "/path/mydoc.md",
+        displayPath: "mydoc.md",
         body: "Line 1\nLine 2\nLine 3\nLine 4\nLine 5",
       });
 
@@ -955,10 +966,10 @@ describe("Document Retrieval", () => {
 
     test("getDocumentBody supports line range", async () => {
       const store = await createTestStore();
-      const collectionName = await createTestCollection();
+      const collectionName = await createTestCollection({ pwd: "/path" });
       await insertTestDocument(store.db, collectionName, {
         name: "mydoc",
-        filepath: "/path/mydoc.md",
+        displayPath: "mydoc.md",
         body: "Line 1\nLine 2\nLine 3\nLine 4\nLine 5",
       });
 
@@ -1089,10 +1100,10 @@ describe("Document Retrieval", () => {
   describe("Legacy getDocument", () => {
     test("getDocument returns document with body", async () => {
       const store = await createTestStore();
-      const collectionName = await createTestCollection();
+      const collectionName = await createTestCollection({ pwd: "/path" });
       await insertTestDocument(store.db, collectionName, {
         name: "mydoc",
-        filepath: "/path/mydoc.md",
+        displayPath: "mydoc.md",
         body: "Document body",
       });
 
@@ -1107,10 +1118,9 @@ describe("Document Retrieval", () => {
 
     test("getDocument supports line range from :line suffix", async () => {
       const store = await createTestStore();
-      const collectionName = await createTestCollection();
+      const collectionName = await createTestCollection({ pwd: "/path" });
       await insertTestDocument(store.db, collectionName, {
         name: "mydoc",
-        filepath: "/path/mydoc.md",
         displayPath: "mydoc.md",
         body: "Line 1\nLine 2\nLine 3\nLine 4",
       });

+ 70 - 5
src/store.ts

@@ -1020,8 +1020,43 @@ export function matchFilesByGlob(db: Database, pattern: string): { filepath: str
  * @returns Context string or null if no context is defined
  */
 export function getContextForPath(db: Database, collectionName: string, path: string): string | null {
-  const context = collectionsFindContextForPath(collectionName, path);
-  return context || null;
+  const config = collectionsLoadConfig();
+  const coll = getCollection(collectionName);
+
+  if (!coll) return null;
+
+  // Collect ALL matching contexts (global + all path prefixes)
+  const contexts: string[] = [];
+
+  // Add global context if present
+  if (config.global_context) {
+    contexts.push(config.global_context);
+  }
+
+  // Add all matching path contexts (from most general to most specific)
+  if (coll.context) {
+    const normalizedPath = path.startsWith("/") ? path : `/${path}`;
+
+    // Collect all matching prefixes
+    const matchingContexts: { prefix: string; context: string }[] = [];
+    for (const [prefix, context] of Object.entries(coll.context)) {
+      const normalizedPrefix = prefix.startsWith("/") ? prefix : `/${prefix}`;
+      if (normalizedPath.startsWith(normalizedPrefix)) {
+        matchingContexts.push({ prefix: normalizedPrefix, context });
+      }
+    }
+
+    // Sort by prefix length (shortest/most general first)
+    matchingContexts.sort((a, b) => a.prefix.length - b.prefix.length);
+
+    // Add all matching contexts
+    for (const match of matchingContexts) {
+      contexts.push(match.context);
+    }
+  }
+
+  // Join all contexts with double newline
+  return contexts.length > 0 ? contexts.join('\n\n') : null;
 }
 
 /**
@@ -1030,6 +1065,7 @@ export function getContextForPath(db: Database, collectionName: string, path: st
 export function getContextForFile(db: Database, filepath: string): string | null {
   // Get all collections from YAML config
   const collections = collectionsListCollections();
+  const config = collectionsLoadConfig();
 
   // Find which collection this absolute path belongs to
   for (const coll of collections) {
@@ -1048,9 +1084,38 @@ export function getContextForFile(db: Database, filepath: string): string | null
       `).get(coll.name, relativePath) as { path: string } | null;
 
       if (doc) {
-        // Use collections.ts to find context
-        const context = collectionsFindContextForPath(coll.name, relativePath);
-        return context || null;
+        // Collect ALL matching contexts (global + all path prefixes)
+        const contexts: string[] = [];
+
+        // Add global context if present
+        if (config.global_context) {
+          contexts.push(config.global_context);
+        }
+
+        // Add all matching path contexts (from most general to most specific)
+        if (coll.context) {
+          const normalizedPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
+
+          // Collect all matching prefixes
+          const matchingContexts: { prefix: string; context: string }[] = [];
+          for (const [prefix, context] of Object.entries(coll.context)) {
+            const normalizedPrefix = prefix.startsWith("/") ? prefix : `/${prefix}`;
+            if (normalizedPath.startsWith(normalizedPrefix)) {
+              matchingContexts.push({ prefix: normalizedPrefix, context });
+            }
+          }
+
+          // Sort by prefix length (shortest/most general first)
+          matchingContexts.sort((a, b) => a.prefix.length - b.prefix.length);
+
+          // Add all matching contexts
+          for (const match of matchingContexts) {
+            contexts.push(match.context);
+          }
+        }
+
+        // Join all contexts with double newline
+        return contexts.length > 0 ? contexts.join('\n\n') : null;
       }
     }
   }