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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ jobs:
command: pnpm run lint
- name: Build
command: pnpm run build
- name: Conformance Smoke
command: pnpm run conformance:run -- --case acp.v1.initialize.handshake
- name: Test
node_version: 22
command: pnpm run test:coverage
Expand Down
176 changes: 176 additions & 0 deletions .github/workflows/conformance-nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
name: Conformance Nightly

on:
schedule:
- cron: "20 3 * * *"
workflow_dispatch:
inputs:
run_real_adapters:
description: "Run real-adapter smoke matrix in this manual run"
required: false
default: false
type: boolean
strict_real_adapters:
description: "Fail workflow when any real-adapter smoke job fails"
required: false
default: false
type: boolean

concurrency:
group: conformance-nightly-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

env:
NODE_VERSION: 24
PNPM_VERSION: 10.23.0

jobs:
conformance-mock:
name: Conformance (Mock Full)
runs-on: blacksmith-16vcpu-ubuntu-2404
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tags: false
submodules: false

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
check-latest: true
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run mock conformance profile
run: |
set -euo pipefail
mkdir -p conformance-artifacts
pnpm run conformance:run -- \
--format json \
--report conformance-artifacts/mock-report.json

- name: Add mock summary
run: |
set -euo pipefail
node - <<'NODE'
const fs = require("node:fs");

const reportPath = "conformance-artifacts/mock-report.json";
const report = JSON.parse(fs.readFileSync(reportPath, "utf8"));
const lines = [
"### Conformance (Mock Full)",
"",
`- Cases: ${report.totals.cases}`,
`- Passed: ${report.totals.passed}`,
`- Failed: ${report.totals.failed}`,
];
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${lines.join("\n")}\n`);
NODE

- name: Upload mock report
uses: actions/upload-artifact@v4
with:
name: conformance-mock-report
path: conformance-artifacts/mock-report.json
if-no-files-found: error

conformance-real-adapters:
name: Conformance (Real Adapter Smoke)
needs: conformance-mock
if: ${{ vars.ACPX_CONFORMANCE_REAL == '1' || (github.event_name == 'workflow_dispatch' && github.event.inputs.run_real_adapters == 'true') }}
runs-on: blacksmith-16vcpu-ubuntu-2404
permissions:
contents: read
continue-on-error: ${{ !(github.event_name == 'workflow_dispatch' && github.event.inputs.strict_real_adapters == 'true') }}
strategy:
fail-fast: false
matrix:
include:
- id: pi
command: "npx -y pi-acp"
- id: codex
command: "npx -y @zed-industries/codex-acp"
- id: claude
command: "npx -y @zed-industries/claude-agent-acp"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tags: false
submodules: false

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
check-latest: true
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run adapter handshake smoke case
run: |
set -euo pipefail
mkdir -p conformance-artifacts
pnpm run conformance:run -- \
--format json \
--agent-command '${{ matrix.command }}' \
--case acp.v1.initialize.handshake \
--report "conformance-artifacts/${{ matrix.id }}-report.json"

- name: Add adapter summary
if: always()
run: |
set -euo pipefail
REPORT="conformance-artifacts/${{ matrix.id }}-report.json"
if [ ! -f "$REPORT" ]; then
node - <<'NODE'
const fs = require("node:fs");
const lines = [
"### Adapter Smoke: ${{ matrix.id }}",
"",
"- Result: report not produced (adapter failed before report write)",
];
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${lines.join("\n")}\n`);
NODE
exit 0
fi
node - <<'NODE'
const fs = require("node:fs");
const reportPath = "conformance-artifacts/${{ matrix.id }}-report.json";
const report = JSON.parse(fs.readFileSync(reportPath, "utf8"));
const lines = [
"### Adapter Smoke: ${{ matrix.id }}",
"",
`- Passed: ${report.totals.passed}`,
`- Failed: ${report.totals.failed}`,
];
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${lines.join("\n")}\n`);
NODE

- name: Upload adapter report
if: always()
uses: actions/upload-artifact@v4
with:
name: conformance-${{ matrix.id }}-report
path: conformance-artifacts/${{ matrix.id }}-report.json
if-no-files-found: ignore
81 changes: 81 additions & 0 deletions .pi/prompts/landpr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
description: Land a PR (merge with proper workflow)
---

Input

- PR: $1 <number|url>
- If missing: use the most recent PR mentioned in the conversation.
- If ambiguous: ask.

Do (end-to-end)
Goal: PR must end in GitHub state = MERGED (never CLOSED). Prefer `gh pr merge --squash`; use `--rebase` only when preserving commit history is required.

1. Assign PR to self:
- `gh pr edit <PR> --add-assignee @me`
2. Repo clean:
- `git status`
3. Identify PR meta:

```sh
gh pr view <PR> --json number,title,author,headRefName,baseRefName,headRepository,maintainerCanModify --jq '{number,title,author:.author.login,head:.headRefName,base:.baseRefName,headRepo:.headRepository.nameWithOwner,maintainerCanModify}'
contrib=$(gh pr view <PR> --json author --jq .author.login)
head=$(gh pr view <PR> --json headRefName --jq .headRefName)
head_repo_url=$(gh pr view <PR> --json headRepository --jq .headRepository.url)
```

4. Fast-forward base:
- `git checkout main`
- `git pull --ff-only`
5. Create temp base branch from main:
- `git checkout -b temp/landpr-<ts-or-pr>`
6. Check out PR branch locally:
- `gh pr checkout <PR>`
7. Rebase PR branch onto temp base:
- `git rebase temp/landpr-<ts-or-pr>`
- Fix conflicts and keep history tidy.
8. Fix + tests + changelog:
- Implement fixes and adjust tests as needed.
- Update [`CHANGELOG.md`](../../CHANGELOG.md) for user-facing changes under `## Unreleased`.
9. Validation gate:
- Docs-only changes: `pnpm run check:docs`
- Code changes: `pnpm run check`
- Code + docs changes: run both
10. Final merge-ready commit:

