Commit Graph

19 Commits

Author SHA1 Message Date
Teknium
26fa3aa079 fix(desktop): Change only where Settings can switch; name the release only on an explicit not-ahead
Review on #136313 (Greptile):
- The overlay offered "Change" to a custom-branch checkout and to runtimes
  older than --set-channel, but Settings shows no selector for either, so
  the link landed nowhere. The label stays; the action is passed only when
  sourceUpdateChannel() allows a choice.
- An older checker omits aheadOfRelease yet may also pin an ahead checkout
  to its own HEAD, so a missing field read as "on the release". source_check
  now always sends the boolean, and the status line names the release only
  on an explicit false.
2026-10-10 16:05:48 -07:00
Teknium
573f514a19 feat(desktop): version details name the update channel; the overlay links to change it
The updates overlay (status-bar version click) showed no channel, so a
source install could not tell it was pinned to stable releases.

- VersionDetails (shared by About and the overlay) gains a Channel row for
  source checkouts: "Stable releases", "Every commit (main)", or
  "Branch: <name>". Packaged installs render no row; their channel is the
  package's.
- The overlay passes a "Change" link that closes the dialog and deep-links
  to Settings > About > Updates, where the selector and its confirm step
  live. The channel is not switchable from the overlay itself.
- Current on stable, the status line names the release ("You're on the
  latest stable release (v0.21.6)."). A forward-only checkout ahead of the
  release keeps the generic line: source_check now reports
  `aheadOfRelease`, since its pinned target is HEAD and would otherwise
  look identical to being on the release.
2026-10-10 16:05:48 -07:00
ethernet
9456670d2f Merge pull request #135743 from NousResearch/harder-linter-fixes-part3
Harder linter fixes part 3
2026-10-10 17:55:39 -04:00
Teknium
cb80675ab3 fix(update): stable lookup failures travel as exceptions and name the quota the failed request spent
Review on #136086 (Greptile):
- The failure no longer travels through a module dict. `_resolve_release`
  raises; `_resolve_stable` describes the exception; `resolve_source_release`
  stays the `(None, None)` wrapper for its other callers.
- A token GitHub rejects (401) retries anonymously; a 403 on that retry was
  described as the user's GITHUB_TOKEN quota. `_request` now marks the
  raised error with whether that request carried a token.
- The test server closes its listening socket and joins its thread.
2026-10-10 10:44:23 -07:00
Maciej Lisiewski
0006a5e229 ci: fix PLW1509, PLW1510, PLW2101 linter errors 2026-10-10 15:20:13 +02:00
Teknium
a7b2ba02e3 fix(desktop): channel selector only where it can save, shows the choice at once, and never calls a custom branch main
Review findings on #135949 (Greptile, @unsupportedpastels):

- An older runtime (v0.21.6) answers checks but rejects --set-channel, so the
  selector failed on every click. source_check now marks its reply
  `channelSelectable`; Desktop shows the row only when the install says so.
- The confirmed choice painted only after the forced check returned. The row
  now shows it at once, and a failure re-reads the install instead of guessing.
- A checkout following a custom branch rendered as "Every commit" (main). The
  row now appears only for stable, or for main itself.
2026-10-10 02:33:22 -07:00
Teknium
9287719a65 feat(desktop): About ▸ Updates picks stable releases or every commit for source installs 2026-10-10 02:33:22 -07:00
Teknium
6a92a2aa49 feat(update): source installs default to the stable release channel
`hermes update` and the Desktop update button on an official source
checkout now move between published vX.Y.Z releases instead of tracking
main commit by commit, and `hermes update --set-channel stable` works.

- stable resolves through R2 when a record exists; until one is published
  it falls back to the latest published GitHub release (non-draft,
  non-prerelease, strict vX.Y.Z, origin tag verified). It used to fail
  with "Channel object not found: releases/channels/stable.json".
- default_channel(): an official-origin source checkout defaults to
  stable; forks, mirrors and checkout-less trees keep main. Package
  installs (MSIX, Store, bundled, electron-updater) are untouched.
- An install that never chose a channel only moves forward: a checkout
  already newer than the latest release (every install that tracked main)
  stays put until a newer release ships. --set-channel stable is the
  explicit consent to land exactly on the release commit.
- Same rule in --check, the apply path and the passive source_check the
  Desktop and banner use.
2026-10-09 19:46:19 -07:00
Maciej Lisiewski
32b70e9733 ci: FURB188, FURB192 linter fixes 2026-10-09 17:31:52 +02:00
Austin Pickett
f6df13bac6 fix(update): keep never-pushed and unmerged branches pinned in source check
An empty ls-remote advertisement cannot tell "merged and deleted upstream"
from "never pushed". The source check now re-pins a missing branch to main
only when the local branch was once published (remote-tracking ref or a
configured upstream) and git cherry finds no commits missing from main.
Otherwise it keeps the branch and reports branch-local-only.

Diagnosis from #105053 by @0xalydev and #105055 by @kokhlo, which targeted
the Electron healer since moved into hermes_cli/source_check.py.

Fixes #105042
2026-09-28 21:02:35 -04:00
kshitijk4poor
064f2f6b09 fix(source-check): strip inherited pathspec modes from read-only git probes
GIT_LITERAL_PATHSPECS=1 turns disk-cleanup's ':(literal)' pathspec into filename text, so ls-files misses tracked files and the plugin deletes them.
2026-09-27 01:36:34 +05:30
ethernet
0cfd42e562 refactor(cli): split source_check.check_for_updates into cache, channel, fetch helpers
check_for_updates had grown to ~CC 75 over 128 lines, mixing install gating,
checkout probing, cache freshness, channel resolution, remote-tip fetch and
result shaping. It now reads as orchestration over cohesive helpers:
_unsupported_reason, _read_checkout (_Checkout facts), _cached_status /
_write_cache, _resolve_channel, _check_branch (_branch_remote,
_heal_deleted_branch, _behind_count). Every function is below CC 30
(check_for_updates 26).

Behaviour, public signature and return shape are unchanged; module-level
seams tests patch (_git_stdout, _git_ok, _branch_tip, resolve_source_target,
time, ...) are still read from this module at call time.
2026-09-24 11:50:30 -04:00
ethernet
97de4b4ef8 Merge origin/main into ethie/pm-clean
Conflict resolutions and semantic fixups:

- utils.py / hermes_yaml.py: main widened ruamel's round-trip emitter so a long
  double-quoted scalar is never folded after an escaped backslash. pm-clean builds
  every rt emitter through hermes_yaml.roundtrip_yaml(), so the width lives there
  (ROUNDTRIP_YAML_WIDTH moves with it); xai_retirement imports it from hermes_yaml.
- hermes_cli/banner.py: keep pm-clean's removal of the banner update check. Main's
  GIT_NO_LAZY_FETCH fix for it applies to its replacement, source_check: every
  read-only probe (source_git_env) now refuses promisor lazy fetches, and the
  partial-clone test targets that probe (red without the flag).
- .github/workflows/tests.yml: keep setup-pm; main's uv pin bump does not apply.
  Main's WAL-capable SQLite gates are kept, run against $HERMES_PYTHON (the
  PM-pinned interpreter, SQLite 3.53.1). The e2e step takes main's
  --include-integration invocation.
