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
74 changes: 56 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
# GitHub Actions: tag-triggered prebuilt-binary release (F166).
# GitHub Actions: tag-triggered prebuilt-binary release (F166 + F174).
#
# Pushing a tag like `v0.6.6` builds the `ccteam` binary on three targets,
# Pushing a tag like `v0.6.7` builds the `ccteam` binary on four targets,
# packages each with a per-asset SHA-256 sum, aggregates a single
# SHA256SUMS file, and uploads everything to the corresponding GitHub
# Release. `install.sh` (repo root) reads these assets — keep the asset
# naming `ccteam-<tag>-<suffix>.<ext>` and the suffix vocabulary
# (linux-x64 / macos-arm64 / macos-x64) in lockstep with that script.
# (linux-x64 / linux-arm64 / macos-arm64 / macos-x64) in lockstep with
# that script.
#
# F174: linux binaries are statically linked against musl libc
# (x86_64-unknown-linux-musl / aarch64-unknown-linux-musl) so they run
# on any Linux distro regardless of host glibc version. Pre-F174
# releases targeted `x86_64-unknown-linux-gnu` on `ubuntu-latest`
# (glibc 2.39 from Ubuntu 24.04) which broke installs on Ubuntu 22.04,
# Debian 12, and NAS-class systems pinned to older glibc. Suffix names
# stay `linux-x64` / `linux-arm64` (musl is transparent to users); the
# static-link sanity step at the end of the build job guards against
# silent regressions if a dep upgrade re-introduces a glibc dependency.
#
# Windows is intentionally out of scope: ccteam's foundation is tmux +
# inotify + POSIX signals (`libc::SIGKILL` / `SIGTERM` in
Expand Down Expand Up @@ -34,9 +45,13 @@ jobs:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target: x86_64-unknown-linux-musl
suffix: linux-x64
ext: tar.gz
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-musl
suffix: linux-arm64
ext: tar.gz
- os: macos-14
target: aarch64-apple-darwin
suffix: macos-arm64
Expand All @@ -50,6 +65,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Install musl toolchain (linux only)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y musl-tools

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -67,19 +86,20 @@ jobs:
# Pre-install the SPA `node_modules/` before `cargo build` so the
# `ccteam-web` build.rs (which feature-gates on `web-bundle`,
# default-on) finds them and skips its own `npm install`. We split
# by runner OS because `package-lock.json` is generated on Linux
# and only resolves the linux-x64 rolldown native binding; macOS
# `npm ci` would honor that lockfile and skip the darwin
# `optionalDependencies`, leaving rolldown unable to load
# `.darwin-arm64.node` at build time. Clearing the lockfile on
# macOS forces a fresh platform-correct resolution.
- name: Pre-install web SPA deps (linux fast path with lockfile)
if: runner.os == 'Linux'
# by runner OS+arch because `package-lock.json` is generated on
# Linux x64 and only resolves the linux-x64 rolldown native
# binding; macOS and linux-arm64 `npm ci` would honor that
# lockfile and skip the platform-specific `optionalDependencies`,
# leaving rolldown unable to load its native node binding at build
# time. Clearing the lockfile on those runners forces a fresh
# platform-correct resolution.
- name: Pre-install web SPA deps (linux x64 fast path with lockfile)
if: runner.os == 'Linux' && runner.arch == 'X64'
working-directory: crates/ccteam-web/web
run: npm ci --no-audit --no-fund --include=optional

- name: Pre-install web SPA deps (macOS — drop lockfile for native binding refresh)
if: runner.os == 'macOS'
- name: Pre-install web SPA deps (macOS / linux-arm64 — drop lockfile for native binding refresh)
if: runner.os == 'macOS' || (runner.os == 'Linux' && runner.arch == 'ARM64')
working-directory: crates/ccteam-web/web
run: |
rm -f package-lock.json
Expand All @@ -88,6 +108,23 @@ jobs:
- name: Build ccteam binary
run: cargo build --release --locked --target ${{ matrix.target }} --bin ccteam

