Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions .agents/docs/2026-10-20-d2x-d2mcpp-first-use-plan.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions .github/workflows/dslings-ref-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ jobs:
run: ./scripts/ci/mask-msvc.ps1
- name: Prepare course (Unix)
if: runner.os != 'Windows'
run: bash scripts/setup.sh
run: python3 scripts/ci/prepare.py
- name: Prepare course (Windows PowerShell 5.1)
if: runner.os == 'Windows'
shell: powershell
run: ./scripts/setup.ps1
run: python scripts/ci/prepare.py
- name: Assert MinGW fallback
if: matrix.mask_msvc
run: |
Expand Down
113 changes: 108 additions & 5 deletions .github/workflows/fresh-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,34 @@ on:
- "book/src/changelog.md"
- "book/en/src/changelog.md"
workflow_dispatch:
inputs:
candidate_run:
description: 'Optional successful d2learn/d2x CI run ID (explicit prerelease override)'
type: string
default: ''
candidate_sha:
description: 'Exact checkout SHA recorded in that candidate provenance'
type: string
default: ''
diagnose:
description: 'Also compare standalone build and checker in separate cold Windows environments'
type: boolean
default: false
schedule:
- cron: '23 4 * * 1'

permissions:
contents: read
actions: read

env:
XLINGS_NON_INTERACTIVE: '1'
D2X_CANDIDATE_SHA: ${{ inputs.candidate_sha }}
D2X_CANDIDATE_DIR: .d2x/candidate

