Commit Graph

266 Commits

Author SHA1 Message Date
Haitao Pan
77024f7904 feat: add NVIDIA embedding API support and QMD remote sync 2026-06-12 07:32:43 +08:00
Haitao Pan
e3711767c6 fix: disable local qmd models by default 2026-05-23 11:04:48 +08:00
Haitao Pan
7c17c8bcce feat: default to NVIDIA embeddings 2026-05-09 16:50:04 +08:00
Haitao Pan
fbad5791e3 feat: support NVIDIA embedding API 2026-05-09 16:44:47 +08:00
Haitao Pan
49fc83ebe2 Default embeddings to external API 2026-05-07 16:19:18 +08:00
Tobias Lütke
e8de7cab02 fix(cli): make status device probe opt-in 2026-04-21 21:45:52 -04:00
Tobias Lütke
525b9970cd
Merge pull request #546 from junmo-kim/fix/handelize-preserve-case
fix: preserve original case in handelize()
2026-04-10 20:48:24 -04:00
Tobias Lütke
3295294be3
Merge pull request #532 from kuishou68/fix-qmd-uri-index-query
fix: include custom index in qmd:// links
2026-04-10 20:47:55 -04:00
Tobias Lütke
46c4dfdaac
Merge pull request #545 from kuishou68/fix-sqlite-vec-actionable-guidance
fix(store): surface actionable sqlite-vec guidance
2026-04-10 20:47:16 -04:00
Tobias Lütke
89df31142d
Merge pull request #548 from kevinburkesegment/fix-gguf-magic-error
fix: detect and explain non-GGUF model files after download
2026-04-10 20:46:59 -04:00
Tobias Lütke
b1dc848086
Merge pull request #554 from bek91/codex/harden-embedding-overflow
fix: Harden embedding overflow handling
2026-04-10 20:46:40 -04:00
max0n232
77e71d09f2 fix: add USERPROFILE fallback for Windows HOME resolution
On Windows, `HOME` is not a standard environment variable — the
equivalent is `USERPROFILE`. When MCP clients (e.g. Claude Code)
spawn the QMD server as a subprocess, they pass `USERPROFILE` but
not `HOME`. This causes QMD to fall back to `/tmp`, opening an
empty database instead of the user's actual index.

Fix: check `USERPROFILE` before falling back to `/tmp`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:20:07 +03:00
Bek
e4990e470e Harden embedding overflow handling 2026-04-10 16:02:46 -04:00
Kevin Burke
f53ee26213
fix: detect and explain non-GGUF model files after download
When a proxy or firewall intercepts HuggingFace downloads, the cached
file is an HTML page instead of a GGUF model. Previously this surfaced
as an opaque "Invalid GGUF magic" error from node-llama-cpp.

Now we validate the GGUF magic bytes right after download, detect HTML
pages specifically, delete the bad file, and show an actionable error
message with workarounds (HF_ENDPOINT mirror, manual download path).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 13:27:46 -07:00
Kim Junmo
bb5becaf81 Merge remote-tracking branch 'origin/main' into fix/handelize-preserve-case
# Conflicts:
#	CHANGELOG.md
2026-04-09 18:27:16 +09:00
kuishou68
0adbdeb337 fix(store): surface actionable sqlite-vec guidance 2026-04-09 10:13:40 +08:00
Tobias Lütke
171e9e3e65
Merge pull request #530 from kuishou68/fix-status-no-build-probe 2026-04-08 21:19:56 -04:00
Tobias Lütke
414fee520b
Merge pull request #533 from rymalia/fix/json-line-field 2026-04-08 21:19:42 -04:00
Tobias Lütke
9990ca01b4
Merge pull request #534 from erskingardner/fix-529-qmd-llama-gpu-override 2026-04-08 21:19:23 -04:00
Kim Junmo
fee576bf98 fix: migrate legacy lowercase paths on reindex
When qmd update runs against an index created before case-preservation,
documents may exist under lowercase paths (e.g. "skill.md" for a file
actually named "SKILL.md"). Add findOrMigrateLegacyDocument() that:

- Falls back to a lowercase lookup when the canonical path is not found
- Renames the document path in-place via UPDATE OR IGNORE
- Manually rebuilds the FTS entry (FTS5 INSERT OR REPLACE does not
  reliably update existing rows via triggers)
- Handles UNIQUE conflicts gracefully (returns null on conflict)

Embeddings are keyed by content hash, so the rename preserves all
existing vectors — no re-embedding required.

Both the CLI indexer and the library reindexer share the same helper,
eliminating the duplication that a previous review flagged.