# Static-link sanity (linux only). musl target should produce a
# binary with no dynamic dependencies; if a dep ever pulls in a
# glibc-linked native lib (rare but possible after dep bumps),
# `file` will report `dynamically linked` and we fail the build
# before shipping a broken binary to users.
- name: Verify static linkage (linux only)
if: runner.os == 'Linux'
shell: bash
run: |
set -eu
BIN="target/${{ matrix.target }}/release/ccteam"
file "$BIN"
if ! file "$BIN" | grep -qE 'statically linked|static-pie linked'; then
echo "::error::ccteam binary is not statically linked — musl target regressed."
exit 1
fi

- name: Package (unix)
if: matrix.ext == 'tar.gz'
shell: bash
Expand Down Expand Up @@ -154,10 +191,11 @@ jobs:
cat > release-notes.md <<EOF
# ccteam ${TAG}

Prebuilt binaries for Linux x86_64 and macOS (Intel + Apple Silicon).
Windows users: run ccteam under WSL2 with the linux-x64 binary
(ccteam's foundation is tmux + inotify + POSIX signals, which
are unix-only).
Prebuilt binaries for Linux (x86_64 + aarch64, statically
linked against musl libc so they run on any glibc version) and
macOS (Intel + Apple Silicon). Windows users: run ccteam under
WSL2 with the linux-x64 binary (ccteam's foundation is tmux +
inotify + POSIX signals, which are unix-only).

## Install (zero-Rust)

Expand Down
15 changes: 8 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@

---

## 一、当前状态(2026-05-24)
## 一、当前状态(2026-05-25)

