From 9872e53cca845276bd0af7cd6d4fc93e030f75bd Mon Sep 17 00:00:00 2001 From: Sebastian Benjamin Date: Mon, 12 Jan 2026 11:45:21 -0800 Subject: [PATCH 1/2] Set built JBrowse CLI version to the @jbrowse/core version --- .../external/fetch-jbrowse-bundle.mjs | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/jbrowse/resources/external/fetch-jbrowse-bundle.mjs b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs index 04623fe0b..27366dbc2 100644 --- a/jbrowse/resources/external/fetch-jbrowse-bundle.mjs +++ b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs @@ -1,5 +1,5 @@ import { execSync } from 'node:child_process'; -import { existsSync, mkdirSync, copyFileSync, rmSync } from 'node:fs'; +import { existsSync, mkdirSync, copyFileSync, rmSync, readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; const ROOT = resolve('.'); @@ -7,6 +7,25 @@ const BUILD = join(ROOT, 'buildCli'); const OUTDIR = join(ROOT, 'resources', 'external'); const OUTFILE = join(OUTDIR, 'jbrowse.js'); +function getResolvedCoreVersion() { + // Prefer lockfile, fallback to node_modules + const lockPath = join(ROOT, 'package-lock.json'); + if (existsSync(lockPath)) { + const lock = JSON.parse(readFileSync(lockPath, 'utf8')); + const v = + lock?.packages?.['node_modules/@jbrowse/core']?.version || + lock?.dependencies?.['@jbrowse/core']?.version; + if (v) return v; + } + + const corePkg = join(ROOT, 'node_modules', '@jbrowse', 'core', 'package.json'); + if (existsSync(corePkg)) { + return JSON.parse(readFileSync(corePkg, 'utf8')).version; + } + + throw new Error('Could not determine resolved @jbrowse/core version (no lockfile entry and no node_modules).'); +} + async function extractTgz(tgzPath, cwd) { try { const mod = await import('tar').catch(() => null); @@ -20,19 +39,36 @@ async function extractTgz(tgzPath, cwd) { execSync(`tar -xzf "${tgzPath}" -C "${cwd}"`, { stdio: 'inherit', shell: true }); } +function findCliEntrypoint(buildDir) { + const candidates = [ + join(buildDir, 'package', 'bundle', 'index.js'), + join(buildDir, 'package', 'lib', 'index.js') + ]; + + for (const p of candidates) { + if (existsSync(p)) return p; + } + + throw new Error( + `Could not find @jbrowse/cli entrypoint. Tried:\n` + + candidates.map(c => ` - ${c}`).join('\n') + ); +} + async function main() { if (existsSync(BUILD)) rmSync(BUILD, { recursive: true, force: true }); mkdirSync(BUILD, { recursive: true }); mkdirSync(OUTDIR, { recursive: true }); - console.log('Packing @jbrowse/cli (latest)…'); - const out = execSync('npm pack @jbrowse/cli', { + const coreVersion = getResolvedCoreVersion(); + const cliSpec = process.env.JBROWSE_CLI_VERSION || coreVersion; + + console.log(`Packing @jbrowse/cli@${cliSpec} (core resolved: ${coreVersion})…`); + const out = execSync(`npm pack @jbrowse/cli@${cliSpec}`, { cwd: BUILD, stdio: ['ignore', 'pipe', 'inherit'], shell: true, - }) - .toString() - .trim(); + }).toString().trim(); const tgz = join(BUILD, out); console.log(`Downloaded: ${tgz}`); @@ -40,12 +76,9 @@ async function main() { console.log('Extracting tarball…'); await extractTgz(tgz, BUILD); - const bundled = join(BUILD, 'package', 'bundle', 'index.js'); - if (!existsSync(bundled)) { - throw new Error(`bundle/index.js not found at ${bundled}`); - } + const entry = findCliEntrypoint(BUILD); - copyFileSync(bundled, OUTFILE); + copyFileSync(entry, OUTFILE); console.log(`Copied bundle to ${OUTFILE}`); rmSync(BUILD, { recursive: true, force: true }); From e3e22c6c6ff0757d5c0abd35ba67e2719acee4a3 Mon Sep 17 00:00:00 2001 From: Sebastian Benjamin Date: Mon, 12 Jan 2026 14:26:18 -0800 Subject: [PATCH 2/2] Floor version to 3.6.0 --- .../external/fetch-jbrowse-bundle.mjs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/jbrowse/resources/external/fetch-jbrowse-bundle.mjs b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs index 27366dbc2..16a028199 100644 --- a/jbrowse/resources/external/fetch-jbrowse-bundle.mjs +++ b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs @@ -26,6 +26,25 @@ function getResolvedCoreVersion() { throw new Error('Could not determine resolved @jbrowse/core version (no lockfile entry and no node_modules).'); } +function semverLt(a, b) { + const pa = String(a).match(/(\d+)\.(\d+)\.(\d+)/); + const pb = String(b).match(/(\d+)\.(\d+)\.(\d+)/); + if (!pa || !pb) return false; + for (let i = 1; i <= 3; i++) { + const da = Number(pa[i]); + const db = Number(pb[i]); + if (da !== db) return da < db; + } + return false; +} + +function floorVersion(spec, min) { + const m = String(spec).match(/^(\^|~|>=)?\s*(\d+\.\d+\.\d+)(.*)$/); + if (!m) return spec; + const [, op = '', v, rest = ''] = m; + return semverLt(v, min) ? `${op}${min}${rest}` : spec; +} + async function extractTgz(tgzPath, cwd) { try { const mod = await import('tar').catch(() => null); @@ -61,7 +80,7 @@ async function main() { mkdirSync(OUTDIR, { recursive: true }); const coreVersion = getResolvedCoreVersion(); - const cliSpec = process.env.JBROWSE_CLI_VERSION || coreVersion; + const cliSpec = floorVersion(process.env.JBROWSE_CLI_VERSION || coreVersion, '3.6.0'); console.log(`Packing @jbrowse/cli@${cliSpec} (core resolved: ${coreVersion})…`); const out = execSync(`npm pack @jbrowse/cli@${cliSpec}`, {