Commit graph

37 commits

Author SHA1 Message Date
39b1f928f4 fix(wizard): restore Antigravity OAuth by matching the 3-tuple session API
0d9005f changed start_profile_oauth to return (session_id, auth_url, port) and
updated the tests, but not its callers. The wizard still unpacked two values, so
every Antigravity connection raised ValueError inside _init_antigravity_oauth,
the handler swallowed it, and the authorization URL never appeared — the primary
onboarding flow has been dead since that commit.

Also stores the listener port as wizard.oauth_port, which the single-session
invariance test reads to prove that repeat "open browser" clicks reuse the
existing listener instead of binding a new one.

Both defects were caught only by tests that the headless run skips, which is why
they survived several reviews.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:00:42 +07:00
Hermes Team
83409d5354 style: normalize merged state tests 2026-08-21 00:11:16 +07:00
Hermes Team
83e1f78818 merge: complete antigravity state layer 2026-08-21 00:10:56 +07:00
Hermes Team
a2280236aa feat(state): harden snapshots quotas and routing 2026-08-21 00:03:50 +07:00
Hermes Team
86c9189edd feat(state-layer): event-driven quota, seq freshness guards, and state layer stabilization
- Added HubStateStore targeted delta update methods (apply_delta_quota_updated, apply_delta_account_added, apply_delta_account_removed, apply_delta_route_changed)
- Added seq sequence freshness tracking in HubStateStore to drop stale out-of-order responses
- Added trigger_refresh_provider in HermesRefreshScheduler
- Bound multi-bucket quotas to specific model families (Claude vs Gemini) with truthful is_estimated tracking
- Connected OAuth completion to targeted account added events across all providers
- Pinned antigravity_provider package root to repo via __init__.py and added import invariant verification
- Added unit tests in tests/test_state_layer_and_event_driven_quota.py and tests/test_import_invariants.py
- Zero modifications to UI zone files (views, components, theme, wizard, hermes_hub_app.py)
2026-08-20 23:48:36 +07:00
Hermes Team
11ce88c18e docs(state): publish UI state contract 2026-08-20 23:46:50 +07:00
Hermes Team
35881c4f04 docs(contract): publish UI state and ViewModel contract for Task A and B 2026-08-20 23:44:07 +07:00
f171a8069d test(conftest): skip GUI tests by marker instead of by test name
The headless guard matched any test whose name contained "ui", "view" or
"wizard", so static checks that never touch the toolkit were skipped too. That
is how four real failures stayed invisible: they lived in modules the name
filter silently removed. Selection is now the `ui` marker alone; modules that
import the GUI stack already guard themselves with pytest.importorskip, which
tests/test_import_invariants.py enforces.

Headless goes from 152 to 156 passed — four tests that were being skipped by
accident now actually run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:41:48 +07:00
8a52f79b21 docs(task): fix control character mangling the plugin path
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:37:12 +07:00
8143150ebc docs(task): add findings that only surface with UI dependencies installed
Running the suite with customtkinter present exposes four failures the headless
run never reaches: hermes_hub_app mutates sys.path so tests load the stale
installed plugin copy, and two OAuth lifecycle tests fail outright. conftest's
name-based skip hid both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:36:36 +07:00
a7027b42d5 refactor(ui): centralize design tokens and complete the component library
PHASE 1 of the UI redesign. Adds semantic colour roles that keep brand gold out
of health states, layout and typography aliases so views stop hand-rolling
padding, and the reusable widgets the redesign depends on: PlanBadge, QuotaBar,
QuotaBucketWidget (stable key plus in-place update), SearchField, FilterButton,
ActionButton, IconButton, EmptyState, RouteTargetWidget, AccountCardWidget,
AgentCardWidget, ConfirmDialog, Toast, plus ellipsize/tooltip helpers for long
account identities.

test_unknown_quota_is_supported_explicitly compared inspect's resolved
annotation object against source strings, so it could only pass while being
skipped; components.py has no `from __future__ import annotations`. Rewritten
to assert through typing.get_args that QuotaBar.set_value accepts None.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:35:10 +07:00
a9c04b75a2 fix(ui): repair startup crash in TeamView and tighten the headless guard
Launching the app died with "'dict' object has no attribute 'readiness'".
TeamView.__init__ forwarded its legacy app_state dict into update_data(snapshot),
whose guard only handled None, so {} reached snapshot.readiness. TeamView is the
default view, so the window never appeared.

Fixes the call site and hardens every snapshot guard to fall back on anything
that is not a HubSnapshot. Adds tests/test_view_startup_contract.py, which
checks both conditions statically and therefore runs headless; verified to fail
on the pre-fix sources.

