Home / Input Output / daedalus
Apr 16, 7-8 AM (1)
Apr 16, 8-9 AM (1)
Apr 16, 9-10 AM (0)
Apr 16, 10-11 AM (0)
Apr 16, 11-12 PM (0)
Apr 16, 12-1 PM (0)
Apr 16, 1-2 PM (0)
Apr 16, 2-3 PM (0)
Apr 16, 3-4 PM (0)
Apr 16, 4-5 PM (0)
Apr 16, 5-6 PM (0)
Apr 16, 6-7 PM (1)
Apr 16, 7-8 PM (0)
Apr 16, 8-9 PM (0)
Apr 16, 9-10 PM (0)
Apr 16, 10-11 PM (0)
Apr 16, 11-12 AM (0)
Apr 17, 12-1 AM (1)
Apr 17, 1-2 AM (1)
Apr 17, 2-3 AM (0)
Apr 17, 3-4 AM (0)
Apr 17, 4-5 AM (0)
Apr 17, 5-6 AM (0)
Apr 17, 6-7 AM (0)
Apr 17, 7-8 AM (0)
Apr 17, 8-9 AM (0)
Apr 17, 9-10 AM (0)
Apr 17, 10-11 AM (0)
Apr 17, 11-12 PM (0)
Apr 17, 12-1 PM (0)
Apr 17, 1-2 PM (0)
Apr 17, 2-3 PM (0)
Apr 17, 3-4 PM (0)
Apr 17, 4-5 PM (0)
Apr 17, 5-6 PM (1)
Apr 17, 6-7 PM (0)
Apr 17, 7-8 PM (0)
Apr 17, 8-9 PM (0)
Apr 17, 9-10 PM (0)
Apr 17, 10-11 PM (0)
Apr 17, 11-12 AM (0)
Apr 18, 12-1 AM (0)
Apr 18, 1-2 AM (0)
Apr 18, 2-3 AM (1)
Apr 18, 3-4 AM (0)
Apr 18, 4-5 AM (0)
Apr 18, 5-6 AM (0)
Apr 18, 6-7 AM (0)
Apr 18, 7-8 AM (0)
Apr 18, 8-9 AM (0)
Apr 18, 9-10 AM (0)
Apr 18, 10-11 AM (0)
Apr 18, 11-12 PM (0)
Apr 18, 12-1 PM (0)
Apr 18, 1-2 PM (0)
Apr 18, 2-3 PM (0)
Apr 18, 3-4 PM (0)
Apr 18, 4-5 PM (0)
Apr 18, 5-6 PM (0)
Apr 18, 6-7 PM (0)
Apr 18, 7-8 PM (0)
Apr 18, 8-9 PM (1)
Apr 18, 9-10 PM (0)
Apr 18, 10-11 PM (0)
Apr 18, 11-12 AM (0)
Apr 19, 12-1 AM (0)
Apr 19, 1-2 AM (0)
Apr 19, 2-3 AM (0)
Apr 19, 3-4 AM (0)
Apr 19, 4-5 AM (0)
Apr 19, 5-6 AM (0)
Apr 19, 6-7 AM (0)
Apr 19, 7-8 AM (0)
Apr 19, 8-9 AM (0)
Apr 19, 9-10 AM (0)
Apr 19, 10-11 AM (0)
Apr 19, 11-12 PM (0)
Apr 19, 12-1 PM (0)
Apr 19, 1-2 PM (0)
Apr 19, 2-3 PM (0)
Apr 19, 3-4 PM (0)
Apr 19, 4-5 PM (0)
Apr 19, 5-6 PM (0)
Apr 19, 6-7 PM (0)
Apr 19, 7-8 PM (0)
Apr 19, 8-9 PM (0)
Apr 19, 9-10 PM (0)
Apr 19, 10-11 PM (0)
Apr 19, 11-12 AM (0)
Apr 20, 12-1 AM (0)
Apr 20, 1-2 AM (0)
Apr 20, 2-3 AM (0)
Apr 20, 3-4 AM (0)
Apr 20, 4-5 AM (0)
Apr 20, 5-6 AM (0)
Apr 20, 6-7 AM (0)
Apr 20, 7-8 AM (0)
Apr 20, 8-9 AM (0)
Apr 20, 9-10 AM (0)
Apr 20, 10-11 AM (0)
Apr 20, 11-12 PM (0)
Apr 20, 12-1 PM (5)
Apr 20, 1-2 PM (0)
Apr 20, 2-3 PM (5)
Apr 20, 3-4 PM (0)
Apr 20, 4-5 PM (3)
Apr 20, 5-6 PM (0)
Apr 20, 6-7 PM (0)
Apr 20, 7-8 PM (0)
Apr 20, 8-9 PM (0)
Apr 20, 9-10 PM (0)
Apr 20, 10-11 PM (0)
Apr 20, 11-12 AM (0)
Apr 21, 12-1 AM (0)
Apr 21, 1-2 AM (0)
Apr 21, 2-3 AM (0)
Apr 21, 3-4 AM (0)
Apr 21, 4-5 AM (0)
Apr 21, 5-6 AM (0)
Apr 21, 6-7 AM (0)
Apr 21, 7-8 AM (0)
Apr 21, 8-9 AM (0)
Apr 21, 9-10 AM (0)
Apr 21, 10-11 AM (0)
Apr 21, 11-12 PM (1)
Apr 21, 12-1 PM (1)
Apr 21, 1-2 PM (5)
Apr 21, 2-3 PM (3)
Apr 21, 3-4 PM (0)
Apr 21, 4-5 PM (2)
Apr 21, 5-6 PM (0)
Apr 21, 6-7 PM (3)
Apr 21, 7-8 PM (3)
Apr 21, 8-9 PM (0)
Apr 21, 9-10 PM (0)
Apr 21, 10-11 PM (0)
Apr 21, 11-12 AM (0)
Apr 22, 12-1 AM (0)
Apr 22, 1-2 AM (0)
Apr 22, 2-3 AM (0)
Apr 22, 3-4 AM (0)
Apr 22, 4-5 AM (0)
Apr 22, 5-6 AM (0)
Apr 22, 6-7 AM (0)
Apr 22, 7-8 AM (0)
Apr 22, 8-9 AM (0)
Apr 22, 9-10 AM (0)
Apr 22, 10-11 AM (0)
Apr 22, 11-12 PM (1)
Apr 22, 12-1 PM (0)
Apr 22, 1-2 PM (0)
Apr 22, 2-3 PM (0)
Apr 22, 3-4 PM (14)
Apr 22, 4-5 PM (0)
Apr 22, 5-6 PM (5)
Apr 22, 6-7 PM (0)
Apr 22, 7-8 PM (8)
Apr 22, 8-9 PM (0)
Apr 22, 9-10 PM (0)
Apr 22, 10-11 PM (4)
Apr 22, 11-12 AM (1)
Apr 23, 12-1 AM (0)
Apr 23, 1-2 AM (0)
Apr 23, 2-3 AM (0)
Apr 23, 3-4 AM (0)
Apr 23, 4-5 AM (0)
Apr 23, 5-6 AM (0)
Apr 23, 6-7 AM (0)
Apr 23, 7-8 AM (0)
72 commits this week Apr 16, 2026 - Apr 23, 2026
feat(updater): prefer darwin-arm installer on Apple Silicon hardware
Detect Apple Silicon via sysctl hw.optional.arm64 (returns 1 even when
running the x86_64 build under Rosetta 2) and expose isAppleSilicon on
the environment object.