Includes integration tests for: successful migration, already-lowercase
no-op, and UNIQUE conflict handling.
2026-04-09 08:25:00 +09:00
Kim Junmo
9fb9de4fd2 fix: preserve original case in handelize()
The blanket .toLowerCase() in handelize() drops filename casing,
which breaks path resolution on case-sensitive filesystems (Linux).
Files like README.md, CHANGELOG.md, and SKILL.md become unreachable
when the index stores them as readme.md, changelog.md, skill.md.

Since FTS5 already performs case-insensitive matching via the
unicode61 tokenizer, lowercasing the stored path provides no search
benefit — it only corrupts the metadata used to locate files on disk.

Remove .toLowerCase() and update all affected test expectations.
2026-04-09 07:59:22 +09:00
jungholee
9dd8a738f9 fix(mcp): call enableProductionMode before getDefaultDbPath
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 19:55:07 +09:00
Ryan Malia
17074eafa1 fix: include line in CLI --json search output
but that function has no callers — the CLI's outputResults() uses its
own inline JSON formatting that destructured only .snippet from
extractSnippet(), discarding .line. Extract the full SnippetResult
and spread the line field into the JSON output object.

Closes #505
2026-04-07 11:53:09 -07:00
Jeff Gardner
1ecb5c9f96
Fix QMD_LLAMA_GPU backend override handling 2026-04-07 18:49:22 +02:00
cocoon
8404cc3bb1 fix(uri): include index in custom qmd links 2026-04-07 23:26:19 +08:00
cocoon
26e3d0c077 fix(status): avoid build attempts during device probe 2026-04-07 23:18:58 +08:00
Tobi Lutke
66e70c028e
fix(test): reset _productionMode in getDefaultDbPath test
Bun runs all test files in a single process, so module-level state
leaks between files. The getDefaultDbPath test now resets the
_productionMode flag before asserting it throws, fixing the flaky
failure on Bun (ubuntu-latest) in CI.
2026-04-05 18:39:51 -04:00
Tobias Lütke
7b3cb550fe fix(cli): resolve strict TS build errors from #470/#502/#508
- Cast loadConfig() through unknown for editor_uri template lookup
- Type cli.opts.json access and handle string[] collection in bench
2026-04-05 18:26:21 -04:00
JohnRichardEnders
8644fa99d1 fix(store): thread embed model URI to format functions for correct prompt detection
When the embed model is configured via YAML (not env var), formatDocForEmbedding
and formatQueryForEmbedding callers in store.ts would fall back to the default
model, producing the wrong prompt format. This adds a public embedModelName
getter on LlamaCpp and threads it through all five call sites.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:34 -04:00
JohnRichardEnders
ce0cd64409 feat(mcp): pass YAML config path to createStore for model resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:09 -04:00
JohnRichardEnders
c8d49d26da feat(cli): configure LlamaCpp singleton from YAML models config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:09 -04:00
JohnRichardEnders
33d42a2a04 feat(sdk): pass YAML models config to LlamaCpp in createStore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:08 -04:00
JohnRichardEnders
50ce17bbfa feat(llm): resolve models as config > env > default
Separate hardcoded default from env var in DEFAULT_EMBED_MODEL so the
constructor can resolve: config param > env var > hardcoded default.
Also add env var support for QMD_GENERATE_MODEL and QMD_RERANK_MODEL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:08 -04:00
JohnRichardEnders
14b384d9d8 feat(config): add ModelsConfig type to CollectionConfig
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:00:08 -04:00
dan mackinlay
1bada2eba6 Add explicit TTY link output tests 2026-04-05 17:58:09 -04:00
dan mackinlay
636631225e Add clickable OSC8 editor links for CLI search results 2026-04-05 17:56:26 -04:00
John R Milinovich
b7a5a86a9b feat(cli): add qmd bench command for search quality benchmarks
Adds a benchmark harness that measures search quality across backends.
Given a fixture file with queries and expected results, it runs each
query through BM25, vector, hybrid (no rerank), and full pipeline,
then reports precision@k, recall, MRR, F1, and latency.

This is primarily a regression testing tool — users create fixtures
for their own vaults to catch quality regressions after config or
index changes. Ships with an example fixture against the eval-docs
test collection to demonstrate the format.

