diff --git a/.github/workflows/fresh-install.yml b/.github/workflows/fresh-install.yml
index 063db29..ad66aec 100644
--- a/.github/workflows/fresh-install.yml
+++ b/.github/workflows/fresh-install.yml
@@ -76,13 +76,13 @@ jobs:
if: matrix.mask_msvc
shell: powershell
run: ./scripts/ci/mask-msvc.ps1
- - name: README preparation (Unix)
+ - name: Follow the README install and practice commands (Unix)
if: runner.os != 'Windows' && matrix.route == 'readme'
- run: bash scripts/setup.sh
- - name: README preparation (PowerShell 5.1)
+ run: python3 scripts/ci/readme.py
+ - name: Follow the README install and practice commands (PowerShell 5.1)
if: runner.os == 'Windows' && matrix.route == 'readme'
shell: powershell
- run: ./scripts/setup.ps1
+ run: python scripts/ci/readme.py
- name: Cold install only (Unix)
if: runner.os != 'Windows' && matrix.route == 'cold'
run: bash scripts/setup.sh --install-only
@@ -90,30 +90,27 @@ jobs:
if: runner.os == 'Windows' && matrix.route == 'cold'
shell: powershell
run: ./scripts/setup.ps1 -InstallOnly
- - name: README environment verification
- if: matrix.route == 'readme'
- run: python scripts/ci/solutions.py
- name: First check, save, advance and resume
+ if: matrix.route == 'cold'
shell: bash
- env:
- ROUTE: ${{ matrix.route }}
- run: |
- args=()
- if [[ "$ROUTE" == cold ]]; then args+=(--cold); fi
- python scripts/ci/first-run.py --allow-source-edit "${args[@]}"
+ run: python scripts/ci/first-run.py --allow-source-edit --cold
- name: Cold route also verifies all reference answers
if: matrix.route == 'cold'
run: python scripts/ci/solutions.py
- name: Assert GNU target without MSVC
if: matrix.mask_msvc
shell: bash
+ env:
+ ROUTE: ${{ matrix.route }}
run: |
+ logs="$(pwd)/.d2x/ci-logs"
+ if [[ "$ROUTE" == readme ]]; then cd .d2x/ci-work/download/d2mcpp; fi
# doctor returns nonzero for warnings too (missing MSVC is expected).
- mcpp self doctor > .d2x/ci-logs/doctor.txt 2>&1 || true
- cat .d2x/ci-logs/doctor.txt
- grep -q 'gcc.*what a build here uses' .d2x/ci-logs/doctor.txt
- grep -q 'payload mingw-gcc' .d2x/ci-logs/doctor.txt
- grep -q 'x86_64.*windows-gnu' .d2x/ci-logs/doctor.txt
+ mcpp self doctor > "$logs/doctor.txt" 2>&1 || true
+ cat "$logs/doctor.txt"
+ grep -q 'gcc.*what a build here uses' "$logs/doctor.txt"
+ grep -q 'payload mingw-gcc' "$logs/doctor.txt"
+ grep -q 'x86_64.*windows-gnu' "$logs/doctor.txt"
ls -d target/*windows-gnu
- uses: actions/upload-artifact@v4
if: always()
@@ -165,9 +162,7 @@ jobs:
runuser -u learner -- env MCPP_HOME=/home/learner/.mcpp PATH="/home/learner/.xlings/subos/current/bin:$PATH" python3 scripts/ci/first-run.py --allow-source-edit --cold
runuser -u learner -- env PATH="/home/learner/.xlings/subos/current/bin:$PATH" python3 scripts/ci/solutions.py
else
- runuser -u learner -- bash scripts/setup.sh
- runuser -u learner -- env PATH="/home/learner/.xlings/subos/current/bin:$PATH" python3 scripts/ci/solutions.py
- runuser -u learner -- env PATH="/home/learner/.xlings/subos/current/bin:$PATH" python3 scripts/ci/first-run.py --allow-source-edit
+ runuser -u learner -- python3 scripts/ci/readme.py
fi
- uses: actions/upload-artifact@v4
if: always()
@@ -184,23 +179,12 @@ jobs:
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- - name: Install xlings baseline
- run: bash scripts/install-xlings.sh
- - name: Follow the actual d2x download route
- run: |
- mkdir -p "$RUNNER_TEMP/course-download"
- cd "$RUNNER_TEMP/course-download"
- xlings install d2x@2026.08.02.2 -y
- d2x install d2mcpp
- cd d2mcpp
- python3 -c 'import json; assert json.load(open(".xlings.json"))["workspace"]["mcpp"] == "2026.10.17.1", "Published course snapshot is stale"'
- bash scripts/setup.sh
- python3 scripts/ci/solutions.py
- python3 scripts/ci/first-run.py --allow-source-edit
+ - name: Follow the README using the public course download
+ run: python3 scripts/ci/readme.py --published
- uses: actions/upload-artifact@v4
if: always()
with:
name: published-course-first-use
- path: ${{ runner.temp }}/course-download/d2mcpp/.d2x/ci-logs/
+ path: .d2x/ci-logs/
if-no-files-found: ignore
include-hidden-files: true
diff --git a/.gitignore b/.gitignore
index f7ef208..c0c6d4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,6 +50,7 @@ media
.d2x/result.ndjson
.d2x/environment-ready
.d2x/ci-logs/
+.d2x/ci-work/
.d2x/checker.lock
.d2x/last-output.log
diff --git a/README.md b/README.md
index c83b651..48f348f 100644
--- a/README.md
+++ b/README.md
@@ -39,77 +39,35 @@
[](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=mcpp-community/d2mcpp)
-Wait for environment preparation to finish (the first launch downloads a toolchain and verifies the reference answers). Then open a terminal and run `d2x checker`, or choose **Tasks: Run Task → d2mcpp: practice**. Reconnecting does not start another checker. If preparation fails, see [environment troubleshooting](docs/environment.md).
+Wait for the environment to be ready, then run `d2x checker` in the terminal.
### Practice locally
-Supported release targets: Linux x86_64, macOS 14+ Apple Silicon, and Windows x86_64 with Windows PowerShell 5.1+. mcpp manages the C++ toolchain; Visual Studio is optional. Linux ARM64 is not yet covered by this course's d2x release. Use your preferred editor; it is not installed as a course dependency.
+**1. Install the tools**
-**1. Get the course** (fork first if you want to save progress with git):
+Install [xlings](docs/environment.md#install-xlings), reopen your terminal, then run:
```bash
-git clone https://github.com/mcpp-community/d2mcpp.git
-cd d2mcpp
+xlings install d2x mcpp -y
```
-**2. Prepare the environment.** These scripts install xlings **2026.10.18.1**, the versions in `.xlings.json` (mcpp **2026.10.17.1**, d2x **2026.08.02.2**, mdBook **0.4.43**), and build and check the Provider. The first build may take several minutes.
-
-Linux / macOS:
+**2. Get the course**
```bash
-bash scripts/setup.sh
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Windows PowerShell:
-
-```powershell
-powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-The PATH command makes the installed tools available in this terminal. For future sessions, reopen your terminal after installation. Preparation can be repeated and preserves your exercise files and progress.
-
-
-Alternative: download with d2x install
-
-Install [xlings](https://github.com/openxlings/xlings) first:
-
-```bash
-curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/v2026.10.18.1/tools/other/quick_install.sh | bash -s v2026.10.18.1
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Or on Windows PowerShell:
-
-```powershell
-irm https://raw.githubusercontent.com/mcpp-community/d2mcpp/main/scripts/install-xlings.ps1 | iex
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-Then, on either system:
-
-```text
-xlings install d2x@2026.08.02.2 -y
d2x install d2mcpp
cd d2mcpp
```
-Continue with the preparation script for your system in step 2; both download routes use the same verification below.
-
-
-
-**3. Verify, then practice:**
+**3. Verify and practice**
```bash
-mcpp test -p solutions # all reference answers must pass (currently 52)
+mcpp test -p solutions # all reference answers should pass
d2x checker # edit -> save -> auto-check -> advance
-d2x status # progress overview
```
-The unfinished exercises are expected to fail; the reference answers must pass. `Provider` errors and linker paths containing `/nonexistent/` indicate an environment problem: see [diagnosis and recovery](docs/environment.md). After `git pull`, rerun the preparation script to apply any changed pins.
+The first run may take a few minutes. Errors in unfinished exercises are expected.
-For native practice, `mcpp test -p src/cpp11` runs one section. See the [English usage guide](https://mcpp-community.github.io/d2mcpp/en/base/chapter_1.html).
+[Setup and troubleshooting](docs/environment.md) · [Usage guide](https://mcpp-community.github.io/d2mcpp/en/base/chapter_1.html)
## Community
diff --git a/README.zh.hant.md b/README.zh.hant.md
index c722ac9..1d4ba1f 100644
--- a/README.zh.hant.md
+++ b/README.zh.hant.md
@@ -39,77 +39,35 @@
[](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=mcpp-community/d2mcpp)
-等待環境準備完成(首次啟動會下載工具鏈並驗證參考答案),然後在終端執行 `d2x checker`,或使用 **Tasks: Run Task → d2mcpp: practice**。重新連線不會重複啟動 checker。準備失敗時查看[環境疑難排解](docs/environment.md)。
+等待環境準備完成,然後在終端執行 `d2x checker`。
### 建立本地練習環境
-支援的發行平台:Linux x86_64、macOS 14+ Apple Silicon、Windows x86_64(Windows PowerShell 5.1+)。mcpp 管理 C++ 工具鏈,Visual Studio 為選用項目。目前課程使用的 d2x Release 尚未涵蓋 Linux ARM64。可自行選擇編輯器,課程不會強制安裝。
+**第一步:安裝工具**
-**第一步:取得課程**(建議先 fork,用 git 儲存自己的練習進度):
+安裝 [xlings](docs/environment.zh.md#install-xlings),重新開啟終端後執行:
```bash
-git clone https://github.com/mcpp-community/d2mcpp.git
-cd d2mcpp
+xlings install d2x mcpp -y
```
-**第二步:準備環境。** 指令碼安裝 xlings **2026.10.18.1** 及 `.xlings.json` 宣告的版本(mcpp **2026.10.17.1**、d2x **2026.08.02.2**、mdBook **0.4.43**),建置並檢查 Provider。首次建置可能需要幾分鐘。
-
-Linux / macOS:
+**第二步:取得課程**
```bash
-bash scripts/setup.sh
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Windows PowerShell:
-
-```powershell
-powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-PATH 指令讓目前終端立即找到工具;安裝後重新開啟終端即可供後續工作階段使用。準備指令碼可重複執行,不會更動練習檔案或學習進度。
-
-
-選用:透過 d2x install 下載課程
-
-先安裝 [xlings](https://github.com/openxlings/xlings):
-
-```bash
-curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/v2026.10.18.1/tools/other/quick_install.sh | bash -s v2026.10.18.1
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Windows PowerShell 使用:
-
-```powershell
-irm https://raw.githubusercontent.com/mcpp-community/d2mcpp/main/scripts/install-xlings.ps1 | iex
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-然後在任一系統執行:
-
-```text
-xlings install d2x@2026.08.02.2 -y
d2x install d2mcpp
cd d2mcpp
```
-繼續執行第二步中對應系統的準備指令碼;兩種下載方式共用下方驗證步驟。
-
-
-
-**第三步:驗證環境並開始練習:**
+**第三步:驗證並開始練習**
```bash
-mcpp test -p solutions # 參考答案應全部通過(目前 52 份)
+mcpp test -p solutions # 參考答案應全部通過
d2x checker # 編輯 -> 儲存 -> 自動偵測 -> 推進
-d2x status # 進度總覽
```
-未完成的練習報錯是預期行為,參考答案必須全綠。`Provider` 錯誤或連結路徑含 `/nonexistent/` 屬於環境問題,請查看[診斷與恢復步驟](docs/environment.md)。`git pull` 後重新執行準備指令碼,讓更新後的版本設定生效。
+首次執行可能需要幾分鐘。未完成的練習報錯屬於正常現象。
-也可使用 `mcpp test -p src/cpp11` 直接練習某一章。更多操作見[使用說明](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)。
+[環境準備與疑難排解](docs/environment.zh.md) · [使用說明](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)
## 社區
diff --git a/README.zh.md b/README.zh.md
index a3c8981..2fb35cb 100644
--- a/README.zh.md
+++ b/README.zh.md
@@ -39,77 +39,35 @@
[](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=mcpp-community/d2mcpp)
-等待环境准备完成(首次启动会下载工具链并验证参考答案),然后在终端运行 `d2x checker`,或使用 **Tasks: Run Task → d2mcpp: practice**。重连不会重复启动 checker。准备失败时查看[环境排错说明](docs/environment.md)。
+等待环境准备完成,然后在终端运行 `d2x checker`。
### 搭建本地练习环境
-支持的发布平台:Linux x86_64、macOS 14+ Apple Silicon、Windows x86_64(Windows PowerShell 5.1+)。mcpp 管理 C++ 工具链,Visual Studio 为可选项。当前课程所用 d2x Release 尚未覆盖 Linux ARM64。编辑器可自行选择,课程不会强制安装。
+**第一步:安装工具**
-**第一步:获取课程**(建议先 fork,用 git 保存自己的练习进度):
+安装 [xlings](docs/environment.zh.md#install-xlings),重新打开终端后执行:
```bash
-git clone https://github.com/mcpp-community/d2mcpp.git
-cd d2mcpp
+xlings install d2x mcpp -y
```
-**第二步:准备环境。** 脚本安装 xlings **2026.10.18.1** 及 `.xlings.json` 声明的版本(mcpp **2026.10.17.1**、d2x **2026.08.02.2**、mdBook **0.4.43**),构建并检查 Provider。首次构建可能需要几分钟。
-
-Linux / macOS:
+**第二步:获取课程**
```bash
-bash scripts/setup.sh
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Windows PowerShell:
-
-```powershell
-powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-PATH 命令让当前终端立即找到工具;安装后重新打开终端即可供后续会话使用。准备脚本可重复执行,不会改动练习文件或学习进度。
-
-
-可选:通过 d2x install 下载课程
-
-先安装 [xlings](https://github.com/openxlings/xlings):
-
-```bash
-curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/v2026.10.18.1/tools/other/quick_install.sh | bash -s v2026.10.18.1
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-```
-
-Windows PowerShell 使用:
-
-```powershell
-irm https://raw.githubusercontent.com/mcpp-community/d2mcpp/main/scripts/install-xlings.ps1 | iex
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-```
-
-然后在任一系统执行:
-
-```text
-xlings install d2x@2026.08.02.2 -y
d2x install d2mcpp
cd d2mcpp
```
-继续执行第二步中对应系统的准备脚本;两种下载方式共用下面的验证步骤。
-
-
-
-**第三步:验证环境并开始练习:**
+**第三步:验证并开始练习**
```bash
-mcpp test -p solutions # 参考答案应全部通过(当前 52 份)
+mcpp test -p solutions # 参考答案应全部通过
d2x checker # 编辑 -> 保存 -> 自动检测 -> 推进
-d2x status # 进度总览
```
-未完成的练习报错是预期行为,参考答案必须全绿。`Provider` 错误或链接路径含 `/nonexistent/` 属于环境问题,请查看[诊断与恢复步骤](docs/environment.md)。`git pull` 后重新运行准备脚本,让更新后的版本配置生效。
+首次运行可能需要几分钟。未完成的练习报错属于正常现象。
-也可使用 `mcpp test -p src/cpp11` 直接练习某一章。更多操作见[使用说明](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)。
+[环境准备与排错](docs/environment.zh.md) · [使用说明](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)
## 社区
diff --git a/book/src/base/chapter_1.md b/book/src/base/chapter_1.md
index 12e4837..e130e71 100644
--- a/book/src/base/chapter_1.md
+++ b/book/src/base/chapter_1.md
@@ -76,7 +76,7 @@ d2x checker # 编辑 -> 保存 -> 自动检测 -> 推进
d2x status # 进度总览
```
-未完成的练习报错是预期行为,参考答案必须全绿。`Provider` 错误或链接路径含 `/nonexistent/` 属于环境问题,请查看[诊断与恢复步骤](https://github.com/mcpp-community/d2mcpp/blob/main/docs/environment.md)。`git pull` 后重新运行准备脚本,让更新后的版本配置生效。
+未完成的练习报错是预期行为,参考答案必须全绿。`Provider` 错误或链接路径含 `/nonexistent/` 属于环境问题,请查看[诊断与恢复步骤](https://github.com/mcpp-community/d2mcpp/blob/main/docs/environment.zh.md)。`git pull` 后重新运行准备脚本,让更新后的版本配置生效。
也可使用 `mcpp test -p src/cpp11` 直接练习某一章。更多操作见[使用说明](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)。
diff --git a/book/src/changelog.md b/book/src/changelog.md
index 0d5c9f1..7f8e273 100644
--- a/book/src/changelog.md
+++ b/book/src/changelog.md
@@ -15,7 +15,7 @@
统一使用 mcpp 2026.10.17.1,增加跨平台准备脚本、全新安装与旧环境恢复验证,更新 Codespaces 入口。
- `Book`: [zh](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html) / [en](https://mcpp-community.github.io/d2mcpp/en/base/chapter_1.html) - 2026/10/19
-- `Code`: [setup](https://github.com/mcpp-community/d2mcpp/tree/main/scripts) / [environment recovery](https://github.com/mcpp-community/d2mcpp/blob/main/docs/environment.md) - 2026/10/19
+- `Code`: [setup](https://github.com/mcpp-community/d2mcpp/tree/main/scripts) / [environment recovery](https://github.com/mcpp-community/d2mcpp/blob/main/docs/environment.zh.md) - 2026/10/19
## 2025/11
diff --git a/docs/environment.md b/docs/environment.md
index e9b6850..c4dd1ca 100644
--- a/docs/environment.md
+++ b/docs/environment.md
@@ -1,132 +1,92 @@
-# 环境准备与排错 / Environment setup and recovery
+# Environment setup and troubleshooting
-课程版本以根目录 [`.xlings.json`](../.xlings.json) 为准:mcpp `2026.10.17.1`、d2x `2026.08.02.2`、mdBook `0.4.43`。安装器基线由 [`scripts/tool-versions.env`](../scripts/tool-versions.env) 管理。支持 Linux x86_64、macOS 14+ ARM64、Windows x86_64 / PowerShell 5.1+;当前 d2x Release 没有 Linux ARM64 资源。
+[中文](environment.zh.md) · [Quick start](../README.md)
-The course pins its tools in `.xlings.json`. The scripts support Linux x86_64, macOS 14+ Apple Silicon, and Windows x86_64 with Windows PowerShell 5.1+. Your preferred editor and Visual Studio are optional. The d2x release used by this course does not yet ship Linux ARM64 binaries.
+Supports Linux x86_64, macOS 14+ Apple Silicon, and Windows x86_64 / PowerShell 5.1+. Tool versions are managed in [`.xlings.json`](../.xlings.json).
-## 准备环境 / Prepare the environment
+
-在课程根目录执行对应系统的命令。脚本会安装固定版本、显示首次 Provider 构建过程,并验证 Provider 可以描述自身和枚举练习。失败时立即停止;不要忽略错误继续启动 checker。
-
-Run from the course root. Preparation installs the pinned tools, visibly builds the Provider, and checks its description and exercise discovery. The first build also downloads mcpp's private C++ toolchain and builds the standard library module; installing the mcpp executable alone does not complete this preparation.
+## Install xlings
Linux / macOS:
```bash
-bash scripts/setup.sh
+curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/v2026.10.18.1/tools/other/quick_install.sh | bash -s v2026.10.18.1
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-mcpp test -p solutions
-d2x checker
```
Windows PowerShell:
```powershell
-powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
+irm https://raw.githubusercontent.com/mcpp-community/d2mcpp/main/scripts/install-xlings.ps1 | iex
$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-mcpp test -p solutions
-d2x checker
```
-准备脚本可以重复执行,不覆盖练习或清理 `.d2x/state.json`。`git pull` 更新配置后,需要重新运行它。参考答案必须全部通过(当前 52 份);未完成的练习编译或运行失败则属于正常练习过程。
+Continue with the README. If a command is not found, reopen your terminal or apply the PATH command above.
-Preparation is repeatable and preserves exercises and `.d2x/state.json`. Repeat it after `git pull` to apply updated pins. Reference answers must all pass (currently 52). Unfinished exercises are expected to fail.
+## Git installation and updates
-## Codespaces / Dev Container
+After installing xlings, you can also clone the course. Replace the URL with your fork if needed:
-等待创建阶段完成依赖安装、Provider 构建和参考答案测试。只有全部成功才显示 ready。进入 VS Code 后在可见终端执行 `d2x checker`,或选择 **Tasks: Run Task → d2mcpp: practice**。这个任务限制一个实例;重连不会自动启动另一个 checker,也不会重复下载和跑全部参考答案。
+```bash
+git clone https://github.com/mcpp-community/d2mcpp.git
+cd d2mcpp
+```
-Wait for creation to finish installing tools, building the Provider and testing reference answers. Then run `d2x checker` in a terminal, or use **Tasks: Run Task → d2mcpp: practice**. The task permits one instance. Reconnection only checks readiness; it does not start a background TUI or repeat the full setup.
+
-容器配置包含 SSH Feature,也支持通过 `gh codespace ssh` 连接和 `gh codespace logs` 获取创建日志。已有 Codespace 更新这项配置后需要重建容器才能生效。
+Prepare from the course root; run `git pull` first when updating. These scripts preserve your exercise code and progress.
-The container includes the SSH Feature for `gh codespace ssh` and creation logs via `gh codespace logs`. Rebuild an existing Codespace to apply this configuration change. See [GitHub's CLI connection instructions](https://docs.github.com/en/codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli).
+```bash
+# Linux / macOS
+bash scripts/setup.sh
+```
-如果更新配置后提示环境尚未准备好,执行:
+```powershell
+# Windows PowerShell
+powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
+```
-If the configuration changed or creation failed, rerun inside the container:
+Then verify and practice:
```bash
-bash .devcontainer/postCreate.sh
+mcpp test -p solutions
+d2x checker
```
-打开创建日志查看失败阶段。`postAttachCommand` 的输出是就绪提示,不是练习终端。普通本地安装使用 `scripts/setup.sh` / `scripts/setup.ps1`,不要执行容器专用的 apt/sudo 初始化脚本。
+## Codespaces
-Use the creation log to find the failing phase. The attach log is a readiness message, not the interactive practice terminal. Outside the container, use the local preparation scripts instead of the container's apt/sudo setup.
+Wait until ready, then run `d2x checker` in a terminal. If creation fails, check the creation log. To retry inside the container:
-## Provider 无响应 / Provider did not respond
+```bash
+bash .devcontainer/postCreate.sh
+```
-这个消息表示 d2x 没有收到 Provider 的描述事件,既可能是找不到命令,也可能是下载、构建、链接或协议错误。先直接执行下列命令,把底层 stderr 保留下来:
+## Provider did not respond
-The message means d2x received no valid Provider description. Run the underlying command directly to expose a missing command, download/build/link failure, or protocol error:
+Run from the course root to expose the error, then retry [preparation](#prepare):
-```text
+```bash
xlings --version
mcpp --version
d2x --version
mcpp run -p d2x/buildtools -- describe
```
-Linux/macOS 用 `command -v xlings mcpp d2x`,PowerShell 用 `Get-Command xlings,mcpp,d2x` 检查实际路径。进入课程目录后应使用项目固定版本;在目录外安装新版不一定会改变项目版本。若找不到工具,先更新当前终端 PATH(见上面的命令),或重新打开终端。
-
-Check executable paths with `command -v xlings mcpp d2x` on Unix or `Get-Command xlings,mcpp,d2x` in PowerShell. The project pin takes precedence inside the course. Update this terminal's PATH as shown above or reopen the terminal after installation.
-
-新 mcpp 支持以下诊断;先把版本更新成功再使用,旧版不一定提供同一命令:
-
-After upgrading mcpp, collect its read-only diagnosis and toolchain inventory:
-
-```text
-mcpp self doctor
-mcpp toolchain list --format json
-```
-
-提交问题时附系统/架构、工具版本与路径、失败的命令及原始错误即可。不要附完整 `.d2x.json`,它可能包含 API key。
-
-When reporting an issue, include OS/architecture, versions/paths, the failing command and its original error. Do not upload your whole `.d2x.json`; it may contain an API key.
-
## `/nonexistent/.../libm.so.6` / `libmvec.so.1`
-这类链接错误表明 glibc 载荷的打包占位路径没有被正确迁移,Provider 尚未生成。先更新课程并重新运行准备脚本,确认 `mcpp --version` 是 `2026.10.17.1`。不要手工创建 `/nonexistent` 目录或修改练习来规避环境错误。
-
-These linker errors mean the packaged glibc paths were not relocated correctly; the Provider has not been built. Update the course, rerun preparation and confirm `mcpp --version` reports `2026.10.17.1`. Keep your exercises and learning progress.
-
-`xlings update` 刷新课程工具的索引;`mcpp index update` 刷新 mcpp 内部工具链索引。二者不是一回事,刷新索引也不等于修复已经损坏的载荷。`mcpp toolchain install ` 可用于按诊断结果更新指定工具链,但不能保证修复所有遗留文件;如果重新准备仍失败,可以使用下面可回退的新 home 恢复方式。
-
-`xlings update` and `mcpp index update` refresh different package layers. An index refresh does not itself repair damaged installed files. A targeted `mcpp toolchain install ` can update a selected toolchain, but may not repair every legacy file. If preparation still fails, isolate a new mcpp home as below.
-
-### 保留旧工具链,使用新 home / Recover with a fresh home
-
-此操作保留原有 home、课程代码和学习进度,但需要重新下载一份工具链,占用额外磁盘空间。先从 `mcpp self doctor` 记录原 home。选择一个尚未使用的路径,再执行对应系统的命令;后续练习会话也需要设置同一个 `MCPP_HOME`。
-
-This keeps the previous home, course and progress intact, at the cost of another toolchain download. Record the original home from `mcpp self doctor`. Choose an unused path; set the same `MCPP_HOME` in subsequent practice sessions.
+Update the course and rerun preparation. If the error persists, choose an unused toolchain directory and repeat [preparation and verification](#prepare):
```bash
# Linux / macOS
export MCPP_HOME="$HOME/.mcpp-d2mcpp-recovered"
-bash scripts/setup.sh
-export PATH="$HOME/.xlings/subos/current/bin:$PATH"
-mcpp test -p solutions
-d2x checker
```
```powershell
# Windows PowerShell
$env:MCPP_HOME = "$env:USERPROFILE\.mcpp-d2mcpp-recovered"
-powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
-$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
-mcpp test -p solutions
-d2x checker
```
-撤销当前会话的覆盖:Unix 使用 `unset MCPP_HOME`,PowerShell 使用 `Remove-Item Env:MCPP_HOME`。原 home 仍然保留供诊断;不要自动删除整个 `~/.mcpp`、`~/.xlings` 或课程 `.d2x`。
-
-To undo this session's override, use `unset MCPP_HOME` on Unix or `Remove-Item Env:MCPP_HOME` in PowerShell. The previous home remains available for diagnosis. No full home or progress deletion is required.
-
-## CI 覆盖 / CI coverage
-
-- `fresh-install.yml`:无缓存的首次检查、失败后保存、通过后推进、重启恢复;Windows 使用 PowerShell 5.1,Linux 使用无预装编译器的普通用户容器,macOS 检查 ARM64 架构。
-- `dslings-ref-ci.yml`:中英文练习初始失败、答案覆盖后全部通过,以及 checker 完成全课;无 MSVC 档检查 GNU target。
-- `environment-lifecycle.yml`:真实 Dev Container 配置的创建/重连,以及旧 mcpp home 升级,以及损坏 glibc、旧索引快照、悬空安装记录的恢复。
-- main/定时任务额外验证真实 `d2x install d2mcpp` 下载入口;PR 的 clone 路线验证候选提交,二者分别报告。
+This downloads a new toolchain, keeping the old directory and progress. Set the same `MCPP_HOME` in future sessions. Undo with `unset MCPP_HOME` on Unix or `Remove-Item Env:MCPP_HOME` in PowerShell.
-CI logs distinguish dependency installation, initial toolchain preparation, Provider events, reference answers and checker progression. GitHub Server runners do not prove compatibility with every Windows desktop release; a CLI container test also does not replace checking the visible terminal in a real Codespace.
+Still stuck? [Open an issue](https://github.com/mcpp-community/d2mcpp/issues) with your OS, tool versions, command and error. Keep API keys out of reports.
diff --git a/docs/environment.zh.md b/docs/environment.zh.md
new file mode 100644
index 0000000..5610708
--- /dev/null
+++ b/docs/environment.zh.md
@@ -0,0 +1,92 @@
+# 环境准备与排错
+
+[English](environment.md) · [快速开始](../README.zh.md)
+
+支持 Linux x86_64、macOS 14+ Apple Silicon、Windows x86_64 / PowerShell 5.1+。工具版本由 [`.xlings.json`](../.xlings.json) 管理。
+
+
+
+## 安装 xlings
+
+Linux / macOS:
+
+```bash
+curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/v2026.10.18.1/tools/other/quick_install.sh | bash -s v2026.10.18.1
+export PATH="$HOME/.xlings/subos/current/bin:$PATH"
+```
+
+Windows PowerShell:
+
+```powershell
+irm https://raw.githubusercontent.com/mcpp-community/d2mcpp/main/scripts/install-xlings.ps1 | iex
+$env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
+```
+
+安装后继续 README 的步骤。找不到命令时,重新打开终端,或执行上面对应的 PATH 命令。
+
+## Git 获取与更新
+
+安装 xlings 后,也可克隆课程;使用 fork 时替换为自己的仓库地址:
+
+```bash
+git clone https://github.com/mcpp-community/d2mcpp.git
+cd d2mcpp
+```
+
+
+
+在课程根目录准备环境;更新时先执行 `git pull`。脚本会保留练习代码和学习进度。
+
+```bash
+# Linux / macOS
+bash scripts/setup.sh
+```
+
+```powershell
+# Windows PowerShell
+powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\setup.ps1
+```
+
+然后验证并开始练习:
+
+```bash
+mcpp test -p solutions
+d2x checker
+```
+
+## Codespaces
+
+等待准备完成,在终端运行 `d2x checker`。创建失败时查看创建日志;需要重试时,在容器内执行:
+
+```bash
+bash .devcontainer/postCreate.sh
+```
+
+## Provider 无响应
+
+在课程根目录运行以下命令,查看具体错误,再重试[准备步骤](#prepare):
+
+```bash
+xlings --version
+mcpp --version
+d2x --version
+mcpp run -p d2x/buildtools -- describe
+```
+
+## `/nonexistent/.../libm.so.6` / `libmvec.so.1`
+
+先更新课程并重新准备。若仍报错,选择未使用的工具链目录,再执行[准备与验证步骤](#prepare):
+
+```bash
+# Linux / macOS
+export MCPP_HOME="$HOME/.mcpp-d2mcpp-recovered"
+```
+
+```powershell
+# Windows PowerShell
+$env:MCPP_HOME = "$env:USERPROFILE\.mcpp-d2mcpp-recovered"
+```
+
+这会重新下载工具链,保留旧目录和学习进度。后续练习需设置同一个 `MCPP_HOME`;取消覆盖用 `unset MCPP_HOME`(Unix)或 `Remove-Item Env:MCPP_HOME`(PowerShell)。
+
+仍有问题时,附系统、工具版本、失败命令和原始错误[提交 issue](https://github.com/mcpp-community/d2mcpp/issues),不要上传 API key。
diff --git a/scripts/ci/check-project.py b/scripts/ci/check-project.py
index 2bb4e86..e777634 100644
--- a/scripts/ci/check-project.py
+++ b/scripts/ci/check-project.py
@@ -18,14 +18,16 @@
assert exercises == solutions, (prefix, exercises ^ solutions)
docs = [ROOT / name for name in ['README.md', 'README.zh.md', 'README.zh.hant.md',
- 'book/src/base/chapter_1.md', 'book/en/src/base/chapter_1.md', 'docs/environment.md']]
+ 'book/src/base/chapter_1.md', 'book/en/src/base/chapter_1.md',
+ 'docs/environment.md', 'docs/environment.zh.md']]
version = re.search(r'^XLINGS_VERSION=(.+)$', (ROOT / 'scripts/tool-versions.env').read_text(), re.M)[1]
for doc in docs:
text = doc.read_text(encoding='utf-8')
- assert 'scripts/setup.' in text, f'Missing preparation command in {doc}'
+ if not doc.name.startswith('README'):
+ assert 'scripts/setup.' in text, f'Missing preparation command in {doc}'
assert 'd2x checker' in text
assert 'tree/main/dslings' not in text, f'Obsolete code link in {doc}'
- if doc.name.startswith('README') or 'chapter_1' in doc.name:
+ if 'chapter_1' in doc.name:
assert version in text, f'Installer version differs in {doc}'
# Code fences contain literal examples, not navigable Markdown links.
prose = re.sub(r'```.*?```', '', text, flags=re.S)
diff --git a/scripts/ci/readme.py b/scripts/ci/readme.py
new file mode 100644
index 0000000..534ddc0
--- /dev/null
+++ b/scripts/ci/readme.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+"""Run the README flow in a disposable checkout, with course downloads pinned to its commit.
+
+Only Git's course URL is redirected to a local bare repository. xlings/d2x still
+perform the real install. Checker flags automate saving and resuming in CI.
+"""
+import argparse
+import json
+import os
+from pathlib import Path
+import re
+import shutil
+import subprocess
+import sys
+
+ROOT = Path(__file__).resolve().parents[2]
+LOGS = ROOT / '.d2x/ci-logs'
+WORK = ROOT / '.d2x/ci-work'
+sys.stdout.reconfigure(encoding='utf-8', errors='replace')
+sys.stderr.reconfigure(encoding='utf-8', errors='replace')
+
+
+def code_blocks(text, language):
+ return re.findall(r'```' + language + r'\n(.*?)```', text, re.S)
+
+
+def readme_commands(name, start, end):
+ text = (ROOT / name).read_text(encoding='utf-8').split(start, 1)[1].split(end, 1)[0]
+ return [line.split('#', 1)[0].strip() for block in code_blocks(text, 'bash')
+ for line in block.splitlines() if line.split('#', 1)[0].strip()]
+
+
+commands = readme_commands('README.md', '### Practice locally', '## Community')
+assert commands == readme_commands('README.zh.md', '### 搭建本地练习环境', '## 社区')
+assert commands == readme_commands('README.zh.hant.md', '### 建立本地練習環境', '## 社區')
+assert commands[-2:] == ['mcpp test -p solutions', 'd2x checker']
+guide = (ROOT / 'docs/environment.md').read_text(encoding='utf-8')
+translation = (ROOT / 'docs/environment.zh.md').read_text(encoding='utf-8')
+for language in ['bash', 'powershell']:
+ assert code_blocks(guide, language) == code_blocks(translation, language), 'Environment guide commands differ by language'
+install = re.search(r'\s*##[^\n]*\n(.*?)(?=\n## |\Z)', guide, re.S)[1]
+bootstrap = code_blocks(install, 'powershell' if os.name == 'nt' else 'bash')[0]
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('--published', action='store_true', help='download the public course instead of the candidate fixture')
+args = parser.parse_args()
+
+assert not WORK.exists(), 'Use a fresh disposable checkout'
+assert not (ROOT / '.d2x/state.json').exists(), 'Use a checkout without learning progress'
+LOGS.mkdir(parents=True, exist_ok=True)
+WORK.mkdir(parents=True)
+source = WORK / 'source.git'
+download = WORK / 'download'
+download.mkdir()
+head = subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip()
+env = os.environ.copy()
+env['XLINGS_NON_INTERACTIVE'] = '1'
+if not args.published:
+ subprocess.run(['git', 'clone', '--bare', '--no-hardlinks', str(ROOT), str(source)], check=True)
+ subprocess.run(['git', '-C', str(source), 'update-ref', 'refs/heads/readme-ci', head], check=True)
+ subprocess.run(['git', '-C', str(source), 'symbolic-ref', 'HEAD', 'refs/heads/readme-ci'], check=True)
+ index = int(env.get('GIT_CONFIG_COUNT', '0'))
+ for key, value in [(f'url.{source.as_uri()}.insteadOf', 'https://github.com/mcpp-community/d2mcpp.git'),
+ ('protocol.file.allow', 'always')]:
+ env[f'GIT_CONFIG_KEY_{index}'] = key
+ env[f'GIT_CONFIG_VALUE_{index}'] = value
+ index += 1
+ env['GIT_CONFIG_COUNT'] = str(index)
+
+# All installation and verification commands come from the docs. The checker
+# harness runs the last command with event output and simulates the user's save.
+checker = ('python' if os.name == 'nt' else 'python3') + ' scripts/ci/first-run.py --allow-source-edit'
+script = WORK / ('readme.ps1' if os.name == 'nt' else 'readme.sh')
+if os.name == 'nt':
+ body = "$ErrorActionPreference = 'Stop'\n" + bootstrap + '\n'
+ for command in commands[:-1] + [checker]:
+ body += command + "\nif ($LASTEXITCODE -ne 0) { throw 'README command failed' }\n"
+ script.write_text(body, encoding='utf-8')
+ shell = ['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', str(script)]
+else:
+ script.write_text('set -euo pipefail\n' + bootstrap + '\n' + '\n'.join(commands[:-1] + [checker]) + '\n', encoding='utf-8')
+ shell = ['bash', str(script)]
+
+course = download / 'd2mcpp'
+print('Running the README commands with the documented xlings installer', flush=True)
+try:
+ with (LOGS / 'readme-install.log').open('w', encoding='utf-8') as log:
+ result = subprocess.run(shell, cwd=download, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=2700)
+ output = (LOGS / 'readme-install.log').read_text(encoding='utf-8', errors='replace')
+ print(output, flush=True)
+ assert result.returncode == 0, 'README flow failed; see readme-install.log'
+ expected = len(list((ROOT / 'solutions/tests').rglob('*.cpp')))
+ assert expected > 0 and re.findall(r'(\d+) passed; (\d+) failed', output)[-1] == (str(expected), '0')
+ assert f'FIRST-RUN PASS: {expected} exercises' in output
+ actual = subprocess.check_output(['git', '-C', str(course), 'rev-parse', 'HEAD'], text=True).strip()
+ if args.published:
+ assert json.loads((course / '.xlings.json').read_text()) == json.loads((ROOT / '.xlings.json').read_text()), 'Published course pins are stale'
+ else:
+ assert actual == head, f'Course download used {actual}, expected candidate {head}'
+ (LOGS / 'readme-result.json').write_text(json.dumps({'candidate': head, 'downloaded': actual, 'published': args.published, 'status': 'passed'}, indent=2), encoding='utf-8')
+finally:
+ if (course / '.d2x/ci-logs').exists():
+ shutil.copytree(course / '.d2x/ci-logs', LOGS / 'readme-events', dirs_exist_ok=True)
+if os.environ.get('GITHUB_PATH'):
+ with open(os.environ['GITHUB_PATH'], 'a', encoding='utf-8') as paths:
+ paths.write(str(Path.home() / '.xlings/subos/current/bin') + '\n')
+print('README PASS: documented install, reference answers and save/advance/resume; course source verified')