HyprCosmic started as a repository beside COSMIC holding a config compiler and a
pile of theme assets, with the two modified components hanging off it. That had
the relationship backwards. COSMIC already has a meta-repo whose whole job is to
name every component and build the desktop from them, so the honest shape for a
fork is to be that meta-repo with the components we changed pointing at our
copies -- not a separate tree that assumes the rest of COSMIC arrived some other
way.
So this merges cosmic-epoch in and repoints exactly two of its 29 submodules:
cosmic-comp -> outbackdingo/hyprcosmic-comp
cosmic-session -> outbackdingo/hyprcosmic-session
The other 27 stay on pop-os. Nothing about them needs to change, and pinning
them to copies we do not maintain would be a promise to keep 27 forks current.
`just build` and `just install` now build and install the whole desktop with our
compositor and session in it, which is what "fork COSMIC" ought to mean. The two
forks still install into /usr/libexec/hyprcosmic rather than over /usr/bin, so a
system that already has COSMIC from its distribution keeps that session on the
greeter's menu alongside this one.
Conflict resolutions worth stating:
.github/workflows/ci.yml upstream's kept as-is. It builds the entire desktop
on Arch through `just sysext`, which is precisely
the check a meta-repo wants and is not made less
useful by forking. Our per-distribution workflow
moved to hyprcosmic.yml beside it, the same way it
did in the compositor fork.
.gitmodules upstream's 29 entries, then two URLs rewritten.
cosmic-comp, cosmic-session
ours. Git reports "no merge base" because they are
unrelated to the pop-os commits recorded here,
which is expected: they are different repositories,
not newer commits of the same one.
.gitignore both sides, plus a note that the two forks are
deliberately no longer ignored.
They were in .gitignore with a note saying they would become submodules once
they had somewhere to live. They do now, so they are, and ignoring them would
from here on only hide which commit of each one this tree is built against.
The paths stay cosmic-comp/ and cosmic-session/, which is where cosmic-epoch
puts them, so this repository can be merged with the upstream meta-repo rather
than laid out beside it.
Running a second cosmic-session on the development machine turns out to be
genuinely dangerous, and twice it logged the developer out mid-session and
destroyed open work. Two distinct causes, both encoded here as guards:
- Name-based process selection cannot distinguish the fork, the system
install, or a stand-in binary; they all answer to `cosmic-session`. The
second logout came from `pgrep -x cosmic-session | head -1` inside the
test written to demonstrate that name matching is unsafe, because `head
-1` favours the oldest match, which is always the live desktop. The
harness therefore never selects a process by name: it spawns under
setsid and signals `-$PGID`, with the group ID taken from `$!`.
- A nested cosmic-session takes the well-known D-Bus name
com.system76.CosmicSession away from the running session on a shared bus
("Connection `:1.3` lost name ..." in the journal), destabilising the
outer desktop before anything is killed. The harness always runs under
dbus-run-session. Nesting cosmic-comp alone does not need this.
It also refuses to start without WAYLAND_DISPLAY, since the winit backend
would otherwise fall back to DRM and seize the real display, and it reaps
IPC socket directories whose owning PID is gone.
Verified: shellcheck-clean syntax; the no-WAYLAND_DISPLAY guard fires; an
audit confirms every `kill` targets the script's own process group and no
code path matches a process by name. NOT verified: the harness has never
been run against the real binaries. Session-level runtime testing is now
deferred to a VM or to logging into hyprcosmic.desktop directly, rather than
nesting inside the developer's live desktop.
cosmic-session joins cosmic-comp in .gitignore; both are forks that become
submodules under the topology in the design spec.
watch: source-include expansion by textual splicing so diagnostic spans stay
correct across merged files; debounced inotify; a bad edit prints diagnostics
and keeps watching rather than killing the daemon.
assets: plan/apply split mirroring emit.rs. Tarball entries and symlink/
hardlink targets are validated before extraction, sharing one routine between
plan and apply so the check cannot drift.
Added tests/archive_escape.rs as independent verification of that boundary.
The tar crate refuses to build hostile archives through its safe API, so the
fixtures write GNU header name/linkname bytes directly — the same thing a
malicious archiver does. Asserts on the filesystem afterwards rather than on
returned errors, and covers symlink indirection, where neither entry path
contains '..' yet a later write still escapes.
99 tests.
Spike results corrected the spec: ThemeBuilder.gaps is (outer, inner) at
cosmic-theme/src/model/theme.rs:895, lives under CosmicTheme.{Dark,Light}.Builder
rather than CosmicTk, and fans out to two components. Entry therefore carries
targets: &[Target].
34 tests, including the folding property that keeps gaps_out from clobbering
gaps_in. Bare #rrggbb colours rejected: # begins a comment, as in Hyprland.
HyDE-style desktop on cosmic-comp: single-file Hyprland-idiom config
compiler, wlr-foreign-toplevel + Hyprland-compatible IPC patches, waybar
in place of cosmic-panel.