New files:
  src/bench/bench.ts       — main runner
  src/bench/score.ts       — precision, recall, MRR, F1, path matching
  src/bench/types.ts       — fixture and result types
  src/bench/fixtures/      — example fixture
  test/bench-score.test.ts — unit tests for scoring (16 tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:17:59 -04:00
Tobias Lütke
76a2f0fb31 Merge pull request #506 from danmackinlay/fix-505-json-line-output
feat: Include line in --json search output

# Conflicts:
#	CHANGELOG.md
2026-04-05 17:16:05 -04:00
Tobias Lütke
6db34d7278 fix(llm): catch GPU init failures and fall back to CPU
Adds QMD_LLAMA_GPU env var (set to false/off/none to force CPU) and
wraps getLlama() in try/catch so Vulkan/CUDA init failures on headless
or driverless machines fall back gracefully instead of crashing the
node process with an uncatchable C++ terminate().
2026-04-05 17:12:53 -04:00
Tobias Lütke
9c9de94bd8 fix(handelize): restore lowercase + convert dots to dashes
- Restore .toLowerCase() in handelize (was dropped, both test files
  expected it inconsistently)
- Convert dots to dashes in filename body (e.g. v2.0 -> v2-0), keeping
  only the extension dot. Tobi confirmed this is the intended behavior.
- Align both test/store.test.ts and test/store.helpers.unit.test.ts to
  match (they had diverged, one expected case-preserved, one lowercase)
- Adjust 'ensureVecTable recreates' test to expect throw behavior
  (matches #501 dimension-mismatch fix)
2026-04-05 17:12:53 -04:00
Tobias Lütke
828823d20a fix: restore toLowerCase() in handelize + align tests with post-#501 behavior
- Restore .toLowerCase() in handelize (was dropped somewhere, tests expect it)
- Update dimension-mismatch test to expect throw instead of silent rebuild
  (matches new behavior from #501)
- Fix one stale test expectation for preserved dots in filenames
2026-04-05 16:56:06 -04:00
Antonio Mello
ef062e1b54
fix(multi-get): support brace expansion patterns in glob matching (#424)
Brace expansion patterns like `{doc1,doc2}.md` or `collection/{a,b}.md`
were incorrectly parsed as comma-separated file lists instead of being
passed to the glob matcher (picomatch). This happened because the
comma-detection heuristic only checked for `*` and `?` but not `{`.

Also adds `collection/path` matching in `matchFilesByGlob` so patterns
like `my-collection/{file1,file2}.md` work — previously the glob only
matched against `qmd://collection/path` (virtual) and `path` (relative
to collection root), missing the `collection/path` form.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:45:33 -04:00
John R. Enders
09a4d19b31
fix(store): error on embedding dimension mismatch instead of silent rebuild (#501)
When switching to an embedding model with different dimensions,
ensureVecTableInternal() silently drops the vector table and all
embeddings are lost. Users only discover this when semantic search
returns empty results.

Throw an error instead, telling users to run 'qmd embed -f' to
explicitly re-embed. This is safe because embed -f calls
clearAllEmbeddings() which drops the table before ensureVecTable
is reached.

Related to #497

Co-authored-by: JohnRichardEnders <john@telli.com>
2026-04-05 16:45:24 -04:00
John R. Enders
54550a3366
fix(llm): set explicit embed context size, default 2048, configurable via env var (#500)
Without an explicit contextSize, node-llama-cpp defaults to "auto" which
allocates the model's full training context (often 32k). For embedding
chunks that are typically ~900 tokens this wastes ~3.5 GB of KV cache
per context on Apple Silicon unified memory.

Default to 2048 (matching the rerank context pattern) and allow override
via QMD_EMBED_CONTEXT_SIZE for users with larger chunks.

Addresses #329, related to #297

Co-authored-by: JohnRichardEnders <john@telli.com>
2026-04-05 16:45:12 -04:00
LJY
698b44fe87
Fix qmd embed model selection (#494) 2026-04-05 16:45:04 -04:00
Oliver Ratzesberger
021236378b
fix(mcp): read version from package.json instead of hardcoding (#431) 2026-04-05 16:44:35 -04:00
Matt Van Horn
1ad3388132
fix(store): preserve underscores in BM25 search terms (#404)
sanitizeFTS5Term stripped all non-letter/non-number characters including
underscores, causing snake_case identifiers like `my_variable` to become
`myvariable` and silently fail BM25 matches.

Add underscore to the preserved character set in the Unicode regex.
Export the function and add unit tests covering snake_case, contractions,
punctuation stripping, and unicode.

Fixes #305

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:44:14 -04:00
Oliver Ratzesberger
959b719038
fix(mcp): include collection name in status output (#416)
The MCP status tool shows collection paths but not names,
making it impossible for agents to discover valid collection
filter values. The CLI 'qmd status' already shows names.

Add col.name prefix to each collection line in the status
tool response.
2026-04-05 16:43:25 -04:00
dan mackinlay
c22d00829b Add line to JSON search output 2026-04-05 10:08:57 +00:00
Tobias Lütke
1fb2e2819e Merge origin/main into feat/ast-aware-chunking
Resolve conflicts: combine AST chunking args (filepath, chunkStrategy)
with abort signal parameter from #458.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 20:00:49 -04:00