Commit Graph

34069 Commits

Author SHA1 Message Date
ethernet
8b56a9306f refactor(pm): own group-only builds and finish dependency hints 2026-09-11 18:25:05 -04:00
ethernet
d08ff92751 fix(build): prepare icon environments through PM 2026-09-11 18:24:54 -04:00
ethernet
69d6dfd077 fix(doctor): honor selected PM runtimes and launcher ownership 2026-09-11 18:20:54 -04:00
ethernet
596f0216a5 fix(skills): route google workspace dependencies through pm 2026-09-11 18:20:23 -04:00
ethernet
6ee8610b67 refactor(pm): finish consumer contracts and enforce private engine imports 2026-09-11 18:18:58 -04:00
ethernet
ea8adb5e22 fix(tests): isolate the platform-default Hermes root
The shared fixture isolates HERMES_HOME, but profile-root resolution also
resolves the native default. This trips the real-home guard even for tests
that use a temporary custom home. Base 75a646e5b3 has the same failures.

Isolate the native default in the shared fixture. Capture its parent before
test fixtures run so explicit home overrides keep their own layout. Leave
HOME, Path.home(), production resolver behavior, and the I/O guard intact.

On the original base, this fixture fixes all 24 PM authority failures and
92 update failures/setup errors. The same four unrelated /proc DB-holder
probe failures remain on both base and current code. Current targeted
profile, path, PM, and guard checks pass: 214 passed, 4 skipped.
2026-09-11 18:15:30 -04:00
ethernet
c91d2be042 fix(pm): gate build work and reuse wheelhouse install policy
Ready tools do not authorize dependency operations when lazy installs are
disabled. Apply the shared guard before build, export, or online lock checks.
Keep offline lock checks passive. Cache pruning only reads the pinned
toolchain and cannot acquire missing tools.

Use one requirements-file installer for requirement builds and runtime
wheelhouse staging. Both enforce the same index and binary-only policy.

Verified 36 targeted tests, including missing-toolchain pruning, disabled
lazy operations with ready tools, and real offline runtime staging.
2026-09-11 18:15:14 -04:00
ethernet
884a0241ca Drop retired Python environment references from bootstrap documentation 2026-09-11 18:15:13 -04:00
ethernet
a154b89b9f Route build and CI Python preparation through PM operations 2026-09-11 18:14:43 -04:00
ethernet
cdd76e03ec fix(pm): enforce install policy for explicit Python builds 2026-09-11 18:13:56 -04:00
ethernet
fc4086c4c5 fix(cli): route dependency hints through pm
Replace direct Hermes-environment pip advice with PM repair, existing
setup commands, or explicit extra sync. Keep Termux package guidance.
Plugin discovery reports missing dependencies without installing them.

Targeted Nix runner, HERMES_TEST_FILE_RETRIES=0:
- Seven focused files: 153 passed.
- Voice CLI integration: 31 passed on the follow-up run.
- Dashboard follow-up: 33 passed before one failure with --maxfail=1.
  test_post_memory_provider_setup_routes_pip_through_pm receives failed
  instead of restart_required from the memory setup endpoint.

Doctor launcher and runtime-detection gaps are reported separately.
No doctor checks are disabled. The full suite was not run.
2026-09-11 18:13:53 -04:00
ethernet
f697856f10 docs(pm): clarify worker probes and manager bootstrap 2026-09-11 18:13:22 -04:00
ethernet
ed568bd947 fix(runtime): route dependency hints through pm 2026-09-11 18:13:06 -04:00
ethernet
547b5de29d docs(pm): route dependency setup through public operations
Direct package installs bypass PM's dependency selection and do not survive
new generations. Document explicit runtime extras, recorded repair, fresh
build outputs, and lock generation through PM instead.

Keep the prepared-interpreter prerequisite and explicit removal requirement
for disposable test environments. Preserve Nix and external-project package
manager ownership. Correct platform and Python-marker claims where the
manifest contradicts the installation hints.

