diff --git a/package.json b/package.json index f87e6994..a423bd4a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "build:mac-x64": "npm run build:mac-x64 --workspace @neuralnomads/codenomad-electron-app", "build:binaries": "npm run build:binaries --workspace @neuralnomads/codenomad-electron-app", "typecheck": "npm run typecheck --workspace @codenomad/ui && npm run typecheck --workspace @neuralnomads/codenomad-electron-app", - "bumpVersion": "npm version --workspaces --include-workspace-root --no-git-tag-version" + "bumpVersion": "npm version --workspaces --include-workspace-root --no-git-tag-version && npm run sync:version --workspace @codenomad/tauri-app" }, "dependencies": { "7zip-bin": "^5.2.0", diff --git a/packages/server/src/ui/__tests__/remote-ui.test.ts b/packages/server/src/ui/__tests__/remote-ui.test.ts index e858498d..99b34900 100644 --- a/packages/server/src/ui/__tests__/remote-ui.test.ts +++ b/packages/server/src/ui/__tests__/remote-ui.test.ts @@ -55,4 +55,31 @@ describe("resolveUi local version preference", () => { assert.equal(result.uiStaticDir, bundledDir) assert.equal(result.uiVersion, "0.8.1") }) + + it("prefers bundled when bundled and downloaded versions are equal", async () => { + const bundledDir = path.join(tempRoot, "bundled") + const configDir = path.join(tempRoot, "config") + const currentDir = path.join(configDir, "ui", "current") + + await mkdir(bundledDir, { recursive: true }) + await mkdir(currentDir, { recursive: true }) + + writeFileSync(path.join(bundledDir, "index.html"), "bundled") + writeFileSync(path.join(bundledDir, "ui-version.json"), JSON.stringify({ uiVersion: "0.8.1" })) + + writeFileSync(path.join(currentDir, "index.html"), "current") + writeFileSync(path.join(currentDir, "ui-version.json"), JSON.stringify({ uiVersion: "0.8.1" })) + + const result = await resolveUi({ + serverVersion: "0.8.1", + bundledUiDir: bundledDir, + autoUpdate: false, + configDir, + logger: noopLogger, + }) + + assert.equal(result.source, "bundled") + assert.equal(result.uiStaticDir, bundledDir) + assert.equal(result.uiVersion, "0.8.1") + }) }) diff --git a/packages/server/src/ui/remote-ui.ts b/packages/server/src/ui/remote-ui.ts index 1aff87df..879c5970 100644 --- a/packages/server/src/ui/remote-ui.ts +++ b/packages/server/src/ui/remote-ui.ts @@ -250,7 +250,7 @@ async function pickBestLocalUi(args: { uiStaticDir: currentResolved, source: "downloaded", uiVersion: await readUiVersion(currentResolved), - priority: 2, + priority: 1, }) } @@ -260,7 +260,7 @@ async function pickBestLocalUi(args: { uiStaticDir: bundledResolved, source: "bundled", uiVersion: await readUiVersion(bundledResolved), - priority: 1, + priority: 2, }) } diff --git a/packages/tauri-app/package.json b/packages/tauri-app/package.json index 67bf4578..fddb3baf 100644 --- a/packages/tauri-app/package.json +++ b/packages/tauri-app/package.json @@ -8,6 +8,7 @@ "dev:ui": "npm run dev --workspace @codenomad/ui", "dev:prep": "node ./scripts/dev-prep.js", "dev:bootstrap": "npm run dev:prep && npm run dev:ui", + "sync:version": "node ./scripts/sync-tauri-version.js", "prebuild": "node ./scripts/prebuild.js", "bundle:server": "npm run prebuild", "build": "tauri build" diff --git a/packages/tauri-app/scripts/prebuild.js b/packages/tauri-app/scripts/prebuild.js index a382a8d2..f74825f5 100644 --- a/packages/tauri-app/scripts/prebuild.js +++ b/packages/tauri-app/scripts/prebuild.js @@ -56,11 +56,7 @@ async function ensureMonacoAssets() { function ensureServerBuild() { const distPath = path.join(serverRoot, "dist") const publicPath = path.join(serverRoot, "public") - if (fs.existsSync(distPath) && fs.existsSync(publicPath)) { - return - } - - console.log("[prebuild] server build missing; running workspace build...") + console.log("[prebuild] rebuilding server workspace for desktop packaging...") execSync("npm --workspace @neuralnomads/codenomad run build", { cwd: workspaceRoot, stdio: "inherit", diff --git a/packages/tauri-app/scripts/sync-tauri-version.js b/packages/tauri-app/scripts/sync-tauri-version.js new file mode 100644 index 00000000..f5f8092e --- /dev/null +++ b/packages/tauri-app/scripts/sync-tauri-version.js @@ -0,0 +1,102 @@ +#!/usr/bin/env node + +const fs = require("fs") +const path = require("path") + +const root = path.resolve(__dirname, "..") +const packageJsonPath = path.join(root, "package.json") +const cargoTomlPath = path.join(root, "src-tauri", "Cargo.toml") +const cargoLockPath = path.join(root, "Cargo.lock") +const tauriConfigPath = path.join(root, "src-tauri", "tauri.conf.json") + +function readPackageVersion() { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) + if (typeof packageJson.version !== "string" || packageJson.version.length === 0) { + throw new Error("Missing version in packages/tauri-app/package.json") + } + return packageJson.version +} + +function syncCargoToml(version) { + const current = fs.readFileSync(cargoTomlPath, "utf8") + const packageVersionPattern = /(\[package\][\s\S]*?^version\s*=\s*")([^"]+)(")/m + const match = current.match(packageVersionPattern) + + if (!match) { + throw new Error("Unable to find [package] version in packages/tauri-app/src-tauri/Cargo.toml") + } + + if (match[2] === version) { + return false + } + + const updated = current.replace(packageVersionPattern, (_, prefix, __, suffix) => `${prefix}${version}${suffix}`) + fs.writeFileSync(cargoTomlPath, updated) + return true +} + +function syncCargoLock(version) { + if (!fs.existsSync(cargoLockPath)) { + return false + } + + const current = fs.readFileSync(cargoLockPath, "utf8") + const packageVersionPattern = /(\[\[package\]\]\r?\nname = "codenomad-tauri"\r?\nversion = ")([^"]+)(")/ + const match = current.match(packageVersionPattern) + + if (!match) { + throw new Error("Unable to find codenomad-tauri version in packages/tauri-app/Cargo.lock") + } + + if (match[2] === version) { + return false + } + + const updated = current.replace(packageVersionPattern, (_, prefix, __, suffix) => `${prefix}${version}${suffix}`) + fs.writeFileSync(cargoLockPath, updated) + return true +} + +function syncTauriConfig(version) { + const current = fs.readFileSync(tauriConfigPath, "utf8") + const config = JSON.parse(current) + if (config.version === version) { + return false + } + + config.version = version + fs.writeFileSync(tauriConfigPath, `${JSON.stringify(config, null, 2)}\n`) + return true +} + +function main() { + const version = readPackageVersion() + const changed = [] + + if (syncCargoToml(version)) { + changed.push(path.relative(root, cargoTomlPath)) + } + + if (syncCargoLock(version)) { + changed.push(path.relative(root, cargoLockPath)) + } + + if (syncTauriConfig(version)) { + changed.push(path.relative(root, tauriConfigPath)) + } + + if (changed.length === 0) { + console.log(`[sync-tauri-version] already aligned to ${version}`) + return + } + + console.log(`[sync-tauri-version] synced ${version} -> ${changed.join(", ")}`) +} + +try { + main() +} catch (error) { + const message = error instanceof Error ? error.message : String(error) + console.error(`[sync-tauri-version] failed: ${message}`) + process.exit(1) +}