docs(macos): record TC-MAC-028..033 and refresh delivery plan
Document the six macOS issues found and fixed during end-to-end verification of the all-in-one install: litellm dependency version-probe SyntaxError (TC-028), prisma generator PATH (TC-029), QMD plist undefined nodejs_version (TC-030), QMD better-sqlite3 Node ABI mismatch (TC-031), XFCE/XRDP apt-on-macOS (TC-032), and litellm DATABASE_URL password percent-encoding / P1013 (TC-033), each with its playbooks commit. Update the fix-dimension summary and the runtime delivery plan status. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d0d5a79be8
commit
7fd48bbf74
@ -4,8 +4,8 @@
|
||||
>
|
||||
> 本文是落地前的详细规划(设计 + 变更清单 + 提交/部署/验收方案)。实现阶段严格按本文执行,不扩大修改范围、不做大规模重构、优先复用现有实现。
|
||||
|
||||
- 状态:规划已定稿,待实现
|
||||
- 影响仓库:`ai-workspace-infra/playbooks`、`ai-workspace-lab/xworkspace-console`、`ai-workspace-lab/xworkspace-core-skills`
|
||||
- 状态:Linux 离线包链路与 macOS 本地校验链路已进入联调阶段;macOS 已越过多数 role 兼容性阻塞,当前重点是 LiteLLM 离线 runtime 接入、完整安装复跑和幂等验收
|
||||
- 影响仓库:`ai-workspace-infra/playbooks`、`ai-workspace-lab/xworkspace-console`、`ai-workspace-lab/xworkspace-core-skills`、`ai-workspace-services/qmd`、`ai-workspace-services/litellm`
|
||||
- 目标主机:`root@acp-bridge.onwalk.net`
|
||||
- 对外默认域名(唯一公开服务):`acp-bridge.onwalk.net`
|
||||
|
||||
@ -14,9 +14,12 @@
|
||||
- [x] 等待并核对 `xworkspace-console` 的离线包 GitHub Actions 发布链路,确认 `publish-release` 完整结束且 release 产物上传成功。
|
||||
- [ ] 继续核对 `root@acp-bridge.onwalk.net` 的远程部署进度,确认 `setup-ai-workspace-all-in-one.sh` 最终完成并输出统一摘要。
|
||||
- [x] `setup-ai-workspace-all-in-one.sh` 在目标主机上优先使用离线安装包加速部署,减少在线拉取与安装耗时。
|
||||
- [x] 为 LiteLLM 新增 runtime wheelhouse release workflow,供 all-in-one 离线包消费。
|
||||
- [ ] 验证 `ai-workspace-services/litellm` 的 runtime release 实际生成成功,并确认 console 离线包能下载 matching `litellm-runtime-<distro>-<version>-<arch>.tar.gz`。
|
||||
- [ ] 验证 `setup-ai-workspace-all-in-one.sh` 幂等性:同一主机连续执行两次均成功,复用凭据、离线包缓存与已导入镜像,并安全等待部署/APT 锁。
|
||||
- [ ] 完成最终验收核对:Bridge 对外可达、其余服务默认仅本地监听、`acp-codex` / `opencode` / `gemini` / `hermes` / `qmd` / `litellm` 状态正常。
|
||||
- [ ] 记录最终提交哈希与远端验证结果,回填到本计划的交付结果部分。
|
||||
- [ ] 完成 macOS 本地最终验收核对:Portal、Bridge、OpenClaw、QMD、Hermes、PostgreSQL、Vault、LiteLLM 状态正常,`http://localhost:8181/mcp` 和 LiteLLM health 可达。
|
||||
- [ ] 完成远程 Linux 最终验收核对:Bridge 对外可达、其余服务默认仅本地监听、`acp-codex` / `opencode` / `gemini` / `hermes` / `qmd` / `litellm` 状态正常。
|
||||
- [ ] 记录最终提交哈希、GitHub Actions run、release tag 与远端验证结果,回填到本计划的交付结果部分。
|
||||
|
||||
---
|
||||
|
||||
@ -325,6 +328,35 @@ setup-ai-workspace-all-in-one.sh [repo: xworkspace-console/scripts]
|
||||
|
||||
> 每个仓库**独立提交**,分别记录 Commit Hash 写入最终交付说明。
|
||||
|
||||
### 6.1 当前实现进度(2026-06-22)
|
||||
|
||||
| 仓库 | 已完成进展 | 已知待处理 |
|
||||
|---|---|---|
|
||||
| `ai-workspace-infra/playbooks` | OpenClaw doctor/restart 已拆分;QMD 已补 macOS LaunchAgent;OpenClaw `acpx` 兼容性 assert 已修;LiteLLM 已切 Python 3.13 venv、安装探测和 `.install-spec` 跳过重复安装 | 需要完整 macOS 复跑确认 `qmd :8181/mcp`、OpenClaw registry、LiteLLM health;需要确认 all-in-one 的 macOS patch 与 playbooks main 不再互相覆盖 |
|
||||
| `ai-workspace-lab/xworkspace-console` | all-in-one 离线包链路已能消费 console/bridge/qmd/litellm runtime release;macOS 调试案例持续记录在 `docs/case/macos_compatibility_tests.md` | `uninstall purge` 仍需打印删除路径;需要清理离线包生成目录等非源码正式目录;需要确认 `install.svc.plus/ai-workspace` 发布入口同步到最新 main |
|
||||
| `ai-workspace-services/qmd` | all-in-one 离线包脚本按 `qmd-runtime-linux-${ARCH}.tar.gz` 消费 release;playbooks 已补 QMD macOS LaunchAgent | 需要确认 latest runtime release 与 offline package 拉取路径持续可用;macOS 需实测 MCP endpoint |
|
||||
| `ai-workspace-services/litellm` | 新增 `.github/workflows/offline-package-litellm-runtime.yaml`,产出 `litellm-runtime-<distro>-<version>-<arch>.tar.gz`、wheelhouse、可选 portable Python、`metadata/runtime.env` | 需要触发 GitHub Actions 并确认 release asset 与 `SHA256SUMS`;需要确认 console 离线包使用 `latest-runtime` 能解析到该 release |
|
||||
| `ai-workspace-lab/xworkspace-core-skills` | all-in-one 离线包仍按 core-skills repo/ref 打包 | 当前未发现新的 macOS 阻塞;最终验收仍需确认技能注入与 OpenClaw/QMD 可见 |
|
||||
|
||||
### 6.2 近期关键提交
|
||||
|
||||
| 仓库 | Commit | 说明 |
|
||||
|---|---|---|
|
||||
| `ai-workspace-infra/playbooks` | `09a39e6` | `perf(openclaw): avoid unnecessary doctor repairs` |
|
||||
| `ai-workspace-infra/playbooks` | `f01e0bb` | `fix(qmd): provision macOS LaunchAgent` |
|
||||
| `ai-workspace-infra/playbooks` | `c11f51b` | `fix(openclaw): allow version-matched acpx plugin` |
|
||||
| `ai-workspace-infra/playbooks` | `71ebe64` | `fix(litellm): isolate runtime in Python 3.13 venv` |
|
||||
| `ai-workspace-infra/playbooks` | `6a2f05f` | `fix(litellm): skip redundant dependency installs` |
|
||||
| `ai-workspace-services/litellm` | `51cde5e32` | `ci: add offline litellm runtime workflow` |
|
||||
|
||||
### 6.3 当前最需要收口的问题
|
||||
|
||||
1. `LiteLLM`:在线 `pip install litellm[proxy]` 仍可能因大 wheel 下载中断失败;应以 runtime wheelhouse release 作为 all-in-one 默认加速路径,并保留在线路径为 fallback。
|
||||
2. `install.svc.plus/ai-workspace`:需要确认公开短链实际拉到的是 `xworkspace-console@main` 最新脚本,否则 macOS 仍可能运行旧 bootstrap。
|
||||
3. `uninstall purge`:需要输出将删除/已删除/不存在的路径,覆盖 macOS 与 Linux 的 token、Vault/OpenClaw 状态、临时部署目录、系统配置目录。
|
||||
4. 工作区清理:需要清理 `ai-workspace-all-in-one-offline-*` 等生成目录,避免离线包产物混入源码根目录。
|
||||
5. 最终验收:需要在 macOS 上做一次干净安装和一次重复安装,记录各服务端口、LaunchAgent/systemd 状态、health endpoint 与 changed 统计。
|
||||
|
||||
---
|
||||
|
||||
## 7. 部署与验证
|
||||
@ -398,8 +430,8 @@ ssh root@acp-bridge.onwalk.net \
|
||||
|
||||
1. **所有 `npm -g` 共享同一 prefix → 必须 Phase 1 串行。**
|
||||
`roles/vhosts/nodejs` 设 `npm_config_prefix=/usr/local/lib/npm`;Agent CLI(opencode-ai / @google/gemini-cli / @openai/codex / @anthropic-ai/claude-code)、`yarn`、`openclaw@ver` 全部 `npm -g` 到该 prefix。并发会争用同一 `node_modules`/`.staging` 与 npm cache 锁 → **不可并发**。
|
||||
2. **LiteLLM 是全局 `pip install` → Phase 1 串行**(非项目内 venv,写系统 site-packages)。修正早期草案中“pip 可 async”的判断。
|
||||
3. **真正安全的 Phase 2 候选是“外部 I/O 预取”**:git clone、二进制下载、docker pull、独立目录的前端 build。它们不碰 dpkg/npm-prefix/pip 全局锁,且写入各自独立路径。
|
||||
2. **LiteLLM 已改为独立 Python 3.13 venv,但依赖安装仍应串行收口**。它不再写系统 site-packages,但 `pip install litellm[proxy]` 依赖树大、网络失败率高,默认方向应是优先消费离线 wheelhouse,在线 venv 安装仅作 fallback。
|
||||
3. **真正安全的 Phase 2 候选是“外部 I/O 预取”**:git clone、二进制下载、docker pull、独立目录的前端 build、runtime release 下载。它们不碰 dpkg/npm-prefix/pip 全局锁,且写入各自独立路径。
|
||||
4. **跨 sub-playbook 的并发收益最大处在 Shell 预取层**:11 个步骤由 ansible 顺序导入,play 间难并发;把可并行的 I/O 上提到 bootstrap 的 Phase 2 fork 池(§10.5)预取,ansible 仅消费已就位产物,是收益/风险比最高的定制。
|
||||
5. **离线包优先**(呼应 TODO):已有离线安装包/已导入镜像时,Phase 2 预取应短路跳过,直接复用缓存。
|
||||
|
||||
@ -414,7 +446,7 @@ ssh root@acp-bridge.onwalk.net \
|
||||
| 5 bridge + ACP | 同步 console;acp_server_* 的全局安装部分 | `xworkmate-go-core` 二进制下载/放置、acp 各自独立工作目录 prepare | 配置渲染、按依赖 `requires acp-*.service` 顺序启动、validation |
|
||||
| 6 vault | (systemd 基础准备) | `get_url` vault zip 下载、解压放置 | 配置渲染、systemd/init、health |
|
||||
| 7 postgres | Docker 安装、common 基础 | `docker pull` PG 镜像、初始化独立 data 目录 | compose 渲染、`compose up`、health |
|
||||
| 8 litellm | apt python3-pip、**全局 pip install litellm** | — | 配置渲染、systemd、health(`:4000/health`) |
|
||||
| 8 litellm | apt/Homebrew Python 准备、Python 3.13 venv 创建、离线 wheelhouse 或 fallback pip 安装 | 下载 `litellm-runtime-<distro>-<version>-<arch>.tar.gz`、校验 SHA256、准备 `packages/pip`/`metadata/runtime.env` | 配置渲染、Prisma client generate、systemd/launchd、health(`:4000/health`) |
|
||||
| 9 qmd | (bun 运行时安装,全局) | 条件并发:qmd 拉取/`bun install`(隔离于 `~/.bun`,不碰 dpkg) | qmd.env/index.yml 渲染、systemd --user、health(`:8181`) |
|
||||
| 11 xfce(可选) | apt 桌面包/xrdp/chrome、`npm -g`/Playwright | — | xrdp 服务 enable/start、会话配置 |
|
||||
|
||||
@ -452,7 +484,7 @@ ssh root@acp-bridge.onwalk.net \
|
||||
```
|
||||
|
||||
- 收口铁律:任一 Phase 2 产物在**被 Phase 3 消费前**必须 `finished`。
|
||||
- dpkg/全局 npm/全局 pip **绝不** `async`(§10.2)。
|
||||
- dpkg/全局 npm/全局 pip **绝不** `async`;LiteLLM venv 安装虽然不再是全局 pip,也应在 wheelhouse 准备完成后串行执行,便于失败定位与重试(§10.2)。
|
||||
|
||||
### 10.5 Shell 层动态 fork 并发(≤ CPU 核心数 × 2,预取层)
|
||||
|
||||
@ -505,7 +537,7 @@ pipelining = true
|
||||
|
||||
- [ ] 优化前后 `ansible-playbook --list-tasks` 任务集合一致(无丢失/合并)。
|
||||
- [ ] 每个 `async` 任务都有对应 `async_status` 收口,无悬挂 job。
|
||||
- [ ] Phase 1(apt/全局 npm/全局 pip/dpkg)与 Phase 3(daemon-reload/enable/start/health/摘要/清理)仍严格串行。
|
||||
- [ ] Phase 1(apt/全局 npm/全局 pip/dpkg、LiteLLM venv 安装)与 Phase 3(daemon-reload/enable/start/health/摘要/清理)仍严格串行。
|
||||
- [ ] Phase 2 任务互不写同一文件、不抢同一锁;离线包存在时短路跳过。
|
||||
- [ ] 连续两次执行均成功、`changed=0` 幂等行为不变;Shell fork 池失败子任务非零退出且日志可见。
|
||||
|
||||
|
||||
@ -177,6 +177,167 @@
|
||||
| **修复方案** | 改 `ansible.builtin.command: brew install python@3.13` + `environment.PATH` 前置 `/opt/homebrew/bin:/usr/local/bin` + `HOMEBREW_NO_AUTO_UPDATE=1`。真实仓库已改;clone 路径由 `patch_playbook_litellm_macos()` 同步补丁 |
|
||||
| **备注** | litellm 后续仍有 macOS 缺口待逐个处理:`/root` 派生的 salt/db 密钥 assert、`/etc/litellm` 配置目录、`become: true` + `become_user` 的 pip/prisma 任务(服务用户在 macOS 未创建)、DB provisioning 等 |
|
||||
|
||||
## 当前进展快照(2026-06-22)
|
||||
|
||||
当前 macOS 调试入口仍以公开安装命令为准:
|
||||
|
||||
```bash
|
||||
curl -sfL https://install.svc.plus/ai-workspace | bash -
|
||||
```
|
||||
|
||||
截至 2026-06-22,`xworkspace-console` 的 bootstrap 入口、`playbooks` 的 all-in-one role 链路、`ai-workspace-services/litellm` 的 runtime 发布链路已经形成三仓库协同。macOS 本地部署已越过早期路径、权限、Homebrew、Vault、PostgreSQL、OpenClaw、QMD 等阻塞点,当前主要剩余风险集中在 LiteLLM 依赖安装的网络稳定性、离线 runtime release 的产物验证,以及最终连续两次幂等部署。
|
||||
|
||||
已推送到 `ai-workspace-infra/playbooks` 的关键提交:
|
||||
|
||||
| Commit | 主题 | 对 macOS 部署的影响 |
|
||||
|---|---|---|
|
||||
| `09a39e6` | `perf(openclaw): avoid unnecessary doctor repairs` | 将 OpenClaw doctor 与 restart 拆开,避免普通 restart 触发 `doctor --fix --force` |
|
||||
| `f01e0bb` | `fix(qmd): provision macOS LaunchAgent` | 为 QMD 补用户级 LaunchAgent,支持 macOS 下启动 MCP 服务 |
|
||||
| `c11f51b` | `fix(openclaw): allow version-matched acpx plugin` | 兼容版本匹配的 `acpx` 插件,避免插件注册表 assert 误杀 |
|
||||
| `71ebe64` | `fix(litellm): isolate runtime in Python 3.13 venv` | LiteLLM 改为 Python 3.13 venv 隔离,避免 Python 3.13/3.14 混用 |
|
||||
| `6a2f05f` | `fix(litellm): skip redundant dependency installs` | 增加包探测和安装标记,重复执行时跳过已满足的 LiteLLM 依赖安装 |
|
||||
|
||||
已推送到 `ai-workspace-services/litellm` 的关键提交:
|
||||
|
||||
| Commit | 主题 | 对 macOS/离线部署的影响 |
|
||||
|---|---|---|
|
||||
| `51cde5e32` | `ci: add offline litellm runtime workflow` | 新增 `.github/workflows/offline-package-litellm-runtime.yaml`,产出 `litellm-runtime-<distro>-<version>-<arch>.tar.gz`,供 console 离线包脚本消费 |
|
||||
|
||||
当前仍需用一次干净安装验证 `install.svc.plus` 指向的远端脚本是否已经包含最新 bootstrap 逻辑。如果失败点仍显示旧任务或旧路径,应先确认发布入口是否已经同步到 `ai-workspace-lab/xworkspace-console@main` 最新版本。
|
||||
|
||||
## TC-MAC-020: OpenClaw doctor 过重导致 handler 慢
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/gateway_openclaw/handlers/main.yml` |
|
||||
| **触发现象** | `RUNNING HANDLER [roles/vhosts/gateway_openclaw/ : Repair OpenClaw health findings (POSIX)]` 耗时约 5-6 秒;此前 restart 与 doctor 绑定,普通配置变化也可能触发 `openclaw doctor --fix --force --yes` |
|
||||
| **根因** | handler 将“轻量 restart”和“doctor repair”耦合,且 `--fix --force` 默认做修复路径,适合真实健康问题,不适合每次部署收口都跑 |
|
||||
| **修复方案** | `playbooks` 中已拆分 doctor 与 restart:日常只做 lightweight restart;只有 package/config/plugin 等实际变化才触发 doctor;优先使用较轻的检查/repair 模式,减少无关变化把 doctor 拉起来 |
|
||||
| **验证状态** | 已提交 `09a39e6`。仍需在完整 macOS 部署中观察 OpenClaw handler 是否只在真实变更时触发 |
|
||||
|
||||
## TC-MAC-021: QMD 缺 macOS LaunchAgent
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/qmd/` |
|
||||
| **触发现象** | QMD MCP 端口 `http://localhost:8181/mcp` 需要作为 macOS 用户服务运行,但 role 缺少 launchd provisioning |
|
||||
| **根因** | Linux/systemd 路径已有服务管理,macOS 缺少 `LaunchAgents/plus.svc.xworkspace.qmd.plist` 等用户级服务描述 |
|
||||
| **修复方案** | 新增 QMD LaunchAgent:`plus.svc.xworkspace.qmd`,以 macOS 用户级服务方式启动 |
|
||||
| **验证状态** | 已提交 `f01e0bb`。仍需在完整安装后验证 `launchctl` 状态与 `http://localhost:8181/mcp` 可达 |
|
||||
|
||||
## TC-MAC-022: OpenClaw Codex 插件兼容性 assert 误杀
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/gateway_openclaw/tasks/main.yml` |
|
||||
| **触发报错** | `Assert OpenClaw Codex plugin matches gateway version` 失败,提示必须运行 `@openclaw/codex 2026.6.1` 与 `openclaw-multi-session-plugins 2026.6.1`,并且不得保留 stale global `@openclaw/acpx` |
|
||||
| **根因** | assert 将 `acpx` 一律视为 stale,但当前 OpenClaw 插件注册表可能包含版本匹配的 `acpx`,应检查版本而非只检查存在性 |
|
||||
| **修复方案** | 调整 assert:允许 version-matched `acpx`,仅拒绝 stale/global 不匹配版本 |
|
||||
| **验证状态** | 已提交 `c11f51b`。仍需在全量部署中观察插件注册表刷新后 assert 结果 |
|
||||
|
||||
## TC-MAC-023: LiteLLM Python 3.13/3.14 混用
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/litellm/defaults/main.yml`、`roles/vhosts/litellm/tasks/main.yml` |
|
||||
| **触发现象** | macOS 上 Homebrew Python 与系统/其它 Python 版本混用,LiteLLM 依赖可能被装进不一致的解释器或 site-packages,后续 `prisma generate` 与服务启动不稳定 |
|
||||
| **根因** | 早期安装路径没有强制独立 venv,且 macOS 环境里可能同时存在 Python 3.13、3.14 |
|
||||
| **修复方案** | LiteLLM runtime 固定使用 Python 3.13 创建隔离 venv:`~/.local/share/litellm/venv`;`pip`、`litellm`、`prisma` 均从该 venv 执行 |
|
||||
| **验证状态** | 已提交 `71ebe64`。仍需完整部署验证服务启动和 `prisma generate` |
|
||||
|
||||
## TC-MAC-024: LiteLLM 依赖安装慢且公网下载易中断
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/litellm/tasks/main.yml`、`roles/vhosts/litellm/defaults/main.yml` |
|
||||
| **触发报错** | `Ensure LiteLLM and DB dependencies are installed` 最长耗时约 581 秒,随后因 `IncompleteRead` / `curl 18` / GitHub archive 或 PyPI wheel 下载中断失败 |
|
||||
| **根因** | `litellm[proxy]` 依赖树大,包含 `polars-runtime-32`、`cryptography`、`boto3`、`mcp` 等大量包;直接在线 `pip install` 既慢又依赖网络稳定性。将 `git+https` 改为 GitHub archive 后解决了 git clone EOF,但仍无法避免大 wheel 下载中断 |
|
||||
| **已修复** | ① 默认安装源由 `git+https` 改为 GitHub archive;② 增加 `PIP_CACHE_DIR` 和更长 timeout;③ 安装前探测已装 `litellm/prisma/psycopg2-binary`,并用 `.install-spec` 标记跳过重复安装;④ 新增 `ai-workspace-services/litellm` 的 offline runtime workflow,预构建目标发行版 wheelhouse |
|
||||
| **当前状态** | 在线安装路径已缓解但未根除网络风险;真正的长期解法是让 all-in-one 优先消费 `litellm-runtime-<distro>-<version>-<arch>.tar.gz` 中的 wheelhouse |
|
||||
| **待验证** | 需要触发并确认 `offline-package-litellm-runtime.yaml` 在 GitHub Actions 生成 release,且 `xworkspace-console/scripts/create-ai-workspace-offline-package.sh` 能拉取 `ai-workspace-services/litellm` 的 matching runtime asset |
|
||||
|
||||
## TC-MAC-025: LiteLLM runtime release 与 all-in-one 离线包对接
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `ai-workspace-services/litellm/.github/workflows/offline-package-litellm-runtime.yaml`、`xworkspace-console/scripts/create-ai-workspace-offline-package.sh`、`xworkspace-console/scripts/ai-workspace-offline-install.sh` |
|
||||
| **契约** | console 离线包脚本会下载 `LITELLM_RUNTIME_RELEASE_REPO=ai-workspace-services/litellm` 下的 `litellm-runtime-${DISTRO_ID}-${DISTRO_VERSION}-${ARCH}.tar.gz`,解包后复制 `packages/pip`、可选 `packages/python`、`metadata/runtime.env` |
|
||||
| **已完成** | `litellm` 仓库新增 workflow,矩阵覆盖 Debian 11/12/13 与 Ubuntu 22.04/24.04/26.04 的 amd64/arm64;Ubuntu 26.04 额外打包 portable Python 3.13.14;release 中合并 SHA256SUMS |
|
||||
| **待处理** | 需要检查 GitHub Actions 实际 run 是否成功;需要确认 release tag 命名与 console 侧 `latest-runtime` 解析一致;需要在离线 all-in-one 包里实测 `metadata/litellm-runtime.env` 是否正确注入 `LITELLM_PACKAGE_SPEC` |
|
||||
|
||||
## TC-MAC-026: uninstall purge 需要打印删除路径
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发命令** | `curl -sfL https://install.svc.plus/ai-workspace \| bash -s -- uninstall purge` |
|
||||
| **需求** | purge 模式不仅删除本地状态,还要明确打印将删除/已删除的路径,便于用户确认清理范围 |
|
||||
| **当前状态** | 已识别为待处理项;需要在 `setup-ai-workspace-all-in-one.sh` 的 uninstall/purge 分支中抽出统一 `purge_path` / `purge_matching_paths` helper,删除前输出存在路径,不存在时也输出 skipped/absent |
|
||||
| **涉及路径** | macOS 至少包括 `~/.ai_workspace_auth_token`、`~/.vault_password`、`~/.openclaw`、`/tmp/xworkspace-core-skills`、`/tmp/xworkmate-bridge`、`/tmp/ai-workspace-deploy`;Linux 还包括 `/opt/ai-workspace`、`/etc/ai-workspace`、用户 systemd unit 等 |
|
||||
|
||||
## TC-MAC-027: 非源码正式目录清理
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发现象** | 工作区出现类似 `ai-workspace-all-in-one-offline-ubuntu-22.04-amd64/` 的生成目录 |
|
||||
| **根因** | 离线包构建/解包产物进入了开发工作区,容易被误认为源码目录 |
|
||||
| **处理原则** | 不属于源码仓库正式目录的生成产物应从工作区清理;离线包输出应放在明确的 `dist/`、release artifact 或临时目录中,不应混入源码根目录 |
|
||||
| **待处理** | 后续需要补一次仓库级清扫:确认 `xworkspace-console`、`playbooks`、`litellm` 各自 `git status --ignored`,清理未跟踪离线包目录,并按需要补 `.gitignore` |
|
||||
|
||||
## TC-MAC-028: LiteLLM 依赖版本探测一行 Python 语法错误致 set_fact 崩溃
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/litellm/tasks/main.yml`(Inspect/Decide 任务) |
|
||||
| **触发报错** | `TASK [litellm : Decide whether LiteLLM dependencies need installation]` → `the field 'args' ... could not be converted to dict.. Expecting value: line 1 column 1 (char 0)` |
|
||||
| **根因** | “Inspect installed LiteLLM dependency versions” 探测脚本写成多行 Python,但在 YAML `>-` 折叠下所有换行被压成空格,`for package in packages: try: ... except:` 变成非法单行 → SyntaxError。`failed_when: false` 吞掉失败导致 stdout 为空,随后 `set_fact` 的 `from_json('')` 崩溃。`default('{}')` 不替换空字符串(仅替换 undefined) |
|
||||
| **修复方案** | 探测改为真正的单行程序(对 `importlib.metadata.distributions()` 用字典/列表推导,分号连接);决策 `set_fact` 改用 `default('{}', true)`,空/非法输出退化为“需要安装”而非中断 playbook。Commit `ce2070e` |
|
||||
|
||||
## TC-MAC-029: prisma generate 找不到 prisma-client-py 生成器
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/litellm/tasks/main.yml`(Generate Prisma Python Client) |
|
||||
| **触发报错** | `Error: Generator "prisma-client-py" failed: /bin/sh: prisma-client-py: command not found` |
|
||||
| **根因** | `prisma generate` 会以 `/bin/sh` 子进程调用 `prisma-client-py` 生成器,其 console script 装在 venv 的 bin 目录,但任务用绝对路径调 prisma 却未把 venv bin 放入 PATH,默认 command PATH 解析不到生成器 |
|
||||
| **修复方案** | 给该任务加 `environment.PATH`,前置 `{{ litellm_venv_dir }}/bin`(再加 Homebrew 前缀),使生成器子进程可解析。Commit `bbf5260` |
|
||||
|
||||
## TC-MAC-030: QMD LaunchAgent 引用未定义的 nodejs_version
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/qmd/templates/qmd.plist.j2` |
|
||||
| **触发报错** | `TASK [qmd : Deploy QMD LaunchAgent]` → `AnsibleUndefinedVariable: 'nodejs_version' is undefined` |
|
||||
| **根因** | plist 的 PATH 硬编码了 `~/.nvm/versions/node/{{ nodejs_version }}/bin`,但 Homebrew 部署下从未定义 `nodejs_version`(同 TC-MAC-005 反模式) |
|
||||
| **修复方案** | QMD 为 bun 二进制,且 Linux user unit 已用 `.bun/bin:.local/bin:...`;plist PATH 对齐为 `{{ qmd_home }}/.bun/bin:{{ qmd_home }}/.local/bin:/opt/homebrew/bin:...`,移除 nvm/nodejs_version 依赖。Commit `d903396` |
|
||||
|
||||
## TC-MAC-031: QMD better-sqlite3 原生模块 Node ABI 不匹配
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/qmd/tasks/main.yml`(npm install / npm run build / Validate QMD status) |
|
||||
| **触发报错** | `TASK [qmd : Validate QMD status]` → `Error: ... better_sqlite3.node was compiled against a different Node.js version using NODE_MODULE_VERSION 137. This version of Node.js requires NODE_MODULE_VERSION 115`(`ERR_DLOPEN_FAILED`) |
|
||||
| **根因** | better-sqlite3 用 node@24(ABI 137)编译,但 validate-status 任务未固定 PATH,用户 PATH 中 nvm 的 Node 20(ABI 115)排在 Homebrew 之前,runtime 与 build 的 Node ABI 不一致 |
|
||||
| **修复方案** | npm install / npm run build / validate-status 三个任务在 Darwin 下用 `{{ '/opt/homebrew/bin:/usr/local/bin:' if ansible_os_family == 'Darwin' else '' }}{{ ansible_env.PATH }}` 固定 node@24,使 build 与 runtime ABI 一致(与 plist 一致);Linux PATH 不变。Commit `6091b9d` |
|
||||
|
||||
## TC-MAC-032: XFCE/XRDP Linux 桌面栈在 macOS 跑 apt 失败
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `setup-xfce-xrdp.yaml` → `roles/vhosts/xfce_desktop_minimal_runtime` |
|
||||
| **触发报错** | `TASK [xfce_desktop_minimal_runtime : Update apt cache]` → `[Errno 2] No such file or directory: b'update'`(macOS 无 apt) |
|
||||
| **根因** | XFCE + XRDP 是 Linux 远程桌面栈(apt/systemd),在已有原生 GUI 的 macOS 上毫无意义,但 all-in-one 仍把该 play 跑到了 Darwin |
|
||||
| **修复方案** | `setup-xfce-xrdp.yaml` 的两个 `include_role` 均加 `when: ansible_os_family != 'Darwin'`,整栈在 macOS 跳过;Linux 不变。Commit `ef67c61` |
|
||||
|
||||
## TC-MAC-033: LiteLLM DATABASE_URL 未对密码做百分号编码致 Prisma P1013
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/litellm/defaults/main.yml`(`litellm_database_url`) |
|
||||
| **触发现象** | 部署“成功”(ansible `failed=0`)但服务摘要显示 `LiteLLM : inactive (not detected;http:000)`,launchd 退出码非 0、4000 端口不监听;`litellm.err.log` 反复 `Error: P1013: The provided database string is invalid. invalid port number in database URL` |
|
||||
| **根因** | 统一鉴权 token 由 `openssl rand -base64` 生成,可能含 `/`、`+`、`=`;直接拼入 `postgresql://litellm:<token>@host:port/db` 的 userinfo 时,`/` 截断 URL authority,导致端口解析失败,proxy 启动失败、4000 不监听。健康检查 `failed_when: false` 掩盖了它,ansible 仍报成功 |
|
||||
| **修复方案** | 仅对 DATABASE_URL 中的密码做百分号编码(新增 `litellm_database_password_urlencoded`,显式 replace 链,`%` 优先;Jinja `urlencode` 不转义 `/` 故不可用)。实际 DB 用户密码在 provision-database 与 `LITELLM_DB_PASSWORD` 仍保持原文,URL 形式解码后与原文一致(已验证 round-trip),鉴权不变。Commit `9926a46` |
|
||||
| **验证手段** | ansible `failed=0` ≠ 服务可用:需独立确认 `launchctl list`(Status 0)、`lsof -iTCP:4000 -sTCP:LISTEN`、`curl /health`(**401 即健康**,auth-gated) |
|
||||
|
||||
---
|
||||
|
||||
## 修复维度总结
|
||||
@ -188,8 +349,18 @@
|
||||
| 用户组适配 (staff vs ubuntu) | TC-003, TC-010 |
|
||||
| 目录路径降级 ($HOME vs /home/ubuntu, /opt, /etc) | TC-004, TC-006, TC-009, TC-010, TC-012, TC-013 |
|
||||
| 克隆后补丁注入 (post-clone patch) | TC-013, TC-014 |
|
||||
| Linux 基线整体跳过 (skip Linux baseline on Darwin) | TC-014 |
|
||||
| Linux 基线整体跳过 (skip Linux baseline on Darwin) | TC-014, TC-032 |
|
||||
| brew 补依赖 + PATH 注入 (jq via brew, Homebrew on PATH) | TC-015 |
|
||||
| 包管理器绕过 (skip apt on Darwin) | TC-008, TC-010 |
|
||||
| 模板变量解耦 (remove nvm/nodejs_version) | TC-005 |
|
||||
| 包管理器绕过 (skip apt on Darwin) | TC-008, TC-010, TC-032 |
|
||||
| 模板变量解耦 (remove nvm/nodejs_version) | TC-005, TC-030 |
|
||||
| 路径空格兼容 (argv vs string) | TC-011 |
|
||||
| Homebrew 模块绕过 (command brew + PATH) | TC-018, TC-019 |
|
||||
| venv/Node 子进程 PATH 注入 (resolve generator/native ABI) | TC-029, TC-031 |
|
||||
| Node ABI 一致性 (build == runtime node@24) | TC-031 |
|
||||
| macOS launchd 用户服务 | TC-021 |
|
||||
| handler 触发条件收敛 | TC-020 |
|
||||
| Python venv 隔离与 pip 缓存 | TC-023, TC-024 |
|
||||
| 单行模板/折叠语法健壮性 (`>-` folding, default(.,true)) | TC-028 |
|
||||
| 连接串密码百分号编码 (URL-encode secrets) | TC-033 |
|
||||
| 离线 runtime wheelhouse | TC-025 |
|
||||
| purge 可观测性 | TC-026 |
|
||||
|
||||
Loading…
Reference in New Issue
Block a user