- apps/desktop: package.json has no build block here, so main's macOS locale-marker
  restore joins the darwin branch of the existing after-pack.mjs, and its test
  loads the hook from electron-builder.config.cjs and imports PlatformPackager
  from app-builder-lib's root (electron-builder 27 exports no ./out paths). The
  win32 row is dropped: this hook sanitizes and signs PE trees on win32 by design.
- reconciliation.ts: main's rowId hydration (#119326) was merged into the first of
  pm-clean's split helpers only; the resolver is now one helper both halves use.
- en.ts: both sides' keys kept. tests/tools/test_lazy_deps.py stays deleted.
- Tests main added with `import yaml` use hermes_yaml, like the rest of the tree.
2026-09-23 19:51:34 -04:00
ethernet
bb39409858 Merge branch 'rev/desktop-elec' into ethie/pm-clean 2026-09-21 19:52:58 -04:00
ethernet
6ba45b300c fix(update-check): authenticate api.github.com calls and name the branch-tip failure
The passive source check moved into hermes_cli/source_check.py during the
pm/ rewrite, and with it the GitHub calls left the desktop — but the four
main fixes that lived on the desktop side (gh-CLI token fallback
c61a11474b, anonymous retry e79ba2d7f2, rate-limit headers
c7d4d32800, failure copy 66a13703b3) did not follow. `_request` sent no
Authorization, so every client behind one NAT/VPN exit shared the anonymous
60/hour budget, and `_branch_tip` collapsed every failure into "Could not
resolve the remote branch tip." — a 403 rate limit read as a Hermes bug.

