From b827d06d9bbe8390ef9046df0402aca95170230c Mon Sep 17 00:00:00 2001 From: vitya Date: Wed, 20 May 2026 14:55:57 +0300 Subject: [PATCH] fix(using-yt-tools): resolve binaries via venv/winget fallback v0.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skill no longer aborts on bare `Get-Command yt-frames` miss — binaries installed in project-local venv or winget cache (Gyan.FFmpeg_*) are valid install sites, just not on PATH for fresh shells. New Step 0 in both flows: probe PATH first, then known install locations (venv Scripts/bin, winget Gyan.FFmpeg_*/ffmpeg-*-full_build/bin); abort only if both empty. PATH-prepend pattern documented (full-path to yt-frames.exe is insufficient — child yt-dlp/ffmpeg need prepend too). Failure modes table updated: removed 'restart CC session' advice — agent can't restart itself, and resolve-fallback makes it unnecessary. MINOR bump per project-discipline (behaviour change in resolve logic). --- skills/using-yt-tools/SKILL.md | 64 +++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/skills/using-yt-tools/SKILL.md b/skills/using-yt-tools/SKILL.md index 0030f1d..cbe5855 100644 --- a/skills/using-yt-tools/SKILL.md +++ b/skills/using-yt-tools/SKILL.md @@ -1,6 +1,6 @@ --- name: using-yt-tools -version: 0.2.3 +version: 0.3.0 description: Two flows for YouTube content. **Iterative-watch** (summary/exploration): transcript with [mm:ss] anchors → pick moments → extract frames. **Targeted-frames** (specific timestamps): extract frames directly, no transcript. Triggers: "что в ролике", "о чём видео", "video summary", "youtube transcript", "покажи кадр на N", или любой youtube.com URL. CLI в `~/projects/.common/lib/yt-tools/`. YouTube-only; для Vimeo/Twitch/local — другие тулзы. --- @@ -22,25 +22,51 @@ Iterative-watching YouTube для агента: clean-markdown транскри - Шаги: extract frames at given timestamps → Read frames. - Trigger phrases: «покажи кадр на N», «посмотри момент N», «что показано на N», «show frame at N». -Оба flow предполагают, что `yt-tools` CLI установлен из `~/projects/.common/lib/yt-tools/`. Если `yt-transcript` / `yt-frames` отсутствуют на PATH — abort с install-hint (см. Prerequisites). +Оба flow предполагают, что `yt-tools` CLI установлен из `~/projects/.common/lib/yt-tools/` (project-local venv). Бинари могут не быть на PATH текущей сессии — это норма, особенно после свежего `winget install`. **Никогда не abort'ить по голому `Get-Command yt-frames` / `which yt-frames`** — сначала прогнать резолв (см. Prerequisites → Locating binaries). ## Prerequisites -**CLI invocation** — один из двух вариантов (выбери по ситуации): +### Locating binaries -| Вариант | Команда | Trade-off | -|---|---|---| -| **A. Активация venv** | Windows: `& ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1`
Linux/macOS: `source ~/projects/.common/lib/yt-tools/.venv/bin/activate` | Одна команда, но меняет shell state | -| **B. Full-path** | `~/projects/.common/lib/yt-tools/.venv/Scripts/yt-frames.exe URL ...` (Windows)
`~/projects/.common/lib/yt-tools/.venv/bin/yt-frames URL ...` (Linux/macOS) | Изолированно, но длиннее в каждом вызове | +Скил ничего не предполагает про активный PATH. **Step 0 каждого flow** — резолв путей для `yt-frames`/`yt-transcript` и `ffmpeg` (+ `yt-dlp`, поставляется в том же venv). Если резолвится через fallback — используй PATH-prepend в каждом вызове (см. Invoke pattern ниже). Abort'ить **только** если бинаря нет ни на PATH, ни в известных install-локациях. -После активации или full-path доступны: -- `yt-transcript`, `yt-frames`, `yt-watch`, `yt-tools` +**yt-tools CLI** (один venv даёт все четыре: `yt-frames`, `yt-transcript`, `yt-watch`, `yt-tools`; туда же ставится `yt-dlp`): -**Внешние бинари** (любая ОС): -- `yt-dlp` — fetches metadata + source mp4 -- `ffmpeg` — muxes streams + extracts frames +1. PATH: `Get-Command yt-frames` (pwsh) / `command -v yt-frames` (bash) +2. Project-local venv: + - Windows: `~/projects/.common/lib/yt-tools/.venv/Scripts/yt-frames.exe` + - Linux/macOS: `~/projects/.common/lib/yt-tools/.venv/bin/yt-frames` +3. Если ни PATH, ни venv — install hint: `python -m venv ~/projects/.common/lib/yt-tools/.venv && ~/projects/.common/lib/yt-tools/.venv/{Scripts,bin}/pip install -e ~/projects/.common/lib/yt-tools/`; стоп. -Полный install per-OS — в `~/projects/.common/lib/yt-tools/README.md`. **Windows-gotcha:** после `winget install Gyan.FFmpeg` или `winget install yt-dlp.yt-dlp` нужен restart терминала (и Claude Code session) — winget пишет в per-user PATH, который текущий shell не перечитывает. +**ffmpeg**: + +1. PATH: `Get-Command ffmpeg` / `command -v ffmpeg` +2. Windows winget cache (версия плавающая, глобь): + `~/AppData/Local/Microsoft/WinGet/Packages/Gyan.FFmpeg_Microsoft.Winget.Source_*/ffmpeg-*-full_build/bin/ffmpeg.exe` +3. macOS Homebrew: `/opt/homebrew/bin/ffmpeg` (Apple Silicon) или `/usr/local/bin/ffmpeg` (Intel) +4. Linux: `/usr/bin/ffmpeg` (apt) или `/usr/local/bin/ffmpeg` +5. Если ни одна локация — install hint per-ОС (`winget install Gyan.FFmpeg` / `brew install ffmpeg` / `apt install ffmpeg`); стоп. **Не** проси юзера restart'ить CC — продолжай резолв-логику в той же сессии после установки, либо подскажи, что новой сессии PATH подхватится сам. + +### Invoke pattern + +`yt-frames` сам спавнит `yt-dlp` и `ffmpeg` через `subprocess.run([..., "ffmpeg", ...])` — full-path к самому `yt-frames.exe` **не хватит**, нужен PATH-prepend, чтобы child процессы тоже их видели. + +```bash +# bash / git-bash — после резолва через fallback +FFDIR=$(dirname "$(ls ~/AppData/Local/Microsoft/WinGet/Packages/Gyan.FFmpeg_*/ffmpeg-*-full_build/bin/ffmpeg.exe 2>/dev/null | head -1)") +YTBIN=~/projects/.common/lib/yt-tools/.venv/Scripts # /bin на Linux/macOS +PATH="$FFDIR:$YTBIN:$PATH" yt-frames --timestamps 1:23,4:56 +``` + +```powershell +# pwsh — glob по плавающей версии ffmpeg +$ff = (Get-ChildItem "$HOME\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_*\ffmpeg-*-full_build\bin\ffmpeg.exe" -ErrorAction SilentlyContinue | Select-Object -First 1).DirectoryName +$ytbin = "$HOME\projects\.common\lib\yt-tools\.venv\Scripts" +$env:PATH = "$ff;$ytbin;" + $env:PATH +yt-frames --timestamps 1:23,4:56 +``` + +Если оба нашлись напрямую на PATH (`Get-Command` вернул что-то) — pre-pend не нужен, зови как обычно. ## Inputs @@ -56,7 +82,7 @@ Iterative-watching YouTube для агента: clean-markdown транскри ### Flow A — iterative-watch ``` -0. Activate venv: & ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1 (Windows) или source ~/projects/.common/lib/yt-tools/.venv/bin/activate (Linux/macOS) +0. Резолв yt-frames + ffmpeg per Prerequisites → Locating binaries; собрать PATH-prepend если резолв через fallback 1. yt-transcript → ./yt-cache//transcript.md 2. Read transcript.md, find [mm:ss] anchors that match the question 3. yt-frames --timestamps 1:23,4:56,… → ./yt-cache//frames/frame_*.jpg @@ -64,8 +90,6 @@ Iterative-watching YouTube для агента: clean-markdown транскри 5. Answer the user, citing both transcript paragraph and frame contents ``` -Альтернатива: skip шаг 0, используй full-path в каждом вызове (см. Prerequisites). - **Stdout contract per CLI** (бери последнюю строку, формат зависит от CLI): - `yt-transcript`, `yt-watch` — одна строка на stdout: bare absolute path артефакта (`/transcript.md` или `/watch.md`). @@ -76,7 +100,7 @@ Warnings и errors уходят в stderr (`warning: …`, `error: …`); stdout ### Flow B — targeted-frames ``` -0. Activate venv: & ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1 (Windows) или source ~/projects/.common/lib/yt-tools/.venv/bin/activate (Linux/macOS) +0. Резолв yt-frames + ffmpeg per Prerequisites → Locating binaries; собрать PATH-prepend если резолв через fallback 1. Parse user's timestamps (mm:ss / h:mm:ss / bare seconds — все работают) 2. yt-frames --timestamps 1:23,4:56,… → ./yt-cache//frames/frame_*.jpg 3. Read each frame_*.jpg @@ -91,9 +115,9 @@ Warnings и errors уходят в stderr (`warning: …`, `error: …`); stdout | Symptom | Cause | Action | |---|---|---| -| `yt-transcript` / `yt-frames` not on PATH | yt-tools pkg не pip-installed | Скажи юзеру install per `~/projects/.common/lib/yt-tools/README.md`; стоп | -| `yt-dlp not found on PATH` | Внешний бин отсутствует | Дай install command для ОС юзера; стоп | -| `ffmpeg not found on PATH` | Внешний бин отсутствует | То же; на Windows после `winget install Gyan.FFmpeg` юзер должен restart терминала + CC session | +| `yt-transcript` / `yt-frames` not on PATH | yt-tools pkg не pip-installed **либо** venv создан, но не на PATH | Прогнать резолв per Prerequisites → Locating binaries. Abort только если и venv-локация пуста — тогда install-hint, стоп | +| `yt-dlp not found on PATH` (от child процесса) | `yt-dlp` есть в venv, но PATH-prepend не собран | Пересобери PATH-prepend (Prerequisites → Invoke pattern); `yt-dlp` ставится тем же `pip install -e` что и `yt-frames` | +| `ffmpeg not found on PATH` (от child процесса) | ffmpeg установлен, но в winget-кэше/Homebrew/etc., не на PATH сессии | Прогнать ffmpeg-резолв per Prerequisites, prepend в PATH. Abort только если ни одна локация не нашла бинаря — install per ОС. **Не** требовать restart CC session — резолв решает | | `yt-dlp source download failed (exit N) \| stderr: …` | Network / private / age-gated / region-locked / malformed URL | Выведи captured stderr verbatim; не retry | | `yt-dlp --dump-json failed` | То же, но на metadata step | То же | | `Subtitles disabled` от `youtube-transcript-api` | Канал отключил CC | Для Flow A это fatal — скажи юзеру, предложи Flow B с явными таймкодами если уместно |