| 项 | 值 |
|---|---|
| 主分支 main HEAD | 以 `git rev-parse origin/main` 为准 |
| Workspace version | **`0.6.6`** |
| 测试 baseline | **`1639/1`**(`cargo test --workspace --locked --no-fail-fast`,1 fail 是 ccteam-web `workflow_summary_reflects_agent_spawn_and_done_events` running_count flake;另 inotify-busy 宿主可见 watcher/SSE 类 transient(WSL2 fs.inotify.max_user_instances=128 易触顶),均不计入 baseline;V0.6.6 +56 测试主要来自 F166 install.sh smoke + F167 probe-project + F169 cost-today ledger + F171 verify-mcp + F172 V2 claude --resume by name + F173 Codex critic ledger)|
| Workspace version | **`0.6.7`** |
| 测试 baseline | **`1639/1`**(`cargo test --workspace --locked --no-fail-fast`,1 fail 是 ccteam-web `workflow_summary_reflects_agent_spawn_and_done_events` running_count flake;另 inotify-busy 宿主可见 watcher/SSE 类 transient(WSL2 fs.inotify.max_user_instances=128 易触顶),均不计入 baseline;V0.6.7 install-fix patch **无业务代码改动**,baseline 与 V0.6.6 持平)|
| Clippy | **0 errors + 0 warnings**(`-D warnings` clean)|
| 代码规模 | ~93 kLOC Rust(workspace,~64 kLOC src + ~29 kLOC tests,不含 references)|
| 当前最新版 | **V0.6.6**(F166-F173 共 8 finding + F172 V2 redesign + Claude Code plugin marketplace chore:F166 GH Releases prebuilt binary + `install.sh` 一键装 / F167 `/ccteam-creator` per-project-type sensible defaults + `ccteam probe-project --json` / F168 active TODO sweep 6 V0.7-defer-with-justification + 3 sister-finding cover / F169 `nl_admin::cost_today` 接真 `ccteam_cost` ledger / F170 doc-comment scrub 4 sites / F171 `ccteam doctor --verify-mcp` + STUB_TOOLS static assertion / F172 V2 tmux mode-3 上下文恢复借 Anthropic 官方 `claude --resume <name>` lossless 续接(V1 chat_snapshot 设计 ditch)/ F173 Codex daemon-routed critic 统一 cost rollup(F156 follow-through))— 详 `docs/versions/v0-6-6/README.md` |
| 上一版 | **V0.6.5**(F146-F165 共 20 finding:Epic E MCP chat 桥 + Epic F advise/Codex critic + Epic G UX cohesion + Epic H 运维健壮性 + 中途 F165 mcp-serve tracing→stderr)— 详 `docs/versions/v0-6-5/README.md` |
| 上上版 | **V0.6.4**(OutboundCursor race fix — NAS 上 Telegram duplicate flood 排错产出,无独立 docs dir,见 commit `504c208`)|
| V0.6.x 延期候选 | 空(本版闭所有 retained risk;F156 daemon-routed Codex critic variant 由 F173 V0.6.6 解决,bash spawn 路径与 daemon-routed unified cost rollup 两条都齐;F168 6 site V0.7-defer-with-justification 是新 / 老 V0.7 候选锚点,**不**算 V0.6.x 延期)|
| 当前最新版 | **V0.6.7**(F174 install-fix ship-blocker patch:`.github/workflows/release.yml` linux build target `x86_64-unknown-linux-gnu` on `ubuntu-latest` → musl static dual-arch(`x86_64-unknown-linux-musl` on `ubuntu-latest` + `aarch64-unknown-linux-musl` on `ubuntu-24.04-arm`)+ npm lockfile fast-path 条件收紧到 `runner.arch == 'X64'` + static-link sanity step;`install.sh` `linux-aarch64`/`linux-arm64` 从 error → `SUFFIX=linux-arm64`。修复 V0.6.6 prebuilt binary 在 glibc 2.35 / 老 NAS 系统 `GLIBC_2.39 not found` 装不上的 ship-blocker。0 行 ccteam 业务代码改动)— 详 `docs/versions/v0-6-7/README.md` |
| 上一版 | **V0.6.6**(F166-F173 共 8 finding + F172 V2 redesign + Claude Code plugin marketplace chore:F166 GH Releases prebuilt binary + `install.sh` 一键装 / F167 `/ccteam-creator` per-project-type sensible defaults + `ccteam probe-project --json` / F168 active TODO sweep 6 V0.7-defer-with-justification + 3 sister-finding cover / F169 `nl_admin::cost_today` 接真 `ccteam_cost` ledger / F170 doc-comment scrub 4 sites / F171 `ccteam doctor --verify-mcp` + STUB_TOOLS static assertion / F172 V2 tmux mode-3 上下文恢复借 Anthropic 官方 `claude --resume <name>` lossless 续接(V1 chat_snapshot 设计 ditch)/ F173 Codex daemon-routed critic 统一 cost rollup(F156 follow-through))— 详 `docs/versions/v0-6-6/README.md` |
| 上上版 | **V0.6.5**(F146-F165 共 20 finding:Epic E MCP chat 桥 + Epic F advise/Codex critic + Epic G UX cohesion + Epic H 运维健壮性 + 中途 F165 mcp-serve tracing→stderr)— 详 `docs/versions/v0-6-5/README.md` |
| V0.6.4 注 | **V0.6.4** OutboundCursor race fix(NAS 上 Telegram duplicate flood 排错产出,无独立 docs dir,见 commit `504c208`)|
| V0.6.x 延期候选 | 空(本版闭所有 retained risk;V0.6.7 是 V0.6.6 install-path ship-blocker 紧急 patch,业务代码不动)|
| V0.7 主线候选 | Epic C 国内 IM(WeChat / 飞书 / DingTalk / QQ)启用 + Slack inbound HTTP + Socket Mode(F168 anchor `TODO(V0.7-{im-providers,slack-inbound,slack-socket-mode})`)+ chat memory 跨设备同步 + monorepo-aware `.mcp.json` + migrate-from-claude + 6 号编排模式深化(HumanApproval × bg/chat 矩阵全开;`HumanApprovalAdapter` full wrapper F168 anchor `TODO(V0.7-human-approval-adapter)`)+ `/ccteam-creator` 完整 template library + LLM-assisted role auto-gen(F167 only 做 sensible defaults 探测)+ per-bot `chat_handle` schema(F168 anchor `TODO(V0.7-chat-handle)` + `TODO(V0.7-listbots-cache)`)|
| 历史版本 | V0.1 → V0.6.5 见各自 `docs/versions/v0-X-Y/README.md`(V0.6.4 仅 commit,无 dir)|

Expand Down
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
]

[workspace.package]
version = "0.6.6"
version = "0.6.7"
edition = "2021"
rust-version = "1.85"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion crates/ccteam-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ fn latest_claude_bg_job_id(paths: &CcteamPaths, slug: &str) -> Option<String> {
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
candidates.push((mtime, id));
}
candidates.sort_by(|a, b| b.0.cmp(&a.0));
candidates.sort_by_key(|c| std::cmp::Reverse(c.0));
candidates.into_iter().next().map(|(_, id)| id)
}

