rename: the desktop is Inkwell — crates, Tauri identity, data move, packaging

Step 3 of milestone 481 (Scribe note 5071: a full rename).

- crates thoughtsync-{core,desktop,ffi,uniffi-bindgen} → inkwell-*, the
  Cargo.lock entries moved to match (checked with `cargo metadata --locked`)
- Tauri: productName "Inkwell", identifier com.fabledsword.inkwell, binary
  `inkwell`, updater feed on bvandeusen/inkwell, store file inkwell.db
- client agent inkwell-desktop, headers X-Inkwell-Client/-Protocol (the server
  reads neither), capture event inkwell://captured, display-version env
- .deb: conflicts + replaces thought-sync, so the updater's install retires the
  old package instead of colliding on it. kebab-case("Inkwell") is `inkwell`, so
  the package name finally matches the command and verify.sh now asserts it
- pacman: inkwell, conflicting with and replacing thoughtsync and
  thoughtsync-desktop
- AppImage ~/Applications/Inkwell.AppImage, menu entry inkwell.desktop,
  installer, release titles, desktop asset names in fetch-clients.sh

The one shim, chosen by the operator because it is the only copy of a
local-first user's notes: crossover.rs moves the old
com.fabledsword.thoughtsync app-data dir's contents into the new one on startup,
before the store opens, renaming thoughtsync.db and its -wal/-shm with it. It
skips when the new dir already has a store, and anything already in the new dir
wins (the installer writes its channel marker there first). Tested.

