From 6a4d48b49f79efb9c2c1fe7e26cd8774790bc51a Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 20 Apr 2026 06:22:29 -0400 Subject: [PATCH] release(v1.7.0-alpha): bump + fix git-method update + reconciler creates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes bundled into the OTA: 1. update.download hard-fail on git-path nodes. handle_update_check's git branch reported update_available=true + update_method="git" but never populated state.available_update, so update.download returned "No update available to download" even though the UI showed one. SystemUpdate.vue now routes update_method=="git" through update.git-apply (pull+rebuild+ restart via self-update.sh); manifest-path nodes keep the download→apply flow. i18n strings + confirm modal added for the git path. 2. Reconciler creating containers behind the user's back. On fresh unbundled installs (.198, .253) archy-mempool-db and archy-btcpay-db materialised ~10 min after first boot because reconcile-containers.sh walked container-specs.sh's canonical tier list and created any "missing" container. reset_spec() now defaults SPEC_OPTIONAL="true", so reconcile is strictly a repair tool — baseline comes from first-boot-containers.sh (filebrowser on unbundled), everything else from the install RPC. Also forces OTA trigger for nodes on 1.6.0-alpha that otherwise saw "I'm at manifest.version, nothing to do" and skipped the refreshed 1.6 artifacts. Co-Authored-By: Claude Opus 4.7 (1M context) --- core/Cargo.lock | 2 +- core/archipelago/Cargo.toml | 2 +- neode-ui/src/locales/en.json | 7 ++- neode-ui/src/locales/es.json | 7 ++- neode-ui/src/views/SystemUpdate.vue | 70 ++++++++++++++++++++++++----- scripts/container-specs.sh | 7 ++- 6 files changed, 78 insertions(+), 17 deletions(-) diff --git a/core/Cargo.lock b/core/Cargo.lock index 3236f32b..01b5972e 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "archipelago" -version = "1.6.0-alpha" +version = "1.7.0-alpha" dependencies = [ "anyhow", "archipelago-container", diff --git a/core/archipelago/Cargo.toml b/core/archipelago/Cargo.toml index 05f330b3..c126161c 100644 --- a/core/archipelago/Cargo.toml +++ b/core/archipelago/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archipelago" -version = "1.6.0-alpha" +version = "1.7.0-alpha" edition = "2021" description = "Archipelago Bitcoin Node OS - Native backend" authors = ["Archipelago Team"] diff --git a/neode-ui/src/locales/en.json b/neode-ui/src/locales/en.json index ae5cef50..be726c6b 100644 --- a/neode-ui/src/locales/en.json +++ b/neode-ui/src/locales/en.json @@ -683,7 +683,12 @@ "applySuccess": "Update applied. The service will restart momentarily.", "applyFailed": "Failed to apply update. You can try again or rollback.", "rollbackSuccess": "Rolled back to previous version. Service will restart.", - "rollbackFailed": "Rollback failed." + "rollbackFailed": "Rollback failed.", + "pullAndRebuild": "Pull & Rebuild", + "gitMethodHint": "This node builds from source. Update will git-pull, rebuild the backend and UI, then restart — takes a few minutes.", + "gitApplyTitle": "Pull & Rebuild?", + "gitApplyMessage": "Archipelago will pull the latest code, rebuild, and restart. This can take several minutes and the UI will be briefly unavailable.", + "gitApplyStarted": "Update started. The backend will rebuild and restart — this can take a few minutes." }, "kiosk": { "pressEsc": "Press ESC to exit", diff --git a/neode-ui/src/locales/es.json b/neode-ui/src/locales/es.json index dbbfff39..79fbca32 100644 --- a/neode-ui/src/locales/es.json +++ b/neode-ui/src/locales/es.json @@ -682,7 +682,12 @@ "applySuccess": "Actualizaci\u00f3n aplicada. El servicio se reiniciar\u00e1 en un momento.", "applyFailed": "Error al aplicar la actualizaci\u00f3n. Puede intentar de nuevo o revertir.", "rollbackSuccess": "Se revirti\u00f3 a la versi\u00f3n anterior. El servicio se reiniciar\u00e1.", - "rollbackFailed": "Error al revertir." + "rollbackFailed": "Error al revertir.", + "pullAndRebuild": "Pull y Recompilar", + "gitMethodHint": "Este nodo compila desde el c\u00f3digo fuente. La actualizaci\u00f3n har\u00e1 git-pull, recompilar\u00e1 y reiniciar\u00e1 — tarda unos minutos.", + "gitApplyTitle": "\u00bfPull y Recompilar?", + "gitApplyMessage": "Archipelago descargar\u00e1 el c\u00f3digo m\u00e1s reciente, lo compilar\u00e1 y reiniciar\u00e1. Puede tardar varios minutos y la UI estar\u00e1 brevemente no disponible.", + "gitApplyStarted": "Actualizaci\u00f3n iniciada. El backend se recompilar\u00e1 y reiniciar\u00e1 — puede tardar unos minutos." }, "kiosk": { "pressEsc": "Presione ESC para salir", diff --git a/neode-ui/src/views/SystemUpdate.vue b/neode-ui/src/views/SystemUpdate.vue index c375de5a..f7adf433 100644 --- a/neode-ui/src/views/SystemUpdate.vue +++ b/neode-ui/src/views/SystemUpdate.vue @@ -64,21 +64,33 @@
+ + +
+

+ {{ t('systemUpdate.gitMethodHint') }} +

@@ -169,12 +181,18 @@

- {{ confirmAction === 'apply' ? t('systemUpdate.applyTitle') : t('systemUpdate.rollbackTitle') }} + {{ confirmAction === 'rollback' + ? t('systemUpdate.rollbackTitle') + : confirmAction === 'git-apply' + ? t('systemUpdate.gitApplyTitle') + : t('systemUpdate.applyTitle') }}

- {{ confirmAction === 'apply' - ? t('systemUpdate.applyMessage') - : t('systemUpdate.rollbackMessage') }} + {{ confirmAction === 'rollback' + ? t('systemUpdate.rollbackMessage') + : confirmAction === 'git-apply' + ? t('systemUpdate.gitApplyMessage') + : t('systemUpdate.applyMessage') }}

@@ -222,10 +244,11 @@ const loading = ref(false) const downloading = ref(false) const downloaded = ref(false) const applying = ref(false) -const confirmAction = ref<'apply' | 'rollback' | null>(null) +const confirmAction = ref<'apply' | 'git-apply' | 'rollback' | null>(null) const currentVersion = ref('0.0.0') const lastCheck = ref(null) const updateInfo = ref(null) +const updateMethod = ref<'git' | 'manifest' | null>(null) const rollbackAvailable = ref(false) const updateInProgress = ref(false) const statusMessage = ref('') @@ -299,10 +322,12 @@ async function checkForUpdates() { last_check: string | null update_available: boolean update: UpdateDetail | null + update_method?: string }>({ method: 'update.check' }) currentVersion.value = res.current_version lastCheck.value = res.last_check updateInfo.value = res.update + updateMethod.value = res.update_method === 'git' ? 'git' : 'manifest' if (!res.update_available) { showStatus(t('systemUpdate.upToDateMessage')) } @@ -349,6 +374,10 @@ function requestApply() { confirmAction.value = 'apply' } +function requestGitApply() { + confirmAction.value = 'git-apply' +} + function requestRollback() { confirmAction.value = 'rollback' } @@ -358,15 +387,32 @@ function cancelConfirm() { } async function executeConfirm() { - if (confirmAction.value === 'apply') { - confirmAction.value = null + const action = confirmAction.value + confirmAction.value = null + if (action === 'apply') { await applyUpdate() - } else if (confirmAction.value === 'rollback') { - confirmAction.value = null + } else if (action === 'git-apply') { + await applyUpdateGit() + } else if (action === 'rollback') { await rollbackUpdate() } } +async function applyUpdateGit() { + applying.value = true + statusMessage.value = '' + try { + await rpcClient.call({ method: 'update.git-apply' }) + showStatus(t('systemUpdate.gitApplyStarted')) + updateInfo.value = null + } catch (e) { + showStatus(t('systemUpdate.applyFailed'), true) + if (import.meta.env.DEV) console.warn('Git apply failed', e) + } finally { + applying.value = false + } +} + async function applyUpdate() { applying.value = true statusMessage.value = '' diff --git a/scripts/container-specs.sh b/scripts/container-specs.sh index 7bdcb70a..34df8689 100755 --- a/scripts/container-specs.sh +++ b/scripts/container-specs.sh @@ -73,7 +73,12 @@ reset_spec() { SPEC_SECURITY="no-new-privileges:true" SPEC_RESTART="unless-stopped" SPEC_HEALTH_CMD="" SPEC_ENV="" SPEC_CUSTOM_ARGS="" SPEC_READONLY="false" SPEC_TMPFS="" SPEC_TIER="3" SPEC_DATA_DIR="" SPEC_DATA_UID="100000:100000" - SPEC_DEPENDS="" SPEC_LOCAL_IMAGE="false" SPEC_OPTIONAL="false" + # SPEC_OPTIONAL defaults true: reconcile-containers.sh only REPAIRS existing + # containers — it never creates missing ones. Baseline (filebrowser) is + # bootstrapped by first-boot-containers.sh; all other apps come from the + # install RPC. Per-spec `SPEC_OPTIONAL="true"` lines below are now redundant + # but kept for readability. + SPEC_DEPENDS="" SPEC_LOCAL_IMAGE="false" SPEC_OPTIONAL="true" SPEC_ENTRYPOINT="" }