Commit graph

887 commits

Author SHA1 Message Date
brooklyn!
40e9b893f7
Merge pull request #63103 from NousResearch/bb/desktop-docs-alignment
docs(desktop): judgment-first AGENTS guide + DESIGN/README alignment
2026-07-12 04:34:21 -05:00
Brooklyn Nicholson
8bea079e2e docs(desktop): add judgment-first AGENTS guide and align DESIGN/README
Capture durable Desktop engineering principles from recent sessions —
state by authority, workspace-switch shapes, resolver ladders, optimistic
UI — and point root AGENTS.md at the scoped guide with current filenames.
2026-07-12 05:31:54 -04:00
Brooklyn Nicholson
e0a650fa7d refactor(desktop): text-only workspace status menu + attribution
Align the workspace status-bar dropdown with the rest of the status bar: drop
the per-item icons (they mixed lucide size-4 with a Codicon 1rem glyph and were
the only status-bar menu carrying item icons), leaving text-only items on the
shared DropdownMenuItem primitive with default typography. The status-bar
trigger keeps its FolderOpen glyph, consistent with sibling items.

Also map true@supersynergy.de → Supersynergy in AUTHOR_MAP.
2026-07-12 04:56:24 -04:00
Maxim M
5fc08c0e0d feat(desktop): add workspace path status action 2026-07-12 04:55:29 -04:00
brooklyn!
8895335453
Merge pull request #63077 from NousResearch/bb/salvage-61950-nongit-groups
fix(desktop): preserve legacy non-git workspace groups (supersedes #61950)
2026-07-12 03:51:48 -05:00
harjoth
a5c0715835 fix(desktop): preserve sidebar workspace targets across new drafts
Squashed salvage of #45744 (@harjothkhara), rebased onto current main and
resolved against #58241 (which swapped the new-session cwd fallback to the
project-aware resolveNewSessionCwd).

An explicitly clicked sidebar workspace stays authoritative until session.create:
a one-shot $newChatWorkspaceTarget (null → detached, string → that folder) plus a
generation counter so a stale async `config.get project` normalization can't
overwrite a newer draft target. The start-workspace-session action is extracted
out of desktop-controller.tsx into a testable workspace-session-target module.

Integrated with #58241: the no-explicit-target branch now falls through to the
project-aware resolveNewSessionCwd() instead of the old workspaceCwdForNewSession.

Co-authored-by: harjoth <harjoth.khara@gmail.com>
2026-07-12 04:43:43 -04:00
Brooklyn Nicholson
ceb179163d fix(desktop): mirror Windows path identity in live overlay + WSL spelling
Addresses @teknium1's review of #61950:

- The desktop live overlay (workspace-groups.ts) matched cwd membership
  case-sensitively, so a fresh mixed-case/separator Windows session missed
  its explicit/auto project until the next backend tree refresh. Mirror the
  backend identity (isWindowsPath/comparisonSegments/pathKey) in isPathUnder,
  liveSessionProjectId, and overlayRepoLanes lane matching. Comparison-only —
  emitted ids/labels keep their spelling. POSIX stays case-sensitive.
- Backend _is_windows_path missed root-relative `\wsl.localhost\...` (single
  leading backslash), leaving that historical spelling case-sensitive. Classify
  any backslash-rooted path as Windows.

Tests: WSL-spelling collapse + explicit-project precedence (project_tree),
Windows/WSL live-overlay membership + POSIX case-sensitivity (workspace-groups).
2026-07-12 04:33:05 -04:00
brooklyn!
095b9eed38
Merge pull request #58241 from tianma-if/codex/fix-desktop-project-session-cwd
fix(desktop): preserve project cwd for new sessions
2026-07-12 03:29:07 -05:00
Brooklyn Nicholson
65712bf788 fix(desktop): clear the OAuth partition before remote sign-in
Sign out of the dedicated OAuth partition before opening the login window so a
stale gateway/identity-provider cookie can't silently bounce an expired session
straight back into failure. Relabel the action "Sign out & sign in" and spell
out the sign-out step in the hint.

