Skip to content

Commit f22f1b0

Browse files
aarondfrancisclaude
andcommitted
Default to native process driver, deprecate GNU Screen
GNU Screen is no longer required. The native driver handles PTY allocation, ANSI passthrough, and UTF-8 directly via Symfony Process with soloterm/screen parsing all ANSI sequences. The screen driver remains available for one release cycle with deprecation warnings logged when explicitly selected via SOLO_PROCESS_DRIVER=screen or SOLO_USE_SCREEN=true. Also adds unhandled ANSI sequence logging via Screen's reportUnhandledSequencesVia() to surface edge cases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent efc58da commit f22f1b0

File tree

10 files changed

+62
-91
lines changed

10 files changed

+62
-91
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Added configurable process drivers via `solo.process_driver` (`screen` or `native`) with backward-compatible fallback to `solo.use_screen`.
1313
- Added regression coverage for dashboard rendering behavior, diff-render cursor anchoring, renderer reuse, process-driver command wrapping, and shutdown signaling paths.
14+
- Added unhandled ANSI sequence logging to surface edge cases in command output.
1415

1516
### Changed
1617

18+
- Changed the default process driver from `screen` to `native`. GNU Screen is no longer required. Solo now uses PTY mode directly via Symfony Process, with `soloterm/screen` handling all ANSI parsing.
1719
- Updated dashboard rendering to prefer screen-diff output when available while preserving string-renderer fallback behavior.
1820
- Upgraded `soloterm/screen` to include the upstream `toCellBuffer()` ANSI decode fix and removed Solo's temporary local shim.
1921

22+
### Deprecated
23+
24+
- Deprecated the `screen` process driver. It will be removed in a future release. Users who explicitly set `SOLO_PROCESS_DRIVER=screen` or `SOLO_USE_SCREEN=true` will see a deprecation warning in the log.
25+
2026
### Fixed
2127

2228
- Fixed a frame composition bug that could scroll away the first row, causing the tab strip to disappear or appear incomplete.

config/solo.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,18 @@
6565
* Process driver used to execute commands.
6666
*
6767
* Supported values:
68-
* - screen: Wrap commands with GNU Screen (default behavior)
69-
* - native: Run directly in Solo's PTY with locale + stty bootstrap
68+
* - native: Run directly in Solo's PTY (default, no external dependencies)
69+
* - screen: Wrap commands with GNU Screen (deprecated, will be removed)
7070
*
71-
* Leave unset to keep legacy `use_screen` behavior.
71+
* You should not need to change this. The native driver handles PTY
72+
* allocation, ANSI passthrough, and UTF-8 without GNU Screen.
7273
*/
7374
'process_driver' => env('SOLO_PROCESS_DRIVER'),
7475

7576
/**
76-
* Backwards-compatible fallback for projects that still use SOLO_USE_SCREEN.
77-
* Prefer `process_driver` for new setups.
77+
* @deprecated Use `process_driver` instead. This option will be removed in a future release.
7878
*/
79-
'use_screen' => (bool) env('SOLO_USE_SCREEN', true),
79+
'use_screen' => (bool) env('SOLO_USE_SCREEN', false),
8080

