Skip to content

th-cc50cd: OpenCode lifecycle plugin — sessions on the th-mail bus #1375

th-cc50cd: OpenCode lifecycle plugin — sessions on the th-mail bus

th-cc50cd: OpenCode lifecycle plugin — sessions on the th-mail bus #1375

Workflow file for this run

name: PR Checks
on:
pull_request:
branches: [main]
# Also fire on direct push to main so the branch carries a
# completed-check-run history. Required by branch-protection's
# "require status checks" rule — without push triggering these,
# an admin-bypass hotfix lands with no check history. Pearl
# th-e392d9.
push:
branches: [main]
merge_group:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
# dorny/paths-filter queries a PR's changed files through the API.
permissions:
contents: read
pull-requests: read
jobs:
rust:
# Pearl th-a165b4: Windows joins the test matrix so cross-platform
# breakage is caught at PR time rather than at release time. Linux
# stays the canonical gate — it alone runs fmt/clippy/release-build
# (those are platform-independent, so duplicating them just burns
# Windows minutes, which bill at 2x).
name: Rust checks (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
# Report both platforms on a failure — knowing whether a break is
# Windows-only or universal is the whole point of the matrix.
fail-fast: false
matrix:
include:
- os: ubuntu-latest
test_args: ''
# smooth-daemon JOINED this lane in th-a59af5. It is Big
# Smooth itself, so excluding it meant the actual product
# was never compiled — let alone tested — on a platform we
# intend to ship to, and every Windows break in it landed
# green. The blocker was one leaf dependency: web-push ->
# ece -> openssl-sys, and windows-latest has no OpenSSL (no
# vcpkg tree, no OPENSSL_DIR). `web-push` is now declared
# only for non-Windows targets, so Windows gives up phone
# notifications (/push/* 503s there) and gains the whole
# agent engine. Do not re-add the exclude to make a red
# Windows build green — that is the bug it was hiding.
#
# smooth-diver's e2e and six smooth-pearls test modules
# drive a real pearl store, which shells out to the
# smooth-dolt binary — a CGO Go binary needing ICU, with no
# Windows build (see the skipped build step above). They are
# filtered out by name rather than passing vacuously. The
# rest of smooth-pearls (dolt.rs, registry, the non-Unix
# dolt_server stub) still runs here.
- os: windows-latest
test_args: >-
--workspace
--exclude smooai-smooth-diver
-E 'not (package(smooai-smooth-pearls) & test(/^(agents|memory|memory_tools|messaging|store|tools)::/))'
steps:
- uses: actions/checkout@v4
# th-6578ee: a bash/JSON/doc-only PR was compiling the whole Rust
# workspace on TWO platforms (Windows bills at 2x) plus a full web
# build — ~45 min of runner time to validate a shell script.
#
# The filter gates STEPS, not the job. The job must still run and
# report: branch protection requires these checks, and a workflow-
# level `paths:` would make them never appear at all, blocking the PR
# forever. Same reason the `push:` trigger exists (pearl th-e392d9).
#
# PR events only. On push-to-main and merge_group there is no
# reliable base to diff against, and those are exactly the moments a
# skipped check would be expensive to be wrong about — so they run
# everything.
- name: Detect changes
id: filter
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@v3
with:
filters: |
rust:
- 'crates/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- 'rustfmt.toml'
- 'go/**'
- 'scripts/build-smooth-dolt.sh'
- '.github/workflows/pr-checks.yml'
# One boolean instead of repeating the compound condition on a dozen
# steps. `shell: bash` because the Windows leg defaults to pwsh,
# where `>> $GITHUB_OUTPUT` is `$env:GITHUB_OUTPUT`.
- name: Gate
id: gate
shell: bash
run: echo "run=${{ github.event_name != 'pull_request' || steps.filter.outputs.rust == 'true' }}" >>"$GITHUB_OUTPUT"
- name: Install system dependencies
if: steps.gate.outputs.run == 'true' && runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libcap-ng-dev libicu-dev pkg-config protobuf-compiler
# No apt on Windows — protoc is the only native build-time tool the
# workspace needs there (tonic-build in smooth-scribe et al.).
- name: Install protoc
if: steps.gate.outputs.run == 'true' && runner.os == 'Windows'
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: dtolnay/rust-toolchain@stable
if: steps.gate.outputs.run == 'true'
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
if: steps.gate.outputs.run == 'true'
- uses: pnpm/action-setup@v4
if: steps.gate.outputs.run == 'true'
- uses: actions/setup-node@v4
if: steps.gate.outputs.run == 'true'
with:
node-version: 22
- name: Build web UI
if: steps.gate.outputs.run == 'true'
shell: bash
run: |
cd crates/smooth-web/web
pnpm install --no-frozen-lockfile
pnpm build
# smooth-dolt is a CGO Go binary. On Linux/macOS the gozstd +
# go-icu-regex CGO deps want ICU (build-smooth-dolt.sh points CGO
# at Homebrew/apt ICU). On Windows the `gms_pure_go` build tag drops
# the ICU path entirely, so only a C compiler (mingw gcc, present on
# the runner) is needed — proven on a Windows SSM box, see
# docs/Operations/Windows-Build-Box-Runbook.md. Pearl-store *tests*
# still skip on Windows (they need the Unix-socket dolt server; the
# TCP transport is pearl th-5f35a5) — but the binary must keep
# compiling so it can't silently regress with another unix-only call.
- name: Build smooth-dolt (embedded Dolt for pearl memory tests)
if: steps.gate.outputs.run == 'true' && runner.os == 'Linux'
run: bash scripts/build-smooth-dolt.sh
- name: Build smooth-dolt (Windows — CGO via mingw, gms_pure_go drops ICU)
if: steps.gate.outputs.run == 'true' && runner.os == 'Windows'
shell: bash
run: cd go/smooth-dolt && CGO_ENABLED=1 go build -tags gms_pure_go -o smooth-dolt.exe .
- name: Install nextest
if: steps.gate.outputs.run == 'true'
uses: taiki-e/install-action@nextest
- name: Format check
if: steps.gate.outputs.run == 'true' && runner.os == 'Linux'
run: cargo fmt --check
- name: Clippy
if: steps.gate.outputs.run == 'true' && runner.os == 'Linux'
# Honor the lint levels declared in [workspace.lints]: clippy::all
# (deny) + unused_must_use/unsafe_code fail the build; pedantic and
# nursery are advisory `warn` by design, so a blanket `-D warnings`
# would weaponize them (and every new lint a stable Rust bump adds).
run: cargo clippy
- name: Build examples (needed by cross-process file-lock test, pearl th-9799fa)
if: steps.gate.outputs.run == 'true'
run: cargo build --examples --workspace
# bash on both legs so the filter expression quotes predictably
# (pwsh would need its own escaping for the `&` and parentheses).
- name: Test
if: steps.gate.outputs.run == 'true'
shell: bash
run: cargo nextest run --profile ci ${{ matrix.test_args }}
env:
NEXTEST_EXPERIMENTAL_LIBTEST_JSON: 1
# One report per PR — publishing from both legs would double every
# entry in the check summary.
- name: Publish test report
if: always() && steps.gate.outputs.run == 'true' && runner.os == 'Linux'
uses: ctrf-io/github-test-reporter@v1
with:
report-path: target/nextest/ci/junit.xml
report-format: junit
continue-on-error: true
- name: Build
if: steps.gate.outputs.run == 'true' && runner.os == 'Linux'
run: cargo build --release -p smooai-smooth-cli
web:
name: Web checks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# Ungated on purpose: this job is a required check, and a changeset
# naming any package other than '@smooai/smooth' breaks the Release
# workflow's `changeset version` on main (it has recurred three times).
- name: Changeset package names
run: |
bad=$(grep -HEn "^['\"]?[@A-Za-z0-9/_-]+['\"]?: *(patch|minor|major)\s*$" .changeset/*.md | grep -v "@smooai/smooth" || true)
if [ -n "$bad" ]; then
echo "$bad"
echo "::error::changesets must name '@smooai/smooth' — any other package name breaks Release's changeset version"
exit 1
fi
# Same step-gating rationale as the rust job above: the job must keep
# reporting for branch protection, so only the work is skipped.
- name: Detect changes
id: filter
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@v3
with:
filters: |
web:
- 'crates/smooth-web/web/**'
- '.github/workflows/pr-checks.yml'
- name: Gate
id: gate
run: echo "run=${{ github.event_name != 'pull_request' || steps.filter.outputs.web == 'true' }}" >>"$GITHUB_OUTPUT"
- uses: pnpm/action-setup@v4
if: steps.gate.outputs.run == 'true'
- uses: actions/setup-node@v4
if: steps.gate.outputs.run == 'true'
with:
node-version: 22
- name: Install
if: steps.gate.outputs.run == 'true'
run: cd crates/smooth-web/web && pnpm install --no-frozen-lockfile
- name: Build
if: steps.gate.outputs.run == 'true'
run: cd crates/smooth-web/web && pnpm build