Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
7e649d3
Chaining(fix[command]): Make command values immutable
tony Aug 29, 2026
484afc4
ControlMode(fix[correlation]): Fence typed command replies
tony Aug 29, 2026
c4a4bad
ControlMode(fix[io]): Bound process output
tony Aug 29, 2026
108d855
ControlMode(fix[lifecycle]): Preserve in-flight replies
tony Aug 29, 2026
6605fd5
ControlMode(fix[bounds]): Cap outstanding work
tony Aug 29, 2026
5378f4b
ControlMode(fix[cleanup]): Bound asynchronous disposal
tony Aug 29, 2026
af60800
ControlMode(fix[framing]): Reject orphaned guards
tony Aug 29, 2026
4d57565
ControlMode(fix[identity]): Attest the attached server
tony Aug 29, 2026
e78b720
Versioning(fix[capabilities]): Support stable releases
tony Aug 29, 2026
56a7b17
Versioning(test[capabilities]): Bind intervals to evidence
tony Aug 29, 2026
b124b93
QueryJson(fix[validation]): Fail closed at wire boundary
tony Aug 29, 2026
2818ea9
QueryJson(fix[contract]): Restore canonical v1 wire
tony Aug 29, 2026
2c434c6
Query(fix[regex]): Freeze culture semantics
tony Aug 29, 2026
bea2777
QueryJson(fix[grammar]): Enforce the closed wire shape
tony Aug 29, 2026
c83d3cc
Query(fix[semantics]): Validate the closed AST
tony Aug 29, 2026
d362ef5
QueryJson(test[goldens]): Bind wire tests to evidence
tony Aug 29, 2026
933f884
QueryJson(refactor[wire]): Split reader and rules
tony Aug 29, 2026
eb07dd9
QueryJson(docs[wire]): Show canonical v1 document
tony Aug 29, 2026
8cd7263
Packaging(fix[restore]): Isolate consumer cache
tony Aug 29, 2026
3614b55
QueryJson(test[closure]): Reach packed and native paths
tony Aug 29, 2026
29088e0
Workspace(fix[parser]): Enforce the supported YAML shape
tony Aug 29, 2026
66e1781
Workspace(fix[builder]): Match tmuxp selection semantics
tony Aug 29, 2026
1464459
Query(fix[catalog]): Separate scalar and relation roles
tony Aug 29, 2026
3565550
QueryJson(fix[schema]): Remove phantom string operators
tony Aug 29, 2026
9026ac1
Query(fix[translation]): Preserve overload semantics
tony Aug 29, 2026
d7d2b37
Query(fix[trimming]): Expose reflective metadata contract
tony Aug 29, 2026
27091e8
Workspace(build[api]): Gate the public surface
tony Aug 29, 2026
935eff6
Packaging(test[workspace]): Reach the shipped package
tony Aug 29, 2026
ab6d420
Workspace(docs[contract]): State failure boundaries
tony Aug 29, 2026
0e8f0f1
Query(test[parity]): Invoke wire predicate
tony Aug 29, 2026
3ab82bc
Query(fix[binding]): Match exact entity types
tony Aug 29, 2026
956ed10
Query(fix[numbers]): Preserve integer semantics
tony Aug 29, 2026
01230b6
QueryJson(fix[regex]): Reject malformed patterns
tony Aug 29, 2026
e90a1b0
Query(fix[nulls]): Distinguish missing members
tony Aug 29, 2026
08be7d6
Query(fix[ids]): Preserve projected ID equality
tony Aug 29, 2026
2258e83
Query(fix[depth]): Capture scalar relations
tony Aug 29, 2026
b1bce64
Query(perf[compile]): Bind plans once
tony Aug 29, 2026
80bf7ef
Query(fix[translation]): Keep constant capture pure
tony Aug 29, 2026
efa725b
ControlMode(fix[events]): Honor backlog cancellation
tony Aug 29, 2026
78b304d
ControlMode(fix[protocol]): Reject stray output
tony Aug 29, 2026
53fcf7d
Workspace(fix[layouts]): Report tmux rejections
tony Aug 29, 2026
a6c5ef1
Workspace(fix[result]): Freeze returned collections
tony Aug 29, 2026
7e16667
Query(refactor[execution]): Keep typed matching local
tony Aug 29, 2026
5a4cb3a
Packaging(test[aot]): Prove packed artifacts
tony Aug 29, 2026
a0c8bd9
Engineering(refactor[plan]): Retire closed scaffold
tony Aug 29, 2026
280dcd3
Engineering(fix[tests]): Import source binder normally
tony Aug 29, 2026
aaf731e
Docs(fix[decisions]): Give capability ADR a unique number
tony Aug 29, 2026
3d0d662
Query(refactor[catalog]): Drop private generator
tony Aug 29, 2026
1bf33f1
Window(fix[layout]): Validate custom prefix
tony Aug 29, 2026
d6644d8
ControlMode(fix[limits]): Count before rendering
tony Aug 29, 2026
8893e9e
Query(fix[json]): Bound structural traversal first
tony Aug 29, 2026
48a65e9
ControlMode(fix[events]): Surface pump failures
tony Aug 29, 2026
0204f41
Docs(fix[claims]): Match current proof boundaries
tony Aug 29, 2026
7e0d6e6
ControlMode(test[argv]): Use a portable literal oracle
tony Aug 29, 2026
947207a
Pane(fix[input]): Keep text out of key mode
tony Aug 29, 2026
2912a7a
Workspace(fix[startup]): Wait for shell acknowledgement
tony Aug 29, 2026
1eea902
Query(fix[execution]): Honor aggregate cancellation
tony Aug 29, 2026
b6f27ad
Query(refactor[constants]): Remove unreachable literal kinds
tony Aug 29, 2026
b54949d
API(fix[surface]): Close contract exemptions
tony Aug 29, 2026
925713d
Server(refactor[files]): Split utility families
tony Aug 29, 2026
6220379
Pane(refactor[files]): Split operation families
tony Aug 29, 2026
39be171
Window(refactor[files]): Split operation families
tony Aug 29, 2026
c033cec
Chaining(refactor[files]): Split request domains
tony Aug 29, 2026
7085453
ControlMode(fix[eof]): Reject truncated control streams
tony Aug 29, 2026
11a76f0
Query(fix[structure]): Bound direct document traversal
tony Aug 29, 2026
cdc4f33
Workspace(fix[readiness]): Keep probes out of pane input
tony Aug 29, 2026
abceb15
Compatibility(feat[tmux]): Prove tmux 3.7c
tony Aug 29, 2026
3fa133d
Hierarchy(refactor[delivery]): Separate subscriber state
tony Aug 29, 2026
481a3c8
Parity(fix[generation]): Preserve version adaptation
tony Aug 29, 2026
9137c07
Query(fix[depth]): Validate the complete document
tony Aug 29, 2026
d5e2e40
Hierarchy(fix[invalidation]): Track selection changes
tony Aug 29, 2026
027ebf8
Waiting(feat[channels]): Hold a wait across timed attempts
tony Aug 29, 2026
cc7436a
Mcp(fix[wait]): Stop handing signals to abandoned waiters
tony Aug 29, 2026
a62e956
Waiting(docs[channels]): Warn that withdrawal wakes every waiter
tony Aug 29, 2026
25d2de3
Jobs(refactor[disposal]): Drop the blocking dispose
tony Aug 29, 2026
bbbceb8
Engineering(build[python]): Lock what the validators run on
tony Aug 29, 2026
6a70916
Compatibility(refactor[versions]): Decide the version list once
tony Aug 29, 2026
412e48b
Engineering(refactor[swap]): Separate JSONC from the swap
tony Aug 29, 2026
1e4634f
Engineering(refactor[swap]): Split building from config editing
tony Aug 29, 2026
7cc3672
Docs(fix[api]): Regenerate the reference for the wait channel
tony Aug 29, 2026
91748d2
Docs(fix[contributing]): Say which tmux the tests should use
tony Aug 29, 2026
91d7c69
Materialization(perf[reads]): Read one entity with one command
tony Aug 29, 2026
52f0742
Api(fix[visibility]): Stop shipping a type the contract calls internal
tony Aug 29, 2026
c5b7340
Contract(fix[materialization]): Record what the query actually is
tony Aug 29, 2026
9c8f2f5
Connection(refactor[dialect]): Decide the multiplexer once
tony Aug 29, 2026
6501eb3
Connection(refactor[dialect]): Publish the banner without a lock
tony Aug 29, 2026
2c90101
Chaining(fix[commands]): Name the session a window is created in
tony Aug 29, 2026
60788a7
Hierarchy(fix[ownership]): Give every handle the server it came from
tony Aug 29, 2026
e2e6c42
Docs(fix[formats]): Say which names tmux expands before storing
tony Aug 29, 2026
13ed8df
Engineering(test[capabilities]): Read the escape gate from one place
tony Aug 29, 2026
b8c0b90
Docs(fix[contributing]): List every document check CI runs
tony Aug 29, 2026
c91c402
Docs(feat[one-shot]): State what bounds a command
tony Aug 29, 2026
dfbcf20
Engineering(fix[quality]): Measure the gates CI runs
tony Aug 29, 2026
fdf3da7
Docs(fix[contract]): Say which packages the contract covers
tony Aug 29, 2026
5c80586
Docs(fix[contributing]): Build before checking the API reference
tony Aug 29, 2026
eda5227
Docs(fix[contributing]): Evict the packed version before the package …
tony Aug 29, 2026
6a245ef
Chaining(fix[generation]): Pin every command built from an entity
tony Aug 29, 2026
629a26a
Workspace(test[readiness]): Give the builder tests a shared-machine b…
tony Aug 29, 2026
06fd46c
Hierarchy(fix[lookup]): Refuse a lookup answered by another server
tony Aug 29, 2026
1963f4d
Chaining(fix[formats]): Say which popup and menu arguments tmux expands
tony Aug 29, 2026
fe59b0c
Requests(fix[formats]): Say that a start directory is a format too
tony Aug 29, 2026
67aecbb
Mcp(fix[jobs]): Say why a job was lost
tony Aug 29, 2026
ba534d4
Mcp(test[protocol]): Stop clamping the wait these tests ask for
tony Aug 29, 2026
081e368
ControlMode(test[restart]): Let the old daemon go before the successor
tony Aug 29, 2026
2f00741
Hierarchy(refactor[scopes]): Put an entity's tables in one file
tony Aug 29, 2026
76a0b37
Tests(fix[budget]): Wait one budget rather than twenty-four literals
tony Aug 29, 2026
cfc1984
Psmux(fix[trust]): Read the audited build markers from the pin
tony Aug 29, 2026
66224b3
Async(fix[context]): Configure the await on a using declaration too
tony Aug 29, 2026
0b7f762
Chaining(fix[generation]): Pin an option and hook command too
tony Aug 29, 2026
a1f9914
Requests(fix[formats]): Say that an option and hook name is a format
tony Aug 29, 2026
1238f2b
Materialization(fix[3.2a]): Avoid unsafe formats
tony Aug 30, 2026
b28276d
Build(fix[uv]): Refresh engineering test lock
tony Aug 30, 2026
2db0d59
Workspace(test[budgets]): Scale readiness waits
tony Aug 30, 2026
e2bc689
Workspace(test[macos]): Pin readiness shell
tony Aug 30, 2026
ca42197
Workspace(test[macos]): Use real shell fixture
tony Aug 30, 2026
68b9dc6
Workspace(test[macos]): Pin Bash startup
tony Aug 30, 2026
52b6652
Waiting(fix[attribution]): Report withdrawal races
tony Aug 30, 2026
6e0198c
Jobs(fix[shutdown]): Withdraw owned waiters
tony Aug 30, 2026
521df13
Waiting(fix[disposal]): Join concurrent cleanup
tony Aug 30, 2026
8d1e462
Waiting(fix[withdrawal]): Signal faulted waiters
tony Aug 30, 2026
0fddfb2
Waiting(fix[withdrawal]): Classify completed failures
tony Aug 30, 2026
4b9f639
Waiting(docs[comment]): Clarify expired attempts
tony Aug 30, 2026
b8077ff
Waiting(docs[comment]): Distinguish wait ownership
tony Aug 30, 2026
1070d93
Docs(fix[changelog]): Record user-visible changes
tony Aug 30, 2026
911a935
Client(fix[control-mode]): Use tmux field name
tony Aug 30, 2026
7562083
Workspace(fix[failure]): Report partial state
tony Aug 30, 2026
c5555c4
Docs(fix[examples]): Avoid duplicate Enter
tony Aug 30, 2026
7da43a5
Tests(fix[wrapper]): Publish atomically
tony Aug 30, 2026
405381e
Merge remote-tracking branch 'origin/master' into improvements-00
tony Aug 30, 2026
6c444e2
Docs(docs[changelog]): Record review fixes
tony Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
143 changes: 116 additions & 27 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,43 @@ from `global-json-file` and calls `dotnet` directly, so a workflow file never
carries the prefix.

