Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
06ee147
Transport(fix[lifecycle]): Bound control and process IO
tony Aug 29, 2026
56cd5c2
Query(fix[wire]): Make filters closed values
tony Aug 29, 2026
2deefc5
Core(fix[state]): Reject ambiguous server state
tony Aug 29, 2026
f0903ab
Workspace(fix[apply]): Validate before effects
tony Aug 29, 2026
fee7dc7
Junit(fix[cleanup]): Prove fixture exit
tony Aug 29, 2026
2b8d8cd
Mcp(fix[protocol]): Bound server lifetime
tony Aug 29, 2026
7439150
Build(fix[matrix]): Restore aggregate gate
tony Aug 29, 2026
61161b0
Docs(docs[safety]): State MCP trust boundary
tony Aug 29, 2026
80ea800
Core(fix[identity]): Reject torn snapshots and stale winlinks
tony Aug 29, 2026
4c86294
Core(fix[lifecycle]): Own process cleanup before closing pipes
tony Aug 29, 2026
5ce5fe5
MCP(test[whoami]): Count identity fence
tony Aug 29, 2026
b10572d
MCP(fix[safety]): Report destructive effects
tony Aug 29, 2026
9e17078
Core(fix[buffers]): Preserve exact buffer arguments
tony Aug 29, 2026
04c51d4
MCP(fix[paste]): Isolate temporary buffers
tony Aug 29, 2026
dc222f0
Workspace(fix[commands]): Reject undispatchable pane input
tony Aug 29, 2026
5740c36
Core(fix[input]): Type lines literally and atomically
tony Aug 29, 2026
0d83e79
MCP(fix[run]): Deliver command lines atomically
tony Aug 29, 2026
0104141
MCP(fix[targets]): Disambiguate destructive targets
tony Aug 29, 2026
b7fc56c
MCP(fix[run]): Keep completion state off panes
tony Aug 29, 2026
e781531
MCP(fix[stdio]): End sessions when output fails
tony Aug 29, 2026
c9e4807
MCP(fix[input]): Bound protocol message size
tony Aug 29, 2026
7117d48
MCP(fix[stdio]): Own session resources through disconnect
tony Aug 29, 2026
f77d543
MCP(fix[launcher]): Release transport after startup failure
tony Aug 29, 2026
4d39f3d
Core(fix[waits]): Reserve transport capacity for signals
tony Aug 29, 2026
0e43d78
Core(fix[snapshots]): Preserve live empty servers
tony Aug 29, 2026
d4f196c
MCP(fix[lifecycle]): Complete every owned cleanup
tony Aug 29, 2026
98f3df6
MCP(fix[startup]): Close accepted transports on failure
tony Aug 29, 2026
8d2a9c3
MCP(fix[stdio]): Serialize outbound sends
tony Aug 29, 2026
ef2e722
MCP(fix[timeouts]): Restore SDK request bound
tony Aug 29, 2026
f9d88ba
MCP(docs[contracts]): State failure boundaries
tony Aug 29, 2026
5a6d5e3
Core(fix[lifecycle]): Reject reads after close
tony Aug 29, 2026
9121c41
MCP(fix[publication]): Scope dependencies to the API
tony Aug 29, 2026
95b7b93
Build(fix[docs]): Compile snippets as a consumer does
tony Aug 29, 2026
878655c
Core(feat[panes]): Paste text as one invocation
tony Aug 29, 2026
e35ff90
MCP(fix[paste]): Close the disconnect window
tony Aug 29, 2026
36c2da2
MCP(test[races]): Close two suite races
tony Aug 29, 2026
08c1216
Test(fix[input]): Wait for the shell to read
tony Aug 29, 2026
f62c2af
Core(feat[paste]): Send text on standard input
tony Aug 29, 2026
3b5f92b
MCP(fix[run]): Signal with this server's tmux
tony Aug 29, 2026
718cbf5
Transport(fix[argv]): Keep a trailing semicolon
tony Aug 29, 2026
7526684
Snapshot(fix[framing]): Read a row spanning lines
tony Aug 29, 2026
bb457e3
Options(fix[listing]): Report the stored value
tony Aug 29, 2026
64b74d3
Format(fix[expand]): Return a multi-line expansion
tony Aug 29, 2026
d51df2b
MCP(refactor[socket]): Use the core expansion
tony Aug 29, 2026
f6870f2
MCP(refactor[naming]): Name the pane reader Screen
tony Aug 29, 2026
f9d757f
Snapshot(refactor[capture]): Extract the capture
tony Aug 29, 2026
257b568
Test(fix[chain]): Define before using the name
tony Aug 29, 2026
6a88323
Build(feat[benchmarks]): Price an operation
tony Aug 29, 2026
841d38f
Build(feat[matrix]): Run the 3.7c lane
tony Aug 29, 2026
70806a0
Snapshot(perf[capture]): Capture in one group
tony Aug 29, 2026
d6338d6
Test(fix[replacement]): Wait for the socket
tony Aug 29, 2026
1c94058
Test(fix[literal]): Reach the clear first
tony Aug 29, 2026
2bb6d20
Test(refactor[await]): Wait in one place
tony Aug 29, 2026
256c8e2
Docs(docs[spikes]): Mark what no longer exists
tony Aug 29, 2026
c413696
Test(refactor[double]): Share the group emulator
tony Aug 29, 2026
71ddc25
Snapshot(fix[fence]): Check the whole identity
tony Aug 29, 2026
099fc4b
Test(fix[waiting]): Give a pane's shell longer
tony Aug 29, 2026
3e81f81
Pane(feat[mode]): Report the mode as a value
tony Aug 29, 2026
f880b51
Server(feat[channel]): Name a wait channel once
tony Aug 29, 2026
f6d7402
Pane(feat[find]): Search the fields tmux offers
tony Aug 29, 2026
b264697
Control(test[attach]): Wait for attachment
tony Aug 30, 2026
9f897f5
Buffer(test[paste]): Wait for the reader
tony Aug 30, 2026
1b82b75
Control(test[close]): Remove pane output race
tony Aug 30, 2026
b7fb0d5
MCP(fix[run]): Isolate caller shell syntax
tony Aug 30, 2026
65601e4
Transport(fix[input]): Bound stdin writes
tony Aug 30, 2026
b5c1da7
MCP(fix[send]): Bound serialized backlog
tony Aug 30, 2026
0e51443
MCP(fix[run]): Preserve accepted commands
tony Aug 30, 2026
c4aa209
MCP(fix[send]): Skip cancelled promotions
tony Aug 30, 2026
1de99b0
Docs(docs[changelog]): Note literal IO and bounds
tony Aug 30, 2026
b7b20d3
Mcp(fix[safety]): Refuse uncertain self-kills
tony Aug 30, 2026
0822989
Mcp(fix[cursors]): Fence resumed pane reads
tony Aug 30, 2026
7d7f7ba
Core(fix[framing]): Count bytes and end rows
tony Aug 30, 2026
b29e953
Mcp(fix[run]): Require a POSIX shell
tony Aug 30, 2026
f2b6079
Style(chore[format]): Apply Java formatter
tony Aug 30, 2026
31f8a11
Merge remote-tracking branch 'origin/master' into improvements-00
tony Aug 30, 2026
6782cbb
Mcp(test[run]): Keep uncertainty fixture at shell
tony Aug 30, 2026
25b47ad
Mcp(test[launcher]): Start an explicit shell
tony Aug 30, 2026
f7b6397
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Nothing about this is a convention you have to remember:
| --- | --- | --- |
| `libtmux*/` | yes | one artifact each, named for its directory |
| `integration-tests/` | no | the real-tmux suite, which spans artifacts |
| `benchmarks/` | no | the carrier measurements |
| `examples/` | no | whole runnable programs, run by its own suite |
| [`docs-tests/`](../docs-tests/) | no | compiles and runs every snippet in the docs |
| `scripts/` | no | what the build does not do |
Expand Down Expand Up @@ -88,19 +87,6 @@ A unix socket path cannot exceed about 104 bytes, and tmux reports a longer one
as `error connecting to … (File name too long)`. That rules out sockets under a
build directory or a deep scratch path, and it is why the roots above are short.

`ExecutionMode` chooses how a command travels, and the suite can be run under
any of them:

```console
$ LIBTMUX_MODE=control ./gradlew check
```

A failure that appears only under one carrier is a real finding — the library
claims the answer does not depend on the carrier, and
`ExecutionModeConformanceTest` is where that claim is gated. Confirm it against
a clean `/tmp` first: the failure modes of cross-port debris and of a genuine
carrier defect look alike.

Against every supported tmux release:

```console
Expand Down Expand Up @@ -215,7 +201,7 @@ toolchain and `options.release` in
matrix in the CI workflow, which builds on 21 and 25, and the claim `README.md`
makes under `Requirements`.

**tmux 3.2a through 3.7b is the supported range**, and it is not a claim: the
**tmux 3.2a through 3.7c is the supported range**, and it is not a claim: the
whole real-tmux suite runs against every one of those releases, and each lane
checks it really ran the tmux it is named after. Moving the range means moving
`workflows/tmux-matrix.yml` and the README together.
Expand Down
10 changes: 5 additions & 5 deletions .github/WRITING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Four things near the top are compatibility claims, and they move together:
exported identifiers without a deprecation period, pin an exact version, not
recommended for production. `CHANGELOG.md` and the `Status` section say the
same thing in the same words.
- **The requirements are JDK 21 or newer, and tmux 3.2a through 3.7b.** The tmux
- **The requirements are JDK 21 or newer, and tmux 3.2a through 3.7c.** The tmux
range is not a claim — the matrix runs every lane of it — so it may not drift
from `workflows/tmux-matrix.yml`.
- **Coordinates are group `io.github.libtmux`, imported through
Expand Down Expand Up @@ -79,7 +79,7 @@ makes it decidable:
points at `tmux_list_servers`.
```

