Commit Graph

106 Commits

Author SHA1 Message Date
Teknium
51044e75e3 fix(update): the Rust installer honours HERMES_DATA_DIR_SUFFIX for the default home and marker root (review F13)
What: platform_default_home() appends HERMES_DATA_DIR_SUFFIX literally to the hermes/.hermes leaf via platform_default_home_with(suffix), which fixes hermes_home(), hermes_root() and the update marker together.
Why: Python (_get_platform_default_hermes_home) and Desktop (platformDefaultHermesHome) both append it, so a hermes-setup launched in a suffix-only channel environment read and wrote the unsuffixed home and marker.
Red: paths::tests::data_dir_suffix_names_the_default_home_and_its_marker_root on the 0ec53574011 resolution (byte-verbatim extract, suffix ignored): left '.hermes' right '.hermes-channel-build-x'.
Green: passes on the real fixed source extract; also cargo check clean for x86_64-pc-windows-msvc (Tauri crate itself cannot build on this host).
2026-10-06 04:36:02 -07:00
Teknium
fc7d24650d fix(update): an exited Windows owner with exit code 259 is dead, not running forever (review F10)
What: the Windows pid_is_alive opens the process with SYNCHRONIZE and returns WaitForSingleObject(h, 0) == WAIT_TIMEOUT; access denied still reads alive via liveness_from_open_error.
Why: GetExitCodeProcess == STILL_ACTIVE (259) is also what a process that exited with code 259 reports while any handle keeps its object, and its creation time still matches the v2 marker, so Busy had no age bound. Python's _early_recovery already uses the wait probe.
Red: Windows-only; marker_tests::pid_is_alive_false_for_an_exited_process_whose_exit_code_is_259 (cfg(windows)) needs a native runner.
Green: cargo check --tests --target x86_64-pc-windows-msvc clean on the real marker.rs (std-only harness); Linux marker tests 49 passed.
2026-10-06 04:36:02 -07:00
Teknium
e0cd07ee43 fix(update): tmp litter under our own reused pid number is reclaimed once stale (review PID-reuse-tmp-sweep)
What: the Python and Rust tmp sweeps reclaim a tmp sibling named for our own pid once its mtime is older than 60 s (OWN_PID_TMP_STALE[_SECONDS]); other pids keep the liveness check, and an ASCII pid past u32 is dead in both (Python had kept it since N06; Rust always swept it).
Why: with deterministic container pids a previous holder of our pid number left a tmp that every later run skipped as 'our own in-flight write', so it was never cleaned. Every write of ours finishes far inside 60 s, so a fresh same-pid tmp is still kept.
Red: test_stale_tmp_under_our_own_pid_number_is_reclaimed FAILED and marker_tests::stale_tmp_under_our_own_pid_number_is_swept FAILED on 07c014355b5 (real marker.rs via a std-only harness; the Tauri crate cannot build here without webkit2gtk/dbus).
Green: both pass; test_update_lock.py 59 passed/1 skipped; marker tests 49 passed/2 ignored.
2026-10-06 04:36:02 -07:00
Teknium
b2d3c7d3f0 fix(update): a completion child the job refused holds its own checkout lease (review R5b)
What: every Windows process that joins its ancestor's checkout lock also locks one of 16 lease bytes
past the owner's byte, taken while the owner is seen alive; _try_lock/checkout_lock_held and the Tauri
marker probe treat any held lease as a held lock. The refused completion child still runs (D2: a
committed update never fails) but is no longer unfenced.
Why: a child outside the kill-on-close job outlived a killed owner, whose msvcrt lock died with it,
so a contender acquired while the child still wrote.
Red/green: Windows-native cells (Python owner-killed/unbound child; Rust held lease) need a native run;
POSIX paths unchanged (update_lock suites pass, same failure set as base).
2026-10-06 04:36:02 -07:00
Teknium
3126c6eb34 fix(installer): reject POSIX marker PIDs that narrow to process groups 2026-10-06 04:36:02 -07:00
Teknium
7d257fb619 fix(update): the Tauri updater never reclaims a dead marker while the checkout lock is held (R6)
UpdateMarkerGuard::acquire now takes the install root. Under the marker mutex, a dead marker is
kept (never compare-and-deleted) while the install's checkout kernel lock is held, mirroring
hermes_cli/update_lock.py: checkout_lock_path (common git dir or <root>/.hermes-update.lock) and
checkout_lock_held (POSIX flock probe; Windows LockFileEx on the byte at 1<<20 that msvcrt locks).
The refusal is Busy with a held owner (pid 0), and busy_update_message says the owner exited but a
process it started still holds the checkout. should_heal_self_marker_refusal no longer heals an
exit 2 while the checkout lock is held.
2026-10-06 04:36:02 -07:00
Teknium
8c6e02c1ac fix(bootstrap-installer): marker liveness and overflow parity with Python (access denied = alive; corpus overflow cases)
Windows pid_is_alive treated every OpenProcess failure as dead, including
ERROR_ACCESS_DENIED for an elevated / other-user updater, while Python's
_early_recovery._pid_is_running calls it alive (racing an elevated updater is
worse than postponing). The decision is now the pure
liveness_from_open_error(GetLastError()): access denied = alive, any other
failure = dead. The creation-time probe still returns None for such a pid, so
the combined verdict equals _identity_live: live only within the v1 age
ceiling of started_at.

