Skip to content

feat(devcontainer): Add compose-based local devcontainer bootstrap#51

Merged
qzhhhi merged 2 commits intomainfrom
dev/agent-tool
May 3, 2026
Merged

feat(devcontainer): Add compose-based local devcontainer bootstrap#51
qzhhhi merged 2 commits intomainfrom
dev/agent-tool

Conversation

@qzhhhi
Copy link
Copy Markdown
Member

@qzhhhi qzhhhi commented May 3, 2026

  • Move the librmcs devcontainer setup to docker-compose and generate a local override for host-specific mounts, environment, and workspace path mapping.
  • Bootstrap shell history and host-matched CLI tools inside the container, and precreate mount targets so local development stays reproducible without committing machine-specific state.

概述

将 librmcs 的 devcontainer 配置从单容器 image 迁移到基于 Docker Compose 的流程,新增主机特定的本地 override 生成、主机工具探测与容器内自举、共享 Zsh 历史,以及预创建挂载目标;旨在提升本地开发的可重现性并将主机特定配置留在本地生成目录中。

核心变更

Docker Compose 与 devcontainer 配置

  • .devcontainer/docker-compose.yml:新增服务 librmcs-develop,使用镜像 qzhhhi/librmcs-develop:latest,设置 network_mode: host、设备 cgroup 规则 c 189:* rwinit: true,并挂载 /dev 及仓库根目录到容器(工作目录 /home/ubuntu),命令保持容器驻留。
  • .devcontainer/devcontainer.json:切换为 dockerComposeFile 配置,引用 docker-compose.yml 与生成的 .generated/docker-compose.local.override.yml;新增 initializeCommand(生成本地 override 并探测主机工具)和 postCreateCommand(设置 shell 历史并在容器内自举工具);保留 VS Code 自定义扩展列表与部分设置。

本地 override 生成

  • .devcontainer/scripts/generate-local-override.sh:生成 .devcontainer/.generated/docker-compose.local.override.yml,功能包括:
    • 将仓库根路径写入环境变量 HOST_WORKSPACE_FOLDER
    • 根据主机环境条件添加 DISPLAY/X11 支持、Wayland 支持(检测 socket 有效性);
    • 传递代理变量(大小写同时支持);
    • 为存在的主机配置目录添加绑定挂载(如 /.codex、/.claude、/.config/opencode、/.local/share/... 等),并支持只读挂载(例如 ~/.agents/skills);
    • 对 YAML 双引号内容进行转义,保证输出合法且提示不应提交该生成文件。

主机工具探测与容器内自举

  • .devcontainer/scripts/probe-host-tools.sh:在宿主机或本地环境中探测 codexclaudeopencodelark-cli 的可用性与版本,生成 .devcontainer/.generated/host-tools.manifest(记录 generated_at 与各工具状态:版本 / absent / unparseable)。
  • .devcontainer/scripts/bootstrap-tools.sh:在容器内读取上述 manifest,若存在 npm 则按 manifest 中记录的版本尝试通过 sudo npm install -g 安装对应包(映射:codex -> @openai/codex, claude -> @anthropic-ai/claude-code, opencode -> opencode-ai, lark-cli -> @larksuite/cli);输出已安装与跳过的汇总,遇到 manifest 不存在、工具缺失或版本不可解析时跳过并记录原因;若容器内无 npm,则优雅退出。

Shell 历史与挂载目标预创建

  • .devcontainer/scripts/setup-shell-history.sh:在仓库内创建共享历史文件 .devcontainer/.zsh_history,并将容器用户 ~/.zsh_history 链接到该文件(保证历史共享、避免提交本机历史)。
  • Dockerfile(develop 阶段):在镜像中预创建 XDG 风格的父目录(/home/ubuntu/.agents、.cache、.config、.local/share、.local/state),并将它们 chown 给 ubuntu 用户,移除了在镜像内创建指向仓库 .zsh_history 的原始符号链接步骤(历史文件由 setup-shell-history.sh 在运行时处理)。

版本控制与忽略规则

  • .devcontainer/.gitignore:新增忽略规则 .zsh_history.generated/(本地生成产物与历史不纳入版本库)。
  • 顶级 .gitignore:新增忽略 build/compile_commands.json;此前对 .devcontainer/.zsh_history 的忽略已调整以配合新的 devcontainer 忽略策略。

设计要点与价值

  • 将 host-specific 配置留在本地生成的 override 文件中,避免将机器特定的挂载和凭据提交到仓库;
  • 主机工具探测 + 容器内按需自举能在一定程度上保持容器工具与宿主一致,减少手动同步成本;
  • 预创建挂载目标与共享历史文件保证容器初始化幂等、可复现,且将主机状态与仓库配置解耦。

