@axon-assistant/plugin-sdk 2026.8.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,287 @@
1
+ # @axon-assistant/plugin-sdk
2
+
3
+ Типы для написания плагинов [Axon](https://github.com/bigtaed/axon).
4
+
5
+ Пакет нужен только редактору. В рантайме плагину импортировать из него нечего:
6
+ `api` приезжает аргументом в `activate`. Плагин без единой зависимости — папка,
7
+ которую можно склонировать и запустить, а не проект, который надо сначала собрать.
8
+
9
+ ```bash
10
+ npm i -D @axon-assistant/plugin-sdk
11
+ ```
12
+
13
+ ## Из чего состоит плагин
14
+
15
+ ```
16
+ my-plugin/
17
+ axon.plugin.json манифест — единственный обязательный файл
18
+ index.js точка входа, если у плагина есть код
19
+ skills/*.md инструкции текстом, если они есть
20
+ ```
21
+
22
+ Плагин **без кода** — законная и частая вещь: манифест из десяти строк,
23
+ поднимающий чужой MCP-сервер.
24
+
25
+ ## Манифест
26
+
27
+ ```json
28
+ {
29
+ "id": "weather",
30
+ "name": "Погода",
31
+ "description": "Прогноз для города пользователя",
32
+ "version": "1.0.0",
33
+ "api": 1,
34
+ "main": "./index.js",
35
+ "permissions": ["net"],
36
+ "settings": [
37
+ { "key": "apiKey", "label": "Ключ OpenWeather", "type": "secret", "required": true },
38
+ { "key": "city", "label": "Город", "type": "text", "default": "Варшава" }
39
+ ],
40
+ "skills": "./skills",
41
+ "mcpServers": {},
42
+ "jobs": [{ "name": "утренняя-сводка", "everySeconds": 3600 }]
43
+ }
44
+ ```
45
+
46
+ | Поле | Смысл |
47
+ | --- | --- |
48
+ | `id` | Слаг. Им префиксуются инструменты: `search` → `weather_search` |
49
+ | `api` | Версия API плагинов. Сейчас `1` |
50
+ | `main` | Точка входа. Нет — плагин без кода |
51
+ | `permissions` | `fs`, `net`, `shell`, `secrets`, `journal`. Показываются пользователю до установки |
52
+ | `settings` | Форма, которую нарисует интерфейс. `secret` хранится шифрованным |
53
+ | `skills` | Папка с `*.md` |
54
+ | `mcpServers` | Имя → транспорт. `${ключ}` подставляется из настроек при запуске |
55
+ | `jobs` | Задачи по расписанию. Обработчик вешается через `api.jobs.on` |
56
+
57
+ ## Код
58
+
59
+ ```js
60
+ export async function activate(api) {
61
+ await api.tools.register({
62
+ name: 'forecast',
63
+ title: 'Прогноз погоды',
64
+ description:
65
+ 'Узнать погоду в городе. Вызывай, когда спрашивают про погоду, ' +
66
+ 'дождь, температуру или что надеть.',
67
+ tier: 'sensitive',
68
+ parameters: {
69
+ type: 'object',
70
+ properties: { city: { type: 'string', description: 'Город' } },
71
+ required: ['city'],
72
+ },
73
+ async execute({ city }) {
74
+ const key = api.settings.get('apiKey');
75
+ const res = await fetch(`https://api.openweathermap.org/…&q=${city}&appid=${key}`);
76
+ return JSON.stringify(await res.json());
77
+ },
78
+ });
79
+ }
80
+
81
+ export function deactivate() {}
82
+ ```
83
+
84
+ `execute` возвращает строку или `{ text, mime }`.
85
+
86
+ ## Что даёт `api`
87
+
88
+ | | |
89
+ | --- | --- |
90
+ | `api.tools.register/unregister` | свои инструменты |
91
+ | `api.context.contribute(name, stability, fn)` | абзац в промпт |
92
+ | `api.skills.add` | скилл на лету (обычно они просто файлы в `skills/`) |
93
+ | `api.providers.register` | свой провайдер модели |
94
+ | `api.jobs.on(name, fn)` | обработчик задачи из манифеста |
95
+ | `api.journal.on(fn)` | события ядра (нужно право `journal`) |
96
+ | `api.settings.get/set/onChange` | настройки плагина |
97
+ | `api.memory.facts/remember` | долговременная память пользователя |
98
+ | `api.blobs.write` | большой вывод мимо контекста модели |
99
+ | `api.log.*` | в логи плагина, видные в интерфейсе |
100
+ | `api.dir` / `api.dataDir` | своя папка и папка для своих данных |
101
+
102
+ ## Что плагин может попросить у ядра
103
+
104
+ До сих пор SDK был про то, как плагин **отдаёт** возможности. Обратная сторона —
105
+ четыре вещи, без которых серьёзный плагин не пишется.
106
+
107
+ **Спросить модель.** Ту, которую человек уже настроил:
108
+
109
+ ```js
110
+ const кратко = await api.model.ask({
111
+ system: 'Отвечай одним предложением.',
112
+ prompt: 'О чём этот текст?
113
+
114
+ ' + текст,
115
+ maxTokens: 300,
116
+ });
117
+ ```
118
+
119
+ Свой ключ заводить не нужно, и расход попадает в общий счётчик. Плагин с
120
+ собственным ключом означал бы, что человек платит дважды и второй раз не видит
121
+ за что.
122
+
123
+ Это один вопрос без истории и без инструментов. Нужен агент — им уже является
124
+ Axon; плагину незачем становиться вторым.
125
+
126
+ **Сказать человеку.**
127
+
128
+ ```js
129
+ await api.notify('Сервер упал', 'не отвечает третью минуту');
130
+ ```
131
+
132
+ Показывает тот клиент, который сейчас на связи, — у ядра экрана нет. Мера, а не
133
+ право: плагин, который звенит каждый час просто потому, что проснулся,
134
+ выключают в тот же день вместе со всей пользой.
135
+
136
+ **Сказать о себе.**
137
+
138
+ ```js
139
+ await api.status.set('токен протух', true); // покажется как «не работает»
140
+ await api.status.clear(); // всё наладилось
141
+ ```
142
+
143
+ Состояние плагина ядро выводит из состояния процесса: жив — значит работает.
144
+ Плагин, у которого отвалился внешний сервер, при этом живее всех живых и
145
+ молчит, а человек гадает, почему инструмент не отвечает.
146
+
147
+ **Поискать в переписке.**
148
+
149
+ ```js
150
+ const найдено = await api.history.search('докер', 5);
151
+ ```
152
+
153
+ Тот же поиск, что у агента. Плагин видел факты, но не разговоры — опереться на
154
+ контекст было неоткуда.
155
+
156
+ ## Своя страница настроек
157
+
158
+ Рядом с плагином в списке есть шестерёнка — за ней страница, которую описывает
159
+ сам плагин. Описывает, а не рисует: ни разметки, ни кода для окна плагин не
160
+ присылает. Пусти его рисовать самому — и код плагина окажется в окне с полным
161
+ доступом к ядру, ровно там, откуда его убрали отдельным процессом.
162
+
163
+ **Разделы** группируют поля. Плоский список годится, пока полей пять; дальше
164
+ человек смотрит на два десятка подписей и не понимает, что с чем связано.
165
+
166
+ ```json
167
+ "sections": [
168
+ {
169
+ "title": "Подключение",
170
+ "description": "Токен берётся в настройках вашего аккаунта.",
171
+ "fields": ["host", "token"]
172
+ }
173
+ ]
174
+ ```
175
+
176
+ **Условные поля** появляются, только когда нужны:
177
+
178
+ ```json
179
+ { "key": "port", "label": "Порт", "type": "number",
180
+ "visibleWhen": { "key": "mode", "equals": "self-hosted" } }
181
+ ```
182
+
183
+ Без этого плагин с двумя способами подключения вываливает поля обоих сразу, и
184
+ человек заполняет половину впустую.
185
+
186
+ **Кнопки** — то, ради чего страница вообще нужна: настройки без способа
187
+ проверить, что они верные, это анкета, а не настройка.
188
+
189
+ ```json
190
+ "actions": [
191
+ { "name": "check", "label": "Проверить подключение", "section": "Подключение" },
192
+ { "name": "reset", "label": "Сбросить кэш", "confirm": "Точно очистить?" }
193
+ ]
194
+ ```
195
+
196
+ ```js
197
+ api.actions.on('check', async () => {
198
+ const response = await fetch(`${api.settings.get('host')}/ping`);
199
+ if (!response.ok) throw new Error(`Сервер ответил ${response.status}`);
200
+ return 'Подключение работает';
201
+ });
202
+ ```
203
+
204
+ Возвращённая строка показывается человеку зелёным, брошенная ошибка — красным.
205
+ Отказ здесь не поломка: «не удалось подключиться» — законный ответ кнопки
206
+ «проверить подключение», и падать из-за него нельзя, человек нажал именно
207
+ затем, чтобы это узнать.
208
+
209
+ Рабочий пример со всем сразу — [examples/feeds-plugin](../../examples/feeds-plugin):
210
+ разделы, условное поле, две кнопки, задача по расписанию, инструмент и вклад в
211
+ промпт, всё без единой зависимости.
212
+
213
+ ## Как не сжечь бюджет пользователя
214
+
215
+ Это главное, ради чего Axon вообще существует, и плагин может всё испортить.
216
+
217
+ **Редкий инструмент помечайте `deferred: true`.** Тогда его схема не грузится в
218
+ контекст, пока модель сама не спросит. Пять инструментов с подробными схемами —
219
+ это несколько тысяч токенов в *каждом* запросе.
220
+
221
+ **Длинный вывод кладите в `api.blobs.write`,** а модели отдавайте краткую
222
+ сводку. Всё, что вернул инструмент, остаётся в истории разговора и
223
+ переотправляется каждый ход.
224
+
225
+ **`stability` у вклада в контекст выбирайте честно.** `stable` уходит в
226
+ кэшируемый префикс промпта, `volatile` — в хвост. Изменчивый текст (время,
227
+ курс, погода), положенный в `stable`, обнуляет кэш промпта на каждом ходу.
228
+ Ошибка не видна глазом и стоит десятикратной цены запроса.
229
+
230
+ **Длинные инструкции — это скилл, а не описание инструмента.** У скилла в
231
+ контексте постоянно висит одна строка; тело модель читает сама, когда задача
232
+ под него подходит.
233
+
234
+ ## С чего начать
235
+
236
+ ```bash
237
+ axon plugin new ./мой-плагин
238
+ ```
239
+
240
+ Три файла: манифест, код и описание. Плагин из заготовки сразу работает —
241
+ поднимается, регистрирует инструмент и отвечает на кнопку, — так что первое, что
242
+ вы увидите, это работающая вещь, а не пустой шаблон.
243
+
244
+ ## Настройки без ручного разбора
245
+
246
+ `get` возвращает `unknown`, и на нём легко ошибиться: пустое поле превращается в
247
+ `NaN`, а галочка из формы приходит строкой `"false"`, которая истинна. Для
248
+ частых случаев есть готовое:
249
+
250
+ ```js
251
+ api.settings.text('greeting', 'Привет') // строка, пустая — умолчание
252
+ api.settings.number('limit', 30) // число, негодное — умолчание
253
+ api.settings.flag('notify', false) // «false» из формы это ложь
254
+ api.settings.lines('urls') // многострочное поле как список
255
+ ```
256
+
257
+ ## Как поставить свой плагин
258
+
259
+ **Из приложения:** Плагины → «Установить свой» в правом верхнем углу. Одно поле,
260
+ куда кладут ссылку на репозиторий, и кнопка для архива. Готовые плагины берут
261
+ из соседней вкладки «Каталог», а MCP-серверы подключают во вкладке «MCP».
262
+
263
+ Архив — обычный `.zip`: тот, что отдаёт «Download ZIP» на гитхабе, или
264
+ сделанный из папки проводником. Обёрточную папку внутри искать не надо, ядро
265
+ найдёт `axon.plugin.json` само. `.tar.gz` тоже принимается.
266
+
267
+ **Пока пишете плагин**, удобнее подключить папку по месту — тогда правки видны
268
+ сразу, без пересборки архива:
269
+
270
+ ```bash
271
+ axon plugin link ./мой-плагин # подключить папку как есть
272
+ axon plugin logs мой-плагин # что он печатает
273
+ ```
274
+
275
+ ## Как это работает внутри
276
+
277
+ Каждый плагин запускается **отдельным процессом**. Бесконечный цикл, утечка
278
+ памяти или `process.exit()` внутри плагина убивают только его: ядро видит
279
+ падение, снимает регистрацию его инструментов и продолжает работать.
280
+
281
+ Обратная сторона — всё общение с ядром асинхронное и проходит через
282
+ сериализуемые сообщения. Возвращать из `execute` можно только то, что
283
+ переживёт `JSON.stringify`.
284
+
285
+ Песочницы при этом нет: процесс работает с правами пользователя. `permissions`
286
+ в манифесте — это информированное согласие, а не ограничение. Чужой
287
+ непроверенный код правильнее подключать как MCP-сервер.
@@ -0,0 +1,292 @@
1
+ /**
2
+ * @axon-assistant/plugin-sdk — то, что нужно, чтобы написать плагин Axon.
3
+ *
4
+ * Пакет почти целиком состоит из типов и не тянет ни одной зависимости. Это
5
+ * не аскеза: `api` приезжает аргументом в `activate`, поэтому в рантайме
6
+ * плагину импортировать из SDK нечего. Плагин без единой зависимости — папка,
7
+ * которую можно склонировать и запустить, а не проект, который надо сначала
8
+ * собрать.
9
+ *
10
+ * ```js
11
+ * export async function activate(api) {
12
+ * await api.tools.register({
13
+ * name: 'ping',
14
+ * title: 'Пинг',
15
+ * description: 'Проверить, что плагин жив. Вызывай, если просят проверить связь.',
16
+ * tier: 'safe',
17
+ * parameters: { type: 'object', properties: {} },
18
+ * execute: async () => 'понг',
19
+ * });
20
+ * }
21
+ * ```
22
+ */
23
+ /** Уровень риска. Определяет, спросят ли разрешение и кому инструмент доступен. */
24
+ export type RiskTier = 'safe' | 'sensitive' | 'dangerous';
25
+ export interface Fact {
26
+ id: string;
27
+ key: string;
28
+ value: string;
29
+ origin: 'user' | 'inferred';
30
+ createdAt: string;
31
+ updatedAt: string;
32
+ }
33
+ export interface PluginToolContext {
34
+ conversationId: string;
35
+ runId: string;
36
+ /** Отменяется, когда пользователь останавливает прогон. */
37
+ signal: AbortSignal;
38
+ /**
39
+ * Спросить разрешение посреди выполнения. Возвращает решение; если ответить
40
+ * некому (фоновая задача, клиент без прав) — false.
41
+ */
42
+ requestPermission(reason: string): Promise<boolean>;
43
+ }
44
+ export interface PluginTool {
45
+ /**
46
+ * Короткое имя. Ядро добавит префикс с id плагина: `search` плагина `github`
47
+ * модель увидит как `github_search`. Поэтому два плагина с одинаково
48
+ * названными инструментами не затирают друг друга.
49
+ */
50
+ name: string;
51
+ title: string;
52
+ /** Для модели — «когда вызывать», а не только «что делает». */
53
+ description: string;
54
+ tier: RiskTier;
55
+ /** JSON Schema аргументов. Обычный объект: zod здесь не нужен. */
56
+ parameters: Record<string, unknown>;
57
+ /**
58
+ * Не грузить схему в контекст, пока модель сама не спросит. Для редких
59
+ * инструментов — прямая экономия на каждом запросе.
60
+ */
61
+ deferred?: boolean;
62
+ /** Свой потолок вывода в символах. По умолчанию 2000. */
63
+ previewLimit?: number;
64
+ execute(args: Record<string, unknown>, ctx: PluginToolContext): Promise<string | {
65
+ text: string;
66
+ mime?: string;
67
+ }>;
68
+ }
69
+ export interface PluginModelInfo {
70
+ id: string;
71
+ name?: string;
72
+ contextTokens?: number;
73
+ inputPerMTok?: number;
74
+ outputPerMTok?: number;
75
+ }
76
+ export type PluginChatEvent = {
77
+ type: 'text';
78
+ delta: string;
79
+ } | {
80
+ type: 'thinking';
81
+ delta: string;
82
+ } | {
83
+ type: 'tool_call';
84
+ call: {
85
+ id: string;
86
+ name: string;
87
+ arguments: Record<string, unknown>;
88
+ };
89
+ } | {
90
+ type: 'usage';
91
+ usage: {
92
+ inputTokens: number;
93
+ cachedInputTokens?: number;
94
+ cacheWriteTokens?: number;
95
+ outputTokens: number;
96
+ costUsd?: number;
97
+ provider: string;
98
+ model: string;
99
+ };
100
+ } | {
101
+ type: 'done';
102
+ stopReason: 'end_turn' | 'tool_use' | 'max_tokens' | 'refusal' | 'cancelled';
103
+ };
104
+ export interface PluginProvider {
105
+ id: string;
106
+ label: string;
107
+ supportsPromptCache: boolean;
108
+ models: PluginModelInfo[];
109
+ chat(request: unknown, signal: AbortSignal): AsyncIterable<PluginChatEvent>;
110
+ }
111
+ export interface PluginContributeInput {
112
+ conversationId: string;
113
+ /** Последнее сообщение пользователя — для поиска по релевантности. */
114
+ userText: string;
115
+ }
116
+ /**
117
+ * Куда попадёт вклад в промпт:
118
+ *
119
+ * - `stable` — в системный блок, то есть в кэшируемый префикс;
120
+ * - `volatile` — в самый хвост, после всей истории.
121
+ *
122
+ * Ошибка не видна глазом, но дорога: изменчивый текст (время, курс, погода) в
123
+ * стабильной части обнуляет кэш промпта на каждом ходу.
124
+ */
125
+ export type PluginStability = 'stable' | 'volatile';
126
+ export interface PluginJournalEntry {
127
+ seq: number;
128
+ at: string;
129
+ event: {
130
+ type: string;
131
+ } & Record<string, unknown>;
132
+ }
133
+ export interface PluginApi {
134
+ readonly id: string;
135
+ /** Корень плагина. Только чтение: обновление перезаписывает папку. */
136
+ readonly dir: string;
137
+ /** Личная папка для данных плагина. Переживает обновление. */
138
+ readonly dataDir: string;
139
+ readonly log: {
140
+ debug(message: string, data?: Record<string, unknown>): void;
141
+ info(message: string, data?: Record<string, unknown>): void;
142
+ warn(message: string, data?: Record<string, unknown>): void;
143
+ error(message: string, data?: Record<string, unknown>): void;
144
+ };
145
+ readonly settings: {
146
+ all(): Record<string, unknown>;
147
+ get<T = unknown>(key: string): T | undefined;
148
+ set(values: Record<string, unknown>): Promise<void>;
149
+ onChange(listener: (values: Record<string, unknown>) => void): void;
150
+ /**
151
+ * Прочитать с приведением типа и умолчанием.
152
+ *
153
+ * `get` возвращает `unknown`, и каждый плагин начинался с десятка строк
154
+ * ручного разбора: `Number(api.settings.get('limit') ?? 30)`. Мелочь,
155
+ * которая встречается в каждом плагине по нескольку раз, — а значит и
156
+ * ошибаются в ней регулярно: пустое поле превращается в `NaN`, галочка
157
+ * из формы приходит строкой `"false"` и оказывается истиной.
158
+ *
159
+ * Умолчание обязательно: настройка, которую человек не заполнил, — это
160
+ * норма, а не исключительная ситуация.
161
+ */
162
+ text(key: string, fallback: string): string;
163
+ number(key: string, fallback: number): number;
164
+ flag(key: string, fallback: boolean): boolean;
165
+ /** Многострочное поле как список: пустые строки отброшены, края обрезаны. */
166
+ lines(key: string): string[];
167
+ };
168
+ readonly tools: {
169
+ register(tool: PluginTool): Promise<void>;
170
+ unregister(name: string): Promise<void>;
171
+ };
172
+ readonly context: {
173
+ /** Добавить абзац в промпт. `null` из функции — в этот раз ничего не добавлять. */
174
+ contribute(name: string, stability: PluginStability, contribute: (input: PluginContributeInput) => Promise<string | null> | string | null): Promise<void>;
175
+ remove(name: string): Promise<void>;
176
+ };
177
+ readonly providers: {
178
+ register(provider: PluginProvider): Promise<void>;
179
+ unregister(id: string): Promise<void>;
180
+ };
181
+ readonly skills: {
182
+ /** Добавить скилл на лету. Обычно они просто лежат файлами в папке из манифеста. */
183
+ add(skill: {
184
+ name: string;
185
+ description: string;
186
+ body: string;
187
+ }): Promise<void>;
188
+ };
189
+ readonly jobs: {
190
+ /** Обработчик задачи из манифеста. Расписанием владеет ядро. */
191
+ on(name: string, run: () => Promise<void> | void): void;
192
+ };
193
+ readonly actions: {
194
+ /**
195
+ * Обработчик кнопки со страницы настроек — той, что объявлена в манифесте
196
+ * в `actions`. Возвращённая строка показывается человеку; брошенная
197
+ * ошибка тоже показывается, но как неудача.
198
+ *
199
+ * Это единственный способ дать плагину что-то делать по нажатию, и
200
+ * намеренно узкий: плагин отвечает текстом, а рисует приложение. Пусти
201
+ * его рисовать самому — и код плагина окажется в окне с полным доступом
202
+ * к ядру, ровно там, откуда его убрали отдельным процессом.
203
+ */
204
+ on(name: string, run: () => Promise<string | void> | string | void): void;
205
+ };
206
+ /**
207
+ * Спросить модель, настроенную у человека.
208
+ *
209
+ * До этого плагин умел быть провайдером, но не умел им пользоваться: автору
210
+ * суммаризатора или переводчика приходилось заводить собственный ключ,
211
+ * хотя у ядра он уже есть и настроен. Расход при этом уходил мимо счётчика
212
+ * и мимо потолка, то есть человек платил и не видел за что.
213
+ *
214
+ * Один вопрос без истории и без инструментов. Это не агент — если плагину
215
+ * нужен агент, он для этого и существует сам по себе.
216
+ */
217
+ readonly model: {
218
+ ask(input: {
219
+ prompt: string;
220
+ system?: string;
221
+ maxTokens?: number;
222
+ }): Promise<string>;
223
+ };
224
+ /**
225
+ * Сказать человеку.
226
+ *
227
+ * Плагин, который следит за чем-то, до этого не мог дать о себе знать: он
228
+ * ждал, пока агента спросят. Уведомление показывает тот клиент, который
229
+ * сейчас на связи, — у ядра экрана нет.
230
+ *
231
+ * Мера, а не право: уведомление, приходящее часто, выключают вместе с
232
+ * плагином.
233
+ */
234
+ notify(title: string, body?: string): Promise<void>;
235
+ /**
236
+ * Сказать о себе.
237
+ *
238
+ * Состояние плагина ядро выводит из состояния процесса: жив — значит
239
+ * работает. Плагин, у которого отвалился внешний сервер, при этом живее
240
+ * всех живых и молчит. Пометкой он может сказать, что дела плохи, и человек
241
+ * увидит это в списке, а не будет гадать, почему инструмент не отвечает.
242
+ */
243
+ readonly status: {
244
+ set(note: string, failed?: boolean): Promise<void>;
245
+ clear(): Promise<void>;
246
+ };
247
+ /**
248
+ * Поиск по переписке — тот же, что у агента.
249
+ *
250
+ * Плагин видит факты, но не разговоры. Тому, кто хочет опереться на
251
+ * контекст, взять его было неоткуда.
252
+ */
253
+ readonly history: {
254
+ search(query: string, limit?: number): Promise<Array<{
255
+ messageId: string;
256
+ conversationId: string;
257
+ role: string;
258
+ snippet: string;
259
+ }>>;
260
+ };
261
+ readonly journal: {
262
+ /** Требует права `journal` в манифесте — иначе события просто не придут. */
263
+ on(listener: (entry: PluginJournalEntry) => void): void;
264
+ };
265
+ readonly memory: {
266
+ facts(): Promise<Fact[]>;
267
+ remember(key: string, value: string): Promise<void>;
268
+ };
269
+ readonly blobs: {
270
+ /** Положить большой вывод в хранилище ядра вместо того, чтобы гнать его в модель. */
271
+ write(input: {
272
+ data: Uint8Array | string;
273
+ mime: string;
274
+ name?: string;
275
+ }): Promise<{
276
+ blobId: string;
277
+ bytes: number;
278
+ }>;
279
+ };
280
+ }
281
+ /** Это плагин экспортирует из файла, указанного в `main`. */
282
+ export interface PluginModule {
283
+ activate(api: PluginApi): Promise<void> | void;
284
+ deactivate?(): Promise<void> | void;
285
+ }
286
+ /**
287
+ * Помощники для вывода типов. Ничего не делают в рантайме — существуют только
288
+ * затем, чтобы редактор подсказывал поля, не заставляя писать аннотации.
289
+ */
290
+ export declare function defineTool(tool: PluginTool): PluginTool;
291
+ export declare function definePlugin(module: PluginModule): PluginModule;
292
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @axon-assistant/plugin-sdk — то, что нужно, чтобы написать плагин Axon.
3
+ *
4
+ * Пакет почти целиком состоит из типов и не тянет ни одной зависимости. Это
5
+ * не аскеза: `api` приезжает аргументом в `activate`, поэтому в рантайме
6
+ * плагину импортировать из SDK нечего. Плагин без единой зависимости — папка,
7
+ * которую можно склонировать и запустить, а не проект, который надо сначала
8
+ * собрать.
9
+ *
10
+ * ```js
11
+ * export async function activate(api) {
12
+ * await api.tools.register({
13
+ * name: 'ping',
14
+ * title: 'Пинг',
15
+ * description: 'Проверить, что плагин жив. Вызывай, если просят проверить связь.',
16
+ * tier: 'safe',
17
+ * parameters: { type: 'object', properties: {} },
18
+ * execute: async () => 'понг',
19
+ * });
20
+ * }
21
+ * ```
22
+ */
23
+ /**
24
+ * Помощники для вывода типов. Ничего не делают в рантайме — существуют только
25
+ * затем, чтобы редактор подсказывал поля, не заставляя писать аннотации.
26
+ */
27
+ export function defineTool(tool) {
28
+ return tool;
29
+ }
30
+ export function definePlugin(module) {
31
+ return module;
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA8QH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@axon-assistant/plugin-sdk",
3
+ "version": "2026.8.23",
4
+ "comment:version": "Заглушка. Настоящий номер проставляется из git-тега при публикации: см. scripts/release-npm.mjs. Версия, которую правят руками, рано или поздно расходится с тем, что опубликовано.",
5
+ "description": "Типы для написания плагинов Axon",
6
+ "keywords": [
7
+ "axon",
8
+ "plugin",
9
+ "ai",
10
+ "agent"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/bigtaed-sys/axon.git",
16
+ "directory": "packages/plugin-sdk"
17
+ },
18
+ "homepage": "https://github.com/bigtaed-sys/axon#readme",
19
+ "bugs": "https://github.com/bigtaed-sys/axon/issues",
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md"
32
+ ],
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc --build",
38
+ "typecheck": "tsc --noEmit",
39
+ "prepublishOnly": "npm run build"
40
+ }
41
+ }