Skip to content

Commit 4c77d79

Browse files
committed
Restore s6, Tart, and Docker boot UX changes accidentally reverted by f559bba
- fix(docker): restore streak-chart BootPanel, ContainerLogWatcher, and detached-container boot flow — boot progress renders as a multi-row streak chart again instead of the old scrolling checklist - fix(s6): restore shared s6 session-activation package (EnvDir, SourceDir, BootServices) — Tart provisioning uses shared constants instead of duplicated paths - fix(tart): restore GUI toggle, dynamic service discovery, and bumped VM defaults — Tart VMs get correct resource allocation and s6 integration - fix(ux): restore Phaser interface, BootPanel widget, and secret-formatting helpers — boot UX components available for all engines - docs(s6): restore s6-rc service topology documentation and testing guide updates - build(deps): bump termoscope to v0.3.0 and go-streak-chart to latest — picks up svg/gif package rename and square tile glyph
1 parent f559bba commit 4c77d79

46 files changed

Lines changed: 4106 additions & 386 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/s6-services.md‎

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# s6-rc Service Topology
2+
3+
34 services managed by s6-rc. Dependencies resolved in parallel with readiness gating.
4+
5+
## Dependency Graph
6+
7+
```mermaid
8+
graph TD
9+
classDef oneshot fill:#dae8fc,stroke:#6c8ebf,color:#333
10+
classDef longrun fill:#d5e8d4,stroke:#82b366,color:#333,font-weight:bold
11+
classDef readiness fill:#d5e8d4,stroke:#82b366,color:#333,font-weight:bold,stroke-width:3px
12+
classDef bundle fill:#e1d5e7,stroke:#9673a6,color:#333
13+
14+
user["user (bundle)"]:::bundle
15+
base_init["base-init"]:::oneshot
16+
17+
env_setup["env-setup"]:::oneshot
18+
secrets["secrets"]:::oneshot
19+
postgres_init["postgres-init"]:::oneshot
20+
system_fixups["system-fixups"]:::oneshot
21+
pulseaudio["pulseaudio"]:::longrun
22+
tor["tor"]:::oneshot
23+
wireguard["wireguard"]:::oneshot
24+
25+
shell_rc["shell-rc"]:::oneshot
26+
postgres["postgres"]:::longrun
27+
gcroot["gcroot"]:::oneshot
28+
nix_daemon["nix-daemon ★"]:::readiness
29+
30+
homedir["homedir"]:::oneshot
31+
gui_config["gui-config"]:::oneshot
32+
claude_config["claude-config"]:::oneshot
33+
codex_config["codex-config"]:::oneshot
34+
opencode_config["opencode-config"]:::oneshot
35+
gemini_config["gemini-config"]:::oneshot
36+
antigravity["antigravity"]:::oneshot
37+
mise["mise"]:::oneshot
38+
project_flake["project-flake"]:::oneshot
39+
40+
chromium_cleanup["chromium-cleanup"]:::oneshot
41+
mcp_toggle["mcp-toggle"]:::oneshot
42+
mise_packages["mise-packages"]:::oneshot
43+
nix_packages["nix-packages"]:::oneshot
44+
45+
xvfb["xvfb ★"]:::readiness
46+
dbus_session["dbus-session"]:::longrun
47+
snixembed["snixembed"]:::longrun
48+
window_manager["window-manager ★"]:::readiness
49+
wallpaper["wallpaper"]:::oneshot
50+
x11vnc["x11vnc"]:::longrun
51+
xrdp["xrdp"]:::longrun
52+
xrdp_chansrv["xrdp-chansrv"]:::longrun
53+
54+
user --> base_init
55+
56+
base_init --> env_setup
57+
base_init --> secrets
58+
base_init --> postgres_init
59+
base_init --> system_fixups
60+
base_init --> pulseaudio
61+
base_init --> tor
62+
base_init --> wireguard
63+
base_init --> dbus_session
64+
65+
env_setup --> shell_rc
66+
system_fixups --> gcroot
67+
system_fixups --> nix_daemon
68+
postgres_init --> postgres
69+
70+
shell_rc --> homedir
71+
shell_rc --> gui_config
72+
shell_rc --> claude_config
73+
shell_rc --> codex_config
74+
shell_rc --> opencode_config
75+
shell_rc --> gemini_config
76+
shell_rc --> antigravity
77+
shell_rc --> mise
78+
nix_daemon --> project_flake
79+
80+
homedir --> chromium_cleanup
81+
gui_config --> xvfb
82+
claude_config --> mcp_toggle
83+
codex_config --> mcp_toggle
84+
opencode_config --> mcp_toggle
85+
mise --> mise_packages
86+
project_flake --> nix_packages
87+
88+
xvfb --> dbus_session
89+
xvfb --> window_manager
90+
xvfb --> x11vnc
91+
xvfb --> xrdp
92+
93+
xrdp --> xrdp_chansrv
94+
dbus_session --> snixembed
95+
window_manager --> wallpaper
96+
97+
subgraph gui ["GUI Stack (DEVCELL_GUI_ENABLED=true)"]
98+
xvfb
99+
dbus_session
100+
snixembed
101+
window_manager
102+
wallpaper
103+
x11vnc
104+
xrdp
105+
xrdp_chansrv
106+
end
107+
108+
style gui fill:none,stroke:#82b366,stroke-dasharray:8 8,color:#333
109+
```
110+
111+
> Blue = oneshot, green = longrun, purple = bundle, **★** = notification-fd=3 (readiness-gated).
112+
113+
## Services
114+
115+
| Service | Type | Platform | Readiness | Notes |
116+
|---------|------|----------|-----------|-------|
117+
| **base-init** | oneshot | all | | `linux/up`, `darwin/up` variants |
118+
| **env-setup** | oneshot | Linux, WinKit | | writes `/etc/s6/env/` |
119+
| **secrets** | oneshot | all | | |
120+
| **postgres-init** | oneshot | all | | |
121+
| **system-fixups** | oneshot | all | | `linux/up`, `darwin/up` variants |
122+
| **pulseaudio** | longrun | Linux, WinKit | | |
123+
| **tor** | oneshot | all | | |
124+
| **wireguard** | oneshot | all | | |
125+
| **shell-rc** | oneshot | all | | |
126+
| **postgres** | longrun | all | | |
127+
| **gcroot** | oneshot | all | | |
128+
| **nix-daemon** | longrun | all | notification-fd=3 | |
129+
| **homedir** | oneshot | all | | |
130+
| **gui-config** | oneshot | all | | |
131+
| **claude-config** | oneshot | all | | |
132+
| **codex-config** | oneshot | all | | |
133+
| **opencode-config** | oneshot | all | | |
134+
| **gemini-config** | oneshot | all | | |
135+
| **antigravity** | oneshot | all | | |
136+
| **mise** | oneshot | all | | |
137+
| **project-flake** | oneshot | all | | |
138+
| **chromium-cleanup** | oneshot | all | | |
139+
| **mcp-toggle** | oneshot | all | | |
140+
| **mise-packages** | oneshot | all | | |
141+
| **nix-packages** | oneshot | all | | |
142+
| **xvfb** | longrun | Linux, WinKit | notification-fd=3 | `:99` |
143+
| **dbus-session** | longrun | Linux, WinKit | | writes `DBUS_SESSION_BUS_ADDRESS` to envdir |
144+
| **window-manager** | longrun | Linux, WinKit | notification-fd=3 | check: `xdotool search --class` |
145+
| **snixembed** | longrun | Linux, WinKit | | reads envdir for `DBUS_SESSION_BUS_ADDRESS` |
146+
| **x11vnc** | longrun | Linux, WinKit | | `:5900` |
147+
| **xrdp** | longrun | Linux, WinKit | | `:3389` |
148+
| **xrdp-chansrv** | longrun | Linux, WinKit | | |
149+
| **wallpaper** | oneshot | Linux, WinKit | | |
150+
| **user** | bundle | all | | `contents.d/` lists all services |
151+
152+
## How It Works
153+
154+
- **Build time**: `s6-rc-compile` (via `s6-linux-renderer.nix`) compiles source definitions from `modules/s6/` into `/etc/s6-rc/compiled/`.
155+
- **Boot time**: entrypoint starts `s6-svscan`, runs `s6-rc-init` to link the compiled DB, then `s6-rc -u change user` brings up all services in parallel dependency order.
156+
- **Privilege model**: s6-svscan runs as root. Services drop to session user via `gosu` in their run scripts. `chmod 0711` on supervise directories lets the session user query status with `s6-svstat`.
157+
- **Envdir** (`/etc/s6/env/`): oneshots write env vars (e.g. `DBUS_SESSION_BUS_ADDRESS`), longruns read them via `s6-envdir`.
158+
- **Dependencies**: declared via `dependencies.d/` directories containing empty files named after deps.
159+
160+
## Known Issues
161+
162+
1. **Compiled DB missing log pipelines** (MEDIUM): per-service s6-log definitions exist in source but aren't in the compiled output. Service stdout goes to the svscan catchall log.
163+
2. **Oneshot up scripts use shell** (LOW): s6-rc-compile expects execline. The community-home compiler wraps them, but pure s6-rc-compile would reject.
164+
3. **xrdp.log root-only** (LOW): session user can't read connection logs. Fixed by #1.

