@axon-assistant/core 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,52 @@
1
+ # @axon-assistant/core
2
+
3
+ Ядро [Axon](https://github.com/bigtaed-sys/axon) — персонального AI-агента,
4
+ который живёт на вашей машине, а не в чужом облаке.
5
+
6
+ Ядро владеет всем: историей, памятью, инструментами, контекстом, вызовами
7
+ моделей. Приложения (десктоп, Telegram) подключаются к нему и синхронизируются
8
+ через журнал событий. Сколько бы устройств ни было подключено, контекст один,
9
+ кэш промпта один, и расход токенов не умножается на число экранов.
10
+
11
+ ## Установка
12
+
13
+ Node 22.5+. Нативных модулей нет, компилятор не нужен.
14
+
15
+ ```bash
16
+ npm install -g @axon-assistant/core
17
+ axon start # слушает 127.0.0.1:8787
18
+ axon start --host 0.0.0.0 # ещё и для устройств из сети
19
+ ```
20
+
21
+ При первом запуске ядро печатает код для подключения первого устройства и
22
+ кладёт его в `bootstrap.code` рядом с данными — код сгорает после первого
23
+ использования.
24
+
25
+ ```bash
26
+ axon status # запущено ли и где
27
+ axon secret set provider.anthropic.apiKey sk-… # ключ провайдера
28
+ axon devices # подключённые устройства
29
+ axon plugin catalog # что можно поставить
30
+ axon backup create # архив с базой и блобами
31
+ axon stop
32
+ ```
33
+
34
+ Папка данных задаётся переменной `AXON_DATA_DIR`; по умолчанию — стандартная
35
+ папка приложений вашей ОС. Внутри лежит всё: база, блобы и ключ шифрования
36
+ секретов. Переносится копированием.
37
+
38
+ ## Что уходит наружу
39
+
40
+ К провайдеру модели — то, что вы видите в разборе контекста. Есть ровно одно
41
+ исключение, и оно по вашему действию: открытая вкладка «Каталог» в плагинах
42
+ тянет список из публичного репозитория, без каких-либо сведений о вас. Само по
43
+ себе ядро в сеть не ходит: обновлений, телеметрии и «анонимной статистики» нет.
44
+
45
+ ## Плагины
46
+
47
+ Свои инструменты, скиллы, работа по расписанию и провайдеры моделей пишутся на
48
+ [@axon-assistant/plugin-sdk](https://www.npmjs.com/package/@axon-assistant/plugin-sdk).
49
+ Заготовка — `axon plugin new мой-плагин`. Чужие MCP-серверы подключаются
50
+ конфигурацией из их README, без обёрток.
51
+
52
+ MIT.
@@ -0,0 +1,119 @@
1
+ import type { CoreConfig, Runtime } from '@axon/core';
2
+ import { Userbot } from '@axon/telegram';
3
+ export declare const DAEMON_VERSION: string;
4
+ export interface DaemonOptions {
5
+ config?: Partial<CoreConfig>;
6
+ host?: string;
7
+ port?: number;
8
+ /** `embedded` — ядро внутри десктопа, `standalone` — отдельный сервис. */
9
+ mode?: 'embedded' | 'standalone';
10
+ }
11
+ export interface DaemonAddress {
12
+ host: string;
13
+ port: number;
14
+ url: string;
15
+ }
16
+ /**
17
+ * Демон: тонкая обвязка вокруг ядра.
18
+ *
19
+ * Живой канал — один WebSocket, по нему идёт всё, кроме блобов: файлы
20
+ * качаются обычным HTTP, чтобы не забивать канал и не терять докачку с
21
+ * кэшированием на стороне клиента.
22
+ *
23
+ * TLS здесь намеренно нет. Локально он не нужен, а для доступа снаружи
24
+ * правильный слой — туннель или обратный прокси: самоподписанный сертификат
25
+ * внутри демона дал бы иллюзию защиты и кучу проблем с доверием.
26
+ */
27
+ export declare class Daemon {
28
+ private readonly options;
29
+ readonly runtime: Runtime;
30
+ private readonly sessions;
31
+ private readonly pairing;
32
+ private readonly permissions;
33
+ private readonly server;
34
+ private readonly wss;
35
+ private address;
36
+ private telegram;
37
+ /** Агент под аккаунтом владельца. Поднимается, когда в секретах есть сессия. */
38
+ readonly userbot: Userbot;
39
+ /** Незавершённый вход: живёт между шагами «телефон → код → пароль». */
40
+ private auth;
41
+ /**
42
+ * Кто ещё слушает эфемерику, кроме сокетов.
43
+ *
44
+ * Сигналы — куски ответа, фазы, расход — не журналируются и до сих пор
45
+ * уходили только в WS-сессии. Телеграм живёт в этом же процессе и обычно без
46
+ * единого открытого сокета: без такой подписки он не увидел бы, как растёт
47
+ * ответ, и мог бы показать его только целиком в самом конце.
48
+ */
49
+ private readonly signalListeners;
50
+ /** Разрешается, когда все установленные плагины отработали запуск. */
51
+ pluginsReady: Promise<void>;
52
+ constructor(options?: DaemonOptions);
53
+ start(): Promise<{
54
+ address: DaemonAddress;
55
+ bootstrapCode: string | null;
56
+ }>;
57
+ /**
58
+ * Поднять или погасить телеграм по наличию токена.
59
+ *
60
+ * Токен есть — бот работает, токена нет — не работает. Отдельного
61
+ * переключателя «включить телеграм» нет намеренно: он был бы вторым
62
+ * источником правды, и рано или поздно человек оказался бы с введённым
63
+ * токеном и выключенным ботом, не понимая почему.
64
+ */
65
+ private syncTelegram;
66
+ /**
67
+ * Поднять или погасить юзербота по наличию сессии.
68
+ *
69
+ * Отдельно от бота: это разные вещи, и одна работает без другой. Бот —
70
+ * канал к агенту, юзербот — команда `.axon` в чужих чатах от твоего имени.
71
+ */
72
+ private syncUserbot;
73
+ /**
74
+ * Шаг входа в аккаунт.
75
+ *
76
+ * Состояние живёт между вызовами в `this.auth`: телеграм присылает код между
77
+ * первым шагом и вторым, и всё это время соединение должно оставаться тем же.
78
+ */
79
+ telegramLogin(step: 'phone' | 'code' | 'password' | 'cancel', value: string): Promise<{
80
+ state: "cancelled";
81
+ hint?: never;
82
+ name?: never;
83
+ } | {
84
+ state: "code_sent";
85
+ hint: string;
86
+ name?: never;
87
+ } | {
88
+ state: "password_needed";
89
+ hint?: never;
90
+ name?: never;
91
+ } | {
92
+ state: "done";
93
+ name: string;
94
+ hint?: never;
95
+ }>;
96
+ telegramLogout(): Promise<void>;
97
+ telegramStatus(): {
98
+ bot: boolean;
99
+ user: boolean;
100
+ };
101
+ /**
102
+ * Заявка о себе рядом с данными.
103
+ *
104
+ * Ядро — самостоятельная программа, и запустить его может кто угодно:
105
+ * автозагрузка, systemd, рука в терминале, приложение. Чтобы клиент на этой
106
+ * же машине мог его найти, не завися от того, кто его поднял, адрес и pid
107
+ * кладутся в файл рядом с базой.
108
+ */
109
+ private announce;
110
+ private withdraw;
111
+ stop(): Promise<void>;
112
+ get url(): string;
113
+ /** Есть ли на связи устройство, способное ответить на запрос разрешения. */
114
+ private hasAudience;
115
+ private onRequest;
116
+ private sendBlob;
117
+ private onUpgrade;
118
+ }
119
+ //# sourceMappingURL=Daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Daemon.d.ts","sourceRoot":"","sources":["../src/Daemon.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAKtD,OAAO,EAML,OAAO,EAER,MAAM,gBAAgB,CAAC;AAKxB,eAAO,MAAM,cAAc,QAC4C,CAAC;AAIxE,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;GAUG;AACH,qBAAa,MAAM;IAyBL,OAAO,CAAC,QAAQ,CAAC,OAAO;IAxBpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,QAAQ,CAAgC;IAChD,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uEAAuE;IACvE,OAAO,CAAC,IAAI,CAA4B;IACxC;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAuC;IACvE,sEAAsE;IACtE,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAqB;gBAEnB,OAAO,GAAE,aAAkB;IAsClD,KAAK,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,aAAa,CAAC;QAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IA+ChF;;;;;;;OAOG;YACW,YAAY;IAmC1B;;;;;OAKG;YACW,WAAW;IAkBzB;;;;;OAKG;IACG,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,EAAE,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;;IAoC3E,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrC,cAAc;;;;IAOd;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,QAAQ;IAIV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,GAAG,IAAI,MAAM,CAGhB;IAED,4EAA4E;IAC5E,OAAO,CAAC,WAAW;YAWL,SAAS;IAsDvB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,SAAS;CA+BlB"}
@@ -0,0 +1,23 @@
1
+ import type { PermissionDecision, PermissionRequest } from '@axon/protocol';
2
+ import type { PermissionBroker } from '@axon/core';
3
+ /**
4
+ * Ожидание ответа на запрос разрешения.
5
+ *
6
+ * Тонкость, из-за которой это отдельный класс: если ответить некому, ждать
7
+ * пять минут бессмысленно и вредно — прогон висит, пользователь смотрит на
8
+ * «выполняется». Поэтому сначала проверяем, есть ли вообще кто-то на связи с
9
+ * правом отвечать, и только потом ждём.
10
+ */
11
+ export declare class PermissionHub implements PermissionBroker {
12
+ private readonly hasAudience;
13
+ private readonly pending;
14
+ constructor(hasAudience: () => boolean);
15
+ request(request: PermissionRequest): Promise<PermissionDecision>;
16
+ /** Ответ пришёл командой от устройства. */
17
+ resolve(requestId: string, decision: PermissionDecision): boolean;
18
+ /** Есть ли незакрытые запросы — демон показывает это в /health. */
19
+ get pendingCount(): number;
20
+ /** Снять все ожидания при остановке демона. */
21
+ shutdown(): void;
22
+ }
23
+ //# sourceMappingURL=PermissionHub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionHub.d.ts","sourceRoot":"","sources":["../src/PermissionHub.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD;;;;;;;GAOG;AACH,qBAAa,aAAc,YAAW,gBAAgB;IAMxC,OAAO,CAAC,QAAQ,CAAC,WAAW;IALxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGpB;gBAEyB,WAAW,EAAE,MAAM,OAAO;IAEjD,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmBtE,2CAA2C;IAC3C,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO;IAUjE,mEAAmE;IACnE,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,+CAA+C;IAC/C,QAAQ,IAAI,IAAI;CAOjB"}
@@ -0,0 +1,32 @@
1
+ import type { WebSocket } from 'ws';
2
+ import { type Device, type Signal } from '@axon/protocol';
3
+ import { type Runtime } from '@axon/core';
4
+ import type { PairingService } from './auth.js';
5
+ import { type TelegramControl } from './commands.js';
6
+ import type { PermissionHub } from './PermissionHub.js';
7
+ export interface SessionDeps {
8
+ runtime: Runtime;
9
+ pairing: PairingService;
10
+ permissions: PermissionHub;
11
+ telegram: TelegramControl;
12
+ version: string;
13
+ mode: 'embedded' | 'standalone';
14
+ }
15
+ export declare class WsSession {
16
+ private readonly socket;
17
+ private readonly device;
18
+ private readonly deps;
19
+ private readonly unsubscribe;
20
+ private droppedSignals;
21
+ constructor(socket: WebSocket, device: Device, deps: SessionDeps);
22
+ get deviceId(): string;
23
+ canReceiveSignals(): boolean;
24
+ /** Эфемерика: доставляется по возможности. */
25
+ emitSignal(signal: Signal): void;
26
+ close(): void;
27
+ private onJournal;
28
+ private onMessage;
29
+ private handleRequest;
30
+ private send;
31
+ }
32
+ //# sourceMappingURL=WsSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WsSession.d.ts","sourceRoot":"","sources":["../src/WsSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAIL,KAAK,MAAM,EAGX,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAYxD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,aAAa,CAAC;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,YAAY,CAAC;CACjC;AAED,qBAAa,SAAS;IAKlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,cAAc,CAAK;gBAGR,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW;IAuBpC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,iBAAiB,IAAI,OAAO;IAI5B,8CAA8C;IAC9C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAShC,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,SAAS;YAKH,SAAS;YAwCT,aAAa;IA4B3B,OAAO,CAAC,IAAI;CAIb"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ import type { Device, DevicePlatform, Scope } from '@axon/protocol';
2
+ import type { Runtime } from '@axon/core';
3
+ /**
4
+ * Токен устройства выдаётся один раз и больше не показывается. В базе лежит
5
+ * только его sha256 — утёкший файл БД не даёт войти в ядро.
6
+ */
7
+ export declare function hashToken(token: string): string;
8
+ export declare function generateToken(): string;
9
+ export interface PendingPairing {
10
+ name: string;
11
+ platform: DevicePlatform;
12
+ scopes: Scope[];
13
+ expiresAt: number;
14
+ }
15
+ /**
16
+ * Пейринг устройств.
17
+ *
18
+ * Обычный путь: уже доверенное устройство просит код, новое устройство меняет
19
+ * код на токен. Проблема курицы и яйца — первое устройство — решается так же,
20
+ * как в Jupyter: при первом запуске ядро пишет одноразовый код в файл рядом с
21
+ * данными. У кого есть доступ к машине, тот и заводит первое устройство; по
22
+ * сети код не улетает.
23
+ */
24
+ export declare class PairingService {
25
+ private readonly runtime;
26
+ private readonly bootstrapPath;
27
+ private readonly pending;
28
+ constructor(runtime: Runtime, bootstrapPath: string);
29
+ /** Код первого устройства. Пишется только если устройств ещё нет. */
30
+ ensureBootstrapCode(): string | null;
31
+ begin(input: {
32
+ name: string;
33
+ platform: DevicePlatform;
34
+ scopes: Scope[];
35
+ ttlSeconds: number;
36
+ }): {
37
+ code: string;
38
+ expiresInSeconds: number;
39
+ };
40
+ /** Обменять код на токен. Код одноразовый. */
41
+ complete(code: string, deviceName?: string): {
42
+ device: Device;
43
+ token: string;
44
+ } | null;
45
+ private sweep;
46
+ }
47
+ /** Найти устройство по предъявленному токену. */
48
+ export declare function authenticate(runtime: Runtime, token: string | null): Device | null;
49
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;gBAG1C,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,MAAM;IAGxC,qEAAqE;IACrE,mBAAmB,IAAI,MAAM,GAAG,IAAI;IA8BpC,KAAK,CAAC,KAAK,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,cAAc,CAAC;QACzB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;IAW9C,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAoBrF,OAAO,CAAC,KAAK;CAMd;AAcD,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGlF"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}