Commit Graph

99 Commits

Author SHA1 Message Date
Tobi Lutke
0dfd7a4686
Fix query hang, SQL errors, and missing docid in search results
- Fix SQL syntax error when collectionId is empty string (searchFTS, searchVec)
- Add 1-second timeout to llama.dispose() to prevent indefinite hang
- Add process.exit(0) after cleanup for clean CLI exit
- Include hash/docid in search results mapping
- Update query expansion to use structured Queryable types
- Switch to Qwen3-1.7B model for better query expansion
- Improve bun discovery in qmd wrapper script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 23:24:00 -05:00
Tobi Lutke
431f6e505b
Fix qmd embed crash and resolve all TypeScript errors
- Fix ReferenceError in vectorIndex(): firstResult was used but never
  defined. Added code to embed first chunk to get embedding dimensions.

- Fix 87 TypeScript errors across codebase:
  - formatter.ts: Define MultiGetFile type locally (was missing from store.ts)
  - collections.ts: Add non-null assertion for array access
  - mcp.ts: Fix StatusResult type to match store.ts CollectionInfo,
    add list parameter to ResourceTemplate, fix undefined checks
  - qmd.ts: Fix boolean/string type coercions, undefined array access
  - llm.test.ts: Update expandQuery tests for Queryable[] return type,
    fix array access assertions
  - store.test.ts: Add non-null assertions for array access in tests
  - eval-harness.ts: Fix array access assertion
2025-12-31 13:32:30 -04:00
Tobi Lutke
c85889df12
fixes 2025-12-21 14:50:17 -04:00
Tobi Lutke
c9ac3c1463
Use default createContext() options for better VRAM management
Let node-llama-cpp handle context size and sequences automatically.
The mutex still serializes generation calls for safety.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:54:30 -04:00
Tobi Lutke
f39db3a593
Fix VRAM and sequence exhaustion issues in generation
- Reduce context sequences from 4 to 1 to minimize VRAM usage
  when multiple models (embed, generate, rerank) are loaded
- Add mutex to serialize generation calls to prevent "No sequences left"
  error when concurrent requests occur with single sequence

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:51:23 -04:00
Tobi Lutke
10c5ec016f
Simplify disposal: let llama cascade to children, remove test dispose calls
- dispose() now just calls llama.dispose() which cascades to models/contexts
  per node-llama-cpp lifecycle docs
- Remove disposeDefaultLlamaCpp calls from tests - they don't help with
  the Metal cleanup crash
- Use singleton getDefaultLlamaCpp() in llm tests for consistency

The Metal backend crash at process exit is a known llama.cpp issue:
https://github.com/ggml-org/llama.cpp/pull/17869

All tests pass - the abort happens after test completion.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:47:55 -04:00
Tobi Lutke
edc294db4f
Don't dispose llama in tests - let process exit handle cleanup
The Metal backend crash happens regardless of whether we dispose or not.
It's a known llama.cpp issue during process exit static destructor cleanup:
https://github.com/ggml-org/llama.cpp/pull/17869

All 297 tests pass - the abort happens after tests complete.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:42:38 -04:00
Tobi Lutke
e8f4dce0b7
Fix Metal backend crash by properly disposing llama resources
The Metal crash was caused by not disposing resources in the right order
at the right time. The fix:

1. Restore proper dispose() that disposes contexts → models → llama in order
2. Move disposeDefaultLlamaCpp() to global afterAll (after all tests complete)
3. Keep disposed flag to prevent double-dispose

The issue was that disposing per-suite broke tests that share llama,
and not disposing at all left orphaned Metal resources at process exit.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:38:08 -04:00
Tobi Lutke
c26e8ea3ba
Add fusion difficulty queries to test RRF's advantage
Add 6 "fusion" queries designed to test cases where neither BM25 nor
vector search alone succeeds, but combining them with RRF does:

- "how much runway before running out of money" → fundraising
- "datacenter replication sync strategy" → distributed-systems
- "splitting data for training and testing" → machine-learning
- "JSON response codes error messages" → api-design
- "video calls camera async messaging" → remote-work
- "CI/CD pipeline testing coverage" → product-launch