‎docs/testing.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,16 @@ Nightly and release CI run these.
2525
- Only `TestMain` and long tests may call `buildLocalImage`.
2626
- Long tests start with the `testing.Short()` skip: no exceptions.
2727
- Skip messages must name both the missing artifact and the command that supplies it, e.g. `"set DEVCELL_TEST_DEV_IMAGE or run 'cell build --stack dev --thin'"`.
28+
29+
## Terminal bell transport
30+
31+
`go test -v -count=1 ./test/terminal_bell_test.go` runs a small Docker transport
32+
test without the full suite's `TestMain` probes. It requires Docker and a local
33+
`alpine:latest` image (`docker pull alpine:latest`); it never pulls or builds an
34+
image itself.
35+
36+
The container verifies stdin/stdout are terminals, emits BEL (`0x07`) between
37+
markers, and the test checks the exact bytes received through an outer PTY. A
38+
second run without BEL checks the control case. No terminal emulator is needed.
39+
This covers `docker run -it` byte transport, not cell's preflight/entrypoint,
40+
agent notification settings, tmux bell handling, or desktop notifications.

‎go.mod‎

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/DimmKirr/devcell
22

3-
go 1.26.0
3+
go 1.26.8
44

55
require (
66
github.com/BurntSushi/toml v1.4.0
@@ -9,10 +9,12 @@ require (
99
github.com/charmbracelet/huh v1.0.0
1010
github.com/charmbracelet/lipgloss v1.1.0
1111
github.com/charmbracelet/log v1.0.0
12-
github.com/charmbracelet/x/vt v0.0.0-20260712004152-b16d026a9d2e
13-
github.com/charmbracelet/x/xpty v0.1.3
12+
github.com/charmbracelet/x/vt v0.0.0-20261004011457-ad85c59fdf4e
13+
github.com/charmbracelet/x/xpty v0.1.4
1414
github.com/creack/pty v1.1.24
1515
github.com/devcell-sh/go-diskoci v0.1.0
16+
github.com/dimmkirr/go-streak-chart v0.2.1-0.20261009061017-93bdac2bfa7c
17+
github.com/dimmkirr/termoscope v0.3.0
1618
github.com/docker/docker v28.5.1+incompatible
1719
github.com/google/go-containerregistry v0.22.0
1820
github.com/google/uuid v1.6.0
@@ -28,8 +30,8 @@ require (
2830
github.com/swaggo/swag v1.16.6
2931
github.com/testcontainers/testcontainers-go v0.40.0
3032
golang.org/x/crypto v0.55.0
31-
golang.org/x/image v0.41.0
32-
golang.org/x/mod v0.39.0
33+
golang.org/x/image v0.46.0
34+
golang.org/x/mod v0.41.0
3335
gopkg.in/yaml.v3 v3.0.1
3436
k8s.io/client-go v0.36.2
3537
sigs.k8s.io/controller-runtime v0.24.1
@@ -42,7 +44,7 @@ require (
4244
github.com/kr/fs v0.1.0 // indirect
4345
github.com/pkg/sftp v1.13.11 // indirect
4446
github.com/tmc/apple v0.6.18 // indirect
45-
golang.org/x/sys v0.47.0 // indirect
47+
golang.org/x/sys v0.48.0 // indirect
4648
)
4749

4850
require (
@@ -60,12 +62,11 @@ require (
6062
github.com/catppuccin/go v0.3.0 // indirect
6163
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
6264
github.com/cespare/xxhash/v2 v2.3.0 // indirect
63-
github.com/charmbracelet/colorprofile v0.4.2 // indirect
64-
github.com/charmbracelet/ultraviolet v0.0.0-20260303162955-0b88c25f3fff // indirect
65-
github.com/charmbracelet/x/ansi v0.11.7 // indirect
65+
github.com/charmbracelet/colorprofile v0.4.3 // indirect
66+
github.com/charmbracelet/ultraviolet v0.0.0-20261001125412-878653296cfd // indirect
67+
github.com/charmbracelet/x/ansi v0.11.8 // indirect
6668
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
67-
github.com/charmbracelet/x/conpty v0.1.1 // indirect
68-
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 // indirect
69+
github.com/charmbracelet/x/conpty v0.2.0 // indirect
6970
github.com/charmbracelet/x/exp/ordered v0.1.0 // indirect
7071
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
7172
github.com/charmbracelet/x/term v0.2.2 // indirect
@@ -113,12 +114,12 @@ require (
113114
github.com/josharian/intern v1.0.0 // indirect
114115
github.com/json-iterator/go v1.1.12 // indirect
115116
github.com/klauspost/compress v1.19.2 // indirect
116-
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
117+
github.com/lucasb-eyer/go-colorful v1.4.1 // indirect
117118
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
118119
github.com/magiconair/properties v1.8.10 // indirect
119120
github.com/mailru/easyjson v0.7.7 // indirect
120121
github.com/mattn/go-localereader v0.0.1 // indirect
121-
github.com/mattn/go-runewidth v0.0.23 // indirect
122+
github.com/mattn/go-runewidth v0.0.30 // indirect
122123
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
123124
github.com/moby/docker-image-spec v1.3.1 // indirect
124125
github.com/moby/go-archive v0.1.0 // indirect
@@ -159,7 +160,7 @@ require (
159160
github.com/ulikunitz/xz v0.5.15 // indirect
160161
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
161162
github.com/x448/float16 v0.8.4 // indirect
162-
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
163+
github.com/xo/terminfo v1.0.0 // indirect
163164
github.com/yusufpapurcu/wmi v1.2.4 // indirect
164165
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
165166
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
@@ -171,9 +172,9 @@ require (
171172
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
172173
golang.org/x/net v0.58.0 // indirect
173174
golang.org/x/oauth2 v0.36.0 // indirect
174-
golang.org/x/sync v0.22.0 // indirect
175+
golang.org/x/sync v0.23.0 // indirect
175176
golang.org/x/term v0.45.0 // indirect
176-
golang.org/x/text v0.41.0 // indirect
177+
golang.org/x/text v0.42.0 // indirect
177178
golang.org/x/time v0.14.0 // indirect
178179
golang.org/x/tools v0.49.0 // indirect
179180
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect

0 commit comments

Comments
 (0)