Expand Down
98 changes: 98 additions & 0 deletions docs/versions/v0-6-7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ccteam V0.6.7 — install.sh ship-blocker hot patch (musl static binaries, dual-arch)

> **范围:install-fix-only patch。** F174 一项,改 `release.yml` linux build target 到 musl static + 加 linux-arm64,改 `install.sh` 支持 `linux-aarch64`/`linux-arm64`。**无 ccteam 业务代码改动**,无新 MCP tool,无 schema 变化。

---

## 1. 为什么紧急

V0.6.6 ship 的 `install.sh` 在两台 Ubuntu 22.04 系机器(包括一台 NAS)上均报:

```
ccteam: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found (required by ccteam)
```

= 用户拿到 install.sh 一行命令但 binary 跑不起来 = product 入口完全堵死。

**根因**:`release.yml` 在 `ubuntu-latest`(目前 = Ubuntu 24.04,glibc 2.39)上 build `x86_64-unknown-linux-gnu` target,产物动态依赖 glibc 2.39;用户机普遍是 glibc 2.35(Ubuntu 22.04 / Debian 12 / 多数现役 NAS)甚至更老,无法运行。

V0.6.6 F166 的 prebuilt binary 设计本身没问题(release matrix / SHA256SUMS / install.sh 主流程都 OK),只是 build target 没考虑 host glibc backward-compat。这是 install-path bug,patch 1 行 release.yml + 几行 install.sh 即可彻底解决。

---

## 2. F174 — Linux musl static binaries + linux-arm64 prebuilt

| Action | 文件 | 改动 |
|---|---|---|
| Build target 改 musl(x86_64) | `.github/workflows/release.yml` | `x86_64-unknown-linux-gnu` → `x86_64-unknown-linux-musl`,runner 留 `ubuntu-latest` + `apt install musl-tools` |
| 新增 linux-arm64 build | `.github/workflows/release.yml` | matrix 加 `aarch64-unknown-linux-musl` on `ubuntu-24.04-arm`(GitHub-hosted ARM runner,public repo 免费) |
| npm lockfile fast-path 收紧 | `.github/workflows/release.yml` | `runner.os == 'Linux'` → `runner.os == 'Linux' && runner.arch == 'X64'`;arm64 走 macOS 同款 drop-lockfile + `npm install --include=optional`(lockfile 是 linux-x64 生成,不含 arm64 rolldown binding) |
| Static-link sanity step | `.github/workflows/release.yml` | build 完跑 `file <binary> \| grep -E 'statically linked\|static-pie linked'`,不命中 fail build(防 dep 升级 silent 退化成 dynamic) |
| install.sh 支持 linux-arm64 | `install.sh` | `linux-aarch64\|linux-arm64` 从 error → `SUFFIX=linux-arm64`;清理 fallback hint 文案 |
| Release notes 文案 | `.github/workflows/release.yml` | "Linux x86_64 + aarch64, statically linked against musl libc so they run on any glibc version" |

**用户面命名保持透明** `linux-x64` / `linux-arm64`,**不**加 `-musl` 后缀。用户感知 = "Linux 二进制现在直接能装",musl 是实现细节。

**为什么 musl 而非 ubuntu-22.04 runner**:musl static binary 完全无 glibc 依赖,覆盖所有 Linux 发行版(包括 Alpine、老 CentOS、各种 NAS)。`ubuntu-22.04` runner 只把兼容下限拉到 glibc 2.35,仍排除老系统;且 GitHub 已宣布 `ubuntu-22.04` image deprecation 在 2026 年某时,1-2 年内还要再迁。一步到位。

**依赖审计**(本地预证 musl 路线无坑):TLS = rustls(`reqwest` default-features=false + `rustls-tls`,`tokio-tungstenite` + `rustls-tls-webpki-roots`),无 OpenSSL;`nix` 0.29 用 `signal`/`fs`/`process` features 全 POSIX 标准;`notify = "8"`(inotify-rs 0.10)musl 完整支持;libc 调用走 `libc` crate。本地 `cargo build --release --target x86_64-unknown-linux-musl --bin ccteam` 3 分钟 build 成功,`file` 报 `static-pie linked`,`ldd` 报 `statically linked`,在本机 glibc 2.35 上 `--version` OK。