The fusion test verifies:
1. Hybrid achieves ≥50% Hit@3 on these multi-signal queries
2. Hybrid outperforms or matches the best individual method

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:36:04 -04:00
Tobi Lutke
4131c827de
Make LlamaCpp dispose idempotent and avoid Metal backend crash
- Add disposed flag to prevent double-dispose
- Don't explicitly dispose llama resources in dispose() - just clear refs
- Let process exit handle Metal cleanup naturally
- Remove disposeDefaultLlamaCpp call from eval tests

Note: llama.cpp Metal backend still crashes at process exit due to
ggml-metal cleanup issues. This is a known upstream issue:
https://github.com/ggml-org/llama.cpp/pull/17869

All tests pass (12/12), the abort happens after test completion.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:34:26 -04:00
Tobi Lutke
d28a89eb5c
Fix eval tests: add missing insertEmbedding params and conditional thresholds
- Pass model and embeddedAt parameters to insertEmbedding
- Convert embedding to Float32Array for sqlite-vec compatibility
- Make hybrid search thresholds conditional on vector availability
  (falls back to BM25-only thresholds when no embeddings exist)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:29:43 -04:00
Tobi Lutke
56dea7d6ce
Add vector and hybrid (RRF) search evaluation tests
Three test suites with different thresholds:
- BM25: easy≥80%, medium≥15%, hard≥15%, overall≥40%
- Vector: easy≥60%, medium≥40%, hard≥30%, overall≥50%
- Hybrid (RRF): easy≥80%, medium≥50%, hard≥35%, overall≥60%

Hybrid should outperform individual methods on semantic queries.
Vector/hybrid tests have 60-120s timeouts for embedding generation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:22:43 -04:00
Tobi Lutke
5343e0e51d
Add production mode guard to prevent tests from using global index
- Add enableProductionMode() that qmd.ts calls at startup
- getDefaultDbPath() throws in test mode unless INDEX_PATH is set
- Update store.test.ts to expect throws for default path tests
- Add eval.test.ts with 18 BM25 quality tests (easy/medium/hard)
- Tests now cannot accidentally write to ~/.cache/qmd/

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:20:32 -04:00
Tobi Lutke
945d4b4572
Add 6 synthetic evaluation documents
Topics covered:
- API design principles
- Startup fundraising memo
- Distributed systems overview
- Product launch retrospective
- Machine learning primer
- Remote work policy

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:10:35 -04:00
Tobi Lutke
7828566333
Add evaluation harness with synthetic test documents
- 6 public-style documents covering diverse topics
- 18 test queries: 6 easy, 6 medium, 6 hard
- Easy: exact keyword matches
- Medium: semantic/conceptual queries
- Hard: partial recall, indirect references
- Measures Hit@1, Hit@3, Hit@5 by difficulty
- Tests both search (BM25) and query (hybrid) modes

Run: bun test/eval-harness.ts

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:10:24 -04:00
Tobi Lutke
a0bceef36a
Add conditional query expansion based on BM25 signal strength
Skip expensive LLM query expansion when initial BM25 search has
strong signals (top result score > 0.7). This saves LLM calls and
latency for queries that already match well.

- Run initial BM25 search first
- Check if top result has strong score
- Skip expansion if signal is strong
- Reuse initial search results for retrieval

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:05:35 -04:00
Tobi Lutke
fd24df81c9
Rerank multiple chunks per document with score aggregation
Instead of reranking just 1 keyword-matched chunk per doc, now:
- Select top 3 chunks per document (by keyword score)
- Rerank all selected chunks
- Aggregate scores using top-2 average (rewards consistency)
- Use best-scoring chunk for snippet display

This improves ranking for long documents where the keyword-matched
chunk isn't always the most relevant to the query.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:04:02 -04:00
Tobi Lutke
7847631224
Fix duplicate files in query results with explicit dedup
Added safety net deduplication after reranking to prevent the same
file appearing multiple times in results. Uses Set to keep only
first (highest-scored) occurrence of each file.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 18:18:48 -04:00
Tobi Lutke
25f8d185f4
Add lazy model loading with 2-minute inactivity auto-unload
Models are now automatically unloaded after 2 minutes of inactivity
to free memory when running as MCP server. Key changes:

