mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
omniroute update always failed on a global install:
- getCurrentVersion() read package.json from process.cwd(), which on a global
npm/brew install is the user's working dir, not the package root → null →
'Could not determine current version'.
- createBackup() resolved bin/ from cwd too, and passed the 'cli' directory to
copyFileSync → EISDIR, swallowed by the catch → 'Failed to create backup'.
Both now resolve package.json/bin relative to the script via import.meta.url,
and the backup uses cpSync({recursive:true}) so the cli/ directory is copied.
Co-authored-by: uniQta <uniQta@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0fcfb159f2
commit
7a3eeaca48
@@ -20,6 +20,7 @@ _Development cycle in progress — entries are added as work merges into `releas
|
||||
### 🔧 Bug Fixes
|
||||
|
||||
- **fix(dashboard):** keep no-auth providers (opencode, duckduckgo-web, theoldllm, veoaifree-web) visible under the "Show configured only" filter — they never create a connection row (`stats.total === 0`) but are always usable and already appear in `/v1/models`, so the filter now treats `displayAuthType === "no-auth"` as configured. (#3290 — thanks @uniQta)
|
||||
- **fix(cli):** `omniroute update` no longer always fails on a global install — `getCurrentVersion()` and `createBackup()` now resolve `package.json`/`bin` relative to the script (`import.meta.url`) instead of `process.cwd()` (the user's working dir on a global npm/brew install → *"Could not determine current version"*), and the backup copies the `cli` directory with `cpSync({recursive:true})` instead of `copyFileSync`, which threw a swallowed `EISDIR` → *"Failed to create backup. Aborting"*. (#3295 — thanks @uniQta)
|
||||
- **fix(sse):** harden the passthrough stream against empty upstream responses — emit a synthetic retry chunk on an empty `choices: []` (fixes a Copilot Chat crash) and log empty post-`tool_calls` completions; also registers **MiniMax M3** (1M context) across 8 provider tiers. ([#3297](https://github.com/diegosouzapw/OmniRoute/pull/3297), #3110 — thanks @wilsonicdev)
|
||||
- **fix(opencode-provider):** extract `contextLength` from the live `/v1/models` catalog (live > `modelContextLengths` > static map) so passthrough models outside the legacy 8-model map no longer silently truncate to OpenCode's 128K default. ([#3298](https://github.com/diegosouzapw/OmniRoute/pull/3298) — thanks @herjarsa / @diegosouzapw)
|
||||
- **fix(dev):** auto-rebuild `better-sqlite3` on a Node ABI mismatch at `npm run dev` startup (nvm 22↔24) — dev-only, no-op on the healthy path, unrelated errors not swallowed. ([#3301](https://github.com/diegosouzapw/OmniRoute/pull/3301) — thanks @zhiru)
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import { printHeading, printInfo, printSuccess, printError } from "../io.mjs";
|
||||
import { homedir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import { t } from "../i18n.mjs";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
async function getCurrentVersion() {
|
||||
// This file lives at <pkgRoot>/bin/cli/commands/update.mjs — resolve package
|
||||
// paths relative to the script, NOT process.cwd(). On a global npm/brew install
|
||||
// the user's cwd is not the package root, so cwd-relative lookups break (#3295).
|
||||
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
||||
const PKG_ROOT = path.resolve(SCRIPT_DIR, "..", "..", "..");
|
||||
const BIN_DIR = path.join(PKG_ROOT, "bin");
|
||||
|
||||
export async function getCurrentVersion() {
|
||||
try {
|
||||
const { readFileSync } = await import("node:fs");
|
||||
const pkg = JSON.parse(readFileSync(path.join(process.cwd(), "package.json"), "utf-8"));
|
||||
const pkg = JSON.parse(readFileSync(path.join(PKG_ROOT, "package.json"), "utf-8"));
|
||||
return pkg.version;
|
||||
} catch {
|
||||
return null;
|
||||
@@ -38,12 +46,12 @@ function compareVersions(a, b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function createBackup() {
|
||||
const binPath = path.join(process.cwd(), "bin");
|
||||
export async function createBackup() {
|
||||
const binPath = BIN_DIR;
|
||||
const backupDir = path.join(homedir(), ".omniroute", "backups", `omniroute-${Date.now()}`);
|
||||
|
||||
try {
|
||||
const { mkdirSync, copyFileSync, existsSync } = await import("node:fs");
|
||||
const { mkdirSync, cpSync, existsSync } = await import("node:fs");
|
||||
if (!existsSync(binPath)) return null;
|
||||
|
||||
mkdirSync(backupDir, { recursive: true });
|
||||
@@ -51,7 +59,9 @@ async function createBackup() {
|
||||
for (const f of files) {
|
||||
const src = path.join(binPath, f);
|
||||
if (existsSync(src)) {
|
||||
copyFileSync(src, path.join(backupDir, f));
|
||||
// cpSync handles both files and directories; the old copyFileSync threw
|
||||
// EISDIR on the "cli" directory, which was swallowed by the catch (#3295).
|
||||
cpSync(src, path.join(backupDir, f), { recursive: true });
|
||||
}
|
||||
}
|
||||
return backupDir;
|
||||
|
||||
65
tests/unit/cli-update-global-paths-3295.test.ts
Normal file
65
tests/unit/cli-update-global-paths-3295.test.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync, mkdtempSync, mkdirSync, existsSync, statSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const update = await import("../../bin/cli/commands/update.mjs");
|
||||
|
||||
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
||||
const REAL_VERSION = JSON.parse(
|
||||
readFileSync(path.join(REPO_ROOT, "package.json"), "utf-8")
|
||||
).version;
|
||||
|
||||
// #3295 issue 1: getCurrentVersion() must resolve package.json relative to the
|
||||
// script, not process.cwd(). When OmniRoute is installed globally, the user's
|
||||
// cwd is not the package root, so a cwd-relative lookup returns null →
|
||||
// "Could not determine current version".
|
||||
test("getCurrentVersion resolves the real version from a foreign cwd (#3295)", async () => {
|
||||
const originalCwd = process.cwd();
|
||||
const foreignCwd = mkdtempSync(path.join(tmpdir(), "omniroute-cwd-"));
|
||||
try {
|
||||
process.chdir(foreignCwd); // no package.json here → cwd-relative lookup would fail
|
||||
const version = await update.getCurrentVersion();
|
||||
assert.equal(version, REAL_VERSION);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
rmSync(foreignCwd, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// #3295 issue 2: createBackup() must (a) resolve bin/ relative to the script,
|
||||
// and (b) copy the "cli" directory recursively. The old copyFileSync(dir) threw
|
||||
// EISDIR which the outer catch swallowed → "Failed to create backup. Aborting".
|
||||
test("createBackup resolves bin/ from a foreign cwd and copies cli/ recursively (#3295)", async () => {
|
||||
const originalCwd = process.cwd();
|
||||
const originalHome = process.env.HOME;
|
||||
const foreignCwd = mkdtempSync(path.join(tmpdir(), "omniroute-cwd-"));
|
||||
const fakeHome = mkdtempSync(path.join(tmpdir(), "omniroute-home-"));
|
||||
try {
|
||||
process.chdir(foreignCwd); // no bin/ here → cwd-relative binPath would be missing
|
||||
process.env.HOME = fakeHome; // redirect ~/.omniroute/backups
|
||||
mkdirSync(fakeHome, { recursive: true });
|
||||
|
||||
const backupDir = await update.createBackup();
|
||||
|
||||
assert.ok(backupDir, "createBackup must return a path (not null)");
|
||||
// omniroute.mjs is a real file in bin/ and must be copied
|
||||
assert.ok(existsSync(path.join(backupDir, "omniroute.mjs")), "omniroute.mjs copied");
|
||||
// "cli" is a directory — it must be copied recursively, not throw EISDIR
|
||||
const cliBackup = path.join(backupDir, "cli");
|
||||
assert.ok(existsSync(cliBackup), "cli/ directory copied");
|
||||
assert.ok(statSync(cliBackup).isDirectory(), "cli/ backup is a directory");
|
||||
assert.ok(
|
||||
existsSync(path.join(cliBackup, "commands")),
|
||||
"cli/ contents copied recursively"
|
||||
);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
if (originalHome === undefined) delete process.env.HOME;
|
||||
else process.env.HOME = originalHome;
|
||||
rmSync(foreignCwd, { recursive: true, force: true });
|
||||
rmSync(fakeHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user