feat: remove check version update feature

This commit is contained in:
2026-07-13 16:32:20 +07:00
parent 275f20e2b8
commit b4ffea7deb
19 changed files with 26 additions and 995 deletions
-1
View File
@@ -82,7 +82,6 @@ That's it! Start coding with FREE AI models.
9router # Start with default settings
9router --port 8080 # Custom port
9router --no-browser # Don't open browser
9router --skip-update # Skip auto-update check
9router --help # Show all options
```
+9 -142
View File
@@ -3,7 +3,6 @@
const { spawn, exec, execSync } = require("child_process");
const path = require("path");
const fs = require("fs");
const https = require("https");
const net = require("net");
const os = require("os");
@@ -26,42 +25,6 @@ function waitServerReady(port, { timeoutMs = 15000, intervalMs = 150 } = {}) {
});
}
// Native spinner - no external dependency
function createSpinner(text) {
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
let i = 0;
let interval = null;
let currentText = text;
return {
start() {
if (process.stdout.isTTY) {
process.stdout.write(`\r${frames[0]} ${currentText}`);
interval = setInterval(() => {
process.stdout.write(`\r${frames[i++ % frames.length]} ${currentText}`);
}, 80);
}
return this;
},
stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
if (process.stdout.isTTY) {
process.stdout.write("\r\x1b[K");
}
},
succeed(msg) {
this.stop();
console.log(`${msg}`);
},
fail(msg) {
this.stop();
console.log(`${msg}`);
}
};
}
const pkg = require("./package.json");
const { ensureSqliteRuntime, buildEnvWithRuntime } = require("./hooks/sqliteRuntime");
const { ensureTrayRuntime } = require("./hooks/trayRuntime");
@@ -77,7 +40,6 @@ try { ensureTrayRuntime({ silent: true }); } catch {}
// Configuration constants
const APP_NAME = pkg.name; // Use from package.json
const INSTALL_CMD_LATEST = `npm i -g ${APP_NAME}@latest --prefer-online`;
const DEFAULT_PORT = 20128;
const DEFAULT_HOST = "0.0.0.0";
@@ -106,7 +68,6 @@ const PROCESS_IDENTIFIERS = [
let port = DEFAULT_PORT;
let host = DEFAULT_HOST;
let noBrowser = false;
let skipUpdate = false;
let showLog = false;
let trayMode = false;
@@ -121,8 +82,6 @@ for (let i = 0; i < args.length; i++) {
noBrowser = true;
} else if (args[i] === "--log" || args[i] === "-l") {
showLog = true;
} else if (args[i] === "--skip-update") {
skipUpdate = true;
} else if (args[i] === "--tray" || args[i] === "-t") {
trayMode = true;
process.env.TRAY_MODE = "1";
@@ -136,7 +95,6 @@ Options:
-n, --no-browser Don't open browser automatically
-l, --log Show server logs (default: hidden)
-t, --tray Run in system tray mode (background)
--skip-update Skip auto-update check
-h, --help Show this help message
-v, --version Show version
`);
@@ -147,26 +105,9 @@ Options:
}
}
// Auto-relaunch after update: detached process has no TTY → fallback to tray
if (skipUpdate && !trayMode && !process.stdin.isTTY) {
trayMode = true;
process.env.TRAY_MODE = "1";
}
// Always use Node.js runtime with absolute path
const RUNTIME = process.execPath;
// Compare semver versions: returns 1 if a > b, -1 if a < b, 0 if equal
function compareVersions(a, b) {
const partsA = a.split(".").map(Number);
const partsB = b.split(".").map(Number);
for (let i = 0; i < 3; i++) {
if (partsA[i] > partsB[i]) return 1;
if (partsA[i] < partsB[i]) return -1;
}
return 0;
}
// Get app data dir (matches app/src/lib/dataDir.js convention)
function getAppDataDir() {
return process.platform === "win32"
@@ -437,55 +378,6 @@ function isRestrictedEnvironment() {
return null;
}
// Check if new version available, return latest version or null
function checkForUpdate() {
return new Promise((resolve) => {
if (skipUpdate) {
resolve(null);
return;
}
const spinner = createSpinner("Checking for updates...").start();
let resolved = false;
const safetyTimeout = setTimeout(() => {
if (!resolved) {
resolved = true;
spinner.stop();
resolve(null);
}
}, 8000);
const done = (version) => {
if (resolved) return;
resolved = true;
clearTimeout(safetyTimeout);
spinner.stop();
resolve(version);
};
const req = https.get(`https://registry.npmjs.org/${pkg.name}/latest`, { timeout: 3000 }, (res) => {
let data = "";
res.on("data", chunk => data += chunk);
res.on("end", () => {
try {
const latest = JSON.parse(data);
if (latest.version && compareVersions(latest.version, pkg.version) > 0) {
done(latest.version);
} else {
done(null);
}
} catch (e) {
done(null);
}
});
});
req.on("error", () => done(null));
req.on("timeout", () => { req.destroy(); done(null); });
});
}
// Open browser
function openBrowser(url) {
const platform = process.platform;
@@ -520,14 +412,12 @@ if (!fs.existsSync(serverPath)) {
process.exit(1);
}
// Start server immediately; run update check in parallel (not on the critical path).
const updatePromise = checkForUpdate();
killAllAppProcesses(port)
.then(() => killProcessOnPort(port))
.then(() => startServer(updatePromise));
.then(() => startServer());
// Show interface selection menu
async function showInterfaceMenu(latestVersion) {
async function showInterfaceMenu() {
const { selectMenu } = require("./src/cli/utils/input");
const { clearScreen } = require("./src/cli/utils/display");
const { getEndpoint } = require("./src/cli/utils/endpoint");
@@ -549,10 +439,6 @@ async function showInterfaceMenu(latestVersion) {
const menuItems = [];
if (latestVersion) {
menuItems.push({ label: `Update to v${latestVersion} (current: v${pkg.version})`, icon: "⬆" });
}
menuItems.push(
{ label: "Web UI (Open in Browser)", icon: "🌐" },
{ label: "Terminal UI (Interactive CLI)", icon: "💻" },
@@ -562,21 +448,16 @@ async function showInterfaceMenu(latestVersion) {
const selected = await selectMenu(`Choose Interface (v${pkg.version})`, menuItems, 0, subtitle);
const offset = latestVersion ? 1 : 0;
if (latestVersion && selected === 0) return "update";
if (selected === offset) return "web";
if (selected === offset + 1) return "terminal";
if (selected === offset + 2) return "hide";
if (selected === 0) return "web";
if (selected === 1) return "terminal";
if (selected === 2) return "hide";
return "exit";
}
const MAX_RESTARTS = 2;
const RESTART_RESET_MS = 30000; // Reset counter if alive > 30s
function startServer(updatePromise) {
// Accept either a Promise (parallel update check) or a resolved value.
const latestVersionPromise = Promise.resolve(updatePromise);
function startServer() {
const displayHost = getDisplayHost();
const url = `http://${displayHost}:${port}/dashboard`;
// Surface real network exposure when bound to all interfaces (default 0.0.0.0).
@@ -708,28 +589,14 @@ function startServer(updatePromise) {
// Wait for server to be ready, then show interface menu loop + tray
waitServerReady(port).then(async () => {
// Resolve parallel update check (already running); don't block server start on it.
const latestVersion = await latestVersionPromise;
// Start tray icon alongside TUI
initTrayIcon();
try {
while (true) {
const choice = await showInterfaceMenu(latestVersion);
const choice = await showInterfaceMenu();
if (choice === "update") {
isShuttingDown = true;
const { clearScreen } = require("./src/cli/utils/display");
clearScreen();
console.log(`\n⬆ Update v${pkg.version} → v${latestVersion}\n`);
console.log(`Run this after exit:\n`);
console.log(` \x1b[33m${INSTALL_CMD_LATEST}\x1b[0m\n`);
cleanup();
await killAllAppProcesses(port);
await killProcessOnPort(port);
setTimeout(() => process.exit(0), 200);
return;
} else if (choice === "web") {
if (choice === "web") {
openBrowser(url);
// Wait for user to come back
const { pause } = require("./src/cli/utils/input");
@@ -767,7 +634,7 @@ function startServer(updatePromise) {
// Windows/Linux: spawn detached bgProcess (systray works fine in child)
console.log(`\n⏳ Starting background process... (tray icon will appear in ~3s)`);
const bgProcess = spawn(process.execPath, [__filename, "--tray", "--skip-update", "-p", port.toString()], {
const bgProcess = spawn(process.execPath, [__filename, "--tray", "-p", port.toString()], {
detached: true,
stdio: "ignore",
windowsHide: true,
-11
View File
@@ -248,17 +248,6 @@ if (fs.existsSync(mitmSrc)) {
console.log("⏭️ No MITM files found\n");
}
// Step 7b: Copy standalone updater (headless Node process for install progress)
console.log("7️⃣ b Copying updater files...");
const updaterSrc = path.join(appDir, "src", "lib", "updater");
const updaterDest = path.join(cliAppDir, "src", "lib", "updater");
if (fs.existsSync(updaterSrc)) {
copyRecursive(updaterSrc, updaterDest);
console.log("✅ Copied updater files\n");
} else {
console.log("⏭️ No updater files found\n");
}
// Step 8: Build MITM server (config driven - see app/cli/scripts/buildMitm.js)
console.log("8️⃣ Building MITM server...");
try {
+1 -3
View File
@@ -14,9 +14,7 @@ const cliDir = path.resolve(__dirname, "..");
const appDir = path.resolve(cliDir, "..");
const cliAppDir = process.env.NINEROUTER_CLI_APP_DIR || path.join(cliDir, "app");
const cliMitmDir = path.join(cliAppDir, "src", "mitm");
// Bundle everything — no externals. This keeps MITM runtime self-contained so
// it can be copied to DATA_DIR/runtime/ and spawned from there (escapes
// node_modules file locks that block `npm i -g 9router@latest` on Windows).
// Bundle everything — no externals. This keeps the MITM runtime self-contained.
const EXTERNALS = [];
const ENTRIES = ["server.js"];
+2 -3
View File
@@ -170,7 +170,6 @@ function enableMacOS(cliPath) {
<string>${nodePath}</string>
<string>${routerScript}</string>
<string>--tray</string>
<string>--skip-update</string>
</array>
<key>EnvironmentVariables</key>
<dict>
@@ -249,7 +248,7 @@ function enableWindows(cliPath) {
// Run node + cli.js directly, hidden window. Avoids the fragile
// `9router.cmd` lookup that depended on the npm prefix path.
const vbsContent = `Set WshShell = CreateObject("WScript.Shell")
WshShell.Run """${nodePath}"" ""${routerScript}"" --tray --skip-update", 0, False
WshShell.Run """${nodePath}"" ""${routerScript}"" --tray", 0, False
`;
fs.writeFileSync(vbsPath, vbsContent);
return true;
@@ -282,7 +281,7 @@ function enableLinux(cliPath) {
Type=Application
Name=9Router
Comment=9Router API Proxy
Exec=${nodePath} ${routerScript} --tray --skip-update
Exec=${nodePath} ${routerScript} --tray
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true