- Move the librmcs devcontainer setup to docker-compose and generate a local override for host-specific mounts, environment, and workspace path mapping.
- Bootstrap shell history and host-matched CLI tools inside the container, and precreate mount targets so local development stays reproducible without committing machine-specific state.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

Walkthrough

将 VS Code devcontainer 从单镜像配置迁移到 Docker Compose;新增主机探测、生成本地 override、引导容器工具和 Shell 历史同步脚本;在镜像中预建 XDG 目录并调整 .gitignore 与容器级忽略文件。

Changes

Devcontainer 与初始化基础设施整合

Layer / File(s) Summary
配置迁移
.devcontainer/devcontainer.json, .devcontainer/docker-compose.yml
将 devcontainer 配置由基于 image 的单容器切换为使用 dockerComposeFile 的 Compose 方案;新增 librmcs-develop 服务与 workspaceFolder
本地覆盖生成(数据/配置产物)
.devcontainer/scripts/generate-local-override.sh, .devcontainer/.generated/*
生成 docker-compose.local.override.yml 内容:基于主机环境条件(DISPLAY、Wayland、代理、存在的主目录路径)填充 environmentvolumes 条目并写入 .generated
主机工具探测(探测 → 产物)
.devcontainer/scripts/probe-host-tools.sh, .devcontainer/.generated/host-tools.manifest
探测主机可用工具(codexclaudeopencodelark-cli)及其版本,将结果写入 .devcontainer/.generated/host-tools.manifestgenerated_at 与每工具条目)。
容器端引导实现
.devcontainer/scripts/bootstrap-tools.sh
在容器内读取 host-tools.manifest,验证 npm 并按清单尝试 sudo npm install -g <pkg>@<version>,记录已安装与跳过项,最终打印摘要。
Shell 历史同步
.devcontainer/scripts/setup-shell-history.sh, .devcontainer/.zsh_history
在仓库中创建共享 zsh 历史文件并将用户 ~/.zsh_history 替换为指向该文件的符号链接(脚本实现和确认输出)。
Compose 与 devcontainer 初始化编排
.devcontainer/devcontainer.json
新增 initializeCommand 调用本地 override 生成与主机探测,更新 postCreateCommand 为运行 setup-shell-history.shbootstrap-tools.sh
Docker Compose 服务定义 / 挂载
.devcontainer/docker-compose.yml
定义 librmcs-develop 服务:使用 qzhhhi/librmcs-develop:latest 镜像、network_mode: host、设备 cgroup 权限、长驻命令并挂载 /dev 与项目工作区到容器。
镜像文件系统准备
Dockerfile
develop 阶段预创建 XDG 风格目录(.agents.cache.config.local/share.local/state)并 chown 给 ubuntu,移除之前在镜像中创建 zsh history 符号链接的步骤。
忽略规则更新
.gitignore, .devcontainer/.gitignore
项目级 .gitignore 添加 build/compile_commands.json,移除对 .devcontainer/.zsh_history 的忽略;容器级 .devcontainer/.gitignore 新增,忽略 .zsh_history.generated/

序列图

sequenceDiagram
    participant Host as Host (主机)
    participant Init as InitScripts\n(probe & generate)
    participant Compose as Docker Compose
    participant Container as Dev Container
    participant Bootstrap as Bootstrap\n(bootstrap-tools & setup-shell-history)

    Host->>Init: 启动 devcontainer 初始化
    Init->>Host: 读取环境变量与探测可用工具
    Init-->>Init: 写入 .devcontainer/.generated/host-tools.manifest\n并生成 docker-compose.local.override.yml
    Init->>Compose: 覆盖文件就位并启动 Compose
    Compose->>Container: 启动容器(带挂载与环境)
    Container->>Bootstrap: 运行 postCreateCommand
    Bootstrap->>Container: 读取 manifest 并通过 npm 安装工具
    Bootstrap->>Container: 创建/链接共享 zsh 历史
    Container-->>Host: 容器准备就绪,开发环境可用
Loading

评估代码审查工作量

🎯 3 (中等) | ⏱️ ~25 分钟

可能相关的PR

🐰 开发箱里起新春,
Compose 携卷来相亲;
探测工具写成表,
本地覆盖按需拼;
历史共享连一统,
环境起步兔子欢!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清楚、具体地总结了主要变更:从单容器设置迁移到基于Docker Compose的开发容器引导系统。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/agent-tool

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.devcontainer/docker-compose.yml (1)

3-3: ⚡ Quick win

建议固定镜像版本标签以保证可复现性

使用 latest 标签意味着不同时间构建的开发容器可能基于不同镜像,导致环境不一致。建议固定到具体的版本标签或镜像摘要(digest)。

♻️ 建议修改
-    image: qzhhhi/librmcs-develop:latest
+    image: qzhhhi/librmcs-develop:<specific-tag>  # e.g., v1.2.3 or sha256:...
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/docker-compose.yml at line 3, 当前 docker-compose 中使用了不固定的镜像标签
"image: qzhhhi/librmcs-develop:latest",请将其替换为具体的版本标签或镜像摘要(digest),例如使用
"qzhhhi/librmcs-develop:vX.Y.Z" 或
"qzhhhi/librmcs-develop@sha256:...",以保证开发容器可复现;更新位于文件中声明该镜像的那一行(即包含 "image:
qzhhhi/librmcs-develop:latest" 的条目),并在提交说明中注明所选版本号或 digest 来源。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.devcontainer/docker-compose.yml:
- Around line 14-16: Remove the unconditional bind mount of /tmp/.X11-unix from
docker-compose.yml and instead add the mount only when DISPLAY is set inside
generate-local-override.sh so the X11 socket is created/forwarded conditionally;
specifically, delete the bind mount block (type: bind, source: /tmp/.X11-unix,
target: /tmp/.X11-unix) from the compose file and update the script that sets
DISPLAY (generate-local-override.sh) to append an override or runtime mount for
/tmp/.X11-unix when $DISPLAY is non-empty, keeping the mount logic consistent
with the existing conditional export of DISPLAY.

---

Nitpick comments:
In @.devcontainer/docker-compose.yml:
- Line 3: 当前 docker-compose 中使用了不固定的镜像标签 "image:
qzhhhi/librmcs-develop:latest",请将其替换为具体的版本标签或镜像摘要(digest),例如使用
"qzhhhi/librmcs-develop:vX.Y.Z" 或
"qzhhhi/librmcs-develop@sha256:...",以保证开发容器可复现;更新位于文件中声明该镜像的那一行(即包含 "image:
qzhhhi/librmcs-develop:latest" 的条目),并在提交说明中注明所选版本号或 digest 来源。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 596b5da4-7011-418d-871a-8d835556eb9e

📥 Commits

Reviewing files that changed from the base of the PR and between 36b0802 and 64ac1d3.

📒 Files selected for processing (9)
  • .devcontainer/.gitignore
  • .devcontainer/devcontainer.json
  • .devcontainer/docker-compose.yml
  • .devcontainer/scripts/bootstrap-tools.sh
  • .devcontainer/scripts/generate-local-override.sh
  • .devcontainer/scripts/probe-host-tools.sh
  • .devcontainer/scripts/setup-shell-history.sh
  • .gitignore
  • Dockerfile
💤 Files with no reviewable changes (1)
  • .gitignore

Comment thread .devcontainer/docker-compose.yml Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.devcontainer/scripts/generate-local-override.sh (1)

20-30: 💤 Low value

add_env 的 if/else 分支逻辑冗余

两个分支的结果完全相同:当 environment_entries 为空时,"${environment_entries}content""content" 等价,因此整个 if/else 可以简化为一行赋值。

♻️ 建议简化
 add_env() {
     env_name=$1
     env_value=$2
     escaped_env_value=$(escape_yaml_double_quoted "$env_value")
-
-    if [ -n "$environment_entries" ]; then
-        environment_entries="${environment_entries}      ${env_name}: \"${escaped_env_value}\"\n"
-    else
-        environment_entries="      ${env_name}: \"${escaped_env_value}\"\n"
-    fi
+    environment_entries="${environment_entries}      ${env_name}: \"${escaped_env_value}\"\n"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/scripts/generate-local-override.sh around lines 20 - 30, The
add_env function contains redundant if/else branches that produce identical
output; simplify by removing the conditional and always append the new entry to
environment_entries in one assignment, e.g. update the body of add_env (which
references env_name, env_value, escaped_env_value, and
escape_yaml_double_quoted) so it computes escaped_env_value and then does a
single line: environment_entries="${environment_entries}      ${env_name}:
\"${escaped_env_value}\"\n".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.devcontainer/scripts/generate-local-override.sh:
- Around line 20-30: The add_env function contains redundant if/else branches
that produce identical output; simplify by removing the conditional and always
append the new entry to environment_entries in one assignment, e.g. update the
body of add_env (which references env_name, env_value, escaped_env_value, and
escape_yaml_double_quoted) so it computes escaped_env_value and then does a
single line: environment_entries="${environment_entries}      ${env_name}:
\"${escaped_env_value}\"\n".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f11a394-d3bb-444b-9a5a-6c31565151db

📥 Commits

Reviewing files that changed from the base of the PR and between 64ac1d3 and 5fca8c3.

📒 Files selected for processing (2)
  • .devcontainer/docker-compose.yml
  • .devcontainer/scripts/generate-local-override.sh
✅ Files skipped from review due to trivial changes (1)
  • .devcontainer/docker-compose.yml

@qzhhhi qzhhhi merged commit ad5ecd5 into main May 3, 2026
5 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in RMCS Slave SDK May 3, 2026
@qzhhhi qzhhhi deleted the dev/agent-tool branch May 3, 2026 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant