Sfoglia il codice sorgente

Enhance qmd status to display contexts for each collection

- Lists all path contexts under their respective collections
- Shows path prefix and context description
- Truncates long context descriptions (>60 chars) for readability
- Clean, indented display format matching existing status style

Fixes qmd-0ic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Tobi Lutke 5 mesi fa
parent
commit
77dc275d06
2 ha cambiato i file con 92 aggiunte e 14 eliminazioni
  1. 2 2
      .beads/issues.jsonl
  2. 90 12
      src/qmd.ts

+ 2 - 2
.beads/issues.jsonl

@@ -17,9 +17,9 @@
 {"id":"qmd-kf8","title":"Move document indexing DB operations to store.ts","description":"Move INSERT/UPDATE/DELETE operations for documents and content tables from indexFiles() to store.ts. Create methods like insertDocument(), updateDocument(), deactivateDocuments(), etc.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T16:36:14.558702-05:00","updated_at":"2025-12-12T16:45:38.830978-05:00","closed_at":"2025-12-12T16:45:38.830978-05:00","dependencies":[{"issue_id":"qmd-kf8","depends_on_id":"qmd-29c","type":"parent-child","created_at":"2025-12-12T16:37:02.770251-05:00","created_by":"daemon"}]}
 {"id":"qmd-ltg","title":"look for missing context","description":"i ran qmd context list and thats only one bit of context, i had a lot more. i think the path matching isn't quite working right","status":"in_progress","priority":2,"issue_type":"task","created_at":"2025-12-12T16:42:57.324769-05:00","updated_at":"2025-12-12T17:08:43.356423-05:00"}
 {"id":"qmd-p1h","title":"Create collection add|remove","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T10:57:00.717864-05:00","updated_at":"2025-12-12T16:12:00.557003-05:00","closed_at":"2025-12-12T16:12:00.557003-05:00"}
-{"id":"qmd-rck","title":"move the source files to src/*, clean up teh directory","description":"","status":"in_progress","priority":2,"issue_type":"task","created_at":"2025-12-12T16:40:19.198119-05:00","updated_at":"2025-12-12T17:09:03.549734-05:00"}
+{"id":"qmd-rck","title":"move the source files to src/*, clean up teh directory","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T16:40:19.198119-05:00","updated_at":"2025-12-12T17:12:22.502746-05:00","closed_at":"2025-12-12T17:12:22.502746-05:00"}
 {"id":"qmd-rhd","title":"Fix 'qmd status' output for new schema","description":"Update status to show collections by name, cleaner context display, virtual path examples.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:54.020596-05:00","updated_at":"2025-12-12T16:13:28.08389-05:00","closed_at":"2025-12-12T16:13:28.08389-05:00","dependencies":[{"issue_id":"qmd-rhd","depends_on_id":"qmd-ama","type":"discovered-from","created_at":"2025-12-12T15:29:54.021095-05:00","created_by":"daemon"}]}
 {"id":"qmd-s1y","title":"Update 'qmd add-context' for collection scoping","description":"Update add-context to work with collection-scoped contexts using new path_contexts schema.","notes":"Refactoring to:\n- qmd context add [path] \"text\" (defaults to current collection if in one)\n- qmd context list\n- qmd context rm \u003cpath\u003e\n- Support \"/\" for global/system context\n- Auto-detect collection from pwd","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:54.076582-05:00","updated_at":"2025-12-12T15:37:47.683263-05:00","closed_at":"2025-12-12T15:37:47.683263-05:00"}
 {"id":"qmd-vro","title":"Update 'qmd get' to support virtual paths","description":"Allow qmd get to accept both virtual paths (qmd://journals/...) and filesystem paths, plus fuzzy matching by filename.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-12T15:29:53.963113-05:00","updated_at":"2025-12-12T15:47:29.178955-05:00","closed_at":"2025-12-12T15:47:29.178955-05:00","dependencies":[{"issue_id":"qmd-vro","depends_on_id":"qmd-ama","type":"discovered-from","created_at":"2025-12-12T15:29:53.963641-05:00","created_by":"daemon"}]}
 {"id":"qmd-x19","title":"Update 'qmd add-context' for collection-scoped contexts","description":"Update add-context to work with collections:\n- qmd add-context \u003ccollection\u003e/\u003cpath\u003e \"context description\"\n- Support both virtual and filesystem paths\n- Update to use new path_contexts schema","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:38.142575-05:00","updated_at":"2025-12-12T15:53:00.525001-05:00","closed_at":"2025-12-12T15:53:00.525001-05:00"}