- Use a concise message and include the PR number when appropriate, for example:
- `git commit -m "fix(conformance): harden runner startup and cwd handling (#130)"`
- `land_sha=$(git rev-parse HEAD)`

11. Push updated PR branch:

```sh
git remote add prhead "$head_repo_url.git" 2>/dev/null || git remote set-url prhead "$head_repo_url.git"
git push --force-with-lease prhead HEAD:$head
```

12. Merge PR:

- Squash (preferred): `gh pr merge <PR> --squash`
- Rebase (history-preserving fallback): `gh pr merge <PR> --rebase`
- Never `gh pr close`

13. Sync main:

- `git checkout main`
- `git pull --ff-only`

14. Comment on PR with what landed:

```sh
merge_sha=$(gh pr view <PR> --json mergeCommit --jq '.mergeCommit.oid')
gh pr comment <PR> --body "Landed via temp rebase onto main.\n\n- Gate: validation completed for this repo's change scope\n- Land commit: $land_sha\n- Merge commit: $merge_sha\n\nThanks @$contrib!"
```

15. Verify PR state == MERGED:

- `gh pr view <PR> --json state --jq .state`

16. Delete temp branch:

- `git branch -D temp/landpr-<ts-or-pr>`
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,38 @@ Harness documentation synchronization policy:
- `pnpm run check:docs` — docs format and markdown lint
- `pnpm run perf:report` — performance reporting helper

## Testing And Changelog Guidelines

- Run `pnpm run test` or `pnpm run test:coverage` before pushing when you touch
runtime logic.
- Changelog entries should cover user-facing changes only. Do not add internal
release-process or meta-only notes.
- Changelog placement: add new entries under [`CHANGELOG.md`](CHANGELOG.md)
`## Unreleased`, appending to the end of the target section (`### Changes`,
`### Breaking`, or `### Fixes`) instead of inserting at the top.
- Changelog attribution: use concise `Thanks @author` attribution and avoid
repeating multiple attribution styles in the same line.
- Pure test-only changes generally do not need a changelog entry unless they
change user-visible behavior or the maintainer explicitly wants one.

## Commit And Pull Request Guidelines

- Repo-local `/landpr` instructions live at [`.pi/prompts/landpr.md`](.pi/prompts/landpr.md).
When landing or merging a PR in this repo, follow that process.
- Before `/landpr`, run `/reviewpr` and require explicit evidence for bug-fix
claims. Do not merge bug-fix PRs based only on issue text, PR text, or AI
rationale.
- Minimum merge gate for bug-fix PRs:
1. symptom evidence (repro, log, or failing test)
2. verified root cause in code with file/line
3. fix touches the implicated code path
4. regression test when feasible; otherwise include manual verification proof
and why no test was added
- Use concise, action-oriented commit messages and keep unrelated refactors out
of the same commit when possible.
- Group changelog updates with the PR that introduces the user-facing change
instead of batching them later.

## Fundamental acpx Calls

Use these examples when you need the most basic `acpx` flows while developing
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Repo: https://github.com/openclaw/acpx

### Changes

- Conformance/ACP: add a data-driven ACP core v1 conformance suite with CI smoke coverage, nightly coverage, and a hardened runner that reports startup failures cleanly and scopes filesystem checks to the session cwd. (#130) Thanks @lynnzc.

### Breaking

### Fixes
Expand Down
Loading