@tobilu/qmd 2.0.1 → 2.5.1
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/CHANGELOG.md +177 -0
- package/README.md +64 -1
- package/bin/qmd +49 -4
- package/dist/ast.d.ts +65 -0
- package/dist/ast.js +334 -0
- package/dist/bench/bench.d.ts +23 -0
- package/dist/bench/bench.js +280 -0
- package/dist/bench/score.d.ts +33 -0
- package/dist/bench/score.js +88 -0
- package/dist/bench/types.d.ts +80 -0
- package/dist/bench/types.js +8 -0
- package/dist/cli/formatter.js +5 -1
- package/dist/cli/qmd.d.ts +27 -0
- package/dist/cli/qmd.js +1328 -115
- package/dist/collections.d.ts +20 -0
- package/dist/collections.js +32 -7
- package/dist/db.d.ts +14 -3
- package/dist/db.js +45 -4
- package/dist/index.d.ts +11 -1
- package/dist/index.js +18 -5
- package/dist/llm.d.ts +77 -6
- package/dist/llm.js +445 -62
- package/dist/mcp/server.d.ts +6 -3
- package/dist/mcp/server.js +68 -29
- package/dist/paths.d.ts +1 -0
- package/dist/paths.js +4 -0
- package/dist/store.d.ts +148 -23
- package/dist/store.js +1018 -255
- package/package.json +48 -20
- package/scripts/build.mjs +29 -0
- package/scripts/check-package-grammars.mjs +29 -0
- package/scripts/package-smoke.mjs +65 -0
- package/scripts/test-all.mjs +27 -0
- package/skills/qmd/SKILL.md +203 -0
- package/skills/qmd/references/mcp-setup.md +102 -0
- package/skills/release/SKILL.md +139 -0
- package/skills/release/scripts/install-hooks.sh +38 -0
- package/dist/embedded-skills.d.ts +0 -6
- package/dist/embedded-skills.js +0 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,183 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [2.5.1] - 2026-05-20
|
|
6
|
+
|
|
7
|
+
### Changes
|
|
8
|
+
|
|
9
|
+
- Release: publish from GitHub Actions via npm Trusted Publishing/OIDC instead of a long-lived `NPM_TOKEN` secret.
|
|
10
|
+
|
|
11
|
+
## [2.5.0] - 2026-05-19
|
|
12
|
+
|
|
13
|
+
### Changes
|
|
14
|
+
|
|
15
|
+
- Dependencies: update core SQLite/config/chunking packages (`better-sqlite3`, `yaml`, `web-tree-sitter`, `tree-sitter-go`, and `tree-sitter-python`) while keeping incompatible `zod`, `tsx`, and `vitest` majors pinned.
|
|
16
|
+
- Agent skills: add `qmd skills list|get|path` to serve version-matched runtime skill instructions from the installed CLI, and make `qmd skill install` write a stable discovery stub so installed agent skills do not go stale after QMD upgrades.
|
|
17
|
+
- CLI: add `qmd doctor` for index/runtime diagnostics, including SQLite/sqlite-vec versions, embedding fingerprint freshness, mixed-fingerprint detection, safe legacy fingerprint adoption, and content-hash sampling.
|
|
18
|
+
|
|
19
|
+
### Fixes
|
|
20
|
+
|
|
21
|
+
- Launcher: prefer runnable TypeScript source in git checkouts even when ignored `dist/` artifacts exist, while packaged installs continue to run `dist/`.
|
|
22
|
+
- GPU: keep node-llama-cpp's documented `gpu: "auto"` initialization as the primary path, then perform no-build packaged CUDA/Vulkan/Metal probes only if auto falls back to CPU.
|
|
23
|
+
- CLI: move GPU/CPU runtime diagnostics out of `qmd status`; use `qmd doctor` for device probing and related environment guidance.
|
|
24
|
+
- CLI: point unexpected command/setup failures toward `qmd doctor` so diagnostics are the default next step when QMD behaves incorrectly.
|
|
25
|
+
- Doctor: explicitly warn when `content_vectors` contains multiple non-empty embedding fingerprint names, with the per-fingerprint document/chunk breakdown.
|
|
26
|
+
- Embed: make the TTY progress line label byte-based input progress explicitly, show embedded chunks as a count, and shorten the displayed model name.
|
|
27
|
+
- Embed: retain per-chunk failure details, retry failed chunks after later successful embeds and again when no other chunks remain, clear recovered errors, and cap retries to avoid endless loops.
|
|
28
|
+
- Tests: expand the container smoke harness to cover npm-global, npx-style, and Bun-global install scenarios, always checking auto and `QMD_FORCE_CPU=1` doctor modes, with opt-in tiny `qmd embed` and GPU probe runs for supported container runtimes.
|
|
29
|
+
- Embedding: fingerprint vector metadata using the active embedding model and formatting/chunking parameters so stale vectors are treated as pending after search semantics change. Legacy `content_vectors` columns are migrated lazily on first vector-health/write use to preserve fast QMD startup.
|
|
30
|
+
|
|
31
|
+
- Skill: expand the packaged QMD skill with retrieval-first workflows, structured query examples, wiki/source collection guidance, and safe fallbacks when model-backed search is unavailable.
|
|
32
|
+
- Tests: make `bun run test` execute the local unit suite under both Node/Vitest and Bun (`test:node` + `test:bun`) so runtime-specific regressions are caught before CI.
|
|
33
|
+
- Model config: centralize embedding/rerank/generation model resolution so `qmd embed`, `status`, `query`, `vsearch`, `pull`, SDK vector search, and `bench` use the same active `.qmd/index.yaml` model hints and environment fallbacks.
|
|
34
|
+
- GPU/status: `qmd status` now uses the same embedding model identity as `qmd embed` when computing pending embeddings, so URI-backed embeddings are not incorrectly reported as pending under the legacy `embeddinggemma` alias.
|
|
35
|
+
- GPU status: `qmd status` now always shows GPU mode/configuration without unsafe native probing, and CPU-fallback warnings point to `QMD_STATUS_DEVICE_PROBE=1 qmd status` for an actual backend probe. The no-GPU warning is emitted once per process instead of once per LLM instance during benchmarks.
|
|
36
|
+
- GPU: add `QMD_FORCE_CPU=1` / `--no-gpu` to bypass CUDA/Vulkan/Metal probing entirely, and route native llama.cpp stdout noise to stderr so JSON output stays parseable during search/query commands.
|
|
37
|
+
- Snippet line numbers: `qmd_query` (MCP), HTTP `/query`, and `qmd query`
|
|
38
|
+
(CLI JSON output and snippet headers) now return absolute source-file
|
|
39
|
+
line numbers instead of chunk-local ones, so the `line` field can be
|
|
40
|
+
passed back to `qmd_get` as `fromLine` without a separate lookup.
|
|
41
|
+
Snippet selection remains scoped to the best matching chunk
|
|
42
|
+
(preserves #149).
|
|
43
|
+
- CLI: `qmd query --full` now emits the full document body in all output
|
|
44
|
+
formats (json, csv, md, xml), restoring the documented behavior of the
|
|
45
|
+
flag. Previously it returned only the best matching chunk (~3.6KB max
|
|
46
|
+
per result). Output payload for `--full` queries is now proportional
|
|
47
|
+
to total document size.
|
|
48
|
+
- macOS Metal: `qmd query --json` now flushes successful JSON output and uses a safe immediate-exit path on Darwin to avoid ggml Metal finalizer aborts; other commands still dispose LLM contexts/models before the llama runtime. #368
|
|
49
|
+
- Embedding: require complete chunk coverage before treating a document as
|
|
50
|
+
embedded, remove partial vectors when chunk/session failures leave a
|
|
51
|
+
document incomplete, and keep `qmd status` pending counts honest after
|
|
52
|
+
interrupted long embed runs. #637 #378
|
|
53
|
+
- Embedding: `qmd embed -c <collection>` now scopes pending-doc selection
|
|
54
|
+
to the requested collection instead of embedding global pending work.
|
|
55
|
+
Scoped `--force` clears only collection-owned vectors, preserves shared
|
|
56
|
+
hashes referenced by sibling collections, and drops `vectors_vec` only
|
|
57
|
+
when the scoped clear empties all vectors.
|
|
58
|
+
- Hybrid search: weight RRF lists by query type so original FTS and original vector evidence get the intended 2x boost, instead of accidentally boosting the first lexical expansion. #591
|
|
59
|
+
- MCP: seed llama.cpp/GGML quiet env vars before launching `qmd mcp` so native logs cannot pollute stdio JSON-RPC framing. #593
|
|
60
|
+
- CLI: remove CommonJS `require()` calls from ESM index path normalization so `qmd --index <path>` no longer crashes with `ERR_AMBIGUOUS_MODULE_SYNTAX` on Node 22+. #634
|
|
61
|
+
- Windows CUDA: serialize llama.cpp embedding/reranking contexts by default to avoid intermittent `ggml-cuda.cu:98` crashes in `qmd query`; set `QMD_EMBED_PARALLELISM` to opt back into parallel contexts if your driver is stable. #519
|
|
62
|
+
- MCP: make `qmd mcp --index <name>` use the selected index for both foreground and daemon HTTP servers instead of falling back to the default store. #343
|
|
63
|
+
- Embedding: respect `QMD_EMBED_MODEL` consistently for vector indexing and vector-backed search, with default-model fallback when unset.
|
|
64
|
+
- Config: use one home-directory resolver for YAML config and the default SQLite cache path, avoiding Windows CLI/MCP split-brain when `HOME` is unset.
|
|
65
|
+
- GPU: respect explicit `QMD_LLAMA_GPU=metal|vulkan|cuda` backend overrides instead of always using auto GPU selection. #529
|
|
66
|
+
- Fix: preserve original filename case in `handelize()`. The previous
|
|
67
|
+
`.toLowerCase()` call made indexed paths unreachable on case-sensitive
|
|
68
|
+
filesystems (Linux). `qmd update` automatically migrates legacy
|
|
69
|
+
lowercase paths without re-embedding.
|
|
70
|
+
- CLI: make `qmd status` skip native `node-llama-cpp` device probing by
|
|
71
|
+
default so status stays safe on machines with broken or unsupported GPU
|
|
72
|
+
drivers. Set `QMD_STATUS_DEVICE_PROBE=1` to opt in.
|
|
73
|
+
- CLI: lazy-load `node-llama-cpp` so lightweight commands such as
|
|
74
|
+
`qmd status` do not import native ML dependencies or trigger llama.cpp
|
|
75
|
+
builds on ARM/no-GPU machines. #491
|
|
76
|
+
- Store: keep content rows referenced by inactive documents during orphan
|
|
77
|
+
cleanup so `qmd update` preserves soft-deleted tombstones for removed
|
|
78
|
+
files. #585
|
|
79
|
+
- Packaging: install AST grammar WASM packages as required dependencies so
|
|
80
|
+
Bun global installs include TypeScript/TSX/JavaScript grammars, and add a
|
|
81
|
+
`smoke:package-grammars` verification command. #595
|
|
82
|
+
- Launcher: add wrapper smoke coverage for scoped package, npm/npx,
|
|
83
|
+
Homebrew/Linuxbrew, Bun global symlink layouts, and `$BUN_INSTALL`
|
|
84
|
+
false-positive runtime selection regressions. #351 #353 #354 #356 #358 #359
|
|
85
|
+
|
|
86
|
+
## [2.1.0] - 2026-04-05
|
|
87
|
+
|
|
88
|
+
Code files now chunk at function and class boundaries via tree-sitter,
|
|
89
|
+
clickable editor links land you at the right line from search results,
|
|
90
|
+
and per-collection model configuration means you can point different
|
|
91
|
+
collections at different embedding models. 25+ community PRs fix
|
|
92
|
+
embedding stability, BM25 accuracy, and cross-platform launcher issues.
|
|
93
|
+
|
|
94
|
+
### Changes
|
|
95
|
+
|
|
96
|
+
- AST-aware chunking for code files via `web-tree-sitter`. Supported
|
|
97
|
+
languages: TypeScript/JavaScript, Python, Go, and Rust. Code files
|
|
98
|
+
are chunked at function, class, and import boundaries instead of
|
|
99
|
+
arbitrary text positions. Markdown and unknown file types are unchanged.
|
|
100
|
+
`--chunk-strategy <auto|regex>` flag on `qmd embed` and `qmd query`
|
|
101
|
+
(default `regex`). SDK: `chunkStrategy` option on `embed()` and
|
|
102
|
+
`search()`. `qmd status` shows grammar availability.
|
|
103
|
+
- `qmd bench <fixture.json>` command for search quality benchmarks.
|
|
104
|
+
Measures precision@k, recall, MRR, and F1 across BM25, vector, hybrid,
|
|
105
|
+
and full pipeline backends. Ships with an example fixture against
|
|
106
|
+
the eval-docs test collection. #470 (thanks @jmilinovich)
|
|
107
|
+
- `models:` section in `index.yml` lets you configure `embed`, `rerank`,
|
|
108
|
+
and `generate` model URIs per collection. Resolution order is
|
|
109
|
+
config > env var (`QMD_EMBED_MODEL`, `QMD_RERANK_MODEL`,
|
|
110
|
+
`QMD_GENERATE_MODEL`) > built-in default. #502
|
|
111
|
+
(thanks @JohnRichardEnders)
|
|
112
|
+
- CLI search output now emits clickable OSC 8 terminal hyperlinks when
|
|
113
|
+
stdout is a TTY. Links resolve `qmd://` paths to absolute filesystem
|
|
114
|
+
paths and open in editors via URI templates (default:
|
|
115
|
+
`vscode://file/{path}:{line}:{col}`). Configure with `QMD_EDITOR_URI`
|
|
116
|
+
or `editor_uri` in the YAML config. #508 (thanks @danmackinlay)
|
|
117
|
+
- `--no-rerank` flag skips the reranking step in `qmd query` — useful
|
|
118
|
+
when you want fast results or don't have a GPU. Also exposed as
|
|
119
|
+
`rerank: false` on the MCP `query` tool. #370 (thanks @mvanhorn),
|
|
120
|
+
#478 (thanks @zestyboy)
|
|
121
|
+
- ONNX conversion script for deploying embedding models via
|
|
122
|
+
Transformers.js. #399 (thanks @shreyaskarnik)
|
|
123
|
+
- GitHub Actions workflow to build the Nix flake on Linux and macOS.
|
|
124
|
+
|
|
125
|
+
### Fixes
|
|
126
|
+
|
|
127
|
+
- Embedding: prevent `qmd embed` from running indefinitely when the
|
|
128
|
+
embedding loop stalls. #458 (thanks @ccc-fff)
|
|
129
|
+
- Embedding: truncate oversized text before embedding to prevent GGML
|
|
130
|
+
crash, and bound memory usage during batch embedding. #393
|
|
131
|
+
(thanks @lskun), #395 (thanks @ProgramCaiCai)
|
|
132
|
+
- Embedding: set explicit embed context size (default 2048, configurable
|
|
133
|
+
via `QMD_EMBED_CONTEXT_SIZE`) instead of using the model's full
|
|
134
|
+
window. #500
|
|
135
|
+
- Embedding: error on dimension mismatch instead of silently rebuilding
|
|
136
|
+
the vec0 table. #501
|
|
137
|
+
- Embedding: handle vec0 `OR REPLACE` limitation in `insertEmbedding`.
|
|
138
|
+
#456 (thanks @antonio-mello-ai)
|
|
139
|
+
- Embedding: fix model selection when multiple models are configured.
|
|
140
|
+
#494
|
|
141
|
+
- BM25: correct field weights to include all 3 FTS columns — title,
|
|
142
|
+
body, and path were not weighted correctly. #462 (thanks @goldsr09)
|
|
143
|
+
- BM25: handle hyphenated tokens in FTS5 lex queries so terms like
|
|
144
|
+
"real-time" match correctly. #463 (thanks @goldsr09)
|
|
145
|
+
- BM25: preserve underscores in search terms instead of stripping them.
|
|
146
|
+
#404
|
|
147
|
+
- BM25: use CTE in `searchFTS` to prevent query planner regression with
|
|
148
|
+
collection filter.
|
|
149
|
+
- Reranker: increase default context size 2048→4096 and make
|
|
150
|
+
configurable via `QMD_RERANK_CONTEXT_SIZE`. Fix template overhead
|
|
151
|
+
underestimate 200→512. #453 (thanks @builderjarvis)
|
|
152
|
+
- GPU: catch initialization failures and fall back to CPU instead of
|
|
153
|
+
crashing.
|
|
154
|
+
- MCP: read version from `package.json` instead of hardcoding. #431
|
|
155
|
+
- MCP: include collection name in status output. #416
|
|
156
|
+
- Multi-get: support brace expansion patterns in glob matching. #424
|
|
157
|
+
- Launcher: prioritize `package-lock.json` to prevent Bun false
|
|
158
|
+
positive. #385 (thanks @rymalia)
|
|
159
|
+
- Launcher: remove `$BUN_INSTALL` check that caused false Bun detection.
|
|
160
|
+
#362 (thanks @syedair)
|
|
161
|
+
- Launcher: skip Git Bash path detection on WSL. #371
|
|
162
|
+
(thanks @oysteinkrog)
|
|
163
|
+
- Model cache: respect `XDG_CACHE_HOME` for model cache directory. #457
|
|
164
|
+
(thanks @antonio-mello-ai)
|
|
165
|
+
- SQLite: add macOS Homebrew SQLite support for Bun and restore
|
|
166
|
+
actionable errors. #377 (thanks @serhii12)
|
|
167
|
+
- Pin zod to exact 4.2.1 to fix `tsc` build failure. #382
|
|
168
|
+
(thanks @rymalia)
|
|
169
|
+
- Preserve dots and original case in `handelize()` — filenames like
|
|
170
|
+
`MEMORY.md` no longer become `memory-md`. #475 (thanks @alexei-led)
|
|
171
|
+
- Include `line` in `--json` search output so editor integrations can
|
|
172
|
+
jump directly to `file:line`. #506 (thanks @danmackinlay)
|
|
173
|
+
- Nix: fix paths in flake and make Bun dependency a fixed-output
|
|
174
|
+
derivation so sandboxed Linux builds work offline. #479
|
|
175
|
+
(thanks @surma-dump)
|
|
176
|
+
- Sync stale `bun.lock` (`better-sqlite3` 11.x → 12.x). CI and release
|
|
177
|
+
script now use `--frozen-lockfile` to prevent recurrence. #386
|
|
178
|
+
(thanks @Mic92)
|
|
179
|
+
- Approve native build scripts in pnpm so `better-sqlite3` and
|
|
180
|
+
tree-sitter modules compile correctly. Update vitest ^3.0.0 → ^3.2.4.
|
|
181
|
+
|
|
5
182
|
## [2.0.1] - 2026-03-10
|
|
6
183
|
|
|
7
184
|
### Changes
|
package/README.md
CHANGED
|
@@ -318,6 +318,7 @@ const result = await store.update({
|
|
|
318
318
|
// Generate vector embeddings
|
|
319
319
|
const embedResult = await store.embed({
|
|
320
320
|
force: false, // true to re-embed everything
|
|
321
|
+
chunkStrategy: "auto", // "regex" (default) or "auto" (AST for code files)
|
|
321
322
|
onProgress: ({ current, total, collection }) => {
|
|
322
323
|
console.log(`Embedding ${current}/${total}`)
|
|
323
324
|
},
|
|
@@ -564,8 +565,27 @@ qmd embed
|
|
|
564
565
|
|
|
565
566
|
# Force re-embed everything
|
|
566
567
|
qmd embed -f
|
|
568
|
+
|
|
569
|
+
# Enable AST-aware chunking for code files (TS, JS, Python, Go, Rust)
|
|
570
|
+
qmd embed --chunk-strategy auto
|
|
571
|
+
|
|
572
|
+
# Also works with query for consistent chunk selection
|
|
573
|
+
qmd query "auth flow" --chunk-strategy auto
|
|
567
574
|
```
|
|
568
575
|
|
|
576
|
+
**AST-aware chunking** (`--chunk-strategy auto`) uses tree-sitter to chunk code
|
|
577
|
+
files at function, class, and import boundaries instead of arbitrary text
|
|
578
|
+
positions. This produces higher-quality chunks and better search results for
|
|
579
|
+
codebases. Markdown and other file types always use regex-based chunking
|
|
580
|
+
regardless of strategy.
|
|
581
|
+
|
|
582
|
+
The default is `regex` (existing behavior). Use `--chunk-strategy auto` to
|
|
583
|
+
opt in. Run `qmd status` to verify which grammars are available.
|
|
584
|
+
|
|
585
|
+
> **Note:** Tree-sitter grammars are optional dependencies. If they are not
|
|
586
|
+
> installed, `--chunk-strategy auto` falls back to regex-only chunking
|
|
587
|
+
> automatically. Tested on both Node.js and Bun.
|
|
588
|
+
|
|
569
589
|
### Context Management
|
|
570
590
|
|
|
571
591
|
Context adds descriptive metadata to collections and paths, helping search understand your content.
|
|
@@ -644,7 +664,13 @@ qmd get <file>[:line] # Get document, optionally starting at line
|
|
|
644
664
|
|
|
645
665
|
### Output Format
|
|
646
666
|
|
|
647
|
-
Default output is colorized CLI format (respects `NO_COLOR` env)
|
|
667
|
+
Default output is colorized CLI format (respects `NO_COLOR` env).
|
|
668
|
+
|
|
669
|
+
When stdout is a TTY, result paths are emitted as clickable terminal hyperlinks (OSC 8). Clicking a path opens the file in your editor using an editor URI template.
|
|
670
|
+
|
|
671
|
+
When stdout is not a TTY (for example piped to another command or redirected to a file), QMD emits plain text paths with no escape sequences.
|
|
672
|
+
|
|
673
|
+
TTY example:
|
|
648
674
|
|
|
649
675
|
```
|
|
650
676
|
docs/guide.md:42 #a1b2c3
|
|
@@ -666,6 +692,27 @@ Discussion about code quality and craftsmanship
|
|
|
666
692
|
in the development process.
|
|
667
693
|
```
|
|
668
694
|
|
|
695
|
+
Configure the editor link target with `QMD_EDITOR_URI` (or `editor_uri` in config):
|
|
696
|
+
|
|
697
|
+
```sh
|
|
698
|
+
# VS Code (default)
|
|
699
|
+
export QMD_EDITOR_URI="vscode://file/{path}:{line}:{col}"
|
|
700
|
+
|
|
701
|
+
# Cursor
|
|
702
|
+
export QMD_EDITOR_URI="cursor://file/{path}:{line}:{col}"
|
|
703
|
+
|
|
704
|
+
# Zed
|
|
705
|
+
export QMD_EDITOR_URI="zed://file/{path}:{line}:{col}"
|
|
706
|
+
|
|
707
|
+
# Sublime Text
|
|
708
|
+
export QMD_EDITOR_URI="subl://open?url=file://{path}&line={line}"
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
Template placeholders:
|
|
712
|
+
- `{path}` absolute filesystem path (URI-encoded)
|
|
713
|
+
- `{line}` 1-based line number
|
|
714
|
+
- `{col}` or `{column}` 1-based column number
|
|
715
|
+
|
|
669
716
|
- **Path**: Collection-relative path (e.g., `docs/guide.md`)
|
|
670
717
|
- **Docid**: Short hash identifier (e.g., `#a1b2c3`) - use with `qmd get #a1b2c3`
|
|
671
718
|
- **Title**: Extracted from document (first heading or filename)
|
|
@@ -750,6 +797,9 @@ llm_cache -- Cached LLM responses (query expansion, rerank scores)
|
|
|
750
797
|
| Variable | Default | Description |
|
|
751
798
|
|----------|---------|-------------|
|
|
752
799
|
| `XDG_CACHE_HOME` | `~/.cache` | Cache directory location |
|
|
800
|
+
| `QMD_LLAMA_GPU` | `auto` | Force llama.cpp GPU backend (`metal`, `vulkan`, `cuda`) or disable GPU with `false` |
|
|
801
|
+
| `QMD_FORCE_CPU` | unset | Set to `1`/`true` to force CPU mode before any CUDA/Vulkan/Metal probing. Equivalent CLI flag: `--no-gpu`. |
|
|
802
|
+
| `QMD_EMBED_PARALLELISM` | automatic | Override embedding/reranking context parallelism (1-8). Windows CUDA defaults to `1` because parallel CUDA contexts can crash with `ggml-cuda.cu:98`; use Vulkan or raise this only if your driver is stable. |
|
|
753
803
|
|
|
754
804
|
## How It Works
|
|
755
805
|
|
|
@@ -813,6 +863,19 @@ The squared distance decay means a heading 200 tokens back (score ~30) still bea
|
|
|
813
863
|
|
|
814
864
|
**Code Fence Protection:** Break points inside code blocks are ignored—code stays together. If a code block exceeds the chunk size, it's kept whole when possible.
|
|
815
865
|
|
|
866
|
+
**AST-Aware Chunking (Code Files):**
|
|
867
|
+
|
|
868
|
+
For supported code files, QMD also parses the source with [tree-sitter](https://tree-sitter.github.io/) and adds AST-derived break points that are merged with the regex scores above:
|
|
869
|
+
|
|
870
|
+
| AST Node | Score | Languages |
|
|
871
|
+
|----------|-------|-----------|
|
|
872
|
+
| Class / interface / struct / impl / trait | 100 | All |
|
|
873
|
+
| Function / method | 90 | All |
|
|
874
|
+
| Type alias / enum | 80 | All |
|
|
875
|
+
| Import / use declaration | 60 | All |
|
|
876
|
+
|
|
877
|
+
Supported for `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.go`, and `.rs` files. Enable with `--chunk-strategy auto`. Markdown and other file types always use regex chunking.
|
|
878
|
+
|
|
816
879
|
### Query Flow (Hybrid)
|
|
817
880
|
|
|
818
881
|
```
|
package/bin/qmd
CHANGED
|
@@ -15,9 +15,54 @@ done
|
|
|
15
15
|
# to avoid native module ABI mismatches (e.g., better-sqlite3 compiled for bun vs node)
|
|
16
16
|
DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
# MCP stdio reserves stdout exclusively for JSON-RPC frames. node-llama-cpp
|
|
19
|
+
# / llama.cpp / ggml can write native logs directly to stdout before JS-level
|
|
20
|
+
# log handlers are attached, so seed the native quiet env before Node/Bun imports
|
|
21
|
+
# the CLI and its LLM modules. Preserve explicit user values when provided.
|
|
22
|
+
if [ "$1" = "mcp" ]; then
|
|
23
|
+
export LLAMA_LOG_LEVEL="${LLAMA_LOG_LEVEL:-error}"
|
|
24
|
+
export GGML_LOG_LEVEL="${GGML_LOG_LEVEL:-error}"
|
|
25
|
+
export GGML_BACKEND_SILENT="${GGML_BACKEND_SILENT:-1}"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
JS="$DIR/dist/cli/qmd.js"
|
|
29
|
+
TS="$DIR/src/cli/qmd.ts"
|
|
30
|
+
|
|
31
|
+
# In published packages, bin/qmd must run dist/. In a git checkout, however,
|
|
32
|
+
# dist/ is often ignored and can be stale after git reset or branch switches.
|
|
33
|
+
# Prefer source mode only for checkouts so ./bin/qmd reflects the checked-out
|
|
34
|
+
# source without changing packaged/runtime behavior.
|
|
35
|
+
if [ -e "$DIR/.git" ] && [ -f "$TS" ]; then
|
|
36
|
+
if [ -f "$DIR/bun.lock" ] || [ -f "$DIR/bun.lockb" ]; then
|
|
37
|
+
if command -v bun >/dev/null 2>&1; then
|
|
38
|
+
exec bun "$TS" "$@"
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
if [ -f "$DIR/node_modules/tsx/dist/cli.mjs" ]; then
|
|
42
|
+
exec node "$DIR/node_modules/tsx/dist/cli.mjs" "$TS" "$@"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [ ! -f "$JS" ]; then
|
|
47
|
+
echo "qmd is not built: missing $JS" >&2
|
|
48
|
+
echo "Run: bun install && bun run build" >&2
|
|
49
|
+
echo "Or: npm install && npm run build" >&2
|
|
50
|
+
echo "After building, run: qmd doctor" >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Detect the package manager that installed dependencies by checking lockfiles.
|
|
55
|
+
# $BUN_INSTALL is intentionally NOT checked — it only indicates that bun exists
|
|
56
|
+
# on the system, not that it was used to install this package (see #361).
|
|
57
|
+
#
|
|
58
|
+
# package-lock.json takes priority: if it exists, npm installed the native
|
|
59
|
+
# modules for Node. The repo ships bun.lock, so without this check, source
|
|
60
|
+
# builds that use npm would be incorrectly routed to bun, causing ABI
|
|
61
|
+
# mismatches with better-sqlite3 / sqlite-vec (see #381).
|
|
62
|
+
if [ -f "$DIR/package-lock.json" ]; then
|
|
63
|
+
exec node "$JS" "$@"
|
|
64
|
+
elif [ -f "$DIR/bun.lock" ] || [ -f "$DIR/bun.lockb" ]; then
|
|
65
|
+
exec bun "$JS" "$@"
|
|
21
66
|
else
|
|
22
|
-
exec node "$
|
|
67
|
+
exec node "$JS" "$@"
|
|
23
68
|
fi
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-aware chunking support via web-tree-sitter.
|
|
3
|
+
*
|
|
4
|
+
* Provides language detection, AST break point extraction for supported
|
|
5
|
+
* code file types, and a stub for future symbol extraction.
|
|
6
|
+
*
|
|
7
|
+
* All functions degrade gracefully: parse failures or unsupported languages
|
|
8
|
+
* return empty arrays, falling back to regex-only chunking.
|
|
9
|
+
*
|
|
10
|
+
* ## Dependency Note
|
|
11
|
+
*
|
|
12
|
+
* Grammar packages (tree-sitter-typescript, etc.) are listed as
|
|
13
|
+
* optionalDependencies with pinned versions. They ship native prebuilds
|
|
14
|
+
* and source files (~72 MB total) but QMD only uses the .wasm files
|
|
15
|
+
* (~5 MB). If install size becomes a concern, the .wasm files can be
|
|
16
|
+
* bundled directly in the repo (e.g. assets/grammars/) and resolved
|
|
17
|
+
* via import.meta.url instead of require.resolve(), eliminating the
|
|
18
|
+
* grammar packages entirely.
|
|
19
|
+
*/
|
|
20
|
+
import type { BreakPoint } from "./store.js";
|
|
21
|
+
export type SupportedLanguage = "typescript" | "tsx" | "javascript" | "python" | "go" | "rust";
|
|
22
|
+
/**
|
|
23
|
+
* Detect language from file path extension.
|
|
24
|
+
* Returns null for unsupported or unknown extensions (including .md).
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectLanguage(filepath: string): SupportedLanguage | null;
|
|
27
|
+
export declare function formatGrammarLoadError(language: SupportedLanguage, err: unknown): string;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a source file and return break points at AST node boundaries.
|
|
30
|
+
*
|
|
31
|
+
* Returns an empty array for unsupported languages, parse failures,
|
|
32
|
+
* or grammar loading failures. Never throws.
|
|
33
|
+
*
|
|
34
|
+
* @param content - The file content to parse.
|
|
35
|
+
* @param filepath - The file path (used for language detection).
|
|
36
|
+
* @returns Array of BreakPoint objects suitable for merging with regex break points.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getASTBreakPoints(content: string, filepath: string): Promise<BreakPoint[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Check which tree-sitter grammars are available.
|
|
41
|
+
* Returns a status object for each supported language.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getASTStatus(): Promise<{
|
|
44
|
+
available: boolean;
|
|
45
|
+
languages: {
|
|
46
|
+
language: SupportedLanguage;
|
|
47
|
+
available: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
}[];
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Metadata about a code symbol within a chunk.
|
|
53
|
+
* Stubbed for Phase 2 — always returns empty array in Phase 1.
|
|
54
|
+
*/
|
|
55
|
+
export interface SymbolInfo {
|
|
56
|
+
name: string;
|
|
57
|
+
kind: string;
|
|
58
|
+
signature?: string;
|
|
59
|
+
line: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Extract symbol metadata for code within a byte range.
|
|
63
|
+
* Stubbed for Phase 2 — returns empty array.
|
|
64
|
+
*/
|
|
65
|
+
export declare function extractSymbols(_content: string, _language: string, _startPos: number, _endPos: number): SymbolInfo[];
|