In AppUpdateStore.getUpdateInfo, look up the 'darwin-arm' key first on
Apple Silicon hardware, falling back to 'darwin' if absent (e.g. when
only one macOS variant is present in the feed).

In News.ts, expand the platform filter to match both 'darwin' and
'darwin-arm' target entries on Apple Silicon, so update news items are
not incorrectly hidden.
feat(newsfeed): make newsfeed URLs build-time configurable
Replace hardcoded newsfeed.daedalus.io and newsfeed.daedaluswallet.io
with NEWS_URL / NEWS_HASH_URL webpack EnvironmentPlugin variables so
installers can be built pointing at a test server. Supports both http://
and https:// schemes; hostname, protocol, and port are parsed from the
full URL and forwarded to externalRequest.

fix(newsfeed): log error.message instead of raw Error object

fix(updater): log news fetch url on getNews error

fix(updater): respect pathname prefix in NEWS_URL and NEWS_HASH_URL

Extracting only hostname/protocol/port from NEWS_URL discarded any
path prefix (e.g. /daedalus/7.4). Export NEWS_PATH_PREFIX and
NEWS_HASH_PATH_PREFIX from urlsConfig and prepend them in getNews and
getNewsHash so URLs like https://cdn.example.com/daedalus/7.4 resolve
correctly to /daedalus/7.4/newsfeed/… and /daedalus/7.4/newsfeed-verification/….

