From f806e35d41559f83a11633a82d6d3cfd8ef34956 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 6 Oct 2026 13:15:52 -0400 Subject: [PATCH] =?UTF-8?q?rename:=20the=20apps=20say=20Inkwell=20?= =?UTF-8?q?=E2=80=94=20web,=20desktop,=20Android=20and=20server=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ThoughtSync is renamed Inkwell ("Fabled Inkwell" in full; Scribe note 5071). This is step 1 of milestone 481: every string a person reads in the running apps. Identities installed clients depend on are deliberately untouched — the Tauri productName (it derives the .deb Package: field), identifier and binary name, applicationId, X-ThoughtSync-* headers, the export's app marker, env vars, module and crate names. - web: title, PWA manifest (name "Fabled Inkwell", short_name "Inkwell"), offline page, icon labels, build labels, prompts, notification title - server: site_name default, import error, link-preview User-Agent - 0030: a stored site_name of exactly the old default follows the rename. The Settings page saves every key, so most servers hold "ThoughtSync" without an admin ever having chosen it; a name they typed is left alone - desktop: window title, default device name, local-mode site name, log line - android: app_name and the strings that name the app - core: probe and compatibility messages Co-Authored-By: Claude Opus 5.5 --- alembic/versions/0030_site_name_inkwell.py | 51 +++++++++++++++++++ android/app/src/main/AndroidManifest.xml | 4 +- .../thoughtsync/ui/SyncViewModel.kt | 2 +- android/app/src/main/res/values/strings.xml | 10 ++-- core/src/sync/client.rs | 10 ++-- core/src/sync/compat.rs | 8 +-- desktop/src-tauri/src/commands/local.rs | 2 +- desktop/src-tauri/src/commands/sync.rs | 2 +- desktop/src-tauri/src/lib.rs | 4 +- desktop/src-tauri/tauri.conf.json | 2 +- frontend/index.html | 4 +- frontend/public/icon-maskable.svg | 2 +- frontend/public/icon.svg | 2 +- frontend/public/manifest.webmanifest | 4 +- frontend/public/offline.html | 4 +- frontend/public/sw.js | 2 +- frontend/src/components/AppShell.vue | 2 +- .../components/DesktopIntegrationPrompt.vue | 10 ++-- frontend/src/components/ImportNotes.vue | 4 +- frontend/src/stores/config.ts | 2 +- frontend/src/stores/reminders.ts | 2 +- frontend/src/views/AccountView.vue | 6 +-- frontend/src/views/BoardView.vue | 2 +- frontend/src/views/LoginView.vue | 2 +- frontend/src/views/RemindersView.vue | 2 +- frontend/src/views/SyncView.vue | 10 ++-- frontend/tailwind.config.js | 2 +- src/thoughtsync/notes/__init__.py | 4 +- src/thoughtsync/settings.py | 2 +- src/thoughtsync/unfurl.py | 2 +- 30 files changed, 108 insertions(+), 57 deletions(-) create mode 100644 alembic/versions/0030_site_name_inkwell.py diff --git a/alembic/versions/0030_site_name_inkwell.py b/alembic/versions/0030_site_name_inkwell.py new file mode 100644 index 0000000..3751740 --- /dev/null +++ b/alembic/versions/0030_site_name_inkwell.py @@ -0,0 +1,51 @@ +"""a stored site_name of the old default follows the rename to Inkwell + +Revision ID: 0030 +Revises: 0029 +Create Date: 2026-10-06 + +The product is renamed ThoughtSync → Inkwell (Scribe note 5071), and the `site_name` +registry default moves with it. On its own that only reaches servers whose settings +table has no `site_name` row — and most servers have one, because the Settings page +saves EVERY key on Save, not just the one that changed. An admin who opened Settings +to flip registration off has persisted `"ThoughtSync"` without ever choosing it. + +So the row is rewritten, but only when it holds exactly the old default. A name the +admin actually typed is theirs and is left alone; the old default is the one value we +can be sure nobody chose. + +The match is on the stored JSON text (`settings.value` is `json.dumps(value)`), so +`'"ThoughtSync"'` is the whole of what it looks for. + +## Downgrade + +Puts the old default back on a row holding exactly the new one. A server where the +admin typed "Inkwell" themselves between the two cannot be told apart from one this +migration rewrote; on downgrade both read "ThoughtSync", which is what the old code +would have shown for either. +""" +from alembic import op +import sqlalchemy as sa + +revision = "0030" +down_revision = "0029" +branch_labels = None +depends_on = None + +_OLD = '"ThoughtSync"' +_NEW = '"Inkwell"' + + +def _swap(old: str, new: str) -> None: + op.get_bind().execute( + sa.text("UPDATE settings SET value = :new WHERE key = 'site_name' AND value = :old"), + {"old": old, "new": new}, + ) + + +def upgrade() -> None: + _swap(_OLD, _NEW) + + +def downgrade() -> None: + _swap(_NEW, _OLD) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5b05bb2..5274bd6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -122,7 +122,7 @@ diff --git a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/SyncViewModel.kt b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/SyncViewModel.kt index 86cca8d..019a0d0 100644 --- a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/SyncViewModel.kt +++ b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/SyncViewModel.kt @@ -344,7 +344,7 @@ private fun SyncOutcome.changedTheStore(): Boolean = * The message to show for a failure. * * The core writes these for people to read — "notes.example.com responded, but not - * with ThoughtSync's configuration" — so they are shown as-is rather than + * with Inkwell's configuration" — so they are shown as-is rather than * replaced with a generic string that would throw away the only useful part. */ private fun Exception.describe(): String = message ?: "Something went wrong." diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 60d353c..3de5e11 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - ThoughtSync + Inkwell Search your notes @@ -164,7 +164,7 @@ Reminders Notifies you when a note\'s reminder is due. Reminders can\'t notify you - Notifications are turned off for ThoughtSync, so reminders will only show here on the board. + Notifications are turned off for Inkwell, so reminders will only show here on the board. Open settings Reminders may arrive late Without permission for exact alarms, Android delivers reminders when it next wakes the phone — usually within a few minutes, sometimes longer. @@ -181,7 +181,7 @@ Later The update didn\'t install Android needs your permission - ThoughtSync has to be allowed to install apps before it can update itself. This is a one-time setting. + Inkwell has to be allowed to install apps before it can update itself. This is a one-time setting. Allow installing App updates come from a server you connect. Until then, install new builds yourself. Your notes live on this device either way — syncing just keeps a server copy in step, so your other devices can catch up. @@ -196,14 +196,14 @@ Working offline on this device - Everything works without a server — your notes are stored on this phone. Connect a ThoughtSync server if you want them to reach your other devices. + Everything works without a server — your notes are stored on this phone. Connect an Inkwell server if you want them to reach your other devices. Server address notes.example.com Uses https unless you type http:// yourself. Check Couldn\'t reach that server Couldn\'t connect - ThoughtSync server + Inkwell server v%1$s Fully compatible. Compatible, but these features aren\'t available on this server: %1$s. diff --git a/core/src/sync/client.rs b/core/src/sync/client.rs index eef837a..5d72321 100644 --- a/core/src/sync/client.rs +++ b/core/src/sync/client.rs @@ -1,4 +1,4 @@ -//! HTTP transport to a ThoughtSync server. +//! HTTP transport to an Inkwell server. //! //! Covers the compatibility handshake (M10.6) and device-token auth (M10.7a). The //! engine that moves notes — push, pull, cursor — grows on top of the same client, @@ -151,8 +151,8 @@ fn unexpected_status(base_url: &str, status: StatusCode) -> String { /// Ask a server who it is and whether we can sync with it. /// -/// `Err` means we never got a usable answer (bad address, unreachable, not a -/// ThoughtSync server). A server that answers but is *incompatible* comes back `Ok` +/// `Err` means we never got a usable answer (bad address, unreachable, not an +/// Inkwell server). A server that answers but is *incompatible* comes back `Ok` /// with a verdict — that distinction matters, because the two need very different /// messages: one is "check what you typed", the other is "update something". pub async fn probe(raw_url: &str) -> Result { @@ -170,12 +170,12 @@ pub async fn probe(raw_url: &str) -> Result { return Err(unexpected_status(&base_url, status)); } - // Something answered 200 that isn't a ThoughtSync server (a router login page, a + // Something answered 200 that isn't an Inkwell server (a router login page, a // captive portal). Report the address, not the parse error, which would mean // nothing to the person reading it. let server: ServerInfo = response.json().await.map_err(|_| { format!( - "{base_url} responded, but not with ThoughtSync's configuration. \ + "{base_url} responded, but not with Inkwell's configuration. \ Is that the right address?" ) })?; diff --git a/core/src/sync/compat.rs b/core/src/sync/compat.rs index f1e6a1d..f10184c 100644 --- a/core/src/sync/compat.rs +++ b/core/src/sync/compat.rs @@ -146,7 +146,7 @@ pub fn evaluate(info: &ServerInfo) -> Compatibility { return incompatible( &format!( "This server requires client protocol v{floor} or newer; this app \ - speaks v{CLIENT_PROTOCOL_VERSION}. Update ThoughtSync." + speaks v{CLIENT_PROTOCOL_VERSION}. Update Inkwell." ), true, ); @@ -234,7 +234,7 @@ pub fn normalize_base_url(raw: &str) -> Option { let with_scheme = match trimmed.split_once("://") { Some((scheme, rest)) => { // Anything that isn't HTTP(S) (ftp://, file://, a stray "foo://") can't - // be a ThoughtSync server; reject rather than fail confusingly later. + // be an Inkwell server; reject rather than fail confusingly later. let scheme = scheme.to_ascii_lowercase(); if scheme != "http" && scheme != "https" { return None; @@ -259,7 +259,7 @@ mod tests { /// A server matching this client exactly, which each test then degrades. fn current_server() -> ServerInfo { ServerInfo { - site_name: Some("ThoughtSync".into()), + site_name: Some("Inkwell".into()), version: Some("0.1.0".into()), sync_protocol_version: Some(CLIENT_PROTOCOL_VERSION), min_client_protocol_version: Some(CLIENT_PROTOCOL_VERSION), @@ -282,7 +282,7 @@ mod tests { fn server_without_protocol_fields_is_too_old() { // A pre-M10.6 server: /api/config parses, but carries no protocol block. let info = ServerInfo { - site_name: Some("ThoughtSync".into()), + site_name: Some("Inkwell".into()), version: Some("0.0.9".into()), ..Default::default() }; diff --git a/desktop/src-tauri/src/commands/local.rs b/desktop/src-tauri/src/commands/local.rs index a41c2ec..05f8e74 100644 --- a/desktop/src-tauri/src/commands/local.rs +++ b/desktop/src-tauri/src/commands/local.rs @@ -29,7 +29,7 @@ pub fn config_get(db: State<'_, Db>) -> PublicConfig { }; // Offline defaults: no signups, no server-side URL unfurling (needs network). PublicConfig { - site_name: "ThoughtSync".to_string(), + site_name: "Inkwell".to_string(), allow_registration: false, // The build a person reads, baked at compile time — see crate::display_version // for why this is neither CARGO_PKG_VERSION nor the updater's ordering key. diff --git a/desktop/src-tauri/src/commands/sync.rs b/desktop/src-tauri/src/commands/sync.rs index 93195bd..f910c3f 100644 --- a/desktop/src-tauri/src/commands/sync.rs +++ b/desktop/src-tauri/src/commands/sync.rs @@ -51,7 +51,7 @@ pub struct LinkResult { /// A recognizable default, so a server's device list doesn't fill up with "Device". fn default_device_name() -> String { - format!("ThoughtSync desktop ({})", std::env::consts::OS) + format!("Inkwell desktop ({})", std::env::consts::OS) } fn trimmed(value: &Option) -> Option<&str> { diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index bb460b3..bac1e9c 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -189,7 +189,7 @@ pub fn run() { capture::capture_done, ]) .run(tauri::generate_context!()) - .expect("error while running the ThoughtSync desktop app"); + .expect("error while running the Inkwell desktop app"); } /// Match the window's own background to the theme the UI is about to render in. @@ -267,7 +267,7 @@ fn log_event(level: String, message: String) { fn log_environment(app: &tauri::App) { use tauri::Manager; log::info!( - "ThoughtSync desktop {} starting ({} {})", + "Inkwell desktop {} starting ({} {})", display_version(), std::env::consts::OS, std::env::consts::ARCH, diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json index 08296e1..acc255c 100644 --- a/desktop/src-tauri/tauri.conf.json +++ b/desktop/src-tauri/tauri.conf.json @@ -15,7 +15,7 @@ "windows": [ { "label": "main", - "title": "ThoughtSync", + "title": "Inkwell", "width": 1100, "height": 780, "minWidth": 480, diff --git a/frontend/index.html b/frontend/index.html index 7a7bb44..3ab5f16 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -20,8 +20,8 @@ - - ThoughtSync + + Inkwell
diff --git a/frontend/public/icon-maskable.svg b/frontend/public/icon-maskable.svg index e8257e4..68a7470 100644 --- a/frontend/public/icon-maskable.svg +++ b/frontend/public/icon-maskable.svg @@ -1,4 +1,4 @@ - + diff --git a/frontend/public/icon.svg b/frontend/public/icon.svg index f1d1229..69a9092 100644 --- a/frontend/public/icon.svg +++ b/frontend/public/icon.svg @@ -1,4 +1,4 @@ - + diff --git a/frontend/public/manifest.webmanifest b/frontend/public/manifest.webmanifest index e22cd3d..4fdad95 100644 --- a/frontend/public/manifest.webmanifest +++ b/frontend/public/manifest.webmanifest @@ -1,7 +1,7 @@ { "id": "/", - "name": "ThoughtSync", - "short_name": "ThoughtSync", + "name": "Fabled Inkwell", + "short_name": "Inkwell", "description": "Capture a fleeting thought in a second — a self-hosted Keep-style board that grows into a lightweight second brain.", "start_url": "/", "scope": "/", diff --git a/frontend/public/offline.html b/frontend/public/offline.html index 589ca4b..ec6b77e 100644 --- a/frontend/public/offline.html +++ b/frontend/public/offline.html @@ -4,7 +4,7 @@ - Offline · ThoughtSync + Offline · Inkwell