- Add inactivityTimeoutMs config option (default: 2 minutes)
- Add touchActivity() called after each model operation
- Add unloadModels() to free memory while keeping instance alive
- Timer uses unref() so it doesn't keep process alive
- Models reload lazily on next operation

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 18:12:19 -04:00
Tobi Lutke
4385a6a8f6
Fix HyDE prompt to generate actual content instead of meta-description
Changed "A hypothetical document excerpt that would answer" to
"Write a brief example passage that answers the query" to make the
model generate actual hypothetical answer content.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 18:08:26 -04:00
Tobi Lutke
d383b5c226
Migrate to node-llama-cpp and add structured query expansion
- Replace Ollama HTTP API with node-llama-cpp for local GGUF models
- Add structured query expansion using JSON schema grammar:
  - Generates lexical query (for BM25), vector query, and HyDE
  - Tree-style CLI output showing query types
- Fix vector search: use cosine distance instead of L2
- Format queries with embeddinggemma nomic-style prompts
- Rename ollama_cache table to llm_cache
- Add disposeDefaultLlamaCpp() for clean process exit

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 18:03:41 -04:00
Tobi Lutke
a3703c069a
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
  first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
  and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
  qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
  YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 14:45:18 -04:00
Tobi Lutke
3a9c5c921e
Add --line-numbers support to get command
The get command now supports --line-numbers flag to prefix each line
with its line number. When combined with --from, line numbers start
from the specified line.

Example:
  qmd get file.md --line-numbers
  qmd get file.md --from 10 -l 5 --line-numbers

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 14:20:45 -04:00
Tobi Lutke
7d6ecc4039
Unskip 4 previously skipped tests that now work
- searchFTS filters by collection name (collection param works with YAML-based collections)
- getStatus returns correct structure
- getStatus counts documents correctly
- getStatus reports collection info

All 278 tests now pass.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 14:17:53 -04:00
Tobi Lutke
5e60bd7085
Add docid, line-numbers, handelize, and fix displayPath format
Features:
- Add short document IDs (docid) - first 6 chars of hash - to all search outputs
- Add --line-numbers CLI option and lineNumbers param for MCP tools
- Add handelize() function for token-friendly filenames (lowercase, special chars to dash, preserves extension)
- Convert triple underscore `___` to folder separator in filenames
- Change displayPath format to include collection name (collection/path)
- Make line-numbers default for MCP search snippets

Changes:
- store.ts: Add getDocid(), findDocumentByDocid(), handelize() functions
- formatter.ts: Add docid to all formatters, addLineNumbers() helper
- qmd.ts: Add --line-numbers option, use handelize during indexing
- mcp.ts: Remove resource listing, lineNumbers default for snippets
- Update all tests to expect new displayPath format and handelize behavior
- Update CLAUDE.md with docid documentation

All 274 tests pass.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:26:39 -04:00
Tobi Lutke
49b2cef85c
Fix all remaining unit test failures and add hierarchical context test
**Test Fixes:**
- Fixed tilde expansion test to create collection with home directory path
- Fixed test expectations for displayPath vs filepath separation
- Fixed MCP test config to use isolated YAML config directory
- Fixed MCP mock to return correct logprobs format
- Fixed qmd_query test to use r.filepath instead of r.file
- Fixed CLI multi-get test to use fresh database for isolation
- Fixed multiGet function to parse filepath (virtual) instead of displayPath

**Bug Fixes:**
- Fixed multiGet to use virtual paths for parsing collection/path info
- Fixed findDocuments selectCols to separate virtual_path and display_path
- Fixed context loading in findDocuments to use virtual paths

**New Test:**
- Added hierarchical context test verifying global + collection + path contexts
  are all included and joined with double newlines

**Results:** 261 passing / 0 failing (100% pass rate)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 17:51:16 -04:00
Tobi Lutke
3d3aed0d4b
Fix MCP resource test queries for new schema
- Update all direct SQL queries in tests to use new schema
- Replace display_path column with path
- Add joins with content table to get document bodies
- Use computed virtual_path for filepath field

Test results: 249 passing / 11 failing (94.3% pass rate)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 14:32:24 -05:00
Tobi Lutke
ebbddd04aa
Fix remaining test failures and schema mismatches
- Update fuzzy matching functions to return relative paths
- Fix findDocument to properly separate displayPath and filepath
- Update MCP test schema to use content-addressable storage
- Remove deprecated getCollectionIdByName function references
- Fix MCP collection filtering to work post-search
- Update test expectations for YAML-based collections
- Fix integration test expectations for path formats