feat(updater): add detailed debug logging to news fetch and update check flow

fix(updater): remove debug logging from news fetch and update store
feat(release-tool): add drt — Daedalus release CLI
Adds the drt (Daedalus Release Tool) Rust CLI, replacing the old
proposal-ui Haskell tool.

Commands:
  drt fetch-installers  — download unsigned installers from a Hydra eval
  drt sign              — GPG + macOS/Windows code signing via SSH hosts
  drt release           — hash, sign, upload to S3, push version JSON
  drt serve             — local HTTP mirror for end-to-end tester workflows
                          (generates newsfeed + verification files on the fly)

Nix:
  - Add crane + fenix flake inputs for Rust builds
  - Add perSystem/release-cli.nix (drt package + devShell + checks)
  - Add ops/ direnv environment for signing credentials

fix(drt/serve): bind IPv6 loopback alongside IPv4

Also bind [::1]:<port> so that `localhost` resolving to ::1 (common on
modern Linux/macOS) works without changing NEWS_URL to 127.0.0.1.
IPv6 bind is best-effort — silently skipped if unavailable.

refactor(drt): remove signing from release, add next-step hints

drt release no longer runs GPG signing — signing is a separate step
done via drt sign. Existing .asc files are still picked up and uploaded.

drt fetch-installers now hints: run drt sign
drt sign now hints: run drt release --bucket <bucket> --bucket-url <url>

fix(drt): skip -unsigned. installer files in all commands

fix(drt): split Darwin platform into DarwinArm/DarwinX86

Platform::Darwin was used for all .pkg files, causing aarch64-darwin
and x86_64-darwin installers to collide in HashMaps (last writer wins).

Split into DarwinArm (aarch64) and DarwinX86 (x86_64), with keys
darwin-arm and darwin in both version JSON and newsfeed output.
Platform detection now parses the full filename rather than just the
extension.

fix(drt/release): split bucket arg into bucket name + key prefix

Passing --bucket dripdropz-production/daedalus/7.4 used the full string
as the S3 bucket name, which contains slashes that are invalid in bucket
names. The AWS SDK then built a malformed canonical request, causing
SignatureDoesNotMatch errors.

Split --bucket on the first '/' into the actual bucket name and an
optional key prefix. All object keys (hash, filename, version JSON,
signatures) are stored under the prefix when one is present.

--bucket my-bucket              → bucket=my-bucket, prefix=
--bucket my-bucket/path/to/dir → bucket=my-bucket, prefix=path/to/dir

feat(drt/release): add --test flag to upload newsfeed stub to S3

Production newsfeeds are managed via GitHub; drt release should not
touch them. Add --test to opt in to uploading a generated newsfeed
stub and its SHA-256 verification file alongside the installers:

  newsfeed/newsfeed_<env>.json
  newsfeed-verification/<env>/<timestamp>.txt

Refactor serve::generate_local_newsfeed into a pub build_newsfeed
function that returns bytes + sha256 without touching the filesystem,
shared by both drt serve and drt release --test.

Add s3::upload_bytes for generic public-read byte uploads.

feat(drt/s3): skip upload if object already exists

Before uploading each installer (hash key + filename copy) or signature,
issue a HeadObject to check if the key is already present. If so, skip
the upload silently.

For hash-keyed objects the key IS the content hash, so existence implies
correct content — no re-download needed to verify.

This makes drt release idempotent: safe to re-run after a partial failure
without re-uploading multi-hundred-MB installer files.

feat(drt/fetch): retry downloads and skip already-verified files

Two improvements for unreliable Hydra connections:

- Retry: wraps each download in up to 5 attempts with exponential
  backoff (3 s, 6 s, 12 s, 24 s). Prints the error and delay before
  each retry so progress is visible.

- Resume: before downloading, checks if the destination file already
  exists and its SHA-256 matches the expected hash. If so, skips the
  download entirely. Re-running after a partial failure continues from
  where it left off rather than restarting from the beginning.

Also removes the unused human_size placeholder.

fix(drt/sign): skip already-signed files and resume partial signing

