Compare commits

...
Author SHA1 Message Date
archipelago d4ea4ed636 chore: release v1.7.113-alpha 2026-07-25 14:41:59 -04:00
archipelagoandClaude Fable 5 0fadbb1d0f docs: sync What's New modal for v1.7.113-alpha
Demo images / Build & push demo images (push) Failing after 48s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:29:48 -04:00
archipelagoandClaude Fable 5 0e5cd24e18 style: rustfmt on lnd channels
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:25:10 -04:00
archipelagoandClaude Fable 5 1d8e57d564 docs: changelog for v1.7.113-alpha
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:12:41 -04:00
archipelagoandClaude Fable 5 00b7e1798f feat(lnd): closed-channels RPC, closing channels in list, streaming close with txid
- lnd.closedchannels: closed-channel history via /v1/channels/closed
- channel list now includes waiting-close and force-closing pending
  channels with their closing_txid
- closechannel reads the close stream's first update with a dedicated
  client instead of hanging until the closing tx confirms; returns the
  closing txid in display byte order

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:12:19 -04:00
archipelago bca1698682 Merge branch 'main' of http://146.59.87.168:3000/lfg2025/archy
Demo images / Build & push demo images (push) Successful in 3m2s
2026-07-25 10:47:41 -04:00
archipelagoandClaude Fable 5 0641ee85ef feat(wallet): total-bitcoin row at top of wallet card; on-chain gets a chain icon
The wallet card (Home + Web5 views) now leads with a Total Bitcoin row
summing all rails (on-chain + lightning + cashu + fedimint + ark), using
the orange ₿ mark. The on-chain row swaps ₿ for a link/chain icon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 10:44:08 -04:00
lfg2025 901cf5713a Merge pull request #123 from fips-companion-5g-hardening
Demo images / Build & push demo images (push) Successful in 3m5s
fix(fips): harden companion mesh joins
2026-07-24 17:52:56 +00:00
13 changed files with 276 additions and 93 deletions
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## v1.7.113-alpha (2026-07-25)
- Fixed a money bug in Cashu ecash sends: the token you handed a recipient could carry your own change proofs along with it, letting the same sats be credited twice. Change now stays in your wallet — only the amount you meant to send leaves it.
- Closing a Lightning channel is no longer a leap of faith. The close used to hang (or time out with an error) even though it had actually gone through; it now comes back within seconds with the closing transaction ID. Channels mid-close appear in the channel list as Closing or Force-closing with their transaction attached, and a new closed-channels history keeps past closes visible instead of letting them vanish from the list.
- The wallet card now leads with your total bitcoin across everything, and the on-chain balance gets its own chain icon so the rows read at a glance.
- The companion phone app (0.5.15) connects dramatically faster away from home: a cold connect over 5G dropped from 40+ seconds to about 5. First connects no longer stall on unreachable mesh dial hints, fresh joins fail fast and retry instead of waiting out long timeouts, and the phone re-announces itself the moment the network around it changes. The node side's mesh-join handling was hardened to match.
## v1.7.112-alpha (2026-07-23)
- Sound works on TVs out of the box. Fresh installs were missing the audio system entirely, and even when present a boot-time race left HDMI silent until the cable was unplugged and replugged. Both are fixed: installer images now ship the full audio stack, and a small background helper detects the silent-HDMI state and heals it automatically.
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "archipelago"
version = "1.7.112-alpha"
version = "1.7.113-alpha"
edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"]
@@ -124,6 +124,7 @@ impl RpcHandler {
}
"lnd.getinfo" => self.handle_lnd_getinfo().await,
"lnd.listchannels" => self.handle_lnd_listchannels().await,
"lnd.closedchannels" => self.handle_lnd_closedchannels().await,
"lnd.openchannel" => self.handle_lnd_openchannel(params).await,
"lnd.closechannel" => self.handle_lnd_closechannel(params).await,
"lnd.newaddress" => self.handle_lnd_newaddress().await,
+187 -35
View File
@@ -30,6 +30,8 @@ struct ChannelInfo {
active: bool,
status: String,
channel_point: String,
#[serde(skip_serializing_if = "String::is_empty")]
closing_txid: String,
}
#[derive(Debug, Serialize)]
@@ -58,6 +60,10 @@ struct LndChannel {
#[derive(Debug, Deserialize, Default)]
struct LndPendingChannelsResponse {
pending_open_channels: Option<Vec<LndPendingOpenChannel>>,
// Cooperative closes waiting for their closing tx to confirm
waiting_close_channels: Option<Vec<LndWaitingCloseChannel>>,
// Force closes serving out their timelock
pending_force_closing_channels: Option<Vec<LndForceClosingChannel>>,
}
#[derive(Debug, Deserialize)]
@@ -65,6 +71,18 @@ struct LndPendingOpenChannel {
channel: Option<LndPendingChannel>,
}
#[derive(Debug, Deserialize)]
struct LndWaitingCloseChannel {
channel: Option<LndPendingChannel>,
closing_txid: Option<String>,
}
#[derive(Debug, Deserialize)]
struct LndForceClosingChannel {
channel: Option<LndPendingChannel>,
closing_txid: Option<String>,
}
#[derive(Debug, Deserialize)]
struct LndPendingChannel {
remote_node_pub: Option<String>,
@@ -74,6 +92,52 @@ struct LndPendingChannel {
channel_point: Option<String>,
}
impl LndPendingChannel {
fn into_channel_info(self, status: &str, closing_txid: Option<String>) -> ChannelInfo {
let parse = |s: &Option<String>| s.as_deref().and_then(|v| v.parse().ok()).unwrap_or(0);
ChannelInfo {
chan_id: String::new(),
remote_pubkey: self.remote_node_pub.clone().unwrap_or_default(),
capacity: parse(&self.capacity),
local_balance: parse(&self.local_balance),
remote_balance: parse(&self.remote_balance),
active: false,
status: status.into(),
channel_point: self.channel_point.unwrap_or_default(),
closing_txid: closing_txid.unwrap_or_default(),
}
}
}
#[derive(Debug, Deserialize, Default)]
struct LndClosedChannelsResponse {
channels: Option<Vec<LndClosedChannel>>,
}
#[derive(Debug, Deserialize)]
struct LndClosedChannel {
chan_id: Option<String>,
remote_pubkey: Option<String>,
capacity: Option<String>,
settled_balance: Option<String>,
close_type: Option<String>,
closing_tx_hash: Option<String>,
channel_point: Option<String>,
close_height: Option<i64>,
}
#[derive(Debug, Serialize)]
struct ClosedChannelInfo {
chan_id: String,
remote_pubkey: String,
capacity: i64,
settled_balance: i64,
close_type: String,
closing_tx_hash: String,
channel_point: String,
close_height: i64,
}
impl RpcHandler {
pub(in crate::api::rpc) async fn handle_lnd_listchannels(&self) -> Result<serde_json::Value> {
let (client, macaroon_hex) = self.lnd_client().await?;
@@ -131,6 +195,7 @@ impl RpcHandler {
"inactive".into()
},
channel_point: ch.channel_point.unwrap_or_default(),
closing_txid: String::new(),
}
})
.collect();
@@ -138,31 +203,20 @@ impl RpcHandler {
let mut pending_channels: Vec<ChannelInfo> = Vec::new();
for pch in pending_resp.pending_open_channels.unwrap_or_default() {
if let Some(ch) = pch.channel {
let capacity: i64 = ch
.capacity
.as_deref()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
let local: i64 = ch
.local_balance
.as_deref()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
let remote: i64 = ch
.remote_balance
.as_deref()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
pending_channels.push(ChannelInfo {
chan_id: String::new(),
remote_pubkey: ch.remote_node_pub.unwrap_or_default(),
capacity,
local_balance: local,
remote_balance: remote,
active: false,
status: "pending_open".into(),
channel_point: ch.channel_point.unwrap_or_default(),
});
pending_channels.push(ch.into_channel_info("pending_open", None));
}
}
for wch in pending_resp.waiting_close_channels.unwrap_or_default() {
if let Some(ch) = wch.channel {
pending_channels.push(ch.into_channel_info("closing", wch.closing_txid));
}
}
for fch in pending_resp
.pending_force_closing_channels
.unwrap_or_default()
{
if let Some(ch) = fch.channel {
pending_channels.push(ch.into_channel_info("force_closing", fch.closing_txid));
}
}
@@ -349,6 +403,46 @@ impl RpcHandler {
Ok(body)
}
pub(in crate::api::rpc) async fn handle_lnd_closedchannels(&self) -> Result<serde_json::Value> {
let (client, macaroon_hex) = self.lnd_client().await?;
let resp: LndClosedChannelsResponse = client
.get(format!("{LND_REST_BASE_URL}/v1/channels/closed"))
.header("Grpc-Metadata-macaroon", &macaroon_hex)
.send()
.await
.context("LND REST connection failed")?
.json()
.await
.context("Failed to parse LND closed channels response")?;
let channels: Vec<ClosedChannelInfo> = resp
.channels
.unwrap_or_default()
.into_iter()
.map(|ch| ClosedChannelInfo {
chan_id: ch.chan_id.unwrap_or_default(),
remote_pubkey: ch.remote_pubkey.unwrap_or_default(),
capacity: ch
.capacity
.as_deref()
.and_then(|s| s.parse().ok())
.unwrap_or(0),
settled_balance: ch
.settled_balance
.as_deref()
.and_then(|s| s.parse().ok())
.unwrap_or(0),
close_type: ch.close_type.unwrap_or_default(),
closing_tx_hash: ch.closing_tx_hash.unwrap_or_default(),
channel_point: ch.channel_point.unwrap_or_default(),
close_height: ch.close_height.unwrap_or(0),
})
.collect();
Ok(serde_json::json!({ "channels": channels }))
}
pub(in crate::api::rpc) async fn handle_lnd_closechannel(
&self,
params: Option<serde_json::Value>,
@@ -389,27 +483,35 @@ impl RpcHandler {
"Closing Lightning channel"
);
let (client, macaroon_hex) = self.lnd_client().await?;
let (_, macaroon_hex) = self.lnd_client().await?;
// The close endpoint is server-streaming: LND holds the connection
// open and emits updates until the closing tx CONFIRMS on-chain
// (potentially hours). Reading the whole body hangs the RPC even
// though the close already went through, and the shared lnd_client's
// 15s total timeout would abort the stream mid-read. Use a dedicated
// client and return as soon as the first streamed update arrives.
let client = reqwest::Client::builder()
.no_proxy()
.connect_timeout(std::time::Duration::from_secs(10))
.danger_accept_invalid_certs(true)
.build()
.context("Failed to create streaming HTTP client")?;
let url = format!(
"{LND_REST_BASE_URL}/v1/channels/{}/{}?force={}",
parts[0], parts[1], force
);
let resp = client
let mut resp = client
.delete(&url)
.header("Grpc-Metadata-macaroon", &macaroon_hex)
.send()
.await
.context("Failed to close channel")?;
let status = resp.status();
let body: serde_json::Value = resp
.json()
.await
.context("Failed to parse close channel response")?;
if !status.is_success() {
if !resp.status().is_success() {
let body: serde_json::Value = resp.json().await.unwrap_or_default();
let msg = body
.get("message")
.and_then(|v| v.as_str())
@@ -417,6 +519,56 @@ impl RpcHandler {
return Err(anyhow::anyhow!("Failed to close channel: {}", msg));
}
Ok(serde_json::json!({ "success": true }))
// First streamed line is {"result":{"close_pending":…}} on success or
// {"error":…} — the stream reports errors in-band after a 200.
let mut buf: Vec<u8> = Vec::new();
let first_update = tokio::time::timeout(std::time::Duration::from_secs(25), async {
while let Some(chunk) = resp.chunk().await? {
buf.extend_from_slice(&chunk);
let line = match buf.iter().position(|&b| b == b'\n') {
Some(pos) => &buf[..pos],
None => &buf[..],
};
if let Ok(v) = serde_json::from_slice::<serde_json::Value>(line) {
return Ok::<_, anyhow::Error>(Some(v));
}
}
Ok(None)
})
.await;
match first_update {
Ok(Ok(Some(update))) => {
if let Some(err) = update.get("error") {
let msg = err
.get("message")
.and_then(|v| v.as_str())
.unwrap_or("Unknown error");
return Err(anyhow::anyhow!("Failed to close channel: {}", msg));
}
// txid arrives base64-encoded in internal byte order; flip it
// into the display order explorers use.
use base64::Engine as _;
let closing_txid = update
.pointer("/result/close_pending/txid")
.and_then(|v| v.as_str())
.and_then(|b64| base64::engine::general_purpose::STANDARD.decode(b64).ok())
.map(|mut bytes| {
bytes.reverse();
hex::encode(bytes)
})
.unwrap_or_default();
info!(channel_point, closing_txid, "Channel close initiated");
Ok(serde_json::json!({ "success": true, "closing_txid": closing_txid }))
}
Ok(Ok(None)) => Err(anyhow::anyhow!(
"LND ended the close stream without an update — check the channel list"
)),
Ok(Err(e)) => Err(e).context("Failed reading close channel response"),
// No update inside the window: the close is almost certainly still
// negotiating with the peer — report initiated, the channel list
// will show it under Closing.
Err(_) => Ok(serde_json::json!({ "success": true, "closing_txid": "" })),
}
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "neode-ui",
"version": "1.7.112-alpha",
"version": "1.7.113-alpha",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "neode-ui",
"version": "1.7.112-alpha",
"version": "1.7.113-alpha",
"dependencies": {
"@types/dompurify": "^3.0.5",
"@vue-leaflet/vue-leaflet": "^0.10.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "neode-ui",
"private": true,
"version": "1.7.112-alpha",
"version": "1.7.113-alpha",
"type": "module",
"scripts": {
"start": "./start-dev.sh",
+1
View File
@@ -415,6 +415,7 @@
"totalEarned": "Total Earned",
"monthlyAvg": "Monthly Avg",
"ecashBalance": "Ecash Balance",
"totalBitcoin": "Total Bitcoin",
"onChain": "On-chain",
"lightning": "Lightning",
"ecash": "Ecash",
+1
View File
@@ -413,6 +413,7 @@
"totalEarned": "Total ganado",
"monthlyAvg": "Promedio mensual",
"ecashBalance": "Saldo Ecash",
"totalBitcoin": "Bitcoin total",
"onChain": "On-chain",
"lightning": "Lightning",
"ecash": "Ecash",
+14 -1
View File
@@ -112,9 +112,18 @@
</transition>
<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">
<div class="flex items-center justify-between p-3 bg-white/10 rounded-lg">
<div class="flex items-center gap-3">
<span class="text-lg text-orange-500 font-bold">&#x20bf;</span>
<span class="text-sm font-medium text-white">{{ t('web5.totalBitcoin') }}</span>
</div>
<span class="text-white text-sm font-semibold">{{ walletTotal.toLocaleString() }} sats</span>
</div>
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
<div class="flex items-center gap-3">
<svg class="w-5 h-5 text-orange-500" role="img" aria-label="On-chain" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg>
<span class="text-sm text-white/80">{{ t('web5.onChain') }}</span>
</div>
<span class="text-orange-500 text-sm font-medium">{{ walletOnchain.toLocaleString() }} sats</span>
@@ -232,6 +241,10 @@ defineEmits<{
const showIncomingTxPanel = ref(false)
const walletTotal = computed(() =>
props.walletOnchain + props.walletLightning + props.walletEcash + props.walletFedimint + (props.walletArk ?? 0)
)
function isOnchain(tx: WalletTransaction): boolean {
return !tx.kind || tx.kind === 'onchain'
}
@@ -362,6 +362,19 @@ init()
</button>
</div>
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
<!-- v1.7.113-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.113-alpha</span>
<span class="text-xs text-white/40">July 25, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>Fixed a money bug in Cashu ecash sends: the token you handed a recipient could carry your own change proofs along with it, letting the same sats be credited twice. Change now stays in your wallet only the amount you meant to send leaves it.</p>
<p>Closing a Lightning channel is no longer a leap of faith. The close used to hang (or time out with an error) even though it had actually gone through; it now comes back within seconds with the closing transaction ID. Channels mid-close appear in the channel list as Closing or Force-closing with their transaction attached, and a new closed-channels history keeps past closes visible instead of letting them vanish from the list.</p>
<p>The wallet card now leads with your total bitcoin across everything, and the on-chain balance gets its own chain icon so the rows read at a glance.</p>
<p>The companion phone app (0.5.15) connects dramatically faster away from home: a cold connect over 5G dropped from 40+ seconds to about 5. First connects no longer stall on unreachable mesh dial hints, fresh joins fail fast and retry instead of waiting out long timeouts, and the phone re-announces itself the moment the network around it changes. The node side's mesh-join handling was hardened to match.</p>
</div>
</div>
<!-- v1.7.112-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
+12 -1
View File
@@ -95,10 +95,21 @@
<div v-if="walletError" class="alert-error mb-3">{{ walletError }}</div>
<div class="space-y-3 flex-1 min-h-0">
<!-- Total Balance -->
<div class="flex items-center justify-between p-3 bg-white/10 rounded-lg">
<div class="flex items-center gap-3">
<span class="text-lg text-orange-500 font-bold"></span>
<span class="text-white text-sm font-medium">{{ t('web5.totalBitcoin') }}</span>
</div>
<span class="text-white text-sm font-semibold">{{ (lndOnchainBalance + lndChannelBalance + ecashBalance).toLocaleString() }} sats</span>
</div>
<!-- On-chain Balance -->
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
<div class="flex items-center gap-3">
<span class="text-lg text-orange-500 font-bold"></span>
<svg class="w-5 h-5 text-orange-500" role="img" aria-label="On-chain" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg>
<span class="text-white/80 text-sm">{{ t('web5.onChain') }}</span>
</div>
<span class="text-orange-500 text-sm font-medium">{{ lndOnchainBalance.toLocaleString() }} sats</span>
+18 -26
View File
@@ -1,36 +1,28 @@
{
"version": "1.7.113-alpha",
"release_date": "2026-07-25",
"changelog": [
"Sound works on TVs out of the box. Fresh installs were missing the audio system entirely, and even when present a boot-time race left HDMI silent until the cable was unplugged and replugged. Both are fixed: installer images now ship the full audio stack, and a small background helper detects the silent-HDMI state and heals it automatically.",
"Plug in a game controller and drive the whole TV interface with it — navigation, menus, and media playback all respond to the gamepad, and dialogs that pop up are controller-navigable too.",
"The companion phone app took a huge leap (0.5.9). Your node and its apps now work from anywhere — on 5G or any internet connection, the phone reaches the node over the encrypted mesh with zero port forwarding or VPN setup. Startup away from home is instant, apps on your node open inside the app, the phone's native camera handles QR scanning, and a branded full-screen loader shows while the mesh connects.",
"Mesh Party: two phones scan each other's QR and instantly get a direct encrypted chat and app sharing between them — plus a \"Share this app\" QR that anyone can scan with a normal camera to install the companion app.",
"Pairing a second phone no longer silently logs out the first. Every device now keeps its own named access credential, ending the mystery reconnects when a household paired more than one phone.",
"The companion pairing QR is scannable again (it had grown too dense for phone cameras) and now identifies your node by its identity key, so the app recognizes your node even after it moves or gets a new address.",
"Every app your node serves on your home network is now also reachable over the mesh — remote access covers the apps themselves, not just the dashboard.",
"Selling files: you now choose which payment methods you accept (Lightning, ecash, …) and buyers are only offered those — enforced by the node itself, not just the buttons. Paying twice for the same file is impossible now, purchases file themselves into a new Paid Files tab, purchased music always plays in the bottom-bar player, and videos get picture-in-picture.",
"Sending Lightning is invoice-first: paste or scan an invoice and the amount fills in and locks by itself. An expired invoice now tells you plainly to ask for a fresh one instead of failing cryptically, and payment errors always reach your screen.",
"Sending to a pasted address gets a confirmation step showing exactly what will happen before any money moves, and buying ecash is an explicit two-step — no more accidental purchases."
"Fixed a money bug in Cashu ecash sends: the token you handed a recipient could carry your own change proofs along with it, letting the same sats be credited twice. Change now stays in your wallet \u2014 only the amount you meant to send leaves it.",
"Closing a Lightning channel is no longer a leap of faith. The close used to hang (or time out with an error) even though it had actually gone through; it now comes back within seconds with the closing transaction ID. Channels mid-close appear in the channel list as Closing or Force-closing with their transaction attached, and a new closed-channels history keeps past closes visible instead of letting them vanish from the list.",
"The wallet card now leads with your total bitcoin across everything, and the on-chain balance gets its own chain icon so the rows read at a glance.",
"The companion phone app (0.5.15) connects dramatically faster away from home: a cold connect over 5G dropped from 40+ seconds to about 5. First connects no longer stall on unreachable mesh dial hints, fresh joins fail fast and retry instead of waiting out long timeouts, and the phone re-announces itself the moment the network around it changes. The node side's mesh-join handling was hardened to match."
],
"components": [
{
"current_version": "1.7.112-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.112-alpha/archipelago",
"name": "archipelago",
"new_version": "1.7.112-alpha",
"sha256": "7cd7ab9dd9b433db929841328cbf553a056937f18814d0b7368b0a5c44dc2b9b",
"size_bytes": 51469560
"current_version": "1.7.113-alpha",
"new_version": "1.7.113-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.113-alpha/archipelago",
"sha256": "3027a33f6e98ddd87b7a37e852501c1e4323823174aa5e164f4d484e9221b201",
"size_bytes": 51560408
},
{
"current_version": "1.7.112-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.112-alpha/archipelago-frontend-1.7.112-alpha.tar.gz",
"name": "archipelago-frontend-1.7.112-alpha.tar.gz",
"new_version": "1.7.112-alpha",
"sha256": "02d916cadb54f76c19910376d6d42e820ee7b42fff7c1ea071bb5ec9b2bea3b8",
"size_bytes": 177952072
"name": "archipelago-frontend-1.7.113-alpha.tar.gz",
"current_version": "1.7.113-alpha",
"new_version": "1.7.113-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.113-alpha/archipelago-frontend-1.7.113-alpha.tar.gz",
"sha256": "f830d6d2180ac9fa9623fe5120f4591a53b18ae1f85cd17716517f783ead71cf",
"size_bytes": 177963652
}
],
"release_date": "2026-07-24",
"signature": "ffe1d1576e63c68f27dc6924f6db4381f745f48e1e279a9b20351c1104cf6e9a8756596cef99e8b3436925361bbbc9f305c14b0632e7c2f095b817783bbfa60d",
"signed_by": "did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur",
"version": "1.7.112-alpha"
]
}
+18 -26
View File
@@ -1,36 +1,28 @@
{
"version": "1.7.113-alpha",
"release_date": "2026-07-25",
"changelog": [
"Sound works on TVs out of the box. Fresh installs were missing the audio system entirely, and even when present a boot-time race left HDMI silent until the cable was unplugged and replugged. Both are fixed: installer images now ship the full audio stack, and a small background helper detects the silent-HDMI state and heals it automatically.",
"Plug in a game controller and drive the whole TV interface with it — navigation, menus, and media playback all respond to the gamepad, and dialogs that pop up are controller-navigable too.",
"The companion phone app took a huge leap (0.5.9). Your node and its apps now work from anywhere — on 5G or any internet connection, the phone reaches the node over the encrypted mesh with zero port forwarding or VPN setup. Startup away from home is instant, apps on your node open inside the app, the phone's native camera handles QR scanning, and a branded full-screen loader shows while the mesh connects.",
"Mesh Party: two phones scan each other's QR and instantly get a direct encrypted chat and app sharing between them — plus a \"Share this app\" QR that anyone can scan with a normal camera to install the companion app.",
"Pairing a second phone no longer silently logs out the first. Every device now keeps its own named access credential, ending the mystery reconnects when a household paired more than one phone.",
"The companion pairing QR is scannable again (it had grown too dense for phone cameras) and now identifies your node by its identity key, so the app recognizes your node even after it moves or gets a new address.",
"Every app your node serves on your home network is now also reachable over the mesh — remote access covers the apps themselves, not just the dashboard.",
"Selling files: you now choose which payment methods you accept (Lightning, ecash, …) and buyers are only offered those — enforced by the node itself, not just the buttons. Paying twice for the same file is impossible now, purchases file themselves into a new Paid Files tab, purchased music always plays in the bottom-bar player, and videos get picture-in-picture.",
"Sending Lightning is invoice-first: paste or scan an invoice and the amount fills in and locks by itself. An expired invoice now tells you plainly to ask for a fresh one instead of failing cryptically, and payment errors always reach your screen.",
"Sending to a pasted address gets a confirmation step showing exactly what will happen before any money moves, and buying ecash is an explicit two-step — no more accidental purchases."
"Fixed a money bug in Cashu ecash sends: the token you handed a recipient could carry your own change proofs along with it, letting the same sats be credited twice. Change now stays in your wallet \u2014 only the amount you meant to send leaves it.",
"Closing a Lightning channel is no longer a leap of faith. The close used to hang (or time out with an error) even though it had actually gone through; it now comes back within seconds with the closing transaction ID. Channels mid-close appear in the channel list as Closing or Force-closing with their transaction attached, and a new closed-channels history keeps past closes visible instead of letting them vanish from the list.",
"The wallet card now leads with your total bitcoin across everything, and the on-chain balance gets its own chain icon so the rows read at a glance.",
"The companion phone app (0.5.15) connects dramatically faster away from home: a cold connect over 5G dropped from 40+ seconds to about 5. First connects no longer stall on unreachable mesh dial hints, fresh joins fail fast and retry instead of waiting out long timeouts, and the phone re-announces itself the moment the network around it changes. The node side's mesh-join handling was hardened to match."
],
"components": [
{
"current_version": "1.7.112-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.112-alpha/archipelago",
"name": "archipelago",
"new_version": "1.7.112-alpha",
"sha256": "7cd7ab9dd9b433db929841328cbf553a056937f18814d0b7368b0a5c44dc2b9b",
"size_bytes": 51469560
"current_version": "1.7.113-alpha",
"new_version": "1.7.113-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.113-alpha/archipelago",
"sha256": "3027a33f6e98ddd87b7a37e852501c1e4323823174aa5e164f4d484e9221b201",
"size_bytes": 51560408
},
{
"current_version": "1.7.112-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.112-alpha/archipelago-frontend-1.7.112-alpha.tar.gz",
"name": "archipelago-frontend-1.7.112-alpha.tar.gz",
"new_version": "1.7.112-alpha",
"sha256": "02d916cadb54f76c19910376d6d42e820ee7b42fff7c1ea071bb5ec9b2bea3b8",
"size_bytes": 177952072
"name": "archipelago-frontend-1.7.113-alpha.tar.gz",
"current_version": "1.7.113-alpha",
"new_version": "1.7.113-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.113-alpha/archipelago-frontend-1.7.113-alpha.tar.gz",
"sha256": "f830d6d2180ac9fa9623fe5120f4591a53b18ae1f85cd17716517f783ead71cf",
"size_bytes": 177963652
}
],
"release_date": "2026-07-24",
"signature": "ffe1d1576e63c68f27dc6924f6db4381f745f48e1e279a9b20351c1104cf6e9a8756596cef99e8b3436925361bbbc9f305c14b0632e7c2f095b817783bbfa60d",
"signed_by": "did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur",
"version": "1.7.112-alpha"
]
}