Skip to content

Создание плагина ​

Плагин представляет собой отдельную программу. QueryLane запускает команду из plugin.json плагина и общается с ней по JSON-RPC 2.0 через stdin и stdout, по одному JSON-сообщению в строке. Писать плагин можно на любом языке. Официальные плагины и инструменты, которые их собирают, подписывают и публикуют, находятся в репозитории querylane-plugins.

QueryLane устанавливает только пакеты, подписанные официальным ключом QueryLane. Пакет, подписанный другим ключом, можно собрать и проверить, но приложение откажется его устанавливать.

Подготовка репозитория ​

  • Node 24, затем npm install.
  • Копия приложения QueryLane в ../dataflow3/roadmap или путь к ней в QUERYLANE_APP_DIR. Тесты запускают плагины через собственный хост плагинов приложения.
  • Для npm run build закрытый ключ Ed25519 в формате PEM в ~/.querylane/plugin-signing/querylane-official.pem или путь к нему в QUERYLANE_PLUGIN_SIGNING_KEY.

Создание плагина ​

  1. Создайте папку plugins/<name>/ с plugin.json и кодом, при желании добавьте иконку и руководство для ИИ-ассистента.
  2. Добавьте папку в PLUGIN_SOURCES в tools/lib/config.mjs вместе с платформами, например { dir: 'plugins/hello', platforms: ['darwin-aarch64'] }. Для папки, которой нет в списке, тест манифестов упадёт.
  3. Дайте плагину английские и русские тексты с одинаковыми ключами, это тоже проверяет тест манифестов.

plugin.json ​

ПолеЗначение
schemaVersion, apiVersionОба равны 1
idИдентификатор из строчных частей через точку, например com.example.hello
version, minAppVersion1.2.3; самая старая версия QueryLane, которая нужна плагину
author{ "name": "…", "url": "…" }
iconКвадратная SVG или PNG в пакете, до 128 КиБ
permissionsЛюбые из network, download, spawnProcesses, userFiles
platformsКлючи вроде darwin-aarch64, у каждого command, необязательные команды setup и env
contributes.stepsid, language кода шага, starterCode и template: true, чтобы значения ${...} подставлялись до того, как плагин получит код
contributes.settingskey, type, default, group, scope и другие поля
contributes.toolsname, description, inputSchema (JSON Schema)
contributes.runEvents["finished"], чтобы получать уведомления о запусках
contributes.guideMarkdown-файл с инструкциями по написанию кода шагов
locales, defaultLocaleТексты по языкам и резервный язык

В командах и значениях env можно использовать ${pluginDir} (распакованный пакет), ${dataDir} (папка, которая переживает обновления) и ${node} (Node.js, на котором работает QueryLane). Команды setup выполняются один раз перед первым запуском и после обновлений.

Типы настроек: string, number, boolean, enum, stringList, secret и proxyProfile. scope принимает значения plugin (по умолчанию), step или notification.

Каждому языку нужны name и description, а также плоские ключи: steps.<id>.title, settings.<key>.label, settings.<key>.description, settings.<key>.options.<option>, groups.<group> и errors.<reasonCode>.

Протокол ​

QueryLane отправляет такие запросы:

МетодОтвет
initialize{ "apiVersion": 1 }
prepareВыполняется один раз после установки и обновления, например чтобы скачать браузер
step/run{ "summary": {...}, "rows": [...] } для code, settings, inputs, variables, timeoutMs, artifactsDir и других параметров
tool/call, tool/close{ "data": ..., "images": [...] } на вызов инструмента; tool/close завершает сессию инструментов
run/finishedСообщает о полном запуске задачи, у которой плагин указан в уведомлениях
shutdownПриходит перед тем, как QueryLane остановит плагин

Во время обработки запроса плагин может отправлять уведомления rows, progress и artifact (kind равен screenshot, html или file), указав в requestId идентификатор запроса. step/cancel приходит уведомлением с runId запуска, который нужно остановить.

Об ошибках сообщайте ошибками JSON-RPC с data.reasonCode. QueryLane покажет текст errors.<reasonCode> из плагина. Оставьте stdout для сообщений протокола, а логи пишите в stderr. Завершайте работу, когда закрывается stdin.

Минимальный пример ​

plugins/hello/plugin.json:

json
{
  "schemaVersion": 1,
  "id": "com.example.hello",
  "version": "1.0.0",
  "apiVersion": 1,
  "author": { "name": "Example" },
  "permissions": [],
  "platforms": {
    "darwin-aarch64": { "command": ["${node}", "${pluginDir}/main.mjs"] }
  },
  "contributes": {
    "steps": [{ "id": "greet", "language": "plaintext", "template": true, "starterCode": "Hello, ${name}" }]
  },
  "locales": {
    "en": { "name": "Hello", "description": "Returns a greeting as a row", "steps.greet.title": "Greeting" },
    "ru": { "name": "Привет", "description": "Возвращает приветствие строкой", "steps.greet.title": "Приветствие" }
  }
}

plugins/hello/main.mjs:

js
import readline from 'node:readline';

const send = message => process.stdout.write(`${JSON.stringify({ jsonrpc: '2.0', ...message })}\n`);

readline.createInterface({ input: process.stdin }).on('line', (line) => {
  const { id, method, params = {} } = JSON.parse(line);
  if (id === undefined)
    return;
  if (method === 'initialize')
    send({ id, result: { apiVersion: 1 } });
  else if (method === 'step/run')
    send({ id, result: { rows: [{ greeting: params.code.trim() }] } });
  else if (method === 'prepare' || method === 'shutdown')
    send({ id, result: {} });
  else
    send({ id, error: { code: -32601, message: `unknown method ${method}`, data: { reasonCode: 'HELLO_METHOD_UNKNOWN' } } });
});

Сборка и проверка ​

  • npm run build упаковывает каждый плагин из списка в dist/<id>-<version>-<platform>.qlplugin, архив gzip tar с plugin.json в корне, подписывает его и записывает dist/catalog.json. Если ключ не официальный, сборка предупреждает, что приложение откажется от этих пакетов.
  • npm run check запускает линтеры, проверку манифестов валидатором приложения и тесты пакетов и плагинов.

Чтобы проверить плагин целиком, напишите тест в tests/ по образцу существующих: соберите пакет одноразовым ключом Ed25519, установите его во временную папку функцией приложения installPluginPackage, передав этот ключ в trustedKeys, затем вызовите preparePlugin и runPluginStep из plugins/host.ts приложения.

Если приложение запущено из исходников, его npm run dev показывает пакеты из dist/catalog.json в списке Маркетплейс. Официальная подпись им всё равно нужна.

Другие среды выполнения ​

  • Bun: package.json с querylanePlugin.bun (version, entry, binary) компилируется в один исполняемый файл, поэтому пользователям ничего не нужно устанавливать. Для сборки нужен Bun этой version.
  • Python: bundleUv: true в PLUGIN_SOURCES добавляет в пакет bin/uv, а команды setup с его помощью ставят Python и зависимости в ${dataDir}, как это делает плагин Браузер.