Add `unsigned_path()` and `is_already_code_signed()` to `Installer`.
In the signing loop, if the -unsigned companion exists and the signed
file is also present, skip (idempotent re-run). If the companion exists
but the signed file is missing (network error mid-SCP/pipe), fall
through and retry — macOS already skips the rename conditionally;
Windows now does the same.

fix(drt/release): simplify done output to version, json url, and installer urls

feat(drt/release): show newsfeed urls in done summary when --test is passed

fix(drt/release): remove duplicate path prefix in newsfeed summary urls

fix(drt/release): use exact timestamp and no-store cache-control for newsfeed uploads

Rounding updatedAt to the nearest hour meant re-runs within the same
hour overwrote the same verification file key in S3, but CloudFront
served the cached old hash causing a mismatch. Using actual milliseconds
gives each run a unique key. Add Cache-Control: no-store to both newsfeed
and verification uploads so CDN never serves stale copies.
feat(updater): prefer darwin-arm installer on Apple Silicon hardware
Detect Apple Silicon via sysctl hw.optional.arm64 (returns 1 even when
running the x86_64 build under Rosetta 2) and expose isAppleSilicon on
the environment object.

In AppUpdateStore.getUpdateInfo, look up the 'darwin-arm' key first on
Apple Silicon hardware, falling back to 'darwin' if absent (e.g. when
only one macOS variant is present in the feed).

In News.ts, expand the platform filter to match both 'darwin' and
'darwin-arm' target entries on Apple Silicon, so update news items are
not incorrectly hidden.
feat(newsfeed): make newsfeed URLs build-time configurable
Replace hardcoded newsfeed.daedalus.io and newsfeed.daedaluswallet.io
with NEWS_URL / NEWS_HASH_URL webpack EnvironmentPlugin variables so
installers can be built pointing at a test server. Supports both http://
and https:// schemes; hostname, protocol, and port are parsed from the
full URL and forwarded to externalRequest.

fix(newsfeed): log error.message instead of raw Error object

fix(updater): log news fetch url on getNews error

fix(updater): respect pathname prefix in NEWS_URL and NEWS_HASH_URL

Extracting only hostname/protocol/port from NEWS_URL discarded any
path prefix (e.g. /daedalus/7.4). Export NEWS_PATH_PREFIX and
NEWS_HASH_PATH_PREFIX from urlsConfig and prepend them in getNews and
getNewsHash so URLs like https://cdn.example.com/daedalus/7.4 resolve
correctly to /daedalus/7.4/newsfeed/… and /daedalus/7.4/newsfeed-verification/….

feat(updater): add detailed debug logging to news fetch and update check flow

fix(updater): remove debug logging from news fetch and update store
feat(release-tool): add drt — Daedalus release CLI
Adds the drt (Daedalus Release Tool) Rust CLI, replacing the old
proposal-ui Haskell tool.

Commands:
  drt fetch-installers  — download unsigned installers from a Hydra eval
  drt sign              — GPG + macOS/Windows code signing via SSH hosts
  drt release           — hash, sign, upload to S3, push version JSON
  drt serve             — local HTTP mirror for end-to-end tester workflows
                          (generates newsfeed + verification files on the fly)

Nix:
  - Add crane + fenix flake inputs for Rust builds
  - Add perSystem/release-cli.nix (drt package + devShell + checks)
  - Add ops/ direnv environment for signing credentials

fix(drt/serve): bind IPv6 loopback alongside IPv4

Also bind [::1]:<port> so that `localhost` resolving to ::1 (common on
modern Linux/macOS) works without changing NEWS_URL to 127.0.0.1.
IPv6 bind is best-effort — silently skipped if unavailable.

refactor(drt): remove signing from release, add next-step hints

drt release no longer runs GPG signing — signing is a separate step
done via drt sign. Existing .asc files are still picked up and uploaded.

drt fetch-installers now hints: run drt sign
drt sign now hints: run drt release --bucket <bucket> --bucket-url <url>

fix(drt): skip -unsigned. installer files in all commands

fix(drt): split Darwin platform into DarwinArm/DarwinX86

Platform::Darwin was used for all .pkg files, causing aarch64-darwin
and x86_64-darwin installers to collide in HashMaps (last writer wins).

Split into DarwinArm (aarch64) and DarwinX86 (x86_64), with keys
darwin-arm and darwin in both version JSON and newsfeed output.
Platform detection now parses the full filename rather than just the
extension.

fix(drt/release): split bucket arg into bucket name + key prefix

