# v0.4.52 (2026-05-17)

## Features
- Add Vercel AI Gateway provider support (#1183)
- rtk: Kiro format tool result compression — handle conversationState.history & currentMessage, preserve error results, ~13.6% savings (#1194)

## Fixes
- openclaw: normalize agent.model object form `{primary, fallbacks}` before .startsWith → fix TypeError & 'not configured' status (#1216)
- Usage Details pagination: stay inside mobile viewport <640px (#1218)
- Fix test model error
- Fix MIMO provider in Codex
- Disable log file creation when using MITM AG
This commit is contained in:
decolua
2026-05-17 16:37:26 +07:00
parent 9326589452
commit 9abbb8ad9b
12 changed files with 188 additions and 79 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "9router",
"version": "0.4.50",
"version": "0.4.52",
"description": "9Router CLI - Start and manage 9Router server",
"bin": {
"9router": "./cli.js"
+25 -6
View File
@@ -1,6 +1,9 @@
const http = require("http");
const https = require("https");
const crypto = require("crypto");
const fs = require("node:fs");
const path = require("node:path");
const os = require("node:os");
const { machineIdSync } = require("node-machine-id");
// Default configuration
@@ -12,18 +15,34 @@ const DEFAULT_CONFIG = {
const CLI_TOKEN_HEADER = "x-9r-cli-token";
const CLI_TOKEN_SALT = "9r-cli-auth";
const APP_NAME = "9router";
function getDataDir() {
if (process.env.DATA_DIR) return process.env.DATA_DIR;
if (process.platform === "win32") {
return path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), APP_NAME);
}
return path.join(os.homedir(), `.${APP_NAME}`);
}
const MACHINE_ID_FILE = path.join(getDataDir(), "machine-id");
let config = { ...DEFAULT_CONFIG };
let cachedCliToken = null;
// Read raw machineId from shared file (written by server) → guarantees token match
function loadRawMachineId() {
try {
const raw = fs.readFileSync(MACHINE_ID_FILE, "utf8").trim();
if (raw) return raw;
} catch {}
try { return machineIdSync(); } catch { return ""; }
}
function getCliToken() {
if (cachedCliToken !== null) return cachedCliToken;
try {
const mid = machineIdSync();
cachedCliToken = crypto.createHash("sha256").update(mid + CLI_TOKEN_SALT).digest("hex").substring(0, 16);
} catch {
cachedCliToken = "";
}
const raw = loadRawMachineId();
cachedCliToken = raw ? crypto.createHash("sha256").update(raw + CLI_TOKEN_SALT).digest("hex").substring(0, 16) : "";
return cachedCliToken;
}