Android's Kotlin side (package, applicationId, uniffi class) is step 4. Its
release asset names stay thoughtsync.* until then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 14:27:26 -04:00
co-authored by Claude Opus 5.5
parent a706644455
commit fe6f0746b2
37 changed files with 453 additions and 247 deletions
+27 -27
View File
@@ -1,8 +1,8 @@
#!/bin/sh
#
# ThoughtSync desktop — one-command Linux installer.
# Inkwell desktop — one-command Linux installer.
#
# curl -fsSL https://git.fabledsword.com/bvandeusen/thoughtsync/raw/branch/dev/desktop/packaging/install.sh | sh
# curl -fsSL https://git.fabledsword.com/bvandeusen/inkwell/raw/branch/dev/desktop/packaging/install.sh | sh
#
# Two channels, the SAME two the app's own updater offers (src-tauri/src/update.rs):
# stable (default) — the rolling build from every merge to `main`.
@@ -35,7 +35,7 @@
set -eu
INSTANCE="https://git.fabledsword.com"
REPO="bvandeusen/thoughtsync"
REPO="bvandeusen/inkwell"
API="$INSTANCE/api/v1/repos/$REPO"
say() { printf '==> %s\n' "$1"; }
@@ -44,7 +44,7 @@ have() { command -v "$1" >/dev/null 2>&1; }
usage() {
cat <<'USAGE'
ThoughtSync desktop installer.
Inkwell desktop installer.
install.sh [--channel stable|dev]
@@ -83,11 +83,11 @@ have curl || die "curl is required."
arch="$(uname -m)"
case "$arch" in
x86_64 | amd64) : ;;
*) die "ThoughtSync ships x86_64 Linux builds only right now (this machine: $arch)." ;;
*) die "Inkwell ships x86_64 Linux builds only right now (this machine: $arch)." ;;
esac
# --- resolve the release for this channel -----------------------------------
say "Finding the latest ThoughtSync build on the $channel channel…"
say "Finding the latest Inkwell build on the $channel channel…"
# ONE lookup, both channels. Each is a release whose tag never moves and whose assets
# are pruned to the current build, so the tag alone names the newest build on that
@@ -131,10 +131,10 @@ trap 'rm -rf "$tmp"' EXIT INT TERM
# The app reads it at startup (src-tauri/src/update.rs, INSTALL_MARKER) and only acts
# when the value CHANGED, so switching channel in the app isn't undone on next launch.
#
# The directory is Tauri's app-data dir for identifier com.fabledsword.thoughtsync;
# The directory is Tauri's app-data dir for identifier com.fabledsword.inkwell;
# both sides hardcode it, so a change to the identifier has to change both.
record_channel() {
marker_dir="${XDG_DATA_HOME:-$HOME/.local/share}/com.fabledsword.thoughtsync"
marker_dir="${XDG_DATA_HOME:-$HOME/.local/share}/com.fabledsword.inkwell"
# Best-effort: a failure here costs the channel setting, not the install, and a
# native install run as root would only be writing into root's home anyway.
mkdir -p "$marker_dir" 2>/dev/null && printf '%s\n' "$channel" > "$marker_dir/install-channel" 2>/dev/null || true
@@ -176,7 +176,7 @@ if have pacman && [ -n "$pkg_url" ]; then
need_root
$sudo pacman -U --noconfirm "$pkg_file"
record_channel
say "Done. Launch ThoughtSync from your application menu, or run thoughtsync."
say "Done. Launch Inkwell from your application menu, or run inkwell."
native_update_note
exit 0
fi
@@ -184,33 +184,33 @@ fi
# --- native .deb path (Debian/Ubuntu) ---------------------------------------
if have dpkg && have apt-get && [ -n "$deb_url" ]; then
say "Debian-family system detected — installing the native .deb"
curl -fSL -o "$tmp/thoughtsync.deb" "$deb_url"
curl -fSL -o "$tmp/inkwell.deb" "$deb_url"
need_root
# apt-get resolves the .deb's dependencies (webkit2gtk etc.). dpkg is the
# fallback if this apt is too old for local-file installs — it leaves the deps
# unconfigured, so `apt-get -f install` is what actually completes that path.
$sudo apt-get install -y "$tmp/thoughtsync.deb" ||
{ $sudo dpkg -i "$tmp/thoughtsync.deb" || true; $sudo apt-get -f install -y; }
$sudo apt-get install -y "$tmp/inkwell.deb" ||
{ $sudo dpkg -i "$tmp/inkwell.deb" || true; $sudo apt-get -f install -y; }
record_channel
say "Done. Launch ThoughtSync from your application menu."
say "Done. Launch Inkwell from your application menu."
native_update_note
exit 0
fi
# --- universal AppImage path (user-local, no sudo) --------------------------
# Install into ~/Applications/ThoughtSync.AppImage — the SAME location the app's
# Install into ~/Applications/Inkwell.AppImage — the SAME location the app's
# own self-integration uses (src/integration.rs) — so the running app sees
# itself already installed and never makes a second copy or menu entry.
say "Installing the de-bundled AppImage (user-local, no sudo)"
[ -n "$appimage_url" ] || die "the $channel release (${version:-unknown}) has no AppImage asset."
apps_dir="$HOME/Applications"
dest="$apps_dir/ThoughtSync.AppImage"
dest="$apps_dir/Inkwell.AppImage"
mkdir -p "$apps_dir"
say "Downloading $(basename "$appimage_url")…"
curl -fSL -o "$tmp/ThoughtSync.AppImage" "$appimage_url"
chmod +x "$tmp/ThoughtSync.AppImage"
mv -f "$tmp/ThoughtSync.AppImage" "$dest"
curl -fSL -o "$tmp/Inkwell.AppImage" "$appimage_url"
chmod +x "$tmp/Inkwell.AppImage"
mv -f "$tmp/Inkwell.AppImage" "$dest"
# Menu entry — written to match integration.rs verbatim (same paths + fields),
# so the app reports is_integrated=true and won't duplicate it.
@@ -222,39 +222,39 @@ mkdir -p "$apps_menu" "$icons_dir"
# entry looks right immediately. Extraction is a non-GUI unsquash (no FUSE, no
# black-window risk); if it fails we fall back to the themed name and the app
# writes its embedded icon on first launch anyway.
icon_ref="thoughtsync"
icon_ref="inkwell"
if ( cd "$tmp" && "$dest" --appimage-extract .DirIcon >/dev/null 2>&1 ) \
&& cp -L "$tmp/squashfs-root/.DirIcon" "$icons_dir/thoughtsync.png" 2>/dev/null; then
icon_ref="$icons_dir/thoughtsync.png"
&& cp -L "$tmp/squashfs-root/.DirIcon" "$icons_dir/inkwell.png" 2>/dev/null; then
icon_ref="$icons_dir/inkwell.png"
fi
rm -rf "$tmp/squashfs-root" 2>/dev/null || true
# StartupWMClass is the BINARY name, not the product name and not the AppImage
# filename: the AppImage's AppRun execs usr/bin/thoughtsync, and GTK derives
# filename: the AppImage's AppRun execs usr/bin/inkwell, and GTK derives
# WM_CLASS from whatever it ends up running. Anything else here means the window
# never associates with this entry and the taskbar shows a second, generic icon.
cat > "$apps_menu/thoughtsync.desktop" <<EOF
cat > "$apps_menu/inkwell.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=ThoughtSync
Name=Inkwell
Comment=Capture a fleeting thought in a second
Exec=$dest %U
Icon=$icon_ref
Terminal=false
Categories=Utility;Office;
StartupWMClass=thoughtsync
StartupWMClass=inkwell
EOF
have update-desktop-database && update-desktop-database "$apps_menu" >/dev/null 2>&1 || true
# Convenience CLI launcher.
mkdir -p "$HOME/.local/bin"
ln -sf "$dest" "$HOME/.local/bin/thoughtsync"
ln -sf "$dest" "$HOME/.local/bin/inkwell"
record_channel
say "Installed to $dest"
printf ' Launch it from your application menu, or run \033[1mthoughtsync\033[0m'
printf ' Launch it from your application menu, or run \033[1minkwell\033[0m'
printf ' (if ~/.local/bin is on your PATH).\n'
# This is the one path where the app can update itself, so say what it will follow.
if [ "$channel" = "dev" ]; then