refactor(desktop): consolidate desktop-electron into desktop package (#25822)

This commit is contained in:
Brendan Allan
2026-05-05 13:43:36 +08:00
committed by GitHub
parent 6f7d63e9ce
commit b4147c8d08
441 changed files with 115 additions and 13441 deletions

View File

@@ -5,8 +5,8 @@ import { RUST_TARGET } from "./utils"
if (!RUST_TARGET) throw new Error("RUST_TARGET not defined")
const BUNDLE_DIR = `src-tauri/target/${RUST_TARGET}/release/bundle`
const BUNDLES_OUT_DIR = path.join(process.cwd(), `src-tauri/target/bundles`)
const BUNDLE_DIR = "dist"
const BUNDLES_OUT_DIR = path.join(process.cwd(), "dist/bundles")
await $`mkdir -p ${BUNDLES_OUT_DIR}`
await $`cp -r ${BUNDLE_DIR}/*/OpenCode* ${BUNDLES_OUT_DIR}`
await $`cp -r ${BUNDLE_DIR}/* ${BUNDLES_OUT_DIR}`

View File

@@ -0,0 +1,12 @@
import { $ } from "bun"
import { resolveChannel } from "./utils"
const arg = process.argv[2]
const channel = arg === "dev" || arg === "beta" || arg === "prod" ? arg : resolveChannel()
const src = `./icons/${channel}`
const dest = "resources/icons"
await $`rm -rf ${dest}`
await $`cp -R ${src} ${dest}`
console.log(`Copied ${channel} icons from ${src} to ${dest}`)

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env bun
import { $ } from "bun"
import path from "path"
const dir = process.env.LATEST_YML_DIR!
if (!dir) throw new Error("LATEST_YML_DIR is required")
const repo = process.env.GH_REPO
if (!repo) throw new Error("GH_REPO is required")
const version = process.env.OPENCODE_VERSION
if (!version) throw new Error("OPENCODE_VERSION is required")
type FileEntry = {
url: string
sha512: string
size: number
blockMapSize?: number
}
type LatestYml = {
version: string
files: FileEntry[]
releaseDate: string
}
function parse(content: string): LatestYml {
const lines = content.split("\n")
let version = ""
let releaseDate = ""
const files: FileEntry[] = []
let current: Partial<FileEntry> | undefined
const flush = () => {
if (current?.url && current.sha512 && current.size) files.push(current as FileEntry)
current = undefined
}
for (const line of lines) {
const indented = line.startsWith(" ") || line.startsWith(" -")
if (line.startsWith("version:")) version = line.slice("version:".length).trim()
else if (line.startsWith("releaseDate:"))
releaseDate = line.slice("releaseDate:".length).trim().replace(/^'|'$/g, "")
else if (line.trim().startsWith("- url:")) {
flush()
current = { url: line.trim().slice("- url:".length).trim() }
} else if (indented && current && line.trim().startsWith("sha512:"))
current.sha512 = line.trim().slice("sha512:".length).trim()
else if (indented && current && line.trim().startsWith("size:"))
current.size = Number(line.trim().slice("size:".length).trim())
else if (indented && current && line.trim().startsWith("blockMapSize:"))
current.blockMapSize = Number(line.trim().slice("blockMapSize:".length).trim())
else if (!indented && current) flush()
}
flush()
return { version, files, releaseDate }
}
function serialize(data: LatestYml) {
const lines = [`version: ${data.version}`, "files:"]
for (const file of data.files) {
lines.push(` - url: ${file.url}`)
lines.push(` sha512: ${file.sha512}`)
lines.push(` size: ${file.size}`)
if (file.blockMapSize) lines.push(` blockMapSize: ${file.blockMapSize}`)
}
lines.push(`releaseDate: '${data.releaseDate}'`)
return lines.join("\n") + "\n"
}
async function read(subdir: string, filename: string): Promise<LatestYml | undefined> {
const file = Bun.file(path.join(dir, subdir, filename))
if (!(await file.exists())) return undefined
return parse(await file.text())
}
const output: Record<string, string> = {}
// Windows: merge arm64 + x64 into single file
const winX64 = await read("latest-yml-x86_64-pc-windows-msvc", "latest.yml")
const winArm64 = await read("latest-yml-aarch64-pc-windows-msvc", "latest.yml")
if (winX64 || winArm64) {
const base = winArm64 ?? winX64!
output["latest.yml"] = serialize({
version: base.version,
files: [...(winArm64?.files ?? []), ...(winX64?.files ?? [])],
releaseDate: base.releaseDate,
})
}
// Linux x64: pass through
const linuxX64 = await read("latest-yml-x86_64-unknown-linux-gnu", "latest-linux.yml")
if (linuxX64) output["latest-linux.yml"] = serialize(linuxX64)
// Linux arm64: pass through
const linuxArm64 = await read("latest-yml-aarch64-unknown-linux-gnu", "latest-linux-arm64.yml")
if (linuxArm64) output["latest-linux-arm64.yml"] = serialize(linuxArm64)
// macOS: merge arm64 + x64 into single file
const macX64 = await read("latest-yml-x86_64-apple-darwin", "latest-mac.yml")
const macArm64 = await read("latest-yml-aarch64-apple-darwin", "latest-mac.yml")
if (macX64 || macArm64) {
const base = macArm64 ?? macX64!
output["latest-mac.yml"] = serialize({
version: base.version,
files: [...(macArm64?.files ?? []), ...(macX64?.files ?? [])],
releaseDate: base.releaseDate,
})
}
// Upload to release
const tag = `v${version}`
const tmp = process.env.RUNNER_TEMP ?? "/tmp"
for (const [filename, content] of Object.entries(output)) {
const filepath = path.join(tmp, filename)
await Bun.write(filepath, content)
await $`gh release upload ${tag} ${filepath} --clobber --repo ${repo}`
console.log(`uploaded ${filename}`)
}
console.log("finalized latest yml files")

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bun
import { $ } from "bun"
import { resolveChannel } from "./utils"
const channel = resolveChannel()
await $`bun ./scripts/copy-icons.ts ${channel}`
await $`cd ../opencode && bun script/build-node.ts`

View File

@@ -1,15 +1,5 @@
import { $ } from "bun"
import { copyBinaryToSidecarFolder, getCurrentSidecar, windowsify } from "./utils"
await $`bun ./scripts/copy-icons.ts ${process.env.OPENCODE_CHANNEL ?? "dev"}`
const RUST_TARGET = Bun.env.TAURI_ENV_TARGET_TRIPLE
const sidecarConfig = getCurrentSidecar(RUST_TARGET)
const binaryPath = windowsify(`../opencode/dist/${sidecarConfig.ocBinary}/bin/opencode`)
await (sidecarConfig.ocBinary.includes("-baseline")
? $`cd ../opencode && bun run build --single --baseline`
: $`cd ../opencode && bun run build --single`)
await copyBinaryToSidecarFolder(binaryPath, RUST_TARGET)
await $`cd ../opencode && bun script/build-node.ts`

View File

@@ -1,20 +1,9 @@
#!/usr/bin/env bun
import { $ } from "bun"
import { Script } from "@opencode-ai/script"
import { copyBinaryToSidecarFolder, getCurrentSidecar, windowsify } from "./utils"
await import("./prebuild")
const pkg = await Bun.file("./package.json").json()
pkg.version = Script.version
await Bun.write("./package.json", JSON.stringify(pkg, null, 2) + "\n")
console.log(`Updated package.json version to ${Script.version}`)
const sidecarConfig = getCurrentSidecar()
const artifact = process.env.OPENCODE_CLI_ARTIFACT ?? "opencode-cli"
const dir = "src-tauri/target/opencode-binaries"
await $`mkdir -p ${dir}`
await $`gh run download ${process.env.GITHUB_RUN_ID} -n ${artifact}`.cwd(dir)
await copyBinaryToSidecarFolder(windowsify(`${dir}/${sidecarConfig.ocBinary}/bin/opencode`))

View File

@@ -1,5 +1,13 @@
import { $ } from "bun"
export type Channel = "dev" | "beta" | "prod"
export function resolveChannel(): Channel {
const raw = Bun.env.OPENCODE_CHANNEL
if (raw === "dev" || raw === "beta" || raw === "prod") return raw
return "dev"
}
export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; assetExt: string }> = [
{
rustTarget: "aarch64-apple-darwin",
@@ -35,22 +43,30 @@ export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; ass
export const RUST_TARGET = Bun.env.RUST_TARGET
export function getCurrentSidecar(target = RUST_TARGET) {
if (!target && !RUST_TARGET) throw new Error("RUST_TARGET not set")
function nativeTarget() {
const { platform, arch } = process
if (platform === "darwin") return arch === "arm64" ? "aarch64-apple-darwin" : "x86_64-apple-darwin"
if (platform === "win32") return arch === "arm64" ? "aarch64-pc-windows-msvc" : "x86_64-pc-windows-msvc"
if (platform === "linux") return arch === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu"
throw new Error(`Unsupported platform: ${platform}/${arch}`)
}
export function getCurrentSidecar(target = RUST_TARGET ?? nativeTarget()) {
const binaryConfig = SIDECAR_BINARIES.find((b) => b.rustTarget === target)
if (!binaryConfig) throw new Error(`Sidecar configuration not available for Rust target '${RUST_TARGET}'`)
if (!binaryConfig) throw new Error(`Sidecar configuration not available for Rust target '${target}'`)
return binaryConfig
}
export async function copyBinaryToSidecarFolder(source: string, target = RUST_TARGET) {
await $`mkdir -p src-tauri/sidecars`
const dest = windowsify(`src-tauri/sidecars/opencode-cli-${target}`)
export async function copyBinaryToSidecarFolder(source: string) {
const dir = `resources`
await $`mkdir -p ${dir}`
const dest = windowsify(`${dir}/opencode-cli`)
await $`cp ${source} ${dest}`
if (process.platform === "win32" && process.env.GITHUB_ACTIONS === "true") {
await $`pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass -File ../../script/sign-windows.ps1 ${dest}`
}
if (process.platform === "darwin") await $`codesign --force --sign - ${dest}`
console.log(`Copied ${source} to ${dest}`)
}