Passing --bucket dripdropz-production/daedalus/7.4 used the full string
as the S3 bucket name, which contains slashes that are invalid in bucket
names. The AWS SDK then built a malformed canonical request, causing
SignatureDoesNotMatch errors.

Split --bucket on the first '/' into the actual bucket name and an
optional key prefix. All object keys (hash, filename, version JSON,
signatures) are stored under the prefix when one is present.

--bucket my-bucket              → bucket=my-bucket, prefix=
--bucket my-bucket/path/to/dir → bucket=my-bucket, prefix=path/to/dir

feat(drt/release): add --test flag to upload newsfeed stub to S3

Production newsfeeds are managed via GitHub; drt release should not
touch them. Add --test to opt in to uploading a generated newsfeed
stub and its SHA-256 verification file alongside the installers:

  newsfeed/newsfeed_<env>.json
  newsfeed-verification/<env>/<timestamp>.txt

Refactor serve::generate_local_newsfeed into a pub build_newsfeed
function that returns bytes + sha256 without touching the filesystem,
shared by both drt serve and drt release --test.

Add s3::upload_bytes for generic public-read byte uploads.

feat(drt/s3): skip upload if object already exists

Before uploading each installer (hash key + filename copy) or signature,
issue a HeadObject to check if the key is already present. If so, skip
the upload silently.

For hash-keyed objects the key IS the content hash, so existence implies
correct content — no re-download needed to verify.

This makes drt release idempotent: safe to re-run after a partial failure
without re-uploading multi-hundred-MB installer files.

feat(drt/fetch): retry downloads and skip already-verified files

Two improvements for unreliable Hydra connections:

- Retry: wraps each download in up to 5 attempts with exponential
  backoff (3 s, 6 s, 12 s, 24 s). Prints the error and delay before
  each retry so progress is visible.

- Resume: before downloading, checks if the destination file already
  exists and its SHA-256 matches the expected hash. If so, skips the
  download entirely. Re-running after a partial failure continues from
  where it left off rather than restarting from the beginning.

Also removes the unused human_size placeholder.

fix(drt/sign): skip already-signed files and resume partial signing

Add `unsigned_path()` and `is_already_code_signed()` to `Installer`.
In the signing loop, if the -unsigned companion exists and the signed
file is also present, skip (idempotent re-run). If the companion exists
but the signed file is missing (network error mid-SCP/pipe), fall
through and retry — macOS already skips the rename conditionally;
Windows now does the same.

fix(drt/release): simplify done output to version, json url, and installer urls

feat(drt/release): show newsfeed urls in done summary when --test is passed

fix(drt/release): remove duplicate path prefix in newsfeed summary urls

fix(drt/release): use exact timestamp and no-store cache-control for newsfeed uploads

Rounding updatedAt to the nearest hour meant re-runs within the same
hour overwrote the same verification file key in S3, but CloudFront
served the cached old hash causing a mismatch. Using actual milliseconds
gives each run a unique key. Add Cache-Control: no-store to both newsfeed
and verification uploads so CDN never serves stale copies.
fix(updater): respect pathname prefix in NEWS_URL/NEWS_HASH_URL, improve error logging
Extract NEWS_PATH_PREFIX and NEWS_HASH_PATH_PREFIX from URL pathnames so
that a NEWS_URL like https://cdn.example.com/daedalus/7.3 resolves to the
correct newsfeed and verification paths instead of dropping the prefix.

Also export newsUrl from getNews for richer error logging, and log the
url, updatedAt, and hash values on fetch/verification failures.
feat(updater): prefer darwin-arm installer on Apple Silicon hardware
Detect Apple Silicon via sysctl hw.optional.arm64 (returns 1 even when
running the x86_64 build under Rosetta 2) and expose isAppleSilicon on
the environment object.

In AppUpdateStore.getUpdateInfo, look up the 'darwin-arm' key first on
Apple Silicon hardware, falling back to 'darwin' if absent (e.g. when
only one macOS variant is present in the feed).

In News.ts, expand the platform filter to match both 'darwin' and
'darwin-arm' target entries on Apple Silicon, so update news items are
not incorrectly hidden.
feat(newsfeed): make newsfeed URLs build-time configurable
Replace hardcoded newsfeed.daedalus.io and newsfeed.daedaluswallet.io
with NEWS_URL / NEWS_HASH_URL webpack EnvironmentPlugin variables so
installers can be built pointing at a test server. Supports both http://
and https:// schemes; hostname, protocol, and port are parsed from the
full URL and forwarded to externalRequest.
feat(release-tool): add drt — Daedalus release CLI
Adds the drt (Daedalus Release Tool) Rust CLI, replacing the old
proposal-ui Haskell tool.