The GUI-import invariant previously matched the literal string "customtkinter",
which missed modules pulling it transitively. Rewritten over the AST, it
immediately found test_codex_opencode_wizard.py importing router.ui.components
without pytest.importorskip — the same defect that took the release gate down
once before, hidden until now behind conftest's name-based skip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:22:19 +07:00
93883f9ce4 docs(task): split Plan A and UI redesign into two non-overlapping assignments
The UI redesign draft duplicated eight Plan A phases on the same files
(accounts_view, routing_view, hermes_hub_app, unified_health), which would have
put two agents into the same merge conflicts. Ownership is now split by file
path, with docs/UI_STATE_CONTRACT.md as the interface between them.

Four draft items were already implemented at 50fde5f and are marked as such
rather than reassigned: OAuth URL copy-before-open, keyed account card reuse,
the no-fake-metrics rule, and the importorskip guard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:13:59 +07:00
Hermes Team
50fde5f16e refactor(plan-a): close residual blockers, concurrency race, and feed verification
- Implemented 3-tier release feed status (MANIFEST_LIVE, PACKAGE_LIVE, PACKAGE_HASH_VERIFIED)
- Added reproducible package and checksum builder in scripts/build_dist.py
- Preserved user header comments across YAML saves in router_config.py
- Connected model_timeout_seconds, monitoring_interval_seconds, and auto_monitoring to runtime
- Guarded global gemini:antigravity credential swap with _AGY_INVOCATION_LOCK to eliminate concurrent subprocess race
- Added concurrency regression test in tests/test_antigravity_concurrency.py
- Added interprocess file locking (_FileLock) for router_state.json in health_tracker.py
- Sandboxed APPDATA and USERPROFILE in tests/test_installer.py
- Exported roadmap modules in router/__init__.py
- Verified 151 passing tests (100%) and 7/7 release gate checks
2026-08-20 22:55:43 +07:00
559a56d80b docs(task): Plan A refactoring task with verified baseline statuses
Every Round 4 finding re-checked against HEAD 63c0385 instead of being carried
forward as still-open. Four are already fixed (customtkinter collection guard,
_CM_LOCK scope, gemini:antigravity restore, session affinity TTL), two are
partial, one is obsolete (web stack moved to legacy/), and five remain open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:31:07 +07:00
63c0385f5c fix: repair seven undefined names and make CI ruff step meaningful
`ruff check .` failed on every push since CI was added (1221 findings), so the
job aborted before pytest and the release gate ever ran. Adds [tool.ruff]
selecting bug-catching rules only (E9, F63, F7, F82, F811); style and
modernization rules stay off until their ~1200 findings are burned down.

That selection immediately surfaced seven live defects:
- hermes_hub_app: HubModal used but never imported, so the "Назначить" role
  modal raised NameError — the handler added to close an earlier review
  finding could never open.
- hermes_hub_app: three `after(0, lambda: ...(e))` callbacks referencing the
  except-bound name, which Python unbinds at block exit, so every UI error
  path raised NameError instead of reporting the error.
- auto_assigner: build_team_hierarchy referenced an undefined `is_main` and
  crashed on every call.
- ui/assets and live_provision_and_validate: annotations naming Any/Tuple
  without importing them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:28:08 +07:00
46a185395c docs(review): add independent audit, five review rounds, and remediation task
Full audit of the project (93 findings) plus the review record for rounds 1-5:
P0 release blockers, 65482e8, 42dfe2c, the v0.1.1 candidate verdict, and the
review of the previously unreviewed OAuth/wizard/quota work. Includes the
remediation task with acceptance criteria that 42eddb3 was verified against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:22:57 +07:00
Hermes Team
51e5b67921 Merge branch 'chore/import-invariants-and-ci' 2026-08-20 22:22:44 +07:00
8db5c46515 test(ci): add import invariants, repair DeepSeek adapter, guard headless runs
deepseek_adapter.py had never been importable: it referenced ProviderAdapter
and ProfileConfig, neither of which exists in src/, and profile.extra, which
RouterProfileConfig does not define. Rewritten against BaseProviderAdapter with
the three missing abstract methods and registered as "deepseek".

Adds tests/test_import_invariants.py, which walks every shipped module and
fails on broken internal references while skipping absent optional GUI extras.
It also asserts that test modules importing customtkinter call
pytest.importorskip, since a missing guard aborts collection of the whole
session and takes the release gate with it.

