合并master统一工作区与Skill指纹
保留master的npm workspaces与内置Skill指纹修复 恢复并保留双方项目决策记录 补记精修最终图稳定运行入口决策
This commit is contained in:
@@ -45,9 +45,17 @@ SpacetimeDB 与 OTLP 不映射宿主端口;Jenkins 通过受控 Compose 网络
|
||||
|
||||
SpacetimeDB 2.7 CLI 发布到受控 Compose 网络地址时固定使用 `--yes=remote,migrate,break-clients`,避免 Jenkins 等待非本地目标交互确认;该预览路径不传 `--delete-data`。Jenkins 同时固定 `GENARRATIVE_PREVIEW_WEB_HOST=192.168.35.82`,不得用默认路由自动探测结果生成页面链接,以免 VPN 或容器网卡地址泄漏到同事可见 URL。
|
||||
|
||||
预览 Compose override 将 SpacetimeDB 内存上限设为 `2g`。基础 loadtest Compose 的 `896m` 是压测采样口径,当前完整模块首次发布和实例化会超过该上限;预览环境若沿用该值,容器会被 cgroup OOM 杀死并使模块上传中断。该覆盖只作用于分支预览实例,不修改生产或压测基线。
|
||||
基础 loadtest Compose 与预览 Compose override 都将 SpacetimeDB 内存上限设为 `2g`。当前完整模块首次发布和实例化的 cgroup 峰值会超过旧 `896m` 上限;完整容器或预览环境若沿用旧值,容器会被 OOM 杀死并使模块上传中断。预览 override 继续显式锁定该值并取消宿主端口映射;这不修改生产服务资源合同。
|
||||
|
||||
每个预览实例使用独立 SpacetimeDB 空库,不继承生产账号和短信凭据。Jenkins 在实例私有 `api-server.env` 中开启预览专用认证:未注册的中国大陆手机号首次使用 6 到 128 位密码时自动创建预览账号;短信入口使用 `mock` provider 与固定预览验证码 `123456`,不向真实手机发送短信。该设置不写入公共 env 示例、生产配置或镜像层;实例重建会重建独立数据库,原预览账号不保留。
|
||||
每个预览实例使用独立 SpacetimeDB 空库,不继承生产账号数据。Jenkins 在实例私有 `api-server.env` 中开启预览专用认证:未注册的中国大陆手机号首次使用 6 到 128 位密码时自动创建预览账号;短信入口强制使用 `mock` provider 与固定预览验证码 `123456`,不调用镜像内置的真实短信凭据。该预览认证覆盖不写入公共 env 示例或生产配置;实例重建会重建独立数据库,原预览账号不保留。
|
||||
|
||||
## 预览 secrets 内置
|
||||
|
||||
Jenkins 节点上的预览 secrets 权威来源固定为 `/data/jenkins/preview-secrets/.env.secrets.local`。该文件不进 Git、Docker build context、构建日志或 artifact;构建时只通过 BuildKit `secret` mount 临时提供给 `api-runtime` stage,并在该运行镜像中安装为 `/srv/genarrative/.env.secrets.local`,权限固定为 `0400`。`nginx-runtime`、Web 静态产物、SpacetimeDB 镜像及其它镜像不得包含该文件。
|
||||
|
||||
宿主固定目录应由 Jenkins 运行账号所有且权限为 `0700`,源文件权限为 `0600`;缺失、不是普通文件、owner 不匹配或权限过宽时,预览构建必须失败关闭。源文件变更后必须重新构建并替换预览镜像,只重启容器不会刷新已内置的内容。容器启动时显式注入的运行环境变量优先级高于镜像内的 `.env.secrets.local`,用于按实例覆盖非通用值。
|
||||
|
||||
这种方案只隐藏构建传输过程,不能让内置后的 secrets 对镜像持有者保密:能读取、保存或运行 `api-runtime` 镜像的人可以提取该文件。因此该镜像只能留在当前受信任内网 Docker 主机,禁止 push 到公共或跨信任边界的 registry,也禁止通过 `docker save`/构建 artifact 导出传播。需要跨边界分发时必须改用不含 secrets 的镜像与运行时密钥注入。
|
||||
|
||||
## Jenkins 参数与产物
|
||||
|
||||
@@ -110,6 +118,7 @@ Jenkins 在构建完成、归档 artifact 和更新 REST 状态之间可能短
|
||||
- Jenkins service account 只授予 `shared/Genarrative-Preview-Deployer` 的 `Job/Read`、`Job/Build` 和读取构建产物所需权限,不授 `Overall/Administer`、`Job/Configure` 或 `Job/Delete`。
|
||||
- 后端固定 Jenkins origin、Job 路径和参数白名单;客户端不能传 URL、Job 名、Compose project、容器名、宿主端口或 Jenkins 凭据。
|
||||
- Git 查询固定使用本机 Gitea SSH 地址和服务端只读凭据;客户端不能传 remote、SSH 参数或凭据。Git 缓存只写入预览控制服务的受控状态目录,搜索接口需要控制台会话且结果有数量上限。
|
||||
- 预览 secrets 只从固定宿主路径读取,构建前校验 owner、类型和权限;不允许分支、Jenkins 参数或控制面请求改写 secrets 路径、BuildKit secret ID 或镜像内目标路径。
|
||||
- Jenkins POST 支持动态 Crumb;API Token 即使免 Crumb,也不能把 Token 放进 URL 或日志。
|
||||
- API 默认只接受同源请求,写请求校验 Origin;内网本身不作为认证。
|
||||
- 同一 deployment 的发布和卸载串行执行;重复请求必须幂等或明确返回冲突。
|
||||
@@ -120,5 +129,6 @@ Jenkins 在构建完成、归档 artifact 和更新 REST 状态之间可能短
|
||||
- 后端:输入校验、登录会话、Origin、Crumb、Jenkins `401/403/404/5xx`、queue 到 build 状态机、artifact schema、卸载所有权和幂等测试。
|
||||
- 前端:登录、分支与可选 commit、自动刷新、排队/构建/成功/失败状态、内网链接、卸载确认和刷新恢复测试。
|
||||
- Jenkins:两个分支依次发布后在不同端口并存;同一分支换 commit 优先复用端口;非分支 commit 被拒绝;卸载只删除目标实例并释放端口。
|
||||
- 预览认证:新手机号可以首次密码登录并重复使用同一密码;错误密码被拒绝;获取验证码后使用 `123456` 可完成登录;容器不包含生产短信凭据。
|
||||
- 预览认证:新手机号可以首次密码登录并重复使用同一密码;错误密码被拒绝;获取验证码后使用 `123456` 可完成登录;短信入口保持 `mock` 且不调用内置的真实短信凭据。
|
||||
- secrets:构建 transcript、context 和 artifact 零出现原文;只有 `api-runtime` 包含 `0400` 的目标文件,`nginx-runtime` 与其它镜像均不包含;修改固定源文件后旧镜像不变、重建新镜像后摘要更新;显式运行 env 可覆盖内置值。
|
||||
- 通用:`npm run check:encoding`、相关 typecheck/build/test、Rust 定向测试和 `git diff --check`。
|
||||
|
||||
@@ -1207,3 +1207,10 @@ game-project/
|
||||
- **真实 Provider 开发验收入口**:`--game-chat-smoke` 是受限 CLI 标记,只允许与默认 `project-supervisor` 的 `--swarm-chat --autonomous-game-build` 组合,将新根 Run 绑定为 `project-supervisor-game-chat`,不作为产品 UI、公开 API 或通用 source 覆盖能力。现有 playable harness 通过 `npm run ai-game-creator-shell:agent-runtime:supervisor-game-chat-single-main-playable-real-e2e` 显式启动该模式,启动前同时校验 `project-supervisor` 与 `code-prototype` 的 Provider 配置,并在隔离 AppData 中验收唯一单主 child、当前 revision 的 static smoke 及 desktop/mobile 试玩回执。只有显式执行这条真实 E2E 命令才会发起 Provider 请求;普通 self-test 不读取凭据、不调用 Provider。现场 smoke 若在配置门因缺少 API Key 阻断,必须报告 `providerUsed=false`,只能证明入口、验收逻辑与无 Provider 自测已落地,不能宣称真实现场验收完成。
|
||||
- **fresh-init 取证边界**:`supervisor-game-chat-single-main-playable` 不再预写 `package.json`、`verify-e2e.mjs` 或 `game/index.html`,由正式 `--init` 生成生产 `DEFAULT_GAME_INDEX_HTML`。self-test 必须逐字节核对 harness 中的 canonical 默认入口与 Rust 生产常量,并证明空项目仍保留 Git、`AGENTS.md`、隔离 evidence 和敏感诱饵基线;真实报告必须同时证明初始 SHA-256 命中生产默认入口、根下唯一固定 child 为 `code-prototype`、最终入口已变化、static-smoke SHA-256 绑定最终入口且 desktop/mobile 各自通过。
|
||||
- **不外推范围**:上述真实 Provider 命令只验收普通 Web 工作台所采用的 `project-supervisor-game-chat + autonomous-game-build` 单 Supervisor 链。显式 `professional-dag` 与固定 16 节点 CLI/GUI 链的 owner-artifact verify、产物所有权和 path-scope 仍是独立未解决项;seeded deterministic E2E、普通 self-test 或本 game-chat 报告都不得冒充该链已修复或已完成真实验收。
|
||||
|
||||
## 2026-08-21 npm workspace 安装与打包边界
|
||||
|
||||
- AGC 进入仓库根 npm workspaces,`apps/ai-game-creator-shell/package.json` 继续独占其 Tauri guest、Codex CLI 和 App 直接依赖,但不再维护独立 `package-lock.json`。开发、CI、Jenkins 与打包前只从仓库根执行一次 `npm ci`;禁止恢复子目录独立安装。
|
||||
- 统一根 lock 出现 `@tauri-apps/api`、`@tauri-apps/plugin-*` 或 `@openai/codex` 是 AGC workspace 的合法聚合结果,不代表根 H5 或 Desktop 获得这些能力。配置门禁必须按 workspace manifest/lock entry 判断归属。
|
||||
- npm 默认 hoist。Vite/Vitest 对 `@cubone/react-file-manager` 的已发布 ESM bundle、AGC TypeScript/Tauri CLI 和 Windows `@openai/codex-win32-x64` sidecar 解析必须兼容 workspace 本地与根提升位置,不得硬编码依赖只存在于 `apps/ai-game-creator-shell/node_modules`。
|
||||
- Windows game-chat release 仍必须核对固定 Codex 文件和 SHA-256 manifest;Linux 根 lock 与 typecheck 通过不能替代 Windows sidecar 打包 smoke。完整安装、锁与 CI 口径见 [`npm workspaces 统一依赖边界`](./【技术方案】npm-workspaces统一依赖边界-2026-08-21.md)。
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# npm workspaces 统一依赖边界
|
||||
|
||||
更新时间:`2026-08-21`
|
||||
|
||||
## 目标
|
||||
|
||||
Genarrative 的 JavaScript 工程统一使用 npm workspaces。仓库只提交根 `package-lock.json`,开发、CI、Jenkins 和容器构建都从仓库根执行一次干净安装;各 App、内部包和工具仍由自己的 `package.json` 声明直接依赖和脚本。
|
||||
|
||||
本方案只迁移包管理与依赖边界,不切换 pnpm,不改变 Cargo workspace、SpacetimeDB schema、前后端 DTO 或业务运行时。
|
||||
|
||||
## Workspace 范围
|
||||
|
||||
根 `package.json` 固定声明:
|
||||
|
||||
```json
|
||||
{
|
||||
"packageManager": "npm@10.9.7",
|
||||
"workspaces": [
|
||||
"apps/admin-web",
|
||||
"apps/ai-game-creator-shell",
|
||||
"apps/desktop-shell",
|
||||
"apps/mobile-shell",
|
||||
"apps/preview-deployer-web",
|
||||
"packages/image-canvas-core",
|
||||
"packages/image-canvas-react",
|
||||
"packages/shared",
|
||||
"tools/spine-json-export-validator"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
当前纳入:
|
||||
|
||||
- `apps/admin-web`
|
||||
- `apps/ai-game-creator-shell`
|
||||
- `apps/desktop-shell`
|
||||
- `apps/mobile-shell`
|
||||
- `apps/preview-deployer-web`
|
||||
- `packages/image-canvas-core`
|
||||
- `packages/image-canvas-react`
|
||||
- `packages/shared`
|
||||
- `tools/spine-json-export-validator`
|
||||
|
||||
`.rag/runtime`、`.worktrees/`、`tmp/`、构建目录和各级 `node_modules` 不属于 workspace。RAG 继续保持独立、gitignored 的本地运行时,不进入根依赖。
|
||||
|
||||
## Manifest 与依赖所有权
|
||||
|
||||
- 根 manifest 只声明根 H5、仓库级脚本和统一测试/格式化工具的直接依赖,不再为 Mobile、AGC 或工具重复声明其专属依赖。
|
||||
- 每个 App 在自己的 manifest 声明运行时直接依赖;测试只由根统一 runner 承担的工具可以留在根,App 自己提供测试脚本时必须声明其直接测试依赖。
|
||||
- `@genarrative/image-canvas-react` 必须显式依赖 `@genarrative/image-canvas-core`;主站和 AGC 必须显式声明它们直接消费的内部画布包。
|
||||
- npm `10.9.7` 不支持依赖值 `workspace:*`。内部 workspace 依赖使用匹配本地包版本的普通 semver,例如 `"@genarrative/image-canvas-core": "0.1.0"`;npm 在根安装时自动生成本地 `link`。
|
||||
- npm 默认提升依赖,统一根 `node_modules` 中存在某包不代表根 H5 拥有该依赖。归属门禁必须检查对应 workspace manifest 和根 lock 中的 workspace package entry,不能按统一 lock 的全局 `node_modules/*` 条目判断归属。
|
||||
|
||||
`packages/shared` 本次纳入统一安装和 lock,但不顺手重写现有源码 import;后续若要把所有相对源码引用改为 `@genarrative/shared`,需先补完整 exports/build 合同并单独实施。
|
||||
|
||||
## 唯一 Lockfile
|
||||
|
||||
- 唯一权威 npm lockfile 为根 `package-lock.json`。
|
||||
- 删除 `apps/ai-game-creator-shell/package-lock.json` 与 `tools/spine-json-export-validator/package-lock.json`。
|
||||
- 新增或修改任一 workspace 依赖后,只能从仓库根使用固定 npm 版本更新根 lock。
|
||||
- 仓库门禁必须校验 workspace 清单、固定 `packageManager`、根 lock 的 workspace package/link 条目,并拒绝受管 workspace 再提交嵌套 `package-lock.json` 或 `npm-shrinkwrap.json`。
|
||||
- optional dependency、平台二进制和 bundled dependency 仍由根 lock 完整记录;Linux 生成 lock 后仍需 Windows/macOS 对应构建门禁,不能把单平台安装等同于跨平台通过。
|
||||
|
||||
## 安装与脚本
|
||||
|
||||
标准安装入口:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
```
|
||||
|
||||
开发者首次拉取或主动更新依赖时可使用根 `npm install`。Husky 的 `prepare` 只在根执行一次;各 workspace 不重复安装 hook。
|
||||
|
||||
现有 `npm run agc`、`npm run mobile-shell:*`、`npm run desktop-shell:*`、`npm run preview-deployer:web:*` 和 `npm run spine-export-validator:*` 等对外入口保持名称稳定。内部可继续使用 `npm --prefix`,或使用 `npm run <script> --workspace=<name>`;无论哪种写法,都必须保证 Expo、EAS 和 Tauri 命令在目标 App cwd 中执行。
|
||||
|
||||
AGC 的 TypeScript、Vite/Vitest bundle 和 Windows Codex sidecar 不允许硬编码依赖一定位于子 App 的 `node_modules`。解析必须兼容 npm 将依赖提升到根安装树,并在错误文案中统一要求从仓库根安装。
|
||||
|
||||
## 原生壳边界
|
||||
|
||||
- Mobile workspace 继续使用 Expo 默认 Metro 配置;当前不增加 `node-linker` 或自定义 `watchFolders`。首次迁移验收清理 Metro cache。
|
||||
- Desktop H5 仍不得声明 `@tauri-apps/api` 或任何 `@tauri-apps/plugin-*` guest 依赖。
|
||||
- AGC 可以在自己的 workspace manifest 声明 Tauri guest;统一根 lock 出现这些解析包是正常结果,不代表 Desktop 或根 H5 获得 guest 权限。
|
||||
- 根 H5 manifest 也不得直接声明 Tauri guest。配置门禁按根、Desktop、AGC 三个 manifest 的所有权分别判断。
|
||||
- Windows AGC release 必须从 workspace 或根提升位置找到 `@openai/codex-win32-x64` 并把固定 sidecar 资源打包;Windows 构建 smoke 是迁移完成条件,不由 Linux lock 检查替代。
|
||||
|
||||
## CI、Jenkins 与容器
|
||||
|
||||
- Gitea 四个 job 每个只执行一次带重试的根 `npm ci`,不再单独安装 AGC。
|
||||
- Jenkins Web Build 在安装前必须精确校验 npm `10.9.7`;`RUN_NPM_CI` 只控制一次根 `npm ci`。
|
||||
- Gitea CI 镜像只维护一个 npm lock SHA 与一份 npm cache;预热上下文必须包含根 lock 和全部 workspace manifests,使根 `npm ci` 能解析 workspace。
|
||||
- CI 镜像仍分别维护 server-rs、Desktop Tauri、AGC Tauri 三份 Cargo lock cache;npm 单锁不改变 Rust lock 边界。
|
||||
- API 镜像的 Web builder 必须显式安装并校验 npm `10.9.7`,再复制全部 workspace manifests、执行根 `npm ci`,之后才复制源码并构建主站与后台。
|
||||
- 根 lock 或任一 workspace manifest 变化都需要刷新 CI 镜像 npm cache。缓存未命中只能报告 `partial` 并受控补齐,不能跳过当前 lock 的干净安装。
|
||||
|
||||
## 验收
|
||||
|
||||
最低本地门禁:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm ls --workspaces --include-workspace-root --depth=0
|
||||
npm run check:npm-workspaces
|
||||
npm run typecheck
|
||||
npm run test
|
||||
npm run admin-web:typecheck
|
||||
npm run preview-deployer:web:test
|
||||
npm run mobile-shell:typecheck
|
||||
npm run mobile-shell:test
|
||||
npm run desktop-shell:typecheck
|
||||
npm run ai-game-creator-shell:typecheck
|
||||
npm run spine-export-validator:typecheck
|
||||
npm run check:native-shells
|
||||
npm run check:repository-ci
|
||||
npm run check:production-ops
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
干净安装验收必须在没有历史根或子 App `node_modules` 的隔离工作树执行。平台补充门禁:
|
||||
|
||||
- Linux:根、后台、预览部署器、Spine 工具构建,Desktop/AGC Tauri release smoke。
|
||||
- Windows x64:根 `npm ci` 后执行 AGC game-chat release,核对 Codex sidecar 完整性。
|
||||
- Android:Expo config/export,并在可用 EAS 环境执行一次本地 Android build。
|
||||
- macOS/iOS:在可用 runner 执行 simulator build;缺少 runner 时必须标记未验证。
|
||||
|
||||
任何 workspace 仍需要第二次 `npm ci --prefix`、嵌套 lock、未声明直接依赖或依赖某个固定 `node_modules` 层级时,迁移都不能视为完成。
|
||||
Reference in New Issue
Block a user