---

## 3. 红线核对(CLAUDE.md §三)

无触及。F174 仅作用于 CI build / 发布 / install 路径,**0 行 ccteam 业务代码改动**:

- `crates/*/src/**` 0 改
- `progress.jsonl` schema 0 改
- MCP tool surface 0 改(仍 27 工具,STUB 仍 0)
- workflow.yaml / `.mcp.json` / `.claude/agents/*.md` 0 改
- 红线 R0-R12 全部不触及

---

## 4. Baseline gate

- workspace `0.6.6` → `0.6.7`(`Cargo.toml::workspace.package.version`)
- test:V0.6.6 baseline `1639/1`,本版**无新增测试**(install path 不进 cargo test,CI build 本身是 gate),目标 ≥ `1639/1`
- clippy:`-D warnings` clean(本版 0 业务代码改,自动持平)
- fmt:`cargo fmt --all -- --check` clean
- CI build 必须四个 target 全绿(linux-x64 / linux-arm64 / macos-arm64 / macos-x64),any one fail = release 不可发

---

## 5. Ship gate(CLAUDE.md §五.7)

| Item | Done |
|---|---|
| `CLAUDE.md §一` baseline / workspace version 更新 | ✅(本 PR) |
| `Cargo.toml::workspace.package.version` 0.6.6 → 0.6.7 | ✅ |
| `Cargo.lock` 同步 | ✅(`cargo build` 自动更新) |
| `docs/versions/v0-6-7/README.md` 落地 | ✅(本文件) |
| `docs/dev-coupling-audit.md` 加 F174 索引 | 见 PR |
| 用户面 docs:`README.md` quickstart 段 / `docs/quickstart.md` install 段 | **无需改动** ── install.sh 命令本身不变,只是底层 binary 变 static;用户视角零差 |
| CI release.yml 四个 target 全绿 | tag-push 后验 |
| 两台用户机重跑 install.sh 验证 | tag-ship 后验 |

---

## 6. 不在范围(V0.7 候选,本版不做)

- macOS universal binary(目前 macos-arm64 / macos-x64 两份独立 tarball,够用)
- Windows native build(WSL2 走 linux-x64 musl binary,foundation 仍 unix-only,见 release.yml 头部注释)
- `cargo install --git` fallback 路径优化(install.sh `error: download failed` 时仍可手动 fallback,主路径 musl 通了之后用户基本不会触发)
- Linux 32-bit / armv7 / riscv64 prebuilt(用户基数极小,需要时再扩 matrix)

---

## 7. Acceptance(用户验)

V0.6.7 tag push → release.yml 跑完 → 两台原本报 `GLIBC_2.39 not found` 的机器重跑:

```sh
curl -sSL https://raw.githubusercontent.com/firstintent/ccteam/main/install.sh | sh
ccteam --version
# 应输出: ccteam 0.6.7
```

成功 = patch 闭环。
11 changes: 5 additions & 6 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ detect_target() {
SUFFIX="linux-x64"
EXT="tar.gz"
;;
linux-aarch64|linux-arm64)
SUFFIX="linux-arm64"
EXT="tar.gz"
;;
darwin-arm64|darwin-aarch64)
SUFFIX="macos-arm64"
EXT="tar.gz"
Expand All @@ -65,14 +69,9 @@ detect_target() {
SUFFIX="macos-x64"
EXT="tar.gz"
;;
linux-aarch64|linux-arm64)
err "linux-arm64 prebuilt is not yet published (planned post-V0.7)."
err "Workaround: cargo install --git https://github.com/$REPO ccteam-cli"
exit 1
;;
*)
err "unsupported platform: $_os-$_arch"
err "Supported: linux-x86_64, darwin-arm64, darwin-x86_64."
err "Supported: linux-x86_64, linux-aarch64, darwin-arm64, darwin-x86_64."
err "Workaround: cargo install --git https://github.com/$REPO ccteam-cli"
exit 1
;;
Expand Down
Loading