Pārlūkot izejas kodu

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
Tobi Lutke 3 mēneši atpakaļ
vecāks
revīzija
63f3b68559
4 mainītis faili ar 89 papildinājumiem un 65 dzēšanām
  1. 9 0
      CHANGELOG.md
  2. 32 17
      scripts/pre-push
  3. 35 43
      skills/release/SKILL.md
  4. 13 5
      src/qmd.ts

+ 9 - 0
CHANGELOG.md

@@ -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,

+ 32 - 17
scripts/pre-push

@@ -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

+ 35 - 43
skills/release/SKILL.md

@@ -16,34 +16,37 @@ 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.
 
-If any step fails, stop and explain. Never force-push or skip validation.
+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.
 
-### Writing the changelog from git history
+6. **Push** — after explicit confirmation, run `git push origin main --tags`.
 
-If `[Unreleased]` is empty when the release is triggered, populate it before
-continuing:
+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.
 
-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.
+If any step fails, stop and explain. Never force-push or skip validation.
 
 ## Changelog Standard
 
@@ -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
-
-Run `skills/release/scripts/install-hooks.sh` to install (also runs
-automatically via `bun install` prepare script).
-
-## Scripts
+3. CI passed on GitHub (warns in non-interactive shells, blocks in terminals)
 
-- [`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).

+ 13 - 5
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()}`);
 }