Co-authored-by: Tony Antunez <57689194+smtony@users.noreply.github.com>
2026-07-12 04:08:29 -04:00
Brooklyn Nicholson
f3af066b85 fix(desktop): treat connected-but-expired remote sessions as reauth
Add isRemoteReauthError so an auth-shaped boot error counts as a remote-reauth
failure even when the session indicator still reads connected (a stale refresh
cookie / failed ws-ticket mint). Wire the boot error into the overlay's reauth
check so those sessions route to Sign in instead of the local-only recovery
buttons.

Co-authored-by: Tony Antunez <57689194+smtony@users.noreply.github.com>
2026-07-12 04:08:14 -04:00
Brooklyn Nicholson
c1c74d7518 fix(desktop): recover a failed gateway from the boot-failure screen
A remote/VPS backend that failed to boot trapped the user on the recovery
screen — Retry/Repair/Use-local only target the local backend, so the only fix
was hand-editing connection.json. Add an in-place "Gateway settings" view (the
real GatewaySettings panel embedded via `embedded`, lazy-loaded) reached from
the recovery card, and shape the recovery actions by failure kind: Sign in for a
lapsed remote session, Gateway settings for any other remote failure (Retry
drops to secondary; Repair is dropped — it can't revive a remote), Retry for a
local backend. Use-local is scoped to remote failures.
2026-07-12 04:07:41 -04:00
Brooklyn Nicholson
f8152d2323 feat(desktop): embeddable Gateway settings panel
Add an `embedded` flag to GatewaySettings (and a `bare` variant to
SettingsContent) that drops the page title/intro, Diagnostics row,
"Save for next restart", and the page gutters — so the same panel can be reused
inside a tighter surface without a second connection form to maintain. No change
to the standalone Settings → Gateway page (defaults off).
2026-07-12 04:05:52 -04:00
Brooklyn Nicholson
e1fa54d367 refactor(desktop): extract isRemoteConfig from the reauth predicate
Factor the "remote/cloud with a URL" check out of isRemoteReauthFailure into a
shared isRemoteConfig helper so the boot-failure overlay can tell any remote
failure apart from a local one.
2026-07-12 04:05:44 -04:00
Brooklyn Nicholson
302a0dade8 chore(desktop): drop the dev-only "soft switch" preview from gateway settings
Remove the DEV-gated "Dev · soft switch" ListRow and its previewGatewaySwitch
helper. It was a temporary review affordance for exercising the soft-switch
reconnect; dead-stripped from production, but it doesn't belong in the tree.
wipeSessionListsForGatewaySwitch (the real path) and $gatewaySwitching stay.
2026-07-12 03:34:57 -04:00
Teknium
7550c594ce
feat(reasoning): add max and ultra effort levels (#62650) 2026-07-12 00:26:49 -07:00
brooklyn!
2043436af1
Merge pull request #63029 from NousResearch/bb/salvage-62022-tooltip
fix(desktop): stop empty mispositioned tooltip on terminal rail hover
2026-07-12 01:59:25 -05:00
Brooklyn Nicholson
be2b73e253 fix(desktop): stop empty mispositioned tooltip on terminal rail hover
A block-level label child (e.g. `flex`) collapses TooltipContent's inline
`box-decoration-clone` wrapper, so Radix measures a zero-size chip and parks
an empty black rectangle in the panel corner instead of by the trigger
(#62022). The terminal rail's hotkey labels and the preview row's two-line
label both hit this.

Harden the shared wrapper (`[&>*]:!inline-flex`) so any call site's direct
child renders inline-flex, add a reusable `TipHintLabel` for the common
text+hotkey label, and keep the preview row's label explicitly inline-flex.

Salvages #62139 (shared-component hardening + TipHintLabel) and #62073
(inline-flex call-site fixes + rail/preview coverage).

Co-authored-by: alelpoan <alelpoan@proton.me>
Co-authored-by: zapabob <1920071390@campus.ouj.ac.jp>
2026-07-12 02:53:03 -04:00
Brooklyn Nicholson
1a3b220651 fix(desktop-terminal): reopen terminal tabs in the last-used directory
A reopened tab restarted the shell in its original launch dir, so the fresh
prompt showed the wrong folder after a prior `cd` (the issue's "separate
thing" note). Track the shell's working directory and restart the PTY there.

Two independent signals feed a persisted per-tab restoreCwd:
- a main-side PTY cwd probe (shell-agnostic; /proc on Linux, lsof on macOS;
  Windows has no cheap per-process query so it falls back to the launch dir)
- cwd-reporting OSC sequences parsed in the renderer (OSC 7 file URIs, OSC 9;9
  ConEmu/Windows-Terminal paths) for shells configured to emit them

On relaunch the fresh shell boots in restoreCwd, falling back to the launch
cwd (then home) when it no longer exists.
2026-07-12 02:49:26 -04:00
Brooklyn Nicholson
817969f5a2 fix(desktop-terminal): trim trailing idle prompt on no-separator shells
cleanReviveSnapshot only dropped the trailing prompt when a blank separator
sat above it (starship add_newline), so shells that print the prompt with no
preceding blank line — default PowerShell (PS C:\..>), bash user@host:~$ —
kept the idle prompt in the saved buffer and showed a duplicate under the
fresh boot prompt on every relaunch of an *active* session.

An interactive shell always reprints its prompt after a command, so the tail
of an idle buffer is the prompt, never history. Drop the short block after a
blank separator when present, otherwise drop the trailing single-line prompt.
Command output is preserved; the fresh shell reprints the live prompt on boot.
2026-07-12 02:48:48 -04:00
Brooklyn Nicholson
164d9126cc fix(desktop-terminal): stop idle prompt accumulation across relaunches
An idle terminal tab (no command ever typed) grew one extra copy of the
shell's boot prompt on every close/reopen: persistSnapshot re-serialized a
buffer that was just the replayed old prompt plus the fresh shell's new
prompt, and cleanReviveSnapshot's blank-line trim can't strip prompts on
shells like default PowerShell that print no separator line.

Track real user input (keystrokes/paste, drag-and-drop paths, injected
commands) and, when a session had none, skip re-serializing. If the buffer
we loaded carried no real scrollback (empty or only a repeated prompt),
clear it so the next launch shows a single fresh prompt and any existing
accumulation heals; otherwise leave the prior snapshot untouched so real
history from an earlier active session survives an idle reopen.

Salvages #61584 (activity tracking) and #61577 (clearing content-free idle
buffers) into one path: it also heals already-polluted buffers, counts
drag-and-drop and injected input as activity, and never discards genuine
short command history (only empty/all-identical buffers are cleared).

Co-authored-by: alelpoan <alelpoan@proton.me>
Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
2026-07-12 02:48:48 -04:00
HexLab
f8054601a8
Merge pull request #62600 from HexLab98/fix/desktop-cron-no-agent-editor
fix(desktop): allow editing script-only (no_agent) cron jobs without a prompt
2026-07-12 02:32:29 -04:00
izumi0uu
ce5c1f9f79 fix(desktop): keep model picker switches session-scoped
Desktop active-session picker calls already pass a session_id, but the gateway's model switch persistence is controlled by parsed model flags. Add --session so the shared parser keeps live-session selections, including MoA virtual provider presets, out of profile config.yaml.

Constraint: config.set model values are parsed by hermes_cli.model_switch before persistence is decided.

Rejected: backend special-case for desktop session_id | it would duplicate existing --session semantics and widen the gateway surface.

Confidence: high

Scope-risk: narrow

Directive: Keep desktop model picker active-session switches explicit with --session; do not rely on session_id alone for persistence.

Tested: npm run test:ui -- src/app/session/hooks/use-model-controls.test.tsx src/app/shell/model-menu-panel.test.tsx

Tested: npm run typecheck

Tested: git diff --check

Not-tested: full pytest suite; change is desktop TypeScript/UI routing only.
2026-07-11 08:39:17 -07:00
teknium1
31152ae108 fix(providers): align Fireworks integration with project policy 2026-07-11 05:43:35 -07:00
Alex Jestin Taylor
c97d9a4c07 feat(providers): add Fireworks AI as preferred provider
Bundle Fireworks AI as a first-class BYOK provider across the CLI, web/TUI,
and desktop onboarding.

- New model-provider plugin with attribution headers (HTTP-Referer / X-Title)
  so Fireworks can attribute Hermes traffic; PAYG-safe default aux + fallback
  models (accounts/fireworks/models/...), IDs tracking fw-ai/fireconnect.
- Registered in CANONICAL_PROVIDERS so it appears in the CLI/web/TUI pickers.
- Alias wiring (fireworks-ai, fw) into both CLI resolvers.
- First-class wiring: OPTIONAL_ENV_VARS, HERMES_OVERLAYS (FIREWORKS_BASE_URL
  override), doctor env hints. Live catalog + model_metadata are auto-derived.
- doctor: treat Fireworks' native slash-form IDs (accounts/fireworks/...) as
  valid, not aggregator vendor prefixes, so it no longer tells Fireworks users
  to switch to openrouter or drop the prefix.
- picker: plugin providers with no static curated list now lead with their
  profile fallback_models, so the default is an agentic chat model instead of
  whatever the live catalog returns first (Fireworks listed an image model,
  flux-*, ahead of its chat models).
- Desktop onboarding: Fireworks as a RECOMMENDED hero card with the official
  Fireworks logomark and a brand-purple badge, routing to the BYOK key form;
  i18n in en/ja/zh/zh-hant.
- Tests: profile contract, first-class wiring (both resolvers, overlay, config,
  doctor incl. the slash-form regression, aux headers, credentials), discovery
  spot-check, and a live smoke test driven through the Hermes runtime.

Fire Pass (fpk_) support is coming soon; the future wiring is kept as a
commented-out scaffold in the plugin.
2026-07-11 05:43:35 -07:00
HexLab98
7acaff5ef2 fix(desktop): pin session context during async prompt submit (#54527)
Snapshot the selected stored session and route token for the full async submit
pipeline so a mid-flight session switch cannot resume the wrong chat or
misroute the user's text. Includes regression tests.
2026-07-10 19:35:05 -07:00
joaomarcos
2afa92c74f fix(desktop): pin composer draft scope to the swap-effect owner, not the render ref
Fixes #54527 — a message typed into one TUI session could be silently
misrouted into (or overwritten by) another concurrently-open session.

Root cause: activeQueueSessionKeyRef is written on every render, but the
debounced draft-persist timer, the pagehide flush, and dispatchSubmit's
reject-restore path all read it lazily at async-resolve time instead of
capturing the scope that was active when the operation started. A session
switch landing between capture and resolve relabels one session's text
under the other session's key. A large paste widens the window (slower
synchronous render), which matches the original report.

Fix: introduce draftScopeRef, written only by the draft-swap effect (so it
always reflects the session whose text is actually loaded in the editor)
and read it instead of the render-time ref at both async write sites.
dispatchSubmit's restore() now uses the submittedScope already captured at
dispatch instead of re-reading the live ref.

Also adds isPendingDraftPersistCurrent as defense-in-depth: before the
debounce timer commits a write, it verifies its captured {scope, text}
pair is still the one on file. This is a no-op under the fix above (a
session swap or a newer keystroke already clears/replaces the pending
entry via clearTimeout), but turns any future regression that reintroduces
a stale/live-ref read at this call site into a dropped write instead of a
silent cross-session misroute.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 19:35:05 -07:00
ethernet
5e849942c3 feat(dev): add isolated sandbox script for local dev
scripts/desktop-sandbox.sh runs a Hermes desktop instance in an isolated
sandbox — separate HERMES_HOME, separate Electron userData, and a
distinct
app name (HERMES_DESKTOP_APP_NAME) so it doesn't compete with the main
desktop instance's single-instance lock.

Two modes:
- Ephemeral (default): temp dir, cleaned up on exit
- --persistent: stored under .hermes-sandbox/ in the worktree git root,
  survives restarts for repeat testing

In the Nix devShell the script is available as 'sandbox'.

Also makes APP_NAME overridable via HERMES_DESKTOP_APP_NAME in main.ts —
app.setName() runs before requestSingleInstanceLock(), so the overridden
name changes the lock key. collectRelaunchEnv already preserves
HERMES_DESKTOP_* vars through self-update relaunches; test updated to
cover the new env var.
2026-07-10 18:51:49 -04:00
brooklyn!
291eae63b7
Merge pull request #62016 from NousResearch/bb/desktop-vibe-hearts
feat: vibe reactions — floating hearts on affection, across CLI/TUI/desktop
2026-07-10 16:14:27 -05:00
Brooklyn Nicholson
1fa3886bce chore(desktop): remove the DEV Shift+H heart preview
The real trigger (core `reaction` event on affectionate messages) is live, so
drop the dev-only hotkey and its always-mounted listener.
2026-07-10 16:09:23 -05:00
ethernet
fc977f62bc fix(desktop): remove old .js files
we built .ts into .js for a minute there and dumped em in src, and those
old .js files are getting resolved over top of the ts updated ones so
desktop clients don't update.

just --clean the old files so there's never a conflict :3
2026-07-10 17:05:08 -04:00
ethernet
f7c9feb395 fix(desktop): only show slash popover when / is first char
The SLASH_TRIGGER_RE regex used (?:^|[\s]) as its left anchor, so typing
a / anywhere in the message (e.g. "hello /") opened the slash command
popover — even though slash commands only execute at the beginning of a
message. Anchor the regex strictly at position 0 (^) so the popover only
appears when / is the first character, matching the actual execution
semantics. The @-mention trigger is left untouched since those work
anywhere in the text.
2026-07-10 16:14:50 -04:00
ethernet
b8880f1245 fix(desktop): type-check electron/ in CI typecheck
removing tsc -b from the build script (previous commit) also removed
the only step that type-checked the electron/ directory — the CI
typecheck job runs tsc -p . --noEmit, which uses tsconfig.json whose
include is only ["src", "../shared/src"], so electron/ was silently
uncovered. extend the typecheck script to also run against
tsconfig.electron.json so electron/ stays type-checked in CI.
2026-07-10 14:06:51 -04:00
ethernet
db8772a062 fix(desktop): don't emit js files when we build desktop 2026-07-10 14:06:51 -04:00
Brooklyn Nicholson
3aaf7e3876 feat(desktop): TikTok-style vibe hearts on a reusable particle system
Add a glyph-agnostic ParticleField (float-up + organic sway/bank + springy
pop-in), skinned as pink pixel hearts. Hearts play on the pet when one is out
(in-window or popped out) and celebrate alongside; otherwise they rise from the
composer. A generic $petReaction bus mirrors the burst to the pop-out overlay
window so it reacts even while the app is minimized.

Consume the core `reaction` event to fire hearts on affectionate messages. DEV
Shift+H previews a burst.
2026-07-10 05:42:14 -05:00
Brooklyn Nicholson
29f3dc0809 fix(desktop): stop Tip from sticking open and blocking clicks
Radix's hoverable-content grace area can leave tips stuck over Electron drag regions; disable it and make tip content pointer-events-none so open state tracks the trigger only.
2026-07-10 04:00:32 -05:00
brooklyn!
a9f3f08700
Merge pull request #61916 from NousResearch/bb/desktop-gateway-switch-ux
feat(desktop): soft gateway switch + gateway-settings polish
2026-07-10 03:16:09 -05:00
brooklyn!
79a104d037
Merge pull request #61912 from NousResearch/bb/salvage-55402-desktop-cloud-mode
feat(desktop): Hermes Cloud connection mode (salvage of #55402)
2026-07-10 03:15:59 -05:00
Brooklyn Nicholson
b3bde1fbee feat(desktop): soft gateway switch + gateway-settings polish
Switching connection mode (local / cloud agent / remote) no longer
full-window-reloads into the cold-boot CONNECTING screen. The primary
backend is torn down in place (no renderer reload); the shell + Settings
stay up while session lists are wiped so sidebar skeletons retrigger, then
the socket re-dials and config/sessions refresh. Cold-boot CONNECTING
latches off after the first successful boot; the intentional teardown
suppresses the backend-exit toast. Dev affordance: a "Preview soft switch"
button under Gateway diagnostics (Electron has no ?query= entry).

Gateway settings UI brought in line with the rest of Settings:
- Mode cards use the shared selectableCardClass on an equal-height
  auto-rows-fr grid, stacking 1→3 (never an orphaned 2+1); titles wrap
  instead of truncating.
- Remote gateway's auth detail moves into a ? tooltip in the title; drop
  the redundant "connects to the one you choose" from the cloud card.
- textStrong buttons force px-0 so the underline sits flush with the label.
- Tooltip chip uses box-decoration-break: clone so the background hugs each
  wrapped line (bg only on the text), capped at max-w-64.

Fully i18n'd (en + zh; ja/zh-hant inherit via defineLocale).
2026-07-10 02:57:02 -05:00
Brooklyn Nicholson
6207d68948 fix(desktop): prevent bootstrap stale commit repin on existing checkouts
Old packaged Desktop apps re-entering bootstrap against an existing
~/.hermes/hermes-agent were still passing the baked-in --commit pin, which
detached the managed checkout back to the app stamp (e.g. 0.15.1) after
hermes update had already moved it forward.

Skip the packaged commit pin when activeRoot already has git metadata;
keep branch args and fresh-install commit pinning unchanged. Port of
#59902 onto the post-ts-ify bootstrap-runner.ts.

Co-authored-by: helix4u <4317663+helix4u@users.noreply.github.com>
2026-07-10 02:29:58 -05:00
Brooklyn Nicholson
57dfebe3db fix(desktop): re-apply UI zoom on show/restore, scoped to chat windows
Windows drops webContents zoom on minimize/restore, so the UI snapped back
to 100% while Settings still read 125%. Zoom was only reasserted on the main
window's did-finish-load, never on show/restore and never for session windows.

Reassert the persisted level on show/restore + first load, wired once in
wireCommonWindowHandlers so the main window and secondary session windows
share it. The pet overlay opts out (zoom:false): it sizes its own OS window
to fit the sprite in unzoomed CSS px and has its own Alt+wheel scale, so
inheriting the global zoom would render the mascot larger than its window and
crop it (and it shares the renderer origin's zoom localStorage key).

Salvages #61245; keeps its pure-helper tests and adds a scope assertion.

Co-authored-by: HexLab98 <liruixinch@outlook.com>
2026-07-10 02:13:10 -05:00
Brooklyn Nicholson
24f6ed53fc simplify(desktop): inline the cloud setup link like the rest of the app
Match the sibling pattern (pet-generate/generate-unavailable.tsx): inline the
portal URL literal in the ExternalLink href instead of a one-off named const.
2026-07-10 02:01:40 -05:00
Brooklyn Nicholson
1c7f31a577 simplify(desktop): hardcode the Hermes Cloud setup link
Drop the portalBaseUrl→IPC→useState plumbing I added for the "create an agent"
link. HERMES_PORTAL_BASE_URL is a dev/staging-only override; threading it
through cloud.status() into React state just to build one link isn't worth it —
in prod it's always portal.nousresearch.com. Module-level constant instead.
2026-07-10 01:59:47 -05:00
Brooklyn Nicholson
703487d7a6 feat(desktop): point the no-agents link at the Hermes Cloud instance-setup page
Per review: the empty-state "create an agent" link went to the generic portal
agents list; point it at the Hermes Cloud create-instance flow
({portal}/cloud?setup=instance) instead. Derive the host from the portalBaseUrl
that cloud.status() already echoes so it honors HERMES_PORTAL_BASE_URL rather
than hardcoding a second copy of the portal host. Link text/copy → "Hermes
Cloud" (en + zh).
2026-07-10 01:55:44 -05:00
Brooklyn Nicholson
0ff097439e refactor(desktop): DRY the cloud helpers
Tighten the salvaged Hermes Cloud code with no behavior change:
- main: one `trimCloudOrg` projection reused by the success-echo and the 409
  org list (drop the duplicated map), and a `cloudLoginError()` factory for the
  three needsCloudLogin throw sites.
- renderer: a `cloudLoginLapsed()` predicate for the duplicated
  needsCloudLogin→signed-out check.
2026-07-10 01:47:46 -05:00
Brooklyn Nicholson
2d315d30f8 polish(desktop): normalize cloud-URL highlight match + correct signedIn doc
Cleanups on top of @ben's Hermes Cloud salvage:
- isConnectedAgent normalized both sides of the cloud-URL comparison (trim +
  drop trailing slash + lowercase). The saved URL is host-lowercased by
  normalizeRemoteBaseUrl but the discovered dashboardUrl is raw from NAS, so
  a host-casing difference could silently break the connected-highlight.
- DesktopCloudStatus.signedIn doc said "AT-or-RT"; it actually reflects the
  Nous portal Privy session (privy-token), not the gateway cookies.
2026-07-10 01:37:54 -05:00
Ben
c101207b99 feat(desktop): Hermes Cloud connection mode — one sign-in, agent discovery, silent connect
Adds a third "Hermes Cloud" gateway mode to the desktop app: one portal
sign-in auto-discovers the agents on your account and connects to any of
them with no second interactive prompt.

- Electron: widen connection mode to 'local' | 'remote' | 'cloud', routed
  through a centralized modeIsRemoteLike() so every resolution site treats
  cloud exactly like remote; portal discovery (GET /api/agents over the
  OAuth partition), Privy-cookie liveness, multi-org picker (NAS 409), and a
  silent per-agent /oauth cascade (load protected root, not /login).
- Persist a cloudOrg on the cloud block; unselect cloud on mode switch.
- Renderer: Hermes Cloud ModeCard + agent picker (signed-out/loading/empty/
  list), org picker, Change-org, connected-highlight + Connected pill.
- i18n (en + zh full; ja/zh-hant inherit via defineLocale), Cloud icon.
- IPC: hermes☁️{status,login,logout,discover,agent-sign-in}.

Salvage of #55402 onto current main: the original branch predates the
desktop electron .cjs -> .ts migration (39d09453f), so the electron half
was re-authored against the .ts files. Authorship preserved.

cloud-auto-discovery Phases 3 + 4.
2026-07-10 01:37:43 -05:00
Brooklyn Nicholson
bf913abc2e fix(desktop): stop using tsx to boot Electron main in dev
Electron 40 ships Node 24.15, where tsx's ESM load hook returns null and
crashes with ERR_INVALID_RETURN_PROPERTY_VALUE. Bundle main+preload via
esbuild for `npm run dev` and always load the JS preload from dist/.
2026-07-08 22:40:51 -05:00
ethernet
56a8e81d33 cleanup(desktop): npm run fix for fmtting
we should run this as part of merges at some point :)
2026-07-08 16:24:16 -07:00
ethernet
7a65530fa5 fix(js): set @types/node to node 22, what's required in "engines" 2026-07-08 16:24:16 -07:00
ethernet
39d09453f9 feat(desktop): ts-ify everything 2026-07-08 16:24:16 -07:00