The validators are Python and run through [uv](https://docs.astral.sh/uv/).
There is no Python project file — each script carries its own PEP 723 header.
There is no Python project file — each script carries its own PEP 723 header,
and a script with dependencies carries a `.lock` beside it so the gate resolves
the same versions every run:

```console
$ uv lock --script eng/run_tests.py
```

Run the engineering tests through that locked runner rather than naming pytest
on the command line, which resolves whatever released that morning:

```console
$ uv run --locked --script eng/run_tests.py
```

Nine of those tests read a pinned revision of the Python library. Point
`LIBTMUX_PYTHON_REPOSITORY` at a checkout of
[tmux-python/libtmux](https://github.com/tmux-python/libtmux) that contains it,
or they fail saying which revision they wanted.

You also need a real `tmux`, version 3.2a or newer. The suite drives one
rather than mocking it, because this library's job is being right about tmux
and only tmux can say whether it is.

Name that tmux explicitly when the machine has more than one:

```console
$ export LIBTMUX_TMUX=/usr/local/bin/tmux
```

Without it the tests spawn whatever `tmux` their own `PATH` resolves, while a
command they send into a pane resolves it again through that pane's
interactive shell. A version-matrix install earlier on the interactive `PATH`
makes those two different binaries, and a client cannot talk to a server of
another version. What you see is `tmux_run` timing out with no exit status,
which reads as a library bug rather than as two tmuxes.

## Own your tmux socket root

Give this repository a socket root of its own before running anything:
Expand Down Expand Up @@ -141,6 +172,12 @@ $ mise exec -- dotnet pack \
$ uv run python eng/parity/inspect_packages.py
```

```console
$ mise exec -- dotnet restore \
tests/LibTmux.PackageConsumer/LibTmux.PackageConsumer.csproj \
--configfile tests/NuGet.config
```

```console
$ mise exec -- dotnet run \
--project tests/LibTmux.PackageConsumer/LibTmux.PackageConsumer.csproj \
Expand All @@ -149,27 +186,40 @@ $ mise exec -- dotnet run \
--no-restore
```

```console
$ mise exec -- dotnet restore \
tests/LibTmux.AotSmoke/LibTmux.AotSmoke.csproj \
--runtime linux-x64 \
--configfile tests/NuGet.config
```

```console
$ mise exec -- dotnet publish \
tests/LibTmux.AotSmoke/LibTmux.AotSmoke.csproj \
--configuration Release \
--framework net10.0 \
--runtime linux-x64
--runtime linux-x64 \
--no-restore
```

`LibTmux.PackageConsumer` is deliberately absent from `LibTmux.slnx`. It exists
to prove the packaged artifact rather than a project reference, so it restores
and runs standalone.
`LibTmux.PackageConsumer` and `LibTmux.AotSmoke` are deliberately absent from
`LibTmux.slnx`. Both restore the packed artifacts rather than project
references, so they run only after `dotnet pack`.

### Validators that read documents, not the build

Five checks run against documents rather than code, which is what makes them
easy to forget locally:
Eight checks run against documents rather than code, which is what makes them
easy to forget locally. They are listed here in the order
[`dotnet.yml`](workflows/dotnet.yml) runs them:

```console
$ uv run python eng/parity/verify_public_api.py
```

```console
$ uv run python eng/parity/render_public_api.py --check
```

```console
$ uv run python eng/parity/verify_capabilities.py
```
Expand All @@ -178,6 +228,14 @@ $ uv run python eng/parity/verify_capabilities.py
$ uv run python eng/parity/verify_workflows.py
```

```console
$ uv run python eng/parity/verify_tmux_versions.py
```

```console
$ uv run python eng/docs/render_api_reference.py --check
```

```console
$ uv run python eng/docs/sync_snippets.py --check
```
Expand All @@ -186,6 +244,15 @@ $ uv run python eng/docs/sync_snippets.py --check
$ uv run eng/mcp/dump_tools.py --check
```

The two renderers hold `docs/api/README.md` and `docs/public-api.md` to the
documents they are generated from. Adding a public member without recording it
fails `render_api_reference.py --check` and nothing before it, so run the whole
list rather than the first few.

`render_api_reference.py` reads the XML documentation the compiler emitted, so
build before running it. Against stale output it reports a difference that is
not there.

`sync_snippets.py --check` is the one that catches a hand-edited example. It
compares each published block against the region it was quoted from and fails
on any difference, so bring a change across rather than typing it into the
Expand All @@ -208,23 +275,31 @@ The engineering scripts have tests of their own:
$ uv run --with pytest --with tomlkit python -m pytest eng --quiet
```

### NU1004, which is not a dependency problem
### AOT restore ownership

Publishing ahead of time names a runtime identifier, and restore then writes
one into the lock file of every project in that graph — including the
library's, where the section is empty because no package resolves differently.
That is why `src/LibTmux` and `src/LibTmux.Generators` declare
`RuntimeIdentifiers`: without it the lock files disagree with the projects and
the *next* `restore --locked-mode` fails with NU1004, which reads like a
dependency problem and is not one.
Only `LibTmux.AotSmoke` names a runtime identifier. The libraries and their
lock files stay portable because the smoke project consumes their packages
instead of adding its runtime to their project graph. The smoke project has no
checked-in lock: its package inputs keep the development version while their
bytes change with each commit. CI combines a clean package cache with
`tests/NuGet.config` source mapping so it cannot substitute a stale or public
package.

Adding a platform to the matrix means adding its identifier there and
regenerating:
A local machine has neither. The version never changes between packs, so a
restore prefers whatever `0.0.0-alpha.9` the global cache already holds and the
freshly packed bytes are ignored. Evict them before running either gate:

```console
$ mise exec -- dotnet restore LibTmux.slnx --force-evaluate
$ rm -rf ~/.nuget/packages/libtmux{,.query.json,.workspace}/0.0.0-alpha.9
```

Skipping that runs last week's library against this week's dependants, which
surfaces as a `TypeLoadException` naming an internal type rather than as
anything that looks like a stale package.

Adding a platform means adding its identifier to `LibTmux.AotSmoke` and adding
the matching standalone restore and publish to the workflow.

### The other workflows

[`dotnet-tmux.yml`](workflows/dotnet-tmux.yml) builds each supported tmux from
Expand Down Expand Up @@ -292,16 +367,26 @@ either of those changes what a user sees on their own screen.
**A behaviour change needs a test against a real tmux.** This library's job is
being right about tmux, and only tmux can say whether it is.

**A new tmux version starts in the manifest.**
[`eng/tmux/versions.json`](../eng/tmux/versions.json) decides which versions
this repository supports. The workflow matrix, both build scripts, the runtime
constants and every README repeat that list, and
`eng/parity/verify_tmux_versions.py` names each one that has not caught up:

```console
$ uv run python eng/parity/verify_tmux_versions.py
```

**A version-dependent behaviour needs a row in the ledger.** Anything that
differs between 3.2a and 3.7b goes through the capability model, and each
differs between 3.2a and 3.7c goes through the capability model, and each
difference names the test that proves it in
[`docs/parity/version-deltas.json`](../docs/parity/version-deltas.json).

**A public API addition needs five edits, and each will tell you.** The Roslyn
analyzer baseline (`PublicAPI.Unshipped.txt`), the type and its members in
`docs/public-api.json`, its values if it is an enum, and its owning component
in `eng/parity/verify_production_plan.py`. They fail independently and by name;
follow the errors.
**A public API addition changes both enforced contracts.** Update the Roslyn
analyzer baseline (`PublicAPI.Unshipped.txt`) and the type and member records in
`docs/public-api.json`, including explicit enum values. If the addition maps a
Python symbol, update its row in `docs/parity/parity-ledger.json`. The validators
report each missing contract independently.

**A documented example is compiled, and a `csharp run` block is executed
against a live tmux.** `ReadmeExampleTests` compiles every C# block in the
Expand Down Expand Up @@ -470,13 +555,17 @@ $ uv run python eng/parity/reconcile_versions.py \

Commit the bundle and the rewritten `version-deltas.json` together, because the
fingerprint is of the tree that commit produces. A tmux build takes about forty
seconds here and the matrix runs the suite fourteen times, so budget half an
seconds here and the matrix runs the suite sixteen times, so budget half an
hour.

## Compatibility

tmux **3.2a through 3.7b**, on **net8.0** and **net10.0**, on Linux and macOS.
Windows is unsupported. The packages are trim- and ahead-of-time-safe.
Stable tmux **3.2a and newer**, on **net8.0** and **net10.0**. The required
Linux matrix covers 3.2a through 3.7c; the advisory macOS lane uses the current
Homebrew tmux. Windows is unsupported. The `LibTmux` core package is trim- and
ahead-of-time-analyzer gated and has a Linux NativeAOT execution smoke test.
Optional packages make narrower compatibility claims in their project files
and package READMEs.

During alpha the public API can change in any release with no deprecation
period, so a consumer pins an exact version. Widening the supported range means
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ body:
attributes:
label: tmux version
description: The output of `tmux -V`.
placeholder: tmux 3.7b
placeholder: tmux 3.7c
validations:
required: true
- type: dropdown
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-tmux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
# readable when the other lanes still run.
fail-fast: false
matrix:
tmux: ['3.2a', '3.3a', '3.4', '3.5', '3.6', '3.7a', '3.7b']
tmux: ['3.2a', '3.3a', '3.4', '3.5', '3.6', '3.7a', '3.7b', '3.7c']
framework: ['net8.0', 'net10.0']
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
36 changes: 21 additions & 15 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ jobs:
# Reaching the library through the package is the point: a missing
# assembly or a wrong target framework is invisible from inside the
# repository.
env:
NUGET_PACKAGES: ${{ runner.temp }}/libtmux-package-consumer
run: |
dotnet restore tests/LibTmux.PackageConsumer/LibTmux.PackageConsumer.csproj
dotnet restore tests/LibTmux.PackageConsumer/LibTmux.PackageConsumer.csproj \
--configfile tests/NuGet.config
for framework in net8.0 net10.0; do
dotnet run \
--project tests/LibTmux.PackageConsumer/LibTmux.PackageConsumer.csproj \
Expand All @@ -96,16 +99,21 @@ jobs:

- name: Ahead-of-time smoke test
# Trim and ahead-of-time warnings are only complete once something is
# published that way and run. This publishes where the closure tests
# below look for it, which is the default location rather than one
# this job picked.
# published that way and run. The isolated cache and mapped source make
# this a test of the packages above rather than the project graph.
env:
NUGET_PACKAGES: ${{ runner.temp }}/libtmux-aot-smoke
run: |
sudo apt-get install --yes clang zlib1g-dev
dotnet restore tests/LibTmux.AotSmoke/LibTmux.AotSmoke.csproj \
--runtime linux-x64 \
--configfile tests/NuGet.config
for framework in net8.0 net10.0; do
dotnet publish tests/LibTmux.AotSmoke/LibTmux.AotSmoke.csproj \
--configuration Release \
--framework "${framework}" \
--runtime linux-x64
--runtime linux-x64 \
--no-restore
"tests/LibTmux.AotSmoke/bin/Release/${framework}/linux-x64/native/LibTmux.AotSmoke"
done

Expand Down Expand Up @@ -155,6 +163,7 @@ jobs:
uv run python eng/parity/render_public_api.py --check
uv run python eng/parity/verify_capabilities.py
uv run python eng/parity/verify_workflows.py
uv run python eng/parity/verify_tmux_versions.py
uv run python eng/docs/render_api_reference.py --check
uv run python eng/docs/sync_snippets.py --check
uv run eng/mcp/dump_tools.py --check
Expand All @@ -168,10 +177,11 @@ jobs:
- name: Engineering tests
env:
LIBTMUX_PYTHON_REPOSITORY: ${{ runner.temp }}/python-libtmux
# tomlkit is what mcp_swap edits Codex and Grok configs with, so its
# tests need it too. There is no Python project file here to declare
# it in — the scripts carry their own PEP 723 headers.
run: uv run --with pytest --with tomlkit python -m pytest eng --quiet
# Naming pytest and tomlkit on the command line resolved whatever
# released that morning, so an unrelated release could turn this red.
# The runner declares them in its own PEP 723 header and pins them in
# the lock beside it; --locked refuses to run against a stale one.
run: uv run --locked --script eng/run_tests.py --quiet

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
# A run that failed before packing has nothing to upload, and saying so
Expand Down Expand Up @@ -203,12 +213,8 @@ jobs:
tmux -V

- name: Restore
# Locked mode is off here, and omitting --locked-mode is not enough to
# do that: Directory.Build.props turns RestoreLockedMode on whenever CI
# is set. The lock files are generated for the Linux runtime identifier
# this repository publishes ahead of time, so a macOS restore resolves
# osx-arm64 and NU1004s against them -- which is the lock files being
# right about Linux, not a dependency problem.
# Directory.Build.props enables locked mode in CI. This advisory macOS
# lane opts out; the required Linux lanes remain the lock-file gate.
run: dotnet restore LibTmux.slnx -p:RestoreLockedMode=false

- name: Build
Expand Down
Loading
Loading