2026-01-24 22:59:20 +00:00
< template >
2026-03-14 17:12:41 +00:00
< div class = "pb-6" >
2026-03-05 10:14:10 +00:00
< div class = "mb-4 md:mb-8 flex items-start justify-between gap-4" >
2026-02-18 10:35:04 +00:00
< div class = "min-h-[4.5rem]" >
< h1 class = "text-3xl font-bold text-white mb-2 drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]" >
{ { line1Text } } < span v-if = "showCaretLine1" class="typing-caret" > < / span >
< / h1 >
< p class = "text-white/80" >
{ { line2Text } } < span v-if = "showCaretLine2" class="typing-caret" > < / span >
< / p >
2026-01-24 22:59:20 +00:00
< / div >
2026-03-05 10:14:10 +00:00
<!-- Desktop : tabs inline with header -- >
< div
v - if = "!uiMode.isChat"
fix: production onboarding, CI tests, container security, keyboard nav
Install & Onboarding:
- Remove DEV_MODE=true from production ISO service file (auto-created
users, skipped password setup)
- Auto-install no longer overwrites rootfs service file with bad template
- Login.vue always checks auth.isSetup — shows password creation form
on fresh install without requiring dev build flag
- Deploy image-versions.sh to /opt/archipelago/scripts/ on installed nodes
- First-boot-containers sources image-versions.sh, runs podman as
archipelago user (rootless), enables linger + podman.socket
- Correct volume ownership (100000:100000 for rootless UID mapping)
Container Security:
- FileBrowser: add --cap-add=DAC_OVERRIDE for rootless podman volume access
- FileBrowser: add --read-only, /data volume for database, proper cmd args
- First-boot script matches backend config (security hardening + health check)
CI Pipeline:
- Add vue-tsc type check + vitest run to build-iso.yml (runs every push)
- Add post-install-tests.yml workflow (workflow_dispatch, SSH to target)
- Build report: set +eo pipefail, fix rootfs path, add || true guards
- Bundle run-post-install-tests.sh into ISO
E2E Test Suite (scripts/run-post-install-tests.sh):
- Phase 1: Install verification (files, services, podman, linger, DEV_MODE check)
- Phase 2: Onboarding flow (auth.isSetup, auth.setup, login, DID, complete)
- Phase 3: Container lifecycle (install 3 apps via package.install RPC,
verify running, stop, verify stopped, restart, verify running, health)
- Phase 4: Log verification (first-boot log, diagnostics, journal errors)
- Correct package.install params: {"id", "dockerImage"}
Frontend:
- Fix backdrop-filter tab-switch bug (keep animations paused during rebuild)
- Dashboard glitch animations paused during tab-hidden
- Gamepad nav: auto-focus first container on route change
- Tab roving: Left/Right on role="tab" cycles and activates sibling tabs
- ContainerApps: data-controller-launch on running app cards
- 515 tests passing (fixed 30 broken, added 19 new keyboard nav tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:16:57 +00:00
role = "tablist"
2026-03-05 10:14:10 +00:00
class = "hidden md:flex mode-switcher flex-shrink-0 transition-opacity duration-500"
: class = "{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
>
2026-03-11 13:45:59 +00:00
< button class = "mode-switcher-btn" role = "tab" : aria -selected = " homeTab = = = ' dashboard ' " : class = "{ 'mode-switcher-btn-active': homeTab === 'dashboard' }" @ click = "homeTab = 'dashboard'" > { { t ( 'home.dashboardTab' ) } } < / button >
< button class = "mode-switcher-btn" role = "tab" : aria -selected = " homeTab = = = ' setup ' " : class = "{ 'mode-switcher-btn-active': homeTab === 'setup' }" @ click = "homeTab = 'setup'" > { { t ( 'home.setupTab' ) } } < / button >
2026-03-11 13:04:31 +00:00
< / div >
< / div >
<!-- Update notification banner -- >
< div
v - if = "updateAvailable && !updateDismissed"
role = "alert"
class = "mb-6 glass-card p-4 flex items-center justify-between gap-4 border-l-4 border-orange-400 transition-opacity duration-300"
: class = "{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
>
< div class = "flex items-center gap-3 min-w-0" >
< svg class = "w-6 h-6 text-orange-400 shrink-0" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" / >
< / svg >
< div class = "min-w-0" >
2026-03-11 13:45:59 +00:00
< p class = "text-sm font-medium text-white" > { { t ( 'home.updateAvailable' , { version : updateVersion } ) } } < / p >
2026-03-11 13:04:31 +00:00
< p v-if = "updateChangelog" class="text-xs text-white/60 truncate" > {{ updateChangelog }} < / p >
< / div >
< / div >
< div class = "flex items-center gap-2 shrink-0" >
2026-03-21 03:01:38 +00:00
< RouterLink to = "/dashboard/settings/update" class = "glass-button rounded-lg px-4 py-2 text-sm font-medium" > { { t ( 'home.updateNow' ) } } < / RouterLink >
2026-03-11 13:04:31 +00:00
< button @click ="dismissUpdate" aria -label = " Dismiss update notification " class = "text-white/40 hover:text-white/80 transition-colors p-1" title = "Dismiss" >
2026-03-21 03:01:38 +00:00
< svg class = "w-5 h-5" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M6 18L18 6M6 6l12 12" / > < / svg >
2026-03-11 13:04:31 +00:00
< / button >
2026-03-05 10:14:10 +00:00
< / div >
2026-01-24 22:59:20 +00:00
< / div >
2026-03-05 07:36:43 +00:00
<!-- Tab bar + content ( all non - chat modes ) -- >
< template v-if = "!uiMode.isChat" >
2026-03-05 10:14:10 +00:00
<!-- Mobile : full - width tabs -- >
< div
2026-03-11 13:04:31 +00:00
role = "tablist"
fix: production onboarding, CI tests, container security, keyboard nav
Install & Onboarding:
- Remove DEV_MODE=true from production ISO service file (auto-created
users, skipped password setup)
- Auto-install no longer overwrites rootfs service file with bad template
- Login.vue always checks auth.isSetup — shows password creation form
on fresh install without requiring dev build flag
- Deploy image-versions.sh to /opt/archipelago/scripts/ on installed nodes
- First-boot-containers sources image-versions.sh, runs podman as
archipelago user (rootless), enables linger + podman.socket
- Correct volume ownership (100000:100000 for rootless UID mapping)
Container Security:
- FileBrowser: add --cap-add=DAC_OVERRIDE for rootless podman volume access
- FileBrowser: add --read-only, /data volume for database, proper cmd args
- First-boot script matches backend config (security hardening + health check)
CI Pipeline:
- Add vue-tsc type check + vitest run to build-iso.yml (runs every push)
- Add post-install-tests.yml workflow (workflow_dispatch, SSH to target)
- Build report: set +eo pipefail, fix rootfs path, add || true guards
- Bundle run-post-install-tests.sh into ISO
E2E Test Suite (scripts/run-post-install-tests.sh):
- Phase 1: Install verification (files, services, podman, linger, DEV_MODE check)
- Phase 2: Onboarding flow (auth.isSetup, auth.setup, login, DID, complete)
- Phase 3: Container lifecycle (install 3 apps via package.install RPC,
verify running, stop, verify stopped, restart, verify running, health)
- Phase 4: Log verification (first-boot log, diagnostics, journal errors)
- Correct package.install params: {"id", "dockerImage"}
Frontend:
- Fix backdrop-filter tab-switch bug (keep animations paused during rebuild)
- Dashboard glitch animations paused during tab-hidden
- Gamepad nav: auto-focus first container on route change
- Tab roving: Left/Right on role="tab" cycles and activates sibling tabs
- ContainerApps: data-controller-launch on running app cards
- 515 tests passing (fixed 30 broken, added 19 new keyboard nav tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:16:57 +00:00
class = "md:hidden mode-switcher mb-6 w-full transition-opacity duration-500"
2026-03-05 10:14:10 +00:00
: class = "{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
>
2026-03-11 13:45:59 +00:00
< button class = "mode-switcher-btn" role = "tab" : aria -selected = " homeTab = = = ' dashboard ' " : class = "{ 'mode-switcher-btn-active': homeTab === 'dashboard' }" @ click = "homeTab = 'dashboard'" > { { t ( 'home.dashboardTab' ) } } < / button >
< button class = "mode-switcher-btn" role = "tab" : aria -selected = " homeTab = = = ' setup ' " : class = "{ 'mode-switcher-btn-active': homeTab === 'setup' }" @ click = "homeTab = 'setup'" > { { t ( 'home.setupTab' ) } } < / button >
2026-03-05 07:36:43 +00:00
< / div >
2026-03-04 07:09:31 +00:00
2026-03-21 03:01:38 +00:00
<!-- Setup tab -- >
< EasyHome v-if = "homeTab === 'setup'" :show="!showWelcomeBlock || animateCards" :animate="animateCards" / >
2026-03-05 07:36:43 +00:00
<!-- Dashboard tab : overview cards -- >
< div
v - else
class = "grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8 transition-opacity duration-300"
: class = "{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
>
2026-03-21 03:01:38 +00:00
<!-- My Apps Overview -- >
< div data -controller -container tabindex = "0" class = "home-card controller-focusable" : class = "{ 'home-card-animate': animateCards }" style = "--card-stagger: 0" >
< div class = "home-card-shell" >
< div class = "home-card-inner p-6 flex flex-col h-full min-h-0" >
< div class = "home-card-header flex items-start justify-between mb-4 shrink-0" >
< div class = "home-card-text" >
< h2 class = "text-xl font-semibold text-white mb-1" > { { t ( 'home.myApps' ) } } < / h2 >
< p class = "text-sm text-white/70" > { { t ( 'home.myAppsDesc' ) } } < / p >
< / div >
< RouterLink to = "/dashboard/apps" :aria-label = "t('home.goToApps')" class = "text-white/60 hover:text-white transition-colors" >
< svg class = "w-5 h-5" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M9 5l7 7-7 7" / > < / svg >
< / RouterLink >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-stats grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4 flex-1 min-h-0" >
< div class = "p-4 bg-white/5 rounded-lg" >
< p class = "text-xs text-white/60 mb-1" > Installed / Running < / p >
< p class = "text-2xl font-bold text-white" > { { appCount } } / { { runningCount } } < / p >
< / div >
< div class = "p-4 bg-white/5 rounded-lg flex items-center justify-around" >
< button v-for = "app in quickLaunchApps" :key="app.id" @click="useAppLauncherStore().openSession(app.id)" class="group" :title="app.name" >
< div class = "w-14 h-14 rounded-xl overflow-hidden border border-white/10 transition-all group-hover:-translate-y-1 group-hover:border-white/25 group-hover:shadow-lg flex items-center justify-center" : style = "app.bg ? { background: app.bg } : {}" : class = "{ 'bg-white/5': !app.bg }" >
2026-03-16 12:58:35 +00:00
< img :src = "app.icon" :alt = "app.name" : class = "app.padded ? 'w-10 h-10 object-contain' : 'w-full h-full object-cover'" / >
< / div >
< / button >
2026-03-21 03:01:38 +00:00
< / div >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-buttons flex gap-2 mt-auto pt-4 shrink-0" >
< RouterLink to = "/dashboard/marketplace" class = "home-card-btn flex-1 px-4 py-2 glass-button rounded-lg text-sm font-medium text-center transition-colors" > { { t ( 'home.browseStore' ) } } < / RouterLink >
< RouterLink to = "/dashboard/apps" class = "home-card-btn flex-1 px-4 py-2 glass-button rounded-lg text-sm font-medium text-center transition-colors" > { { t ( 'home.manageApps' ) } } < / RouterLink >
2026-02-17 19:19:54 +00:00
< / div >
< / div >
2026-01-24 22:59:20 +00:00
< / div >
< / div >
2026-03-21 03:01:38 +00:00
<!-- Cloud Overview -- >
< div data -controller -container tabindex = "0" class = "home-card controller-focusable" : class = "{ 'home-card-animate': animateCards }" style = "--card-stagger: 1" >
< div class = "home-card-shell" >
< div class = "home-card-inner p-6 flex flex-col h-full min-h-0" >
< div class = "home-card-header flex items-start justify-between mb-4 shrink-0" >
< div class = "home-card-text" >
< h2 class = "text-xl font-semibold text-white mb-1" > { { t ( 'home.cloud' ) } } < / h2 >
< p class = "text-sm text-white/70" > { { t ( 'home.cloudDesc' ) } } < / p >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< RouterLink to = "/dashboard/cloud" :aria-label = "t('home.goToCloud')" class = "text-white/60 hover:text-white transition-colors" >
< svg class = "w-5 h-5" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M9 5l7 7-7 7" / > < / svg >
< / RouterLink >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-stats grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4 flex-1 min-h-0" >
< div class = "p-4 bg-white/5 rounded-lg" > < p class = "text-xs text-white/60 mb-1" > { { t ( 'home.storageUsed' ) } } < / p > < p class = "text-2xl font-bold text-white" > { { cloudStorageDisplay } } < / p > < / div >
< div class = "p-4 bg-white/5 rounded-lg" > < p class = "text-xs text-white/60 mb-1" > { { t ( 'home.folders' ) } } < / p > < p class = "text-2xl font-bold text-white" > { { cloudFolderDisplay } } < / p > < / div >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-buttons flex gap-2 mt-auto pt-4 shrink-0" >
< RouterLink to = "/dashboard/cloud" class = "home-card-btn flex-1 px-4 py-2 glass-button rounded-lg text-sm font-medium text-center transition-colors" > { { t ( 'home.viewFolders' ) } } < / RouterLink >
< button @click ="uploadFiles" class = "home-card-btn flex-1 px-4 py-2 glass-button rounded-lg text-sm font-medium text-center transition-colors" > { { t ( 'home.uploadFiles' ) } } < / button >
2026-02-17 19:19:54 +00:00
< / div >
2026-01-24 22:59:20 +00:00
< / div >
< / div >
< / div >
2026-03-21 03:01:38 +00:00
<!-- Network Overview -- >
< div data -controller -container tabindex = "0" class = "home-card controller-focusable" : class = "{ 'home-card-animate': animateCards }" style = "--card-stagger: 2" >
< div class = "home-card-shell" >
< div class = "home-card-inner p-6 flex flex-col h-full min-h-0" >
< div class = "home-card-header flex items-start justify-between mb-4 shrink-0" >
< div class = "home-card-text" >
< h2 class = "text-xl font-semibold text-white mb-1" > { { t ( 'home.network' ) } } < / h2 >
< p class = "text-sm text-white/70" > { { t ( 'home.networkDesc' ) } } < / p >
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< RouterLink to = "/dashboard/server" :aria-label = "t('home.goToNetwork')" class = "text-white/60 hover:text-white transition-colors" >
< svg class = "w-5 h-5" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M9 5l7 7-7 7" / > < / svg >
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
< / RouterLink >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-stats space-y-3 mb-4 flex-1 min-h-0" >
< div class = "flex items-center justify-between p-3 bg-white/5 rounded-lg" >
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
< div class = "flex items-center gap-3" > < div class = "w-2 h-2 rounded-full" : class = "torConnected ? 'bg-purple-400' : 'bg-white/40'" > < / div > < span class = "text-sm text-white/80" > Tor < / span > < / div >
< span class = "text-sm font-medium" : class = "torConnected ? 'text-purple-400' : 'text-white/40'" > { { torConnected ? 'Connected' : 'Offline' } } < / span >
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "flex items-center justify-between p-3 bg-white/5 rounded-lg" >
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
< div class = "flex items-center gap-3" > < div class = "w-2 h-2 rounded-full" : class = "vpnConnected ? 'bg-orange-400' : 'bg-white/40'" > < / div > < span class = "text-sm text-white/80" > VPN < / span > < / div >
2026-04-18 11:07:08 -04:00
< span class = "text-sm font-medium" : class = "vpnConnected ? 'text-orange-400' : 'text-white/40'" > { { vpnConnected ? 'WireGuard' : 'Not configured' } } < / span >
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "flex items-center justify-between p-3 bg-white/5 rounded-lg" >
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
< div class = "flex items-center gap-3" > < div class = "w-2 h-2 rounded-full" : class = "systemStats.bitcoinAvailable ? 'bg-orange-400' : 'bg-white/40'" > < / div > < span class = "text-sm text-white/80" > Bitcoin < / span > < / div >
< span class = "text-sm font-medium" : class = "systemStats.bitcoinAvailable ? 'text-orange-400' : 'text-white/40'" > { { bitcoinSyncDisplay } } < / span >
2026-02-17 19:19:54 +00:00
< / div >
2026-04-19 00:42:56 -04:00
< div class = "flex items-center justify-between p-3 bg-white/5 rounded-lg" >
< div class = "flex items-center gap-3" > < div class = "w-2 h-2 rounded-full" :class = "fipsDotClass" > < / div > < span class = "text-sm text-white/80" > FIPS < / span > < / div >
< span class = "text-sm font-medium" :class = "fipsTextClass" > { { fipsStatusLabel } } < / span >
< / div >
2026-02-17 19:19:54 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "home-card-buttons flex gap-2 mt-auto pt-4 shrink-0" >
< RouterLink to = "/dashboard/server" class = "home-card-btn flex-1 px-4 py-2 glass-button rounded-lg text-sm font-medium text-center transition-colors" > { { t ( 'home.manageNetwork' ) } } < / RouterLink >
2026-02-17 19:19:54 +00:00
< / div >
2026-01-24 22:59:20 +00:00
< / div >
< / div >
< / div >
2026-03-21 03:01:38 +00:00
<!-- Wallet Overview -- >
< HomeWalletCard
: animate = "animateCards"
: wallet - connected = "walletConnected"
: wallet - onchain = "walletOnchain"
: wallet - lightning = "walletLightning"
: wallet - ecash = "walletEcash"
: wallet - transactions = "walletTransactions"
: is - dev = "isDev"
@ show - send = "showSendModal = true"
@ show - receive = "showReceiveModal = true"
@ show - transactions = "showTransactionsModal = true"
@ faucet = "devFaucet"
@ open - in - mempool = "openInMempool"
/ >
<!-- System Stats -- >
< HomeSystemCard
: animate = "animateCards"
: loaded = "systemStatsLoaded"
: stats = "systemStats"
: uptime - display = "systemUptimeDisplay"
/ >
2026-01-24 22:59:20 +00:00
< / div >
2026-03-21 03:01:38 +00:00
<!-- Quick Start Goals -- >
2026-03-11 00:24:59 +00:00
< div
2026-03-21 03:01:38 +00:00
v - if = "homeTab === 'dashboard' && showQuickStart"
class = "home-card transition-opacity duration-300"
: class = "{ 'home-card-animate': animateCards, 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
style = "--card-stagger: 5"
2026-03-11 00:24:59 +00:00
>
< div class = "home-card-shell" >
2026-03-21 03:01:38 +00:00
< div class = "home-card-inner px-6 py-6" >
< div class = "flex items-start justify-between mb-2" >
< div >
< h2 class = "text-xl font-semibold text-white/96 mb-1" > { { t ( 'home.quickStartGoals' ) } } < / h2 >
< p class = "text-sm text-white/60 mb-4" > { { t ( 'home.quickStartDesc' ) } } < / p >
2026-03-11 00:24:59 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< button @click ="dismissQuickStart" aria -label = " Dismiss Quick Start " class = "text-white/40 hover:text-white/80 transition-colors p-1 -mt-1 -mr-1" title = "Dismiss" >
< svg class = "w-5 h-5" aria -hidden = " true " fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M6 18L18 6M6 6l12 12" / > < / svg >
< / button >
2026-03-11 00:24:59 +00:00
< / div >
2026-03-21 03:01:38 +00:00
< div class = "grid grid-cols-1 md:grid-cols-3 gap-3" >
< RouterLink v-for = "goal in topGoals" :key="goal.id" :to="`/dashboard/goals/${goal.id}`" class="home-card-btn path-action-button path-action-button--continue flex items-center justify-center gap-3" >
< span > { { goal . title } } < / span >
< / RouterLink >
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
< / div >
< / div >
< / div >
2026-01-24 22:59:20 +00:00
< / div >
2026-03-05 07:36:43 +00:00
< / template >
2026-03-21 03:01:38 +00:00
<!-- Chat Mode -- >
2026-03-04 07:09:31 +00:00
< div v-if = "uiMode.isChat" class="flex flex-col items-center justify-center min-h-[40vh]" >
2026-03-21 03:01:38 +00:00
< RouterLink to = "/dashboard/chat" class = "glass-button rounded-lg px-8 py-4 text-lg font-medium" > { { t ( 'home.openAI' ) } } < / RouterLink >
2026-03-04 07:09:31 +00:00
< / div >
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
feat: gamepad navigation rewrite, focus styling, container grid system
- Rewrite useControllerNav.ts with clean console-style navigation:
Sidebar (up/down wrap, right→containers, left→nothing),
Container tile grid (spatial nav, no wrap at edges),
Nav bar support (up from containers, down to grid),
Inner controls (enter drills in, escape exits, trapped arrows)
- Add data-controller-container to Mesh, Fleet, Settings pages
- Fix Home.vue fragment (modals outside root div) causing Vue warnings
- Remove skip-to-content link (handled by controller nav)
- Orange ambient glow focus styling matching glass aesthetic
- Disable PWA service worker in dev mode (fixes HMR caching)
- Add gamepad-nav skill and GAMEPAD-NAV-MAP.md spec document
- 39 tests covering all navigation patterns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:01:17 +00:00
<!-- Wallet Modals -- >
< SendBitcoinModal :show = "showSendModal" @ close = "showSendModal = false" @sent ="loadWeb5Status()" / >
< ReceiveBitcoinModal :show = "showReceiveModal" @ close = "showReceiveModal = false" @received ="loadWeb5Status()" / >
< TransactionsModal :show = "showTransactionsModal" :transactions = "walletTransactions" @ close = "showTransactionsModal = false" / >
< / div >
2026-01-24 22:59:20 +00:00
< / template >
< script setup lang = "ts" >
2026-03-11 00:24:59 +00:00
import { computed , reactive , ref , watch , onBeforeUnmount , onMounted } from 'vue'
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
import { RouterLink , useRouter } from 'vue-router'
2026-03-11 13:45:59 +00:00
import { useI18n } from 'vue-i18n'
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
import SendBitcoinModal from '@/components/SendBitcoinModal.vue'
import ReceiveBitcoinModal from '@/components/ReceiveBitcoinModal.vue'
2026-03-18 22:05:21 +00:00
import TransactionsModal from '@/components/TransactionsModal.vue'
2026-01-24 22:59:20 +00:00
import { useAppStore } from '../stores/app'
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
import { useAppLauncherStore } from '@/stores/appLauncher'
2026-02-17 19:19:54 +00:00
import { useLoginTransitionStore } from '../stores/loginTransition'
2026-03-04 07:09:31 +00:00
import { useUIModeStore } from '@/stores/uiMode'
2026-01-24 22:59:20 +00:00
import { PackageState } from '../types/api'
2026-02-17 19:19:54 +00:00
import { playTypingSound } from '@/composables/useLoginSounds'
2026-03-04 07:09:31 +00:00
import { GOALS } from '@/data/goals'
import EasyHome from '@/components/EasyHome.vue'
2026-03-05 07:05:14 +00:00
import { fileBrowserClient } from '@/api/filebrowser-client'
2026-03-11 00:24:59 +00:00
import { rpcClient } from '@/api/rpc-client'
2026-03-21 03:01:38 +00:00
import HomeWalletCard from './home/HomeWalletCard.vue'
import HomeSystemCard from './home/HomeSystemCard.vue'
import type { WalletTransaction } from './home/HomeWalletCard.vue'
2026-03-04 07:09:31 +00:00
2026-03-21 03:01:38 +00:00
const { t } = useI18n ( )
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
const router = useRouter ( )
2026-03-04 07:09:31 +00:00
const uiMode = useUIModeStore ( )
2026-03-18 22:05:21 +00:00
const isDev = import . meta . env . DEV
2026-03-05 07:36:43 +00:00
const homeTab = ref < 'dashboard' | 'setup' > ( 'dashboard' )
2026-03-04 07:09:31 +00:00
const topGoals = GOALS . slice ( 0 , 3 )
2026-01-24 22:59:20 +00:00
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
const QUICK _START _APPS = [ ... new Set ( topGoals . flatMap ( ( g ) => g . requiredApps ) ) ]
const QUICK _START _KEY = 'archipelago-quick-start-dismissed'
const QUICK _START _RESHOW _LOGINS = 5
2026-01-24 22:59:20 +00:00
const store = useAppStore ( )
2026-02-17 19:19:54 +00:00
const loginTransition = useLoginTransitionStore ( )
2026-03-11 13:45:59 +00:00
const LINE1 = t ( 'home.title' )
const LINE2 = t ( 'home.subtitle' )
2026-02-17 19:19:54 +00:00
const MS _PER _CHAR = 55
const displayLine1 = ref ( '' )
const displayLine2 = ref ( '' )
const showCaretLine1 = ref ( false )
const showCaretLine2 = ref ( false )
const showWelcomeBlock = ref ( false )
const hasTypedWelcome = ref ( false )
const animateCards = ref ( false )
let typingInterval : ReturnType < typeof setInterval > | null = null
2026-03-21 03:01:38 +00:00
const line1Text = computed ( ( ) => showWelcomeBlock . value ? displayLine1 . value : LINE1 )
const line2Text = computed ( ( ) => showWelcomeBlock . value ? displayLine2 . value : LINE2 )
2026-02-17 19:19:54 +00:00
onBeforeUnmount ( ( ) => {
if ( typingInterval ) clearInterval ( typingInterval )
2026-03-11 00:24:59 +00:00
if ( systemStatsInterval ) clearInterval ( systemStatsInterval )
2026-02-17 19:19:54 +00:00
} )
2026-03-21 03:01:38 +00:00
watch ( ( ) => loginTransition . pendingWelcomeTyping , ( pending ) => { if ( pending ) showWelcomeBlock . value = true } )
2026-02-17 19:19:54 +00:00
watch ( ( ) => loginTransition . startWelcomeTyping , ( shouldStart ) => {
if ( ! shouldStart || hasTypedWelcome . value ) return
2026-03-21 03:01:38 +00:00
hasTypedWelcome . value = true ; showWelcomeBlock . value = true
displayLine1 . value = '' ; displayLine2 . value = ''
showCaretLine1 . value = true ; showCaretLine2 . value = false
playTypingSound ( ) ; animateCards . value = true
2026-02-17 19:19:54 +00:00
let i = 0
typingInterval = setInterval ( ( ) => {
2026-03-21 03:01:38 +00:00
if ( i < LINE1 . length ) { displayLine1 . value = LINE1 . slice ( 0 , i + 1 ) ; i ++ }
else if ( i < LINE1 . length + LINE2 . length ) { showCaretLine1 . value = false ; showCaretLine2 . value = true ; displayLine2 . value = LINE2 . slice ( 0 , i - LINE1 . length + 1 ) ; i ++ }
else { if ( typingInterval ) clearInterval ( typingInterval ) ; typingInterval = null ; showCaretLine2 . value = false ; loginTransition . setStartWelcomeTyping ( false ) }
2026-02-17 19:19:54 +00:00
} , MS _PER _CHAR )
} , { immediate : true } )
2026-01-24 22:59:20 +00:00
const packages = computed ( ( ) => store . packages )
2026-03-16 15:34:04 +00:00
const appCount = computed ( ( ) => Object . keys ( packages . value || { } ) . length )
2026-03-21 03:01:38 +00:00
const runningCount = computed ( ( ) => Object . values ( packages . value || { } ) . filter ( pkg => pkg . state === PackageState . Running ) . length )
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
2026-03-16 12:58:35 +00:00
const quickLaunchApps = [
{ id : 'indeedhub' , name : 'Indeehub' , icon : '/assets/img/app-icons/indeedhub.png' , bg : '#0a0a0a' , padded : true } ,
{ id : 'botfights' , name : 'BotFights' , icon : '/assets/img/app-icons/botfights.svg' , bg : '' , padded : false } ,
{ id : '484-kitchen' , name : '484 Kitchen' , icon : '/assets/img/app-icons/484-kitchen.png' , bg : '' , padded : false } ,
]
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
// Network card data
const torConnected = computed ( ( ) => {
const torAddr = store . data ? . [ 'server-info' ] ? . [ 'tor-address' ]
return ! ! torAddr && torAddr . length > 0
} )
2026-04-07 15:23:17 +01:00
const vpnStatus = ref ( { connected : false , provider : '' } )
2026-04-07 15:18:35 +01:00
const vpnConnected = computed ( ( ) => vpnStatus . value . connected || ( ! ! packages . value [ 'tailscale' ] && packages . value [ 'tailscale' ] . state === PackageState . Running ) )
2026-04-19 00:42:56 -04:00
const fipsStatus = ref < { installed : boolean ; service _active : boolean ; key _present : boolean } | null > ( null )
const fipsDotClass = computed ( ( ) => {
const s = fipsStatus . value
if ( ! s || ! s . installed ) return 'bg-white/40'
if ( s . service _active ) return 'bg-green-400'
return 'bg-white/40'
} )
const fipsTextClass = computed ( ( ) => {
const s = fipsStatus . value
if ( ! s || ! s . installed ) return 'text-white/40'
if ( s . service _active ) return 'text-green-400'
return 'text-white/40'
} )
const fipsStatusLabel = computed ( ( ) => {
const s = fipsStatus . value
if ( ! s ) return '…'
if ( ! s . installed ) return 'Not installed'
if ( s . service _active ) return 'Active'
if ( ! s . key _present ) return 'Awaiting seed'
return 'Inactive'
} )
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
const bitcoinSyncDisplay = computed ( ( ) => {
if ( ! systemStats . bitcoinAvailable ) return 'Not running'
if ( systemStats . bitcoinSyncPercent >= 99.9 ) return 'Synced'
2026-04-01 23:35:27 +01:00
if ( systemStats . bitcoinSyncPercent < 0.01 && systemStats . bitcoinBlockHeight === 0 ) return 'Loading...'
fix: container DNS, nginx chown, onboarding guard, seed UX, install flow
Backend:
- Add --add-host host.containers.internal:host-gateway to LND and Bitcoin
Knots containers (fixes DNS resolution failure in rootless podman)
- Add --user 0:0 and DAC_OVERRIDE to nginx UI sidecar containers
(fixes chown crash in rootless podman for bitcoin-ui, electrs-ui, lnd-ui)
- Add hostadd to Rust Podman API client for web UI container installs
- Add Chromium privacy flags to kiosk launcher (disable telemetry)
Frontend:
- Fix onboarding reset on raw IP visits (trust localStorage as first-class
signal, skip boot screen when server is up but not onboarded)
- Fix seed regression: persist challenge indices in sessionStorage so going
back from Verify doesn't change which words are asked
- Remove glass container from seed Generate/Verify/Restore screens
- Add Back button to Restore from Seed screen
- Replace Network card: Tor (purple), VPN status (orange), Bitcoin sync (orange)
- Add ElectrumX to curated app list with correct .webp icon
- Install flow: navigate to My Apps immediately with toast, hide
installed/installing apps from marketplace and discover views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:06:57 +01:00
return ` ${ systemStats . bitcoinSyncPercent . toFixed ( 1 ) } % `
} )
2026-03-05 07:43:40 +00:00
2026-03-21 03:01:38 +00:00
// Quick Start
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
const quickStartDismissed = ref ( false )
2026-03-21 03:01:38 +00:00
const allQuickStartAppsInstalled = computed ( ( ) => QUICK _START _APPS . every ( ( appId ) => Object . keys ( packages . value ) . includes ( appId ) ) )
const showQuickStart = computed ( ( ) => ! allQuickStartAppsInstalled . value && ! quickStartDismissed . value )
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
function loadQuickStartState ( ) {
2026-03-21 03:01:38 +00:00
try { const raw = localStorage . getItem ( QUICK _START _KEY ) ; if ( ! raw ) { quickStartDismissed . value = false ; return } ; const data = JSON . parse ( raw ) ; if ( ! data . dismissed ) { quickStartDismissed . value = false ; return } ; const loginCount = ( data . loginCount || 0 ) + 1 ; localStorage . setItem ( QUICK _START _KEY , JSON . stringify ( { dismissed : true , loginCount } ) ) ; quickStartDismissed . value = loginCount % QUICK _START _RESHOW _LOGINS !== 0 } catch { quickStartDismissed . value = false }
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
}
2026-03-21 03:01:38 +00:00
function dismissQuickStart ( ) { quickStartDismissed . value = true ; try { localStorage . setItem ( QUICK _START _KEY , JSON . stringify ( { dismissed : true , loginCount : 0 } ) ) } catch { /* ignore */ } }
feat: complete AIUI integration — all 31 overnight tasks
- Protocol: 10 context categories (apps, system, network, bitcoin, media, files, notes, search, ai-local, wallet)
- ContextBroker: real data wiring for all categories with sanitization
- Permissions: user toggles for all categories in Settings
- Nginx: Claude API, OpenRouter, SearXNG proxy pass-through
- Actions: launch-app, search-web, install-app handlers
- Chat.vue: loading state + connection indicator
- Integration test page: test-aiui.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:34:02 +00:00
loadQuickStartState ( )
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
2026-03-11 13:04:31 +00:00
// Update notification
2026-03-21 03:01:38 +00:00
const updateAvailable = ref ( false ) ; const updateDismissed = ref ( false ) ; const updateVersion = ref ( '' ) ; const updateChangelog = ref ( '' )
2026-03-11 13:04:31 +00:00
async function checkUpdateStatus ( ) {
2026-03-21 03:01:38 +00:00
try { const res = await rpcClient . call < { update _available : boolean } > ( { method : 'update.status' } ) ; updateAvailable . value = res . update _available } catch { /* unavailable */ }
if ( updateAvailable . value ) { try { const detail = await rpcClient . call < { update : { version : string ; changelog : string [ ] } | null } > ( { method : 'update.check' } ) ; if ( detail . update ) { updateVersion . value = detail . update . version ; updateChangelog . value = detail . update . changelog . slice ( 0 , 2 ) . join ( '; ' ) } } catch { /* unavailable */ } }
2026-03-11 13:04:31 +00:00
}
2026-03-21 03:01:38 +00:00
async function dismissUpdate ( ) { updateDismissed . value = true ; try { await rpcClient . call ( { method : 'update.dismiss' } ) } catch { /* ignore */ } }
2026-03-11 13:04:31 +00:00
2026-03-05 07:05:14 +00:00
// Cloud data
2026-03-21 03:01:38 +00:00
const cloudStorageUsed = ref < number | null > ( null ) ; const cloudFolderCount = ref < number | null > ( null )
function formatBytes ( bytes : number ) : string { if ( bytes === 0 ) return '0 B' ; const units = [ 'B' , 'KB' , 'MB' , 'GB' , 'TB' ] ; const i = Math . floor ( Math . log ( bytes ) / Math . log ( 1024 ) ) ; const val = bytes / Math . pow ( 1024 , i ) ; return ` ${ val < 10 ? val . toFixed ( 1 ) : Math . round ( val ) } ${ units [ i ] } ` }
const cloudStorageDisplay = computed ( ( ) => cloudStorageUsed . value !== null ? formatBytes ( cloudStorageUsed . value ) : '...' )
const cloudFolderDisplay = computed ( ( ) => cloudFolderCount . value !== null ? String ( cloudFolderCount . value ) : '...' )
2026-03-05 07:05:14 +00:00
onMounted ( async ( ) => {
2026-03-21 03:01:38 +00:00
try { const usage = await fileBrowserClient . getUsage ( ) ; cloudStorageUsed . value = usage . totalSize ; cloudFolderCount . value = usage . folderCount } catch { /* not running */ }
loadSystemStats ( ) ; systemStatsInterval = setInterval ( loadSystemStats , 30000 ) ; checkUpdateStatus ( ) ; loadWeb5Status ( )
2026-04-07 15:23:17 +01:00
rpcClient . vpnStatus ( ) . then ( s => { vpnStatus . value = { connected : s . connected , provider : s . provider ? ? '' } } ) . catch ( ( ) => { } )
2026-04-19 00:42:56 -04:00
rpcClient . call < { installed : boolean ; service _active : boolean ; key _present : boolean } > ( { method : 'fips.status' } ) . then ( s => { fipsStatus . value = s } ) . catch ( ( ) => { } )
2026-03-05 07:05:14 +00:00
} )
2026-03-18 22:05:21 +00:00
// Wallet modals
2026-03-21 03:01:38 +00:00
const showSendModal = ref ( false ) ; const showReceiveModal = ref ( false ) ; const showTransactionsModal = ref ( false )
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
2026-03-21 03:01:38 +00:00
async function devFaucet ( ) { try { await rpcClient . call ( { method : 'dev.faucet' , params : { amount _sats : 1 _000 _000 } } ) ; await loadWeb5Status ( ) } catch { /* ignore */ } }
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
2026-03-21 03:01:38 +00:00
const walletConnected = ref ( false ) ; const walletOnchain = ref ( 0 ) ; const walletLightning = ref ( 0 ) ; const walletEcash = ref ( 0 )
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
const walletTransactions = ref < WalletTransaction [ ] > ( [ ] )
2026-03-21 03:01:38 +00:00
function openInMempool ( txHash : string ) { router . push ( { name : 'app-session' , params : { appId : 'mempool' } , query : { path : ` /tx/ ${ txHash } ` } } ) }
2026-03-11 13:04:31 +00:00
async function loadWeb5Status ( ) {
2026-03-21 03:01:38 +00:00
try { const res = await rpcClient . call < { balance _sats : number ; channel _balance _sats : number } > ( { method : 'lnd.getinfo' , timeout : 5000 } ) ; walletOnchain . value = res . balance _sats || 0 ; walletLightning . value = res . channel _balance _sats || 0 ; walletConnected . value = true } catch { walletConnected . value = false ; walletOnchain . value = 0 ; walletLightning . value = 0 }
try { const res = await rpcClient . call < { balance _sats : number } > ( { method : 'wallet.ecash-balance' , timeout : 5000 } ) ; walletEcash . value = res . balance _sats ? ? 0 } catch { walletEcash . value = 0 }
try { const res = await rpcClient . call < { transactions : WalletTransaction [ ] ; incoming _pending _count : number } > ( { method : 'lnd.gettransactions' , timeout : 5000 } ) ; walletTransactions . value = res . transactions || [ ] } catch { walletTransactions . value = [ ] }
2026-03-11 13:04:31 +00:00
}
2026-03-11 00:24:59 +00:00
// System stats
2026-03-11 13:04:31 +00:00
const systemStatsLoaded = ref ( false )
2026-03-21 03:01:38 +00:00
const systemStats = reactive ( { cpuPercent : 0 , memUsed : 0 , memTotal : 0 , memPercent : 0 , diskUsed : 0 , diskTotal : 0 , diskPercent : 0 , uptimeSecs : 0 , bitcoinSyncPercent : 0 , bitcoinBlockHeight : 0 , bitcoinAvailable : false } )
const systemUptimeDisplay = computed ( ( ) => { if ( systemStats . uptimeSecs === 0 ) return t ( 'home.systemMonitoring' ) ; const days = Math . floor ( systemStats . uptimeSecs / 86400 ) ; const hours = Math . floor ( ( systemStats . uptimeSecs % 86400 ) / 3600 ) ; if ( days > 0 ) return ` Uptime: ${ days } d ${ hours } h ` ; const mins = Math . floor ( ( systemStats . uptimeSecs % 3600 ) / 60 ) ; return ` Uptime: ${ hours } h ${ mins } m ` } )
2026-03-11 00:24:59 +00:00
let systemStatsInterval : ReturnType < typeof setInterval > | null = null
async function loadSystemStats ( ) {
2026-03-21 03:01:38 +00:00
try { const res = await rpcClient . call < { cpu _usage _percent : number ; mem _used _bytes : number ; mem _total _bytes : number ; disk _used _bytes : number ; disk _total _bytes : number ; uptime _secs : number } > ( { method : 'system.stats' } ) ; systemStats . cpuPercent = res . cpu _usage _percent ; systemStats . memUsed = res . mem _used _bytes ; systemStats . memTotal = res . mem _total _bytes ; systemStats . memPercent = res . mem _total _bytes > 0 ? ( res . mem _used _bytes / res . mem _total _bytes ) * 100 : 0 ; systemStats . diskUsed = res . disk _used _bytes ; systemStats . diskTotal = res . disk _total _bytes ; systemStats . diskPercent = res . disk _total _bytes > 0 ? ( res . disk _used _bytes / res . disk _total _bytes ) * 100 : 0 ; systemStats . uptimeSecs = res . uptime _secs ; systemStatsLoaded . value = true } catch { systemStatsLoaded . value = true }
2026-04-01 23:35:27 +01:00
try { const btc = await rpcClient . call < { block _height : number ; sync _progress : number } > ( { method : 'bitcoin.getinfo' , timeout : 5000 } ) ; systemStats . bitcoinSyncPercent = ( btc . sync _progress ? ? 0 ) * 100 ; systemStats . bitcoinBlockHeight = btc . block _height ? ? 0 ; systemStats . bitcoinAvailable = true } catch { /* RPC failed — check if container is at least running (loading/syncing) */ const btcPkg = packages . value [ 'bitcoin-knots' ] ; systemStats . bitcoinAvailable = btcPkg ? . state === PackageState . Running }
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
}
2026-03-21 03:01:38 +00:00
function uploadFiles ( ) { const pkg = packages . value [ 'filebrowser' ] ; if ( pkg && pkg . state === PackageState . Running ) { const host = window . location . hostname ; useAppLauncherStore ( ) . open ( { url : ` http:// ${ host } :8083 ` , title : 'File Browser' } ) } else { router . push ( '/dashboard/cloud' ) } }
2026-01-24 22:59:20 +00:00
< / script >
2026-02-17 19:19:54 +00:00
< style scoped >
2026-03-21 03:01:38 +00:00
. typing - caret : : after { content : '' ; display : inline - block ; width : 3 px ; height : 1.1 em ; background : # fbbf24 ; margin - left : 2 px ; vertical - align : text - bottom ; animation : caret - blink 0.7 s step - end infinite ; }
@ keyframes caret - blink { 0 % , 100 % { opacity : 1 ; } 50 % { opacity : 0 ; } }
2026-03-22 03:30:21 +00:00
< / style >
< style >
/* Home card styles — unscoped so they reach child components (HomeWalletCard, HomeSystemCard) */
2026-03-21 03:01:38 +00:00
. grid > . home - card { min - height : 280 px ; }
. home - card - shell { background - color : rgba ( 0 , 0 , 0 , 0.65 ) ; backdrop - filter : blur ( 18 px ) ; - webkit - backdrop - filter : blur ( 18 px ) ; border - radius : 1 rem ; overflow : hidden ; box - shadow : 0 8 px 24 px rgba ( 0 , 0 , 0 , 0.45 ) ; border : 1 px solid transparent ; height : 100 % ; }
. home - card - animate . home - card - shell { animation : card - fly - in 1.2 s cubic - bezier ( 0.25 , 0.46 , 0.45 , 0.94 ) forwards ; animation - delay : calc ( var ( -- card - stagger ) * 0.18 s ) ; opacity : 0 ; transform : translateY ( 50 px ) scale ( 0.92 ) ; }
@ keyframes card - fly - in { 0 % { opacity : 0 ; transform : translateY ( 50 px ) scale ( 0.92 ) ; border - color : transparent ; } 75 % { opacity : 1 ; transform : translateY ( 0 ) scale ( 1 ) ; border - color : transparent ; } 100 % { opacity : 1 ; transform : translateY ( 0 ) scale ( 1 ) ; border - color : rgba ( 255 , 255 , 255 , 0.18 ) ; } }
. home - card - inner { overflow : hidden ; opacity : 0 ; }
. home - card - animate . home - card - inner { animation : inner - draw 0.8 s cubic - bezier ( 0.25 , 0.46 , 0.45 , 0.94 ) forwards ; animation - delay : calc ( var ( -- card - stagger ) * 0.18 s + 0.9 s ) ; }
@ keyframes inner - draw { 0 % { opacity : 0 ; clip - path : inset ( 0 100 % 0 0 ) ; } 15 % { opacity : 1 ; } 100 % { opacity : 1 ; clip - path : inset ( 0 0 0 0 ) ; } }
. home - card - text { overflow : hidden ; }
. home - card - stats { overflow : hidden ; }
. home - card - btn { opacity : 0 ; transform : scale ( 0.5 ) ; border - color : transparent ; min - height : 44 px ; padding - top : 10 px ; padding - bottom : 10 px ; }
. home - card - animate . home - card - btn { animation : btn - pop 0.5 s cubic - bezier ( 0.34 , 1.56 , 0.64 , 1 ) forwards ; animation - delay : calc ( var ( -- card - stagger ) * 0.18 s + 1.5 s ) ; }
@ keyframes btn - pop { 0 % { opacity : 0 ; transform : scale ( 0.5 ) ; border - color : transparent ; } 85 % { opacity : 1 ; transform : scale ( 1 ) ; border - color : transparent ; } 100 % { opacity : 1 ; transform : scale ( 1 ) ; border - color : rgba ( 255 , 255 , 255 , 0.18 ) ; } }
. home - card : not ( . home - card - animate ) . home - card - inner , . home - card : not ( . home - card - animate ) . home - card - btn { opacity : 1 ; animation : none ; clip - path : none ; transform : none ; border - color : rgba ( 255 , 255 , 255 , 0.18 ) ; }
. home - card : not ( . home - card - animate ) . home - card - shell { border - color : rgba ( 255 , 255 , 255 , 0.18 ) ; }
2026-02-17 19:19:54 +00:00
< / style >