@axon-assistant/core 2026.8.27 → 2026.8.29

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 CHANGED
@@ -33,6 +33,7 @@ axon start --host 0.0.0.0 # ещё и для устройств из се
33
33
 
34
34
  ```bash
35
35
  axon code # новый код подключения устройства
36
+ axon doctor # осмотр: что настроено и что сломано
36
37
  axon status # запущено ли и где
37
38
  axon secret set provider.anthropic.apiKey sk-… # ключ провайдера
38
39
  axon devices # подключённые устройства
@@ -1 +1 @@
1
- {"version":3,"file":"Daemon.d.ts","sourceRoot":"","sources":["../src/Daemon.ts"],"names":[],"mappings":"AAMA,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;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAoCD;;;;;;;;;;GAUG;AACH,qBAAa,MAAM;IA8BL,OAAO,CAAC,QAAQ,CAAC,OAAO;IA7BpC,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;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0C;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;IAqDhF;;;;;;;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,WAAW;IAInB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAKzB,0EAA0E;IAC1E,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,QAAQ;IAIV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,GAAG,IAAI,MAAM,CAGhB;IAED,4EAA4E;IAC5E,OAAO,CAAC,WAAW;YAWL,SAAS;IAuHvB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,SAAS;CA+BlB"}
1
+ {"version":3,"file":"Daemon.d.ts","sourceRoot":"","sources":["../src/Daemon.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAMtD,OAAO,EAML,OAAO,EAER,MAAM,gBAAgB,CAAC;AAKxB,eAAO,MAAM,cAAc,QAC4C,CAAC;AAOxE,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;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAoCD;;;;;;;;;;GAUG;AACH,qBAAa,MAAM;IA8BL,OAAO,CAAC,QAAQ,CAAC,OAAO;IA7BpC,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;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0C;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;IAqDhF;;;;;;;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,WAAW;IAInB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAKzB,0EAA0E;IAC1E,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,QAAQ;IAIV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,GAAG,IAAI,MAAM,CAGhB;IAED,4EAA4E;IAC5E,OAAO,CAAC,WAAW;YAWL,SAAS;IAmIvB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,SAAS;CA+BlB"}
package/dist/auth.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare class PairingService {
38
38
  expiresInSeconds: number;
39
39
  };
40
40
  /** Обменять код на токен. Код одноразовый. */
41
- complete(code: string, deviceName?: string): {
41
+ complete(code: string, deviceName?: string, platform?: DevicePlatform): {
42
42
  device: Device;
43
43
  token: string;
44
44
  } | null;
@@ -1 +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"}
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,CACN,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,cAAc,GACxB;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAoB3C,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.js CHANGED
@@ -10197,7 +10197,7 @@ var PairingService = class {
10197
10197
  return { code: code3, expiresInSeconds: input.ttlSeconds };
10198
10198
  }
10199
10199
  /** Обменять код на токен. Код одноразовый. */
10200
- complete(code3, deviceName) {
10200
+ complete(code3, deviceName, platform) {
10201
10201
  this.sweep();
10202
10202
  const pending = this.pending.get(code3);
10203
10203
  if (!pending) return null;
@@ -10205,7 +10205,7 @@ var PairingService = class {
10205
10205
  const token = generateToken();
10206
10206
  const device = this.runtime.store.pairDevice({
10207
10207
  name: deviceName || pending.name,
10208
- platform: pending.platform,
10208
+ platform: platform ?? pending.platform,
10209
10209
  scopes: pending.scopes,
10210
10210
  tokenHash: hashToken(token)
10211
10211
  });
@@ -11726,7 +11726,8 @@ var WsSession = class {
11726
11726
  };
11727
11727
 
11728
11728
  // src/Daemon.ts
11729
- var DAEMON_VERSION = true ? "2026.8.27" : "0.0.0-dev";
11729
+ var DAEMON_VERSION = true ? "2026.8.29" : "0.0.0-dev";
11730
+ var CORS_PATHS = /* @__PURE__ */ new Set(["/health", "/v1/pair"]);
11730
11731
  var MAX_UPLOAD_BYTES = 64 * 1024 * 1024;
11731
11732
  function isWildcard(host) {
11732
11733
  return host === "0.0.0.0" || host === "::" || host === "";
@@ -12015,7 +12016,7 @@ var Daemon = class {
12015
12016
  // ─── HTTP ─────────────────────────────────────────────────────────────────
12016
12017
  async onRequest(req, res) {
12017
12018
  const url = new URL(req.url ?? "/", "http://localhost");
12018
- if (url.pathname.startsWith("/v1/blobs")) {
12019
+ if (url.pathname.startsWith("/v1/blobs") || CORS_PATHS.has(url.pathname)) {
12019
12020
  res.setHeader("Access-Control-Allow-Origin", "*");
12020
12021
  res.setHeader("Access-Control-Allow-Headers", "authorization, content-type");
12021
12022
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -12063,7 +12064,12 @@ var Daemon = class {
12063
12064
  const body = await readJson(req);
12064
12065
  const code3 = typeof body?.["code"] === "string" ? body["code"] : "";
12065
12066
  const name = typeof body?.["name"] === "string" ? body["name"] : void 0;
12066
- const paired = this.pairing.complete(code3.trim().toUpperCase(), name);
12067
+ const platform = zDevicePlatform.safeParse(body?.["platform"]);
12068
+ const paired = this.pairing.complete(
12069
+ code3.trim().toUpperCase(),
12070
+ name,
12071
+ platform.success ? platform.data : void 0
12072
+ );
12067
12073
  if (!paired) return respond(res, 403, { error: "invalid_code" });
12068
12074
  return respond(res, 200, {
12069
12075
  token: paired.token,
@@ -12192,6 +12198,8 @@ async function main() {
12192
12198
  return await status();
12193
12199
  case "code":
12194
12200
  return await code2(args);
12201
+ case "doctor":
12202
+ return await doctor();
12195
12203
  case "stop":
12196
12204
  return stop();
12197
12205
  case "help":
@@ -12294,6 +12302,74 @@ async function code2(args) {
12294
12302
  console.log(` \u043F\u0440\u0430\u0432\u0430: ${chatOnly ? "\u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0430" : "\u043F\u043E\u043B\u043D\u044B\u0435"}`);
12295
12303
  console.log(` \u0430\u0434\u0440\u0435\u0441 \u0434\u043B\u044F \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F: ${(record.reachable ?? [])[0] ?? record.url}`);
12296
12304
  }
12305
+ async function doctor() {
12306
+ const config = resolveConfig();
12307
+ const record = readRecord();
12308
+ const running2 = record !== null && await alive(record.url);
12309
+ console.log(`Axon ${DAEMON_VERSION}`);
12310
+ console.log(` \u0434\u0430\u043D\u043D\u044B\u0435: ${config.dataDir}`);
12311
+ console.log("");
12312
+ const notes = [];
12313
+ const say = (ok2, text, hint) => {
12314
+ console.log(` ${ok2 === null ? "\xB7" : ok2 ? "\u2713" : "\u2717"} ${text}`);
12315
+ if (!ok2 && hint) notes.push(hint);
12316
+ };
12317
+ say(running2, running2 ? `\u044F\u0434\u0440\u043E \u043D\u0430 \u0441\u0432\u044F\u0437\u0438: ${record.url}` : "\u044F\u0434\u0440\u043E \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E", "axon start");
12318
+ if (record && !running2) {
12319
+ say(false, `\u0437\u0430\u043F\u0438\u0441\u044C \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043D\u0430 ${record.url}, \u043D\u043E \u0442\u0430\u043C \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u044E\u0442`, "axon stop && axon start");
12320
+ }
12321
+ if (running2) {
12322
+ console.log("");
12323
+ console.log(" \u041E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u0431\u0430\u0437\u0435 \u2014 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u044F\u0434\u0440\u043E: axon stop");
12324
+ return;
12325
+ }
12326
+ const runtime = createRuntime();
12327
+ try {
12328
+ const secrets = runtime.store.secrets.status();
12329
+ const broken = secrets.filter((secret2) => secret2.unreadable);
12330
+ say(
12331
+ secrets.length === 0 ? null : broken.length === 0,
12332
+ secrets.length === 0 ? "\u0441\u0435\u043A\u0440\u0435\u0442\u043E\u0432 \u043D\u0435\u0442" : broken.length === 0 ? `\u0441\u0435\u043A\u0440\u0435\u0442\u043E\u0432 ${secrets.length}, \u0432\u0441\u0435 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F` : `\u043D\u0435 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F: ${broken.map((secret2) => secret2.key).join(", ")}`,
12333
+ "\u0431\u0430\u0437\u0430 \u043F\u0440\u0438\u0435\u0445\u0430\u043B\u0430 \u0431\u0435\u0437 \u0444\u0430\u0439\u043B\u0430 secret.key \u2014 \u0432\u043F\u0438\u0448\u0438\u0442\u0435 \u043A\u043B\u044E\u0447\u0438 \u0437\u0430\u043D\u043E\u0432\u043E"
12334
+ );
12335
+ const active = String(runtime.store.settings.get("provider.active") ?? "anthropic");
12336
+ const providers = await runtime.providers.describe();
12337
+ const provider = providers.find((item) => item.id === active);
12338
+ say(
12339
+ Boolean(provider?.configured),
12340
+ provider ? `\u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 ${provider.title}: ${provider.configured ? "\u0433\u043E\u0442\u043E\u0432" : "\u043D\u0435\u0442 \u043A\u043B\u044E\u0447\u0430"}` : `\u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 ${active} \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D \u044F\u0434\u0440\u0443`,
12341
+ `axon secret set provider.${active}.apiKey \u2026`
12342
+ );
12343
+ const devices2 = runtime.store.devices.list();
12344
+ say(devices2.length > 0, `\u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432 ${devices2.length}`, "axon code \u2014 \u0432\u044B\u0434\u0430\u0442\u044C \u043A\u043E\u0434 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F");
12345
+ await runtime.startPlugins();
12346
+ const plugins = runtime.plugins.list();
12347
+ const failed = plugins.filter((plugin2) => plugin2.status === "failed");
12348
+ say(
12349
+ failed.length === 0,
12350
+ failed.length === 0 ? `\u043F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 ${plugins.length}, \u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442 \u0432\u0441\u0435` : `\u043D\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442: ${failed.map((plugin2) => plugin2.id).join(", ")}`,
12351
+ failed.length > 0 ? `axon plugin logs ${failed[0].id}` : void 0
12352
+ );
12353
+ const catalog = await runtime.plugins.catalog();
12354
+ say(
12355
+ catalog.origin === "network",
12356
+ `\u043A\u0430\u0442\u0430\u043B\u043E\u0433: ${catalog.entries.length} \u0437\u0430\u043F\u0438\u0441\u0435\u0439, ${CATALOG_ORIGIN[catalog.origin]}`,
12357
+ "\u0441\u0435\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u2014 \u0440\u0430\u0437\u0434\u0435\u043B \xAB\u041A\u0430\u0442\u0430\u043B\u043E\u0433\xBB \u043F\u043E\u043A\u0430\u0436\u0435\u0442 \u0441\u0442\u0430\u0440\u043E\u0435"
12358
+ );
12359
+ } finally {
12360
+ await runtime.close();
12361
+ }
12362
+ if (notes.length > 0) {
12363
+ console.log("");
12364
+ console.log(" \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C:");
12365
+ for (const note of notes) console.log(` ${note}`);
12366
+ }
12367
+ }
12368
+ var CATALOG_ORIGIN = {
12369
+ network: "\u0441\u0432\u0435\u0436\u0438\u0439",
12370
+ cache: "\u0438\u0437 \u043A\u044D\u0448\u0430",
12371
+ bundled: "\u0438\u0437 \u0441\u0431\u043E\u0440\u043A\u0438"
12372
+ };
12297
12373
  function logPath() {
12298
12374
  return path19.join(resolveConfig().dataDir, "axon.log");
12299
12375
  }
@@ -12591,6 +12667,7 @@ function usage() {
12591
12667
  --foreground, -f \u043D\u0435 \u0443\u0445\u043E\u0434\u0438\u0442\u044C \u0432 \u0444\u043E\u043D (systemd, docker)
12592
12668
  axon status \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E \u043B\u0438 \u044F\u0434\u0440\u043E \u0438 \u0433\u0434\u0435
12593
12669
  axon code [--chat] [--ttl 300] \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430
12670
+ axon doctor \u043E\u0441\u043C\u043E\u0442\u0440: \u0447\u0442\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D\u043E \u0438 \u0447\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043D\u043E
12594
12671
  axon stop \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u044F\u0434\u0440\u043E
12595
12672
  axon secret list \u043A\u0430\u043A\u0438\u0435 \u0441\u0435\u043A\u0440\u0435\u0442\u044B \u0437\u0430\u0434\u0430\u043D\u044B
12596
12673
  axon secret get <\u043A\u043B\u044E\u0447> \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0441\u0435\u043A\u0440\u0435\u0442 \u0446\u0435\u043B\u0438\u043A\u043E\u043C
package/dist/index.js CHANGED
@@ -9860,7 +9860,7 @@ var PairingService = class {
9860
9860
  return { code, expiresInSeconds: input.ttlSeconds };
9861
9861
  }
9862
9862
  /** Обменять код на токен. Код одноразовый. */
9863
- complete(code, deviceName) {
9863
+ complete(code, deviceName, platform) {
9864
9864
  this.sweep();
9865
9865
  const pending = this.pending.get(code);
9866
9866
  if (!pending) return null;
@@ -9868,7 +9868,7 @@ var PairingService = class {
9868
9868
  const token = generateToken();
9869
9869
  const device = this.runtime.store.pairDevice({
9870
9870
  name: deviceName || pending.name,
9871
- platform: pending.platform,
9871
+ platform: platform ?? pending.platform,
9872
9872
  scopes: pending.scopes,
9873
9873
  tokenHash: hashToken(token)
9874
9874
  });
@@ -11389,7 +11389,8 @@ var WsSession = class {
11389
11389
  };
11390
11390
 
11391
11391
  // src/Daemon.ts
11392
- var DAEMON_VERSION = true ? "2026.8.27" : "0.0.0-dev";
11392
+ var DAEMON_VERSION = true ? "2026.8.29" : "0.0.0-dev";
11393
+ var CORS_PATHS = /* @__PURE__ */ new Set(["/health", "/v1/pair"]);
11393
11394
  var MAX_UPLOAD_BYTES = 64 * 1024 * 1024;
11394
11395
  function isWildcard(host) {
11395
11396
  return host === "0.0.0.0" || host === "::" || host === "";
@@ -11678,7 +11679,7 @@ var Daemon = class {
11678
11679
  // ─── HTTP ─────────────────────────────────────────────────────────────────
11679
11680
  async onRequest(req, res) {
11680
11681
  const url = new URL(req.url ?? "/", "http://localhost");
11681
- if (url.pathname.startsWith("/v1/blobs")) {
11682
+ if (url.pathname.startsWith("/v1/blobs") || CORS_PATHS.has(url.pathname)) {
11682
11683
  res.setHeader("Access-Control-Allow-Origin", "*");
11683
11684
  res.setHeader("Access-Control-Allow-Headers", "authorization, content-type");
11684
11685
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -11726,7 +11727,12 @@ var Daemon = class {
11726
11727
  const body = await readJson(req);
11727
11728
  const code = typeof body?.["code"] === "string" ? body["code"] : "";
11728
11729
  const name = typeof body?.["name"] === "string" ? body["name"] : void 0;
11729
- const paired = this.pairing.complete(code.trim().toUpperCase(), name);
11730
+ const platform = zDevicePlatform.safeParse(body?.["platform"]);
11731
+ const paired = this.pairing.complete(
11732
+ code.trim().toUpperCase(),
11733
+ name,
11734
+ platform.success ? platform.data : void 0
11735
+ );
11730
11736
  if (!paired) return respond(res, 403, { error: "invalid_code" });
11731
11737
  return respond(res, 200, {
11732
11738
  token: paired.token,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axon-assistant/core",
3
- "version": "2026.8.27",
3
+ "version": "2026.8.29",
4
4
  "comment:version": "Заглушка. Настоящий номер проставляется из git-тега при публикации: см. scripts/release-npm.mjs. Версия, которую правят руками, рано или поздно расходится с тем, что опубликовано.",
5
5
  "description": "Ядро Axon: персональный AI-агент, который живёт на вашей машине",
6
6
  "keywords": [