Commit Graph
100 Commits
Author SHA1 Message Date
Claude da86b9a160 fix(kyber-linux): fix ___chkstk_ms link error in cmd shim
Large stack array WCHAR[4096] triggered a stack probe (__chkstk_ms)
unavailable in -nostdlib builds. Fix: heap-allocate the pass-through
command line buffer, and add -mno-stack-arg-probe as a safety net.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 23:10:56 +00:00
Claude 11d33efd04 fix(kyber-linux): fix cmd shim compile — replace _wcsicmp with CompareStringOrdinal
_wcsicmp is a CRT function unavailable with -nostdlib/-ffreestanding.
Replace with CompareStringOrdinal from kernel32 (always available).
Also fix step numbering (1-2 were still labeled /5 instead of /7),
and remove 2>/dev/null from compile so errors are visible if it fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 23:07:55 +00:00
Claude 331f8d1e19 fix(kyber-linux): prevent duplicate shortcuts; fix sudo for mingw-w64
- Python shortcut script now checks for existing 'Kyber Launcher' entry
  and exits early instead of appending a duplicate on each re-run
- Use sudo apt-get directly for mingw-w64 install so the password prompt
  works (previous chained || approach suppressed the interactive prompt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 23:02:38 +00:00
Claude 38ef272dce feat(kyber-linux): add cmd shim + OAuth watcher for login fix
Wine's cmd.exe crashes (0xC0000005) when Kyber calls cmd /c start with
the EA auth URL, on native Linux Steam just as in Wolf. Fix:

1. Compile a minimal cmd shim with mingw-w64 (auto-installed if missing).
   The shim intercepts cmd /c start <http url>, writes the URL to
   C:\kyber_oauth_url.txt, and exits 0. All other cmd invocations are
   passed through to the backed-up cmd-real.exe.
   Installed into the Kyber prefix's system32 only — does not affect
   other games or Proton globally.

2. Install a watcher script (~/.local/bin/kyber-oauth-watcher.sh) that
   polls for the URL file and calls xdg-open to open it in the system
   browser. Registered as a systemd user service so it starts on login.

Login flow: Kyber → cmd shim → URL file → watcher → xdg-open → browser
→ EA login → redirect to 127.0.0.1:PORT → Kyber loopback catches code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 22:47:36 +00:00
Claude b147120688 fix(kyber-linux): skip installer if Kyber.exe already present; fix re-run
On re-run the installer was trying to overwrite locked files in an existing
prefix, causing repeated Access Denied dialogs. Now check for Kyber.exe
first and skip the installer entirely if it's found.

Also kill any leftover Wine/Proton processes before a fresh install to
avoid file-lock conflicts, and move Windows path resolution to after the
installer/skip decision so it always runs regardless of path taken.

Default fallback path updated to match Kyber's actual install location:
  C:\Program Files (x86)\KYBER Launcher\

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 22:31:47 +00:00
Claude f425912bc8 fix(kyber-linux): handle shortcuts.vdf permission error gracefully
If shortcuts.vdf exists but is not writable, attempt chmod 644 before
writing. If that also fails, print a clear instruction and skip the
shortcut step rather than crashing with a Python traceback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 21:58:48 +00:00
Claude 23c1699b05 fix(kyber-linux): install WebView2 via standalone installer, not bootstrapper
The Evergreen bootstrapper (linkid=2124703) requires a second download from
inside the Wine process, which fails in Proton. Switch to the standalone
offline installer (linkid=2135547, ~150 MB) which installs without any
Wine-internal network calls.

Also prefer winetricks if installed — it uses a local cache, handles the
WINEPREFIX env correctly, and is the most reliable method. Fall back to
the standalone download if winetricks is not available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 21:41:54 +00:00
Claude 66eb9f9bef fix(kyber-linux): use correct download URL — zip from api.prod.kyber.gg
Replace guessed CDN URL with the real API endpoint:
  https://api.prod.kyber.gg/download/kyber-installer-win64.zip

The download is a zip, so extract the .exe before passing it to Proton.
Requires unzip (standard on Ubuntu).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 21:35:28 +00:00
Claude 970d6b1ab2 feat(kyber-linux): auto-download KyberLauncher.exe if not present
Instead of erroring when the installer is missing, attempt to fetch it
automatically: first scrape kyber.gg for a direct .exe link, then fall
back to a known CDN path. If download fails, print the manual instruction
and exit cleanly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 21:32:35 +00:00
Claude 5f61c7bad2 fix(kyber-linux): correct login flow docs — Maxima loopback OAuth, not WebView2
Kyber uses a PKCE loopback OAuth flow (Maxima): it starts a temporary
HTTP server on 127.0.0.1 and calls cmd /c start to open the EA auth URL
in the system browser. On native Linux, Wine's cmd passes http:// URLs
to xdg-open, which works fine inside Steam's single bwrap layer.

Remove the incorrect claim that WebView2 intercepts qrc:// URIs and is
the only path to completing login. Keep the WebView2 runtime install
(harmless, prevents in-app render errors) but clarify it is not the
login mechanism.

Update end-of-script instructions to describe what the user will actually
see: browser opens EA page, redirects to 127.0.0.1:PORT, tab shows OK or
connection-refused (normal), login completes in Kyber. Add troubleshooting
notes for the two real failure modes: xdg-open not reaching the desktop
(headless/no DISPLAY), and login timeout (loopback server expired).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-23 20:14:06 +00:00
Claude 351bfc47e8 Add fix-wolf-webview2-userns.sh — finish Kyber-in-Wolf
The WolfSteam app container already runs seccomp=unconfined + apparmor=unconfined
+ SYS_ADMIN, so the WebView2 CLONE_NEWUSER failure is gated at the HOST level by
kernel.apparmor_restrict_unprivileged_userns=1 (default-on since Ubuntu 23.10),
which overrides the unconfined container. This script relaxes that sysctl (and
the legacy unprivileged_userns_clone) persistently, then probes userns creation
on the host and inside the running container so login can complete without
leaving Wolf.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-23 14:25:56 +00:00
Claude 30df687540 Add setup-kyber-linux.sh for native Linux Steam
Runs Kyber outside Wolf so its embedded WebView2 can initialize without
nested-bwrap blocking CLONE_NEWUSER. Builds the Wine prefix, ensures the
WebView2 Evergreen runtime is installed (the component that intercepts EA's
qrc:// OAuth redirect), registers Kyber as a non-Steam shortcut forced to
Proton Experimental, and notes the Steam Remote Play path for headless boxes.
No fake cmd.exe / Firefox scaffolding needed here.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-23 14:18:45 +00:00
Claude 9573c8d010 Add setup-kyber-wolf.sh for Kyber Launcher in Wolf container
Documents the complete Kyber/EA OAuth investigation: root cause is EA's
qrc:// redirect URI which only Kyber's embedded WebView2 can intercept;
WebView2 cannot initialize inside Wolf due to nested bwrap blocking
CLONE_NEWUSER. Script automates all discovered workarounds (fake cmd.exe,
Firefox profile with network.process.enabled: false) and clearly documents
why the real fix is running Kyber outside the Docker container.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-23 13:41:14 +00:00
Claude d6c0fc2014 fix: _steam_home() prefers container that is currently running
With multiple WolfSteam containers, the previous head -1 pick was
arbitrary. Now matches each Steam state directory against running
container IDs so ge-proton, fix-ea-game, and other commands all
target the active session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 22:26:56 +00:00
Claude dd56f3f837 fix: search all Wolf Steam homes for AppID prefix, not just head -1
With multiple WolfSteam containers running, _steam_home() picks the first
Steam directory found which may not contain the target game's prefix.
_apply_ea_fix now scans all Wolf Steam homes and selects the one that has
the AppID's Proton prefix, falling back to the original behavior if none
match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 20:40:39 +00:00
Claude 77e40d4955 fix: lock config directory so Steam cannot overwrite launch options
Steam writes localconfig.vdf via atomic rename (write temp + rename over
original). chmod 444 on the file is bypassed by the rename. chmod 555 on
the directory blocks rename-into, preserving the launch option across
Steam restarts.

Also unlocks the directory at the start of step 6 so re-running the
script can update the launch option.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 18:08:57 +00:00
Claude 0c56837505 fix: detect existing EA Desktop install, skip MSI extraction if Link2EA.exe present
On native Linux Steam, EA App self-installs via EAappInstaller.exe on first
SWBF2 launch. Link2EA.exe appears in the Wine prefix without any MSI extraction.
Script now checks for Link2EA.exe first and skips steps 2-3 (MSI locate +
extract) if EA Desktop is already installed, proceeding directly to writing
registry fix files and the launch wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 17:51:58 +00:00
Claude e33b2f6491 fix: search game files for ea_app.msi, not just drive_c
The MSI is bundled in steamapps/common with the game files. The script
was only checking drive_c (where Steam copies it after a launch), causing
a false "not found" error before the user had launched the game.

Now searches steamapps/common and all of steamapps as fallbacks, reports
which path it found the MSI at. Also remove stale references to the
"Origin is not installed" error which no longer appears.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 17:23:43 +00:00
Claude 92fd67ec34 feat: auto-install msitools in both SWBF2 setup scripts
Both scripts now detect and install msitools if missing, supporting
apt-get (Debian/Ubuntu), dnf (Fedora), and pacman (Arch). Falls back
to a clear error if the package manager is not recognised.

Remove msitools from manual prerequisites in the doc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 16:31:42 +00:00
Claude 7f926c03af feat: add GE-Proton auto-install to both SWBF2 setup scripts
Both scripts now download and install GE-Proton10-34 if not already present:
- setup-swbf2-linux.sh: installs to ~/.steam/root/compatibilitytools.d/
- setup-swbf2-wolf.sh: installs into the WolfSteam container via docker cp + tar

Both pause after install and prompt the user to set GE-Proton in Steam
(Compatibility → Force) before continuing, since that step requires the GUI.

Update docs to reflect GE-Proton is now handled automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 16:15:24 +00:00
Claude 1b29873f62 docs: rename wolf-setup to linux-setup, native Linux section first
- Rename SWBF2-2017-wolf-setup.md -> SWBF2-2017-linux-setup.md
- Move Native Linux Steam section before Wolf/Moonlight section
- Update TOC link order to match

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 14:37:46 +00:00
Claude 11a7c6529c docs: rewrite SWBF2 setup guide as clean how-to with native Linux section
- Remove editorial content (EA server speculation, 2005 alternative, opinions)
- Add native Linux Steam section covering all six setup steps
- Add separate key paths tables for Wolf and native
- Add native Linux troubleshooting commands alongside Wolf equivalents
- Rename title to reflect both platforms
- Fresh install table rewritten as factual survival matrix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 14:21:22 +00:00
Claude 4324ad7ce2 docs: add SWBF2 2017 discovery writeup explaining why the fix works
Long-form document tracing the actual discovery process: the wrong turns,
the aha moments, and the reasoning behind each step. Covers:

- Why EA is involved in a Steam game at all (link2ea:// architecture)
- JunoConfigureRegistry failure and why DISABLEROLLBACK was a dead end
- msiextract bypass as the actual solution
- Why direct system.reg edits don't survive reboots (wineserver ownership)
- The launch wrapper approach for registry persistence
- RPC_S_SERVER_UNAVAILABLE and EALocalHostSvc
- Wolf-specific bwrap capabilities mismatch
- localconfig.vdf atomic rename problem and chmod 555 fix

Written for sharing — no identifying information, explains the "why"
for each fix so readers can adapt if EA changes their MSI structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 13:26:11 +00:00
Claude c6d58a7ccd feat: add standalone SWBF2 2017 setup scripts for Wolf and native Linux Steam
Two self-contained scripts for getting SWBF2 (2017, AppID 1237950) working
with GE-Proton on Linux — no dependency on the ubuntu-post-install framework.

setup-swbf2-wolf.sh  — for Wolf/Games-on-Whales + Moonlight streaming
setup-swbf2-linux.sh — for native Linux Steam (no Docker)

Both implement the same core fix:
- msiextract bypass for JunoConfigureRegistry Wine incompatibility
- EA Desktop files copied into Wine prefix from extracted MSI
- link2ea_fix.reg + ea_services.reg written to drive_c
- Launch wrapper that imports .reg files via Proton on every launch
  (direct system.reg edits are overwritten by wineserver on shutdown)

Wolf version also handles Docker cp, container paths, STEAM_UNIX_SOCKET,
and localconfig.vdf directory locking inside the Wolf state folder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 12:59:49 +00:00
Claude 8084276738 feat(wolf): add setup-swbf2 command for full SWBF2 2017 Wolf/Moonlight setup
Automates the complete working solution for SWBF2 (AppID 1237950) on Wolf:

1. Extracts EA Desktop from ea_app.msi using msiextract on the host,
   bypassing JunoConfigureRegistry Wine incompatibility that causes MSI rollback
2. Copies EA Desktop files (Link2EA.exe, EALocalHostSvc.exe, etc.) into the
   Wine prefix at the versioned path with symlink
3. Writes link2ea_fix.reg and ea_services.reg into drive_c so they persist
   across Wine prefix operations
4. Installs a launch wrapper (/home/retro/ea_install.sh) that runs regedit
   via Steam's sniper+GE-Proton launch chain — required because direct edits
   to system.reg are overwritten when wineserver flushes on shutdown
5. Sets LaunchOptions for AppID 1237950 in localconfig.vdf and locks the
   config directory (chmod 555) to prevent Steam overwriting it via
   atomic rename on shutdown

Run after: Steam open in Moonlight, GE-Proton set, SWBF2 launched once
(triggers Wine prefix + ea_app.msi creation), EA account linked at ea.com.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 12:38:05 +00:00
Claude b756e7eedb docs: rewrite SWBF2-2017 guide with working msiextract + wrapper solution
Complete rewrite reflecting the actual working setup:
- msiextract on host bypasses JunoConfigureRegistry Wine incompatibility
- Wrapper script imports registry fixes via regedit through Steam's launch chain
- chmod 555 on config dir prevents Steam overwriting localconfig.vdf
- Honest fresh-install assessment table (what's automated vs one-time manual)
- Troubleshooting section covering all errors encountered
- Key paths reference table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 12:35:14 +00:00
Claude 5cff764d3b docs: add EA auth dependency context, login process, and longevity notes
Documents the EA account requirement, first-time login flow, credential
caching for machine transfers, community server options if EA shuts down,
and the SWBF2 2005 alternative for a launcher-free experience.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 05:02:19 +00:00
Claude 6b385e62ba docs: update SWBF2 guide with direct-exe bypass and Origin registry spoof
Revised approach: skip link2ea:// and EA App account requirement entirely.
Launch starwarsbattlefrontii.exe directly via the wrapper, spoof Origin
registry entries so the game's built-in launcher check passes. Documents
what doesn't work and why (msiexec/bwrap/EA account issues).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 04:25:26 +00:00
Claude 0202515163 docs: add SWBF2 2017 Wolf/Moonlight setup guide
Documents the EA App installation workaround for Star Wars Battlefront II
(2017) running under Wolf/WolfSteam with GE-Proton10-34. Covers the bwrap
capability problem, Steam launch wrapper trick, msiextract bypass for the
JunoConfigureRegistry Wine incompatibility, and correct EA Desktop file layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 03:56:56 +00:00
Claude b031d7e7d4 fix(wolf): use wineserver -f as anchor instead of cmd.exe timeout
wine cmd.exe /c "timeout /t 900 > nul" failed silently (docker exec -d
hides errors), leaving no anchor process and letting wineserver die as
soon as EAappInstaller.exe exited.

Replace with wineserver -f (foreground mode) which keeps the server
alive unconditionally until explicitly killed with wineserver -k.
This is the correct primitive for holding a Wine session open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 19:21:40 +00:00
Claude 70a7b83cc4 fix(wolf): keep wineserver alive during EA App install
EAappInstaller.exe is a WiX/Burn bootstrapper that spawns the real
installer as a background Wine process and exits immediately. When the
foreground wine process exited, wineserver shut down and killed the
background installer before it could write any files.

Fix: launch a cmd.exe/timeout anchor before running the installer so
the shared wineserver stays up while background installer processes run.
Kill the anchor (wineserver -k) after EADesktop.exe is detected or the
15-minute timeout expires.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 19:13:59 +00:00
Claude 7eadf642b7 wolf: fix install-ea-app — correct installer path, clear fake InstallSuccessful
Two bugs in install-ea-app:

1. Installer search included compatdata (the Wine prefix), so it found the
   temp-extracted copy at drive_c/windows/temp/{UUID}/.cr/EAappInstaller.exe
   instead of the bundled copy at steamapps/common/…/__Installer/…/
   Fixed: search only under steamapps/common.

2. Our fake InstallSuccessful=true (written by fix-ea-game to bypass the
   install-script loop) caused EAappInstaller to detect EA App as "already
   installed" and exit in ~15 seconds without doing anything.
   Fixed: delete the InstallSuccessful values via wine reg delete inside the
   container BEFORE launching the installer. The real EA App installer writes
   them back correctly after a successful install.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 19:02:04 +00:00
Claude ddf481b72f wolf: add install-ea-app and diagnose-ea, fix link2ea registration
install-ea-app: runs EAappInstaller.exe inside the WolfSteam container
using GE-Proton's wine binary. The container has a virtual display so the
EA App installer GUI appears in Moonlight; the user clicks through it and
logs in to their EA account. After EA App installs, fix-ea-game registers
the link2ea:// handler and clears the install-script loop.

diagnose-ea: prints the current link2ea:// registry state from both
system.reg and user.reg, locates EADesktop.exe/Link2EA.exe, shows
StateFlags, and tails the relevant Proton log lines — the first thing to
run when the game returns straight to the Play screen.

_apply_ea_fix: now checks user.reg as well as system.reg for an existing
link2ea:// registration (GE-Proton writes to user.reg during prefix setup);
also searches for Link2EA.exe as a fallback handler when EADesktop.exe is
not yet installed; reports a clear next step when neither is found.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 18:50:22 +00:00
Claude 02ae1ae02c wolf: pre-download GE-Proton at install time, auto-extract on start
GE-Proton is required for EA games but was a manual step users had to
remember after first Steam launch. This change eliminates that gap:

- install_wolf() downloads the GE-Proton tarball to
  ~/docker/wolf/ge-proton-cache/ during initial setup (~500 MB, runs
  before the "Start Wolf now?" prompt so it's ready immediately)
- _cache_ge_proton() helper in manage.sh does the same on demand
- ge-proton subcommand checks the cache dir first and extracts from
  there instead of re-downloading (~instant vs ~500 MB download)
- start subcommand auto-extracts the cached tarball into Steam's
  compatibilitytools.d if Steam has already launched at least once,
  so GE-Proton appears in the Compatibility dropdown without any
  manual ./manage.sh ge-proton step

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 17:27:19 +00:00
Claude ef6a63a908 wolf: register link2ea:// handler and add wait-ea-app subcommand
SWBF2 (AppID 1237950) launches, calls ShellExecute("link2ea://..."),
and exits. Without a link2ea:// URL protocol handler registered in the
Wine registry, ShellExecute returns error 31 and the game never plays.

_apply_ea_fix now also writes the link2ea:// Classes registry keys
pointing to EADesktop.exe when it is found in the Proton prefix. If
EADesktop.exe is not yet present (EAappInstaller runs async via
RunType=1 in installScript.vdf), the function warns and skips the
handler registration with instructions to run wait-ea-app.

New 'wait-ea-app [appid]' subcommand polls every 15 seconds (up to 20
minutes) for EADesktop.exe to appear, then calls _apply_ea_fix so the
full fix including the link2ea:// handler is applied automatically once
EA App finishes installing in the background.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 16:50:03 +00:00
Claude a1b4107e3e fix(wolf): stop Steam container before patching EA registry to survive wineserver flush
wineserver holds the Wine registry in memory and flushes it back to
system.reg on shutdown, overwriting any edits made while the container
is running. _apply_ea_fix now stops the WolfSteam container first,
patches system.reg + appmanifest StateFlags on disk, then restarts Wolf
so the keys persist when wineserver next starts.

Also sets StateFlags to 6 (fully installed) so Steam skips the
install-script phase entirely and launches the game directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 05:11:40 +00:00
Claude 74d4e0d0e7 wolf: register tab-completion for both 'manage.sh' and './manage.sh'
Bash treats these as different command names so both need registering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 02:24:51 +00:00
Claude f462c6baa2 wolf: fix steam-cache mount missing from configure-apps CATALOG block
The first Python CATALOG (used at initial install time) was missing the
steam-cache mount that the update-apps block had. Both paths now include
the persistent cache mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 02:09:52 +00:00
Claude 0785d30199 wolf: add install-completion to README manage section + tab-completion note
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 02:08:17 +00:00
Claude 40bb80bc7a wolf: persist Steam shader cache across sessions
Mount GAME_STORAGE_DIR/steam-cache → /home/retro/.cache so DXVK/Mesa
Vulkan shader compilations survive container restarts. Without this the
cache lived in the ephemeral session home and was wiped on every Wolf
restart, forcing a full recompile each session.

Also create steam-cache/ in initial setup and update-storage so the
directory exists with correct uid-1000 ownership before the container
first starts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 01:50:25 +00:00
Claude 3f6e359c7b wolf: make 'games' interactive — pick a number to apply the EA fix
./manage.sh games now lists installed games numbered with their AppIDs,
then prompts for a number to apply the EA App install-script fix to that
game (Enter to skip). Factored the reg-fix into a shared _apply_ea_fix
helper used by both 'games' and 'fix-ea-game'. The EA Desktop installed
marker is shared across all EA titles, so the same fix works for any EA
game — the picker just supplies the right per-game AppID.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-21 00:02:48 +00:00
Claude d32832ec75 wolf: add tab-completion + clarify fix-ea-game is universal for EA titles
- install-completion: writes a bash completion script to
  ~/.bash_completion.d/manage-wolf and registers it, so double-tab
  after './manage.sh ' shows all available commands.
- fix-ea-game kept as general name (not fix-swbf2-2017): the EA Desktop
  registry key is shared across all EA games; the Valve has-run key
  follows the same EADesktopSetup pattern across EA's catalog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 23:53:00 +00:00
Claude 3a09c6b6ea wolf: add 'games' AppID lister + GE-Proton version pin + README docs
- ./manage.sh games: lists installed Steam games with their AppIDs
  (parsed from appmanifest_*.acf) so users can find the AppID to pass to
  fix-ea-game instead of hunting for it.
- ./manage.sh ge-proton [version]: optional arg pins a specific
  GE-Proton release for reproducibility; still defaults to latest.
- Document the full EA-games flow + AppID/version notes in the generated
  ~/docker/wolf/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 23:47:03 +00:00
Claude dcb28adc4f wolf: add ge-proton + fix-ea-game manage commands for EA titles
Add two manage.sh commands that bake in the workarounds needed to run
EA Steam titles (e.g. Star Wars Battlefront II 2017) under Proton in a
container:

- ge-proton: downloads the latest GE-Proton into Steam's
  compatibilitytools.d (the path Steam actually scans) and chowns it to
  uid 1000 so the in-container user can launch it. GE-Proton carries the
  EA App installer fixes stock Proton/Experimental lack.

- fix-ea-game [appid]: pre-satisfies the EA App install-script markers
  in the game's Proton prefix (InstallSuccessful + Valve EADesktopSetup
  has-run key) so Steam stops looping on 'running install script (EA
  app)'. Opt-in per AppID, defaults to SWBF2 1237950, no-ops if the
  prefix doesn't exist, idempotent, and keeps the prefix owned by uid
  1000 so Wine accepts it.

Also document the EA-game flow in the post-install summary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 23:42:51 +00:00
Claude 2b6cf7700c wolf: drive app-container timezone from .env (WOLF_TZ) to fix Steam/EA time
App containers were defaulting to a non-local timezone (e.g. BST), showing the
wrong local time in Steam — and a skewed clock can stall EA App's installer.
The kernel clock is shared with the host, so this is a display/TZ issue: fix
it by setting each app's TZ env var, sourced from SITE_TZ at install and from
WOLF_TZ in .env for ./manage.sh apps.

Also generalize the array updater to rewrite both `mounts` and `env` (Wolf
reformats either as multi-line), so re-running apps updates the TZ on
already-installed entries without corrupting the TOML.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 18:44:10 +00:00
Claude dd7df8ce18 wolf: mount host timezone into Steam container
/etc/localtime and /etc/timezone are bind-mounted read-only so the Steam
container shows the correct local time. A wrong clock causes EA App install
scripts to hang indefinitely (SSL/token validation against EA's servers fails
when the client clock is skewed).

Fix the host clock first: sudo timedatectl set-ntp true

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 17:19:04 +00:00
Claude 9d2e0848e6 wolf: make add-web actually open the URL (firefox policy) + replace on re-add
The GoW firefox image launches `firefox` with no URL and ignores START_URL,
so add-web tiles opened a blank default tab. Instead generate a per-app
Firefox enterprise policy (policies.json) that sets the homepage to the
target URL and bind-mount it over /etc/firefox/policies/policies.json so the
site loads on launch.

Also make add-web replace an existing tile of the same name instead of
erroring, so re-running it repairs a previously broken tile in place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 16:23:38 +00:00
Claude 3aab169fbc wolf: fix config.toml corruption when re-running on an existing install
Wolf rewrites config.toml on every start and reformats `mounts` as a
multi-line TOML array. update_mounts() only replaced the single line
starting with `mounts =`, leaving the remaining array elements and the
closing `]` orphaned — producing invalid TOML ("Expected '=' after a key")
that crashed Wolf on the next start. This bit any re-run of the installer
(or `./manage.sh apps`) against a config Wolf had already reformatted.

Replace the entire array (from `mounts =` to its closing `]`), and also
clean up orphaned remnants left by a previously corrupted single-line
rewrite so re-running the script repairs a broken config in place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 15:55:44 +00:00
Claude 37f85d6adf wolf: add ./manage.sh add-web — URL shortcut tiles in Moonlight via Firefox kiosk
Prompts for a display name and URL, auto-fetches the site's apple-touch-icon
or favicon.png, falls back to a manual URL/local-PNG prompt, then injects a
[[profiles.apps]] block using ghcr.io/games-on-whales/firefox:edge with
START_URL set to the target URL. Wolf's virtual gamepad injection means
controller-aware sites (Gamepad API) work naturally through the stream.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 15:21:30 +00:00
Claude b72e2bf549 wolf: add interactive 'manage.sh reorder' for Moonlight tile order
Moonlight shows app tiles in config.toml order with no in-client reordering.
Add ./manage.sh reorder: lists the current [[profiles.apps]] blocks by title,
prompts for a new order (read from /dev/tty since stdin is the heredoc),
rewrites config.toml preserving each block's nested runner subtable and
spacing, then restarts Wolf. Updated help text and README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 15:11:34 +00:00
Claude f71edf1aad wolf: read WOLF_STATE_DIR from .env at runtime, not baked into compose
docker compose reads variables from .env automatically. Use ${WOLF_STATE_DIR}
in docker-compose.yml so the state folder path is dynamic — editing .env is
enough to relocate it without regenerating the compose file. IP/MAC/render
node stay baked in (hardware-specific, not in .env).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 13:56:22 +00:00
Claude 1a85ddf063 wolf: relocate Wolf's state folder to the game drive (no symlinks/vdf)
The right fix, finally. Instead of fighting Steam's libraryfolders.vdf or
symlinking individual app session homes, point Wolf's entire state folder at
the game drive. Steam's install, downloaded games, and Proton prefixes are
born there because Wolf creates every app's session home under
HOST_APPS_STATE_FOLDER.

- docker-compose.yml: mount $WOLF_STATE_DIR (=<game_dir>/wolf-state) at the
  SAME path inside and outside the wolf container, set HOST_APPS_STATE_FOLDER
  and WOLF_CFG_FOLDER to it. Same-path mount is required because Wolf hands
  host paths to the Docker daemon when spawning sibling app containers.
- config.toml now lives at $WOLF_STATE_DIR/cfg/config.toml; all WOLF_CFG
  references updated (install + manage.sh, via WOLF_STATE_DIR in .env).
- Optional migration: move existing /etc/wolf data onto the drive on upgrade.
- Removed all symlink machinery: relocate_steam_home, steam-home dir,
  _relocate_steam_home in manage.sh, and the fix-perms relocation step.
  fix-perms now just re-owns the state folder + game storage.
- Dropped the redundant Steam app mount; updated README/summary text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 13:44:10 +00:00
Claude df988cca3c wolf: put Steam home on the game drive via symlink, not libraryfolders.vdf
Seeding libraryfolders.vdf never stuck: Steam rewrites that file on every
launch and forces its primary library back to its own install dir
(/home/retro/.local/share/Steam), which is the Wolf session home on the OS
drive. That's why Steam Storage kept showing /home/retro with the OS drive's
size no matter how many times we seeded the vdf.

New approach: relocate_steam_home symlinks each Wolf Steam session home
(/etc/wolf/<id>/Steam, bind-mounted to /home/retro) at
$GAME_STORAGE_DIR/steam-home. Steam's one and only library is then the game
drive, so installs, game files, and Proton prefixes all land there and the
Storage screen reports the game drive's free space. An existing Steam install
is moved over once (no re-download) before the symlink is created.

Wired into first install, manage.sh start (self-heals on reboot), and
manage.sh fix-perms. Dropped the redundant /mnt/games/steam mount and the
vdf seeding everywhere; updated the README heredoc with the one-time
connect / fix-perms / reconnect sequence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 13:13:50 +00:00
Claude 2ac7d6898d wolf: seed Steam libraryfolders.vdf into session dirs after first install
After app injection + docker compose restart, Wolf creates per-app session
dirs under /etc/wolf/<id>/Steam. Wait up to 30s for those dirs to appear,
then copy the pre-built libraryfolders.vdf into each one so Steam sees the
game storage location on its very first launch — no manual setup needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 12:53:50 +00:00
Claude b3b5cc9b6e wolf: auto-seed Steam library config on manage.sh start
Wolf creates /etc/wolf/<id>/Steam/ session dirs when the container starts,
not at install time. Previously the user had to manually run fix-perms after
first start to propagate libraryfolders.vdf.

manage.sh start now calls _seed_steam_library() after docker compose up,
which copies libraryfolders.vdf from game storage into any Wolf session dir
that doesn't have it yet — so the correct library path (/mnt/games/steam)
is in place before the first Moonlight connection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 12:17:02 +00:00
Claude 16f4f56168 wolf: seed Steam libraryfolders.vdf into Wolf session home dir
Steam reads libraryfolders.vdf from /home/retro/.local/share/Steam/steamapps/
which Wolf serves from /etc/wolf/<session-id>/Steam/. Seeding it only in
/mnt/games/steam/steamapps/ was ignored since Steam doesn't know to look there.

- Seed the VDF into any existing /etc/wolf/<id>/Steam session dirs at install time
- manage.sh fix-perms now propagates the VDF from game storage into every
  Wolf session dir so running fix-perms is the one-command remedy on existing
  installs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 06:11:44 +00:00
Claude f735825ad9 wolf: list mounted drives via lsblk -P so whole-disk mounts show in picker
The drive picker enumerated mounts with `lsblk MOUNTPOINT | df` round-trips,
which could miss a whole-disk mount (e.g. an nvme formatted directly with no
partition table). Switch to `lsblk -Pno NAME,MOUNTPOINT,SIZE,LABEL,UUID` and
parse the key="value" pairs directly — handles whole-disk mounts and empty
LABEL/UUID fields reliably, so every mounted data drive appears as a numbered
choice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 06:00:46 +00:00
Claude bd84f1df1e wolf: pre-seed Steam libraryfolders.vdf so game storage dir is set on first launch
Creates steamapps/libraryfolders.vdf pointing at /mnt/games/steam during
install so Steam uses the correct library path without needing the user to
navigate Settings → Storage on first launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 05:50:19 +00:00
Claude e7f65d127c wolf: add fix-perms command and document app home-dir ownership fix
Wolf mounts each app's home dir from /etc/wolf/<session-id>/<App> into the
container as /home/retro. If anything there is root-owned (e.g. left over
from an earlier mount layout), the in-container retro user (uid 1000) hits
"Permission denied" creating ~/.steam and the app exits on launch.

- Add `./manage.sh fix-perms`: chowns every /etc/wolf/<id>/ app home dir
  and the on-disk game storage to uid/gid 1000
- Document the /mnt/games mount layout, first-Steam-launch library step,
  3DS/Azahar emulator path, and the fix-perms troubleshooting flow in the
  generated README

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 05:44:13 +00:00
Claude 01c4dd8525 wolf: mount game storage at /mnt/games/* not /home/retro/* paths
Mounting into /home/retro subpaths causes Docker to create intermediate
directories (/.local/share/Steam etc.) as root-owned in the container
overlay before init runs. The GoW init chown step doesn't fully fix these,
so the retro user hits Permission denied on first write.

Move all mounts to neutral /mnt/games/* paths that don't interfere with
the container's home directory setup:
  steam    → /mnt/games/steam    (add as Steam Library Folder via UI)
  lutris   → /mnt/games/lutris
  kodi     → /mnt/games/kodi
  firefox  → /mnt/games/firefox
  minecraft → /mnt/games/minecraft
  saves    → /mnt/games/saves
  emulators → /mnt/games/emulators

ROMs stay at /ROMs (GoW ES-DE hardcodes that path).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 05:17:41 +00:00
Claude c10bf62c79 wolf: fix duplicate /home/retro mount — target Steam library path directly
Mounting steam:/home/retro conflicted with the GoW Steam image's own
internal /home/retro mount. Mount steam:/home/retro/.local/share/Steam
instead — this is where steamapps/ and Proton prefixes actually live,
persists all game data, and doesn't collide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:59:37 +00:00
Claude 87414bdc44 wolf: fix manage.sh apps permission denied on /etc/wolf/cfg/config.toml
config.toml is root-owned (Wolf container writes it as root). manage.sh
runs as the regular user, so python3 and grep against the file need sudo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:56:04 +00:00
Claude 54082ad8b0 wolf: fix Steam storage mount, add Azahar 3DS emulator, emulators/ dir
- Steam mount was steam:/home/retro/.steam — games download to
  /home/retro/.local/share/Steam/steamapps/ which was NOT mounted and
  lived in the ephemeral container layer. Fixed to steam:/home/retro
  so the full home dir (library, user data, Proton prefixes) persists.
- Add emulators/ subdir to game storage layout; mounted into ES-DE
  container at /home/retro/Applications (ES-DE's default AppImage search path)
- Add optional Azahar (open-source Citra fork) AppImage download at
  install time — fetches latest release from GitHub, chmod +x, places
  in emulators/ where ES-DE finds it automatically for nintendo3ds ROMs
- Update README to document new storage layout and 3DS emulation setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:46:48 +00:00
Claude 73a41e7252 wolf: redesign app selection with numbered menu, ES-DE ROM dirs, and manage.sh apps command
- Drive picker: numbered list with UUID display, mounted + unmounted drives,
  explicit system-path exclusions (no regex bare-/ bug), skip whole disks
  with mounted partitions
- Pre-create ES-DE ROM system directories (~50 systems) so ES-DE detects
  all platforms on first launch
- App selection at install time: numbered menu for Steam, ES-DE, Lutris,
  RetroArch, Prism Launcher, Kodi, Firefox, Desktop
- Python catalog-driven TOML injector shared between install and manage.sh;
  supports update_mounts() to patch paths on re-run without duplicating entries
- manage.sh `apps` command replaces `add-apps` / `update-storage`: shows
  installed apps, interactive picker, updates game storage path from .env
- Game storage written to ~/docker/wolf/.env as GAME_STORAGE_DIR

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:41:59 +00:00
Claude fa906186c3 fix(services): conditional caddy_net across all Docker service scripts
Only include the caddy_net network block in generated docker-compose.yml
files when ~/docker/caddy exists. Prevents "network caddy_net declared
as external, but could not be found" on standalone installs without Caddy.

Affected: actualbudget, archivebox, arm, audiobookshelf, calibre-web,
changedetection, drum-rhythm-game, emby, fmd, frigate, frigate-audio,
frigate-notify, gatus, homeassistant, immich, iopaint, jellyfin, joplin,
koha, lyrion, magicmirror, mail-archiver, mattermost, mealie, meshcentral,
n8n, nextcloud, ntfy, onlyoffice, portainer, stirling-pdf, syncthing,
traccar, unifi, uptimekuma, vaultwarden, wg-easy

Skipped: authelia (creates caddy_net itself), caddy, crowdsec, wolf,
wolf-pair, and services using network_mode: host with no caddy_net.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:16:41 +00:00
Claude 68a4effad5 fix(services): conditional caddy_net for filebrowser, homebox, watchtower
Only include the caddy_net network block in docker-compose.yml when
~/docker/caddy exists, preventing "network not found" errors on
standalone installs without Caddy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 04:06:51 +00:00
Claude 07d09a73fe fix(js99er): missing write_readme stub + conditional caddy_net
- Add write_readme() to the standalone bootstrap stubs (was defined in
  wolf-pair.sh and other services but missing here)
- Only include the caddy_net network block in docker-compose.yml when
  ~/docker/caddy exists; otherwise docker compose up fails with
  "network caddy_net declared as external, but could not be found"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 03:49:53 +00:00
Claude 88ac2ac06a fix(wolf-pair): set allow_reuse_address so restarts don't hit EADDRINUSE
HTTPServer.allow_reuse_address must be set before __init__ calls
server_bind(). Setting it as a class attribute before instantiation
is the correct pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 03:29:58 +00:00
Claude 63ee2e8aff fix(wolf-pair): remove stray networks block from docker-compose.yml
network_mode: host containers cannot join Docker networks, so the
caddy_net networks: block was dead code. The ${CADDY_NET:-caddy_net}
value (colon inside unquoted YAML scalar) was also causing
"mapping values are not allowed in this context" at parse time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 03:19:38 +00:00
Claude c34dd29cd1 fix(wolf): regex bug was skipping all mounted drives in picker
^(/|/boot|...) — the bare / alternate matches every absolute path,
so every non-home mount was silently skipped. Replace with explicit
glob checks so only root, system paths, and [SWAP] are excluded.
Fixes /home/user/drives/1tb-space (and any other secondary mount)
not appearing in the numbered list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 03:07:20 +00:00
Claude 96e9705c88 fix(wolf): show UUIDs in drive picker; fix false-unmounted for whole disks
- Display UUID under each mounted and unmounted entry so users can
  cross-reference with fstab / blkid output
- Fix detection bug: a whole disk (e.g. sdb) with a mounted partition
  (sdb1) was incorrectly listed as unmounted; now checks lsblk children
  before including a disk in the unmounted list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 03:02:50 +00:00
Claude 051fed8dd2 feat(wolf): numbered drive picker for game storage location
Replace the free-text path prompt with an interactive menu:
- Lists mounted non-system drives as numbered choices (1, 2, ...)
- Each shows mount point, drive label/name, total size, and free space
- Default path is <selected-mountpoint>/games
- Unmounted drives shown as U1, U2, ... (script formats + mounts them)
- Option c for a fully custom path
- Final confirm/edit step lets user tweak the subdir before committing
- Unattended mode defaults to ~/games

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 02:52:11 +00:00
Claude 7974bf11ef fix(wolf): persist game storage path and update mounts on re-run
- Write GAME_STORAGE_DIR to ~/docker/wolf/.env so the chosen path is
  visible and editable after setup
- Fix inline Python injection to UPDATE existing Steam/ES-DE mounts in
  config.toml instead of silently skipping when entries already exist
  (previously re-running setup with a new path had no effect)
- Add update-storage subcommand to manage.sh so the path can be changed
  post-install without a full re-run: ./manage.sh update-storage /new/path
- Same fix applied to add-apps in manage.sh
- chown game storage dir to ACTUAL_USER after creating subdirectories

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-20 02:46:43 +00:00
Claude 2edc719a7a Add optional Groq Cloud API support to ai-gpu's Open WebUI
Wires Groq (api.groq.com) into Open WebUI as an OpenAI-compatible
connection so its hosted models show up alongside local Ollama models.
Prompts for an API key during install, stores it in llm/.env, and
patches the cloned docker-compose.yml's open-webui environment block
(idempotently) to reference it.
2026-06-19 02:13:24 +00:00
Claude 5b340552c3 Replace CADDY_REMOTE_HOST with explicit CADDY_MODE in site config
The old CADDY_REMOTE_HOST variable was confusingly named — it sounded like
the Caddy server's address but actually stored this machine's IP (so Caddy
knew how to reach services here). Services don't need to know where Caddy
is; they only need to know whether to write a Caddyfile or create a snippet.

Changes in lib/common.sh:
- Add CADDY_MODE=local|remote|none as the authoritative setting
- load_site_config: parse CADDY_MODE; if old CADDY_REMOTE_HOST present and
  CADDY_MODE unset, infer CADDY_MODE=remote (backward compat)
- save_site_config: write CADDY_MODE, drop CADDY_REMOTE_HOST output
- configure_caddy_for_service: use CADDY_MODE for mode detection; for remote
  snippets auto-detect this machine's primary IP via hostname -I instead of
  requiring a stored value (still falls back to CADDY_REMOTE_HOST if present
  in an old .config)

Changes in setup.sh (run_site_configure wizard):
- Replace free-text "Caddy remote host" prompt with a 3-choice menu:
  [1] This machine  [2] Remote machine  [3] None/skip
- Existing installs with CADDY_REMOTE_HOST pre-select option 2 automatically

https://claude.ai/code/session_01S7UecmQRG6CKTYPoBqbVLj
2026-06-10 00:49:41 +00:00
Claude ec9aa605cf Fix named volumes in koha/asterisk for backup coverage; add Koha setup wizard
koha.sh:
- Replace named volume `koha_db_data` with bind-mount `./data:/var/lib/mysql`
  so the MariaDB database is inside ~/docker/koha/ and covered by backup.sh
- Add interactive setup wizard: collects library name, code, admin credentials,
  item types (with custom additions), and shelf locations before first start
- Generate ~/docker/koha/post-setup.sh at install time; after completing the
  web installer the user runs it to auto-configure the library branch, item
  types, shelf locations, and system preferences via the Koha REST API
- Updated README with exact step-by-step web installer instructions and
  admin password prominently displayed

asterisk.sh:
- Replace all 5 named volumes (asterisk-config, easy-asterisk-config,
  asterisk-logs, asterisk-spool, asterisk-lib) with bind-mounts inside
  ~/docker/asterisk/ so all config and state is covered by backup.sh
- mkdir -p for all bind-mount dirs before compose up
- Replace SSH-based standalone configure_caddy_for_service stub with the
  snippet approach used everywhere else (local Caddy writes Caddyfile;
  remote Caddy via VPN/Netbird saves ~/docker/caddy-snippets/<name>.caddy)

https://claude.ai/code/session_01S7UecmQRG6CKTYPoBqbVLj
2026-06-09 18:39:27 +00:00
Claude f9013287d9 iopaint, ai-gpu: interactive model selection, auto-pull, fixes
iopaint:
- Add model selection menu (10 choices) with CPU/GPU/SD tiers and
  size/use-case descriptions shown at install time
- Fix volume mount: ./models:/root/.cache (was only /root/.cache/iopaint)
  — now persists both torch hub cache (LaMa) and HuggingFace cache (SD/PowerPaint)
- Refactor compose to use ${MODEL} and ${DEVICE} env vars so switching
  models only requires editing .env + restart, no compose file edit needed
- Add PowerPaint-V2-filling and SD 1.5 inpainting as explicit menu choices
  for text-guided object replacement
- Update header and README to document all three use cases (erase, fill, replace)
  and note that IOPaint is local-only (cannot use a remote GPU)

ai-gpu:
- Add Ollama model selection menu (8 models, multi-select with sizes/descriptions)
  defaulting to llama3.2:3b + nomic-embed-text
- Auto-pull selected Ollama models immediately after LLM stack starts
- Add InvokeAI starter model selection (SD 1.5 / SDXL Turbo / SDXL Base / skip)
- Queue InvokeAI model download via REST API (POST /api/v2/models/install)
  with fallback instructions if the API is unavailable
- Add HuggingFace token prompt; stored as HUGGING_FACE_HUB_TOKEN in image-gen .env
- Wire SearXNG into Open WebUI via ENABLE_RAG_WEB_SEARCH + SEARXNG_QUERY_URL in llm .env
- Default start choice is now 2 (portal + LLM + Ollama pull) so the stack
  is ready to use immediately after install

https://claude.ai/code/session_01JEu7LgCWXKhXo18MeYFRZp
2026-06-09 03:57:01 +00:00
Claude 5c394815b4 Add iopaint and ai-gpu services
iopaint: AI image inpainting (object removal, fill, restore) via IOPaint +
LaMa model. Runs CPU by default; GPU option writes nvidia deploy block.
No built-in auth — Authelia SSO prompt included. Port 8100.

ai-gpu: GPU AI stack from outis1one/ai-6gb-gpu. Clones repo and sets up
three stacks under ~/docker/ai-gpu/: InvokeAI image gen (port 9090),
Ollama + Open WebUI + SearXNG LLM stack (ports 11434/3000), and Flask
portal (port 8080) that hot-swaps the GPU between stacks. Patches
hardcoded home paths in portal docker-compose.yml to use ACTUAL_HOME.
Prompts for TZ (replaces hardcoded America/New_York). Caddy for both
portal (localai) and InvokeAI (images).

https://claude.ai/code/session_01JEu7LgCWXKhXo18MeYFRZp
2026-06-09 03:13:51 +00:00
Claude b6f499295f Add koha: full ILS for physical book library (catalog, shelf locations, loans) 2026-06-09 02:29:54 +00:00
Claude 12795a27fd Add drum-rhythm-game: nginx-served browser rhythm game with Authelia SSO support 2026-06-09 01:58:30 +00:00
Claude d47d8dc26f unifi.sh: add remote Caddy snippet support, fix standalone CADDY_REMOTE_HOST global 2026-06-09 00:58:57 +00:00
Claude 8bdc4ca025 Improve changedetection.sh: explicit env vars in compose, chmod 600 .env, better readme 2026-06-09 00:30:43 +00:00
Claude 5ee08523e3 Improve n8n.sh: explicit env vars in compose, chmod 600 .env, better readme 2026-06-09 00:28:40 +00:00
Claude f21c96c1a7 Add 7 new services: Joplin, Stirling PDF, n8n, Changedetection, ArchiveBox, Calibre-Web, Homebox
- joplin: self-hosted sync server (PostgreSQL sidecar, APP_BASE_URL from SITE_DOMAIN)
- stirling-pdf: PDF toolkit with optional Authelia SSO (no built-in auth)
- n8n: workflow automation connecting self-hosted services (WEBHOOK_URL from SITE_DOMAIN)
- changedetection: web page change monitoring with playwright-chrome renderer
- archivebox: personal Wayback Machine, initializes data dir at install time
- calibre-web: ebook library UI with Calibre conversion support (linuxserver image)
- homebox: home inventory and asset management

All services follow the standalone bootstrap pattern and support local/remote Caddy.
README.md updated with new services in appropriate group rows.
2026-06-09 00:28:40 +00:00
Claude 7c3f101fe0 Add asterisk, nextcloud, onlyoffice, mattermost services + vendor/easy-asterisk
asterisk.sh (homelab):
- Easy Asterisk PBX with self-hosted coturn TURN server
- Vendored from outis1one/easy-asterisk v0.10.0 for offline install
- LAN-only or FQDN mode (TLS + TURN relay for remote access)
- Auto-answer SIP headers for intercom use case
- Authelia SSO for web admin; WEB_ADMIN_AUTH_DISABLED=true when chosen
- UFW rules: 5060-5061, 8080, 8088-8089, 3478, 10000-20000/udp, 49152-49252/udp
- Builds custom Docker image from vendor/easy-asterisk/

nextcloud.sh (utilities):
- Custom Dockerfile: nextcloud:apache + smbclient (SMB external storage)
- MariaDB 10.11 sidecar with matching env vars
- OVERWRITEPROTOCOL/OVERWRITECLIURL/TRUSTED_PROXIES set for Caddy
- Enables files_external app after first-run init (waits up to 90s)

onlyoffice.sh (utilities):
- JWT generated once, preserved across re-runs
- _ensure_yq: auto-installs yq v4 for FileBrowser config patching
- _wire_nextcloud: idempotent occ wiring (DocumentServerUrl, jwt_secret)
- _wire_filebrowser: patches config.yaml + restarts container
- Caddy block overrides X-Frame-Options to allow iframe embedding

mattermost.sh (utilities):
- PostgreSQL 15-alpine + Mattermost Team Edition + coturn (port 3479)
- 8443/udp for Calls plugin RTC server
- coturn uses --use-auth-secret HMAC mode (required by Calls plugin)
- SITE_URL computed from SITE_DOMAIN, promptable
- UFW: 8443/udp, 3479, 49153-49352/udp

vendor/easy-asterisk/:
- All upstream source files vendored for offline/self-contained installs
- Dockerfile, docker/entrypoint.sh, docker/coturn-entrypoint.sh
- easy-asterisk-v0.10.0.sh (6929-line management script)
- scripts/vpn-diagnostics.sh, scripts/dns-whitelist.sh
- .env.example

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-09 00:28:38 +00:00
Claude ec3f9bfd3f Add remote Caddy support — generate snippet files when Caddy is on another host
New site config key: CADDY_REMOTE_HOST (set via 'sudo ./setup.sh configure').
When set, configure_caddy_for_service operates in "remote" mode instead of
writing to a local Caddyfile:
- Upstream uses CADDY_REMOTE_HOST:PORT (host IP, not container name)
- Snippet saved to ~/docker/caddy-snippets/<subdomain>.caddy
- User is shown scp/rsync commands to copy it to the Caddy machine

Three modes in configure_caddy_for_service (lib/common.sh and inline stubs):
  local:  ~/docker/caddy/ exists → write Caddyfile + reload (existing behavior)
  remote: CADDY_REMOTE_HOST set → save snippet, print copy instructions
  none:   neither configured → silent return (unchanged)

All 31 service standalone bootstrap stubs updated with the new logic.
CADDY_REMOTE_HOST global added to all 42 standalone bootstrap sections.
setup.sh configure now prompts for CADDY_REMOTE_HOST with a clear explanation.
wolf.sh: add missing stubs (configure_caddy_for_service, write_readme,
  prompt_yn, ensure_docker_dir_ownership) and the Authelia/Caddy/start calls
  that were missing from the install function.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-09 00:28:30 +00:00
Claude 13dec9a857 Add asterisk, nextcloud, onlyoffice, mattermost services + vendor/easy-asterisk
asterisk.sh (homelab):
- Easy Asterisk PBX with self-hosted coturn TURN server
- Vendored from outis1one/easy-asterisk v0.10.0 for offline install
- LAN-only or FQDN mode (TLS + TURN relay for remote access)
- Auto-answer SIP headers for intercom use case
- Authelia SSO for web admin; WEB_ADMIN_AUTH_DISABLED=true when chosen
- UFW rules: 5060-5061, 8080, 8088-8089, 3478, 10000-20000/udp, 49152-49252/udp
- Builds custom Docker image from vendor/easy-asterisk/

nextcloud.sh (utilities):
- Custom Dockerfile: nextcloud:apache + smbclient (SMB external storage)
- MariaDB 10.11 sidecar with matching env vars
- OVERWRITEPROTOCOL/OVERWRITECLIURL/TRUSTED_PROXIES set for Caddy
- Enables files_external app after first-run init (waits up to 90s)

onlyoffice.sh (utilities):
- JWT generated once, preserved across re-runs
- _ensure_yq: auto-installs yq v4 for FileBrowser config patching
- _wire_nextcloud: idempotent occ wiring (DocumentServerUrl, jwt_secret)
- _wire_filebrowser: patches config.yaml + restarts container
- Caddy block overrides X-Frame-Options to allow iframe embedding

mattermost.sh (utilities):
- PostgreSQL 15-alpine + Mattermost Team Edition + coturn (port 3479)
- 8443/udp for Calls plugin RTC server
- coturn uses --use-auth-secret HMAC mode (required by Calls plugin)
- SITE_URL computed from SITE_DOMAIN, promptable
- UFW: 8443/udp, 3479, 49153-49352/udp

vendor/easy-asterisk/:
- All upstream source files vendored for offline/self-contained installs
- Dockerfile, docker/entrypoint.sh, docker/coturn-entrypoint.sh
- easy-asterisk-v0.10.0.sh (6929-line management script)
- scripts/vpn-diagnostics.sh, scripts/dns-whitelist.sh
- .env.example

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 23:42:44 +00:00
Claude d4e06914e7 Add remote Caddy support — generate snippet files when Caddy is on another host
New site config key: CADDY_REMOTE_HOST (set via 'sudo ./setup.sh configure').
When set, configure_caddy_for_service operates in "remote" mode instead of
writing to a local Caddyfile:
- Upstream uses CADDY_REMOTE_HOST:PORT (host IP, not container name)
- Snippet saved to ~/docker/caddy-snippets/<subdomain>.caddy
- User is shown scp/rsync commands to copy it to the Caddy machine

Three modes in configure_caddy_for_service (lib/common.sh and inline stubs):
  local:  ~/docker/caddy/ exists → write Caddyfile + reload (existing behavior)
  remote: CADDY_REMOTE_HOST set → save snippet, print copy instructions
  none:   neither configured → silent return (unchanged)

All 31 service standalone bootstrap stubs updated with the new logic.
CADDY_REMOTE_HOST global added to all 42 standalone bootstrap sections.
setup.sh configure now prompts for CADDY_REMOTE_HOST with a clear explanation.
wolf.sh: add missing stubs (configure_caddy_for_service, write_readme,
  prompt_yn, ensure_docker_dir_ownership) and the Authelia/Caddy/start calls
  that were missing from the install function.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 21:10:37 +00:00
Claude e95e82be2f Fix functional bugs found in service audit
wg-easy: PASSWORD env var removed in v14+; generate bcrypt hash at install
  time via 'docker run wg-easy wgpw' and write PASSWORD_HASH instead.

ntfy: write config/server.yml with base-url, cache-file, auth-file, and
  behind-proxy:true so push notification links work when behind Caddy.
  auth-default-access: deny-all (require topic auth).

mealie: BASE_URL was hardcoded to http://localhost:9925; email links and
  OAuth redirects broke when served via Caddy. Now computed from SITE_DOMAIN
  and written to .env so it's easy to update.

nextcloud: add OVERWRITEPROTOCOL=https, OVERWRITECLIURL, TRUSTED_PROXIES to
  .env so share links and internal redirects use https:// behind Caddy.

onlyoffice: Caddy's default X-Frame-Options: SAMEORIGIN header blocked
  OnlyOffice from being embedded as an iframe in Nextcloud. Override it in
  the Caddy site block to allow framing.

vaultwarden: remove exposed port 3012 (WebSocket — not needed since v1.29+,
  all handled on port 80). Publish port 8888 for direct host access instead.
  Remove WEBSOCKET_ENABLED=true (ignored in current versions).

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 19:13:09 +00:00
Claude 551c254b89 Add Authelia SSO prompt to js99er, magicmirror, wolf-pair
These services have no built-in auth. Per CLAUDE.md they should check for
Authelia and offer to protect them with SSO before calling
configure_caddy_for_service. Adds the standard prompt_yn + import authelia
extra block pattern to all three.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 19:02:00 +00:00
Claude 9f0ff0bb9f Add write_readme, Caddy, and start prompt to wolf/homeassistant/js99er/minecraft
- wolf.sh: add Authelia SSO check, configure_caddy_for_service, write_readme,
  and prompt to start Wolf (it had none of these)
- homeassistant.sh: add write_readme with access URL and manage commands
- js99er.sh: add write_readme with access URL and manage commands
- minecraft.sh: add write_readme with manage and backup commands

Completes the service audit — all 49 services now have full interactive setup,
standalone bootstrap, and self-documenting README in the deploy directory.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:53:17 +00:00
Claude e9f05cc127 Use stored SITE_DOMAIN as default in Caddy domain prompt
lib/common.sh: configure_caddy_for_service now pre-fills the domain prompt
with $DEFAULT_SUBDOMAIN.$SITE_DOMAIN when a site domain has been configured
(setup.sh configure / ~/docker/.config). No more typing the full domain for
every service — just press Enter to accept the default.

services/mattermost.sh: remove redundant custom Caddy/domain block added in
the previous commit. MATTERMOST_SITE_URL is already computed from SITE_DOMAIN
before configure_caddy_for_service is called, so the simple call is sufficient.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:46 +00:00
Claude ab778868df Fix Mattermost Calls, add Authelia to Asterisk web admin
Mattermost Calls:
- Add 8443/udp to compose ports for the Calls plugin RTC server (WebRTC
  direct path; coturn relay is only the fallback, not the sole path)
- Add 8443/udp to UFW rules and router port-forward table
- Warn that WebRTC requires HTTPS — calls silently fail over HTTP
- Prompt for Caddy domain and update MATTERMOST_SITE_URL in .env to match
  the HTTPS URL before Caddy is wired (previously SITEURL was written before
  the domain was known, leaving it as http://localhost:8065)
- Update README with RTC server address field and corrected port table

Asterisk web admin:
- No built-in auth: add Authelia SSO check matching CLAUDE.md pattern
- Set WEB_ADMIN_AUTH_DISABLED=true in .env when Authelia handles auth
  (prevents double-login prompts)

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:46 +00:00
Claude dc1552f5d3 Fix asterisk.sh: symlink→cp, management script mount, TURN_SERVER, ports
- Replace symlink with real cp for easy-asterisk-v0.10.0.sh: Docker COPY
  doesn't reliably follow symlinks; using a real copy is safer.
- Add ./easy-asterisk.sh:/usr/local/bin/easy-asterisk:ro bind mount so the
  management script can be updated without rebuilding the image.
- Add TURN_SERVER to .env (empty in LAN-only mode, domain:3478 in FQDN mode)
  and reference it in compose instead of building the value inline — fixes
  malformed "":3478 in LAN-only mode.
- Add provisioning ports 8088/8089 to UFW rules; these are Asterisk's built-in
  HTTP server for Linphone XML provisioning (not the web admin, not Caddy).
- Document in README that Caddy has no role in calls: SIP/RTP use host
  networking. Caddy only proxies the web admin (8080). Provisioning ports
  (8088/8089) must be accessed directly, not through Caddy.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:46 +00:00
Claude 0d81839c80 Vendor easy-asterisk source files; fix asterisk.sh and onlyoffice.sh
vendor/easy-asterisk/: All source files from outis1one/easy-asterisk v0.10.0
vendored so the repo is self-contained — no internet required at install time.
Includes the real Dockerfile (FROM ubuntu:24.04 + full Asterisk stack),
entrypoint.sh (IP detection, TLS cert gen, pjsip/rtp config, web admin),
coturn-entrypoint.sh (robust IP detection wrapper), and the management
script + diagnostic utilities.

services/asterisk.sh: Rewritten to copy from vendor/ instead of downloading
at runtime. Uses the upstream Dockerfile verbatim. Symlinks
easy-asterisk-v0.10.0.sh → easy-asterisk.sh for build context compatibility.

services/onlyoffice.sh: Complete rewrite with correct standalone bootstrap.
_ensure_yq() installs yq v4 automatically (arch-aware). JWT secret is
preserved across re-runs so rotating is explicit. _wire_nextcloud() and
_wire_filebrowser() run on every install invocation (idempotent), skipping
gracefully when containers aren't running rather than failing.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:46 +00:00
Claude d948e86341 Add Nextcloud, OnlyOffice, and Mattermost services
Nextcloud: custom Dockerfile (nextcloud:apache + smbclient) for SMB external
storage support without AIO. All data uses bind mounts so Kopia/Borg coverage
is automatic. Enables files_external app after first boot.

OnlyOffice: JWT-secured document server wired to Nextcloud via occ commands
and FileBrowser Quantum config.yaml if both are installed. Port 8082.

Mattermost: Team Edition + PostgreSQL + dedicated coturn on port 3479 (does
not conflict with Easy Asterisk's coturn on 3478). Bind mounts throughout.
UFW rules and router port-forward instructions printed at install time.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:46 +00:00
Claude 9f667705ae Add Easy Asterisk PBX service with self-hosted coturn TURN server
Integrates https://github.com/outis1one/easy-asterisk into the post-install
system. Downloads the management script and coturn entrypoint at install time,
generates docker-compose.yml with host-networking Asterisk + coturn, writes
a randomised TURN password, and opens UFW ports for SIP/RTP/TURN.

Interactive FQDN setup chooses between LAN-only (UDP, no TLS) and FQDN mode
(TLS+SRTP+TURN) and prints required router port-forward instructions.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 18:41:17 +00:00
Claude 95ac16efbd services: add btop to base essential packages
btop is a modern resource monitor (CPU, memory, disk, network) with
a clean interactive UI. Useful on both servers and desktops.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 17:04:50 +00:00
Claude 67d6ae1f1b services: add KDE Connect phone/desktop integration
Apt-based service for Android/iPhone ↔ Linux integration: shared
clipboard, notifications, file transfer, remote input. Works on Ubuntu
(GNOME) and Linux Mint Cinnamon. Opens UFW ports 1714-1764 automatically.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 17:01:36 +00:00
Claude 21bd9df614 services: add Syncthing continuous file sync service
Docker-based Syncthing with PUID/PGID ownership, caddy_net integration,
and standalone bootstrap support. Exposes web UI on 8384 and sync
protocol on 22000 (tcp+udp) and discovery on 21027/udp.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 17:01:36 +00:00