[{"data":1,"prerenderedAt":883},["ShallowReactive",2],{"navigation_docs":3,"-modules-options-module-structure":238,"-modules-options-module-structure-surround":880},[4,45,60],{"title":5,"description":6,"icon":7,"path":8,"stem":9,"children":10},"Методология",null,"ruler","\u002Fmethodology","1.methodology",[11,15,20,25,30,35,40],{"title":12,"path":8,"stem":13,"description":14},"bxshef: методология и проверка навыков","1.methodology\u002Findex","Как писать навыки ИИ-агентов для Битрикса и как проверять, что им можно верить",{"title":16,"path":17,"stem":18,"description":19},"Стандарт навыка","\u002Fmethodology\u002Fstandard","1.methodology\u002F1.standard","11 правил, каждое из провала на стенде",{"title":21,"path":22,"stem":23,"description":24},"Методология проверки","\u002Fmethodology\u002Fmethod","1.methodology\u002F2.method","lint → eval → стенд; что измерено",{"title":26,"path":27,"stem":28,"description":29},"bxshef — CLI","\u002Fmethodology\u002Fbxshef","1.methodology\u002F3.bxshef","lint, eval, feedback",{"title":31,"path":32,"stem":33,"description":34},"GitHub Action","\u002Fmethodology\u002Faction","1.methodology\u002F4.action","тот же lint + eval в любом репозитории навыков",{"title":36,"path":37,"stem":38,"description":39},"Заготовка репозитория","\u002Fmethodology\u002Ftemplate","1.methodology\u002F5.template","с чего начать автору модуля",{"title":41,"path":42,"stem":43,"description":44},"Приёмник отзывов","\u002Fmethodology\u002Ffeedback","1.methodology\u002F6.feedback","куда уходят отзывы ИИ-агентов",{"title":46,"description":6,"icon":47,"path":48,"stem":49,"children":50},"Навыки","sparkles","\u002Fskills","2.skills",[51,55],{"title":52,"path":48,"stem":53,"description":54},"Навыки shef.*","2.skills\u002Findex","npx skills add bx-shef\u002Fskills",{"title":56,"path":57,"stem":58,"description":59},"shef-feedback","\u002Fskills\u002Fshef-feedback","2.skills\u002F1.shef-feedback","Отправить отзыв о навыке shef-* или навыке команды. Брать ВСЕГДА, когда просят оставить или отправить отзыв о навыке — даже если сам навык в диалоге не виден, —",{"title":61,"description":6,"icon":62,"path":63,"stem":64,"children":65},"Модули shef.*","package","\u002Fmodules","3.modules",[66,69,131,179],{"title":61,"path":63,"stem":67,"description":68},"3.modules\u002Findex","Что за чем ставить",{"title":70,"description":6,"path":71,"stem":72,"children":73},"shef.options","\u002Fmodules\u002Foptions","3.modules\u002F1.options\u002Findex",[74,76,81,86,91,96,101,106,110,114,119,123,127],{"title":70,"path":71,"stem":72,"description":75},"фундамент: настройки, трейты, компоненты",{"title":77,"path":78,"stem":79,"description":80},"[`\\Shef\\Options\\Installator`] Installer","\u002Fmodules\u002Foptions\u002Finstaller","3.modules\u002F1.options\u002F1.installer","Для облегчения установок.",{"title":82,"path":83,"stem":84,"description":85},"Сборка, CI и релиз","\u002Fmodules\u002Foptions\u002Fbuild-and-install","3.modules\u002F1.options\u002F10.build-and-install","Раскладка репозитория — в module-structure.md, процесс —\nв CONTRIBUTING.md, установка глазами пользователя —\nв README.md.",{"title":87,"path":88,"stem":89,"description":90},"Раскладка репозитория","\u002Fmodules\u002Foptions\u002Fmodule-structure","3.modules\u002F1.options\u002F11.module-structure","Файл про устройство репозитория. Опорные точки модуля — в CLAUDE.md,\nпроцесс — в CONTRIBUTING.md, сборка — в\nbuild-and-install.md.",{"title":92,"path":93,"stem":94,"description":95},"Проверка на портале","\u002Fmodules\u002Foptions\u002Fportal-check","3.modules\u002F1.options\u002F12.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, кеш,\nраскладка файлов, поведение при обновлении. Проверять это приходится руками —\nи лучше по списку, потому что забытый шаг находит не разработчик, а клиент.",{"title":97,"path":98,"stem":99,"description":100},"[`\\Shef\\Options\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Foptions\u002Foptions","3.modules\u002F1.options\u002F2.options","Поддерживает следующие типы:",{"title":102,"path":103,"stem":104,"description":105},"Работа с пользователями","\u002Fmodules\u002Foptions\u002Fsecurity","3.modules\u002F1.options\u002F3.security","",{"title":107,"path":108,"stem":109,"description":105},"[`\\Shef\\Options\\Main\\Utils`] Утилиты","\u002Fmodules\u002Foptions\u002Futils","3.modules\u002F1.options\u002F4.utils",{"title":111,"path":112,"stem":113,"description":105},"[`\\Shef\\Options\\Components`] Работа с компонентами","\u002Fmodules\u002Foptions\u002Fcomponents","3.modules\u002F1.options\u002F5.components",{"title":115,"path":116,"stem":117,"description":118},"[`\\Shef\\Options\\Options`] Паттерны","\u002Fmodules\u002Foptions\u002Fpattern","3.modules\u002F1.options\u002F6.pattern","Запускаемые примеры: singleton.php,\nconfig.php, smartstd.php —\nкак их гонять, написано в examples\u002FREADME.md.",{"title":120,"path":121,"stem":122,"description":105},"[`\\Shef\\Options\\Tests`] Тестирование","\u002Fmodules\u002Foptions\u002Ftests","3.modules\u002F1.options\u002F7.tests",{"title":124,"path":125,"stem":126,"description":105},"[`\\Shef\\Options\\TraitList`] Набор трейтов","\u002Fmodules\u002Foptions\u002Ftraitlist","3.modules\u002F1.options\u002F8.traitlist",{"title":128,"path":129,"stem":130,"description":105},"Правила для ИИ-агентов в этом репозитории","\u002Fmodules\u002Foptions\u002Fagent-rules","3.modules\u002F1.options\u002F9.agent-rules",{"title":132,"description":6,"path":133,"stem":134,"children":135},"shef.problems","\u002Fmodules\u002Fproblems","3.modules\u002F2.problems\u002Findex",[136,138,143,147,152,157,161,166,169,172,175],{"title":132,"path":133,"stem":134,"description":137},"логи, журнал событий, учёт проблем",{"title":139,"path":140,"stem":141,"description":142},"[`\\Shef\\Problems\\Integration`] События и меню","\u002Fmodules\u002Fproblems\u002Fevents","3.modules\u002F2.problems\u002F1.events","Что модуль регистрирует в ядре при установке. Список — в .settings.php, ключ\ninstallEvents; что каждый обработчик существует, сверяет\ntests\u002Fsettings_test.php.",{"title":144,"path":145,"stem":146,"description":105},"Безопасность логов","\u002Fmodules\u002Fproblems\u002Fsecurity","3.modules\u002F2.problems\u002F10.security",{"title":148,"path":149,"stem":150,"description":151},"Быстрая отладка: `_pr`, `_log`, `_log1`","\u002Fmodules\u002Fproblems\u002Fdeffunctions","3.modules\u002F2.problems\u002F2.deffunctions","Функции объявляет def-functions.php, подключается он из include.php.",{"title":153,"path":154,"stem":155,"description":156},"Уровни логирования","\u002Fmodules\u002Fproblems\u002Floglevel","3.modules\u002F2.problems\u002F3.loglevel","Уровни — стандарт PSR-3, в Monolog это \\Monolog\\Level. Ниже — когда какой брать.",{"title":158,"path":159,"stem":160,"description":105},"[`\\Shef\\Problems\\Integration\\Monolog`] Monolog","\u002Fmodules\u002Fproblems\u002Fmonolog","3.modules\u002F2.problems\u002F4.monolog",{"title":162,"path":163,"stem":164,"description":165},"Ротация логов","\u002Fmodules\u002Fproblems\u002Flogrotate","3.modules\u002F2.problems\u002F5.logrotate","Логи модуля лежат в каталоге логов — по умолчанию на уровень выше корня сайта,\nдля BitrixVM \u002Fhome\u002Fbitrix\u002Fsh_log\u002F*.log, — и сами не чистятся. Ротацию делает\nlogrotate — системная утилита, а не Monolog: Monolog тоже умеет\n(RotatingFileHandler), но тогда за файлами следит каждый PHP-процесс, а не\nодна служба.",{"title":128,"path":167,"stem":168,"description":105},"\u002Fmodules\u002Fproblems\u002Fagent-rules","3.modules\u002F2.problems\u002F6.agent-rules",{"title":82,"path":170,"stem":171,"description":85},"\u002Fmodules\u002Fproblems\u002Fbuild-and-install","3.modules\u002F2.problems\u002F7.build-and-install",{"title":87,"path":173,"stem":174,"description":90},"\u002Fmodules\u002Fproblems\u002Fmodule-structure","3.modules\u002F2.problems\u002F8.module-structure",{"title":92,"path":176,"stem":177,"description":178},"\u002Fmodules\u002Fproblems\u002Fportal-check","3.modules\u002F2.problems\u002F9.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, меню,\nраскладка файлов, журнал событий, поведение при обновлении. Проверять это\nприходится руками — и лучше по списку, потому что забытый шаг находит не\nразработчик, а клиент.",{"title":180,"description":6,"path":181,"stem":182,"children":183},"shef.insync","\u002Fmodules\u002Finsync","3.modules\u002F3.insync\u002Findex",[184,186,191,194,198,203,208,213,218,222,227,232,235],{"title":180,"path":181,"stem":182,"description":185},"агенты, импорт, API-клиенты, модели",{"title":187,"path":188,"stem":189,"description":190},"[`\\Shef\\InSync\\Agents`] Агенты","\u002Fmodules\u002Finsync\u002Fagents","3.modules\u002F3.insync\u002F1.agents","Агент импорта — наследник \\Shef\\InSync\\Agents\\AAgent. Описание агента для\nb_agent — \\Shef\\InSync\\Agents\\Entity, установку и управление берёт на себя\n\\Shef\\InSync\\Agents\\Manager.",{"title":87,"path":192,"stem":193,"description":90},"\u002Fmodules\u002Finsync\u002Fmodule-structure","3.modules\u002F3.insync\u002F10.module-structure",{"title":92,"path":195,"stem":196,"description":197},"\u002Fmodules\u002Finsync\u002Fportal-check","3.modules\u002F3.insync\u002F11.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое\nменю, раскладка компонентов, агенты, таблица импорта, поведение при\nобновлении. Проверять это приходится руками — и лучше по списку, потому что\nзабытый шаг находит не разработчик, а клиент.",{"title":199,"path":200,"stem":201,"description":202},"Безопасность","\u002Fmodules\u002Finsync\u002Fsecurity","3.modules\u002F3.insync\u002F12.security","Модуль даёт другим модулям заготовки для синхронизаций, и самые опасные места\nу него общие с ними: кто может запускать агенты и импорт, что ложится в каталоги\nимпорта, что уходит в SQL и в лог. Ниже — что держит модуль и что остаётся\nпроекту.",{"title":204,"path":205,"stem":206,"description":207},"[`\\Shef\\InSync\\Sync`] Импорт","\u002Fmodules\u002Finsync\u002Fimport","3.modules\u002F3.insync\u002F2.import","Импорт идёт в два шага через таблицу импорта \\Shef\\InSync\\Sync\\Model\\SyncTable\n(shef_insync_model):",{"title":209,"path":210,"stem":211,"description":212},"[`\\Shef\\InSync\\Api`] API","\u002Fmodules\u002Finsync\u002Fapi","3.modules\u002F3.insync\u002F3.api","Обращение к внешнему API по HTTP — наследник \\Shef\\InSync\\Api\\AConnector.",{"title":214,"path":215,"stem":216,"description":217},"[`\\Shef\\InSync\\TraitList\\Xml`] Парсинг XML","\u002Fmodules\u002Finsync\u002Fxml","3.modules\u002F3.insync\u002F4.xml","Разбор XML сделан через SbWereWolf\u002Fxml-navigator\n(статья на Хабре): XMLReader идёт по\nдокументу потоком, а каждый элемент с нужным тегом HierarchyComposer\nпревращает в массив — n имя, v значение, a атрибуты, s вложенные\nэлементы.",{"title":219,"path":220,"stem":221,"description":105},"Компоненты","\u002Fmodules\u002Finsync\u002Fcomponents","3.modules\u002F3.insync\u002F5.components",{"title":223,"path":224,"stem":225,"description":226},"Страницы","\u002Fmodules\u002Finsync\u002Fpage","3.modules\u002F3.insync\u002F6.page","Страницы модуля — в левом меню, штатным разделом intranet\n(Bitrix\\Intranet\\CustomSection): раздел «SH Импорт», код shinsync.\nВерхней панели и shef.uiclear больше нет.",{"title":228,"path":229,"stem":230,"description":231},"[`\\Shef\\InSync\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Finsync\u002Foptions","3.modules\u002F3.insync\u002F7.options","Опции для страницы настроек модуля импорта (на ShOptionsConfig из\nshef.options): добавьте их во вкладку своего options_conf.php.",{"title":128,"path":233,"stem":234,"description":105},"\u002Fmodules\u002Finsync\u002Fagent-rules","3.modules\u002F3.insync\u002F8.agent-rules",{"title":82,"path":236,"stem":237,"description":85},"\u002Fmodules\u002Finsync\u002Fbuild-and-install","3.modules\u002F3.insync\u002F9.build-and-install",{"id":239,"title":87,"body":240,"description":90,"extension":874,"meta":875,"navigation":876,"path":88,"rawbody":877,"seo":878,"stem":89,"__hash__":879},"docs\u002F3.modules\u002F1.options\u002F11.module-structure.md",{"type":241,"value":242,"toc":864},"minimark",[243,265,270,301,307,323,329,347,351,723,727,733,746,753,780,795,803,807,816,826,836,852],[244,245,246,247,254,255,260,261,264],"p",{},"Файл про устройство репозитория. Опорные точки модуля — в ",[248,249,253],"a",{"href":250,"rel":251},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002FCLAUDE.md",[252],"nofollow","CLAUDE.md",",\nпроцесс — в ",[248,256,259],{"href":257,"rel":258},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002FCONTRIBUTING.md",[252],"CONTRIBUTING.md",", сборка — в\n",[248,262,263],{"href":83},"build-and-install.md",".",[266,267,269],"h2",{"id":268},"модуль-лежит-в-корне-и-это-вынужденно","Модуль лежит в корне, и это вынужденно",[244,271,272,273,277,278,282,283,282,286,289,290,293,294,297,298,264],{},"Composer разворачивает в целевой каталог ",[274,275,276],"strong",{},"корень пакета целиком"," и подкаталоги\nвыбирать не умеет. Поэтому ",[279,280,281],"code",{},"lib\u002F",", ",[279,284,285],{},"install\u002F",[279,287,288],{},"lang\u002F"," лежат прямо в корне\nрепозитория, рядом с ",[279,291,292],{},"build.sh"," и ",[279,295,296],{},".github\u002F",", а не в отдельном подкаталоге вроде\n",[279,299,300],{},"src\u002F",[244,302,303,304,306],{},"Плата за это — два списка в шапке ",[279,305,292],{},":",[308,309,310,317],"ul",{},[311,312,313,316],"li",{},[274,314,315],{},"SHIP"," — уезжает на портал и в Composer-пакет;",[311,318,319,322],{},[274,320,321],{},"KEEP"," — остаётся в репозитории.",[244,324,325,328],{},[274,326,327],{},"Файл, не попавший ни в один список, роняет сборку."," Это единственная\nстраховка такой раскладки: без неё новый файл однажды уехал бы на портал молча.",[244,330,331,332,335,336,339,340,343,344,264],{},"Тот же список продублирован в ",[279,333,334],{},".gitattributes"," через ",[279,337,338],{},"export-ignore"," — он решает,\nчто попадёт в Composer-пакет, потому что ",[279,341,342],{},"git archive"," его соблюдает. Списки\nобязаны совпадать, иначе на портал уедет разное в зависимости от способа\nустановки. Сверяется автоматически и в обе стороны, см. ",[279,345,346],{},"check_gitattributes",[266,348,350],{"id":349},"что-где-лежит","Что где лежит",[352,353,354,369],"table",{},[355,356,357],"thead",{},[358,359,360,364,366],"tr",{},[361,362,363],"th",{},"путь",[361,365],{},[361,367,368],{},"что это",[370,371,372,388,406,421,436,457,478,489,504,522,536,550,567,579,591,602,614,626,648,659,669,680,693,711],"tbody",{},[358,373,374,380,382],{},[375,376,377],"td",{},[279,378,379],{},"install\u002Findex.php",[375,381,315],{},[375,383,384,385],{},"установщик, класс ",[279,386,387],{},"shef_options extends CModule",[358,389,390,395,397],{},[375,391,392],{},[279,393,394],{},"install\u002Fversion.php",[375,396,315],{},[375,398,399,293,402,405],{},[279,400,401],{},"VERSION",[279,403,404],{},"VERSION_DATE"," — источник истины о версии",[358,407,408,413,415],{},[375,409,410],{},[279,411,412],{},"install\u002Fcss\u002F",[375,414,315],{},[375,416,417,418],{},"стили страницы настроек; установщик раскладывает их в ",[279,419,420],{},"\u002Fbitrix\u002Fcss",[358,422,423,428,430],{},[375,424,425],{},[279,426,427],{},".settings.php",[375,429,315],{},[375,431,432,433],{},"настройки модуля: ajax-контроллеры, карта раскладки ",[279,434,435],{},"installDir",[358,437,438,443,445],{},[375,439,440],{},[279,441,442],{},"include.php",[375,444,315],{},[375,446,447,448,282,451,293,454],{},"точка входа модуля: подключает ",[279,449,450],{},"autoload.php",[279,452,453],{},"def-functions.php",[279,455,456],{},"register-js.php",[358,458,459,463,465],{},[375,460,461],{},[279,462,453],{},[375,464,315],{},[375,466,467,468,293,471,474,475],{},"глобальные ",[279,469,470],{},"_log()",[279,472,473],{},"_pr()",", которые зовёт трейт ",[279,476,477],{},"TraitList\\Log",[358,479,480,484,486],{},[375,481,482],{},[279,483,450],{},[375,485,315],{},[375,487,488],{},"зависимости модуля и регистрация чужих namespace",[358,490,491,496,498],{},[375,492,493],{},[279,494,495],{},"project-context.php",[375,497,315],{},[375,499,500,501],{},"знает, есть ли на проекте Composer и где его ",[279,502,503],{},"vendor",[358,505,506,517,519],{},[375,507,508,282,511,282,514],{},[279,509,510],{},"options.php",[279,512,513],{},"options_conf.php",[279,515,516],{},"optionsconfig.php",[375,518,315],{},[375,520,521],{},"страница настроек модуля",[358,523,524,528,530],{},[375,525,526],{},[279,527,281],{},[375,529,315],{},[375,531,532,533],{},"классы модуля, ",[274,534,535],{},"имена файлов строго строчными",[358,537,538,543,545],{},[375,539,540],{},[279,541,542],{},"lang\u002Fru\u002F",[375,544,315],{},[375,546,547,548],{},"языковые файлы, зеркалят структуру ",[279,549,281],{},[358,551,552,563,565],{},[375,553,554,282,557,282,560],{},[279,555,556],{},"README.md",[279,558,559],{},"CHANGELOG.md",[279,561,562],{},"LICENSE",[375,564,315],{},[375,566],{},[358,568,569,574,576],{},[375,570,571],{},[279,572,573],{},"composer.json",[375,575,315],{},[375,577,578],{},"манифест пакета",[358,580,581,586,588],{},[375,582,583],{},[279,584,585],{},"docs\u002F",[375,587,321],{},[375,589,590],{},"вся документация, и модуля, и репозитория",[358,592,593,597,599],{},[375,594,595],{},[279,596,292],{},[375,598,321],{},[375,600,601],{},"сборка и проверки",[358,603,604,609,611],{},[375,605,606],{},[279,607,608],{},"tests\u002F",[375,610,321],{},[375,612,613],{},"тесты",[358,615,616,621,623],{},[375,617,618],{},[279,619,620],{},"examples\u002F",[375,622,321],{},[375,624,625],{},"запускаемые примеры к строительным блокам",[358,627,628,633,635],{},[375,629,630],{},[279,631,632],{},".claude\u002Fskills\u002F",[375,634,321],{},[375,636,637,638,641,642,293,645],{},"навыки агента (источник для всей линейки) плюс ",[279,639,640],{},"evals\u002F"," внутри навыков, ",[279,643,644],{},"sync.sh",[279,646,647],{},"MANIFEST",[358,649,650,654,656],{},[375,651,652],{},[279,653,296],{},[375,655,321],{},[375,657,658],{},"CI и релиз",[358,660,661,665,667],{},[375,662,663],{},[279,664,259],{},[375,666,321],{},[375,668],{},[358,670,671,675,677],{},[375,672,673],{},[279,674,253],{},[375,676,321],{},[375,678,679],{},"памятка агенту: она про репозиторий, а не про модуль",[358,681,682,689,691],{},[375,683,684,282,686],{},[279,685,334],{},[279,687,688],{},".gitignore",[375,690,321],{},[375,692],{},[358,694,695,700,702],{},[375,696,697],{},[279,698,699],{},".php-cs-fixer.dist.php",[375,701,321],{},[375,703,704,705,708,709],{},"правила форматирования; гоняются ",[279,706,707],{},"composer run lint",", не из ",[279,710,292],{},[358,712,713,718,720],{},[375,714,715],{},[279,716,717],{},"composer.lock",[375,719,321],{},[375,721,722],{},"версии инструментов разработчика; на зависимости пакета не влияет",[266,724,726],{"id":725},"почему-документация-не-едет-на-портал","Почему документация не едет на портал",[244,728,729,730,732],{},"Документация живёт в репозитории целиком. В поставке из неё остаётся только\n",[279,731,556],{}," — как readme пакета, — и все ссылки из него ведут на GitHub.",[244,734,735,736,738,739,282,742,745],{},"Раньше модуль рендерил ",[279,737,556],{}," прямо в настройках: отдельная вкладка,\najax-контроллер, вендорённый php-markdown и js-расширение к нему. В 3.0.0 этот\nблок убран целиком. Документация на GitHub всегда свежая, а не той версии, что\nкогда-то поставили на портал, — значит, второй её копии внутри модуля хватало\nровно на то, чтобы расходиться с первой. Заодно с ней из поставки ушли\n",[279,740,741],{},"vendor\u002FMichelf\u002F",[279,743,744],{},"install\u002Fjs\u002F"," и единственный ajax-контроллер модуля.",[266,747,749,750,752],{"id":748},"нижний-регистр-в-lib-обязателен","Нижний регистр в ",[279,751,281],{}," обязателен",[244,754,755,758,759,762,763,766,767,770,771,774,775,777,778,264],{},[279,756,757],{},"Bitrix\\Main\\Loader"," отображает класс в путь ",[274,760,761],{},"строчными",", разбирая первые два\nсегмента namespace как id модуля: ",[279,764,765],{},"Shef\\Options\\Main\\Utils"," ищется как\n",[279,768,769],{},"bitrix\u002Fmodules\u002Fshef.options\u002Flib\u002Fmain\u002Futils.php",". Отсюда же пустой\n",[279,772,773],{},"registerNamespace"," в ",[279,776,427],{}," — он нужен только для чужих namespace, а\nсвоих у модуля нет. Читает этот ключ ",[279,779,450],{},[244,781,782,784,785,788,789,791,792,794],{},[279,783,495],{}," выглядит частью той же механики, но ею не является:\nфайл объявляет глобальный ",[279,786,787],{},"ShComposerContext"," и едет в поставку, однако в самом\nмодуле его никто не подключает — ",[279,790,773],{}," задан пустым литералом.\nЭто заготовка для модулей линейки, чей ",[279,793,427],{}," может собрать список\nпутей Composer через него.",[244,796,797,798,282,800,264],{},"На macOS заглавная буква сходит с рук, на боевом Linux класс просто не найдётся.\nПроверяется в ",[279,799,292],{},[279,801,802],{},"check_lowercase",[266,804,806],{"id":805},"несимметричные-имена-каталогов-фронта","Несимметричные имена каталогов фронта",[808,809,814],"pre",{"className":810,"code":812,"language":813},[811],"language-text","install\u002Fcss\u002Fshef.options\u002F     -> \u002Fbitrix\u002Fcss\u002Fshef.options\u002F      (точка)\n     (js)  shef-options\u002F      -> \u002Fbitrix\u002Fjs\u002Fshef-options\u002F       (дефис)\n","text",[279,815,812],{"__ignoreMap":105},[244,817,818,819,822,823,264],{},"Точка — id модуля, дефис — требование имён расширений Битрикса: каталог\n",[279,820,821],{},"\u002Fbitrix\u002Fjs\u002Fshef-options\u002Foptions-markdown"," грузился бы как расширение\n",[279,824,825],{},"shef-options.options-markdown",[244,827,828,829,831,832,835],{},"Своего JS модуль с 3.0.0 не раскладывает — ",[279,830,744],{}," в репозитории нет, —\nно ",[279,833,834],{},"getPublicJsDir()"," остался: по нему установщик убирает каталог, оставшийся\nна порталах от прежних версий.",[244,837,838,839,774,842,845,846,848,849,264],{},"Оба пути выводятся из ",[279,840,841],{},"MODULE_ID",[279,843,844],{},"Constants::getPublicCssDir()"," и\n",[279,847,834],{}," и больше нигде строкой не пишутся. Сходимость с раскладкой\nустановщика проверяет ",[279,850,851],{},"tests\u002Fassets_test.php",[853,854,855],"note",{},[244,856,857,858,863],{},"Источник: ",[248,859,862],{"href":860,"rel":861},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002Fdocs\u002Fmodule-structure.md",[252],"options\u002Fdocs\u002Fmodule-structure.md"," — правки туда, сайт пересобирается сам.",{"title":105,"searchDepth":865,"depth":865,"links":866},3,[867,869,870,871,873],{"id":268,"depth":868,"text":269},2,{"id":349,"depth":868,"text":350},{"id":725,"depth":868,"text":726},{"id":748,"depth":868,"text":872},"Нижний регистр в lib\u002F обязателен",{"id":805,"depth":868,"text":806},"md",{},true,"---\ntitle: \"Раскладка репозитория\"\n---\n\nФайл про устройство репозитория. Опорные точки модуля — в [CLAUDE.md](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002FCLAUDE.md),\nпроцесс — в [CONTRIBUTING.md](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002FCONTRIBUTING.md), сборка — в\n[build-and-install.md](\u002Fmodules\u002Foptions\u002Fbuild-and-install).\n\n## Модуль лежит в корне, и это вынужденно\n\nComposer разворачивает в целевой каталог **корень пакета целиком** и подкаталоги\nвыбирать не умеет. Поэтому `lib\u002F`, `install\u002F`, `lang\u002F` лежат прямо в корне\nрепозитория, рядом с `build.sh` и `.github\u002F`, а не в отдельном подкаталоге вроде\n`src\u002F`.\n\nПлата за это — два списка в шапке `build.sh`:\n\n* **SHIP** — уезжает на портал и в Composer-пакет;\n* **KEEP** — остаётся в репозитории.\n\n**Файл, не попавший ни в один список, роняет сборку.** Это единственная\nстраховка такой раскладки: без неё новый файл однажды уехал бы на портал молча.\n\nТот же список продублирован в `.gitattributes` через `export-ignore` — он решает,\nчто попадёт в Composer-пакет, потому что `git archive` его соблюдает. Списки\nобязаны совпадать, иначе на портал уедет разное в зависимости от способа\nустановки. Сверяется автоматически и в обе стороны, см. `check_gitattributes`.\n\n## Что где лежит\n\n| путь | | что это |\n|---|---|---|\n| `install\u002Findex.php` | SHIP | установщик, класс `shef_options extends CModule` |\n| `install\u002Fversion.php` | SHIP | `VERSION` и `VERSION_DATE` — источник истины о версии |\n| `install\u002Fcss\u002F` | SHIP | стили страницы настроек; установщик раскладывает их в `\u002Fbitrix\u002Fcss` |\n| `.settings.php` | SHIP | настройки модуля: ajax-контроллеры, карта раскладки `installDir` |\n| `include.php` | SHIP | точка входа модуля: подключает `autoload.php`, `def-functions.php` и `register-js.php` |\n| `def-functions.php` | SHIP | глобальные `_log()` и `_pr()`, которые зовёт трейт `TraitList\\Log` |\n| `autoload.php` | SHIP | зависимости модуля и регистрация чужих namespace |\n| `project-context.php` | SHIP | знает, есть ли на проекте Composer и где его `vendor` |\n| `options.php`, `options_conf.php`, `optionsconfig.php` | SHIP | страница настроек модуля |\n| `lib\u002F` | SHIP | классы модуля, **имена файлов строго строчными** |\n| `lang\u002Fru\u002F` | SHIP | языковые файлы, зеркалят структуру `lib\u002F` |\n| `README.md`, `CHANGELOG.md`, `LICENSE` | SHIP | |\n| `composer.json` | SHIP | манифест пакета |\n| `docs\u002F` | KEEP | вся документация, и модуля, и репозитория |\n| `build.sh` | KEEP | сборка и проверки |\n| `tests\u002F` | KEEP | тесты |\n| `examples\u002F` | KEEP | запускаемые примеры к строительным блокам |\n| `.claude\u002Fskills\u002F` | KEEP | навыки агента (источник для всей линейки) плюс `evals\u002F` внутри навыков, `sync.sh` и `MANIFEST` |\n| `.github\u002F` | KEEP | CI и релиз |\n| `CONTRIBUTING.md` | KEEP | |\n| `CLAUDE.md` | KEEP | памятка агенту: она про репозиторий, а не про модуль |\n| `.gitattributes`, `.gitignore` | KEEP | |\n| `.php-cs-fixer.dist.php` | KEEP | правила форматирования; гоняются `composer run lint`, не из `build.sh` |\n| `composer.lock` | KEEP | версии инструментов разработчика; на зависимости пакета не влияет |\n\n## Почему документация не едет на портал\n\nДокументация живёт в репозитории целиком. В поставке из неё остаётся только\n`README.md` — как readme пакета, — и все ссылки из него ведут на GitHub.\n\nРаньше модуль рендерил `README.md` прямо в настройках: отдельная вкладка,\najax-контроллер, вендорённый php-markdown и js-расширение к нему. В 3.0.0 этот\nблок убран целиком. Документация на GitHub всегда свежая, а не той версии, что\nкогда-то поставили на портал, — значит, второй её копии внутри модуля хватало\nровно на то, чтобы расходиться с первой. Заодно с ней из поставки ушли\n`vendor\u002FMichelf\u002F`, `install\u002Fjs\u002F` и единственный ajax-контроллер модуля.\n\n## Нижний регистр в `lib\u002F` обязателен\n\n`Bitrix\\Main\\Loader` отображает класс в путь **строчными**, разбирая первые два\nсегмента namespace как id модуля: `Shef\\Options\\Main\\Utils` ищется как\n`bitrix\u002Fmodules\u002Fshef.options\u002Flib\u002Fmain\u002Futils.php`. Отсюда же пустой\n`registerNamespace` в `.settings.php` — он нужен только для чужих namespace, а\nсвоих у модуля нет. Читает этот ключ `autoload.php`.\n\n`project-context.php` выглядит частью той же механики, но ею не является:\nфайл объявляет глобальный `ShComposerContext` и едет в поставку, однако в самом\nмодуле его никто не подключает — `registerNamespace` задан пустым литералом.\nЭто заготовка для модулей линейки, чей `.settings.php` может собрать список\nпутей Composer через него.\n\nНа macOS заглавная буква сходит с рук, на боевом Linux класс просто не найдётся.\nПроверяется в `build.sh`, `check_lowercase`.\n\n## Несимметричные имена каталогов фронта\n\n```\ninstall\u002Fcss\u002Fshef.options\u002F     -> \u002Fbitrix\u002Fcss\u002Fshef.options\u002F      (точка)\n     (js)  shef-options\u002F      -> \u002Fbitrix\u002Fjs\u002Fshef-options\u002F       (дефис)\n```\n\nТочка — id модуля, дефис — требование имён расширений Битрикса: каталог\n`\u002Fbitrix\u002Fjs\u002Fshef-options\u002Foptions-markdown` грузился бы как расширение\n`shef-options.options-markdown`.\n\nСвоего JS модуль с 3.0.0 не раскладывает — `install\u002Fjs\u002F` в репозитории нет, —\nно `getPublicJsDir()` остался: по нему установщик убирает каталог, оставшийся\nна порталах от прежних версий.\n\nОба пути выводятся из `MODULE_ID` в `Constants::getPublicCssDir()` и\n`getPublicJsDir()` и больше нигде строкой не пишутся. Сходимость с раскладкой\nустановщика проверяет `tests\u002Fassets_test.php`.\n\n::note\nИсточник: [options\u002Fdocs\u002Fmodule-structure.md](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Foptions\u002Fblob\u002Fmain\u002Fdocs\u002Fmodule-structure.md) — правки туда, сайт пересобирается сам.\n::\n\n",{"title":87,"description":90},"4tZVgkU8DRZLHtRgUSfe4Tt5Di9GauvOl9IVaiLvGyg",[881,882],{"title":82,"path":83,"stem":84,"description":85,"children":-1},{"title":92,"path":93,"stem":94,"description":95,"children":-1},1790857270085]