Checked the public CLI help, literal PM calls against public signatures and
extra declarations, fenced blocks, and whitespace. No dependency build or
site build ran. The docs toolchain is not installed in this checkout.
2026-09-11 18:12:49 -04:00
ethernet
9aac9f9fe8 refactor(cli): delegate Python setup and sync to PM 2026-09-11 18:12:12 -04:00
ethernet
c7b1f238b5 fix(pm): keep bootstrap and readiness checks behind safe operations 2026-09-11 18:11:59 -04:00
ethernet
8417678ae2 feat(pm): add semantic build and cache operations
Build callers need lock validation without mutation and frozen exports that
retain markers and Git pins. Route these operations through the private
engine instead of giving callers uv commands.

Requirement builds claim fresh destinations, validate installed packages,
and remove failed candidates. Wheelhouse builds reject indexes and source
builds. Cache pruning keeps downloaded wheels except in CI mode.

Verified with real local wheels, a local Git source, and loopback downloads:
30 targeted tests passed across test_build_operations.py and
test_environment_build.py. No full-suite claim while the base migration is
in progress.
2026-09-11 18:11:13 -04:00
ethernet
97252910f3 fix(pm): declare locked setup extras and unsupported engines
Setup needs declared extras instead of unbounded package installs. Pin ddgs,
langfuse and Piper without changing any existing resolved package versions.
Use upload-time cutoffs for the reviewed pins.

NeuTTS excludes Python 3.14. KittenTTS requires misaki, which excludes Python
3.13 and newer. Keep matching dependency markers and PM gates so bundles omit
these engines and explicit requests fail instead of reporting empty success.
Piper also excludes Intel macOS and Windows ARM64 because its native closure
lacks wheels there.

Verify the parent sync gate against the native Python version, including an
installed-anchor override. The test fails without that gate. Check declaration
and runtime gate agreement across bundle targets. Isolate an existing test's
home lookup, whose failure also reproduces on the base commit.

Verification: public PM lock/check and fresh 85-package environment passed in
an isolated manager runtime. DDGS, Langfuse and Piper imports passed on Linux.
No full suite or cross-host execution was performed.
2026-09-11 18:09:08 -04:00
ethernet
8bf20a3bc8 test(pm): align engine fixtures with public builds
Isolate profile discovery and supply explicit engine inputs for output diagnostics. Keep destination safety checks independent of invalid-source error ordering, and verify sealed pruning with real offline wheels.

The requested canonical group passes: 98 passed, 0 failed, 4 Windows-only skips across 15 files. The full suite was not run.
2026-09-11 18:06:20 -04:00
ethernet
80273b4507 refactor(pm): route Python tool installs through PM
Use PM-selected interpreters and tool entrypoints for Browser Use, Hindsight and Python language servers. Sync the declared Google Chat extras instead of changing the active environment with pip.

Verified the affected 11-file Nix test subset: 359 passed, 7 skipped. The full suite and real third-party package installation were not run.
2026-09-11 18:05:43 -04:00
ethernet
cc48185220 refactor(pm): expose Python operations instead of uv binaries 2026-09-11 18:05:28 -04:00
ethernet
01821b8e14 refactor(pm): consolidate private Python environment engine 2026-09-11 18:00:04 -04:00
ethernet
c184f04838 Use prepared Python for bootstrap and desktop build helpers 2026-09-11 17:59:55 -04:00
ethernet
75a646e5b3 fix(icons): render icns on Apple's 824-on-1024 mac grid
Testers reported the macOS app icon reads oversized next to other apps:
the full-bleed 1024 squircle master put the shape ~149px past Apple's
icon grid on every side. macOS icns targets now render from an in-memory
mac master built on new squircle-mac-{light,dark} backgrounds — the same
white/#0d1117 squircle at 824x824 (r=185.4) centered in 1024 with 100px
margins, with the girl box scaled by 824/1024 to keep her relative size
inside the shape. All non-mac targets keep the full-bleed squircle.
2026-09-11 17:22:11 -04:00
ethernet
26c39cbb27 fix(logging): fall back from concurrent-log-handler when portalocker is dead
A Windows bundle whose venv never processed pywin32.pth (see the launcher
fix) fails 'import pywintypes' with ModuleNotFoundError; portalocker 3.x
has no msvcrt fallback, so CLH retries lock() 20x and raises 'Cannot
acquire lock after 20 attempts' — which handleError suppressed entirely.
Result: zero file logging, silently, on every affected install.