Name identifiers literally: `Pane.capture`, `LIBTMUX_MODE`, `--rerun-tasks`,
Name identifiers literally: `Pane.capture`, `LIBTMUX_WATCH`, `--rerun-tasks`,
`tmux://panes/{pane}`. Lead with a concrete verb — add, fix, remove, reject,
`now`, `no longer`.

Expand All @@ -104,7 +104,7 @@ Order it capability, then consequence, then compatibility:

> 0.0.1-alpha.7 adds streaming capture, and rejects `windowId` at pane scope
> rather than ignoring it. Pass `scope: window` to read at window scope. JDK 21
> and tmux 3.2a through 3.7b are unchanged.
> and tmux 3.2a through 3.7c are unchanged.

The title is plain — the version, optionally preceded by `libtmux for Java`.
Never "we are excited to announce"; state what shipped.
Expand Down Expand Up @@ -354,8 +354,8 @@ has nothing but the string:
"JDK 21" both appear upstream — this project writes **JDK 21**.
- A **pane**, **window**, **session**, and **server** are what tmux calls them.
Do not introduce a synonym for one.
- Write the identifier, not a description of it: `LIBTMUX_MODE=control`, not
"the mode environment variable"; `--rerun-tasks`, not "the rerun flag";
- Write the identifier, not a description of it: `LIBTMUX_WATCH=true`, not
"the watch environment variable"; `--rerun-tasks`, not "the rerun flag";
`/tmp/libtmux-java-test/`, not "the test socket directory".

Treat AI slop as review-hostile noise. The goal is information density:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tmux-matrix.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: tmux matrix

# The README claims tmux 3.2a through 3.7b, and says that range is not a claim because the suite runs
# The README claims tmux 3.2a through 3.7c, and says that range is not a claim because the suite runs
# against every one of them. This is where that stops depending on someone running it locally.

on:
Expand Down Expand Up @@ -32,7 +32,7 @@ jobs:
matrix:
# Must match the lanes in build-logic/src/main/kotlin/libtmux.tmux-matrix.gradle.kts, which
# is the source of truth. The agree step below fails if they drift apart.
tmux: ['3.2a', '3.3a', '3.4', '3.5', '3.6', '3.7', '3.7a', '3.7b']
tmux: ['3.2a', '3.3a', '3.4', '3.5', '3.6', '3.7', '3.7a', '3.7b', '3.7c']
steps:
- uses: actions/checkout@v7

Expand Down
121 changes: 121 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,127 @@ production.

## Unreleased

### Added