Test results: 244 passing / 16 failing (93.8% pass rate)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 14:30:51 -05:00
Tobi Lutke
a26a7f3a3c
Fix CLI tests for context and collection filter
- Update add-context test to use virtual path format (qmd://collection/)
- Fix collection filter test to provide explicit collection names with --name
- Add debug output for failing tests
2025-12-13 14:19:41 -05:00
Tobi Lutke
d32ec1991b
Fix MCP double-encoding and schema mismatches
- Update MCP queries to use new schema (path, collection instead of display_path, filepath)
- Fix resource list to construct virtual paths properly: qmd://collection/path
- Fix resource read handler to parse virtual paths and join with content table
- Prevents double-encoding issues like qmd://qmd%3A//archive/...
2025-12-13 14:16:48 -05:00
Tobi Lutke
bcd354adb9
Fix context loading in search results and populate hash field
- Update getContextForFile to parse virtual paths (qmd://collection/path)
- Add context loading in searchFTS and searchVec
- Populate hash field from database joins (not empty strings)
- Fix listPathContexts reference to use YAML-based listAllContexts
2025-12-13 14:11:57 -05:00
Tobi Lutke
998448d8cf
Fix FTS search test expectations for displayPath 2025-12-13 13:41:40 -05:00
Tobi Lutke
c3bcfdc7b8
Fix searchFTS and searchVec to use correct column names (path not display_path) 2025-12-13 13:40:20 -05:00
Tobi Lutke
6210720c08
Fix test isolation: use separate YAML config for CLI tests
- Create test config directory in beforeAll
- Pass QMD_CONFIG_DIR to spawned CLI processes
- Initialize with empty collections config
- Tests now properly isolated from user's real config

Test results improved: 193 passing (90.6%), 16 failing (down from 20)
2025-12-13 13:28:50 -05:00
Tobi Lutke
cbb7a13d98
Update test to expect all matching contexts joined
Test now expects contexts to be joined with \n\n as implemented
2025-12-13 13:17:15 -05:00
Tobi Lutke
e2b6700113
Fix missing loadConfig import in store.ts
qmd query now works properly!
2025-12-13 13:15:54 -05:00
Tobi Lutke
b848000ce4
Add defensive checks for undefined paths in context retrieval 2025-12-13 13:13:23 -05:00
Tobi Lutke
b52ba1ef61
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
2025-12-13 13:12:30 -05:00
Tobi Lutke
4687394106
Fix query command: use filepath instead of file property
- Fixed querySearch to map r.filepath instead of non-existent r.file
- Fixed vectorSearch to use r.filepath consistently
- Fixed search function to pass filepath to getContextForFile
- All search commands now work correctly with SearchResult type

qmd query now works!
2025-12-13 13:10:19 -05:00
Tobi Lutke
d1e9ca150d
Clean up legacy code and remove collections table dependencies
Removed dead code and unnecessary abstractions:
- Deleted context-ops.ts (64 lines, completely unused)
- Removed migration code from store.ts (273 lines)
- Removed legacy functions from qmd.ts (~100 lines)

Fixed all collections table references to use YAML:
- Updated getDocument() to query by collection name, not ID
- Updated multiGet() to use collection names
- Updated listFiles() to use YAML collections
- Updated collectionAdd/Remove/Rename to use YAML directly
- Fixed search functions to validate collection names via YAML
- Removed getCollectionIdByName and getCollectionByName imports
- Removed dropCollection() (obsolete with YAML)
- Removed REMOVED_searchVec dead code (~70 lines)

Simplified context management:
- contextAdd now uses yamlAddContext directly
- contextRemove now uses yamlRemoveContext and setGlobalContext
- contextList now uses listAllContexts directly
- detectCollectionFromPath now uses YAML collections

Net reduction: 445 lines of code removed
2025-12-13 12:57:06 -05:00
Tobi Lutke
5dcf2417cf
Fix findDocument absolute path matching logic
The function was incorrectly concatenating collection path with filepath
even when filepath was already absolute, resulting in paths like
'/exact/path//exact/path/mydoc.md'.

Fixed to:
- Check if filepath starts with collection path and extract relative part
- Otherwise treat filepath as relative to collection

This fixes 1 test, bringing us to 93 passing, 9 failing.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 12:32:25 -05:00
Tobi Lutke
6542e1271c
Fix FTS schema and getStatus() to use YAML collections
1. Fixed FTS table schema mismatch:
   - Updated initDb() to create FTS with filepath, title, body columns
   - Updated migration to match the same schema
   - Fixed triggers to properly populate FTS on insert/update
   - Removed legacy path_contexts index

2. Fixed getStatus() function:
   - Load collections from YAML instead of querying collections table
   - Query documents table for counts per collection
   - Changed CollectionInfo type to use 'name' instead of 'id'

3. Fixed searchFTS() collectionId parameter:
   - Removed query to collections table
   - Made collectionId parameter legacy/deprecated

These fixes resolve the FTS trigger errors during qmd update.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 12:31:13 -05:00
Tobi Lutke
86f4374ba3
Fix qmd update and update tests for YAML-based collections
This commit completes the refactoring to YAML-based collection management:

1. Fixed qmd update command:
   - Pass collection name to indexFiles()
   - Remove obsolete getOrCreateCollection() function
   - Update command now works with YAML collections

2. Updated test suite for YAML architecture:
   - Changed test helpers to use YAML config instead of DB tables
   - createTestCollection() now creates collections in YAML
   - addPathContext() now updates YAML config
   - insertTestDocument() now uses collection names
   - Added QMD_CONFIG_DIR environment variable support for test isolation

Test results:
- 92 tests passing
- 4 tests skipped (due to known bugs in store.ts)
- 10 tests failing (due to bugs in store.ts functions that need updating)

The failing tests are due to store.ts functions (findDocument, getDocumentBody,
etc.) that still need to be updated to use YAML configuration instead of
querying the non-existent collections table.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:37:04 -05:00
Tobi Lutke
0c7f65f95a
Add QMD_CONFIG_DIR environment variable for test isolation
Collections module now supports QMD_CONFIG_DIR environment variable
to override the default config directory (~/.config/qmd). This allows
tests to use isolated YAML config files without affecting the user's
actual configuration.

All CONFIG_PATH and CONFIG_DIR references now use dynamic functions
that check the environment variable.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:19:03 -05:00
Tobi Lutke
47f58c6c14
Remove legacy --pull flag and git-specific update code
Removed all git repository detection, git pull, and git status logic
from updateCollections(). Users should now use the update: key in YAML
to specify update commands (like 'git pull').

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:17:49 -05:00
Tobi Lutke
b4e60a08e5
Add optional update: command support to collections YAML
Collections can now specify an optional 'update:' key with a bash command
that will be executed during 'qmd update' before indexing files.

Features:
- Runs command in collection directory (cwd)
- Uses /usr/bin/env bash -c "..."
- Always prints stdout/stderr output
- Stops with exit code if command fails (!= 0)
- Legacy --pull flag still works for git repos without update command

Example YAML:
```yaml
collections:
  archive:
    path: /path/to/repo
    pattern: "**/*.md"
    update: git pull
```

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:16:24 -05:00
Tobi Lutke
49207c524e
Fix root context display showing // instead of /
Handle both empty string and '/' as root context in path display logic.
YAML stores root contexts as '/' but old code expected empty string.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:13:12 -05:00
Tobi Lutke
f6db87c9a5
Fix YAML parsing and context grouping in qmd status
- Fixed YAML syntax: Quote all context strings containing colons
- Fixed context grouping: Use collection names instead of IDs
- contextsByCollection now uses Map<string, ...> keyed by name
- Removed collection.id references (collections from YAML have no ID)

YAML now properly parses and contexts display correctly per collection.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 11:11:33 -05:00
Tobi Lutke
f109193e62
Drop collections and path_contexts tables from schema
- Remove collections and path_contexts table creation from initializeDatabase()
- Update all queries to work without these tables
- Remove JOINs with collections table from document retrieval functions
- Compute absolute file paths from YAML collections in application code
- Update deleteContext() to use collection names instead of IDs
- Update qmd.ts status command to use listCollections() from YAML
- Deprecate cleanupDuplicateCollections() (returns 0)

All collection and context metadata is now managed exclusively in YAML
at ~/.config/qmd/index.yml. Database contains only documents and content
(content-addressable storage).

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 10:27:01 -05:00
Tobi Lutke
20e5b2269a
Update qmd.ts commands to use YAML-based collection management
- Changed removeCollection() call to use collection name instead of ID
- Changed renameCollection() call to use oldName, newName instead of ID
- Both commands now work with YAML config via store.ts

All collection commands now fully integrated with YAML configuration.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 10:17:39 -05:00