chore(release): refresh v1.7.56-alpha notes and artifacts

This commit is contained in:
archipelago 2026-05-15 17:54:32 -04:00
parent 5818541721
commit 30505f41ff
7 changed files with 88 additions and 10 deletions

View File

@ -1,11 +1,21 @@
# Changelog
## v1.7.56-alpha (2026-05-14)
## v1.7.56-alpha (2026-05-15)
- Health notifications now clear when an app is no longer unhealthy, including stale alerts for removed containers such as Portainer.
- Quadlet environment values with spaces or shell metacharacters are quoted consistently, preventing env drift recreate loops for apps like nostr-rs-relay and Grafana.
- Boot/bootstrap reconcile avoids restarting running Bitcoin containers while repairing RPC config, preserving IBD progress on active nodes.
- Exit code 137 is labeled as SIGKILL instead of assuming OOM, avoiding false OOM alerts for orchestrator-managed recreates.
- Container reconcile force-recreates Podman records stuck in `Stopping`, preserving bind-mounted app data while recovering wedged containers automatically.
- Container health reporting is honest for running containers: Archipelago surfaces Podman's actual health state instead of marking every running container healthy.
- Quadlet reconciliation restarts services when stale health gates, port bindings, network aliases, exec commands, or healthchecks drift from the current manifest.
- Bitcoin Knots sync performance improves on fresh installs and updates with 8Gi container memory, a 4Gi dbcache, and full CPU parallelism.
- ElectrumX initial indexing gets more headroom: CPU caps are removed, memory is raised to 4Gi, cache is raised to 3Gi, and oversized sends are allowed for heavier wallet/indexing workloads.
- Mempool/ElectrumX lifecycle qualification respects pruned/non-archival Bitcoin nodes instead of installing a half-running stack with unhealthy dependencies.
- LND wallet/RPC helpers are more tolerant of container-owned files and updated REST port metadata, improving LND lifecycle and wallet-connect flows.
- Marketplace/catalog metadata carries richer container config so remote lifecycle tests install apps using the same settings users get from the UI.
- The app screensaver no longer activates during media-heavy app sessions such as IndeeHub, Jellyfin, Immich, PhotoPrism, and File Browser; apps can also pause/resume it with media playback messages.
- A fresh `1.7.56-alpha` unbundled installer ISO is built from the same primary VPS2 release line for easy download and USB flashing.
## v1.7.55-alpha (2026-05-13)

View File