Commands:
  drt fetch-installers  — download unsigned installers from a Hydra eval
  drt sign              — GPG + macOS/Windows code signing via SSH hosts
  drt release           — hash, sign, upload to S3, push version JSON
  drt serve             — local HTTP mirror for end-to-end tester workflows
                          (generates newsfeed + verification files on the fly)

Nix:
  - Add crane + fenix flake inputs for Rust builds
  - Add perSystem/release-cli.nix (drt package + devShell + checks)
  - Add ops/ direnv environment for signing credentials

fix(drt/serve): bind IPv6 loopback alongside IPv4

Also bind [::1]:<port> so that `localhost` resolving to ::1 (common on
modern Linux/macOS) works without changing NEWS_URL to 127.0.0.1.
IPv6 bind is best-effort — silently skipped if unavailable.

refactor(drt): remove signing from release, add next-step hints

drt release no longer runs GPG signing — signing is a separate step
done via drt sign. Existing .asc files are still picked up and uploaded.

drt fetch-installers now hints: run drt sign
drt sign now hints: run drt release --bucket <bucket> --bucket-url <url>

fix(drt): skip -unsigned. installer files in all commands

fix(drt): split Darwin platform into DarwinArm/DarwinX86

Platform::Darwin was used for all .pkg files, causing aarch64-darwin
and x86_64-darwin installers to collide in HashMaps (last writer wins).

Split into DarwinArm (aarch64) and DarwinX86 (x86_64), with keys
darwin-arm and darwin in both version JSON and newsfeed output.
Platform detection now parses the full filename rather than just the
extension.

fix(drt/release): split bucket arg into bucket name + key prefix

Passing --bucket dripdropz-production/daedalus/7.4 used the full string
as the S3 bucket name, which contains slashes that are invalid in bucket
names. The AWS SDK then built a malformed canonical request, causing
SignatureDoesNotMatch errors.

Split --bucket on the first '/' into the actual bucket name and an
optional key prefix. All object keys (hash, filename, version JSON,
signatures) are stored under the prefix when one is present.

--bucket my-bucket              → bucket=my-bucket, prefix=
--bucket my-bucket/path/to/dir → bucket=my-bucket, prefix=path/to/dir

feat(drt/release): add --test flag to upload newsfeed stub to S3

Production newsfeeds are managed via GitHub; drt release should not
touch them. Add --test to opt in to uploading a generated newsfeed
stub and its SHA-256 verification file alongside the installers:

  newsfeed/newsfeed_<env>.json
  newsfeed-verification/<env>/<timestamp>.txt

Refactor serve::generate_local_newsfeed into a pub build_newsfeed
function that returns bytes + sha256 without touching the filesystem,
shared by both drt serve and drt release --test.

Add s3::upload_bytes for generic public-read byte uploads.

feat(drt/s3): skip upload if object already exists

Before uploading each installer (hash key + filename copy) or signature,
issue a HeadObject to check if the key is already present. If so, skip
the upload silently.

For hash-keyed objects the key IS the content hash, so existence implies
correct content — no re-download needed to verify.

This makes drt release idempotent: safe to re-run after a partial failure
without re-uploading multi-hundred-MB installer files.

feat(drt/fetch): retry downloads and skip already-verified files

Two improvements for unreliable Hydra connections:

- Retry: wraps each download in up to 5 attempts with exponential
  backoff (3 s, 6 s, 12 s, 24 s). Prints the error and delay before
  each retry so progress is visible.

- Resume: before downloading, checks if the destination file already
  exists and its SHA-256 matches the expected hash. If so, skips the
  download entirely. Re-running after a partial failure continues from
  where it left off rather than restarting from the beginning.

Also removes the unused human_size placeholder.

fix(drt/sign): skip already-signed files and resume partial signing

Add `unsigned_path()` and `is_already_code_signed()` to `Installer`.
In the signing loop, if the -unsigned companion exists and the signed
file is also present, skip (idempotent re-run). If the companion exists
but the signed file is missing (network error mid-SCP/pipe), fall
through and retry — macOS already skips the rename conditionally;
Windows now does the same.
feat(updater): prefer darwin-arm installer on Apple Silicon hardware
Detect Apple Silicon via sysctl hw.optional.arm64 (returns 1 even when
running the x86_64 build under Rosetta 2) and expose isAppleSilicon on
the environment object.

