Бесплатный интерактивный курс · aicoding.space
Демонстрации, которые не надо переснимать
Практический курс по паку @dzhechkov/skills-demo-publisher для инженера, которому раз за разом приходится показывать продукт руками. Вместе с Лерой ты опишешь показ продукта в JSON, снимешь его локальным Chromium, соберёшь видео с русскими подписями, построишь статический сайт без единого скрипта, удержишь бюджет байтов и выложишь результат на GitHub Pages — но только после санкции владельца и живой квитанции по фактическим байтам.
Содержание курса
1. Почему показ продукта стоит собирать, а не переснимать
Что делает @dzhechkov/skills-demo-publisher одной фразой — и почему это не «ещё один экранный рекордер».
Ключевая мысль: повторяемая демонстрация из описанного сценария
Лера снимает показ продукта руками третий релиз подряд. Путь один и тот же, а видео каждый раз другое: то курсор дёрнулся, то всплыло уведомление, то она забыла показать главный экран. К пятнице выясняется, что в продукте переехала кнопка — и всё надо переснимать.
Пак решает ровно одну задачу: повторяемая демонстрация из описанного сценария. Ты записываешь в JSON, что делает пользователь и какими словами это подписать. Дальше пак сам открывает браузер, ведёт курсор, снимает кадр после каждого действия, собирает видео с русскими подписями и строит статический сайт, который можно выложить.
Что меняется на практике:
- показ становится результатом сборки, а не подвигом: запустил заново — получил то же самое;
- продукт изменился — правишь несколько строк сценария, а не переснимаешь двадцать минут;
- ошибку в показе видно в различиях JSON, а не только глазами на видео.
И ещё одно, менее очевидное. Раз показ описан текстом, его можно проверять машиной: схема ловит опечатку в сценарии, гейт размера ловит раздутое видео, проверка сайта ловит внешнюю ссылку. Живой человек эти три вещи заметит в лучшем случае через раз.
Компромисс: ты платишь описанием сценария вперёд — это дороже, чем один раз нажать «запись». Окупается со второго прогона, а на разовое видео «для себя» пак брать незачем.
2. Рабочее место: ffmpeg, Chromium и SKILL_ROOT
Три предустановки, одна переменная и первая команда, которая должна ответить квитанцией.
Ключевая мысль: SKILL_ROOT указывает на каталог навыка
Первое, обо что Лера споткнулась: она вызвала скрипт как node scripts/record-demo.mjs из корня своего проекта — и получила «файл не найден». Скрипты живут не в её проекте, а внутри пака.
Поэтому всё начинается с одной переменной: SKILL_ROOT указывает на каталог навыка — тот, где лежит SKILL.md. Все команды курса пишутся через неё, и тогда они одинаково работают и из корня проекта, и из подкаталога.
Подготовка занимает три строки:
apt install ffmpeg— сборка видео и проверка профиля;npm install— зависимости пакета;npx playwright install chromium— браузер, которым ведётся запись.
Потом задаёшь переменную и делаешь первый вызов:
SKILL_ROOT="$PWD/demo-site-publisher"
node "$SKILL_ROOT/scripts/preflight.mjs"Ответ должен быть положительной квитанцией — строкой, которая начинается с галочки и называет версию ffmpeg и путь к Chromium. Молчание — это не успех: если строки нет, значит команда до конца не дошла.
Где взять сам пакет:
Дальше по README идёт полный путь из шести команд: запись, карточки, монтаж, сайт, гейт размера. Публикации в этом списке нет намеренно — она требует решения владельца, и мы дойдём до неё в секции 12.
Компромисс: тяжёлые внешние зависимости (полный ffmpeg и настоящий браузер) — это лишние сотни мегабайт на машине; зато сборка идёт локально, без облачных сервисов и без загрузки чужих экранов на сторону.
3. Два входных файла, и почему их именно два
demo.json описывает человека, demo-site.config.json — технику. Смешаешь — получишь отказ схемы.
Ключевая мысль: сценарий отделён от кодирования и лимитов
Лера попробовала описать всё в одном файле: и шаги пользователя, и качество сжатия. Схема отказала и назвала точное место: «это поле принадлежит demo-site.config.json».
Это не придирка, а несущее решение пака: сценарий отделён от кодирования и лимитов.
demo.json— про человека: слаг набора, заголовок, цель, базовый адрес и сценарии со словами подписей;demo-site.config.json— про технику: имя набора, размер кадра, качество сжатия, частота кадров и бюджеты байтов и секунд.
Зачем такое разделение. Эти два файла меняются по разным причинам и разными людьми. Сценарий переписывают, когда изменился продукт, — часто. Профиль кодирования трогают, когда изменились требования площадки, — редко. Держать их вместе значит каждый раз перечитывать чужие поля и рисковать задеть их случайно.
Чтобы это правило нельзя было обойти по невнимательности, оно закреплено машинно: поля budget, encode и viewport внутри demo.json вызывают отказ разбора, а не молчаливое игнорирование. Разница принципиальная: проигнорированное поле — это настройка, которая никогда не сработала, и автор, который так и не узнал почему.
Границы значений тоже не советы, а правила: качество сжатия принимается только в диапазоне 26..40, частота кадров зафиксирована на 30, размер кадра допускается один из трёх (1280×800, 1280×720, 1920×1080), а поднять лимит на один файл выше 100 МБ нельзя — это потолок самого GitHub.
Компромисс: два файла вместо одного — это лишний файл в репозитории и лишний аргумент в каждой команде; взамен ты получаешь два независимых цикла правок и невозможность случайно поменять кодирование, редактируя текст подписи.
4. Шесть стадий и цепочка квитанций
Предполёт, запись, монтаж, сайт, бюджет, публикация — и почему порядок не переставляется.
Ключевая мысль: провал стадии обесценивает все квитанции ниже
Лера пересобрала видео и решила не перезапускать гейт размера: «отчёт же был зелёный полчаса назад». Отчёт действительно был зелёный — только про другие байты.
Поэтому у пака есть жёсткое правило: провал стадии обесценивает все квитанции ниже. Квитанция — это напечатанная строка «✓ имя стадии — подробности», подтверждающая, что стадия дошла до конца. Каждая следующая стадия опирается на выход предыдущей, поэтому переделал верхнюю — переделывай и всё, что под ней.
Шесть стадий по порядку:
- Предполёт — есть ли ffmpeg с нужными фильтрами и Chromium;
- Запись — браузер проходит сценарий и сохраняет кадры;
- Монтаж — из клипов и карточек собирается один MP4 с подписями;
- Сайт — оглавление, страница демонстрации и каталог с видео;
- Бюджет — файлы и длительности укладываются в лимиты;
- Публикация — выкладка после санкции владельца и живая проверка.
Обрати внимание на важную деталь хранения: сырые записи браузера остаются вне сайта, а в публичный набор попадают только итоговый MP4 и, если он включён, WebM. Черновики не должны утекать в публичное место просто потому, что лежали рядом.
Компромисс: строгая цепочка означает, что после правки одного кадра придётся перегнать всё, что ниже, — это время. Взамен ни одна квитанция никогда не описывает состояние, которого уже нет.
5. Предполёт: отказ вместо тихой деградации
Проверка фильтров, кодеков и браузера до первого кадра — и почему «сделаем как получится» здесь запрещено.
Ключевая мысль: отсутствующая возможность — это отказ, а не деградация
Сюрприз, который Лера не ожидала: на её ноутбуке стоял ffmpeg — и предполёт всё равно отказал. Оказалось, это была урезанная сборка без фильтра overlay, а без него подписи не лягут поверх кадра.
Отсюда правило: отсутствующая возможность — это отказ, а не деградация. Пак не пытается «собрать как получится» из того, что нашлось. Он заранее перечисляет, что ему нужно, и проверяет каждый пункт живым вызовом:
- восемь фильтров:
scale,pad,fps,format,setpts,fade,overlay,concat; - кодировщик
libx264(иlibvpx-vp9дополнительно, если набор просит WebM); - контейнер
mp4на запись иconcatна чтение; ffprobe— им проверяется профиль готового файла;- исполняемый Chromium.
Почему это лучше молчаливой подстройки. Молчаливая подстройка даёт видео, которое выглядит почти нормально, — и никто не узнает, что подписи не наложились, пока результат не увидит зритель. Громкий отказ на первой секунде стоит одну команду apt install ffmpeg.
Отказ ещё и адресный: сообщение перечисляет имена недостающих возможностей и подсказывает, что поставить. Это разница между «что-то не так» и «поставь полный ffmpeg, у тебя нет overlay».
Компромисс: на нестандартном образе предполёт может отказать там, где сборка в принципе прошла бы; зато сборка, которая началась, уже не упадёт на середине из-за отсутствующего кодировщика.
6. Сценарий: ровно одно действие на шаг
Девять действий, устойчивые селекторы и разбор схемы до того, как откроется браузер.
Ключевая мысль: ровно одно действие на шаг, схема проверяется до браузера
Лера написала шаг, который сразу и переходит на страницу, и нажимает кнопку: экономия строки. Разбор отказал, назвав адрес $.scenarios[0].steps[0].
Правило звучит так: ровно одно действие на шаг, схема проверяется до браузера. Обе половины этого правила стоят объяснения.
Почему одно действие. Каждый шаг превращается в кадр и в отметку времени на дорожке подписей. Два действия в одном шаге — это один кадр на два события: зритель не увидит, что произошло между ними, а ты не сможешь показать пальцем, где именно сломалось.
Почему до браузера. Разбор схемы стоит миллисекунды, запуск браузера — секунды и мегабайты. Дешёвая проверка обязана идти первой, а её сообщение обязано называть точный путь в JSON, который надо исправить, — иначе ты ищешь опечатку глазами.
Что можно положить в шаг: переход, наведение с нажатием, обычное нажатие, заполнение поля, посимвольный ввод, нажатие клавиши, ожидание, снимок экрана и подпись. Девять действий, и ни одно из них не «сделай всё сразу».
Ещё три требования, которые легко забыть:
- слаг набора — короткое имя из строчных букв и дефисов, не длиннее 40 символов;
- идентификатор сценария начинается с двух цифр:
01-open-page,02-fill-form— так порядок виден в имени; - селекторы лучше брать устойчивые (
data-testid), а не завязанные на верстку: перекрашенная кнопка не должна ломать показ.
Компромисс: описание становится многословнее, чем «нажми сюда и туда»; взамен каждый кадр соответствует ровно одному событию, а ошибка в сценарии называет свой адрес сама.
7. Запись: курсор, кадры и герметичный прогон
Видимый курсор, снимок после каждого действия и режим, в котором внешняя сеть недоступна, а петля обязана открыться.
Ключевая мысль: offline разрешает петлю и запрещает внешнюю сеть
Лера пересмотрела своё первое видео и растерялась: действия на экране происходят, а понять, куда именно нажали, невозможно — курсора в записи браузера нет.
Поэтому запись делает три вещи, которых обычный прогон браузера не делает: рисует видимый указатель, добавляет вспышку на месте нажатия и сохраняет PNG после каждого действия. Кадры потом становятся и материалом для проверки, и опорой при разборе, если шаг не сработал.
Каждый сценарий пишется в собственном окне браузера размером 1280×800 — чтобы соседний сценарий не притащил своё состояние. Результат описывается в recording-manifest.json: список сценариев, их отметки времени и пути к кадрам.
Теперь про герметичность. Флаг --offline включает режим, в котором offline разрешает петлю и запрещает внешнюю сеть. Формулировка нарочно точная: «offline» здесь не значит «ничего не доступно». Локальный адрес 127.0.0.1 обязан открываться — именно там живёт твой продукт во время записи; всё остальное отбивается. Такой режим делает прогон повторяемым: чужая аналитика или шрифт со стороны больше не влияют ни на кадры, ни на длительность.
И важное про честность: если селектор не нашёлся, сценарий помечается как ошибочный, и успешной записи для него не появляется. Не будет «почти получилось» — будет отказ с именем сценария.
Команда записи выглядит так:
node "$SKILL_ROOT/scripts/record-demo.mjs" --demo demo.json --config demo-site.config.json --out out/recording --offlineКомпромисс: герметичный режим не покажет продукт, который по-настоящему ходит во внешние сервисы, — такой показ придётся снимать без флага и мириться с непостоянством; зато локальный прогон повторяется от раза к разу.
8. Монтаж: один профиль и русские подписи
H.264, yuv420p, 30 кадров, без звука — и длинный клип, который ускоряют, а не режут.
Ключевая мысль: длинный клип ускоряется, а не обрезается
Лера сняла сценарий, который занял 40 секунд, а лимит на клип — 32. Она приготовилась вырезать «лишнее» и потерять концовку. Резать не пришлось.
Правило монтажа: длинный клип ускоряется, а не обрезается. Это осознанный выбор в пользу смысла: обрезка молча теряет то, что происходило в конце, а ускорение сохраняет все события — просто показывает их быстрее. Зритель видит весь путь целиком, а бюджет секунд соблюдён.
Второе решение — единый профиль. Все сегменты приводятся к одному виду: кодек H.264, формат пикселей yuv420p, 30 кадров в секунду, звука нет. Профиль проверяется перед склейкой, а не после: склеивать разнородные куски — верный способ получить файл, который часть плееров откроет, а часть нет.
Монтаж собирается из двух видов материала: карточки (заставка, название сценария, финал) и сами клипы. Подпись накладывается поверх кадра картинкой, а не системным субтитром, — так она гарантированно выглядит одинаково везде.
Вместе с видео появляется текст подписей в двух форматах: SRT и русский WebVTT. Это не украшение — WebVTT становится дорожкой субтитров на странице, а SRT остаётся для внешних инструментов.
Если набор просит WebM, рядом собирается второй файл в VP9. Он необязателен и включается настройкой набора.
Компромисс: ускоренный фрагмент читается тяжелее оригинального темпа, и очень длинный сценарий лучше просто разбить на два; зато ни одно действие не исчезает из показа молча.
9. Сайт без скриптов и без внешних ресурсов
Нативное видео, включённая русская дорожка, встроенные стили и текстовая расшифровка как обязательная часть.
Ключевая мысль: страница демонстрации живёт без JavaScript и без внешних ресурсов
Лера предложила добавить на страницу удобный плеер со стороннего сервиса. Проверка сайта отклонила бы такую страницу — и в этом её смысл.
Правило: страница демонстрации живёт без JavaScript и без внешних ресурсов. Никаких скриптов, никаких подключаемых шрифтов, никаких ссылок наружу — только собственные файлы набора. Причин три:
- страница открывается всегда, даже когда сторонний сервис лежит или заблокирован;
- просмотр демонстрации ничего не сообщает третьим сторонам;
- страница остаётся байт в байт такой же при пересборке — а значит, различия в ней означают реальные изменения, а не случайный мусор.
Что собирается: оглавление набора, отдельная страница на каждую демонстрацию и каталог с видео. На странице — нативный элемент <video>, включённая по умолчанию русская дорожка субтитров, встроенные стили прямо в документе и текстовая расшифровка: список сценариев с их подписями.
Расшифровка — не приложение к видео, а полноправная часть страницы. Она делает показ доступным тем, кто не может или не хочет смотреть видео, и превращает демонстрацию в текст, который ищется поиском. Ровно так же обязательна и дорожка субтитров.
Проверка сайта смотрит на четыре вещи: замкнут ли HTML, нет ли скрипта на странице демонстрации, нет ли внешних ссылок и стилей, ведёт ли каждая ссылка на существующий файл внутри набора. Отдельно ловится обратный случай — видео, на которое не ссылается ни одна страница: такой файл занимал бы байты и не показывался бы никому.
Компромисс: без скриптов не сделать интерактива — ни главы, ни поиск по показу; взамен страница переживает любой сбой на стороне и не следит за зрителем.
10. Бюджет байтов и отчёт, который протухает
Пять лимитов, отпечаток медиафайлов и правило: поменял байты — старый отчёт мёртв.
Ключевая мысль: отчёт бюджета недействителен после смены медиабайтов
Лера получила зелёный отчёт бюджета, потом пересобрала монтаж «чуть-чуть по-другому» и пошла публиковать со старым отчётом. Публикация отказала.
Правило: отчёт бюджета недействителен после смены медиабайтов. Отчёт содержит отпечаток всех медиафайлов набора; перед публикацией отпечаток считается заново и сравнивается. Не совпал — отчёт про другие байты, и его вердикт ничего не говорит о том, что ты собираешься выложить.
Сами лимиты по умолчанию:
- 20 МБ на один файл;
- 100 МБ на весь набор;
- 32 секунды на клип;
- 240 секунд на монтаж;
- 900 МБ — предельный размер репозитория после выкладки.
Первые два держатся заметно ниже потолков GitHub: платформа предупреждает на файлах больше 50 МиБ и блокирует файлы больше 100 МиБ, а для исходного репозитория рекомендует держаться в пределах 1 ГБ. Запас нужен для того, чтобы отказ приходил от твоего гейта на твоей машине, а не от чужого сервера в момент отправки.
Лимит на один файл нельзя поднять выше 100 МБ никакой настройкой — это потолок платформы, а не предпочтение. Остальные лимиты можно только опустить: значение из конфигурации применяется, если оно строже значения по умолчанию.
Теперь остановись на секунду и спроси себя: сколько раз ты видел «зелёный» отчёт, который на самом деле описывал прошлое состояние? Именно эту ошибку здесь закрыли машинно, а не соглашением.
Компромисс: после каждой пересборки видео гейт приходится гонять заново — это время; зато ни один вердикт никогда не относится к байтам, которых уже нет.
11. Публикация: порядок, который нельзя переставить
Шесть проверок до первой команды git — и живая квитанция по фактическим байтам страницы и видео.
Ключевая мысль: публикация проверяется по фактическим байтам живой страницы
Лера отправила набор и увидела «push ok». Через час коллега написал, что на странице крутится вечная загрузка: видео на сервер не доехало. Отправка прошла — показ не появился.
Отсюда самое важное правило этой секции: публикация проверяется по фактическим байтам живой страницы. Успешная отправка ничего не доказывает; доказывает только ответ настоящего сервера.
Проверка живого адреса устроена так:
- страница
index.htmlскачивается и сравнивается по контрольной сумме с локальной — не «открылась», а совпала побайтно; - для каждого видеофайла запрашивается только заголовок ответа, и объявленная длина сравнивается с реальным размером файла;
- если совпадения ещё нет, проверка повторяется несколько раз с паузами — площадка выкладывает страницы не мгновенно.
Если квитанции так и нет, скрипт печатает готовую команду отката. Это тоже намеренно: в момент неудачи проще выполнить напечатанную команду, чем гадать, какая из отправок доехала.
До того, как будет вызвана хоть одна команда git, проходит шесть проверок: правильность сайта, отсутствие запрещённых идентификаторов, свежий отчёт бюджета, повторный прогон гейта размера, проекция размера репозитория после выкладки и — первой из всех — проверка политики и санкции, о которой следующая секция.
Компромисс: живая проверка занимает минуты ожидания и требует доступа к сети; зато «опубликовано» означает «зритель это видит», а не «отправка завершилась без ошибки».
12. Санкция владельца и закрытые слаги
Публичная выкладка — решение человека; шесть шаблонов слагов отклоняются машинно, до всякого решения.
Ключевая мысль: санкция владельца обязательна, конфиденциальный слаг отклоняется
Здесь решаешь ты, а не пак. Лера подготовила набор, все гейты зелёные — и дальше нужен человек, который скажет «выкладываем».
Правило: санкция владельца обязательна, конфиденциальный слаг отклоняется. Это две разные защиты, и полезно понимать, чем они отличаются.
Санкция — текст решения, который передаётся флагом --sanction и сохраняется рядом с набором вместе с датой. Пустая строка не считается решением. Смысл не в том, чтобы усложнить команду, а в том, чтобы у публичной выкладки был названный автор и записанное основание.
Политика слагов — машинный запрет. Шесть шаблонов имён (^talk-, ^workshop-, ^genai-, ^health-, ^ha-, ^tg-post) отклоняются независимо от любой санкции: это материалы докладов, мастерских и закрытых тем, которым в публичном месте не место. Проверка идёт не только по имени набора, но и по слагу каждой демонстрации внутри него — иначе один закрытый показ уехал бы наружу вместе с открытым набором.
Обрати внимание на порядок: политика проверяется раньше санкции. Санкцией нельзя разрешить то, что запрещено политикой, — иначе запрет был бы просто вопросом настойчивости.
Команда выглядит так:
node "$SKILL_ROOT/scripts/publish-demo.mjs" --site out/demo-site/my-set --config demo-site.config.json --sanction "владелец разрешил публикацию набора"А пока решение не принято, есть безопасный режим --dry-run: он прогоняет все проверки и печатает, что произошло бы, но не вызывает ни одной команды git.
Компромисс: список закрытых шаблонов приходится поддерживать руками, и он всегда неполон — он ловит известные категории, а не всякую тайну; зато самые вероятные утечки закрыты машинно, а не памятью человека.
13. Язык отказов: коды выхода и «ответа не получено»
Девять кодов вместо одной «ошибки», отдельный код для непроверенного результата и запрет на флаг --force.
Ключевая мысль: каждый код выхода называет свой вид отказа
Последнее, что Лера усвоила, оказалось самым полезным в работе: каждый код выхода называет свой вид отказа. Не «упало», а «упало вот по этой причине» — и по коду сразу понятно, чинить продукт, машину или решение.
Особняком стоит код 9. Он означает не провал и не успех, а третье состояние: проверка не смогла дать ответ. Так завершается дымовой прогон, если на машине нет ffmpeg или Chromium: он ничего не проверил, потому что нечем. Смешивать это с успехом нельзя — иначе пустая машина выглядела бы как машина, на которой всё прошло.
Это и есть та самая привычка, ради которой стоило пройти весь курс: отсутствие результата — не результат. Зелёный вывод должен означать «проверено и сошлось», а не «ничего не сломалось на нашем пути».
Чем это подкреплено на практике:
- Дымовой прогон поднимает временный локальный сервер, записывает три сценария, собирает настоящие медиафайлы, строит и проверяет сайт и прогоняет оба детерминированных гейта. Он проверяет весь путь целиком, а не отдельные куски.
- Проверка чистой комнаты сравнивает пак с сохранённым отпечатком, а поиск идентификаторов ловит имена и адреса, которым нельзя попасть в публичный набор. Его запускают дважды: по самому паку и отдельно по собранному сайту.
И правило, которое в SKILL.md написано прямым текстом: отказ никогда не превращают в предупреждение, и флаг принудительного продолжения не добавляют. Флаг --force — это способ выключить собственные защиты в тот единственный момент, когда они сработали.
Компромисс: девять кодов надо один раз выучить, и строгая система отказов действительно чаще останавливает работу; зато каждый её отказ несёт адрес причины, а зелёный результат означает ровно то, что написано.
Частые вопросы
- У меня уже стоит ffmpeg, но предполёт всё равно отказывает. Что делать?
Скорее всего, это урезанная сборка. Предполёт проверяет по именам восемь фильтров (scale, pad, fps, format, setpts, fade, overlay, concat), кодировщик libx264, контейнеры mp4 и concat, ffprobe и исполняемый Chromium. Сообщение об отказе перечисляет недостающее поимённо — поставь полный ffmpeg (
apt install ffmpeg) и браузер (npx playwright install chromium).- Мой продукт ходит во внешние сервисы. Можно ли снимать его в герметичном режиме?
Нет: в этом режиме открывается только петлевой адрес 127.0.0.1, всё остальное отбивается. Такой продукт снимают без флага герметичности — и тогда прогон перестаёт быть строго повторяемым, потому что чужие сервисы влияют и на кадры, и на длительность. Если это важно, поднимите на время записи локальные заглушки.
- Сценарий получился длиннее лимита. Он обрежется?
Нет. Клип длиннее лимита секунд ускоряется, а не обрезается: все события остаются в показе. Если ускорение получается слишком сильным, лучше разбить показ на две демонстрации в одном наборе — так зритель успевает за происходящим.
- Можно ли поднять лимит на один файл выше 20 МБ?
Опустить — да, поднять — только до 100 МБ, и это потолок самого GitHub, выше которого разбор конфигурации отказывает. Правильное лечение — уменьшать байты (поднять число качества сжатия в диапазоне 26..40 или разбить набор), а не расширять прибор, который их измеряет.
- Отправка прошла успешно, а на странице ничего нет. Что смотреть?
Успешная отправка не является квитанцией публикации: пак сравнивает контрольную сумму живого index.html с локальной и запрашивает заголовок каждого видеофайла, сверяя объявленную длину с реальным размером. Если совпадения нет после нескольких попыток, скрипт печатает готовую команду отката — выполните именно её, а не догадывайтесь, какая отправка доехала.
- Почему на странице демонстрации нельзя ни одного скрипта?
Страница обязана открываться всегда и ничего не сообщать третьим сторонам, а при пересборке давать те же байты. Проверка сайта отклоняет скрипт на странице демонстрации, внешние ссылки и стили, битые пути и видео, на которое не ссылается ни одна страница.
- Как прогнать весь путь целиком, ничего не публикуя?
Есть дымовой прогон:
bash "$SKILL_ROOT/scripts/smoke-test.sh". Он поднимает временный локальный сервер, записывает три сценария из тестовых данных, собирает настоящие медиафайлы, строит и проверяет сайт и прогоняет оба детерминированных гейта. Для проверки самой публикации без единой команды git используйте флаг --dry-run.- Пак публикует себя в npm?
Нет: публикация пакета в npm лежит вне этого навыка. Навык публикует собранный набор демонстраций на GitHub Pages — и только после санкции владельца и живой квитанции по фактическим байтам.