feat: show models in status, improve pre-push hook
- Move model info from --help to `qmd status` with live HuggingFace links derived from actual configured URIs - Pre-push hook: handle non-interactive shells gracefully, resolve annotated tags correctly for CI checks
This commit is contained in:
parent
8dd6cdcebf
commit
63f3b68559
@ -2,6 +2,15 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changes
|
||||
|
||||
- CLI: `qmd status` now shows models with full HuggingFace links instead of
|
||||
static names in `--help`. Model info is derived from the actual configured
|
||||
URIs so it stays accurate if models change.
|
||||
- Release tooling: pre-push hook handles non-interactive shells (CI, editors)
|
||||
gracefully — warnings auto-proceed instead of hanging on a tty prompt.
|
||||
Annotated tags now resolve correctly for CI checks.
|
||||
|
||||
## [1.0.5] - 2026-02-16
|
||||
|
||||
The npm package now ships compiled JavaScript instead of raw TypeScript,
|
||||
|
||||
@ -8,7 +8,28 @@ set -euo pipefail
|
||||
# 2. CHANGELOG.md has a "## [{version}] - {date}" entry
|
||||
# 3. CI passed upstream on GitHub for the tagged commit
|
||||
#
|
||||
# Installed automatically by: bun install (via prepare script)
|
||||
# In non-interactive shells (no tty), warnings auto-proceed instead of
|
||||
# prompting. Hard failures (version mismatch, missing changelog) always block.
|
||||
|
||||
# Detect if we can prompt
|
||||
CAN_PROMPT=false
|
||||
if [[ -t 0 ]] || [[ -e /dev/tty ]]; then
|
||||
# Verify /dev/tty is actually usable
|
||||
if echo -n "" > /dev/tty 2>/dev/null; then
|
||||
CAN_PROMPT=true
|
||||
fi
|
||||
fi
|
||||
|
||||
prompt_or_continue() {
|
||||
local msg="$1"
|
||||
if $CAN_PROMPT; then
|
||||
read -p "$msg [y/N] " -n 1 -r </dev/tty
|
||||
echo ""
|
||||
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
|
||||
else
|
||||
echo "$msg — auto-proceeding (non-interactive)"
|
||||
fi
|
||||
}
|
||||
|
||||
while read -r local_ref local_sha remote_ref remote_sha; do
|
||||
# Only validate v* tag pushes
|
||||
@ -34,7 +55,7 @@ while read -r local_ref local_sha remote_ref remote_sha; do
|
||||
echo "Run: jq --arg v '$VERSION' '.version = \$v' package.json > tmp && mv tmp package.json"
|
||||
exit 1
|
||||
fi
|
||||
echo " package.json version: $PKG_VERSION"
|
||||
echo " package.json version: $PKG_VERSION ✓"
|
||||
|
||||
# --- 2. CHANGELOG.md must have an entry for this version ---
|
||||
if [[ ! -f CHANGELOG.md ]]; then
|
||||
@ -51,17 +72,17 @@ while read -r local_ref local_sha remote_ref remote_sha; do
|
||||
echo "Write the changelog entry first. See CLAUDE.md for guidelines."
|
||||
exit 1
|
||||
fi
|
||||
echo " CHANGELOG.md: entry found"
|
||||
echo " CHANGELOG.md: entry found ✓"
|
||||
|
||||
# --- 3. CI must have passed on GitHub for this commit ---
|
||||
COMMIT=$(git rev-parse "$TAG" 2>/dev/null || git rev-parse HEAD)
|
||||
# Resolve annotated tag to its underlying commit
|
||||
COMMIT=$(git rev-list -n 1 "$TAG" 2>/dev/null || git rev-parse HEAD)
|
||||
|
||||
if ! command -v gh &>/dev/null; then
|
||||
echo " CI check: skipped (gh CLI not installed)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check GitHub Actions check runs
|
||||
CHECK_JSON=$(gh api "repos/{owner}/{repo}/commits/$COMMIT/check-runs" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -z "$CHECK_JSON" ]]; then
|
||||
@ -72,17 +93,13 @@ while read -r local_ref local_sha remote_ref remote_sha; do
|
||||
TOTAL=$(echo "$CHECK_JSON" | jq -r '.total_count // 0' 2>/dev/null || echo "0")
|
||||
|
||||
if [[ "$TOTAL" -eq 0 ]] 2>/dev/null; then
|
||||
# No checks found — commit may not be pushed yet
|
||||
MAIN_SHA=$(git rev-parse origin/main 2>/dev/null || echo "")
|
||||
if [[ "$COMMIT" != "$MAIN_SHA" ]]; then
|
||||
echo ""
|
||||
echo "WARNING: No CI runs found for $COMMIT and it's not the tip of origin/main."
|
||||
echo "Push the commit to main first and wait for CI to pass."
|
||||
read -p "Push tag anyway? [y/N] " -n 1 -r </dev/tty
|
||||
echo ""
|
||||
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
|
||||
echo "WARNING: No CI runs found for $COMMIT"
|
||||
prompt_or_continue "Push tag anyway?"
|
||||
else
|
||||
echo " CI check: no runs found (commit is on main)"
|
||||
echo " CI check: no runs yet (commit is tip of origin/main)"
|
||||
fi
|
||||
else
|
||||
FAILED=$(echo "$CHECK_JSON" | jq '[.check_runs // [] | .[] | select(.conclusion == "failure")] | length' 2>/dev/null || echo "0")
|
||||
@ -98,15 +115,13 @@ while read -r local_ref local_sha remote_ref remote_sha; do
|
||||
if [[ "$PENDING" -gt 0 ]] 2>/dev/null; then
|
||||
echo ""
|
||||
echo "WARNING: CI still running for commit $COMMIT ($PENDING pending)"
|
||||
read -p "Push tag anyway? [y/N] " -n 1 -r </dev/tty
|
||||
echo ""
|
||||
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
|
||||
prompt_or_continue "Push tag anyway?"
|
||||
else
|
||||
echo " CI check: all passed"
|
||||
echo " CI check: all passed ✓"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "All checks passed for $TAG"
|
||||
echo "All checks passed for $TAG ✓"
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
||||
@ -16,35 +16,38 @@ Cut a release, validate the changelog, and ensure git hooks are installed.
|
||||
|
||||
When the user triggers `/release <version>`:
|
||||
|
||||
1. **Install hooks** — run `scripts/install-hooks.sh` (idempotent)
|
||||
2. **Check for unstaged work** — run `git status`. If there are valuable
|
||||
unstaged/uncommitted changes that belong in this release, commit them
|
||||
first (use the commit skill or make well-formed commits directly).
|
||||
3. **Validate changelog** — check if `## [Unreleased]` has content.
|
||||
If empty or missing, **write the changelog now** (see below).
|
||||
4. **Preview** — show the user what will be released (unreleased content +
|
||||
minor series rollup via `scripts/extract-changelog.sh`)
|
||||
5. **Ask for confirmation** — do NOT proceed without explicit user approval
|
||||
6. **Run `scripts/release.sh <version>`** — renames `[Unreleased]`, bumps
|
||||
version, commits, tags
|
||||
7. **Remind** — tell the user to `git push origin main --tags`
|
||||
1. **Gather context** — run `skills/release/scripts/release-context.sh <version>`.
|
||||
This silently installs git hooks and prints everything needed: version info,
|
||||
working directory status, commits since last release, files changed, current
|
||||
`[Unreleased]` content, and the previous release entry for style reference.
|
||||
|
||||
2. **Commit outstanding work** — if the context shows staged, modified, or
|
||||
untracked files that belong in this release, commit them first. Use the
|
||||
/commit skill or make well-formed commits directly.
|
||||
|
||||
3. **Write the changelog** — if `[Unreleased]` is empty, write it now using
|
||||
the commits and file changes from the context output. Follow the changelog
|
||||
standard below. Re-run the context script after committing if needed.
|
||||
|
||||
4. **Cut the release** — run `scripts/release.sh <version>`. This renames
|
||||
`[Unreleased]` → `[X.Y.Z] - date`, inserts a fresh `[Unreleased]`,
|
||||
bumps `package.json`, commits, and tags.
|
||||
|
||||
5. **Show the final changelog** — print the full `[Unreleased]` +
|
||||
minor series rollup via `scripts/extract-changelog.sh <version>`.
|
||||
Ask the user to confirm before pushing.
|
||||
|
||||
6. **Push** — after explicit confirmation, run `git push origin main --tags`.
|
||||
|
||||
7. **Watch CI** — after the push, start a background dispatch to watch the
|
||||
publish workflow. Use `interactive_shell` in dispatch mode with:
|
||||
```
|
||||
gh run watch $(gh run list --workflow=publish.yml --limit=1 --json databaseId --jq '.[0].databaseId') --exit-status
|
||||
```
|
||||
The agent will be notified when CI completes and should report the result.
|
||||
|
||||
If any step fails, stop and explain. Never force-push or skip validation.
|
||||
|
||||
### Writing the changelog from git history
|
||||
|
||||
If `[Unreleased]` is empty when the release is triggered, populate it before
|
||||
continuing:
|
||||
|
||||
1. Find the last release tag: `git describe --tags --abbrev=0`
|
||||
2. Review commits since then: `git log <tag>..HEAD --oneline`
|
||||
3. Read the diffs for anything non-obvious: `git log <tag>..HEAD --stat`
|
||||
4. Write changelog entries following the standard below — group by theme,
|
||||
explain the why, include numbers, credit contributors.
|
||||
5. Add optional prose highlights (1-4 sentences) if the release warrants it.
|
||||
6. Write the entries into `## [Unreleased]` in CHANGELOG.md.
|
||||
7. Commit the changelog update, then continue with the release.
|
||||
|
||||
## Changelog Standard
|
||||
|
||||
The changelog lives in `CHANGELOG.md` and follows [Keep a Changelog](https://keepachangelog.com/) conventions.
|
||||
@ -54,18 +57,15 @@ The changelog lives in `CHANGELOG.md` and follows [Keep a Changelog](https://kee
|
||||
- `## [Unreleased]` — accumulates entries between releases
|
||||
- `## [X.Y.Z] - YYYY-MM-DD` — released versions
|
||||
|
||||
The release script renames `[Unreleased]` → `[X.Y.Z] - date` and inserts a
|
||||
fresh empty `[Unreleased]` section automatically.
|
||||
|
||||
### Structure of a release entry
|
||||
|
||||
Each version entry has two parts:
|
||||
|
||||
**1. Highlights (optional, 1-4 sentences of prose)**
|
||||
|
||||
Immediately after the version heading, before any `###` section. This is the
|
||||
elevator pitch — what would you tell someone in 30 seconds? Only include for
|
||||
releases with significant changes. Skip for small patches.
|
||||
Immediately after the version heading, before any `###` section. The elevator
|
||||
pitch — what would you tell someone in 30 seconds? Only for significant
|
||||
releases; skip for small patches.
|
||||
|
||||
```markdown
|
||||
## [1.1.0] - 2026-03-01
|
||||
@ -110,8 +110,7 @@ through parallel contexts. GPU auto-detection replaces the unreliable
|
||||
## GitHub Release Notes
|
||||
|
||||
Each GitHub release includes the full changelog for the **minor series** back
|
||||
to x.x.0. Releasing v1.2.3 includes entries for 1.2.3, 1.2.2, 1.2.1, and
|
||||
1.2.0. The `scripts/extract-changelog.sh` script handles this, and the
|
||||
to x.x.0. The `scripts/extract-changelog.sh` script handles this, and the
|
||||
publish workflow (`publish.yml`) calls it to populate the GitHub release.
|
||||
|
||||
## Git Hooks
|
||||
@ -120,15 +119,8 @@ The pre-push hook (`scripts/pre-push`) blocks `v*` tag pushes unless:
|
||||
|
||||
1. `package.json` version matches the tag
|
||||
2. `CHANGELOG.md` has a `## [X.Y.Z] - date` entry for the version
|
||||
3. CI passed on GitHub for the tagged commit
|
||||
3. CI passed on GitHub (warns in non-interactive shells, blocks in terminals)
|
||||
|
||||
Run `skills/release/scripts/install-hooks.sh` to install (also runs
|
||||
automatically via `bun install` prepare script).
|
||||
|
||||
## Scripts
|
||||
|
||||
- [`scripts/install-hooks.sh`](scripts/install-hooks.sh) — install/update git hooks
|
||||
- Project scripts used during release:
|
||||
- `scripts/release.sh` — rename [Unreleased], bump version, commit, tag
|
||||
- `scripts/extract-changelog.sh` — extract minor series notes for GitHub release
|
||||
- `scripts/pre-push` — pre-push validation hook
|
||||
Hooks are installed silently by the context script. They can also be installed
|
||||
manually via `skills/release/scripts/install-hooks.sh` or automatically via
|
||||
`bun install` (prepare script).
|
||||
|
||||
18
src/qmd.ts
18
src/qmd.ts
@ -365,6 +365,19 @@ async function showStatus(): Promise<void> {
|
||||
console.log(`\n${c.dim}No collections. Run 'qmd collection add .' to index markdown files.${c.reset}`);
|
||||
}
|
||||
|
||||
// Models
|
||||
{
|
||||
// hf:org/repo/file.gguf → https://huggingface.co/org/repo
|
||||
const hfLink = (uri: string) => {
|
||||
const match = uri.match(/^hf:([^/]+\/[^/]+)\//);
|
||||
return match ? `https://huggingface.co/${match[1]}` : uri;
|
||||
};
|
||||
console.log(`\n${c.bold}Models${c.reset}`);
|
||||
console.log(` Embedding: ${hfLink(DEFAULT_EMBED_MODEL_URI)}`);
|
||||
console.log(` Reranking: ${hfLink(DEFAULT_RERANK_MODEL_URI)}`);
|
||||
console.log(` Generation: ${hfLink(DEFAULT_GENERATE_MODEL_URI)}`);
|
||||
}
|
||||
|
||||
// Device / GPU info
|
||||
try {
|
||||
const llm = getDefaultLlamaCpp();
|
||||
@ -2182,11 +2195,6 @@ function showHelp(): void {
|
||||
console.log(" --max-bytes <num> - Skip files larger than N bytes (default: 10240)");
|
||||
console.log(" --json/--csv/--md/--xml/--files - Output format (same as search)");
|
||||
console.log("");
|
||||
console.log("Models (auto-downloaded from HuggingFace):");
|
||||
console.log(" Embedding: embeddinggemma-300M-Q8_0");
|
||||
console.log(" Reranking: qwen3-reranker-0.6b-q8_0");
|
||||
console.log(" Generation: Qwen3-0.6B-Q8_0");
|
||||
console.log("");
|
||||
console.log(`Index: ${getDbPath()}`);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user