-{"id":"qmd-x64","title":"for each collection, on update, check if there is a .git directory, if so write out the git status, add --pull as a qmd update --pull parameter which also executes git pull before reindexing\n","description":"","status":"in_progress","priority":2,"issue_type":"task","created_at":"2025-12-12T17:04:15.994054-05:00","updated_at":"2025-12-12T17:08:39.825722-05:00"}
+{"id":"qmd-x64","title":"for each collection, on update, check if there is a .git directory, if so write out the git status, add --pull as a qmd update --pull parameter which also executes git pull before reindexing\n","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T17:04:15.994054-05:00","updated_at":"2025-12-12T17:14:40.107181-05:00","closed_at":"2025-12-12T17:14:40.107181-05:00"}

+ 90 - 12
src/qmd.ts

@@ -468,26 +468,44 @@ function showStatus(): void {
     console.log(`  Updated:  ${formatTimeAgo(lastUpdate)}`);
   }
 
-  // Get context counts per collection
-  const contextCounts = db.prepare(`
-    SELECT collection_id, COUNT(*) as count
-    FROM path_contexts
-    GROUP BY collection_id
-  `).all() as { collection_id: number; count: number }[];
-  const contextCountMap = new Map(contextCounts.map(c => [c.collection_id, c.count]));
+  // Get all contexts grouped by collection
+  const allContexts = listPathContexts(db);
+  const contextsByCollection = new Map<number, { path_prefix: string; context: string }[]>();
+
+  for (const ctx of allContexts) {
+    // Find collection by name
+    const collection = collections.find(col => col.name === ctx.collection_name);
+    if (collection) {
+      if (!contextsByCollection.has(collection.id)) {
+        contextsByCollection.set(collection.id, []);
+      }
+      contextsByCollection.get(collection.id)!.push({
+        path_prefix: ctx.path_prefix,
+        context: ctx.context
+      });
+    }
+  }
 
   if (collections.length > 0) {
     console.log(`\n${c.bold}Collections${c.reset}`);
     for (const col of collections) {
       const lastMod = col.last_modified ? formatTimeAgo(new Date(col.last_modified)) : "never";
-      const contextCount = contextCountMap.get(col.id) || 0;
+      const contexts = contextsByCollection.get(col.id) || [];
 
       console.log(`  ${c.cyan}${col.name}${c.reset} ${c.dim}(qmd://${col.name}/)${c.reset}`);
       console.log(`    ${c.dim}Path:${c.reset}     ${col.pwd}`);
       console.log(`    ${c.dim}Pattern:${c.reset}  ${col.glob_pattern}`);
       console.log(`    ${c.dim}Files:${c.reset}    ${col.active_count} (updated ${lastMod})`);
-      if (contextCount > 0) {
-        console.log(`    ${c.dim}Contexts:${c.reset} ${contextCount}`);
+
+      if (contexts.length > 0) {
+        console.log(`    ${c.dim}Contexts:${c.reset} ${contexts.length}`);
+        for (const ctx of contexts) {
+          const pathDisplay = ctx.path_prefix === '' ? '/' : `/${ctx.path_prefix}`;
+          const contextPreview = ctx.context.length > 60
+            ? ctx.context.substring(0, 57) + '...'
+            : ctx.context;
+          console.log(`      ${c.dim}${pathDisplay}:${c.reset} ${contextPreview}`);
+        }
       }
     }
 
@@ -784,6 +802,64 @@ function contextRemove(pathArg: string): void {
   closeDb();
 }
 
+function contextCheck(): void {
+  const db = getDb();
+
+  // Get collections without any context
+  const collectionsWithoutContext = getCollectionsWithoutContext(db);
+
+  // Get all collections to check for missing path contexts
+  const allCollections = listCollections(db);
+
+  if (collectionsWithoutContext.length === 0 && allCollections.length > 0) {
+    // Check if all collections have contexts
+    console.log(`\n${c.green}✓${c.reset} ${c.bold}All collections have context configured${c.reset}\n`);
+  }
+
+  if (collectionsWithoutContext.length > 0) {
+    console.log(`\n${c.yellow}Collections without any context:${c.reset}\n`);
+
+    for (const coll of collectionsWithoutContext) {
+      console.log(`${c.cyan}${coll.name}${c.reset}`);
+      console.log(`  ${c.dim}Path: ${coll.pwd}${c.reset}`);
+      console.log(`  ${c.dim}Documents: ${coll.doc_count}${c.reset}`);
+      console.log(`  ${c.dim}Suggestion: qmd context add qmd://${coll.name}/ "Description of ${coll.name}"${c.reset}\n`);
+    }
+  }
+
+  // Check for top-level paths without context within collections that DO have context
+  const collectionsWithContext = allCollections.filter(c =>
+    !collectionsWithoutContext.some(cwc => cwc.id === c.id)
+  );
+
+  let hasPathSuggestions = false;
+
+  for (const coll of collectionsWithContext) {
+    const missingPaths = getTopLevelPathsWithoutContext(db, coll.id);
+
+    if (missingPaths.length > 0) {
+      if (!hasPathSuggestions) {
+        console.log(`${c.yellow}Top-level directories without context:${c.reset}\n`);
+        hasPathSuggestions = true;
+      }
+
+      console.log(`${c.cyan}${coll.name}${c.reset}`);
+      for (const path of missingPaths) {
+        console.log(`  ${path}`);
+        console.log(`    ${c.dim}Suggestion: qmd context add qmd://${coll.name}/${path} "Description of ${path}"${c.reset}`);
+      }
+      console.log('');
+    }
+  }
+
+  if (collectionsWithoutContext.length === 0 && !hasPathSuggestions) {
+    console.log(`${c.dim}All collections and major paths have context configured.${c.reset}`);
+    console.log(`${c.dim}Use 'qmd context list' to see all configured contexts.${c.reset}\n`);
+  }
+
+  closeDb();
+}
+
 function getDocument(filename: string, fromLine?: number, maxLines?: number): void {
   const db = getDb();
 
@@ -2252,6 +2328,8 @@ function parseCLI() {
       mask: { type: "string" },  // glob pattern
       // Embed options
       force: { type: "boolean", short: "f" },
+      // Update options
+      pull: { type: "boolean" },  // git pull before update
       // Get options
       l: { type: "string" },  // max lines
       from: { type: "string" },  // start line
@@ -2310,7 +2388,7 @@ function showHelp(): void {
   console.log("  qmd get <file>[:line] [-l N] [--from N]  - Get document (optionally from line, max N lines)");
   console.log("  qmd multi-get <pattern> [-l N] [--max-bytes N]  - Get multiple docs by glob or comma-separated list");
   console.log("  qmd status                    - Show index status and collections");
-  console.log("  qmd update                    - Re-index all collections");
+  console.log("  qmd update [--pull]           - Re-index all collections (--pull: git pull first)");
   console.log("  qmd embed [-f]                - Create vector embeddings (chunks ~6KB each)");
   console.log("  qmd cleanup                   - Remove cache and orphaned data, vacuum DB");
   console.log("  qmd search <query>            - Full-text search (BM25)");
@@ -2532,7 +2610,7 @@ switch (cli.command) {
     break;
 
   case "update":
-    await updateCollections();
+    await updateCollections(cli.values.pull || false);
     break;
 
   case "embed":