The new oversized-numeric corpus cases already pass in Rust (u32/u64 parse
failure = malformed, saturating age, +inf ct never matches); unit tests now pin
the started_at = u64::MAX age (0, no overflow) and the +inf ct explicitly.
2026-10-06 04:36:02 -07:00
Teknium
86afd649c3 fix(update): own-incarnation check never probes our own pid
Release now judges the marker by identity, and the identity check sent
os.kill(own_pid, 0) on every release. Our pid is alive by definition; only
the incarnation (5 ms ct) is in question. Same short-circuit in marker.rs.
2026-10-06 04:36:02 -07:00
Teknium
a66193a8c7 fix(update): A7 marker mutex, one incarnation rule, delegate-aware release, checkout custody
R3 / A7 rule 1: every marker decision-and-mutation (reclaim of a dead claim,
adopt + delegate append, release, ownership hand-over) now runs while holding
the kernel lock on the never-deleted sidecar `<marker>.lock` (POSIX flock;
Windows: the file opened share-none, the same lock the PowerShell hand-off
takes), bounded to 10 s. Only the exclusive first publish stays lock-free
(rule 2). Python (update_lock.marker_mutex) and Rust (marker.rs lock_marker)
interoperate on the same lock. A stale reader paused before its unlink can no
longer delete a claim published after its read.

A7 rule 4 / R12: one incarnation rule. Our own pid is ours only within 5 ms of
our creation time; a no-ct claim naming our pid is a previous incarnation
(dead) — in Python (`update_lock.incarnation_live`, exported for the pause
record) and in marker.rs (no more 2 s self tolerance; Electron's v1 own-pid
pre-write is reclaimed and republished as v2; the exit-2 heal requires our
exact incarnation).

A7 rule 5: release is identity-based (`_release_decision` / `release_decision`).
The owner removes its claim regardless of delegate lines unless a LIVE
delegate other than itself exists, which then inherits the claim (rewritten
with the delegate as owner, started_at and run lines kept). A delegate drops
its line while the owner lives, else deletes. This is the native Windows
`orphaned_update` root cause: the hand-off script named `hermes update` as
delegate before it claimed, the child adopted without writing, and its exit
released nothing, leaving '<dead owner> ... delegate:<exited child>'.

Parser (A7 rule 7): lines 4+ are tagged — first well-formed delegate line,
every `run:<id>` line; pid must fit u32. Both consumers run
tests/fixtures/update_marker_corpus.json (judge + release cases).

