diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 009d773..f2d717d 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -67,7 +67,7 @@ jobs: - name: Ensure taskboard resource dirs exist run: mkdir -p vendor/dashi-taskboard/dist/web - name: Install vendored taskboard dependencies - run: npm --prefix vendor/dashi-taskboard install + run: npm --prefix vendor/dashi-taskboard ci - name: Clippy run: cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings - name: Test diff --git a/package.json b/package.json index 3cc9052..e1d6c46 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codex-pro-max", "private": true, - "version": "1.22.2", + "version": "1.22.3", "license": "MIT", "type": "module", "scripts": { @@ -11,7 +11,7 @@ "preview": "vite preview", "tauri": "node scripts/tauri.mjs", "build:updater": "node scripts/build-updater.mjs", - "build:taskboard": "npm --prefix vendor/dashi-taskboard install && npm --prefix vendor/dashi-taskboard run build:web", + "build:taskboard": "npm --prefix vendor/dashi-taskboard ci && npm --prefix vendor/dashi-taskboard run build:web", "ensure:taskboard": "node -e \"require('fs').mkdirSync('vendor/dashi-taskboard/dist/web',{recursive:true})\"", "check:craft": "node scripts/check-craft.mjs", "check:release": "node scripts/check-release.mjs", diff --git a/release-notes/v1.22.3.md b/release-notes/v1.22.3.md new file mode 100644 index 0000000..1868131 --- /dev/null +++ b/release-notes/v1.22.3.md @@ -0,0 +1,6 @@ +## Changes + +- Repackage the bundled `dashi-taskboard` at `c9fb80c` (`v1.1.23`) after reviewing the current upstream runtime changes. New runtime files remain covered by the existing `server` / `shared` / `scripts` / `cli` / `inject` resource roots, so the bundle whitelist is not widened unnecessarily. +- Switch vendored Taskboard dependency installation from `npm install` to `npm ci` in release builds and CI, making the packaged web UI and runtime dependencies follow the submodule lockfile exactly. +- Strengthen release preflight: initialize the pinned Taskboard submodule when needed, verify the required Taskboard resource contract, and validate the `dashi-taskboard` Node engine requirement before packaging. +- Sync the release version to `1.22.3` across `package.json`, Tauri config, `Cargo.toml`, and the root package entry in `Cargo.lock`; release validation now checks all four locations. diff --git a/scripts/check-release.mjs b/scripts/check-release.mjs index 0c1defc..c52290e 100644 --- a/scripts/check-release.mjs +++ b/scripts/check-release.mjs @@ -1,65 +1,103 @@ #!/usr/bin/env node // 发布前置校验(本地打 tag 前与 CI validate job 共用): -// 必查:package.json / tauri.conf.json / Cargo.toml 三处版本号一致 -// 必查:tauri.conf.json bundle.resources 中被 git 跟踪的源路径真实存在 -// (v1.3.2 曾漏打包 skills/ 导致安装技能失败,见 AGENTS.md。 -// dist/web 等构建产物被 gitignore,CI validate 阶段尚未构建, -// 只对 git 已跟踪的路径做存在性校验) +// 必查:package.json / tauri.conf.json / Cargo.toml / Cargo.lock 四处版本一致 +// 必查:Taskboard 运行时资源白名单完整,且固定 submodule 中预构建阶段应存在的资源真实存在 +// dist/web 与 node_modules 由 build:taskboard 在后续构建阶段生成,因此预检仅校验其映射存在 // --tag :追加校验 tag 与版本一致 + release-notes/.md 存在 // 用法:node scripts/check-release.mjs [--tag v0.12.2] -import { readFileSync, existsSync } from "node:fs"; -import { dirname, resolve } from "node:path"; import { execFileSync } from "node:child_process"; +import { existsSync, readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; const read = (p) => readFileSync(p, "utf8"); +const taskboardPackagePath = "vendor/dashi-taskboard/package.json"; +if (!existsSync(taskboardPackagePath)) { + try { + execFileSync( + "git", + ["submodule", "update", "--init", "--recursive", "vendor/dashi-taskboard"], + { stdio: "inherit" }, + ); + } catch (error) { + console.error("✗ 无法初始化 vendor/dashi-taskboard submodule"); + process.exit(1); + } +} const pkgVersion = JSON.parse(read("package.json")).version; const tauriConfPath = "src-tauri/tauri.conf.json"; const tauriConf = JSON.parse(read(tauriConfPath)); const tauriVersion = tauriConf.version; const cargoVersion = read("src-tauri/Cargo.toml").match(/^version = "([^"]+)"$/m)?.[1]; +const cargoLockVersion = read("src-tauri/Cargo.lock").match( + /\[\[package\]\]\nname = "codex-pro-max"\nversion = "([^"]+)"/, +)?.[1]; const failures = []; -if (!cargoVersion) { - failures.push("src-tauri/Cargo.toml 找不到 version 字段"); -} -if (pkgVersion !== tauriVersion || tauriVersion !== cargoVersion) { +if (!cargoVersion) failures.push("src-tauri/Cargo.toml 找不到 version 字段"); +if (!cargoLockVersion) failures.push("src-tauri/Cargo.lock 找不到 codex-pro-max 根包版本"); +if ( + pkgVersion !== tauriVersion || + tauriVersion !== cargoVersion || + cargoVersion !== cargoLockVersion +) { failures.push( - `版本号三处不一致:package.json=${pkgVersion} tauri.conf.json=${tauriVersion} Cargo.toml=${cargoVersion}`, + `版本号四处不一致:package.json=${pkgVersion} tauri.conf.json=${tauriVersion} Cargo.toml=${cargoVersion} Cargo.lock=${cargoLockVersion}`, ); } -// bundle.resources 的源路径(map 的 key)必须存在。../vendor/... 相对 tauri.conf.json 所在目录解析。 -// dist/web 等构建产物被 gitignore,CI validate job 在构建前运行、产物尚不存在, -// 因此只对 git 已跟踪的路径做存在性校验(能拦下 skills/ 这种仓库内资源漏打包)。 -const isGitTracked = (abs) => { - try { - execFileSync("git", ["ls-files", "--error-unmatch", abs], { stdio: "pipe" }); - return true; - } catch { - return false; - } -}; -const tauriDir = dirname(tauriConfPath); const resources = tauriConf.bundle?.resources ?? {}; const resourceEntries = typeof resources === "object" && !Array.isArray(resources) ? Object.keys(resources) : resources; +const requiredTaskboardResources = [ + "../vendor/dashi-taskboard/server", + "../vendor/dashi-taskboard/shared", + "../vendor/dashi-taskboard/scripts", + "../vendor/dashi-taskboard/cli", + "../vendor/dashi-taskboard/inject", + "../vendor/dashi-taskboard/skills", + "../vendor/dashi-taskboard/dist/web", + "../vendor/dashi-taskboard/package.json", + "../vendor/dashi-taskboard/node_modules/smol-toml", + "../vendor/dashi-taskboard/node_modules/ws", + "../vendor/dashi-taskboard/integrations/deepseek-harness", +]; +for (const required of requiredTaskboardResources) { + if (!resourceEntries.includes(required)) { + failures.push(`bundle.resources 缺少 Taskboard 运行时资源:${required}`); + } +} + +const tauriDir = dirname(tauriConfPath); +const generatedBeforeBuild = new Set([ + resolve(tauriDir, "../vendor/dashi-taskboard/dist/web"), + resolve(tauriDir, "../vendor/dashi-taskboard/node_modules/smol-toml"), + resolve(tauriDir, "../vendor/dashi-taskboard/node_modules/ws"), +]); for (const src of resourceEntries) { const abs = resolve(tauriDir, src); - if (isGitTracked(abs) && !existsSync(abs)) { - failures.push(`bundle.resources 源路径不存在(git 已跟踪):${src}(解析为 ${abs})`); + if (generatedBeforeBuild.has(abs)) continue; + if (!existsSync(abs)) { + failures.push(`bundle.resources 源路径不存在:${src}(解析为 ${abs})`); + } +} + +if (existsSync(taskboardPackagePath)) { + const taskboardPkg = JSON.parse(read(taskboardPackagePath)); + if (taskboardPkg.engines?.node !== ">=22.5") { + failures.push( + `dashi-taskboard Node 引擎要求发生变化:当前=${taskboardPkg.engines?.node ?? "未声明"},请同步 launcher 前置条件`, + ); } } const tagIdx = process.argv.indexOf("--tag"); const tag = tagIdx !== -1 ? process.argv[tagIdx + 1] : null; if (tag) { - if (tag !== `v${pkgVersion}`) { - failures.push(`tag ${tag} 与版本号 v${pkgVersion} 不一致`); - } + if (tag !== `v${pkgVersion}`) failures.push(`tag ${tag} 与版本号 v${pkgVersion} 不一致`); const notesPath = `release-notes/${tag}.md`; if (!existsSync(notesPath)) { - failures.push(`缺少 release notes:${notesPath}(build-release.yml 强制要求,见 AGENTS.md)`); + failures.push(`缺少 release notes:${notesPath}(build-release.yml 强制要求)`); } } diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index acf3811..95ac70b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -504,7 +504,7 @@ dependencies = [ [[package]] name = "codex-pro-max" -version = "1.22.0" +version = "1.22.3" dependencies = [ "hmac", "libc", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 2d53bf0..33c1f81 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codex-pro-max" -version = "1.22.2" +version = "1.22.3" description = "One-click launcher for dashi-taskboard integrated with Codex" authors = ["codex-pro-max"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 33ffa07..d01ded3 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json", "productName": "Codex Pro Max", - "version": "1.22.2", + "version": "1.22.3", "identifier": "com.codex.pro.max", "build": { "beforeDevCommand": "pnpm run ensure:taskboard && pnpm run dev",