opencode-better-hashline
v0.9.0
Published
Fail-closed, snapshot-bound line editing for OpenCode
Maintainers
Readme
| Точные данные | Зависимые от операции значения по умолчанию | Разрешения OpenCode | Защищённая публикация |
| :--- | :--- | :--- | :--- |
| Сохранённые байты файла вместо коротких хешей строк | Для инкрементальных операций отсутствие режима означает точный перенос unique, а для replace_file и lifecycle-операций остаётся строгий режим | Используются существующие разрешения read, edit и external_directory | Один план, повторная проверка и публикация без перезаписи |
[!IMPORTANT] Better Hashline защищает транспорт редактирования, но не является файловой транзакцией или песочницей безопасности. Команды оболочки и враждебные внешние процессы находятся вне его гарантий. Перед использованием в чувствительной среде прочитайте модель угроз.
[!NOTE] Это русскоязычный обзор проекта. Нормативными источниками для точных контрактов, кодов ошибок и граничных случаев остаются английские README и спецификация протокола.
Быстрый старт
Требования: OpenCode >=1.18.3 <2 и Bun >=1.3.0.
opencode plugin opencode-better-hashlineЛибо добавьте пакет в opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-better-hashline"]
}После изменения конфигурации перезапустите OpenCode. Плагин сразу использует зависящие от операции настройки по умолчанию, обязательных параметров нет.
Убедитесь, что пакет действительно загружен:
opencode debug agent build --tool hashline_read --params '{"filePath":"README.md","limit":1}'Результат должен начинаться с @hashline snapshot=. Если пакет не удалось импортировать, OpenCode может продолжить работу без плагина, а встроенные инструменты изменения файлов останутся доступны. Диагностический fail-closed режим начинается только после загрузки модуля плагина.
Зачем нужны точные снимки
Во многих инструментах рядом с каждой строкой выводится короткая контрольная сумма, которая затем считается подтверждением актуальности. Better Hashline разделяет адресацию и полномочия:
- модель видит компактные строки вида
N|content; - плагин хранит точные байты файла за непрозрачным 128-битным идентификатором снимка;
- перед записью файл перечитывается, после чего применяется строгая проверка байтов либо точный однозначный перенос в зависимости от операции и
rebase; - изменённая цель без точного однозначного переноса, неоднозначное или конфликтующее изменение отклоняется до мутации.
| Свойство | Поведение Better Hashline |
| --- | --- |
| Актуальность | Точные сохранённые байты вместо 8/12/16-битной метки |
| Адресация | Привычные N|content и случайный ID снимка |
| Устаревшие изменения | Для инкрементального пакета без rebase используется точный перенос unique; явный none требует полного совпадения байтов |
| Пакетные операции | Полностью разбираются и проверяются до изменения файла |
| Разрешения | Повторно используются разрешения OpenCode |
| Публикация | Временный файл в том же каталоге, сброс, повторная проверка, одна попытка переименования |
| Встроенные инструменты | Нативный read сохраняется; edit, write и apply_patch по умолчанию скрыты и заблокированы |
Как это работает
1. Агент читает редактируемый снимок
Для UTF-8 файла, который планируется изменить, агент вызывает hashline_read вместо обычного read:
@hashline snapshot=s_J7yi7wDyv3j9xQ2zP5kL8A sha256=6d09c2db9f10 lines=3 coverage=complete
1|export const retries = 2;
2|await connect();
3|return client;
@eofПрефиксы являются аннотациями, а не содержимым файла. Каждый заголовок @hashline содержит coverage=partial|complete, вычисленное по свидетельствам, уже выданным на момент рендеринга, и самой странице-кандидату. coverage=complete означает, что этого набора достаточно для полного редактируемого покрытия BOF-to-EOF; если кандидат остаётся действительным, а именно эта страница доставлена и подтверждена, полнота сохраняется при выдаче других страниц. coverage=partial означает, что в момент рендеринга этого набора было недостаточно, однако другая страница, доставленная и подтверждённая позднее или в ином порядке, может завершить покрытие снимка и сделать прогноз консервативным. Рендеринг и ожидающий подтверждения вывод ничего не выдают; признанный недействительным кандидат также ничего не выдаёт.
partial=true описывает только текущую страницу: она сама не содержит полного редактируемого покрытия. Поэтому сочетание partial=true coverage=complete допустимо, если выданных на момент рендеринга свидетельств вместе с текущей страницей-кандидатом достаточно для полного совокупного покрытия. @more означает остановку до конца файла, а @eof - достижение EOF; partial=true может сопровождать оба варианта.
Строка вида N!|... [preview only; line not issued] слишком велика для одной страницы и не может быть изменена по ссылке. Последующие страницы не смогут выдать эту строку: нужно безопасно увеличить maxOutputBytes в допустимых пределах либо остановиться и вручную реструктурировать файл, не используя preview как исходный текст.
2. Агент отправляет логические операции
{
"filePath": "src/client.ts",
"snapshotId": "s_J7yi7wDyv3j9xQ2zP5kL8A",
"readbackLimit": 100,
"operations": [
{
"op": "replace",
"startLine": 1,
"endLine": 1,
"lines": ["export const retries = 5;"]
},
{
"op": "insert",
"afterLine": 2,
"lines": ["await audit();"]
}
]
}replace удаляет точный включительный диапазон startLine..endLine, а lines содержит полную замену. Соседние строки сохраняются, поэтому их не нужно повторять. lines: [] удаляет диапазон.
В этом примере rebase отсутствует, а пакет содержит только инкрементальные операции, поэтому выбирается точный перенос unique с отказом при неоднозначности. Если весь текущий файл должен побайтово совпадать со снимком, укажите "rebase": "none".
Для единственной операции replace_file отсутствие rebase означает строгий none. Это текстовая операция с требованием полного выданного покрытия; она поддерживает явно запрошенный readback, но никогда не запрашивает его автоматически. Отсутствие finalNewline сохраняет состояние снимка, если lines не пуст. Само lines: [] создаёт пустой файл, автоматически подразумевая finalNewline:false; явное true с пустым массивом остаётся недопустимым.
Для любой текстовой операции, включая replace_file, readback:true запрашивает одну страницу результата с окном по умолчанию. Наличие readbackOffset или readbackLimit само включает readback, поэтому отдельный флаг не нужен; явное readback:false вместе с окном недопустимо. Заголовок страницы сохраняет прогноз совокупного coverage, вычисленный во время рендеринга, но ссылки выдаются только после подтверждения доставки; признанный недействительным кандидат ничего не выдаёт.
Все координаты пакета относятся к исходному неизменяемому снимку, а не к промежуточным результатам предыдущих элементов массива. Известные изменения одного файла следует отправлять одним вызовом.
Поддерживаемые операции:
| Операция | Назначение |
| --- | --- |
| replace | Заменить или удалить точный диапазон строк |
| insert | Вставить строки после исходной границы |
| replace_file | Полностью заменить файл при наличии полного покрытия |
| copy_range | Скопировать выданный диапазон без повторной передачи текста |
| move_range | Переместить диапазон с проверкой всего коридора |
| delete_file | Удалить полностью выданный снимок файла |
| move_file | Переместить файл без перезаписи назначения |
hashline_write предназначен только для создания новых файлов; его строгой схеме передаются лишь filePath и content. Каждый вызов закрепляет самый глубокий существующий предок для проверки идентичности пути, затем резервирует и блокирует максимум 64 изначально отсутствующих каталога плюс цель. Пока удерживаются исходные блокировки резерва и ещё не запрошено разрешение на изменение, соседний вызов мог создать непрерывный префикс каталогов. Better Hashline точно проверяет и использует этот префикс, сохраняя исходный набор блокировок отсутствующих имён и цели, и сообщает об этом как об успешном результате вместо ошибки и повтора. Только оставшиеся каталоги создаются эксклюзивно от корня к листу, а файл публикуется без перезаписи. Если этот вызов уже создал каталог или исход mkdir стал неоднозначным, дальнейшая ошибка возвращает PARTIAL_PUBLICATION без отката; уже ожидающие вызовы с пересекающимися путями останавливаются до изменения. Перед новым вызовом нужно проверить и согласовать дерево и цель. Частичный результат аннулирует затронутые снимки и отвязывает live epoch native aliases; после согласования нужен новый доставленный hashline_read, а старые snapshot ID больше не применимы.
Lifecycle-операциями являются только delete_file и move_file. Отсутствие или явное значение rebase: "none" означает строгую побайтовую проверку; unique запрещён. Эти операции не возвращают readback и отклоняют readback:true, readbackOffset и readbackLimit. move_file по-прежнему требует существующего родителя, не создаёт каталоги и не перезаписывает назначение.
3. Плагин проверяет и публикует
Плагин канонизирует и авторизует все пути, проверяет область снимка и выданное покрытие, берёт детерминированные блокировки, перечитывает файл и строит точный план изменения до запроса разрешения. После одобрения план не пересчитывается.
Текст записывается во временный файл в том же каталоге и публикуется одной попыткой переименования. Удаление повторно проверяет прямую запись каталога. Перемещение не перезаписывает существующий путь и проверяет точное назначение до удаления источника.
Кратковременные ошибки чтения состояния файловой системы обрабатываются внутри инструментов с небольшим ограниченным и прерываемым бюджетом повторных полных проверок. Если точные путь, идентичность, байты и итог публикации стабилизировались, исходный вызов завершается успешно. Системные вызовы, публикующие изменение, повторно не выполняются; устойчивое расхождение, потеря provenance или неоднозначная публикация по-прежнему возвращают ошибку с безопасным следующим действием.
Режимы изменений
Если rebase отсутствует, режим выбирается по операции:
| Пакет | Режим при отсутствии rebase |
| --- | --- |
| Только replace, insert, copy_range и move_range | unique |
| Единственная replace_file, delete_file или move_file | none |
Для инкрементального пакета отсутствие rebase запрашивает точный текстовый перенос с отказом при неоднозначности. Явный rebase: "unique" выбирает то же поведение и сохраняет прежние ограничения по поддерживаемым операциям. Цель переносится только тогда, когда точные ненормализованные данные однозначно определяют исходное вхождение и весь успешно сопоставленный ограниченный контекст согласуется.
Явный rebase: "none" требует полного побайтового совпадения для любой поддерживаемой операции. Любое изменение после hashline_read возвращает строгий TARGET_CHANGED. Этот режим нужен вызывающим сторонам, которым требуется сравнение полного файла перед построением плана; публикация всё равно не является атомарным kernel CAS.
Режим unique доказывает только точную текстовую идентичность и перенос. Он никогда не выбирает ближайшее совпадение, не нормализует окончания строк, не исправляет отступы и не вставляет маркеры конфликтов. Он не доказывает семантическую независимость или причинную связь с историей изменений. Если current-байты отличались и точный unique rebase завершился успешно, первая строка результата добавляет Exact unique rebase occurred.. Это сообщает о stale-byte recovery, а не обязательно о сдвиге координат.
Миграция с 0.7.0
В версии 0.7.0 отсутствие rebase всегда означало строгий none. Новое зависимое от операции поведение является семантически несовместимым: инкрементальный пакет без rebase теперь может примениться после постороннего внешнего изменения, если его точные текстовые данные переносятся однозначно. Клиенты, которым необходимо полное совпадение байтов файла, должны явно передавать "rebase": "none".
При изменившихся байтах инкрементальный вызов без rebase теперь может завершиться успешно либо вернуть диагностику точного переноса, например TARGET_CHANGED, BOUNDARY_CHANGED или AMBIGUOUS_RELOCATION, вместо безусловного строгого TARGET_CHANGED для всего файла. Успешный changed-byte rebase сообщает Exact unique rebase occurred. независимо от того, сдвинулись ли координаты; явный none сохраняет строгий путь диагностики. unique остаётся только текстовым механизмом, не доказывает семантическую независимость или причинную связь с историей изменений и никогда не использует нормализацию или нечёткий поиск.
Теперь каждый заголовок @hashline обязан содержать coverage=partial|complete; парсеры должны принимать partial=true coverage=complete и не считать ожидающий подтверждения вывод выданным. Единственная строгая операция replace_file поддерживает явно запрошенный текстовый readback, а параметры readback отклоняют только delete_file и move_file; при отсутствии запроса successor не создаётся.
Изменение контракта меняет идентичность схемы и пакета native aliases, хотя маркер остаётся native-aliases/v2. После обновления перезапустите плагин или хост и получите новый доставленный и подтверждённый hashline_read до изменения через native aliases; ID снимка версии 0.7.0 повторно использовать нельзя. Нормативные детали находятся в разделе Migration From 0.7.0.
Конфигурация
Параметры передаются вторым элементом кортежа плагина:
{
"plugin": [
[
"opencode-better-hashline",
{
"enforce": true,
"toolSurface": "hashline",
"maxFileBytes": 8388608,
"maxLines": 100000,
"maxCacheBytes": 67108864,
"maxSnapshots": 64,
"maxSnapshotsPerPath": 4,
"maxSnapshotsPerSession": 32,
"snapshotTtlMs": 1800000,
"maxOutputBytes": 40960,
"maxContextLines": 4,
"lspDiagnostics": true
}
]
]
}| Параметр | По умолчанию | Назначение |
| --- | ---: | --- |
| enforce | true | Скрывать и отклонять встроенные edit, write и apply_patch |
| toolSurface | "hashline" | Набор ID инструментов; "native-aliases" является экспериментальным режимом |
| maxFileBytes | 8 MiB | Максимальный размер редактируемого или создаваемого текста |
| maxLines | 100 000 | Максимальное число логических строк |
| maxCacheBytes | 64 MiB | Приблизительный бюджет памяти снимков |
| maxSnapshots | 64 | Число снимков на процесс |
| maxSnapshotsPerPath | 4 | Ревизии одного пути в сессии |
| maxSnapshotsPerSession | 32 | Снимки одной сессии OpenCode |
| snapshotTtlMs | 30 минут | Время жизни снимка |
| maxOutputBytes | 40 KiB | Бюджет вывода чтения; настраивается до 45 KiB |
| maxContextLines | 4 | Точный контекст с каждой стороны для unique |
| lspDiagnostics | включена | Управляемая Error-диагностика из подходящих публичных записей LSP OpenCode и необязательных переопределений; false отключает её |
Неизвестные или противоречивые параметры переводят плагин в диагностический fail-closed режим: встроенные инструменты изменения остаются скрыты, а Better Hashline возвращает CONFIG_INVALID. Исправьте настройки и перезапустите OpenCode. maxCacheBytes должен быть не меньше трёх maxFileBytes.
enforce: false следует использовать только для миграции или A/B-сравнения: встроенные инструменты изменения при этом остаются доступны.
Управляемая LSP-диагностика
lspDiagnostics включена по умолчанию. Отсутствие параметра, true и объект оставляют её включённой; только false является явным отказом. При первом запросе к управляемому LSP Better Hashline получает эффективную конфигурацию OpenCode для текущего каталога через публичный хук config или один ограниченный вызов публичного client.config.get. Из объекта config.lsp импортируются только записи с явными непустыми command и extensions; отключённые, некорректные, неприменимые и похожие на приватные записи пропускаются. Значение config.lsp: true может включить встроенные приватные определения OpenCode, но они не представлены в публичной конфигурации и не могут быть клонированы плагином.
Объект lspDiagnostics может добавить сервер или переопределить импортированную запись с тем же id. Массив servers может быть пустым. Если после объединения нет ни одного подходящего сервера, подсистема является точным no-op: менеджер и процессы не создаются, предупреждения не выводятся, а бюджет и байты прежнего результата не меняются. Значения по умолчанию и допустимые диапазоны:
startupTimeoutMs: 15 000 мс (1 000..60 000);diagnosticsTimeoutMs: 5 000 мс (250..30 000);maxDiagnostics: 20 Error-записей (1..100);maxDiagnosticsBytes: 8 KiB (1..16KiB) для рекомендательного блока или обязательного предупреждения.
Например, публичную запись LSP из эффективной конфигурации OpenCode можно использовать напрямую:
{
"lsp": {
"typescript": {
"command": ["bun", "x", "--no-install", "typescript-language-server", "--stdio"],
"extensions": [".ts", ".tsx", ".js", ".jsx"],
"initialization": {
"tsserver": {
"path": "./node_modules/@typescript/old/lib/tsserver.js"
}
}
}
},
"plugin": [
[
"opencode-better-hashline",
{ "lspDiagnostics": true }
]
]
}Команда bun x --no-install не устанавливает отсутствующие пакеты, поэтому языковой сервер и TypeScript должны быть доступны в проекте. Путь @typescript/old полезен только проектам, которые намеренно установили совместимый пакет TypeScript под таким псевдонимом; в остальных случаях укажите фактический tsserver.path проекта или не задавайте его. Поля rootMarkers, дополнения окружения и независимые определения можно указать в lspDiagnostics.servers; запись с совпадающим id имеет приоритет над импортированной.
Эффективный набор серверов и лимиты host tool_output фиксируются при первом запросе менеджера, а не при загрузке модуля. Последующие обновления хука config игнорируются до перезапуска плагина или хоста. Сам процесс запускается лениво только при подходящем прогреве чтения или опубликованной мутации и сохраняется по каноническому корню, ID сервера и неизменяемому digest нормализованной конфигурации. Клиенты Better Hashline не разделяют клиентов host LSP OpenCode и могут дублировать процессы, кеши и потребление ресурсов.
Маршрутизация требует совпадающее расширение и абсолютный канонический путь внутри активного канонического worktree. Безопасные относительные rootMarkers выбирают ближайшего стабильного предка с маркером, иначе корнем служит worktree. Если OpenCode передаёт / как sentinel worktree, Better Hashline ограничивается активным directory, а не корнем файловой системы. Внешние пути и выход через symlink не запускают и не переиспользуют управляемый клиент.
Стабильный hashline_read может прогреть подходящие клиенты, не задерживая и не меняя вывод. Одна абсолютная граница diagnosticsTimeoutMs охватывает ожидание очереди, маршрутизацию, запуск, синхронизацию, lifecycle и диагностику всех подходящих серверов. Работа после мутации начинается только вслед за проверенной публикацией и освобождением блокировки пути, никогда не выполняется после PARTIAL_PUBLICATION и не откатывает опубликованные байты. Создание и текстовое изменение передают неизменяемый URI и точный текст commit; удаление закрывает принадлежащий менеджеру документ; перемещение закрывает источник и независимо открывает назначение. Watched-file notifications не отправляются.
После ожидания LSP плагин стабильно перечитывает цель только для проверки, что текущая идентичность и байты всё ещё совпадают с опубликованным результатом. Drift скрывает диагностику, аннулирует ожидающий readback, помещает binding в карантин и выводит обязательное предупреждение. Очередная работа со старой ревизией подавляется. При чистом результате ничего не добавляется; иначе только severity Error очищается, дедуплицируется, детерминированно сортируется и выводится как явно рекомендательная:
@better-hashline-lsp advisory=true errors=1 truncated=false
LSP| src/example.ts:4:9 [typescript/2322] Type 'string' is not assignable to type 'number'.Ошибка запуска, timeout, crash, отмена, некорректные или слишком большие protocol data, неподдерживаемая синхронизация и lifecycle-сбой дают ограниченное обязательное предупреждение LSP_DIAGNOSTICS_UNAVAILABLE. Оно сообщает, что мутация уже выполнена, её нельзя повторять и перед продолжением нужны проверка пути и новый hashline_read. Диагностика и предупреждения являются post-commit наблюдениями, а не полномочием актуальности или доказательством семантической корректности.
Блок LSP получает дополнительный запас байтов и строк OpenCode tool_output сверх прежнего maxOutputBytes, но ограничен maxDiagnosticsBytes и лимитами хоста. Необязательная диагностика усекается или удаляется раньше существующего receipt или приложенного readback. Обязательное предупреждение о недоступности или drift имеет приоритет и может уменьшить readback либо усечь длинный прежний receipt, чтобы сохранить запрет повторной мутации. Полный итоговый вывод подтверждается после доставки. В renderer metadata native aliases поле намеренно остаётся точно diagnostics: {}.
Команды запускаются напрямую без shell в каноническом корне и наследуют окружение хоста с ограниченными дополнениями. Размер protocol body ограничен 8 MiB, headers - 16 KiB, сохранённый stderr - 64 KiB; очереди, диагностика и завершение дерева процессов также ограничены. Менеджер допускает не более 64 постоянных клиентов и 4 096 document bindings/queues; клиент хранит не более 64 открытых документов и 16 MiB текста, очередь документа содержит не более 64 задач, а сбойный клиент перезапускается не более двух раз за скользящие 60 секунд.
Клиент использует статическую UTF-16 синхронизацию и push- или pull-диагностику. Он не поддерживает dynamic registration и watched-file notifications, не форматирует файлы, не реализует hover/definition/references/symbols/rename, не выполняет code actions, не принимает workspace/applyEdit, не исполняет произвольные или запрошенные сервером команды и не обновляет host LSP OpenCode. Единственное исключение на уровне командного протокола действует для typescript-language-server: если при инициализации объявлена точная команда typescript.tsserverRequest, клиент отправляет фиксированные запросы syntacticDiagnosticsSync, semanticDiagnosticsSync и suggestionDiagnosticsSync исключительно как post-change барьер свежести диагностики. Актуальная push-диагностика с противоречащими чистому результату ошибками имеет приоритет; некорректные или неподдерживаемые command evidence никогда не подтверждают чистый результат. Для интерактивных возможностей по-прежнему используются встроенные lsp и formatter OpenCode.
Поскольку конфигурация фиксируется лениво, изменение opt-out, импортированного config.lsp, переопределений серверов, лимитов или host output после первого запроса менеджера требует перезапуска плагина или хоста. До следующей мутации получите новый доставленный и подтверждённый hashline_read. Native aliases должны связать новый live epoch; старые ID снимков остаются недействительными.
Экспериментальные нативные псевдонимы
toolSurface: "native-aliases" публикует тот же snapshot-bound исполнитель под именем edit для не-GPT маршрутов и apply_patch для GPT-5-подобных маршрутов, чтобы OpenCode мог использовать штатный рендеринг diff. Режим требует enforce: true, совместимый хост и свежий подтверждённый hashline_read в той же сессии.
{
"plugin": [
[
"opencode-better-hashline",
{ "enforce": true, "toolSurface": "native-aliases" }
]
]
}После изменения конфигурации, версии пакета, схемы, версии хоста или набора инструментов перезапустите плагин и выполните новое доставленное чтение. Старые ID снимков не восстанавливаются. Держите Better Hashline последним среди плагинов, определяющих edit или apply_patch.
После установки и каждого изменения порядка плагинов или конфигурации запустите изолированный проверяющий сценарий без учётных данных:
bunx opencode-better-hashline verify --surface allПроизводственным режимом по умолчанию и основной рекомендацией остаётся уникальный набор инструментов hashline.
Почему не короткий хеш каждой строки
Короткий хеш помогает модели скопировать адрес, но не может надёжно доказать актуальность:
- изменённая цель проходит 8-битную проверку с вероятностью
1/256, а 16-битную с вероятностью1/65 536; - среди 1 000 идентификаторов вероятность хотя бы одной 16-битной коллизии составляет около
99,95%; - проверка только концов не замечает изменения внутри многострочного диапазона;
- более широкие хеши увеличивают промпт, но не решают вопросы разрешений, конфликтов, гонок и публикации.
Поэтому модель получает компактную адресацию, а сервер подтверждает актуальность точными байтами и полным SHA-256.
Проверяемые результаты
Текущий детерминированный runner использует schema v11. Его write-once сохранённый результат: schema-v11 managed LSP diagnostics. Schema v11 сохраняет неизменные классификации 29 сценариев и прежние fixtures schema v10 для совокупного coverage в заголовке и явного readback у replace_file, а затем добавляет production-composed fixtures вывода и запаса OpenCode для управляемого LSP через общие production-пути lspLegacyLimits и buildLspOutput. Они охватывают чистый побайтово неизменный вывод, Error-диагностику, запас байтов и строк, обязательные предупреждения manager/drift и недостаточный host envelope, не запуская language server или model. Strict-only defaults по-прежнему проверяются runtime-тестами, а не этим корпусом. Неизменяемые результаты от schema-v5 до schema-v10, а также pilot-v7, сохраняют исходные байты и область утверждений.
| Адаптер | Небезопасно принятые | Ложные отказы |
| --- | ---: | ---: |
| Better Hashline, явный none | 0 | 5 |
| Better Hashline, явный unique | 0 | 0 |
| Better Hashline, отсутствие поля/default | 0 | 0 |
| Точный поиск/замена только цели | 5 | 1 |
| Только номера строк | 21 | 0 |
| 8-битные хеши концов | 6 | 4 |
| 16-битные хеши концов | 5 | 4 |
Это механическая проверка текстового протокола в памяти, а не доказательство семантической независимости, качества модели и не полный тест хуков, разрешений или файловой публикации. Методология и ограничения описаны в документе о бенчмарках.
Совместимость
| Компонент | Статус |
| --- | --- |
| OpenCode >=1.18.3 <2, стабильный Plugin API V1 | Поддерживается; verifier закреплён на 1.18.4 |
| Экспериментальные native aliases | Проверка возможностей при запуске, только явное включение |
| Управляемая LSP-диагностика | Включена по умолчанию; импортирует подходящие явные публичные записи config.lsp и необязательные переопределения, только внутри канонического worktree |
| Windows, Linux, macOS | CI и файловые тесты |
| UTF-8, BOM, LF, CRLF, смешанные EOL, одиночный CR | Поддерживается |
| Каталоги, изображения, PDF, бинарные файлы | Используйте встроенный read; здесь они не редактируются |
| Hardlink, специальные и read-only файлы | Отклоняются |
| OpenCode Plugin API V2 | Не поддерживается |
Ограничения
- Блокировка путей координирует только этот процесс плагина, а не внешние процессы.
- Между финальной проверкой и переименованием остаётся неизбежное окно; это не kernel CAS.
- Пакет операций одного файла проверяется атомарно, но транзакции между файлами нет.
- Атомарность переименования, долговечность каталога, ACL, xattr, hardlink, сетевые ФС и открытые дескрипторы Windows зависят от платформы.
enforceблокирует встроенные ID инструментов изменения, но не ограничивает оболочку или другие плагины.- Управляемая LSP-диагностика использует отдельные постоянные процессы и состояние, может дублировать потребление ресурсов host LSP OpenCode и остаётся рекомендацией, а не доказательством семантической корректности.
- Кеш снимков находится в памяти и исчезает после перезапуска, истечения TTL или вытеснения.
PARTIAL_PUBLICATIONможет оставить созданные этим вызовом каталоги, новый файл или обе стороны частичного перемещения; небезопасный автоматический откат намеренно не выполняется, а уже ожидающие операции с пересекающимися путями останавливаются до изменения.
Полные границы гарантий и доверия находятся в модели угроз.
Документация
- Спецификация протокола
- Архитектура
- Модель угроз
- Исследование и аналоги
- Бенчмарки
- Процесс релиза
- Участие в разработке
- Кодекс поведения
- Политика безопасности
- Поддержка
Разработка
bun install --frozen-lockfile
bun run check
bun run test:coverage
bun run build
bun run pack:checkЛицензия
MIT Copyright (c) 2026 Maksim Ivanov.
