diff --git a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md index 8fa50c4f1..f07d93a6e 100644 --- a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md +++ b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md @@ -102,7 +102,7 @@ - 对象布局:清单固定写成 `agc/-win|mac/latest.json`;安装包与签名写成同一分区的 `/` 与 `.sig`。 - macOS 正式交付使用 universal 主程序:两个平台键指向同一个 `.app.tar.gz` 与签名,一份产物同时服务 Apple Silicon 与 Intel。单架构目标(`aarch64-apple-darwin` / `x86_64-apple-darwin`)只用于本机诊断,不登记正式分区清单——单架构构建不可轮流覆盖同一个 `latest.json` 并宣称双架构均可更新。 -- universal 主程序同时携带分目录的 arm64/x64 原生 Codex 组件:每个组件保持上游单架构布局与独立 SHA-256 清单,运行中的主程序切片只选择同架构目录,不得把两套原生包的元数据或辅助程序混装。 +- universal 主程序同时携带分目录的 arm64/x64 原生 Codex 组件:每个组件保持上游单架构布局与独立 SHA-256 清单,运行中的主程序切片只选择同架构目录,不得把两套原生包的元数据或辅助程序混装。随包 Node 运行时同样按架构分目录(`game-runtime/node/darwin-arm64/`、`darwin-x64/`,各带 `agc-node-runtime.v1` 清单):两套都来自节点上同版本的官方发行版,构建时缺一份或版本不一致即在写出资源前失败,运行切片只采用与当前架构匹配的那一份,单架构构建保持扁平目录不变。 - 构建期要求:打开 `bundle.createUpdaterArtifacts` 以生成 `.sig`;构建环境提供签名私钥与密码(私钥内容不得入库);公钥写入客户端配置。公钥在首个带更新能力的版本发布后不可更换,更换等于放弃自动更新(只能手动重装)。 - 版本递增按渠道及系统分区独立进行:发布脚本读取该分区远端 `latest.json` 的 `version`,与本地版本取较高者递增 patch;不同分区的远端版本互不影响。 - 版本高水位:仅 dev 的 Windows 分区在迁移窗口内取「分区清单版本」与「旧协议迁移指针版本」较大值再递增,避免已发布旧客户端版本倒退。迁移窗口结束(旧指针 404)后只读分区清单;release、自定义渠道与所有 Mac 分区均不参与旧指针比较。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 0657da9a2..bb044b152 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -71,7 +71,7 @@ ### 环境与工作流 -- 客户端交付配套 Node/npm;发布包从本机已安装且与目标平台/架构一致的工具链制作受校验资源,保留许可并校验内容摘要。安装态不依赖系统 PATH 的 Node;开发态可使用已验证的宿主运行时。不得从项目或相对 PATH 加载伪造运行时。 +- 客户端交付配套 Node/npm;发布包从本机已安装且与目标平台/架构一致的工具链制作受校验资源,保留许可并校验内容摘要。安装态不依赖系统 PATH 的 Node;开发态可使用已验证的宿主运行时。不得从项目或相对 PATH 加载伪造运行时。universal 包携带**两套**架构运行时并按架构并列存放(`game-runtime/node/-/`,各自一份清单),运行切片只采用与当前架构一致的那一份;两套必须来自同一 Node 版本,缺一份或版本不一致时构建在写出任何资源之前失败,不能用「少带一份」或退回系统 Node 充数。 - 新建 Web 游戏在生图和大量实现前执行客户端环境预检,检查 Node/npm 的实际版本、浏览器启动和 CDP 可用性。报告只包含安全状态、版本、耗时和错误码。缺失或异常必须尽早返回阻塞,不能指示模型改宿主环境、全盘搜索或自行下载一套运行时。编辑器工程不强制 Web 工具链。 - 预检不安装依赖、不修改项目 revision、不请求平台生成;构建仍执行项目自己的 npm 脚本。Codex 隔离 HOME 与平台凭据边界保持不变,客户端把已验证的运行时加入执行 PATH,不能把宿主凭据目录交给模型。 - 第一轮先明确本次必需玩法、素材和验收项。同批独立读取尽量合并,必需图片一次规划;已有且可用的资产复用。已有目标全部通过后给出交付结果,非阻塞的新点子列为后续工作,不在收尾时主动开启新的生产链。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 0596085fc..f72e3be9c 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -736,6 +736,23 @@ Job 名为 `Genarrative-Agc-MacOS-Build`,SCM 直接读取仓库内上述 Jenki 发布凭据全部走 Jenkins 全局凭据,并在 `withCredentials` 内注入当前进程:`AgcUpdaterSigningKey`(与 `AgcUpdaterSigningKeyPassword`)映射为 `TAURI_SIGNING_PRIVATE_KEY` / `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`,`AliyunAccessKeyId` / `AliyunaccessKeySecret` 映射为 `AGC_OSS_ACCESS_KEY_ID` / `AGC_OSS_ACCESS_KEY_SECRET`;私钥与凭据不写入 workspace、日志或归档产物。上传顺序为更新包、签名、首装包,三者全部成功后才覆盖 `agc/-mac/latest.json` 指针;`AGC_RELEASE_DRY_RUN` 与 Windows 渠道对称:默认关闭即真发布,勾选后才退化为演练(只打印将上传的对象、不写任何 OSS 对象)。本 Job 是正式发布入口,调度器在发号后与 Windows 一起触发它,并额外传 `SKIP_IF_SUPERSEDED=true`——Mac 节点是日常办公机,离线期间排队的旧构建在节点回来后若已被源码分支推进,直接跳过而不发布过期版本。Mac 节点需要 `ossutil`(实测 1.7.19 原生 arm64 可用,装在 `~/.local/bin`,已在 Job 的 PATH 内),可用 `OSSUTIL_BIN` 指定命令名或绝对路径。首次发布建议显式指定 `AGC_RELEASE_VERSION`,避免按渠道高水位递增时出现版本链回退。 +随包 Node 运行时也是节点前置,且 universal 需要**两套架构各一份**:客户端发布包内嵌 Node + npm 作为受校验资源(`agc-node-runtime.v1` 清单 + 逐文件 SHA-256),构建时只从**本机已安装、且与目标平台/架构一致**的工具链取材,缺文件、版本不符或目标不匹配立即失败,禁止回退系统 Node、也不允许从项目或相对 PATH 里借用运行时。宿主架构那一份直接取构建 Node(Mac 节点为 arm64,即 PATH 上的 `node`);另一架构必须由节点显式提供:预装官方 darwin-x64 发行版到 `~/Library/Jenkins/node/darwin-x64`(位置可用 `AGC_NODE_RUNTIME_DARWIN_X64_HOME` 覆盖),保留 `LICENSE` 与 `lib/node_modules/npm`,Job 会把它们导出为 `AGC_NODE_RUNTIME_DARWIN_X64_PATH` / `AGC_NODE_RUNTIME_DARWIN_X64_LICENSE_PATH`。两套必须**同版本**(首次接入时均为 `v22.23.2`):缺一份、架构不符或版本不一致,staging 都会在写出任何运行时目录之前失败关闭,不会生成半套资源的更新包;版本核对同时是 Job 的编译前预检。预装与核对命令(官方 dist,校验 `SHASUMS256.txt`,再确认架构与版本): + +```sh +version=22.23.2 +curl -fsSLO "https://nodejs.org/dist/v${version}/node-v${version}-darwin-x64.tar.gz" +curl -fsSLO "https://nodejs.org/dist/v${version}/SHASUMS256.txt" +grep " node-v${version}-darwin-x64.tar.gz\$" SHASUMS256.txt | shasum -a 256 -c - +mkdir -p "$HOME/Library/Jenkins/node/darwin-x64" +tar -xzf "node-v${version}-darwin-x64.tar.gz" -C "$HOME/Library/Jenkins/node/darwin-x64" --strip-components=1 +/usr/bin/lipo -archs "$HOME/Library/Jenkins/node/darwin-x64/bin/node" # 期望 x86_64 +/usr/bin/arch -x86_64 "$HOME/Library/Jenkins/node/darwin-x64/bin/node" --version # 期望与构建 Node 相同 +``` + +universal 包的随包 Node 按架构并列存放:`Contents/Resources/game-runtime/node/darwin-arm64/` 与 `darwin-x64/`,各自带独立 `manifest.json`;Rust 侧按当前运行架构选择对应目录(两个候选都要过清单的平台/架构校验,存在但损坏则失败关闭,绝不退回系统 Node),架构校验脚本对两份都做完整性核对与 `lipo -archs` 架构核对,只执行与本次 smoke 架构一致的那一份,另一份由另一次架构的 smoke 覆盖。单架构目标仍写扁平目录 `game-runtime/node/`,行为不变。体积代价:官方 Node + npm 解包后约 130 MB/份(实测 arm64 `node` 112.9 MB + npm 16.3 MB,x64 `node` 115.4 MB + npm 15.6 MB),universal 两份合计约 260 MB,DMG 压缩后增量预计在 50 MB 量级——这是双架构必须付的代价,不通过「Mac 跳过随包 Node」来省。 + +同一条规则适用于本机跨架构诊断构建:宿主架构以外的目标(例如 Apple Silicon 上打 `x86_64-apple-darwin`)必须用 `AGC_NODE_RUNTIME___PATH` 指定来源,缺失时报「缺少 / 的 Node 运行时」并给出该变量名,不再退化成含义模糊的「平台/架构不一致」。 + 产物边界:macOS 代码签名与公证暂缺,构建通过剥离 `APPLE_*` 凭据让 Tauri 跳过 Apple 签名,**不得使用 `--no-sign`**——该标志会连带跳过 updater 的 minisign 签名,产物缺少 `.sig` 会直接卡在验签门禁(首次实跑即命中该坑)。构建清单按 `codesign -dv` 实测记录 `appleSigned` / `appleSignatureKind`(如 `adhoc`),并固定记录 `notarized=false`。用户首次安装需要在 Gatekeeper 中手动放行;更新包校验本身只依赖 minisign 签名,因此未签名不阻断自动更新的校验环节,但「安装 → 重启接管新版本」的实机闭环仍未验证,不得以构建成功替代。 Job 描述与节点描述是 Jenkins 侧元数据,**不随仓库同步**:Jenkinsfile 只回写参数定义,描述必须手工维护,否则会停留在建 Job 时的口径(2026-09-20 就出现过描述还写着「只构建归档、不签名不上传」,而实际已经是含签名、分区清单、验签与 OSS 上传的发布管线)。当前口径:Job 描述说明「构建 universal → 双架构 smoke → DMG → `-mac` 分区清单 → 更新包验签 → 按 dry-run 决定上传,未做 Apple 签名与公证」;节点描述说明「`genarrative-agc-macos`、EXCLUSIVE 单 executor、仅手动触发、独立 workspace、sccache 在 HOME」。维护手法:该 Job 上 `POST job//config.xml` 会返回 500,节点侧同接口正常;因此改 Job 描述用脚本接口原地更新(保留构建历史),不要为了改描述删 Job 重建。 diff --git a/jenkins/Jenkinsfile.ai-game-creator-shell-macos-build b/jenkins/Jenkinsfile.ai-game-creator-shell-macos-build index 91bcfdc97..511c0bd42 100644 --- a/jenkins/Jenkinsfile.ai-game-creator-shell-macos-build +++ b/jenkins/Jenkinsfile.ai-game-creator-shell-macos-build @@ -34,6 +34,10 @@ pipeline { CARGO_INCREMENTAL = '0' // 不把节点用户名写进仓库:PATH 在下面的 shell 步骤里按 $HOME 展开。 AGC_EXTRA_PATH = '/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin' + // universal 需要两份**同版本**的架构运行时:宿主(arm64)取自 PATH 里的构建 Node, + // x86_64 由节点预装的官方发行版提供。只写相对 HOME 的目录,绝对路径在 shell 步骤里拼。 + // 节点没有它时构建前即失败,绝不静默跳过或让更新包缺一份运行时。 + AGC_NODE_RUNTIME_DARWIN_X64_HOME = 'Library/Jenkins/node/darwin-x64' } stages { stage('Checkout') { @@ -116,6 +120,24 @@ pipeline { arch -x86_64 /usr/bin/uname -m if command -v sccache >/dev/null 2>&1; then sccache --version; else echo '[agc-macos] 未找到 sccache;本次回退到 rustc 直接构建。'; fi rustup target add aarch64-apple-darwin x86_64-apple-darwin + # 随包 Node 的两套架构运行时:宿主那一份就是 PATH 里的构建 Node, + # x86_64 那一份必须是节点上预装的官方发行版(含 LICENSE 与 lib/node_modules/npm)。 + # 两份版本必须一致,否则 staging 会在写出任何资源前失败关闭;这里提前到编译前暴露。 + x64_root="${AGC_NODE_RUNTIME_DARWIN_X64_HOME:-Library/Jenkins/node/darwin-x64}" + case "$x64_root" in /*) ;; *) x64_root="${HOME:?HOME 不能为空}/$x64_root" ;; esac + if [ ! -x "${x64_root}/bin/node" ]; then + echo "[agc-macos] 缺少 x86_64 Node 运行时:${x64_root}/bin/node" + echo '[agc-macos] 安装官方 darwin-x64 发行版到该目录(保留 LICENSE 与 lib/node_modules/npm)后重试;也可以覆盖 AGC_NODE_RUNTIME_DARWIN_X64_HOME' + exit 1 + fi + host_node_version="$(node --version)" + x64_node_version="$(/usr/bin/arch -x86_64 "${x64_root}/bin/node" --version)" + if [ "$host_node_version" != "$x64_node_version" ]; then + echo "[agc-macos] 两套 Node 运行时版本不一致:arm64=${host_node_version} x86_64=${x64_node_version}" + echo '[agc-macos] universal 更新包只接受同版本的两套运行时,请把节点上的 x86_64 发行版升到与构建 Node 相同版本' + exit 1 + fi + echo "[agc-macos] 随包 Node 运行时:arm64=${host_node_version} x86_64=${x64_node_version}(来源 ${x64_root})" npm ci --no-audit --no-fund node apps/ai-game-creator-shell/scripts/prepare-macos-codex.mjs ''' @@ -143,6 +165,12 @@ pipeline { sh ''' set -eu export PATH="$HOME/.local/bin:$HOME/.cargo/bin:${AGC_EXTRA_PATH}" + # universal staging 需要另一架构的 Node 来源;路径与 Toolchain 阶段同一口径, + # 缺失/版本不一致由 staging 在任何落盘前再次失败关闭。 + x64_root="${AGC_NODE_RUNTIME_DARWIN_X64_HOME:-Library/Jenkins/node/darwin-x64}" + case "$x64_root" in /*) ;; *) x64_root="${HOME:?HOME 不能为空}/$x64_root" ;; esac + export AGC_NODE_RUNTIME_DARWIN_X64_PATH="${x64_root}/bin/node" + export AGC_NODE_RUNTIME_DARWIN_X64_LICENSE_PATH="${x64_root}/LICENSE" echo "[agc-macos] 渠道=${AGC_UPDATE_CHANNEL} 分区=${AGC_UPDATE_CHANNEL}-mac 目标=universal-apple-darwin dry-run=${AGC_RELEASE_DRY_RUN}" ossutil_bin="${OSSUTIL_BIN:-ossutil}" if command -v "${ossutil_bin}" >/dev/null 2>&1; then