diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d2aa777 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +jobs: + test: + name: hook contract tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + - run: node --test tests/*.test.mjs + + fixtures-drift: + name: fixtures match lich + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Refresh from omartelo/lich@main + run: tests/refresh-fixtures.sh + - name: Fail if the vendored copies drifted + run: | + git diff --exit-code -- tests/fixtures || { + echo "::error::A hook contract moved in lich. Run tests/refresh-fixtures.sh, then make the scripts match." + exit 1 + } diff --git a/CHANGELOG.md b/CHANGELOG.md index db4f0ab..56b28f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- **The hook payloads are asserted against lich's contract fixtures.** lich + publishes every hook contract as bytes (`docs/hooks/fixtures/*.jsonl` there, + one case per line: the payloads it accepts and the ones it refuses) and + asserts its endpoints against them. This repository now asserts the other + half: `node --test tests/*.test.mjs` runs every hook script as a real + subprocess — from the command line its registration actually spells, for both + harnesses — against a stub HTTP server, and checks the body it POSTs matches + an accepted shape, matches no rejected one, lands on the right endpoint with + the right `?token=`, and never sends the deprecated `claude_session_id`. It + also pins the client rules: no report without the full lich environment, exit + 0 and silence when lich answers 500 or refuses the connection. The fixtures + are vendored (`tests/fixtures/`, refreshed by `tests/refresh-fixtures.sh`) so + the suite never needs the network, and CI diffs the copies against lich on + every run. A field that moves in either repository now goes red in both. + +### Fixed + +- **A blank session title is no longer reported.** `report-title.sh` checked + that it had extracted *something* before posting, which a title of nothing but + spaces passes — and lich rejects a blank title with a 400. Codex made it + reachable: it names a thread after its first user message, so a prompt whose + first line is indentation produced exactly that payload. The title is trimmed + before the check now, which also matches what lich stores. + ## [0.6.0] - 2026-08-09 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index cfa46e0..d752c65 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,6 +14,7 @@ hooks/codex-hooks.json # hook registration, Codex hooks/ # hook scripts ($CLAUDE_PLUGIN_ROOT/hooks/