feat(packaging): run figcraft-cli from the AppImage with `cli <args>` (#232)

The AppImage ships figcraft-cli in usr/bin, but AppRun only ever launched the
app, so the CLI (and its MCP server) could not be reached without extracting
the image. `FigCraft.AppImage cli mcp` now execs `figcraft-cli mcp`, skipping
desktop integration because the CLI is headless.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Muhammadyusuf 2026-10-14 07:30:42 +05:00 committed by GitHub
parent 6d735653a2
commit dd3d4d326c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 36 additions and 2 deletions

View File

@ -40,6 +40,9 @@ built-in fonts. Attached, the app's own fonts apply. The browser build has no sy
Build the CLI first (`cargo build --release -p figcraft-cli`) and use the absolute path to
`target/release/figcraft-cli`.
The Linux AppImage bundles the CLI: `FigCraft.AppImage cli <args>` runs `figcraft-cli <args>`, so
`/path/to/FigCraft.AppImage cli mcp` works wherever `/path/to/figcraft-cli mcp` appears below.
### Claude Code
```sh

View File

@ -148,7 +148,8 @@ shared-mime-info file for `.figcraft`) and builds every format from it: `.tar.gz
`.rpm` with [nfpm](https://nfpm.goreleaser.com/) (`nfpm.yaml` lists the dlopen'd runtime
libraries as dependencies); and an `.AppImage` with update information and a `.zsync`, whose
`AppRun` registers the desktop entry and icons on launch so Wayland docks show the right icon
(`FIGCRAFT_NO_DESKTOP_INTEGRATION=1` opts out; covered by `apprun-test.sh`).
(`FIGCRAFT_NO_DESKTOP_INTEGRATION=1` opts out; covered by `apprun-test.sh`) and runs the bundled
`figcraft-cli` for `FigCraft.AppImage cli <args>`.
`flatpak-bundle.sh` repackages the tarball into a `.flatpak` with
`flatpak/ai.storyteller.figcraft.bundle.yml` (freedesktop 26.08). `flatpak/ai.storyteller.figcraft.yml`
is the from-source manifest for a Flathub submission (not built in CI; vendor crates with

View File

@ -8,6 +8,9 @@
# (and whenever the AppImage's path changes) install the .desktop entry and the
# hicolor icons into $XDG_DATA_HOME, then launch. Every failure here must leave
# the launch untouched. Opt out with FIGCRAFT_NO_DESKTOP_INTEGRATION=1.
#
# `FigCraft.AppImage cli <args>` runs the bundled headless figcraft-cli with <args>
# (e.g. `cli mcp`) instead of the app, without touching the desktop.
set -u
@ -68,5 +71,17 @@ integrate() {
done
}
# The CLI is headless and its stdout may be a protocol stream (`cli mcp`): no
# desktop integration, straight to the binary.
if [ "${1:-}" = cli ]; then
shift
cli="$APPDIR/usr/bin/figcraft-cli"
if [ ! -x "$cli" ]; then
echo "figcraft: this AppImage was built without figcraft-cli" >&2
exit 127
fi
exec "$cli" "$@"
fi
integrate
exec "$APPDIR/usr/bin/figcraft" "$@"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Smoke test for packaging/linux/AppRun: the AppImage's desktop integration writes
# and refreshes the host .desktop entry and icons, is idempotent, honours the opt-out
# and an unwritable HOME, and always launches the app.
# and an unwritable HOME, and always launches the app; `cli` runs figcraft-cli instead.
#
# Runs in seconds with no build (CI: .github/workflows/packaging-lint.yml).
set -euo pipefail
@ -95,4 +95,19 @@ out="$(APPIMAGE="$odd" "$APPDIR/AppRun" x)" || fail "launch with an odd path exi
[ "$out" = "stub: x" ] || fail "odd path: $out"
[ ! -e "$XDG_DATA_HOME" ] || fail "integrated an AppImage path that needs escaping"
# 10. `cli <args>` runs figcraft-cli with the remaining arguments and integrates nothing.
rm -rf "$XDG_DATA_HOME"
out="$("$APPDIR/AppRun" cli mcp --attach 7979 2>&1)" && fail "cli ran without figcraft-cli in the AppDir"
[ "$out" = "figcraft: this AppImage was built without figcraft-cli" ] || fail "missing cli: $out"
printf '#!/bin/sh\necho "cli stub: $*"\n' >"$APPDIR/usr/bin/figcraft-cli"
chmod +x "$APPDIR/usr/bin/figcraft-cli"
out="$("$APPDIR/AppRun" cli mcp --attach 7979)" || fail "cli launch exited non-zero"
[ "$out" = "cli stub: mcp --attach 7979" ] || fail "cli arguments not forwarded: $out"
out="$("$APPDIR/AppRun" cli)" || fail "bare cli launch exited non-zero"
[ "$out" = "cli stub: " ] || fail "bare cli output: $out"
[ ! -e "$XDG_DATA_HOME" ] || fail "cli launch integrated the desktop"
# Only the first argument selects the CLI.
out="$("$APPDIR/AppRun" file.figcraft cli)" || fail "app launch with a later cli argument exited non-zero"
[ "$out" = "stub: file.figcraft cli" ] || fail "later cli argument hijacked the launch: $out"
echo "AppRun desktop integration ok"