* probe portalocker once at import (scratch lock/unlock) and fall back to
  stdlib RotatingFileHandler when it fails; the fallback disables rollover
  (multi-process appends make Windows renames fail with WinError 32, the
  #44873 trap CLH exists to avoid) and setup_logging() warns once
* the suppressed CLH lock timeout now warns once through the logging
  system instead of vanishing
2026-09-11 16:45:38 -04:00
ethernet
f67a3b59db fix(bundle): process the venv's .pth files in payload launchers
The minted launchers wired venv site-packages onto sys.path with a raw
insert (win32 wrapper) / PYTHONPATH (posix), neither of which runs .pth
files. pywin32.pth is load-bearing on Windows: it puts win32\lib on
sys.path, which is what makes 'import pywintypes' resolve — without it
portalocker's Win32Locker dies and concurrent-log-handler silently drops
every file-log record on Windows bundles.

* launcher_wrapper.py: site.addsitedir() for the site entry (repo first,
  site directly after, .pth dirs last)
* launchers.py posix: same via HERMES_SITE env in the -c bootstrap
* pm/environment.py: prune_site_pth() drops _virtualenv.pth and the
  __editable__ pointer (build-machine path) that must never run in a
  sealed payload
* python_env.py: run the prune after every environment build
2026-09-11 16:45:28 -04:00
ethernet
ad231c164b fix(setup): parse lock and mirror json by structure, not indentation
Two pre-Python readers anchored their awk patterns on the exact leading
whitespace of the machine-written json they parse:

- setup-hermes.sh read artifact-mirror.json with /^  "origin"/ (exact
  two spaces), so any other one-member-per-line layout lost the mirror
  fallback silently: the mirror url resolved empty and fetch_pinned
  reported only the primary url it failed on.
- scripts/install.sh read packages.python.version from pm/lock.json
  with exact 4-space and 6-space anchors; on any other layout the pin
  resolved empty and the install fell back to the hardcoded "3.14".

setup-hermes.sh's own pin() already established the contract for the
same file ("follow object names and braces, not indentation"); both
sites now follow it. The mirror read is a flat key match; the python
pin uses the same brace-tracking reader as pin().

No other site in the tree has the pattern: setup-hermes.ps1 uses
ConvertFrom-Json, nix uses builtins.fromJSON, python readers use
json.loads, and remaining awk users parse command output, not config.

Tests:

- tests/pm/test_setup_lock_format.py now parametrizes the mirror json
  indent (it was fixed at 2, leaving the mirror read unguarded) and
  adds a mirror-fallback E2E: the primary url is a dead port (curl
  exit 7, retriable), so the staged uv must come from the mirror,
  with the mirror json written at 9-space indent. Red on the old
  regex (mirror url resolves empty, exit 1), green with the fix.
- tests/test_install_sh_python_pin_indent.py (new) sources
  install.sh --manifest and proves bootstrap_python resolves the
  pinned version through a fake uv that records its calls, across
  2/4/0/tab/blank-line lock layouts.

Verified via scripts/run_tests.sh: 16 passed, 0 failed on the fix; the
new mirror-fallback test fails against the old parsers (verified by
stashing the two script changes and re-running). Sibling install/setup
tests (test_install_sh_node_deps_workspaces, test_install_stage_frames,
test_install_sh_desktop_stage, pm/test_activate_scripts) all green.
2026-09-11 16:33:02 -04:00
ethernet
6d344be588 fix(wake): upgrade sherpa for native Windows ARM64
Sherpa 1.13.8 supplies native Windows ARM64 Python and core wheels.
Remove its platform exclusion so auto selects the keyless engine there.

Declare pypinyin for both wake install paths. The tokenizer imports it
unconditionally, including for English phrases. Include sentencepiece
in the lazy engine extra too. Keep the matching core in the lockfile
and admit the reviewed release with bounded package cutoffs.

Verified native ARM64 Python 3.14 with the unchanged Hermes engine:
three phrases detected twice each, with no triggers in 180 seconds of
silence. Engine construction failed without pypinyin and passed with it.
The tested wheels match the lockfile hashes. Focused tests: 78 passed,
2 skipped. uv lock --check passed. No MSIX rebuild or microphone test.

The dependency audit reports the same existing httpx2/httpcore2
advisories as the parent commit. No unrelated packages changed.
2026-09-11 16:30:47 -04:00
ethernet
410ac37a0b fix(wake): select a supported engine by default
The fixed openWakeWord default selects an unavailable engine on native
Windows ARM64 and Intel macOS. Use auto and the existing PM platform gates
to prefer openWakeWord, then sherpa, then Porcupine.

Keep explicit provider choices unchanged. Porcupine still requires its
access key, and wake detection remains disabled until the user enables it.
Expose auto in the config UI and document the backend-platform selection.

Verified config loading, platform selection, explicit-provider preservation,
key requirements, and the config schema. No microphone detection was run.
2026-09-11 15:59:08 -04:00
ethernet
86efc1f945 fix(release): allow explicit environment clears in commit bundles
An inherited HERMES_HOME can defeat a test bundle's data-directory suffix.
Older Windows installers also persisted that variable in the user registry.
This gives the app fresh UI state while its backend reads existing sessions.

Add --bundle-unset NAME, encoded as null in the existing bundle environment
object. Apply each clear as an explicit empty value before module startup.
Do not restore an explicitly empty HERMES_HOME from the Windows registry.
Ordinary defaults still preserve runtime overrides.

Verified the release parser, builder handoff, compiled startup ordering,
registry opt-out, and child environment with focused regression tests.
A native Windows probe passed with an inherited home. No MSIX was rebuilt.
2026-09-11 15:59:08 -04:00
ethernet
2b1312d4ca Merge branch 'ethie/pm-binary' into ethie/pm-clean 2026-09-11 15:13:11 -04:00
ethernet
162c5b92d5 feat(desktop): name commit and canary builds in the product display name
Commit builds now show 'Hermes Agent <sha7>' (e.g. Hermes Agent abc1234)
and canary builds 'Hermes Canary' / 'Hermes Light Canary' / 'Hermes Agent
Canary' as the OS-visible product name, so side-by-side installs and
per-commit artifacts are readable at a glance.

Display-only by design: appId, appNamePascal, and msixAppIdWithOrg are
unchanged, so a canary MSIX still updates in place over stable and
userData / single-instance sharing with the stable install is unaffected.
bundle-electron-main.mjs derives the commit from the install stamp
(source='commit-build') so the baked runtime identity matches the
packaging identity.
2026-09-11 14:58:11 -04:00
ethernet
3301c31ff8 fix(desktop): restore backend lifecycle and update build contracts 2026-09-11 14:35:25 -04:00
ethernet
4e45b78311 fix(release): inline Windows reserved-path check for pre-3.13 runners
ntpath.isreserved was added in Python 3.13, but release workflow legs
(commit-builds-summary, builds-table, builds-pending) run bare python3 on
ubuntu-24.04, whose system Python is 3.12. render-builds-table.py crashed
with AttributeError before rendering the expected-binary matrix.

Port the CPython ntpath reserved-name semantics (device stems incl.
superscript COM/LPT forms, trailing dot/space per component) into
_is_windows_reserved() in scripts/releases/r2.py so the release transport
stays self-contained on whatever python3 the runner provides. Verified
byte-parity against real ntpath.isreserved on a 239-case corpus.
2026-09-11 14:30:56 -04:00
ethernet
06ef8ce786 feat(paths): suffix default agent and desktop data directories 2026-09-11 14:25:18 -04:00
ethernet
7d326adf9d feat(release): bake explicit environment defaults into commit bundles 2026-09-11 14:25:12 -04:00
ethernet
fea2858c99 merge: unify shared product builders, caches, and Windows prerequisites
Merge ethie/shared-product-builders with the CI dependency cache and native Windows setup work. Preserve UTF-8 diagnostics in the shared Python environment runner. Pass a persistent cache through isolated native staging and PM-runtime construction. Reuse one Windows prerequisite installer from source setup, native adapters, and CI, preserving Rust homes across HOME isolation.

Verified 85 targeted Python tests (5 host skips), 18 JavaScript tests, workflow validation, and scoped lint/typecheck. On native Windows ARM64, five prerequisite contracts passed and the actual shared provider reused OpenSSL, compiled its header with MSVC, and retained Rust under isolated HOME. Full signed distribution builds and live Actions cache transfer remain CI verification.
2026-09-11 13:45:05 -04:00
ethernet
4cc2b7bab5 fix(ci): remove legacy uv cache compatibility 2026-09-11 13:32:32 -04:00
ethernet
018d2b39d8 fix(pm): prepare platform trust before bootstrap downloads
Standalone Python cannot locate the system CA bundle on this NixOS host.
Use the shell-staged uv to prepare the independent PM runtime before PM
fetches managed Python. Declare and lock truststore in that runtime, then
activate it before CLI and worker imports construct HTTPS clients.

Make setup's awk pin reader follow object nesting rather than indentation.
Use the same reader for tool versions and artifact fields.

Verified cold activation with CA overrides removed, pinned Python and uv
downloads, pm doctor, and a public worker HTTPS install. The targeted suite
passed 56 tests with one Windows-only skip. The TLS regression fails when
truststore is installed but entrypoint activation is removed. Bash syntax
and Ruff checks passed. The full suite was not run.

Two additional setup-toolchain tests fail on unchanged HEAD because their
fixtures reach the real home before home isolation. CI bootstrap unification
is not part of this change.
2026-09-11 13:31:41 -04:00
ethernet
fffccbb2ae fix(setup): prepare native Windows ARM64 build dependencies
Source activation could not build cryptography because the setup shell
could not discover the installed OpenSSL development libraries.

Configure Visual Studio ARM64, Clang, Rust, and static OpenSSL before PM
runs. Reuse installed tools and install missing prerequisites. Select a
classic vcpkg with a ports tree and use an explicit installation root.
Report damaged shared libraries without deleting the shared installation.

Verified native PowerShell activation and deactivation on Promise, then
warm activation with no new dependency generation. Cryptography imported
with static OpenSSL. Real vcpkg checks covered installation into a path
with spaces, warm reuse, manifest mode, and damaged-package rejection.
The canonical Windows runner passed the helper and output-encoding tests.

Fresh Visual Studio and Rust installation were not exercised because
Promise already had those toolchains installed.
2026-09-11 13:29:45 -04:00
ethernet
caf27c01b9 fix(pm): decode captured build output as UTF-8
Windows defaulted captured uv output to CP1252. A UnicodeDecodeError in
the pipe reader hid the OpenSSL build failure and left an empty diagnostic.
Decode uv and npm output as UTF-8, replacing malformed bytes while keeping
the exit status and build error.

Real subprocess tests cover stdout, stderr, legacy locale defaults, and
malformed output. The encoding tests passed on native Windows ARM64 and
Linux through scripts/run_tests.sh.
2026-09-11 13:29:45 -04:00
ethernet
493ae9daa3 fix(ci): reuse uv wheels and save caches after bundle failures 2026-09-11 13:28:15 -04:00
ethernet
0a3a189235 refactor(build): remove superseded launcher templates 2026-09-11 13:17:10 -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
284dbaf537 fix(pm): isolate bootstrap dependencies and unify YAML on ruamel
Activation reaches plugin discovery before the application dependencies
exist. Give PM its own locked Python project and runtime so it can install
or repair the application without importing that dependency tree.

Keep PM outside the application workspace. A shared uv workspace resolves
the application graph and cannot provide this isolation. Route mutations
through an isolated worker and preserve transaction callbacks, cancellation,
custom package registrations, and correlated receipts.

Use the same runtime builder for source installs and packaged payloads.
Keep offline wheelhouse support in that builder. Nix builds the independent
PM lock as a separate derivation. Refuse lazy-disabled bootstrap before
installing tools or dependencies.

Move first-party YAML readers and writers to ruamel. Keep the application
lock's transitive PyYAML requirements for third-party packages.

Verification:
- Focused canonical Python suite: 177 passed, 1 host-gated skip.
- Electron backend probes: 12 passed. Electron typecheck passed.
- Both uv locks, scoped lint, Bash syntax, and whitespace checks passed.
- Cold activation, corrupt-app repair, offline staging, and relocation ran.
- Built and exercised the Nix PM runtime and standalone YAML merge script.

Six broader caller test files retain the same 24 failing test IDs as an
archive of HEAD. The existing real-home guard blocks those tests before
they can exercise the affected paths. No full-suite pass is claimed.
Native Windows signing and full Bionic package execution remain unverified.
2026-09-11 12:23:51 -04:00
ethernet
bfabc23f7f fix(desktop): reconcile runtime wiring after the PM merge
The merge combined old callers with newer lifecycle and update modules.
It also dropped native handlers while keeping their preload methods.
Type declarations alone could not repair those runtime failures.

Restore bounded backend teardown and retain failed-stop ownership.
Use API-only passive checkout checks with a daily disk cache, and pass
manual refresh requests through the updater strategy. Keep the shared
About UI and restore onboarding, feature flags, and notification wiring.

Verified all workspace typechecks, lint on the changed desktop files,
focused UI and Electron tests, and the development bundle. A headless
Electron smoke test exercised the real main process, preload, and native
IPC. A separate test exercised update checks with a linked git worktree,
loopback HTTP, and the disk cache. The full repository suite was not run.
2026-09-11 11:56:35 -04:00
ethernet
8f6d98e4c3 fix activation of devenv, use /usr/bin/env bash everywhere 2026-09-11 11:17:18 -04:00
ethernet
3c2e1bd452 fix(desktop): disable MSIX virtualization 2026-09-11 10:58:02 -04:00
ethernet
b3bfc3afe5 Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts:
#	apps/desktop/electron/backend-connection-state.test.ts
#	apps/desktop/electron/backend-connection-state.ts
#	apps/desktop/electron/backend-exit.test.ts
#	apps/desktop/electron/main.ts
#	apps/desktop/electron/pool-spawn-coordinator.test.ts
#	apps/desktop/electron/pool-stop.ts
#	apps/desktop/electron/preload.ts
#	apps/desktop/src/app/settings/about-settings.tsx
#	apps/desktop/src/app/updates-overlay.tsx
#	apps/desktop/src/global.d.ts
#	apps/desktop/src/store/notifications.ts
#	apps/desktop/src/store/updates.ts
#	gateway/config_loader.py
#	hermes_cli/banner.py
#	plugins/platforms/dingtalk/adapter.py
#	tests/hermes_cli/test_plugins_cmd.py
#	tests/test_live_system_guard.py
#	tui_gateway/server.py
#	website/docs/user-guide/desktop.md
2026-09-11 09:36:04 -04:00
Teknium
a2413495ad fix(state): fts_trigram_session_sql qualifies model_config under the json_valid guard
The _sql_json_extract wrapper removed the `COALESCE(model_config` text the
alias string-replace keyed on, so the deferred-backfill SELECT joined an
unqualified `model_config`. Build the predicate from the alias directly and
derive the unaliased constant from it, so the two can never disagree.
2026-09-11 06:24:54 -07:00