hermes_cli/github_api.py owns the credential ladder (GITHUB_TOKEN, GH_TOKEN,
`gh auth token` cached per process, anonymous; a 401 on a token retries
anonymously) and the failure copy (rate limit with reset time and the
GITHUB_TOKEN remedy, 5xx as GitHub trouble, else the status/transport
error). `_branch_tip` returns that reason and check_for_updates puts it in
the message.

apps/desktop/electron/github-api-auth.ts had no caller left (the desktop no
longer talks to api.github.com) — removed with its test; the behaviour now
lives where the request is made.
2026-09-21 18:56:56 -04:00
ethernet
6a6771e5e7 termux: stamp the deb as a self-contained runtime, not a bundled payload
build_deb.sh wrote HERMES_DESKTOP_VARIANT=bundled, so the Termux stamp
carried payload=bundled and every 'bundled' reader treated the tree as
the repo/ of an Electron payload. hermes uninstall --data then called
resolve_bundle_layout on it and rejected the plan: the deb has no
enclosing app to protect, so data-only removal was impossible on Termux.

Add a 'runtime' variant to write_install_stamp.py for a sealed CLI
runtime with no desktop app around it. It stays sealed for the update
gate and channel identity (source_check, update_channel accept it next
to bundled/light) while is_bundled_payload keeps answering False, so
cleanup planning protects the APT-owned package tree the ordinary way
and never asks where the app is.
2026-09-21 18:37:21 -04:00
ethernet
b37acb8389 feat(release): dynamic R2-owned channels and preview retirement (rounds 1-2)
Checkpoint before round-3 reduction (two-tier retirement derived from
product identity). Includes:

- R2 channel protocol (release_channels.py, channel-protocol.ts): records,
  builds, manifests, retired channels with pinned destinationHead and
  receiverProtocol; fail-closed readers in both languages
- One shared native manifest/feed writer (scripts/bundles/channel_artifacts.py)
- Scoped/disposable R2 publication, fork isolation before credential
  access, canary bootstrap verification of its own promoted outputs
- Channel source CLI: typed SourceTarget, source-channel resolution,
  retirement downgrade refusal
- Desktop channel resolver/strategy, install-stamp/build-stamp receiver
  ownership (stable-owned S/T candidates), single-flight updater operation
- Cross-package retirement machinery (receiver/host/preservation/
  compatibility/connections/dialog/discovery, backup_migration strict
  snapshots with retained-link inventory, empty-dir preservation,
  connection-collision resolution, URL-credential rejection)
- Native install harness (tests/install/channel-retirement-*) and
  install-e2e retirement jobs
- checkout-source.test.ts transport shim now covers build_opener().open
  (was silently hitting the real network in CI)

Removed secondary certification protocol (channel_qualification.py) per
approved round-2 plan. All focused suites green at checkpoint; native
cross-package journeys unverified (to be deleted in round 3).
2026-09-14 10:26:36 -04:00
ethernet
3a707117c5 fix(cli): accept BOM-prefixed catalog and runtime metadata 2026-09-13 18:21:59 -04:00
ethernet
cfebdfd466 Own passive source update checks in Python
Use the exact target root and profile for branch, release, and cache decisions. Keep the desktop as a transport and handoff adapter. Remove the competing TypeScript checker and switch the banner, dashboard, and updater count consumers.

Preserve fork origins, unknown counts, publication checks, old-probe recovery, and official SSH branch healing through public HTTPS. Keep the historical unstamped-root policy unchanged.
2026-09-12 19:03:26 -04:00