8181
/*
8282
|--------------------------------------------------------------------------

docs/architecture.md

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ Each command runs as a subprocess managed by the `ManagesProcess` trait.
6161

6262
When a command starts:
6363

64-
1. A new process is spawned with `proc_open()`
65-
2. If GNU Screen is available, the command is wrapped for proper PTY handling
64+
1. A new process is spawned with `proc_open()` using PTY mode
65+
2. The command runs in a login shell with locale and terminal size bootstrap
6666
3. Non-blocking I/O is configured for output collection
6767

6868
### Output Collection
@@ -132,26 +132,6 @@ public function hasNewOutput(): bool
132132

133133
This reduces terminal I/O by ~99.5% for typical workloads.
134134

135-
## GNU Screen Wrapper
136-
137-
Solo wraps commands in GNU Screen for:
138-
139-
- **PTY allocation** - Proper terminal emulation
140-
- **ANSI rendering** - Better color and formatting support
141-
- **Size handling** - Correct terminal dimensions
142-
143-
The wrapper command:
144-
145-
```bash
146-
screen -U -q sh -c "your-command"
147-
```
148-
149-
Disable if Screen isn't available:
150-
151-
```env
152-
SOLO_USE_SCREEN=false
153-
```
154-
155135
## Key Components
156136

157137
### Dashboard

docs/configuration.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,6 @@ return [
5959
'Queue' => Command::from('php artisan queue:work')->lazy(),
6060
],
6161

62-
/*
63-
|--------------------------------------------------------------------------
64-
| GNU Screen
65-
|--------------------------------------------------------------------------
66-
*/
67-
'use_screen' => (bool) env('SOLO_USE_SCREEN', true),
68-
6962
/*
7063
|--------------------------------------------------------------------------
7164
| Dump Server
@@ -126,14 +119,6 @@ Available keybinding presets. Add your own custom keybinding classes here. See [
126119

127120
The commands that appear as tabs in Solo. The array key becomes the tab name. See [Commands](commands) for all the ways to define commands.
128121

129-
### use_screen
130-
131-
```php
132-
'use_screen' => (bool) env('SOLO_USE_SCREEN', true),
133-
```
134-
135-
Whether to use GNU Screen as a wrapper for commands. Screen provides proper PTY allocation and better ANSI rendering. Disable if Screen isn't installed or causes issues.
136-
137122
### dump_server_host
138123

139124
```php
@@ -153,9 +138,6 @@ SOLO_THEME=dark
153138
# Keybindings
154139
SOLO_KEYBINDING=vim
155140
156-
# GNU Screen
157-
SOLO_USE_SCREEN=true
158-
159141
# Dump server
160142
SOLO_DUMP_SERVER_HOST=tcp://127.0.0.1:9984
161143
```

docs/installation.md

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,6 @@ description: How to install and set up Solo in your Laravel application.
1818

1919
Solo requires `ext-pcntl` and `ext-posix` for process management. These extensions are not available on Windows. If you're on Windows, consider using WSL2.
2020

21-
### GNU Screen (Recommended)
22-
23-
Solo works best with GNU Screen 5.0.0 or higher installed. Screen provides proper PTY allocation and improves ANSI rendering.
24-
25-
Check if Screen is installed:
26-
27-
```bash
28-
screen --version
29-
```
30-
31-
Install on macOS:
32-
33-
```bash
34-
brew install screen
35-
```
36-
37-
Install on Ubuntu/Debian:
38-
39-
```bash
40-
sudo apt install screen
41-
```
42-
43-
Solo will work without Screen, but you may experience degraded output in some commands.
44-
4521
## Install via Composer
4622

4723
Install Solo as a development dependency:
@@ -109,7 +85,7 @@ Solo respects these environment variables:
10985
|----------|---------|-------------|
11086
| `SOLO_THEME` | `dark` | Theme to use (light or dark) |
11187
| `SOLO_KEYBINDING` | `default` | Keybinding preset |
112-
| `SOLO_USE_SCREEN` | `true` | Use GNU Screen wrapper |
88+
| `SOLO_PROCESS_DRIVER` | `native` | Process driver (`native` or `screen`) |
11389
| `SOLO_DUMP_SERVER_HOST` | `tcp://127.0.0.1:9984` | Dump server address |
11490

11591
## Troubleshooting
@@ -129,21 +105,6 @@ composer dump-autoload
129105
2. Check if the command has an `--ansi` or `--colors=always` option
130106
3. Verify the command writes to STDOUT
131107

132-
### Screen-related issues
133-
134-
If you experience rendering problems:
135-
136-
```bash
137-
# Disable Screen wrapper
138-
SOLO_USE_SCREEN=false php artisan solo
139-
```
140-
141-
Or in your `.env`:
142-
143-
```env
144-
SOLO_USE_SCREEN=false
145-
```
146-
147108
### Port conflicts
148109

149110
If the dump server port is in use:

src/Commands/Command.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Chewie\Concerns\Ticks;
1313
use Chewie\Contracts\Loopable;
1414
use Illuminate\Support\Collection;
15+
use Illuminate\Support\Facades\Log;
1516
use Illuminate\Support\Str;
1617
use SoloTerm\Screen\Screen;
1718
use SoloTerm\Solo\Commands\Concerns\ManagesProcess;
@@ -424,6 +425,13 @@ protected function makeNewScreen(): Screen
424425
height: $this->scrollPaneHeight()
425426
);
426427

428+
$screen->reportUnhandledSequencesVia(function (string $sequence) {
429+
Log::debug('Solo: Unhandled ANSI sequence in command output', [
430+
'command' => $this->name,
431+
'sequence' => addcslashes($sequence, "\x00..\x1f\x7f..\xff"),
432+
]);
433+
});
434+
427435
return $screen->respondToQueriesVia(function ($output) {
428436
$this->input->write($output);
429437
});

src/Commands/Concerns/ManagesProcess.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ trait ManagesProcess
135135
*/
136136
protected static bool $invokedProcessPropertyUnavailable = false;
137137

