feat: встроенная команда completions (bash/zsh/pwsh) + хук &ПоставщикДополнения#20
feat: встроенная команда completions (bash/zsh/pwsh) + хук &ПоставщикДополнения#20nixel2007 wants to merge 3 commits intoautumn-library:masterfrom
Conversation
Команда автоматически доступна всем приложениям на autumn-cli. Обходит
дерево cli-команд через публичный API cli-библиотеки и запекает в скрипт
статический список имён команд/опций/аргументов.
Для динамических значений (например, список установленных версий)
добавлена аннотация &ПоставщикДополнения("ИмяМетода"). Приложение
навешивает её на поле опции/аргумента и экспортирует метод-поставщик,
возвращающий Массив со строками. Результат запекается в скрипт на момент
выполнения команды completions — во время автодополнения в оболочке
внешние процессы не запускаются.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WalkthroughВерсия пакета Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 минут Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…style Команда 'completions' удалена из ovm и теперь предоставляется напрямую autumn-cli — все приложения на autumn-cli получают её бесплатно. На полях команд навешена аннотация &ПоставщикДополнения (новая в autumn-cli 1.4.0), которая на этапе генерации скрипта запекает в него динамические значения: - use / uninstall / which / run — установленные версии; - install — доступные к установке версии. КомандаInstall переписана в декларативный стиль (&Опция/&Аргумент + &ВыполнениеКоманды) взамен устаревшего ОписаниеКоманды/ВыполнитьКоманду. Фича completions.feature обновлена: теперь поддерживаются все три оболочки (bash, zsh, pwsh), сценарий 'не поддерживается' проверяется на fish. packagedef: autumn-cli → 1.4.0 (релиз с фичей в autumn-library/autumn-cli#20). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/Классы/ИКС_КомандаДополнения.os (2)
454-462: В zsh-описании команд в качестве описания используется само имя команды.На строке 460
ОписаниеЗначенияинициализируется какОписание.Имена[0], из‑за чего_describe 'command' commandsпоказывает рядом с именем команды то же самое имя вместо осмысленного текста. Стоит получать описание команды через публичное API (аналогично тому, как оно уже читается из аннотацииКомандаПриложенияв других местах фреймворка — черезПолучитьЗначениеПараметраАннотации(..., "Описание", "")) и подставлять его после двоеточия.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/Классы/ИКС_КомандаДополнения.os` around lines 454 - 462, В текущем цикле генерации zsh-описаний переменная ОписаниеЗначения берётся из Описание.Имена[0], поэтому в _describe 'command' commands рядом с именем показывается само имя; замените источник описания на публичное API получения аннотации (вместо Описание.Имена[0]) — вызвать ПолучитьЗначениеПараметраАннотации(Описание, "Описание", "") или аналогичный метод, получить реальное текстовое описание команды и затем использовать его при формировании строки через ЭкранироватьДляОдинарныхКавычек(ОписаниеЗначения), сохранив остальную логику добавления в Строки и циклы по Модель/Описание/Имя.
180-193: Рекомендуется заменитьВычислитьнаРефлектор.ВызватьМетоддля безопасности.Текущий код
Вычислить("Бин." + ИмяМетода + "()")работает, но подвержен проблемам с инъекциями и некорректно escapeляет специальные символы. В oscript имеетсяРефлектор.ВызватьМетод(Объект, "ИмяМетода"), который безопаснее и исключает риск кода в строке. Особенно актуально, еслиИмяМетодапоступает из внешнего источника.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/Классы/ИКС_КомандаДополнения.os` around lines 180 - 193, В функции ВыполнитьМетод заменить рискованное вычисление строки Вычислить("Бин."+ИмяМетода+"()") на безопасный вызов Рефлектор.ВызватьМетод(Бин, ИмяМетода) — оставьте проверку ОписаниеМетода.ЭтоФункция и поиск в ТаблицаМетодов (через Рефлектор.ПолучитьТаблицуМетодов), затем вернуть результат Рефлектор.ВызватьМетод(Бин, ИмяМетода) вместо строки, чтобы устранить инъекции и корректно вызывать метод.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/Классы/ИКС_КомандаДополнения.os`:
- Around line 357-388: Функция ДобавитьВеткуBashПодкоманды сейчас не рекурсивно
обходит Описание.Подкоманды, из‑за чего автодополнение поддерживает только два
уровня; исправьте это, сделав обход рекурсивным по аналогии с
ПостроитьОписаниеКоманды: добавить в ДобавитьВеткуBashПодкоманды проверку и цикл
по Описание.Подкоманды и при обнаружении вложенной подкоманды вызывать саму
ДобавитьВеткуBashПодкоманды с увеличенным Отступом (или вынести логику ветвления
в вспомогательную рекурсивную функцию), обеспечив корректную генерацию
case-веток и вызовов для всех уровней; при этом сохранить существующие сборы
ИменаОпций/ЗначенияАргументов (СобратьЗначенияАргументов) и условные блоки для
флагов и аргументов.
- Around line 300-311: Генерируемый bash/pwsh скрипт вставляет сырые значения из
Описание.Опции через СтрСоединить(Опция.Значения, " ") и в ветке pwsh через
МассивPwsh без корректного экранирования, что ломает/инжектит команды;
исправьте: при построении списка значений для СтрокиСкрипта (где сейчас
используется СтрСоединить(Опция.Значения, " ")) замените на объединение уже
безопасно-экранированных/промаркированных элементов (каждое значение
оборачивать/экранировать для bash — эквивалент printf '%q' или реализовать
функцию ЭкранироватьДляBash/КвотироватьКаждоеЗначение — и затем соединять
пробелом), во всех местах ветки pwsh и для МассивPwsh пропускать значения через
ЭкранироватьДляОдинарныхКавычек и дополнительно экранировать спецсимволы в
контекстах типа "$wordToComplete*"; также добавьте короткую
валидацию/логирование недопустимых значений и документируйте контракт для
поставщиков (запрещённые символы или требование без пробелов).
---
Nitpick comments:
In `@src/Классы/ИКС_КомандаДополнения.os`:
- Around line 454-462: В текущем цикле генерации zsh-описаний переменная
ОписаниеЗначения берётся из Описание.Имена[0], поэтому в _describe 'command'
commands рядом с именем показывается само имя; замените источник описания на
публичное API получения аннотации (вместо Описание.Имена[0]) — вызвать
ПолучитьЗначениеПараметраАннотации(Описание, "Описание", "") или аналогичный
метод, получить реальное текстовое описание команды и затем использовать его при
формировании строки через ЭкранироватьДляОдинарныхКавычек(ОписаниеЗначения),
сохранив остальную логику добавления в Строки и циклы по Модель/Описание/Имя.
- Around line 180-193: В функции ВыполнитьМетод заменить рискованное вычисление
строки Вычислить("Бин."+ИмяМетода+"()") на безопасный вызов
Рефлектор.ВызватьМетод(Бин, ИмяМетода) — оставьте проверку
ОписаниеМетода.ЭтоФункция и поиск в ТаблицаМетодов (через
Рефлектор.ПолучитьТаблицуМетодов), затем вернуть результат
Рефлектор.ВызватьМетод(Бин, ИмяМетода) вместо строки, чтобы устранить инъекции и
корректно вызывать метод.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b93ae2bc-5bed-4710-98fd-bd156f615488
📒 Files selected for processing (3)
packagedefsrc/Классы/ИКС_АннотацияПоставщикДополнения.ossrc/Классы/ИКС_КомандаДополнения.os
| Для Каждого Опция Из Описание.Опции Цикл | ||
| Если Опция.Значения.Количество() = 0 Тогда | ||
| Продолжить; | ||
| КонецЕсли; | ||
|
|
||
| Для Каждого ИмяОпции Из Опция.Имена Цикл | ||
| СтрокиСкрипта.Добавить(Отступ + " if [ ""$prev"" = """ + ИмяОпции + """ ]; then"); | ||
| СтрокиСкрипта.Добавить(Отступ + " COMPREPLY=($(compgen -W """ + СтрСоединить(Опция.Значения, " ") + """ -- ""$cur""))"); | ||
| СтрокиСкрипта.Добавить(Отступ + " return 0"); | ||
| СтрокиСкрипта.Добавить(Отступ + " fi"); | ||
| КонецЦикла; | ||
| КонецЦикла; |
There was a problem hiding this comment.
Отсутствует экранирование значений поставщика для bash/pwsh — генерируемый скрипт может сломаться.
Значения из поставщика дополнения (пользовательские строки) вставляются в сгенерированный bash-скрипт внутри двойных кавычек через СтрСоединить(Опция.Значения, " ") без какого-либо экранирования. Если поставщик вернёт значение, содержащее пробел, ", $, `, \, перевод строки и т.п., скрипт будет синтаксически невалидным или выполнит произвольный код при source. То же справедливо для аргументов (строки 347–348, 382–384) и для ветки pwsh (594–619, через МассивPwsh, где используется только ЭкранироватьДляОдинарныхКавычек, но не экранируются спецсимволы внутри "$wordToComplete*" и т.п. контекста). Для zsh частично решено через ЭкранироватьДляОдинарныхКавычек, но разделение значений в bash по пробелу всё равно теряет значения с пробелами.
Рекомендуется:
- для bash: квотировать каждое значение (например, через
printf '%q ') либо строго валидировать алфавит допустимых символов и отбрасывать/логировать недопустимые; - для pwsh: пропускать значения через
ЭкранироватьДляОдинарныхКавычекво всех местах, где они попадают в одинарные кавычки; - задокументировать контракт для авторов поставщиков (без пробелов/кавычек) либо явно фильтровать такие значения.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Классы/ИКС_КомандаДополнения.os` around lines 300 - 311, Генерируемый
bash/pwsh скрипт вставляет сырые значения из Описание.Опции через
СтрСоединить(Опция.Значения, " ") и в ветке pwsh через МассивPwsh без
корректного экранирования, что ломает/инжектит команды; исправьте: при
построении списка значений для СтрокиСкрипта (где сейчас используется
СтрСоединить(Опция.Значения, " ")) замените на объединение уже
безопасно-экранированных/промаркированных элементов (каждое значение
оборачивать/экранировать для bash — эквивалент printf '%q' или реализовать
функцию ЭкранироватьДляBash/КвотироватьКаждоеЗначение — и затем соединять
пробелом), во всех местах ветки pwsh и для МассивPwsh пропускать значения через
ЭкранироватьДляОдинарныхКавычек и дополнительно экранировать спецсимволы в
контекстах типа "$wordToComplete*"; также добавьте короткую
валидацию/логирование недопустимых значений и документируйте контракт для
поставщиков (запрещённые символы или требование без пробелов).
| Процедура ДобавитьВеткуBashПодкоманды(СтрокиСкрипта, Описание, Отступ) | ||
|
|
||
| ПаттернCase = СтрСоединить(Описание.Имена, "|"); | ||
| СтрокиСкрипта.Добавить(Отступ + ПаттернCase + ")"); | ||
|
|
||
| ИменаОпций = ИменаПараметровДляКомплита(Описание.Опции); | ||
|
|
||
| Для Каждого Опция Из Описание.Опции Цикл | ||
| Если Опция.Значения.Количество() = 0 Тогда | ||
| Продолжить; | ||
| КонецЕсли; | ||
| Для Каждого ИмяОпции Из Опция.Имена Цикл | ||
| СтрокиСкрипта.Добавить(Отступ + " if [ ""$prev"" = """ + ИмяОпции + """ ]; then"); | ||
| СтрокиСкрипта.Добавить(Отступ + " COMPREPLY=($(compgen -W """ + СтрСоединить(Опция.Значения, " ") + """ -- ""$cur""))"); | ||
| СтрокиСкрипта.Добавить(Отступ + " return 0"); | ||
| СтрокиСкрипта.Добавить(Отступ + " fi"); | ||
| КонецЦикла; | ||
| КонецЦикла; | ||
|
|
||
| СтрокиСкрипта.Добавить(Отступ + " if [[ ""$cur"" == -* ]]; then"); | ||
| СтрокиСкрипта.Добавить(Отступ + " COMPREPLY=($(compgen -W """ + СтрСоединить(ИменаОпций, " ") + """ -- ""$cur""))"); | ||
| СтрокиСкрипта.Добавить(Отступ + " return 0"); | ||
| СтрокиСкрипта.Добавить(Отступ + " fi"); | ||
|
|
||
| ЗначенияАргументов = СобратьЗначенияАргументов(Описание); | ||
| Если ЗначенияАргументов.Количество() > 0 Тогда | ||
| СтрокиСкрипта.Добавить(Отступ + " COMPREPLY=($(compgen -W """ + СтрСоединить(ЗначенияАргументов, " ") + """ -- ""$cur""))"); | ||
| КонецЕсли; | ||
|
|
||
| СтрокиСкрипта.Добавить(Отступ + " ;;"); | ||
|
|
||
| КонецПроцедуры |
There was a problem hiding this comment.
Ограничение глубины подкоманд: поддерживаются только 2 уровня.
ДобавитьВеткуBashПодкоманды не рекурсивно обходит Описание.Подкоманды — для подкоманды третьего уровня автодополнение работать не будет. Аналогично в zsh/pwsh ветках обработка подкоманд разворачивается только на один уровень. Если это осознанное ограничение, стоит отметить в комментарии/README; иначе — сделать рекурсивный обход по аналогии с ПостроитьОписаниеКоманды.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Классы/ИКС_КомандаДополнения.os` around lines 357 - 388, Функция
ДобавитьВеткуBashПодкоманды сейчас не рекурсивно обходит Описание.Подкоманды,
из‑за чего автодополнение поддерживает только два уровня; исправьте это, сделав
обход рекурсивным по аналогии с ПостроитьОписаниеКоманды: добавить в
ДобавитьВеткуBashПодкоманды проверку и цикл по Описание.Подкоманды и при
обнаружении вложенной подкоманды вызывать саму ДобавитьВеткуBashПодкоманды с
увеличенным Отступом (или вынести логику ветвления в вспомогательную рекурсивную
функцию), обеспечив корректную генерацию case-веток и вызовов для всех уровней;
при этом сохранить существующие сборы ИменаОпций/ЗначенияАргументов
(СобратьЗначенияАргументов) и условные блоки для флагов и аргументов.
There was a problem hiding this comment.
Pull request overview
PR по описанию должен добавить в autumn-cli встроенную команду completions (bash/zsh/pwsh) и аннотацию &ПоставщикДополнения, но в предоставленных изменениях виден только bump версии пакета.
Changes:
- Обновлена версия пакета
autumn-cliс1.3.0до1.4.0.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Каждая оболочка (bash/zsh/pwsh) получает свой бин с общим интерфейсом (Оболочка, СформироватьСкрипт) и прозвищем 'ГенераторДополнения'. Команда выбирает нужный через НайтиЖелуди + фильтр по Оболочка(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…отацию Базовая функциональность команды completions (три генератора bash/zsh/pwsh, класс команды, обход дерева подкоманд, вызов поставщиков) перенесена в сам cli-пакет — теперь любое приложение на cli получает ее из коробки. На стороне autumn-cli остался только специфичный для autumn-фреймворка слой: - аннотация &ПоставщикДополнения (была); - эмиссия `ТекКоманда.ПоставщикДополнения(ЭтотОбъект, "ИмяМетода");` в сгенерированный метод ОписаниеКоманды для полей, помеченных аннотацией — декоратор теперь прокидывает провайдера в cli API. Удалены: ИКС_КомандаДополнения.os, ИКС_ГенераторДополненияBash.os, ИКС_ГенераторДополненияZsh.os, ИКС_ГенераторДополненияPwsh.os. Зависимость cli поднята до 0.12.0 (встроенные completions). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Классы/ИКС_ДекораторКоманд.os (1)
122-128:⚠️ Potential issue | 🟠 MajorПередавайте владельца свойства в
ПоставщикДополнения, а не всегдаЭтотОбъект.В цикле по
НаборыОпцийаннотация&ПоставщикДополнениябудет развёрнута для свойства набора, но Line 214 генерирует вызов провайдера на объекте команды. Если метод-поставщик объявлен на бине набора опций, completions для таких полей не найдёт метод и получит пустой список/ошибку.Лучше передавать в
РазвернутьОписаниеАннотацииПолейвыражение объекта-владельца: для полей команды —ЭтотОбъект, для полей набора — соответствующийИКС_НаборОпций_*; для вложенных наборов это нужно делать рекурсивно вместе с владельцем свойства.Also applies to: 202-214
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/Классы/ИКС_ДекораторКоманд.os` around lines 122 - 128, Вместо жёсткой передачи "ЭтотОбъект" в вызов РазвернутьОписаниеАннотацииПолей при разворачивании свойств из НаборыОпций, определите и передавайте корректный выражение-владельца: для свойств команды — "ЭтотОбъект", для свойств набора — соответствующий объект-набора (например ИКС_НаборОпций_* или переменная-владельца, представляющая текущий набор), и при рекурсивной обработке вложенных наборов прокидывайте владельца вниз; обновите места, где вызывается РазвернутьОписаниеАннотацииПолей (включая контекст ТелоМетода и СвойствоНабора), чтобы передавать это выражение-владельца вместо всегда "ЭтотОбъект", и при необходимости измените логику в СобратьВсеСвойстваНабора/обходе НаборыОпций, чтобы вычислять и передавать правильный владельца рекурсивно.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/Классы/ИКС_ДекораторКоманд.os`:
- Around line 122-128: Вместо жёсткой передачи "ЭтотОбъект" в вызов
РазвернутьОписаниеАннотацииПолей при разворачивании свойств из НаборыОпций,
определите и передавайте корректный выражение-владельца: для свойств команды —
"ЭтотОбъект", для свойств набора — соответствующий объект-набора (например
ИКС_НаборОпций_* или переменная-владельца, представляющая текущий набор), и при
рекурсивной обработке вложенных наборов прокидывайте владельца вниз; обновите
места, где вызывается РазвернутьОписаниеАннотацииПолей (включая контекст
ТелоМетода и СвойствоНабора), чтобы передавать это выражение-владельца вместо
всегда "ЭтотОбъект", и при необходимости измените логику в
СобратьВсеСвойстваНабора/обходе НаборыОпций, чтобы вычислять и передавать
правильный владельца рекурсивно.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7a36ee68-3255-4811-9400-526935dc8d3c
📒 Files selected for processing (2)
packagedefsrc/Классы/ИКС_ДекораторКоманд.os
| РазвернутьПоставщикаДополнения(ТелоМетода, Свойство); | ||
| КонецПроцедуры | ||
|
|
||
| Процедура РазвернутьПоставщикаДополнения(ТелоМетода, Свойство) |
There was a problem hiding this comment.
Выглядит так, что было бы круто для команд и подкоманд делать это по умолчанию.
у них известно автодополнение-же
У команд - подкоманды или опции и параметры, а у подкоманд - опции и параметры и им нет смысла даже аннотацию навешивать. просто из коробки давать разыменование.
There was a problem hiding this comment.
@Segate-ekb мне кажется, это уже и так работает. можешь проверить на vrunner 3.0?
Суть
Аннотация
&ПоставщикДополнения("ИмяМетода")для полей&Опция/&Аргумент— хук, через который прикладная команда отдаёт список вариантов автодополнения.Что изменилось
Базовая реализация команды
completionsи три генератора скриптов (bash / zsh / PowerShell) перенесены в cli-библиотеку (см. oscript-library/cli#88). Теперь любое cli-приложение получает подкомандуcompletionsиз коробки — не только autumn-cli-приложения.На стороне autumn-cli остался только специфичный для autumn-фреймворка слой:
ИКС_АннотацияПоставщикДополнения.os— регистрация аннотации&ПоставщикДополнения.ИКС_ДекораторКоманд.os— при генерации методаОписаниеКомандыдля декорированной команды эмититТекКоманда.ПоставщикДополнения(ЭтотОбъект, "ИмяМетода");для каждого поля, помеченного аннотацией. Значение прокидывается в cli APIПараметрКоманды.ПоставщикДополнения(...).Удалены:
ИКС_КомандаДополнения.os,ИКС_ГенераторДополненияBash.os,ИКС_ГенераторДополненияZsh.os,ИКС_ГенераторДополненияPwsh.os.Пример
Команда
<app> completions --shell bashзапечёт возврат этого метода литералом в сгенерированный bash-скрипт.Зависимости
cliподнят с0.10.2до0.12.0(см. feat: built-in completions command with shell script generation oscript-library/cli#88).Связанные PR
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com