In AppUpdateStore.getUpdateInfo, look up the 'darwin-arm' key first on
Apple Silicon hardware, falling back to 'darwin' if absent (e.g. when
only one macOS variant is present in the feed).

In News.ts, expand the platform filter to match both 'darwin' and
'darwin-arm' target entries on Apple Silicon, so update news items are
not incorrectly hidden.
feat(newsfeed): make newsfeed URLs build-time configurable
Replace hardcoded newsfeed.daedalus.io and newsfeed.daedaluswallet.io
with NEWS_URL / NEWS_HASH_URL webpack EnvironmentPlugin variables so
installers can be built pointing at a test server. Supports both http://
and https:// schemes; hostname, protocol, and port are parsed from the
full URL and forwarded to externalRequest.
feat(release-tool): add drt — Daedalus release CLI
Adds the drt (Daedalus Release Tool) Rust CLI, replacing the old
proposal-ui Haskell tool.

Commands:
  drt fetch-installers  — download unsigned installers from a Hydra eval
  drt sign              — GPG + macOS/Windows code signing via SSH hosts
  drt release           — hash, sign, upload to S3, push version JSON
  drt serve             — local HTTP mirror for end-to-end tester workflows
                          (generates newsfeed + verification files on the fly)

Nix:
  - Add crane + fenix flake inputs for Rust builds
  - Add perSystem/release-cli.nix (drt package + devShell + checks)
  - Add ops/ direnv environment for signing credentials

fix(drt/serve): bind IPv6 loopback alongside IPv4

Also bind [::1]:<port> so that `localhost` resolving to ::1 (common on
modern Linux/macOS) works without changing NEWS_URL to 127.0.0.1.
IPv6 bind is best-effort — silently skipped if unavailable.

refactor(drt): remove signing from release, add next-step hints

drt release no longer runs GPG signing — signing is a separate step
done via drt sign. Existing .asc files are still picked up and uploaded.

drt fetch-installers now hints: run drt sign
drt sign now hints: run drt release --bucket <bucket> --bucket-url <url>

fix(drt): skip -unsigned. installer files in all commands

fix(drt): split Darwin platform into DarwinArm/DarwinX86

Platform::Darwin was used for all .pkg files, causing aarch64-darwin
and x86_64-darwin installers to collide in HashMaps (last writer wins).

Split into DarwinArm (aarch64) and DarwinX86 (x86_64), with keys
darwin-arm and darwin in both version JSON and newsfeed output.
Platform detection now parses the full filename rather than just the
extension.

fix(drt/release): split bucket arg into bucket name + key prefix

Passing --bucket dripdropz-production/daedalus/7.4 used the full string
as the S3 bucket name, which contains slashes that are invalid in bucket
names. The AWS SDK then built a malformed canonical request, causing
SignatureDoesNotMatch errors.

Split --bucket on the first '/' into the actual bucket name and an
optional key prefix. All object keys (hash, filename, version JSON,
signatures) are stored under the prefix when one is present.

--bucket my-bucket              → bucket=my-bucket, prefix=
--bucket my-bucket/path/to/dir → bucket=my-bucket, prefix=path/to/dir

feat(drt/release): add --test flag to upload newsfeed stub to S3

Production newsfeeds are managed via GitHub; drt release should not
touch them. Add --test to opt in to uploading a generated newsfeed
stub and its SHA-256 verification file alongside the installers:

  newsfeed/newsfeed_<env>.json
  newsfeed-verification/<env>/<timestamp>.txt

Refactor serve::generate_local_newsfeed into a pub build_newsfeed
function that returns bytes + sha256 without touching the filesystem,
shared by both drt serve and drt release --test.

Add s3::upload_bytes for generic public-read byte uploads.

feat(drt/s3): skip upload if object already exists

Before uploading each installer (hash key + filename copy) or signature,
issue a HeadObject to check if the key is already present. If so, skip
the upload silently.

For hash-keyed objects the key IS the content hash, so existence implies
correct content — no re-download needed to verify.

This makes drt release idempotent: safe to re-run after a partial failure
without re-uploading multi-hundred-MB installer files.