Adds a headless CI job that uninstalls customtkinter and runs the suite, so
that invariant is enforced rather than remembered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:13:54 +07:00
Hermes Team
42eddb3627 fix(quota, oauth): enforce data truthfulness, honest quota sources, and fail-closed OAuth
- Removed fabricated used_percent numbers and fake *_api source tags from quota_collector.py
- Marked quota snapshot sources as baseline/estimated and added visual estimation indicators in accounts_view.py
- Eliminated silent fallback on fake user_code/device_code in codex_oauth.py and grok_oauth.py
- Gated mock OAuth sessions strictly behind HERMES_HUB_DEV_MODE=1 with visible UI warnings
- Documented Google, OpenAI, xAI, and Claude OAuth clients in docs/OAUTH_CLIENT.md
- Relocated unused gui_server.py and gui_cockpit.html to legacy/
- Added test_data_truthfulness_and_oauth_security.py covering fail-closed and source truthfulness invariants
- Verified 98 passed tests (100%) and 7/7 release gate checks
2026-08-20 22:11:57 +07:00
Hermes Team
0c511cd3b6 feat(hub): Plan A stabilization, refresh architecture, delta UI, and capability routing
- Implemented HubSnapshot and central HubStateStore for normalized in-memory state caching (<0.05ms)
- Refactored AccountsView and RoutingView with reusable AccountCardWidget and RoutingRoleWidget to eliminate widget recreation
- Implemented central HermesRefreshScheduler with 5s tick, concurrency throttling, dedup, and spread initial delays
- Added typed EventBus with thread-safe UI main loop dispatching via root.after
- Implemented dynamic ModelRegistry with capability-based role requirements and multi-dimensional scoring
- Integrated Antigravity separate quota buckets (Claude vs Gemini) and same-account model fallback
- Enhanced SessionAffinityTracker with TTL expiration and LRU capacity bounds
- Eliminated long subprocess holding of _CM_LOCK and ensured Windows credential restoration in finally block
- Added FastAPI REST contracts in gui_server.py as foundation for future Tauri frontend
- Verified 100% pass across all 91 pytest tests and 7/7 release gate criteria
2026-08-20 21:20:51 +07:00
Hermes Team
2b8b709ac9 feat: multi-provider accounts, tariffs, quota buckets, Claude & Grok integration 2026-08-20 21:02:13 +07:00
Hermes Team
3aae1a8def feat(wizard): support Codex OAuth/API Key & OpenCode Go with clipboard UX 2026-08-20 20:31:59 +07:00
Hermes Team
249a88867c feat(oauth): adopt Cockpit Tools model with immediate URL readiness, manual callback fallback, and race protection 2026-08-20 20:17:37 +07:00
Hermes Team
0d9005f55b fix(oauth): eliminate ERR_CONNECTION_REFUSED, guarantee immediate listener binding, single session reuse, and diagnostic logging 2026-08-20 19:59:49 +07:00
Hermes Team
8314d46c43 fix: update canonical installer with dependency resolution and close release blockers 2026-08-20 18:17:08 +07:00
Hermes Team
42dfe2caa6 feat: production update feed architecture, host allowlist, and truthful release gate 2026-08-20 17:25:30 +07:00
Hermes Team
2f5e6d9f7a fix: strengthen secret scanning and oauth configuration 2026-08-20 17:23:40 +07:00
Hermes Team
70d34c1642 fix(router): connect persisted settings to runtime behavior 2026-08-20 17:22:23 +07:00
Hermes Team
925e6c6687 fix(router): correct spare assignment and error presentation 2026-08-20 17:21:30 +07:00
Hermes Team
65482e8eee fix(router): address review findings B1-B4 and S1-S9 with full regression suite 2026-08-20 17:04:49 +07:00
Hermes Team
7926de9ad2 feat(release): recovery stabilization, built-in updater, release gate, and v0.1.1 release pipeline 2026-08-20 16:29:35 +07:00
Hermes Team
2a97e80a3e fix: close P0 release blockers 2026-08-20 16:25:11 +07:00
Hermes Team
5ccfd48c41 docs: add completed stabilization and roadmap report 2026-08-20 11:02:28 +07:00
Hermes Team
7609ad87c2 feat(hub): product stabilization, native windows ux v3, provider icons, and architecture roadmap 2026-08-20 11:01:52 +07:00
Hermes Team
e66248ab09 feat: initialize standalone Hermes Hub 2026-08-20 10:53:49 +07:00
Hermes Team
fdf9eccbdb feat: initialize standalone Hermes Hub 2026-08-20 00:17:11 +07:00