jobs:
native:
if: ${{ !inputs.diagnose }}
name: fresh (${{ matrix.os }}, ${{ matrix.route }}, MSVC=${{ !matrix.mask_msvc }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
Expand All @@ -62,6 +82,18 @@ jobs:
- {os: windows-2025, route: cold, mask_msvc: true}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
if: inputs.candidate_run != ''
with:
repository: d2learn/d2x
run-id: ${{ inputs.candidate_run }}
github-token: ${{ github.token }}
name: ${{ runner.os == 'Linux' && 'candidate-linux-x86_64' || format('candidate-{0}', matrix.os) }}
path: ${{ env.D2X_CANDIDATE_DIR }}
- name: Verify explicit candidate provenance
if: inputs.candidate_run != ''
shell: bash
run: ${{ runner.os == 'Windows' && 'python' || 'python3' }} scripts/ci/candidate.py
- name: Select an empty toolchain home
shell: bash
run: echo "MCPP_HOME=$RUNNER_TEMP/d2mcpp-fresh" >> "$GITHUB_ENV"
Expand All @@ -85,11 +117,11 @@ jobs:
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
run: python3 scripts/ci/prepare.py --install-only
- name: Cold install only (PowerShell 5.1)
if: runner.os == 'Windows' && matrix.route == 'cold'
shell: powershell
run: ./scripts/setup.ps1 -InstallOnly
run: python scripts/ci/prepare.py --install-only
- name: First check, save, advance and resume
if: matrix.route == 'cold'
shell: bash
Expand All @@ -104,7 +136,7 @@ jobs:
ROUTE: ${{ matrix.route }}
run: |
logs="$(pwd)/.d2x/ci-logs"
if [[ "$ROUTE" == readme ]]; then cd .d2x/ci-work/download/d2mcpp; fi
if [[ "$ROUTE" == readme ]]; then cd "$(cat "$logs/readme-course-path.txt")"; fi
# doctor returns nonzero for warnings too (missing MSVC is expected).
mcpp self doctor > "$logs/doctor.txt" 2>&1 || true
cat "$logs/doctor.txt"
Expand All @@ -121,6 +153,7 @@ jobs:
include-hidden-files: true

linux-minimal:
if: ${{ !inputs.diagnose }}
name: fresh (Linux without a compiler, ${{ matrix.route }})
runs-on: ubuntu-24.04
container: ubuntu:24.04
Expand All @@ -138,6 +171,18 @@ jobs:
! command -v g++
! command -v clang++
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
if: inputs.candidate_run != ''
with:
repository: d2learn/d2x
run-id: ${{ inputs.candidate_run }}
github-token: ${{ github.token }}
name: candidate-linux-x86_64
path: ${{ env.D2X_CANDIDATE_DIR }}
- name: Verify explicit candidate provenance
if: inputs.candidate_run != ''
shell: bash
run: ${{ runner.os == 'Windows' && 'python' || 'python3' }} scripts/ci/candidate.py
- name: Give the ordinary user a fresh checkout
shell: bash
env:
Expand All @@ -158,7 +203,7 @@ jobs:
run: |
cd "$COURSE_DIR"
if [[ "$ROUTE" == cold ]]; then
runuser -u learner -- bash scripts/setup.sh --install-only
runuser -u learner -- python3 scripts/ci/prepare.py --install-only
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
Expand All @@ -174,7 +219,7 @@ jobs:

released-course:
name: Published d2x install route (main only)
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && inputs.candidate_run == ''
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
Expand All @@ -188,3 +233,61 @@ jobs:
path: .d2x/ci-logs/
if-no-files-found: ignore
include-hidden-files: true

cold-diagnostics:
if: inputs.diagnose
runs-on: windows-2025
strategy:
fail-fast: false
matrix:
route: [build, run, checker]
steps:
- uses: actions/checkout@v4
- name: Mask MSVC
shell: powershell
run: ./scripts/ci/mask-msvc.ps1
- name: Select independent cold home
shell: bash
run: echo "MCPP_HOME=$RUNNER_TEMP/diagnostic-${{ matrix.route }}" >> "$GITHUB_ENV"
- name: Install tools only
shell: powershell
run: python scripts/ci/prepare.py --install-only
- name: Diagnose baseline cold startup
shell: bash
env:
DIAGNOSTIC_ROUTE: ${{ matrix.route }}
run: python scripts/ci/cold-diagnostics.py
- uses: actions/upload-artifact@v4
if: always()
with:
name: cold-diagnostic-${{ matrix.route }}
path: .d2x/ci-logs/
include-hidden-files: true

latest-stable:
if: github.ref == 'refs/heads/main' && inputs.candidate_run == ''
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-14, windows-2025]
steps:
- uses: actions/checkout@v4
- name: Install xlings (Unix)
if: runner.os != 'Windows'
run: bash scripts/install-xlings.sh
- name: Install xlings (PowerShell 5.1)
if: runner.os == 'Windows'
shell: powershell
run: ./scripts/install-xlings.ps1
- name: Check stable release, public latest and course pin
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: ${{ runner.os == 'Windows' && 'python' || 'python3' }} scripts/ci/latest.py
- uses: actions/upload-artifact@v4
if: always()
with:
name: latest-stable-versions-${{ matrix.os }}
path: .d2x/ci-logs/
include-hidden-files: true
2 changes: 1 addition & 1 deletion .xlings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"workspace": {
"d2x": "2026.08.02.2",
"d2x": "2026.10.21.1",
"mdbook": "0.4.43",
"mcpp": "2026.10.17.1"
}
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ Wait for the environment to be ready, then run `d2x checker` in the terminal.
Install [xlings](docs/environment.md#install-xlings), reopen your terminal, then run:

```bash
xlings install d2x mcpp -y
xlings update
xlings install --use d2x@latest mcpp@latest -y
```

**2. Get the course**
Expand Down
3 changes: 2 additions & 1 deletion README.zh.hant.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
安裝 [xlings](docs/environment.zh.md#install-xlings),重新開啟終端後執行:

```bash
xlings install d2x mcpp -y
xlings update
xlings install --use d2x@latest mcpp@latest -y
```

**第二步:取得課程**
Expand Down
3 changes: 2 additions & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
安装 [xlings](docs/environment.zh.md#install-xlings),重新打开终端后执行:

```bash
xlings install d2x mcpp -y
xlings update
xlings install --use d2x@latest mcpp@latest -y
```

**第二步:获取课程**
Expand Down
18 changes: 16 additions & 2 deletions book/en/src/base/chapter_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ git clone https://github.com/mcpp-community/d2mcpp.git
cd d2mcpp
```

**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.
**2. Prepare the environment.** These scripts install xlings **2026.10.18.1**, the versions in `.xlings.json` (mcpp **2026.10.17.1**, d2x **2026.10.21.1**, mdBook **0.4.43**), and build and check the Provider. The first build may take several minutes.

Linux / macOS:

Expand Down Expand Up @@ -59,7 +59,8 @@ $env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
Then, on either system:

```text
xlings install d2x@2026.08.02.2 -y
xlings update
xlings install --use d2x@latest mcpp@latest -y
d2x install d2mcpp
cd d2mcpp
```
Expand Down Expand Up @@ -266,3 +267,16 @@ xlings install
**Tutorial Repository:** [https://github.com/mcpp-community/d2mcpp](https://github.com/mcpp-community/d2mcpp)

**Tutorial Video Collection:** [https://space.bilibili.com/65858958/lists/5208246](https://space.bilibili.com/65858958/lists/5208246)

## First-start preparation and version checks

`d2x install` installs the downloaded course's declared workspace dependencies.
After a Git update, rerun the preparation script to apply changed versions.
Run `d2x --version` from the course directory and compare it with `.xlings.json`;
updating a global tool alone does not establish which project version is selected.

The checker shows preparation before the first exercise. Initial Provider startup
has a total 900-second budget; subsequent Provider calls have a 120-second idle
limit. Preparation messages do not extend the startup deadline. On failure, keep
`.d2x/provider.stdout.log`, `.d2x/provider.stderr.log` and the command output.
Startup/transport errors exit nonzero; an unfinished exercise verdict is expected.
7 changes: 7 additions & 0 deletions book/en/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@

## 2026/10

**d2x upgrade and cold-start diagnostics**

Upgrade d2x to 2026.10.21.1 and verify the selected executable; bound first Provider startup separately, show preparation and retain raw logs.

- `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/20
- `Code`: [first-use CI](https://github.com/mcpp-community/d2mcpp/blob/main/.github/workflows/fresh-install.yml) - 2026/10/20

**Environment upgrade and first-use validation**

Pin mcpp 2026.10.17.1, add platform setup scripts and fresh/legacy environment checks, and update the Codespaces entry point.
Expand Down
14 changes: 12 additions & 2 deletions book/src/base/chapter_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ git clone https://github.com/mcpp-community/d2mcpp.git
cd d2mcpp
```

**第二步:准备环境。** 脚本安装 xlings **2026.10.18.1** 及 `.xlings.json` 声明的版本(mcpp **2026.10.17.1**、d2x **2026.08.02.2**、mdBook **0.4.43**),构建并检查 Provider。首次构建可能需要几分钟。
**第二步:准备环境。** 脚本安装 xlings **2026.10.18.1** 及 `.xlings.json` 声明的版本(mcpp **2026.10.17.1**、d2x **2026.10.21.1**、mdBook **0.4.43**),构建并检查 Provider。首次构建可能需要几分钟。

Linux / macOS:

Expand Down Expand Up @@ -59,7 +59,8 @@ $env:Path = "$env:USERPROFILE\.xlings\subos\current\bin;$env:Path"
然后在任一系统执行:

```text
xlings install d2x@2026.08.02.2 -y
xlings update
xlings install --use d2x@latest mcpp@latest -y
d2x install d2mcpp
cd d2mcpp
```
Expand Down Expand Up @@ -263,3 +264,12 @@ xlings install
**教程仓库:** [https://github.com/mcpp-community/d2mcpp](https://github.com/mcpp-community/d2mcpp)

**教程视频合集:** [https://space.bilibili.com/65858958/lists/5208246](https://space.bilibili.com/65858958/lists/5208246)

## 首次启动准备与版本核对

`d2x install` 会安装下载课程所声明的项目依赖。通过 Git 更新后,重新运行准备脚本以应用版本变化。
在课程目录执行 `d2x --version`,与 `.xlings.json` 对照;仅更新全局工具不能证明项目实际使用的版本。

checker 在第一题之前显示准备信息。首次 Provider 启动的总期限为 900 秒,后续调用的空闲期限为 120 秒;
准备提示不会延长期限。失败时保留 `.d2x/provider.stdout.log`、`.d2x/provider.stderr.log` 与命令输出。
启动和传输错误会非零退出;未完成练习的 fail 判定属于预期行为。
7 changes: 7 additions & 0 deletions book/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@

## 2026/10

**d2x 最新版联动与冷启动诊断**

升级 d2x 至 2026.10.21.1,核对实际执行版本;首次 Provider 构建单独限时,显示准备进度并保留原始日志。

- `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/20
- `Code`: [first-use CI](https://github.com/mcpp-community/d2mcpp/blob/main/.github/workflows/fresh-install.yml) - 2026/10/20

**练习环境升级与首次使用验证**

统一使用 mcpp 2026.10.17.1,增加跨平台准备脚本、全新安装与旧环境恢复验证,更新 Codespaces 入口。
Expand Down
17 changes: 17 additions & 0 deletions docs/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,20 @@ $env:MCPP_HOME = "$env:USERPROFILE\.mcpp-d2mcpp-recovered"
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.

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.

## First-start preparation and version checks

`d2x install` installs the downloaded course's declared workspace dependencies.
After a Git update, rerun the preparation script to apply changed versions.
Run `d2x --version` from the course directory and compare it with `.xlings.json`;
updating a global tool alone does not establish which project version is selected.

The checker shows preparation before the first exercise. Initial Provider startup
has a total 900-second budget; subsequent Provider calls have a 120-second idle
limit. Preparation messages do not extend the startup deadline. On failure, keep
`.d2x/provider.stdout.log`, `.d2x/provider.stderr.log` and the command output.
Startup/transport errors exit nonzero; an unfinished exercise verdict is expected.

For an existing tool installation, use `xlings install --use d2x@latest mcpp@latest -y` after `xlings update`. `@latest` selects the newest stable index entry; `--use` activates it even when already installed. Bare install commands can retain the previously selected version.

User cancellation returns 130 and a `cancelled` event without a Provider-failure warning or a failed exercise verdict.
13 changes: 13 additions & 0 deletions docs/environment.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,16 @@ $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。

## 首次启动准备与版本核对

`d2x install` 会安装下载课程所声明的项目依赖。通过 Git 更新后,重新运行准备脚本以应用版本变化。
在课程目录执行 `d2x --version`,与 `.xlings.json` 对照;仅更新全局工具不能证明项目实际使用的版本。

checker 在第一题之前显示准备信息。首次 Provider 启动的总期限为 900 秒,后续调用的空闲期限为 120 秒;
准备提示不会延长期限。失败时保留 `.d2x/provider.stdout.log`、`.d2x/provider.stderr.log` 与命令输出。
启动和传输错误会非零退出;未完成练习的 fail 判定属于预期行为。

已有工具环境先执行 `xlings update`,再执行 `xlings install --use d2x@latest mcpp@latest -y`。`@latest` 选择最新稳定条目;`--use` 即使新版已安装也会激活它。仅执行不带版本或激活选项的 install 可能继续保留旧版。

用户取消返回 130 和 `cancelled` 事件,不报告 Provider 故障,也不生成练习失败判定。
20 changes: 20 additions & 0 deletions scripts/ci/candidate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python3
"""Activate only an explicitly requested, checksum-verified d2x CI artifact."""
import hashlib
import json
import os
from pathlib import Path
import subprocess

root = Path(os.environ['D2X_CANDIDATE_DIR']).resolve()
metadata = json.loads((root / 'provenance.json').read_text())
assert metadata['repository'] == 'd2learn/d2x'
assert metadata['sha'] == os.environ['D2X_CANDIDATE_SHA']
assert metadata['file'] in ['d2x', 'd2x.exe']
binary = root / metadata['file']
assert hashlib.sha256(binary.read_bytes()).hexdigest() == metadata['sha256']
binary.chmod(0o755)
assert subprocess.check_output([str(binary), '--version'], text=True).strip() == metadata['version']
with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
env.write(f'D2X_CANDIDATE={binary}\n')
print('Explicit d2x candidate:', json.dumps(metadata), flush=True)
Loading
Loading