@wei840222/qmd 2026.9.6 → 2026.9.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wei840222/qmd",
3
- "version": "2026.9.6",
3
+ "version": "2026.9.25",
4
4
  "packageManager": "pnpm@11.15.1",
5
5
  "description": "Query Markup Documents - On-device hybrid search for markdown files with BM25, vector search, and LLM reranking",
6
6
  "type": "module",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@modelcontextprotocol/server": "2.0.0",
68
- "@node-rs/jieba": "2.0.2",
68
+ "@node-rs/jieba": "2.0.3",
69
69
  "fast-glob": "3.3.3",
70
70
  "node-llama-cpp": "3.20.0",
71
71
  "picomatch": "4.0.5",
@@ -77,7 +77,10 @@ async function downloadPinnedSource(source, label) {
77
77
 
78
78
  async function updateRemotePin(source, label) {
79
79
  const response = await fetch(apiUrl(source), {
80
- headers: { Accept: "application/vnd.github+json" },
80
+ headers: {
81
+ Accept: "application/vnd.github+json",
82
+ "User-Agent": "qmd-dict-sync",
83
+ },
81
84
  redirect: "error",
82
85
  });
83
86
  if (!response.ok) throw new Error(`${label} commit lookup failed with HTTP ${response.status}.`);
@@ -201,6 +201,17 @@ qmd query "merchant support product reality" -c concepts -c sources -n 10
201
201
 
202
202
  > **Performance Tip for Agents:** Collection filters (`-c`) are natively indexed in both lexical and vector virtual tables. Scoping by collection guarantees millisecond search latency and avoids ranking dilution from unrelated collections. Omit `-c` only when searching across the entire workspace.
203
203
 
204
+ ## Filter by metadata
205
+
206
+ Documents can carry typed metadata in a `qmd.metadata` frontmatter block (strings, numbers, booleans, or flat arrays). `search`, `vsearch`, and `query` accept `--filter` with a recursive JSON AST; every returned result satisfies it:
207
+
208
+ ```bash
209
+ qmd search "authentication" --filter '{"key":"status","operator":"eq","value":"published"}'
210
+ qmd query "dependency injection" --filter '{"operator":"and","operands":[{"key":"topics","operator":"all","value":["typescript"]},{"key":"status","operator":"nin","value":["draft","archived"]}]}'
211
+ ```
212
+
213
+ Nodes are discriminated by `operator`: groups `and`/`or` take `operands`, `not` takes one `operand`, and conditions take `key` + `value` with operators `eq`/`ne`/`gt`/`gte`/`lt`/`lte` (comparison), `in`/`nin`/`all` (membership), or `exists` (presence). Matching is typed and exact; missing keys do not match `ne`/`nin` (add an `exists: false` branch in an `or` group to include them). The MCP `query` tool accepts the same AST as a `filter` object. JSON output includes each result's `metadata`.
214
+
204
215
  ## MCP Tool: `query`
205
216
 
206
217
  When using the MCP server, prefer structured searches:
@@ -1,141 +0,0 @@
1
- ---
2
- name: release
3
- description: Manage releases for this project. Validates changelog, installs git hooks, and cuts releases. Use when user says "/release", "release 1.0.5", "cut a release", or asks about the release process. NOT auto-invoked by the model.
4
- disable-model-invocation: true
5
- ---
6
-
7
- # Release
8
-
9
- Cut a release, validate the changelog, and ensure git hooks are installed.
10
-
11
- ## Usage
12
-
13
- `/release 1.0.5` or `/release patch` (bumps patch from current version).
14
-
15
- ## Process
16
-
17
- When the user triggers `/release <version>`:
18
-
19
- 1. **Gather context** — run `skills/release/scripts/release-context.sh <version>`.
20
- This silently installs git hooks and prints everything needed: version info,
21
- working directory status, commits since last release, files changed, current
22
- `[Unreleased]` content, and the previous release entry for style reference.
23
-
24
- 2. **Commit outstanding work** — if the context shows staged, modified, or
25
- untracked files that belong in this release, commit them first. Use the
26
- /commit skill or make well-formed commits directly.
27
-
28
- 3. **Write the changelog** — if `[Unreleased]` is empty, write it now using
29
- the commits and file changes from the context output. Follow the changelog
30
- standard below. Re-run the context script after committing if needed.
31
-
32
- 4. **Check dependency updates** — before cutting the release, check for
33
- updates to `sqlite-vec` (and platform packages), `node-llama-cpp`,
34
- and `better-sqlite3`. Run `pnpm outdated` and report any available
35
- updates for these packages. If updates exist, bump them (pinned, no
36
- `^` ranges) and re-run tests before proceeding.
37
-
38
- 5. **Cut the release** — run `scripts/release.sh <version>`. This renames
39
- `[Unreleased]` → `[X.Y.Z] - date`, inserts a fresh `[Unreleased]`,
40
- bumps `package.json` and the plugin version in
41
- `.claude-plugin/marketplace.json` (so installed plugins see the update),
42
- commits, and tags.
43
-
44
- 6. **Show the final changelog** — print the full `[Unreleased]` +
45
- minor series rollup via `scripts/extract-changelog.sh <version>`.
46
- Ask the user to confirm before pushing.
47
-
48
- 7. **Push** — after explicit confirmation, run `git push origin main --tags`.
49
-
50
- 8. **Watch CI** — after the push, start a background dispatch to watch the
51
- publish workflow. Use `interactive_shell` in dispatch mode with:
52
- ```
53
- gh run watch $(gh run list --workflow=publish.yml --limit=1 --json databaseId --jq '.[0].databaseId') --exit-status
54
- ```
55
- The agent will be notified when CI completes and should report the result.
56
-
57
- If any step fails, stop and explain. Never force-push or skip validation.
58
-
59
- ## Dependency Policy
60
-
61
- All dependencies must be pinned to exact versions (no `^` or `~` ranges).
62
- The lockfile ensures reproducible installs. When adding or updating any
63
- dependency, always use the exact version string (e.g. `"3.18.1"` not
64
- `"^3.18.1"`).
65
-
66
- ## Changelog Standard
67
-
68
- The changelog lives in `CHANGELOG.md` and follows [Keep a Changelog](https://keepachangelog.com/) conventions.
69
-
70
- ### Heading format
71
-
72
- - `## [Unreleased]` — accumulates entries between releases
73
- - `## [X.Y.Z] - YYYY-MM-DD` — released versions
74
-
75
- ### Structure of a release entry
76
-
77
- Each version entry has two parts:
78
-
79
- **1. Highlights (optional, 1-4 sentences of prose)**
80
-
81
- Immediately after the version heading, before any `###` section. The elevator
82
- pitch — what would you tell someone in 30 seconds? Only for significant
83
- releases; skip for small patches.
84
-
85
- ```markdown
86
- ## [1.1.0] - 2026-03-01
87
-
88
- QMD now runs on both Node.js and Bun, with up to 2.7x faster reranking
89
- through parallel contexts. GPU auto-detection replaces the unreliable
90
- `gpu: "auto"` with explicit CUDA/Metal/Vulkan probing.
91
- ```
92
-
93
- **2. Detailed changelog (`### Changes` and `### Fixes`)**
94
-
95
- ```markdown
96
- ### Changes
97
-
98
- - Runtime: support Node.js (>=22) alongside Bun. The `qmd` wrapper
99
- auto-detects a suitable install via PATH. #149 (thanks @igrigorik)
100
- - Performance: parallel embedding & reranking — up to 2.7x faster on
101
- multi-core machines.
102
-
103
- ### Fixes
104
-
105
- - Prevent VRAM waste from duplicate context creation during concurrent
106
- `embedBatch` calls. #152 (thanks @jkrems)
107
- ```
108
-
109
- ### Writing guidelines
110
-
111
- - **Explain the why, not just the what.** The changelog is for users.
112
- - **Include numbers.** "2.7x faster", "17x less memory".
113
- - **Group by theme, not by file.** "Performance" not "Changes to llm.ts".
114
- - **Don't list every commit.** Aggregate related changes.
115
- - **Credit contributors:** end bullets with `#NNN (thanks @username)` for
116
- external PRs. No need to credit the repo owner.
117
-
118
- ### What not to include
119
-
120
- - Internal refactors with no user-visible effect
121
- - Dependency bumps (unless fixing a user-facing bug)
122
- - CI/tooling changes (unless affecting the release artifact)
123
- - Test additions (unless validating a fix worth mentioning)
124
-
125
- ## GitHub Release Notes
126
-
127
- Each GitHub release includes the full changelog for the **minor series** back
128
- to x.x.0. The `scripts/extract-changelog.sh` script handles this, and the
129
- publish workflow (`publish.yml`) calls it to populate the GitHub release.
130
-
131
- ## Git Hooks
132
-
133
- The pre-push hook (`scripts/pre-push`) blocks `v*` tag pushes unless:
134
-
135
- 1. `package.json` version matches the tag
136
- 2. `CHANGELOG.md` has a `## [X.Y.Z] - date` entry for the version
137
- 3. CI passed on GitHub (warns in non-interactive shells, blocks in terminals)
138
-
139
- Hooks are installed silently by the context script. They can also be installed
140
- manually via `skills/release/scripts/install-hooks.sh` or automatically via
141
- `bun install` (prepare script).
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Install git hooks for release validation.
5
- # Idempotent — safe to run multiple times.
6
-
7
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
8
- if [[ -z "$REPO_ROOT" ]]; then
9
- echo "Error: not in a git repository" >&2
10
- exit 1
11
- fi
12
-
13
- HOOKS_DIR="$REPO_ROOT/.git/hooks"
14
- SOURCE="$REPO_ROOT/scripts/pre-push"
15
-
16
- if [[ ! -f "$SOURCE" ]]; then
17
- echo "Error: scripts/pre-push not found at $SOURCE" >&2
18
- exit 1
19
- fi
20
-
21
- # Install pre-push hook
22
- if [[ -L "$HOOKS_DIR/pre-push" ]] && [[ "$(readlink "$HOOKS_DIR/pre-push")" == "$SOURCE" ]]; then
23
- echo "pre-push hook: already installed (symlink)"
24
- elif [[ -f "$HOOKS_DIR/pre-push" ]]; then
25
- # Existing hook that isn't our symlink — back it up
26
- BACKUP="$HOOKS_DIR/pre-push.backup.$(date +%s)"
27
- echo "pre-push hook: backing up existing hook to $(basename "$BACKUP")"
28
- mv "$HOOKS_DIR/pre-push" "$BACKUP"
29
- ln -sf "$SOURCE" "$HOOKS_DIR/pre-push"
30
- echo "pre-push hook: installed (symlink → scripts/pre-push)"
31
- else
32
- ln -sf "$SOURCE" "$HOOKS_DIR/pre-push"
33
- echo "pre-push hook: installed (symlink → scripts/pre-push)"
34
- fi
35
-
36
- # Ensure the source is executable
37
- chmod +x "$SOURCE"
38
- echo "Done."
@@ -1,129 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Gather release context for the /release skill (skills/release/SKILL.md step 1).
5
- # Silently installs git hooks, then prints version info, working-tree status,
6
- # commits and files since the last release tag, the current [Unreleased]
7
- # changelog block, and the previous release entry for style reference.
8
- #
9
- # Usage: skills/release/scripts/release-context.sh [patch|minor|major|<version>]
10
-
11
- VERSION_ARG="${1:?Usage: release-context.sh [patch|minor|major|<version>]}"
12
-
13
- SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
14
-
15
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
16
- if [[ -z "$REPO_ROOT" ]]; then
17
- echo "Error: not in a git repository" >&2
18
- exit 1
19
- fi
20
- cd "$REPO_ROOT"
21
-
22
- # Hooks are installed silently — the skill documents this as the auto-install path.
23
- if [[ -x "$SCRIPT_DIR/install-hooks.sh" ]]; then
24
- "$SCRIPT_DIR/install-hooks.sh" >/dev/null
25
- fi
26
-
27
- bump_version() {
28
- local current="$1" type="$2"
29
- IFS='.' read -r major minor patch <<< "$current"
30
- case "$type" in
31
- major) echo "$((major + 1)).0.0" ;;
32
- minor) echo "$major.$((minor + 1)).0" ;;
33
- patch) echo "$major.$minor.$((patch + 1))" ;;
34
- *) echo "$type" ;;
35
- esac
36
- }
37
-
38
- if [[ ! -f package.json ]]; then
39
- echo "Error: package.json not found in $REPO_ROOT" >&2
40
- exit 1
41
- fi
42
-
43
- CURRENT=$(jq -r .version package.json)
44
- NEXT=$(bump_version "$CURRENT" "$VERSION_ARG")
45
- BRANCH=$(git branch --show-current)
46
- LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
47
-
48
- echo "=== Version ==="
49
- echo "Current: $CURRENT"
50
- echo "Requested: $VERSION_ARG"
51
- echo "Next: $NEXT"
52
- echo "Branch: ${BRANCH:-"(detached)"}"
53
- if [[ -n "$LAST_TAG" ]]; then
54
- echo "Last tag: $LAST_TAG"
55
- else
56
- echo "Last tag: (none)"
57
- fi
58
- echo
59
-
60
- echo "=== Working tree ==="
61
- STATUS=$(git status --short)
62
- if [[ -z "$STATUS" ]]; then
63
- echo "(clean)"
64
- else
65
- printf '%s\n' "$STATUS"
66
- fi
67
- echo
68
-
69
- echo "=== Commits since last release ==="
70
- if [[ -n "$LAST_TAG" ]]; then
71
- COMMITS=$(git log --oneline "${LAST_TAG}..HEAD")
72
- if [[ -z "$COMMITS" ]]; then
73
- echo "(none since $LAST_TAG)"
74
- else
75
- printf '%s\n' "$COMMITS"
76
- fi
77
- else
78
- echo "(no tags)"
79
- git log --oneline
80
- fi
81
- echo
82
-
83
- echo "=== Files changed since last release ==="
84
- if [[ -n "$LAST_TAG" ]]; then
85
- FILES=$(git diff --name-only "${LAST_TAG}..HEAD")
86
- if [[ -z "$FILES" ]]; then
87
- echo "(none since $LAST_TAG)"
88
- else
89
- printf '%s\n' "$FILES"
90
- fi
91
- else
92
- echo "(no tags)"
93
- fi
94
- echo
95
-
96
- echo "=== CHANGELOG [Unreleased] ==="
97
- if [[ -f CHANGELOG.md ]]; then
98
- UNRELEASED=$(awk '
99
- /^## \[Unreleased\]/ { p=1; next }
100
- /^## \[/ { if (p) exit }
101
- p { print }
102
- ' CHANGELOG.md)
103
- TRIMMED=$(printf '%s' "$UNRELEASED" | sed '/^[[:space:]]*$/d')
104
- if [[ -z "$TRIMMED" ]]; then
105
- echo "(empty)"
106
- else
107
- printf '%s\n' "$UNRELEASED"
108
- fi
109
- else
110
- echo "(CHANGELOG.md not found)"
111
- fi
112
- echo
113
-
114
- echo "=== Previous release entry ==="
115
- if [[ -f CHANGELOG.md ]]; then
116
- PREVIOUS=$(awk '
117
- /^## \[Unreleased\]/ { next }
118
- /^## \[/ { if (p) exit; p=1 }
119
- p { print }
120
- ' CHANGELOG.md)
121
- TRIMMED=$(printf '%s' "$PREVIOUS" | sed '/^[[:space:]]*$/d')
122
- if [[ -z "$TRIMMED" ]]; then
123
- echo "(none)"
124
- else
125
- printf '%s\n' "$PREVIOUS"
126
- fi
127
- else
128
- echo "(CHANGELOG.md not found)"
129
- fi