R2: checkout mutators keep custody. `_git_run` passes the held checkout lock
fd to git (and its hooks); `run_source_script` passes it to the Node build;
`complete_source_checkout` ACQUIRES `UpdateLock(install_root=root)` instead of
claiming only its home's marker; venv_sync's interrupted-update finish acquires
the checkout lock before mutating instead of sampling it and hands the fd to
its completion child; the historical takeover chain passes it down. On Windows
a child of the update joins the lock when its holder record names a live
ancestor (it runs in that owner's kill-on-close job).

R11: a live pre-root-marker claim under <root>/profiles/*/ (the old per-profile
marker) is observed: a new update refuses while one is live and not a partner.

Real-process tests: tests/hermes_cli/test_update_lock_protocol.py (each fails on
6ff4055cd74), corpus consumers in Python and cargo.
2026-10-06 04:36:02 -07:00
Teknium
0a8e2f950a fix(bootstrap-installer): marker claim, parse and liveness follow the LP-LOCK r2 contract
The Rust updater now applies the same marker rules as hermes_cli/update_lock.py:

- A2 parse: one BOM and one trailing CR per line are dropped, spaces/tabs
  trimmed; lines 1-2 must be ASCII digits (fractional/garbage => malformed,
  dead, compare-and-deleted); line 3 is `ct:` or a v1 marker; only line 4
  can be `delegate:<pid> ct:<ct>`.
- A1 liveness: a live pid whose creation time cannot be read gets the v1
  20-minute ceiling instead of an unbounded pass. The ct probe is injected
  so the rule is unit-testable.
- A3 claim: the body is written and fsynced in a `<marker>.<pid>.<n>.tmp`
  sibling and published with an exclusive hard link (fallback: create_new);
  a 0-byte marker younger than 5 s is a claim in flight (live, never deleted).
- M1: an own-pid v1 pre-write (Electron) is CAS-upgraded to v2 with our
  creation time, lines 1-2 byte-identical, and released by complete().
- m8: a marker that cannot be written refuses the update with a clear
  message instead of running unclaimed (AcquireError::{Busy, Unwritable}).
- m10: dead claimants' tmp siblings are swept at claim time.
2026-10-06 04:36:02 -07:00
Teknium
dfb33c107c refactor(bootstrap-installer): move the update marker into marker.rs
Pure move of UpdateMarkerGuard, the marker parse/liveness/compare-and-delete
helpers, the exit-2 self-heal decision and their tests out of update.rs
(2514 lines) into a new marker module. No behaviour change; update.rs now
imports the guard and the heal decision from crate::marker.
2026-10-06 04:36:02 -07:00
Teknium
e267537a75 fix(bootstrap-installer): update marker v2 — root home, creation-time liveness, atomic claim
UpdateMarkerGuard now implements update-marker contract C1:
- marker lives under the profile-tree root (paths::hermes_root), never profiles/<p>
- body pid / started_at / ct:<creation time>; GetProcessTimes on Windows,
  /proc stat on Linux, proc_pidinfo on macOS
- an owner is live iff its pid is alive and its creation time matches (2.0 s);
  no age ceiling for v2 markers, the 20-min ceiling only ages out v1 markers
- claim is create_new + sync_all with one compare-and-delete reclaim of a dead owner
- every delete is compare-and-delete; a live line-4 delegate keeps the marker live

Why: a 20-min ceiling reclaimed live owners mid-update, a reused Windows pid held
the gate, and read-then-write claims let two updaters run at once.
2026-10-06 04:36:02 -07:00
ethernet
383916b845 feat(icons): layered macOS 26 icon for the bootstrap installer and the DMGs
Tauri's bundler (cli 2.11.4) compiles an Icon Composer package listed in
bundle.icon into Assets.car with actool >= 26 and sets CFBundleIconName, so
the bootstrap installer gets an unbranded twin of the desktop package under
src-tauri/icons/icon.icon (generator target; the bundle stays the plain
brand because flavours only apply under apps/desktop/). Tauri only logs when
actool is too old, so the macOS job selects Xcode 26 and the verify step
asserts Assets.car and the plist key are in the built .app.

The desktop DMG's volume icon defaulted to the packager's icns, which is
actool's 256px fallback whenever mac.icon is the .icon package; point
dmg.icon at the full-resolution assets/icon.icns. Tauri's DMG already takes
--volicon from the bundle's .icns, which the regenerated outputs cover.
2026-10-02 10:33:44 -04:00
ethernet
c2b69de66d feat(icons): drop the brand ring everywhere and frost the mono icon
Next to macOS 26's own icons the flat plate + girl reads better than the
ringed tile, so the ring is off in every output: the tiles' inward stroke,
the layered icon's border layer and its targets. BORDER_ENABLED keeps the
ring code one flag away.

Without a ring the girl's lowest nodes are dragged past the tile edge
(EDGE_OVERSHOOT) so the outline crops her instead of leaving a gap.

Clear light/dark and Tinted light/dark now come from one grayscale mono
layer with Liquid Glass on: the parts of the girl that are black in light
mode become a near-black frosted ink (0.13 @ 90%), her white parts stay
white, each pixel painted exactly once so materials never stack. The art
layer hides under "tinted" and the mono layer shows only there.

Mac girl at 1.06x (between main's 1.12x and the layers' 1.0x), for the icns
and the layered icon alike. Chosen from a six-appearance matrix of real
IconServices renders next to Finder.
2026-10-02 10:33:44 -04:00
Brooklyn Nicholson
0590ab25fe fix(marker): zombie-aware stale-marker self-heal parity across all readers
Rust live_marker_owner now REMOVES a stale marker (dead pid, past ceiling,
unparseable) on read — previously stale bytes were only ignored, so a crashed
updater whose Drop never ran refused every later acquire until the 20-minute
ceiling (#77259). pid_is_alive gains pid-0 and zombie handling (Linux /proc
state, macOS ps stat), closing the kill(pid,0) false-positive that kept a
dead-but-unreaped updater 'live'.

Python _pid_is_running gains the same zombie awareness via a new
_process_state probe (Linux /proc, macOS ps), which read_live_update inherits
through update_lock._pid_alive — so the CLI gate self-heals a zombie-owned
marker in seconds instead of 20 minutes (#120635, #125932).

Electron readLiveUpdateMarker consults a new posixProcessState probe
(injectable, fail-open to the signal-0 verdict) so the desktop boot gate no
longer parks on a zombie-owned marker.

Rust fix cherry-picked from #77885 (authorship kept); Python and Electron
are new parity work.
2026-09-29 20:57:17 -05:00
webtecnica
0ca79e3602 fix(installer): self-heal stale update marker after crash (#77259) 2026-09-29 20:57:17 -05:00
teknium1
07be7d47ed fix(bootstrap-installer): write the shared receipt schema and resolve the commit without git
Hermes-Setup.exe replaced install.ps1's .hermes-bootstrap-complete with its
own copy: completedAtUnix instead of the completedAt every other writer and
reader uses (install.ps1, Electron main, hermes_cli/source_stamp.py,
scripts/verify-bootstrap-version-stamp.py), and a pinnedCommit from a bare
`git rev-parse HEAD`, which is null on a machine where git exists only as
the PM-staged binary install.ps1 uses.

The receipt now carries completedAt (UTC ISO-8601, milliseconds), and the
commit resolves like install.ps1's Stage-Complete: the pinned commit, else
the checkout HEAD read from its ref files (loose ref or packed-refs), else
the full sha install.ps1 already recorded (read BOM-tolerant).

Fixes #124949
2026-09-27 03:35:26 -07:00
Hermes Agent
5ef8d96554 fix(bootstrap-installer): resolve linux-arm64-unpacked desktop builds (#94703)
resolve_hermes_desktop_exe and the update lock probe only knew the x64
linux-unpacked dir, so on ARM64 Linux the bootstrap installer could not
find the rebuilt app to relaunch and did not wait for the running app's
app.asar before an update. Add linux-arm64-unpacked to both lists.
2026-09-26 20:29:47 -05:00
Hermes Agent
c8094dc399 fix(icons): put the dev Dock icon on the mac grid and enlarge the mac art
Dev runs replace the Dock icon with public/apple-touch-icon.png, which the
generator rendered full-bleed, so it drew ~24% larger than its Dock
neighbors. Render it from the mac-grid master like the icns targets.

On the 824 grid the plate matches peers, but the girl inside a white tile
with a ring read small; scale her 1.12x about the plate center for every
mac target.
2026-09-26 18:10:54 -05:00
brooklyn!
e726b79803 fix(desktop): stop macOS launch from showing two Dock icons
The setup launcher had no LSUIElement, and its already-installed hand-off
ran after Tauri/AppKit, whose default activation policy is Regular. That
registered the setup bundle as a second Dock app beside the real desktop.
Hand off before constructing Tauri, and restore Regular activation only
when the installer UI is actually shown.

On macOS the Electron single-instance lock also ran before deep-link
registration. setAsDefaultProtocolClient relaunches the app through Launch
Services, so the loser already had a Dock icon by the time the lock failed
and app.exit(0) ran. Register the protocol first. The lock-losing instance
still hard-exits before ready.

Fixes #73151
2026-09-25 01:01:42 -05:00
ethernet
7b11c1bcac Merge pull request #122025 from NousResearch/fix/bootstrap-no-stale-script
fix(bootstrap-installer): never use a cached install script
2026-09-24 23:50:11 -04:00
ethernet
274b412aa7 fix(bootstrap-installer): never reuse a downloaded install script
Every bootstrap downloads the script fresh, commit pins included; the
on-disk file is only the -File target for this run. Removes the reuse
path, ScriptSource::Cached and the in-place BOM upgrade of old caches.
2026-09-24 19:28:21 -04:00
ethernet
0e7d560d6b fix(bootstrap-installer): never run a stale install script for a branch pin
A 429 from raw.githubusercontent.com made the installer fall back to a
cached pre-migration install-main.ps1. Its repository stage then
fast-forwarded the checkout to live main, whose lock only supports
Python >=3.14, so the old script's 3.11 venv got no core dependencies
and every install died at 'Baseline imports failed'.

The checkout follows the live branch, so the script must too: a failed
refresh of a mutable pin is now fatal (Retry re-downloads). Immutable
commit pins keep permanent cache reuse.
2026-09-24 19:26:32 -04:00
ethernet
4b7229d612 fix(icons): commit generated icons; installs and regular builds never render
User installs failed with 'resvg-py is missing' because the web/desktop
source builds rendered icons on whatever python was on PATH. The default
brand outputs are now committed; source_build, apps/desktop build.mjs and
the npm/docusaurus pre-hooks consume them directly. Flavored release
bundles (canary/commit) still render into their own product dir.

icons-freshness-check now regenerates and fails on any byte diff.
2026-09-24 19:17:34 -04:00
ethernet
7dd4d7556c test(installer): drop retired Windows venv path assertions 2026-09-24 05:10:06 -04:00
ethernet
ca06a8dec9 Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts:
#	apps/bootstrap-installer/src-tauri/src/update.rs
2026-09-24 05:03:23 -04:00
brooklyn!
edecebf69d fix(bootstrap): show the update child's exit-2 refusal instead of "still running"
Every exit 2 from `hermes update` was reported as "Hermes is still
running. Close all Hermes windows", including when the holder was another
live update. The child prints the specific refusal as a ✗ block right
before exiting; keep a bounded stdout tail and show that block, falling
back to the generic text only when none was captured.

Co-authored-by: RelaxJonh <92573950+RelaxJonh@users.noreply.github.com>
2026-09-24 03:49:06 -05:00
ethernet
9cc319f9a1 feat(version): main carries 0.0.0 and dev distance counts from release tags
The committed version is a placeholder now; a build stamps the real one.
Dev installs report their distance from the highest reachable release tag,
so an -rc claim sitting on the same commit never becomes the version.
2026-09-21 20:41:59 -04:00
ethernet
d87d134564 chore: bump version to v1.0.0 (2026.9.21) 2026-09-21 13:15:16 -04:00
ethernet
7bc32b575f chore: bump version to v0.22.2 (2026.9.21) 2026-09-21 13:09:52 -04:00
ethernet
dcd40f61a4 chore: bump version to v0.22.1 (2026.9.21) 2026-09-21 13:09:36 -04:00
ethernet
483b46f7e3 chore: bump version to v0.22.0 (2026.9.21) 2026-09-21 13:08:31 -04:00
ethernet
b4a294fff9 Merge origin/main; keep PM as plugin dependency owner
Reconcile plugin declarations and validation through PM's atomic generation publication; preserve external runtimes, target markers, and conflict refusal. Keep one source-update completion owner and port upstream lifecycle changes to the PM desktop/runtime paths.
2026-09-17 13:52:05 -04:00
teknium1
1503d40aba fix(desktop): strip installer escapes from the manifest-failure banner too
Only Log lines were sanitized at the emitter; the manifest-step error string
was still built from the raw child stderr/stdout tail, so a failing
`install.sh --manifest` (print_error writes `${RED}✗${NC}`) put escape bytes
straight into the Setup failure banner. Run stripAnsi / strip_ansi over the
embedded tail on both the Electron and the Tauri bootstrap surfaces (#112675).
2026-09-16 17:50:47 -07:00
teknium1
22b576999f test(installer): fold the strip_ansi cases into one invariant table
Seven near-identical #[test] fns become one table test over the same inputs
(SGR banners, cursor/erase/private modes, OSC with BEL and ST, \r redraws,
sequences cut by the pipe, plain multi-byte text) plus the existing
sanitized_for_ui_only_touches_log_lines. Same coverage, two tests: the
salvage bar is ≤2 invariant tests per fix.

Verified with the function and tests extracted into a standalone
`rustc --test` binary (cargo test on this host fails in libdbus-sys, a
missing system header unrelated to this crate's code).
2026-09-16 17:50:47 -07:00
liuhao1024
74466f03cd fix(installer): strip ANSI escapes from live log events
The macOS setup app drives a shell install script whose output carries
SGR styling, cursor movement, and OSC title commands; the Live output
pane renders log lines as plain text, so those bytes showed up as
mojibake (#112675).

Strip escape sequences at the Rust-to-webview event boundary (bootstrap
and update flows) and collapse carriage-return redraws to the last
visible frame. The on-disk tee keeps the raw bytes for terminal viewing.

Fixes #112675
2026-09-16 17:50:47 -07:00
teknium1
18a14cec0c test(bootstrap-installer): keep two stdio-inheritance invariants, cite #112856
Trim the Windows-only re-exec matrix from four tests to two: one per
launch builder (std = launcher fast path, tokio = `--update` handoff),
each paired with a different captured stream. stdout and stderr flow
through the same handle-inheritance path (GetStdHandle +
SetHandleInformation on the installer side, Stdio::null() on the child),
so the 2x2 product added runtime without adding a distinct invariant.

Also replace the "(issue TBD)" placeholder on open_macos_app_detached
with the issue number.
2026-09-16 16:56:02 -07:00
Sora-bluesky
555ffa3cb5 fix(bootstrap-installer): launched Desktop no longer holds the installer's stdout/stderr pipe
`hermes-setup.exe --update` hands off to the rebuilt Desktop right before it
exits. On Windows, CreateProcess duplicates every inheritable handle of the
installer into the Desktop, and the installer's stdout/stderr are inheritable
pipe handles whenever a shell captures its output. The Desktop therefore held
the pipe's write end and the shell kept waiting until the Desktop exited, even
though the update had succeeded (Windows 11, 2026-09-05: still waiting after
18 minutes, while `> file` returned normally). DETACHED_PROCESS detaches the
console only; Rust's std::process passes bInheritHandles=TRUE and has no
handle list (rust-lang/rust#54760), and setting the child's own stdio to null
does not change which stray handles it inherits (measured: same 4 s stall).

Right before the handoff, clear HANDLE_FLAG_INHERIT on the installer's own
std handles (GetStdHandle + SetHandleInformation, best effort, skipping
missing handles of a GUI-launched installer), through one spawn helper used
by both launch sites; the Desktop's stdio is nulled as well so it never uses
the installer's handles at all. The installer's tracing goes to a file, so
nothing is lost. macOS `open` branches get the same nulling for consistency.

Tests (Windows-only; the crate's CI lane runs on Ubuntu): the test binary
re-executes itself as a helper that launches a 4 s sleeper grandchild through
each real builder and the shared spawn helper; the parent asserts the helper's
piped stdout, and separately stderr, reaches EOF in under 2 s and that the
helper's sentinel line arrived. Without the fix all four cases stall ~4 s;
with it, EOF arrives when the helper exits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:56:02 -07:00
ethernet
5e4a2a3d24 refactor(pm): remove legacy dependency and launch managers
Competing installers and checkout-local venv assumptions bypassed PM
selection, install consent, and generation lifetimes. Route consumers
through PM and installation-bound launchers. Refresh source launchers
before obsolete Python entries can be collected.

Remove Node, browser, and CUA acquisition engines, obsolete venv-holder
handling, detached sync, and unused PM APIs. Keep historical updater
exports inert and preserve external tool ownership and native integration.

Share product freshness and prepared inputs across builders. Align plugin
admission, Docker provisioning, setup instructions, and behavioral tests.

Verified targeted Python and JavaScript tests, desktop and web typechecks,
scoped lint, real product builds, and the Docker frontend smoke test.
The missed post-setup test cleanup is included and verified.

Native Windows/macOS execution, full Rust compilation, and the complete
repository suite remain unverified. Historical compatibility requirements
were preserved and extended, not fully rescanned.
2026-09-12 14:57:38 -04:00
ethernet
cc01ae9d44 merge: connector UI e2e v2 into bundled onboarding (rebuilt)
# Conflicts:
#	apps/desktop/electron/main.ts
#	apps/desktop/src/app/settings/local-models-settings.test.tsx
#	hermes_wisdom/agent_led/share_flow.py
#	plugins/memory/hindsight/__init__.py
#	scripts/lib/wisdom-demo-env.sh
#	scripts/release.py
#	tests/skills/test_collective_wisdom_install_skill.py
#	tools/checkpoint_manager.py
2026-09-11 21:10:19 -04:00
ethernet
1bf588234c refactor(build): share product recipes across distributions
Build TUI, web, desktop UI and runnable agent products from explicit
prepared inputs. Keep dependency preparation separate from distribution
packaging, with PM and native builds sharing uv environment construction.

Docker copies compiled frontend products instead of build dependencies.
Nix retains uv2nix environments and consumes shared assembly through store
references. Native desktop and Termux use the same launcher and frontend
contracts. Preserve the independent PM runtime and source imports from
arbitrary working directories.

Keep failed frontend builds from replacing the previous product, reject
source/output overlap, and bound dependency-process output draining.
Include hermes_wisdom in the Nix wheel: real CLI smoke tests exposed its
missing package declaration on the base revision too.

Verified focused Python and JavaScript suites, Docker build/runtime checks,
Nix desktop and CLI/ACP checks, standalone TUI and packaged Electron PTY,
and real full-Chromium interaction. Native signed installers, Android device
installation and the full repository suite remain CI verification.
2026-09-11 13:16:55 -04:00
ethernet
8f6d98e4c3 fix activation of devenv, use /usr/bin/env bash everywhere 2026-09-11 11:17:18 -04:00
KoNit-K
0b8daf30aa fix(bootstrap-installer): stamp setup app version from release semver
Fixes #107177

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-11 16:10:47 +02:00
ethernet
f5b56a2746 feat(icons): no-frame wordmarks, squircle BrandMarks, on-demand generation
- website wordmarks (logo.png/logo-dark.png) drop the black/white frame:
  the girl alone on transparency, black for light navbar / white for dark
  (docusaurus srcDark stays)
- BrandMark marks are now the app-icon squircle itself (transparent
  corners, 824px safe-zone composition) instead of plain tiles; the
  components no longer paint a tile/rounding
- generated icon outputs are NOT committed anymore: all 35 targets are
  gitignored and regenerated on demand by the consuming pipelines via the
  new scripts/generate-icons.mjs (website prebuild, desktop prebuild+dev,
  installer prebuild, web prebuild)
- freshness lane switched from byte-compare to structural verification
  (sizes, squircle corner transparency, ICO frame sets via header parse) —
  no more windows/ubuntu byte drift dance
- marks saved as 8-bit palette PNGs (FASTOCTREE quantize keeps per-index
  alpha tRNS -> 2.5KB, AA edges preserved); compose_svg renders in the
  background's native space so resvg scales per output size
2026-09-06 21:49:26 -04:00
ethernet
1c729b39f7 fix(icons): commit linux-truth regenerated icons; drop harvest temp
Refresh the 35 generated targets from the ubuntu freshness lane (the
windows regen compresses PNG differently per host zlib; CI checks
against linux bytes). Girl marks + masters are host-stable (stored
deflate blocks / plain text). Removes the temporary artifact-harvest
step now that the committed set matches the check lane.
2026-09-06 21:18:23 -04:00
ethernet
1fa5fea74f feat(icons): derive every icon from nous-girl SVGs + platform backgrounds
The icon pipeline now composes all 35 targets from two source axes instead
of a single hand-edited master:
- girl art: assets/nous-girl-black.svg / nous-girl-white.svg (brand kit)
- backgrounds: assets/backgrounds/ (squircle light/dark, logo frames,
  BrandMark tiles)

assets/icon-master*.svg are generated artifacts (squircle background + girl
nested in the 824px HIG content safe zone). New dark-appearance artifacts
(icon-dark.* containers, appx *-dark logos, logo-dark wordmark,
nous-logo-dark) land everywhere a surface consumes them: docusaurus navbar
srcDark, BrandMark dark tile (keyed off renderedMode).

nous-girl.jpg jpgs are replaced by lossless 8-bit palette PNGs saved with
compress_level=0 (stored deflate blocks, byte-identical across hosts for
the CI freshness lane).

Includes the temp linux-truth harvest step in icons-freshness-check.yml so
the committed compressed bytes can be refreshed from the ubuntu regen.
2026-09-06 21:12:44 -04:00
ethernet
0ee0bd903e fix(icons): commit linux-truth regenerated icons; drop harvest temp
resvg-py 0.4.0 rasterizes identically per-host but the committed set was
generated on Windows (22440-byte icon.png) while the freshness lane runs
on linux (24200). Harvested linux regeneration via a temp artifact step,
committed it (all 23 targets now match linux output), reverted the temp.
2026-09-04 04:53:42 -04:00
ethernet
096e4dbe68 fix(icons): regenerate all 23 targets from icon-master.svg (audit RED: --check drift)
generate_icons.py --check was RED on 23 targets — committed files
diverged from icon-master.svg output (large stale binaries: logo.png
1.3MB→60KB, icon.icns 1.5MB→94KB). Regenerated via the single-master
pipeline; --check now passes. Also gates the icons-freshness-check CI
lane that ci.yaml calls.
2026-09-04 03:59:04 -04:00
konsisumer
b3a2065ff3 fix(installer): target Windows updater shim kills 2026-08-26 07:59:01 -07:00
hermias1
7d9953d34f fix(desktop): allow microphone from macOS setup launcher 2026-08-25 21:59:23 -07:00