- **`Pane.findWindow` searches by name, title, or content, with
case-insensitive and regular-expression matching.** Build a `FindSpec` or
configure one inline. (#6)
- **`Batch.length()` reports the exact UTF-8 byte length of the encoded
command.** Use it to dispatch before tmux's command-size limit is reached.
(#6)
- **`Pane.paste(String)` sends literal text without leaving a server buffer.**
Text no longer shares tmux's command-size limit; this API requires tmux 3.4.
(#6)

### Changed

- **`Pane.findWindowByName` and `Pane.findWindowByContent` are removed.** Use
`findWindow` with `inName()` or `inContent()`. (#6)
- **`Server.waitFor`, `waitForWithSignalCapacity`, `signal`, and `drain` move
to `Server.channel(name)`.** Use `await`, `awaitReservingCapacity`,
`signal`, and `drain` on the returned `Channel`. (#6)
- **`Pane.mode()` returns `PaneMode` rather than text.** Compare against enum
values such as `PaneMode.TREE`; `modeOrNull()` changes with it. (#6)
- **The supported tmux range now includes 3.7c.** The compatibility matrix runs
that lane. (#6)
- **`Server.snapshot()` captures the hierarchy in one fenced command group.**
Watchers start fewer tmux processes, and a replacement server is rejected
before its rows are read. (#6)
- **`CommandRequest` carries command groups and optional input rather than one
flat argv.** Use `CommandRequest.of` for one command and `commands()` where
`argv()` was read; `ControlClient.isCommandGroup` is removed. (#6)
- **`Pane.paste(String bufferName)` is now `Pane.pasteBuffer(String name)`.**
`Pane.paste(String)` now means literal text. (#6)
- **`ControlClient.onOutput` and `onEvent` are replaced by bounded pull
subscriptions.** Use `subscribeOutput` or `subscribeEvents`, close the
returned `EventSubscription`, and inspect `droppedCount()`. (#6)
- **Filter expressions are immutable, model-bound wire values.** Build fields
and relations through `Fields` or generated handles, and pass the matching
`FilterModel` to `FilterJson.write*`; `EntityMetamodel`, `FieldProvenance`,
and `FieldRef.name()` are removed. (#6)
- **`ProcessTransport` now bounds concurrency, input writes, output, deadlines,
and cleanup.** Configure its limits through the constructors; timeouts
surface as `TmuxTimeoutException` with dispatch certainty. A deadline or
cancellation during input terminates the child instead of blocking. (#6)
- **`Buffers.delete` now requires tmux 3.4 and reports a missing name.** tmux
3.2a and 3.3a can delete the top buffer when the named buffer is absent, so
the library refuses that unsafe operation. (#6)

### Fixed

- **Destructive MCP tools fail closed when caller-pane identity cannot be
proven.** Uncertain socket, server, or pane identity now requires explicit
self-confirmation instead of bypassing the guard. (#6)
- **MCP pane cursors are authenticated and bound to daemon and pane identity.**
Reads preserve continuity across bounded history compaction when it can be
proven, and pane capture uses identity-fenced batches with strict outcome
checks. (#6)
- **`RowFormat` uses an explicit record terminator.** Multiline final fields
and single-field rows no longer depend on physical line boundaries. (#6)
- **`tmux_run` requires a POSIX shell and uses a 128-bit completion marker.**
It refuses another foreground program instead of sending shell framing that
program cannot interpret. (#6)
- **Hierarchy listings preserve values containing newlines.** A pane working
directory containing a newline no longer empties session, window, and pane
listings. (#6)
- **`Options.all`, `Options.effective`, and `Options.get` return complete
stored values.** Escape-sensitive and multiline strings are no longer
altered or truncated. (#6)
- **`Server.expand`, `Session.expand`, `Window.expand`, and `Pane.expand`
preserve multiline results.** They no longer return only the first line.
(#6)
- **Names, options, sent keys, shell commands, and batch operations preserve a
trailing semicolon.** The semicolon remains data rather than ending the tmux
command. (#6)
- **`Pane.sendLine`, command-chain input, and `tmux_run` deliver text plus
Enter as one literal operation.** Option-shaped input remains data, and
concurrent calls cannot interleave their input. (#6)
- **`tmux_paste_text` no longer leaves pasted text on the server when a client
disconnects during the call.** (#6)
- **`tmux_run` keeps caller shell syntax isolated from completion framing, uses
the server's resolved tmux binary, and keeps completion state off pane
options.** A command accepted before an indeterminate send failure still
executes. (#6)
- **Serialized MCP sends obey their queue and byte bounds across cancellation
and shutdown.** A send cancelled after promotion is skipped before delegate
delivery, later sends keep order, and close settles every admitted caller.
(#6)
- **`libtmux-mcp` publishes the dependencies its API exposes.** Consumers now
receive `mcp-core`; the artifact no longer selects an SLF4J provider or
exports `libtmux-jackson`. (#6)
- **Handles refuse a replacement tmux server that reused an identifier.**
Linked-window operations also retain the exact session and index they came
from. (#6)
- **Workspace input is validated before session creation.** Unsupported
layouts, unsafe names, malformed topology, and uncertain creation replies
leave tmux untouched or roll back the exact staging session. (#6)
- **MCP watching stays consistent across concurrent output, new sessions,
dropped events, outages, and server restarts.** Notifications are serialized
and bounded, and watcher clients remain hidden from listings. (#6)
- **The MCP launcher exits when its protocol session ends.** Oversized or
malformed input and output failures no longer leave the process waiting on
stdin. (#6)
- **MCP tools now advertise non-additive effects as destructive.** Clients can
request confirmation for commands, input, and settings even when the safety
ceiling permits those tools. (#6)
- **MCP rename and kill tools resolve destructive targets unambiguously.**
Session operations use stable identifiers; only arguments explicitly naming
a session by name use names. (#6)
- **Snapshot-backed accessors reject a closed `Server`.** They no longer turn
use after close into an empty hierarchy. (#6)
- **A live server with no sessions captures as an empty snapshot.** Child
listings are not attempted when tmux has no current target. (#6)
- **`TmuxExtension` proves abandoned servers exited before deleting their
directories.** Successful recovery also removes the abandoned directory.
(#6)

### Removed

- **`ExecutionMode`, `ControlTransport`, `VirtualThreadTransport`,
`LIBTMUX_MODE`, and their benchmark surface are removed.** `Server` uses
process execution; use `ControlClient` for event streams and batches or
command chains to reduce round trips. (#6)

## 0.0.1-alpha.7 — 2026-08-22

### Documented
Expand Down
34 changes: 6 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,32 +159,11 @@ In a real pane those two variables are already set, so `TmuxEnvironment.current(
takes nothing and returns empty when there is no pane to describe. This README is
not running inside one, so the example supplies them.

## Three switches
## Avoid unnecessary round trips

| to stop | write | which costs |
| ------------------------------------------- | ------------------------------ | ------------------------------ |
| paying for a process per command | `.mode(ExecutionMode.CONTROL)` | one tmux client, then reused |
| waiting on the thread you were handed | `.mode(ExecutionMode.VIRTUAL)` | a virtual thread per command |
| round-tripping to learn what you just made | `server.chain()` | one request, however many steps |

```java
ServerConfig config = ServerConfig.builder()
.endpoint(ServerEndpoint.socketPath(socket))
.mode(ExecutionMode.CONTROL)
.build();
```

A carrier can also be chosen from outside the program that uses one, so trying
another costs nothing:

```console
$ LIBTMUX_MODE=control java -jar app.jar
```

A carrier and a grouping are separate choices that compose, and neither changes
what a call returns: the same filter answers identically under each. What that
costs is measured in [the benchmark](docs/benchmarks/modes.md), which shows the
identical answers next to the different prices.
`server.batch()` sends independent commands in one invocation. `server.chain()`
does the same for dependent commands, letting tmux carry the current target from
one step to the next. Both retain an outcome for every operation.

## What it is like to use

Expand Down Expand Up @@ -238,7 +217,7 @@ README, and each is [on Maven Central](https://central.sonatype.com/namespace/io

Not published, and part of how the library is built:
[`examples/`](examples/) · [`integration-tests/`](integration-tests/) ·
[`docs-tests/`](docs-tests/) · [`benchmarks/`](benchmarks/) ·
[`docs-tests/`](docs-tests/) ·
[`scripts/`](scripts/) · `build-logic/`

A directory is a published artifact exactly when it appears above, and
Expand Down Expand Up @@ -306,7 +285,7 @@ bug. See [the Scala guide](docs/guide/scala.md).

JDK 21 or newer.

tmux 3.2a through 3.7b. That range is not a claim: the whole real-tmux suite runs
tmux 3.2a through 3.7c. That range is not a claim: the whole real-tmux suite runs
against every one of those releases, and each lane checks it really ran the tmux
it is named after.

Expand All @@ -317,7 +296,6 @@ $ ./gradlew testTmuxMatrix -PlibtmuxMatrix=/path/to/tmux/builds
## Documentation

- [Getting started](docs/guide/getting-started.md)
- [Execution modes](docs/guide/execution-modes.md) — and the [measured comparison](docs/benchmarks/modes.md)
- [Filtering](docs/guide/filtering.md)
- [Options and hooks](docs/guide/options-and-hooks.md)
- [Batching and chaining](docs/guide/batching-and-chaining.md)
Expand Down
24 changes: 16 additions & 8 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
# benchmarks

**Measures what each carrier costs. Not published.**
**Measures what an operation costs. Not published.**

`ExecutionMode` changes how a command travels, never what it answers. This
measures the difference in price, and regenerates
[`docs/benchmarks/modes.md`](../docs/benchmarks/modes.md) from a real run.
Every command this library sends starts a tmux process, so what a caller pays is
decided by how many commands an operation takes rather than by how fast any one
of them runs. This measures that, and regenerates
[`docs/benchmarks/operations.md`](../docs/benchmarks/operations.md) from a real
run.

```console
$ ./gradlew modeBenchmark -PlibtmuxTmux=/path/to/tmux
$ ./gradlew operationBenchmark -PlibtmuxTmux=/path/to/tmux
```

The table is **never hand-edited**. It shows identical answers next to different
prices, which is the only honest way to present a performance switch.
The table is **never hand-edited**, and it stamps which tmux answered, because a
table without its conditions is a claim rather than a measurement. Read the
dispatch counts; the milliseconds are one machine at one moment.

Four things are measured, and each exists because the library made a choice that
costs something: collapsing round trips with `batch()` and `chain()`, capturing
the hierarchy, fencing a handle's command against a replaced server, and reading
a scope's options.

Its own module, and excluded from `check`: a benchmark starts a tmux server per
case and takes seconds. Keeping it inside a published artifact's tests made that
a matter of remembering a tag rather than a matter of where the code lives.

## Next

- [Execution modes](../docs/guide/execution-modes.md) · [the measured table](../docs/benchmarks/modes.md)
- [Batching and chaining](../docs/guide/batching-and-chaining.md) · [the measured table](../docs/benchmarks/operations.md)
13 changes: 5 additions & 8 deletions benchmarks/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
// Measures what each carrier costs, and rewrites docs/benchmarks/modes.md from a real run.
// Measures what an operation costs, and rewrites docs/benchmarks/operations.md from a real run.
//
// Its own module, and never published. A benchmark takes seconds per case and starts a server per
// case, so it must not run in any ordinary suite; keeping it in a published artifact's tests made
// that a matter of remembering a tag rather than a matter of where the code lives.
plugins { id("libtmux.java-library") }

dependencies {
testImplementation(project(":libtmux"))
testImplementation(project(":libtmux-junit5"))
}
dependencies { testImplementation(project(":libtmux")) }

// Nothing here belongs to `check`: it writes a file and takes seconds. Run it when the table needs
// regenerating.
tasks.named<Test>("test") { enabled = false }

tasks.register<Test>("modeBenchmark") {
tasks.register<Test>("operationBenchmark") {
group = "verification"
description = "Measures each execution mode and rewrites docs/benchmarks/modes.md."
description = "Measures what each operation costs and rewrites docs/benchmarks/operations.md."
val tests = sourceSets.test.get()
testClassesDirs = tests.output.classesDirs
classpath = tests.runtimeClasspath
useJUnitPlatform { includeTags("benchmark") }
systemProperty("libtmux.tmux", providers.gradleProperty("libtmuxTmux").getOrElse("tmux"))
systemProperty(
"libtmux.benchmark.out",
rootProject.layout.projectDirectory.file("docs/benchmarks/modes.md").asFile.path,
rootProject.layout.projectDirectory.file("docs/benchmarks/operations.md").asFile.path,
)
outputs.upToDateWhen { false }
}
Loading
Loading