Commit Graph
503 Commits
Author SHA1 Message Date
Mai Huy HoàngandClaude Opus 5 983e6a14c0 [2.x] fix: Make sbtn's result line consistent with sbt --server (#9783)
**Problem**
sbt compile through the thin client prints only elapsed time: 2 s, where the
same command in the shell or under sbt --server prints
elapsed time: 2 s, cache 94%, 13 disk cache hits, 24 remote cache hits. The
summary is computed server-side and thrown away: ManagedLogger.success is gated
on Terminal.isSuccessEnabled, and a NetworkChannel's terminal answered
interactive.get || isInWatch, which is false whenever a command is passed on
the command line. The line the user sees is the client's own, built from
wall-clock alone.

**Solution**
Report the line from the server, and have the client print only when the server
will not.

NetworkChannel's terminal reports isSuccessEnabled = true, so the server
writes the line on every channel, and it advertises successLog in its
capabilities. A server from before this sends no such key, which reads as false,
so an older client-server pair behaves as it does today; an unattached client
also always prints, since it renders build/logMessage rather than the proxied
systemOut bytes. Older sbtn keeps printing its own line and so reports
success twice until it updates.

Generated-by: Claude Opus 5

Claude-Session: https://claude.ai/code/session_015BqrfmHbJUph6Kx7gJn3G8

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-21 00:06:51 -04:00
Albert MeltzerandClaude Opus 5 e4e7ec8116 [2.x] fix: Read the token again when it is refused (#9738)
**Problem**
The client sent the handshake and ignored the answer: responsePlan had
no case for it, so an invalid token was dropped. The channel then stayed
unauthenticated and every later request was refused, with nothing saying
why.

**Solution**
Match the handshake response. On a refusal, read the token file again
and present what it names now, up to handshakeAttemptLimit times, then
report the refusal.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-17 22:44:10 -04:00
Stas Shevchenko 4eba898c9e [2.x] fix: let one client at a time restart the server (#9708)
Two invocations that both find different -D options could interleave, the second
one connecting to the server the first had just started and shutting that down
mid-build. The restart now holds the connection file and reads it again once it
has it, so a replacement that already carries the right options is left alone.
2026-09-12 18:56:21 -04:00
Eugene Yokota f9688c1464 Apply Scalafmt format (Scala 3 syntax) 2026-09-10 14:16:27 -04:00
Albert MeltzerandClaude Opus 5 dbeeb199aa [2.x] fix: Stop a displaced server (#9713)
**Problem**
If a client cannot reach the server, it deletes the portfile. Then it
starts a second server. The first server is displaced: its socket path
now belongs to the second server.

A displaced server keeps running. A dropIfIdle notification cannot
reach it, because the proc file it registered names the socket that
the second server now owns.

**Solution**
The portfile holds the serverId of whichever server wrote it. Watch
that file, and exit when the id is not this server's. Leave the
portfile to the server that owns it.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-10 12:55:11 -04:00
Albert MeltzerandClaude Opus 5 db4d22cc18 [2.x] fix: Keep accepting after a client fails
**Problem**
The accept loop did not catch an exception from onIncomingSocket, so
its thread ended. Nothing closed the server socket, so the path stayed
bound: the server took no further client, and the process kept running.
The socket of the client that failed stayed open too.

**Solution**
Log that client, close its socket, and take the next one. An exception
from accept itself keeps the handling it had, so a socket that is
really broken still ends the loop.

The callback now takes a holder rather than the socket, and calls
AtomicCloseable.release to keep it. The loop closes whatever the
callback left behind.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-08 10:14:23 -07:00
Albert MeltzerandClaude Opus 5 b2544cfa02 [2.x] test: Pin a client the server cannot serve
**Problem**
Nothing covers what the accept loop does when it cannot serve a client.
The next commit changes it.

**Solution**
Assert what the server does now. An exception from onIncomingSocket
ends the accept loop, and the server serves no client after that.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-08 06:49:28 -07:00
Stas Shevchenkoandeugene yokota f389e676cd fix: restart the sbt server when -D options change (#9685)
* fix: restart the sbt server when -D options change

* fix: don't restart on completions, wait for the socket

* fix: only trust -D options recorded for this build

* fix: confirm the server left before reporting it gone

* Update protocol/src/main/contraband/portfile.contra

Co-authored-by: eugene yokota <[email protected]>

* fix: record the server -D options as a list

* fix: record the -D options without their values

The connection file keeps the name of each option and a salted digest of it
rather than the option itself, and the comparison follows the JVM in taking the
last definition of a name. A client that is not allowed to restart the server
says which options it cannot pick up instead of staying quiet about them.

* fix: compare the -D options given before a command

A trailing -D option used to switch the whole comparison off, which dropped the
options written before it, and a shutdown request that never reached the server
waited the full timeout before saying so.

* fix: leave a server no client started alone

The connection file says whether its recorded options are the whole story, so a
server an editor keeps is warned about instead of shut down, while one the client
started with no options is still replaced. A restart that cannot reach the server
warns and carries on rather than failing the invocation.

* build: filter NetworkClient clinit in MiMa

---------

Co-authored-by: eugene yokota <[email protected]>
2026-09-08 11:46:36 +09:00
Albert MeltzerandClaude Opus 5 9a858d15d1 [2.x] fix: Write the server's files by rename (#9689)
* [2.x] test: Pin how a server writes its files

**Problem**
Nothing covers how the server writes the portfile and the token file.
The next commit changes both.

**Solution**
Assert what the server does now. The tests read the token file only.
The server rewrites it on every authentication, so a test can read it
while the server writes. The server writes the portfile once, as it
starts.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

* [2.x] fix: Write the portfile and zip by rename

**Problem**
A client reads the portfile as soon as it appears. The server wrote it
with IO.write, in place, so a client could read part of one and fail to
parse it. ActionCache staged and renamed its zip by hand.

**Solution**
The portfile calls IO.writeFileAtomically, and the cache zip calls
IO.copyFile, which stages and renames on its own. The token file needs
its staging file kept to the owner, which neither can do yet, so it
still writes its own way.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

* [2.x] sbt-io: upgrade to v1.13.1

* [2.x] fix: Write the token file by rename

**Problem**
writeTokenfile would first remove the existing token file, and then go
through a non-atomic sequence of steps to write a new one. If a client
attempts to read the file during that process, it is likely to find it
either missing or half-written.

**Solution**
Use newly released IO.writeFileAtomically with ownerOnly flag set.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-04 12:07:13 +09:00
Albert MeltzerandClaude Opus 5 0591362134 [2.x] fix: Retry a read before discarding a server (#9690)
* [2.x] test: Pin how a client meets an unreadable portfile

**Problem**
Nothing covers what the client does when it cannot read the portfile.
The next commit changes it.

**Solution**
Assert what the client does now. The client reads the portfile once, so
a whole one that arrives a moment later comes too late.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

* [2.x] fix: Retry a read before discarding a server

**Problem**
One failure was enough for the client to delete the portfile and start
a second server, which took the socket from a server that was still
running. The client already tried ten times when a Windows pipe was
busy. It tried once when the portfile would not parse, and once when
the connection was refused.

**Solution**
Give those two failures the same ten attempts as the busy pipe. After
ten the client still deletes the portfile, which a portfile left by a
dead server needs.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-04 11:35:27 +09:00
Albert MeltzerandClaude Opus 5 952b82e461 [2.x] fix: Share a holder for a closeable (#9692)
**Problem**
Four fields hold a closeable that a later caller replaces. Each one
reads the field, closes what it finds and writes the new value in its
own way.

**Solution**
AtomicCloseable holds such a value. It closes the value it replaces,
and closes the value that loses a race to fill an empty field.

Two things change for a caller. The client replaced its session
without closing the one it dropped, and now closes it. A close that
throws no longer escapes: each of these sites is discarding the value
it closes, and whatever led there matters more than the close.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-29 23:42:06 -05:00
azdrojowa123andClaude Opus 5 a25e9fe59a [2.x] fix: Fixes --addPluginSbtFile getting lost after reboot (#9669)
reboot restarts sbt with a fresh state, so the extra plugin sbt files registered in BasicKeys.extraMetaSbtFiles were dropped and their plugins disappeared. Prepend an early(addPluginSbtFile=<path>) command for each registered file to the arguments handed to the restarted sbt, so they are re-registered.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-24 15:38:34 -04:00
eugene yokota 8753a98161 [2.x] fix: sbtn to retry on corrupt active.json (#9617)
**Problem**
sbtn gets stuck when active.json is corrupt.

**Solution**
Delete active.json, and retry.
2026-08-19 02:26:44 -04:00
BrianHotopp e8f40d68c3 [2.x] fix: sbtn to log connection errors
onClose now logs sbt server disconnected when the close wasn't initiated by the client.

Generated-by: Oh My Pi (kimi-code/k3)
2026-08-17 14:08:21 -04:00
kenji yoshida c5eac14c14 [2.x] refactor: Remove unused code (#9589) 2026-08-13 14:50:30 -04:00
Eugene Yokota e6ac4ecffc [2.x] fix: Gate LSP calls behind auth
**Problem**
Some custom LSP calls do not check initialize-handshake,
which over TCP includes token-based authentication.

**Solution**
This adds checkAuthenticated check around sbt/exec etc.
2026-08-06 14:02:51 -04:00
BrianHotopp b0c840105b [2.x] fix: Bound the client boot wait when the forked server never starts (#9549)
The thin client's blockUntilStart loop recursed while the portfile was
missing and the forked process looked valid, with no deadline: a forked
server that died before writing project/target/active.json, or stayed
alive but wedged, hung the client forever with no output. On Windows the
check ignored process death entirely (Properties.isWin short-circuited
the liveness test), making the hang unconditional there.

The wait is now bounded (default 5 minutes, tunable with
-Dsbt.client.boot.timeout.seconds). On expiry the client fails with a
"did not start within N seconds" message and then prints the server's
captured stderr, instead of hanging silently (#9484). The Windows
liveness workaround is preserved; the deadline is what bounds it.

Generated-by: kimi-code/k3 (Oh My Pi)
2026-08-04 15:59:48 -04:00
eugene yokota 67924298f2 [2.x] fix: Fixes sbtn stdin race condition (#9521)
**Problem**
There's a race condition between per-byte readSystemIn notification
and one-byte-read thread lifecycle.

Note: One-byte-read thread was introduced as a solution to the problem
that switching the terminal between raw and canonical mode cannot happen
if it's blocked by read.

**Solution**
This eliminates the thread lifecycle issue by keeping the thread alive
throughout the lifecycle of sbtn itself.
read is still called on demand by the server readSystemIn notification.
2026-07-27 19:52:30 -04:00
BrianHotoppandClaude Opus 4.8 c78d6af748 [2.x] fix: Complete server teardown before logging so reboot works from sbtn (#9497)
Running reboot in the sbt shell dropped to the OS shell instead of rebooting.
The break was in teardown: Server.shutdown opened with
log.info, and during a client-initiated reboot the terminal in scope is that
client's already-closed virtual terminal, so the log write throws
ClosedChannelException through the terminal proxy. That aborted teardown
before the portfile was deleted and the server socket closed, and the
exception was swallowed by the shutdown hook (whose own error print goes to
the same dead terminal).

Server.shutdown now completes its state cleanup (portfile, tokenfile, running
flag, server socket) before logging, and CommandExchange.shutdown wraps each
channel shutdown and the server shutdown individually so one failing step
cannot skip the rest.

Fixes #9095

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-26 01:06:36 -04:00
Kevin Lee 97a1dc360b [2.x] fix: Fixes three test-classloader / jar-handle leaks in the sbt server JVM (#9485)
Three independent, pre-existing retention bugs kept the classloader of a
finished in-process test run -- and the open jar handles it holds -- alive
for the rest of the server session.

- JUnitXmlTestsListener: testSuite is an InheritableThreadLocal, so
  threads spawned during a run (e.g. async-framework pool workers) inherit
  a copy of the suite reference that remove() cannot reach.

- TestRecap.collect: the recap is stashed on State.attributes and outlives
  the command, so it must not retain live throwables.

- ClassLoaderCache: loaders evicted from delegate by clearExpiredLoaders
  are unreachable from the map and never enqueued on the ReferenceQueue, so
  neither clear()/close() nor the cleanup thread could ever close them.

SuiteResult now documents the retention hazard on throwables. Adds
deterministic, cross-platform tests for all three severed chains.
2026-07-23 18:05:37 -04:00
eugene yokota 3f073b0059 [2.x] Use JDK's Unix domain socket for bootserver (#9427)
Use JDK's Unix domain socket for bootserver.
2026-07-22 23:57:13 -04:00
BrianHotoppandClaude Opus 4.8 3de18d446f [2.x] fix: Propagate -java-home to a server the thin client starts (#9448)
The thin client (sbtn) parsed the launcher value flags (-java-home, -mem,
-jvm-debug, -sbt-dir, ...) but then dropped them. The space form was consumed
and discarded; the flag=value form fell through to the residual arguments and
was forwarded to the server verbatim, where --java-home=/path was rejected as a
command (`Not a valid command: --`).

When the client had to start a server (none running, no --server), the consumed
-java-home never reached the forked sbt launcher, so the server came up under
the default JVM and, in CI where the intended JDK is only reachable via
-java-home, failed to connect.

parseArgs now captures the consumed launcher value flags (both `flag value` and
`flag=value`) into Arguments.launcherValueArgs, and the cold-start fork re-passes
them to the sbt launcher so the server runs under the requested JVM. The client
tokenizes arguments by splitting on whitespace, which would otherwise fragment a
value that contains spaces (a Windows path like C:\Program Files\Java); parseArgs
tracks those split boundaries and rejoins a value flag's value. An empty flag=
value and a dangling flag with no value are consumed but not propagated, since
the launcher's require_arg would otherwise fail the fork.

The fork command construction is extracted into a pure, package-visible
serverCommand so a test can assert the propagated flag reaches the started
server. The sbt-launch-jar path is unchanged: it invokes java directly, with no
launcher to interpret the flag.

Fixes #9418

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-16 10:14:20 +09:00
eugene yokota 45a4e88adb [2.x] Tweak server startup message (#9429)
**Problem/Solution**
sbt 2.x uses client-server by default.
This makes the message a bit more obvious when the build is using a client.
2026-07-11 12:51:47 -04:00
BrianHotoppandClaude Fable 5 bcd7fe1fbc [2.x] fix: Probe for a live server before refusing to start (#9337)
Any IOException while creating the boot io socket was wrapped in
ServerAlreadyBootingException and reported as "sbt thinks that server
is already booting" with a stack trace, and non-interactive
invocations exited with code 2. Permission or path-length problems
with XDG_RUNTIME_DIR or the temp directory and Windows named-pipe
access errors all hit this, blocking sbt entirely (#6777). Raw
IOExceptions from the constructor (socket directory creation) were
not caught at all and crashed startup.

getSocketOrExit now connects to the socket (BootServerSocketProbe,
shared with the test suite) to check for a live server before
believing the exception.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-01 17:02:50 -04:00
Anatolii Kmetiuk 1d7b0d66c3 Fix #9358: preserve --allow-empty and --sbt-create in sbtArguments (#9370) 2026-06-23 15:03:21 +09:00
Eugene Yokota 0bab2066df [2.x] Reimplement FarmHash
**Problem**
sbtn and server uses FarmHash.

**Solution**
This reimplements FarmHash using Scala.
2026-05-31 16:07:28 -04:00
eugene yokota 315202181c [2.x] ci: Scalafmt 3.11.1 (#9279)
Apply Scalafmt
2026-05-31 16:01:15 -04:00
eugene yokota ffa8c14ca6 [2.x] Migrate FarmHash usage to xxhash64 (#9267)
Problem
ZAHa, which we use for FarmHash, uses Unsafe.

Solution
This ports xxhash64 to Scala.
2026-05-30 19:14:53 -04:00
kenji yoshida 6a1222ad06 [2.x] fix: Remove explicit equals and hashCode in LabeledFunctions (#9228) 2026-05-16 23:57:41 -04:00
kenji yoshida f454c05fe1 [2.x] refactor: Use scala.util.Using.resource instead of try-finally (#9230) 2026-05-16 05:51:07 -04:00
Eugene Yokota bf678f2d6a [2.x] fix: Fixes ctrl-c handling
**Problem**
Ctrl-C during client-side run gets interpreted in sbtn,
and shuts down the shell.

**Solution**
Ignore ctrl-c during client-side run.
2026-04-25 03:36:32 -04:00
bitloi 936a7e1ffb [2.x] fix: clear compiler bridge zinc cache on reboot dev (#9057)
Reboot dev now removes zinc/org.scala-sbt under the resolved global zinc
directory (same layout as ZincComponentManager secondary cache).

Closes #5735
2026-04-13 04:28:43 -04:00
eugene yokota 25dd9b7363 [2.x] fix: Fixes client-side run status (#9081)
**Problem**
In sbt 2.x, if we execute a run task from the shell,
and if the program fails, it ends up taking down the entire shell
because client-side run rethrows, which is not desirable
for the sbt shell.

**Solution**
1. Omit printing out success for ClientJobParams, which is the runinfo.
2. Print out success or error on the client-side for shell usage case.
2026-04-13 00:41:35 -04:00
BrianHotoppandClaude Opus 4.6 d765ba263a [2.x] fix: Return JSON-RPC error for unknown server methods (#9002)
The fallback ServerHandler silently dropped requests with unknown
methods, violating the JSON-RPC spec. Clients like Metals that send
unrecognized requests would never receive a response, potentially
causing timeouts or hangs.

Return a -32601 (Method not found) error response instead.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-04-10 01:33:20 -04:00
Dream 544f56695a [2.x] feat: Add cacheVersion setting for global cache invalidation (#8993)
* [2.x] feat: Add cacheVersion setting for global cache invalidation

**Problem**
There was no escape hatch to invalidate all task caches when needed.

**Solution**
Add `Global / cacheVersion` setting that incorporates into the cache key
hash. Changing it invalidates all caches. Defaults to reading system
property `sbt.cacheversion`, or else 0L. When 0L, the hash is identical
to the previous behavior (backward compatible).

Fixes #8992

* [2.x] refactor: Simplify BuildWideCacheConfiguration and add cacheVersion test

- Replace auxiliary constructors with default parameter values
- Add unit test verifying cacheVersion invalidates the cache

* [2.x] fix: Restore auxiliary constructors for binary compatibility

* [2.x] test: Improve cacheVersion scripted test and add release note

- Scripted test now verifies cache invalidation via a counter
  that increments only when the task body actually executes
- Add release note documenting the cacheVersion setting
2026-04-01 11:23:10 +09:00
Daniil Sivak 9939666a33 [2.x] fix: server-test and related refactoring (#8904)
- TestServer was replaced with ServerSession class, which is located in protocol module and allows you to interact with JSON-RPC sbt server.
2026-03-21 23:45:37 -04:00
BitToby be305eb3a5 fix: Use sbt script in BSP config instead of hardcoded Java path (#8920)
**Problem**

sbt bspConfig writes the absolute path of the current Java binary into .bsp/sbt.json. When the user switches Java versions (via sdkman, cs java, etc.) or removes that JDK, the IDE fails to start the sbt BSP server because the hardcoded path is stale or gone.

**Solution**

When an sbt launcher script is available (via `sbt.script` system property or PATH lookup), generate:

"argv": ["/path/to/sbt", "bsp"]
2026-03-19 20:57:53 -04:00
DreamandClaude Opus 4.6 dc90f160df [2.x] feat: Support --autostart=false and --no-server in sbtn client (#8895)
**Problem**
When sbtn (native thin client) can't find a running sbt server, it prompts
to start one. There was no way to opt out of server auto-start from the
client side, which is needed for CI environments and scripting (sbt/sbt#7079).

**Solution**
Reuse the existing sbt.server.autostart system property in NetworkClient
to control whether sbtn should attempt to start a server. When no server is
running and sbt.server.autostart=false, sbtn exits with an error instead
of prompting.

Support setting this property via:
- sbtn --no-server compile (sets sbt.server.autostart=false)
- sbtn --autostart=false compile (new flag following sbt conventions)
- sbtn -Dsbt.server.autostart=false compile (direct system property)
- sbt --autostart=false compile (bash runner and sbtw)

This follows sbt's naming conventions for properties/options: positive
property names with =false opt-out (like --color=false, --supershell=false).

Fixes sbt/sbt#7079

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-12 20:51:07 -04:00
kenji yoshida 963e38256c [2.x] ci: Update java file formatter plugin (#8892) 2026-03-10 11:19:48 -04:00
chrisrock1124 dd66216309 [2.x] fix: sbt --client fails if -mem is provided (#8831)
The bash launcher's runNativeClient() passed all original CLI args to
sbtn, only stripping --client. This caused sbtn to receive launcher
flags like -mem 10000, which NetworkClient.parseArgs() misclassified:
-mem went to sbtArguments and 10000 went to commandArgs, resulting in
a broken server start command.
2026-03-05 01:30:03 -05:00
Dream 8d9a0027e2 [2.x] fix: Print server stderr on startup failure (#8816)
**Problem**
When the sbt server fails to start (e.g. wrong JDK version), the client
only shows "failed to connect to server" hiding the actual error. The
server stderr is redirected to /dev/null to prevent Linux pipe buffer
deadlocks (#8442), so diagnostic output is lost.

**Solution**
Redirect server stderr to a temp file instead of /dev/null. When the
server fails to start (portfile never appears), read and print the temp
file contents before throwing ServerFailedException. The temp file is
cleaned up eagerly on both success and failure paths.

Fixes #8812
2026-02-26 00:31:09 -05:00
bitloi 130a332100 [2.x] feat: sbtn subscription level (#8796)
Closes #4399

- Add subscribeToAll to InitializeOption (protocol); default true for backward compatibility.
- CommandExchange: send broadcast notifyEvent/logMessage only to channels with subscribeToAll.
- TestServer: support subscribeToAll parameter for tests; AbstractServerTest: subscribeToAllForTest.
- ClientSubscriptionTest: assert default client receives build/logMessage when command runs.
- Scripted test server/client-subscription: run show name to exercise server client path.
2026-02-24 21:46:37 -05:00
Eve 44b9ca7c2d [2.x] feat: client-side run env inheritance (#8752)
merge current env into client-side run env
2026-02-17 14:07:54 -05:00
eugene yokota edd7061f15 [2.x] Minimalist console (#8722)
**Problem**
Forked console currently pulls in full Zinc, which includes JLine.

**Solution**
This implements a lighter-weight, full Java ForkConsoleMain,
which no longer depends on JLine.
2026-02-09 10:55:44 -05:00
bitloi d633de5c3f [2.x] fix: Detect alias/task key name conflicts (#8659)
Problem
When a user defines an alias with a name that matches an existing task or setting key (e.g., `alias c = compile` when a custom task `c` exists), the alias silently wins and shadows the task.

Solution
Detect conflicts at alias creation time and fail with an error message:
```
Alias 'c' conflicts with a task or setting key of the same name. Use a different alias name to avoid ambiguity.
```
2026-01-31 17:56:42 -05:00
Dream a5f915bf87 [2.x] test: Migrate ClassLoaderCacheTest to verify.BasicTestSuite (#8534) 2026-01-19 17:13:21 -05:00
E.G 0ec5144a63 [2.x] test: Migrate parser specs to verify.BasicTestSuite (#8551)
Migrate the following test files from ScalaTest's AnyFlatSpec to
verify.BasicTestSuite, following the pattern established by other
test files in the sbt codebase:

- SizeParserSpec.scala (util-complete)
- MultiParserSpec.scala (main-command)

Changes in all files:
- Replace AnyFlatSpec class with BasicTestSuite object
- Convert 'should ... in' syntax to 'test(...)' syntax
- Use Scala 3 syntax with colon indentation
- Add 'end' markers
- Add explicit types where needed

Related to the ongoing test migration effort.
2026-01-18 14:33:04 -05:00
bitloi c832fad7b5 [2.x] feat: Notify sbtn client when command is queued (#8568)
Fixes #8356

**Problem**

When `sbtn` sends a command while another long-running task (like `console`) is already executing, the client silently blocks with no indication that the command is waiting in a queue.

**Solution**

When a new command arrives via the network channel and another command is currently running, the server now sends an `ExecStatusEvent` notification with status `"Queued"` to the client. The client displays a message like:

```
[info] waiting for: console
```
2026-01-16 16:17:00 -05:00
eugene yokota 4d7e0633a8 Revert "[2.x] feat: Enable musl static linking for sbtn on JDK 17+ (#8464)" (#8557)
This reverts commit e16298521b.
2026-01-16 00:06:28 -05:00
aka James4u dce915e794 [2.x] fix: Error "Exception in thread "sbt-socket-server" java.lang.NullPointerException" on exit (#8448)
Fixes #8538

The code was calling e.getMessage.contains() without checking if getMessage()
returns null. Changed to use Option(e.getMessage).exists() to safely handle
null values.
2026-01-15 11:06:51 -05:00