@ -161,7 +161,7 @@ function onKeyDown(e: KeyboardEvent) {
}
// 's' key activates screensaver when authenticated (skip if typing in input)
if (e.key === 's' || e.key === 'S') {
if (!isInput && appStore.isAuthenticated && !screensaverStore.isActive) {
if (!isInput && appStore.isAuthenticated && !screensaverStore.isActive && !screensaverStore.isSuppressed) {
e.preventDefault()
screensaverStore.activate()
}

View File

@ -68,6 +68,24 @@ describe('useScreensaverStore', () => {
expect(store.isActive).toBe(false)
})
it('suppression prevents automatic and manual activation until resumed', () => {
const store = useScreensaverStore()
store.suppress('video')
expect(store.isSuppressed).toBe(true)
store.resetInactivityTimer()
vi.advanceTimersByTime(5 * 60 * 1000)
expect(store.isActive).toBe(false)
store.activate()
expect(store.isActive).toBe(false)
store.resume('video')
expect(store.isSuppressed).toBe(false)
vi.advanceTimersByTime(3 * 60 * 1000)
expect(store.isActive).toBe(true)
})
it('activate clears any pending timer', () => {
const store = useScreensaverStore()
store.deactivate()

View File

@ -6,12 +6,15 @@ const INACTIVITY_MS = 3 * 60 * 1000 // 3 minutes
export const useScreensaverStore = defineStore('screensaver', () => {
const isActive = ref(false)
const activationCount = ref(0)
const suppressionReasons = ref<Set<string>>(new Set())
let inactivityTimer: ReturnType<typeof setTimeout> | null = null
/** True when the current activation is the ASCII variant (every 3rd time) */
const isAsciiMode = computed(() => activationCount.value > 0 && activationCount.value % 3 === 0)
const isSuppressed = computed(() => suppressionReasons.value.size > 0)
function activate() {
if (isSuppressed.value) return
activationCount.value++
isActive.value = true
clearInactivityTimer()
@ -24,8 +27,10 @@ export const useScreensaverStore = defineStore('screensaver', () => {
function resetInactivityTimer() {
clearInactivityTimer()
if (isSuppressed.value) return
inactivityTimer = setTimeout(() => {
inactivityTimer = null
if (isSuppressed.value) return
isActive.value = true
}, INACTIVITY_MS)
}
@ -37,13 +42,30 @@ export const useScreensaverStore = defineStore('screensaver', () => {
}
}
function suppress(reason: string) {
suppressionReasons.value = new Set(suppressionReasons.value).add(reason)
clearInactivityTimer()
isActive.value = false
}
function resume(reason: string) {
if (!suppressionReasons.value.has(reason)) return
const next = new Set(suppressionReasons.value)
next.delete(reason)
suppressionReasons.value = next
if (next.size === 0) resetInactivityTimer()
}
return {
isActive,
isAsciiMode,
isSuppressed,
activationCount,
activate,
deactivate,
resetInactivityTimer,
clearInactivityTimer,
suppress,
resume,
}
})

View File

@ -91,6 +91,7 @@
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useAppLauncherStore } from '@/stores/appLauncher'
import { useScreensaverStore } from '@/stores/screensaver'
import NostrIdentityPicker from '@/components/NostrIdentityPicker.vue'
import AppSessionHeader from './appSession/AppSessionHeader.vue'
import AppSessionFrame from './appSession/AppSessionFrame.vue'
@ -115,6 +116,7 @@ const isInlinePanel = computed(() => !!props.appIdProp)
const route = useRoute()
const router = useRouter()
const screensaverStore = useScreensaverStore()
const sessionRef = ref<HTMLElement | null>(null)
const frameRef = ref<InstanceType<typeof AppSessionFrame> | null>(null)
@ -145,6 +147,14 @@ const appId = computed(() => {
const appTitle = computed(() => resolveAppTitle(appId.value))
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
const mustOpenNewTab = computed(() => NEW_TAB_APPS.has(appId.value))
const screensaverReason = computed(() => `app-session:${appId.value}`)
const screensaverSuppressedApps = new Set([
'indeedhub',
'jellyfin',
'immich',
'photoprism',
'filebrowser',
])
const appUrl = computed(() => {
return resolveAppUrl(appId.value, route.query.path as string | undefined)
@ -306,6 +316,8 @@ function onFullscreenChange() {
function onMessage(e: MessageEvent) {
if (e.data?.type === 'nostr-request') nostrBridge.handleNostrRequest(e)
if (e.data?.type === 'archipelago:identity:request') identity.handleIdentityRequest()
if (e.data?.type === 'archipelago:media:playing') screensaverStore.suppress(screensaverReason.value)
if (e.data?.type === 'archipelago:media:idle') screensaverStore.resume(screensaverReason.value)
}
// Enter fullscreen on mount if mode is fullscreen
@ -338,6 +350,9 @@ onMounted(() => {
sessionRef.value?.requestFullscreen().catch(() => {})
})
}
if (screensaverSuppressedApps.has(appId.value)) {
screensaverStore.suppress(screensaverReason.value)
}
})
onBeforeUnmount(() => {
@ -347,6 +362,7 @@ onBeforeUnmount(() => {
window.removeEventListener('keydown', onKeyDown, true)
window.removeEventListener('message', onMessage)
document.removeEventListener('fullscreenchange', onFullscreenChange)
screensaverStore.resume(screensaverReason.value)
if (document.fullscreenElement) document.exitFullscreen().catch(() => {})
})
</script>

View File

@ -1,11 +1,17 @@
{
"version": "1.7.56-alpha",
"release_date": "2026-05-14",
"release_date": "2026-05-15",
"changelog": [
"Health notifications now clear when an app is no longer unhealthy, including stale alerts for removed containers such as Portainer.",
"Quadlet environment values with spaces or shell metacharacters are quoted consistently, preventing env drift recreate loops for apps like nostr-rs-relay and Grafana.",
"Boot/bootstrap reconcile avoids restarting running Bitcoin containers while repairing RPC config, preserving IBD progress on active nodes.",
"Exit code 137 is labeled as SIGKILL instead of assuming OOM, avoiding false OOM alerts for orchestrator-managed recreates."
"Exit code 137 is labeled as SIGKILL instead of assuming OOM, avoiding false OOM alerts for orchestrator-managed recreates.",
"Container reconcile force-recreates Podman records stuck in `Stopping`, preserving bind-mounted app data while recovering wedged containers automatically.",
"Container health reporting is honest for running containers: Archipelago surfaces Podman's actual health state instead of marking every running container healthy.",
"Quadlet reconciliation restarts services when stale health gates, port bindings, network aliases, exec commands, or healthchecks drift from the current manifest.",
"Bitcoin Knots sync performance improves on fresh installs and updates with 8Gi container memory, a 4Gi dbcache, and full CPU parallelism.",
"ElectrumX initial indexing gets more headroom: CPU caps are removed, memory is raised to 4Gi, cache is raised to 3Gi, and oversized sends are allowed for heavier wallet/indexing workloads.",
"Mempool/ElectrumX lifecycle qualification respects pruned/non-archival Bitcoin nodes instead of installing a half-running stack with unhealthy dependencies."
],
"components": [
{
@ -21,8 +27,8 @@
"current_version": "1.7.56-alpha",
"new_version": "1.7.56-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.56-alpha/archipelago-frontend-1.7.56-alpha.tar.gz",
"sha256": "9cee503e260891267fed33e4c97f067a4a592b10695ecea4cbf730d517ff6c8b",
"size_bytes": 166493666
"sha256": "91bfa10085696921c929ab7d216a8e617eb02e7105f21f32cdc3a2ba15158cd4",
"size_bytes": 166465069
}
]
}

View File

@ -1,11 +1,17 @@
{
"version": "1.7.56-alpha",
"release_date": "2026-05-14",
"release_date": "2026-05-15",
"changelog": [
"Health notifications now clear when an app is no longer unhealthy, including stale alerts for removed containers such as Portainer.",
"Quadlet environment values with spaces or shell metacharacters are quoted consistently, preventing env drift recreate loops for apps like nostr-rs-relay and Grafana.",
"Boot/bootstrap reconcile avoids restarting running Bitcoin containers while repairing RPC config, preserving IBD progress on active nodes.",
"Exit code 137 is labeled as SIGKILL instead of assuming OOM, avoiding false OOM alerts for orchestrator-managed recreates."
"Exit code 137 is labeled as SIGKILL instead of assuming OOM, avoiding false OOM alerts for orchestrator-managed recreates.",
"Container reconcile force-recreates Podman records stuck in `Stopping`, preserving bind-mounted app data while recovering wedged containers automatically.",
"Container health reporting is honest for running containers: Archipelago surfaces Podman's actual health state instead of marking every running container healthy.",
"Quadlet reconciliation restarts services when stale health gates, port bindings, network aliases, exec commands, or healthchecks drift from the current manifest.",
"Bitcoin Knots sync performance improves on fresh installs and updates with 8Gi container memory, a 4Gi dbcache, and full CPU parallelism.",
"ElectrumX initial indexing gets more headroom: CPU caps are removed, memory is raised to 4Gi, cache is raised to 3Gi, and oversized sends are allowed for heavier wallet/indexing workloads.",
"Mempool/ElectrumX lifecycle qualification respects pruned/non-archival Bitcoin nodes instead of installing a half-running stack with unhealthy dependencies."
],
"components": [
{
@ -21,8 +27,8 @@
"current_version": "1.7.56-alpha",
"new_version": "1.7.56-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.56-alpha/archipelago-frontend-1.7.56-alpha.tar.gz",
"sha256": "9cee503e260891267fed33e4c97f067a4a592b10695ecea4cbf730d517ff6c8b",
"size_bytes": 166493666
"sha256": "91bfa10085696921c929ab7d216a8e617eb02e7105f21f32cdc3a2ba15158cd4",
"size_bytes": 166465069
}
]
}