138+
/**
139+
* Whether the screen driver deprecation warning has already been logged.
140+
*/
141+
protected static bool $screenDeprecationWarned = false;
142+
138143
public function createPendingProcess(): PendingProcess
139144
{
140145
$this->input ??= new InputStream;
@@ -274,13 +279,26 @@ protected function processDriver(): string
274279
static::PROCESS_DRIVER_NATIVE,
275280
static::PROCESS_DRIVER_LEGACY,
276281
], true)) {
282+
if ($normalized === static::PROCESS_DRIVER_SCREEN && !static::$screenDeprecationWarned) {
283+
static::$screenDeprecationWarned = true;
284+
Log::warning('Solo: The "screen" process driver is deprecated and will be removed in a future release. Remove SOLO_PROCESS_DRIVER from your environment to use the native driver.');
285+
}
286+
277287
return $normalized;
278288
}
279289
}
280290

281-
return (bool) Config::get('solo.use_screen', true)
282-
? static::PROCESS_DRIVER_SCREEN
283-
: static::PROCESS_DRIVER_LEGACY;
291+
// Legacy fallback: SOLO_USE_SCREEN=true selects the (deprecated) screen driver.
292+
if ((bool) Config::get('solo.use_screen', false)) {
293+
if (!static::$screenDeprecationWarned) {
294+
static::$screenDeprecationWarned = true;
295+
Log::warning('Solo: The SOLO_USE_SCREEN option is deprecated. GNU Screen is no longer required. Remove SOLO_USE_SCREEN from your environment.');
296+
}
297+
298+
return static::PROCESS_DRIVER_SCREEN;
299+
}
300+
301+
return static::PROCESS_DRIVER_NATIVE;
284302
}
285303

286304
protected function localeEnvironmentVariables(): string

src/Console/Commands/Solo.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ protected function checkScreenVersion(): void
3535
return;
3636
}
3737

38+
Log::warning('Solo: The GNU Screen process driver is deprecated and will be removed in a future release. The native driver is now the default and does not require GNU Screen.');
39+
3840
$process = new Process(['screen', '-v']);
3941
$process->run();
4042

@@ -61,7 +63,7 @@ protected function usesScreenDriver(): bool
6163
return strtolower(trim($driver)) === 'screen';
6264
}
6365

64-
return (bool) Config::get('solo.use_screen', true);
66+
return (bool) Config::get('solo.use_screen', false);
6567
}
6668

6769
protected function monitor(): void

tests/Unit/ManagesProcessTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class ManagesProcessTest extends Base
1212
public function commands_are_not_tokenized_when_screen_is_disabled(): void
1313
{
1414
config()->set('solo.use_screen', false);
15-
config()->set('solo.process_driver', null);
15+
config()->set('solo.process_driver', 'legacy');
1616

1717
$command = new class(name: 'Tests', command: 'APP_ENV=testing php artisan test --filter="User Test"') extends Command
1818
{
@@ -347,6 +347,8 @@ protected function sendTermSignals(bool $force = false): void
347347
#[Test]
348348
public function screen_shutdown_refreshes_stay_eager_until_children_have_been_discovered(): void
349349
{
350+
config()->set('solo.process_driver', 'screen');
351+
350352
$command = new class extends Command
351353
{
352354
public float $fakeNowMs = 0;

tests/Unit/SoloCommandTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,13 @@ public function runScreenVersionCheckForTest(): void
5252
$command->runScreenVersionCheckForTest();
5353
});
5454

55+
$deprecationWarning = [
56+
'level' => 'warning',
57+
'message' => 'Solo: The GNU Screen process driver is deprecated and will be removed in a future release. The native driver is now the default and does not require GNU Screen.',
58+
];
59+
5560
$this->assertSame([
61+
$deprecationWarning,
5662
[
5763
'level' => 'error',
5864
'message' => 'The installed version of `screen` (4.9.0) is outdated. Please upgrade to 5.0.0 or greater for best compatibility with Solo.',
@@ -82,7 +88,13 @@ public function runScreenVersionCheckForTest(): void
8288
$command->runScreenVersionCheckForTest();
8389
});
8490

91+
$deprecationWarning = [
92+
'level' => 'warning',
93+
'message' => 'Solo: The GNU Screen process driver is deprecated and will be removed in a future release. The native driver is now the default and does not require GNU Screen.',
94+
];
95+
8596
$this->assertSame([
97+
$deprecationWarning,
8698
[
8799
'level' => 'error',
88100
'message' => 'Unable to determine `screen` version. Make sure `screen` is installed.',

0 commit comments

Comments
 (0)