The web deploy serves a config.json kept on the server (not in git), which
is where the Giphy key lives. The desktop app bundles the repo's
config.json, whose gifApiKey is empty, so on desktop the GIF button never
appeared even with Settings → GIF Picker switched on.
scripts/sync-web-config.mjs copies an allow-list of deployment-only keys
(just gifApiKey) from https://chat.lotusguild.org/config.json into
cinny/config.json before the Windows and Linux builds. The key is public
already (served to every web visitor; Giphy keys are client keys). A fetch
failure is a warning, not a build failure.
Tested locally: sets the key, is a no-op on a second run, and skips cleanly
on a 404.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
actions/checkout@v4 is a JS action requiring a Node runtime to execute;
archlinux:base-devel doesn't ship one, so the job failed immediately
with "node: executable file not found". The job only needs one file
(packaging/pacman/PKGBUILD), so fetch it via curl from Gitea's raw
endpoint instead of checking out the whole repo. Also drop pacman -Syu
to -Sy (sync-only) — a full system upgrade isn't needed in a
throwaway container and risks partial-upgrade/keyring failures.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WebKitGTK ships enable-media-stream/enable-webrtc off by default
(unlike WebView2/WKWebView), leaving navigator.mediaDevices undefined
and Element Call reporting "browser does not support WebRTC" on every
Linux build. Enable both settings and auto-grant the resulting
camera/mic permission request, mirroring the existing WebView2 handling.
Also add a build-arch CI job that repackages the existing .deb into a
real .pkg.tar.zst and uploads it to the Gitea release alongside the
Windows/Linux artifacts, for Arch/CachyOS users who'd rather use pacman
than an AppImage.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Continuous "latest" builds track lotus HEAD, so only the newest submodule bump
needs to build. Cancel a superseded in-flight release: rapid lotus pushes would
otherwise queue several ~30-min Tauri builds back-to-back, and build-linux runs
on ubuntu-latest — the same runner pool as cinny web CI — so the queue also
starves web CI/deploys. update-manifest only publishes release.json on full
success, so a cancelled run leaves the last good manifest untouched.
Reviewed by 2 agents (SHIP).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
From the deep-audit wave (reviewer-verified: capability identifiers valid, no
removed-crate references, GDI free ordering correct):
- Removed 8 never-registered plugins (clipboard-manager, fs, shell, http,
process, os, dialog, global-shortcut) from Cargo.toml AND their capability
grants (shell:allow-execute, unscoped fs writes, http:default, …) — verified
the web never invokes any of them. A latent RCE-class surface is gone.
- on_new_window: only http/https/mailto reach the OS opener (file:///custom
schemes previously bypassed the opener capability scope entirely).
- set_badge_count: freed hdc + hdc_screen on all three GDI error paths
(leaked per badge update in a long-running tray app).
- 8s reveal failsafe gated by an AtomicBool: no longer re-shows a window the
user closed to tray; page-load reveal now fires once only (logout reloads
don't re-surface a tray-hidden window); recovery for a missed page-load
event preserved.
- toast.rs: store pruned on Activated too + capped at 20 (was unbounded).
- Startup no longer panics when the bundled icon is missing (tray skipped
gracefully); msSmartScreenProtection no longer disabled (throttling
disables kept); rust-version corrected to 1.77.2.
- release.yml update-manifest: fails on empty signatures (was: could publish
a manifest that traps Windows users in a failed-update loop); partial-
failure window documented. Deleted the stale upstream tauri.yml workflow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rustup shim at .cargo\bin\cargo.exe was failing with
"No application is associated with the specified file for
this operation" — a Windows error indicating the shim proxy
could not resolve the toolchain. Fix by also adding the
actual stable toolchain bin dir to PATH, bypassing the shim.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GITHUB_PATH written by a prior step is not reliably picked up by act
(the local runner). Set PATH directly in the Build step's PowerShell
session so cargo.exe is visible to tauri build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Em dash in Write-Error string broke PowerShell string termination.
Also try C:\Users\%USERNAME%\.cargo\bin as fallback since act may
override USERPROFILE to a temp directory.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cargo.exe lives in %USERPROFILE%\.cargo\bin but act does not
automatically export it into the CI subprocess PATH. Added an explicit
step to append that directory to GITHUB_PATH, matching what the Linux
job already does for $HOME/.cargo/bin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three changes to the build-windows job:
1. CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse — uses lightweight HTTPS
per-crate fetching instead of a full git clone of the crates.io index.
The git clone path triggers an SSL connection reset ([curl 35]) on
Windows Schannel in this runner environment.
2. CARGO_HTTP_MULTIPLEXING=false — disables HTTP/2 ALPN negotiation which
is another common source of Schannel SSL resets on Windows.
3. CARGO_NET_RETRY=5 — retry transient network errors up to 5 times before
failing the build.
4. Add Swatinem/rust-cache for Windows (mirrors the Linux job) — after a
successful build, compiled crates are cached so subsequent runs skip the
crates.io download entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The squashfs magic was not found at any 512-byte boundary because
Tauri's linuxdeploy build uses a non-standard layout. Using the
AppImage's own --appimage-extract flag extracts squashfs internally
without FUSE or needing to locate the offset manually.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The step exits in 1s with no output — need to see which command fails
and whether github.com is reachable from the runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 4096-byte-aligned scan raised StopIteration when linuxdeploy's squashfs
starts at a non-page-aligned boundary. Scan every 512 bytes instead and
exit cleanly with error code 1 if nothing is found.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Linux runner cannot reach static.rust-lang.org, so dtolnay/rust-toolchain
times out every build. The runner host has Rust installed and bind-mounts
~/.cargo into the container — use that directly and skip the download.
Also bump cinny submodule to 2178295e.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Column-0 lines inside run: | blocks (Python -c script and C heredoc)
caused Gitea's YAML parser to terminate the literal block early, resulting
in a 500 error on every workflow_dispatch call. Fix by collapsing the
Python to a single line and moving the C source into tools/ld_wrapper.c
so CI can compile it directly without any heredoc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows (windows-rs 0.61):
- FONT_PITCH_AND_FAMILY does not exist; ipitchandfamily is u32 - revert
to (DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32
- CreateBitmap returns HBITMAP directly (not Result<HBITMAP>); replace
.map_err()? with explicit null pointer check on hbm_mask.0
Linux AppImage:
- Shell script wrapper is destroyed by Tauri's `dd if=/dev/zero bs=1
count=3 seek=8` which zeroes the shebang at bytes 8-10
- Compile a tiny C ELF forwarder instead: ELF bytes 8-10 are
EI_OSABI/EI_ABIVERSION padding (already zero), dd is a no-op
- Use page-aligned squashfs offset search for more reliable extraction
- Add set -e to Stage step and explicit gcc install
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Docker CI containers lack FUSE kernel module, and the env var approach
was unreliable when Tauri spawns linuxdeploy as a subprocess.
Instead: download linuxdeploy-x86_64.AppImage, extract its squashfs
content using squashfs-tools (no FUSE needed), then place a shell
wrapper at ~/.cache/tauri/linuxdeploy-x86_64.AppImage so Tauri uses
the extracted binary directly without AppImage runtime.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move BOOL import to windows::core (removed from Win32::Foundation in 0.61)
- Move CreateBitmap import from WindowsAndMessaging to Win32::Graphics::Gdi
- Wrap nullable handles in Some() for GetDC, CreateCompatibleDC,
CreateDIBSection, ReleaseDC (new Option<T> API in 0.61)
- Add .into() for all SelectObject/DeleteObject GDI handle args (now HGDIOBJ)
- Use FONT_PITCH_AND_FAMILY type directly in CreateFontW instead of u32 cast
- Make DrawTextW slice mutable (&mut [u16] required in 0.61)
- Use hicon.unwrap_or_default() for SetOverlayIcon (takes HICON not Option<HICON>)
- Add libfuse2 to apt-get for Linux AppImage bundler (FUSE mount fallback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows: ConvertTo-Json outputs True/False (invalid JSON) and UTF-16
BOM, corrupting tauri.conf.json. Switch to `node -e` which round-trips
JSON correctly.
Linux: linuxdeploy is itself an AppImage and cannot execute inside
Docker without FUSE. APPIMAGE_EXTRACT_AND_RUN=1 makes it self-extract
and run as a plain binary instead.
Also fix unreachable_code warning in check_for_update.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add prepare job: computes version (4.12.{run_number}), creates/updates
the Gitea release once — eliminates the race condition where build-windows
and build-linux both tried to create the same release simultaneously.
- Auto-increment version: both build jobs patch tauri.conf.json with
4.12.{run_number} before building, so every CI run produces a strictly
increasing semver and the Tauri updater fires correctly.
- Fix double -- in Windows build command: was 'build -- --bundles nsis'
which passed --bundles as cargo args (silently ignored), causing all
bundle targets to build. Now 'build --bundles nsis' (single --).
- Add setup-node to Windows build: pins Node.js to .node-version like
the Linux job already does.
- update-manifest: uses version/release_id from prepare outputs instead
of re-fetching and parsing the release name.
- Fix window title: was "Cinny", now "Lotus Chat".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix COREWEBVIEW2_PERMISSION_KIND out-param pattern in PermissionRequestedEventHandler
- Add "wry" feature to tauri dep so with_webview compiles on Windows
- Build both appimage and deb on Linux for auto-update compatibility
- Commit AppRun-x86_64 binary to avoid GitHub download timeout in CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Multi-line python3 -c "..." with zero-indented Python code caused Gitea
to fail parsing the workflow YAML (line 188: could not find expected ':').
Replace with jq which handles variable interpolation in a single line.
This was silently breaking every push-triggered workflow run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two build failures after rename to "Lotus Chat":
- Windows upload was globbing for Cinny_*_x64-setup.exe; Tauri now
outputs "Lotus Chat_4.12.2_x64-setup.exe" to match productName
- Linux upload was globbing for Cinny_*_amd64.deb; same issue
Also switch version source from filename parsing to tauri.conf.json
directly — more robust, no regex.
Linux: drop AppImage bundle (--bundles deb only). AppImage requires
downloading AppRun from github.com/tauri-apps/binary-releases during
the build step; the CI runner times out on that download. The deb
builds cleanly. Re-enable AppImage once GitHub connectivity is fixed.
Update manifest now covers Windows only (Linux AppImage not available).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>