From a655ceee192883b9ff9985987ec59f31701833b8 Mon Sep 17 00:00:00 2001 From: Sergei Aronsen Date: Thu, 21 May 2026 11:41:00 +0200 Subject: [PATCH] feat(skills-picker): render upstream GitHub URL after description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skills TUI picker now shows ` · ` after each row's description, sourced from manifest.json:skills_pins[*].repo + .commit + .path. Lets the user click through to the canonical upstream (in iTerm2 / modern terminals) or eyeball the source repo before installing. Changes: - scripts/lib/skills.sh: add `_skills_default_manifest_path` and `_skills_upstream_url `. Constructs `${repo}/tree/${commit}/${path}` (or shorter forms when commit/path missing). Returns empty for skills with `_status: "no-upstream-found"` (memo-skill) or skills absent from skills_pins (impeccable). Uses jq line-per-field output to dodge the Bash IFS-whitespace tab-collapse trap. - scripts/install.sh: populate `TUI_URLS[]` parallel to `TUI_LABELS[] / TUI_DESCS[]` in the skills branch. - scripts/lib/tui.sh: render ` · ${url}` after ` — ${desc}` when the TUI_URLS[] array is set and the row's entry is non-empty. Guarded by `${TUI_URLS[*]+x}` so MCP / TK pickers (which don't set the array) stay unaffected. No truncation policy in tui.sh — caller owns row width. Terminals that wrap will wrap; iTerm2 / Kitty / WezTerm hyperlink-detect the URL. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/install.sh | 3 +++ scripts/lib/skills.sh | 56 +++++++++++++++++++++++++++++++++++++++++++ scripts/lib/tui.sh | 13 ++++++++++ 3 files changed, 72 insertions(+) diff --git a/scripts/install.sh b/scripts/install.sh index 79a999e1..2ac5fac2 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1289,10 +1289,13 @@ if [[ "$SKILLS" -eq 1 ]]; then TUI_GROUPS=() # shellcheck disable=SC2034 TUI_DESCS=() + # shellcheck disable=SC2034 # consumed by tui_checklist for inline GitHub URL render + TUI_URLS=() local_total=${#SKILLS_CATALOG[@]} for ((i=0; i — return GitHub URL for a skill from manifest skills_pins. +# Construction: ${repo}/tree/${commit}/${path} when both commit + path present, +# ${repo}/tree/${commit} when only commit present, ${repo} when only repo present. +# Returns empty (no stdout) when: +# - manifest.json absent or unreadable +# - jq absent +# - skill name absent from skills_pins +# - skill marked _status: "no-upstream-found" (e.g. memo-skill) +# - repo field missing/empty +# Caller uses to render an inline GitHub link in the skills picker TUI. +_skills_upstream_url() { + local name="${1:-}" + [[ -z "$name" ]] && return 0 + command -v jq >/dev/null 2>&1 || return 0 + local manifest + manifest="$(_skills_default_manifest_path)" + [[ -f "$manifest" ]] || return 0 + + # Bash treats \t as IFS-whitespace — consecutive tabs collapse and leading + # tabs are skipped, so @tsv loses empty leading fields. Emit each field on + # its own line and read 4 lines instead. Also keeps URLs (which may contain + # `:` `/`) untouched. + local lines + lines=$(jq -r --arg n "$name" ' + .skills_pins[$n] // empty + | (.repo // ""), (.commit // ""), (.path // ""), (._status // "") + ' "$manifest" 2>/dev/null) || return 0 + [[ -z "$lines" ]] && return 0 + + local repo commit path status + { IFS= read -r repo + IFS= read -r commit + IFS= read -r path + IFS= read -r status + } <<<"$lines" + [[ "$status" == "no-upstream-found" ]] && return 0 + [[ -z "$repo" ]] && return 0 + + if [[ -n "$commit" && -n "$path" ]]; then + echo "${repo}/tree/${commit}/${path}" + elif [[ -n "$commit" ]]; then + echo "${repo}/tree/${commit}" + else + echo "$repo" + fi +} + # skills_catalog_names — print all skill names from SKILLS_CATALOG, one per line. skills_catalog_names() { printf '%s\n' "${SKILLS_CATALOG[@]}" diff --git a/scripts/lib/tui.sh b/scripts/lib/tui.sh index 300ec516..e9719997 100644 --- a/scripts/lib/tui.sh +++ b/scripts/lib/tui.sh @@ -191,6 +191,16 @@ _tui_render() { local required="${TUI_REQUIRED[$i]:-0}" local checked="${TUI_RESULTS[$i]:-0}" local desc="${TUI_DESCS[$i]:-}" + # Optional parallel array TUI_URLS[]; callers (skills picker) populate + # an upstream GitHub URL string per row. Empty when caller omits the + # array entirely (MCP / TK pickers) or per-row when no upstream is + # known (e.g. memo-skill in skills picker). Rendered after desc as + # ` · ${url}` when non-empty; tui itself adds no truncation — caller + # owns width policy. + local url="" + if [[ -n "${TUI_URLS[*]+x}" ]]; then + url="${TUI_URLS[$i]:-}" + fi local row_num=$((i + 1)) # Section header on group change — extra blank line above for clearer separation. @@ -268,6 +278,9 @@ _tui_render() { if [[ -n "$desc" ]]; then _label_render+=" — ${desc}" fi + if [[ -n "$url" ]]; then + _label_render+=" · ${url}" + fi # Immutable rows (installed/required) render dim so they read as # "disabled" — user knows space won't toggle them. Exception: # reinstall state is bright light-green (call-out, not dim) so