Commit Graph

23151 Commits

Author SHA1 Message Date
SHT
5c290caa9c test(cron): pin the eager NUL rejection contract for _run_job_script (#86829) 2026-08-16 06:29:03 -07:00
SHT
40586082e5 fix(cron): reject NUL-bearing script paths before any Path call (#76762 class)
_run_job_script wrapped only expanduser() in its ingestion try/except.
On Linux an unexpandable NUL-bearing value raises inside that call, so it
landed on the clean fail-with-report path; on Windows expanduser() never
expands '~user' (and so never raises), and the NUL surfaces later as an
uncaught ValueError from resolve()/exists() — crashing the scheduler.

Align with cron.lifecycle_guard._expand_candidate_path, which already
documents this as the whole-class fix (the per-syscall catching produced
#76762, #77703, #77780, #78256): reject '\\x00' eagerly at the ingestion
boundary so both platforms fail identically.
2026-08-16 06:29:03 -07:00
Eva
089b437b35 fix(tui): stop queued dispatch after session close 2026-08-16 06:26:37 -07:00
Eva
ad85feec43 fix(tui): settle session close against active turns 2026-08-16 06:26:37 -07:00
QDung210
0a1cca5648 refactor(gateway): share breakaway marker constant 2026-08-16 06:26:12 -07:00
QDung210
b921fdd886 fix(gateway): improve Windows detach diagnostics 2026-08-16 06:26:12 -07:00
Darko Mesaroš
a7253a6c02 fix(cli): deliver the Bedrock API key through a named provider
The Bedrock API-key flow stored the bearer token in OPENAI_API_KEY and set
a bare `provider: custom`. Since #28660 that variable is only honoured for
openai.com hosts, so for bedrock-mantle.*.api.aws the token was dropped and
requests went out with api_key="no-key-required", a 401 on every call.

Write a named `providers.bedrock-mantle` entry with
key_env: AWS_BEARER_TOKEN_BEDROCK instead. The named-provider branch in
runtime_provider.py resolves key_env; the bare-custom branch cannot.

Fixes authentication only. Per-model mantle route selection is separate.
2026-08-16 06:25:46 -07:00
Yasushi Fukutake
b44f956dff fix(desktop-update): put --daemonized ahead of ORIGINAL_ARGS in posix.sh re-exec
Appending --daemonized after ORIGINAL_ARGS put it past the `--`
relaunch-args separator on Linux, so it was absorbed into
RELAUNCH_ARGS instead of being parsed as a flag. HANDOFF_DAEMONIZED
never got set, so the one-shot self-detach block re-fired on every
re-exec -- an unbounded self-exec loop (thousands of iterations/sec,
100%+ CPU, argv growing until execve fails with E2BIG) whenever
relaunch args were present, which is the normal invocation shape on
Linux.

Fixes #86957

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-16 06:25:21 -07:00
Merge_Conflict - Pasi
309cf2c5e2 fix: honor JSON-array string forms for skills.disabled and agent.disabled_toolsets
`hermes config set` and JSON-mode editor saves store lists as quoted
strings (e.g. '["skill-a","skill-b"]' or "['memory']"). Both disable
filters treated such a string as a single name, so curated disable
lists silently filtered nothing with zero diagnostics.

Add parse_config_string_list() in agent.skill_utils and use it in
_normalize_string_set (skills.disabled / platform_disabled) and at
every agent.disabled_toolsets read site: tools_config resolve +
reconcile, CLI, gateway agent construction (both sites), cron
scheduler, and prompt_size. A scalar string still names a single
entry (#13026); malformed JSON falls back to the single-name
behavior instead of raising.

Fixes #86661
2026-08-16 06:24:56 -07:00
3Nya3
bd0586e062 fix(update): surface config mutations applied silently during version-bump-only updates 2026-08-16 06:24:31 -07:00
SHT
58d6bf2d61 fix(cron): log and document the .pth bootstrap fallback (#86816 review)
- WARN when the venv site-packages layout is unresolvable and the script
  falls back to plain PYTHONPATH execution, so 'editable installs
  invisible' failures are diagnosable.
- Docstring: note that runpy does not set __package__/__spec__ the way a
  direct python script.py invocation does.
2026-08-16 06:24:06 -07:00
SHT
029a0d8c76 fix(cron): process .pth files for Windows uv-venv script jobs (#86567)
_windows_cron_python_invocation bypasses the uv venv launcher (to avoid
flashing a console window) and re-attaches the venv via PYTHONPATH — but
PYTHONPATH entries are plain sys.path additions and never get .pth
processing, so editable installs (pip install -e) were invisible to cron
script jobs (ModuleNotFoundError).

Bootstrap the script with site.addsitedir() on the venv site-packages,
then exec it as __main__ via runpy.run_path, preserving the script
directory on sys.path (python script.py semantics). Falls back to a
plain invocation when the venv layout is unresolvable.
2026-08-16 06:24:06 -07:00
kshitij
56526bc0d3 Merge pull request #87630 from kshitijk4poor/fix/kitty-extended-keys-proper
fix(cli): restore Kitty keyboard protocol push and complete the extended-key alias table
2026-08-16 15:57:33 +05:30
kshitij
03bf85d83b fix(cli): restore Kitty keyboard protocol push and complete the extended-key alias table
Commit 4c34eeb416 fixed dead Ctrl+C by removing the Kitty protocol push
(CSI >1u) from _EXTENDED_ENTER_KEYS_SEQ, keeping only modifyOtherKeys
level 2. That regressed kitty-the-terminal completely: kitty removed
xterm modifyOtherKeys support (kovidgoyal/kitty#4075) and only speaks
its own protocol, so after the removal kitty users lost Shift+Enter and
every other extended key — the CSI >4;2m we still pushed is a no-op
there (kitty even logs a PARSE ERROR for it).

The original reason for removing the push is obsolete: #87511 mapped
CSI-u control sequences, so Ctrl+C as ESC[99;5u now parses to
Keys.ControlC and fires the existing c-c binding. (The kernel-INTR
concern in that commit was moot — prompt_toolkit's raw mode clears
ISIG, so Ctrl+C is always handled by the binding, never the kernel.)

Restore the dual push (CSI >1u + CSI >4;2m), exactly mirroring the Ink
TUI, and complete the alias table for what the kitty disambiguate flag
actually emits — #87511 left real gaps, some of which its PR body
wrongly claimed were covered:

- Esc key: ESC[27u (+ modifiers) — previously leaked '[27u' as text
- Ctrl+Backspace -> backward-kill-word (#78285 was closed on the wrong
  claim that codepoint-127 mapping existed; it did not)
- Shift+Space -> space (#86866's second symptom; the Ctrl+Space
  mapping never covered modifier 2)
- Alt+Enter -> newline tuple; Shift+Tab -> BackTab; Ctrl+Tab -> Tab;
  Alt/Shift+Backspace
- Multi-modifier letters (Shift+Alt 4, Ctrl+Shift 6, Ctrl+Alt 7,
  Ctrl+Alt+Shift 8) normalized onto their Ctrl/Escape-prefix targets,
  both unshifted (kitty) and shifted (mok emitters) codepoints
- Kitty PUA functional keys: keypad -> non-keypad equivalents,
  F13-F24, and Ignore for lock/media/modifier-event keys so they are
  consumed instead of leaking (kitty emits these even in legacy mode)

Also: clear the VT100 parser's prefix cache after installing (stale
answers could misparse), and re-push extended keys after
_recover_terminal_input_modes' reset — the recovery previously popped
both modes mid-session and never re-enabled them, silently killing
Shift+Enter until restart.

Refs #87511, #87074, #56684, #56645, #78285, #86866, #87390.
2026-08-16 15:52:24 +05:30
Teknium
f4c80e4243 fix(desktop): recycle live backends and sockets when a connection edit changes its target
saveRegistryConnection only rewrote the registry file: editing a
connection's URL/token/host left pooled backend descriptors under
'conn:<id>::*' and open renderer sockets pointing at the OLD endpoint —
the UI showed the new target while traffic kept flowing to the old one
until idle-reap.

When a save MATERIALLY changes an existing connection (endpoint / auth /
ssh routing fields, via the new connectionDialFieldsChanged helper),
main now stops that connection's pooled backends and tunnels
(stopRegistryConnectionBackends, same teardown as removal) and
broadcasts 'hermes:connections:changed' with reason 'updated' so
renderers dispose and re-dial their secondaries at the new target.
Label-only renames do not recycle.
2026-08-16 03:17:39 -07:00
Teknium
28c729e68f fix(desktop): tear down renderer secondaries when a registry connection is removed
Removing a connection stopped its pooled backends and ssh tunnels but
never told the renderer: for remote/cloud sources there is no local
process to die, so the removed connection's WebSocket stayed open and
kept streaming ghost events into the UI until page reload. If the
socket did drop, openSecondary -> getConnectionFor threw 'No connection
with id' and scheduleReconnect retried forever (backoff caps at 15s,
entry never evicted).

- main now broadcasts 'hermes:connections:changed' on removal (and on
  material edits); preload exposes connections.onChanged.
- use-gateway-boot subscribes and calls the new
  disposeSecondariesForConnection(), which disposes + evicts every
  secondary scoped to the connection id (redialing on edits).
- reconnectSecondary fail-stops: when the Electron main reports the
  connection no longer exists, the entry is disposed and evicted
  instead of retrying forever; ordinary transport errors keep the
  existing backoff behavior.
2026-08-16 03:17:39 -07:00
Teknium
9e062912b9 fix(desktop): exclude process-less descriptors from backend pool LRU cap
Remote/cloud registry descriptors (entry.process === null) shared the
POOL_MAX_BACKENDS cap with real spawned local backends, so a roster
refresh across N registered remote connections could LRU-evict a live
local backend idle past the keepalive window. Cap accounting and
cap-driven eviction now count only entries with a live child process;
descriptors remain subject to the idle reaper.
2026-08-16 03:17:39 -07:00
Teknium
6ce7922af1 chore: map contributor email for focused-session atoms salvage 2026-08-16 03:15:27 -07:00
lepetitprince716-prog
5fa092b481 fix(desktop-sdk): address adversarial review — type honesty, real tile coverage, docs
Independent second-pass review found three gaps:

- focusedUsage is null | UsageStats, not Partial — ClientSessionState.usage
  is the full type (app/types.ts) and its only write site seeds the four
  required fields before merging (gateway-event.ts). The earlier Partial
  annotation traced the wrong type (SessionRuntimeInfo, an RPC payload).
  Comment now names the genuinely optional fields instead.
- The tile-focus contract test never seeded $sessionTiles/$sessionStates,
  so it proved focusedStoredSessionId follows a tile but could not
  distinguish focusedSessionId/focusedUsage working from broken. Seed a
  bound runtime with distinct usage and assert both readout atoms move.
- The two public host.state references (website docs + bundled skill
  reference) enumerated the old six atoms; plugin authors would never
  discover the new ones. Both lists updated.

tsc/eslint/vitest green (4/4).
2026-08-16 03:15:27 -07:00
lepetitprince716-prog
a445a81279 fix(desktop-sdk): type focusedUsage as Partial<UsageStats>, fix expect arity
ClientSessionState.usage is Partial<UsageStats> (app/types.ts) — the
backend streams whichever fields changed — so the computed produces
ReadableAtom<Partial<UsageStats> | null>. Annotate the entry honestly
instead of claiming full UsageStats, and document the fallback rule for
plugin authors. Also collapse the three-argument expect() calls in the
contract test (vitest takes one message arg). Addresses triage review on
PR #80461.
2026-08-16 03:15:27 -07:00
lepetitprince716-prog
74b7d5da2d test(desktop-sdk): contract-test the focused-session host.state atoms
Locks the plugin-facing contract: the focused atoms exist as readonly
nanostores, mirror the primary session while no tile is focused, project
the focused session's usage, and — the behavior this PR exists for —
follow the interacted tile while the primary-only $activeSessionId
stays put.
2026-08-16 03:15:27 -07:00
lepetitprince716-prog
68bd8befd2 feat(desktop-sdk): expose focused-session state atoms to plugins
Disk plugins read app state exclusively through host.state, which only
exposed the primary workspace tab ($activeSessionId). In the multi-tile
layout, clicking a tile never touches that atom — and tile focus is a
pure renderer concern, invisible to both gateway RPC and the event
stream — so a plugin cannot follow the session the user is actually
looking at.

The core statusbar solves this same problem by reading the focused-
session atoms (use-statusbar-items.tsx). Widen the generic plugin
surface with the same signals, per the contribution rubric:

- host.state.focusedSessionId — runtime id of the focused session
  (interacted tile, else the primary), the key for session.* RPC
- host.state.focusedStoredSessionId — durable id for navigation and
  session-list matching
- host.state.focusedUsage — live streamed UsageStats projection
  (context_used/max/percent, tokens, cost_usd), no RPC needed

Additive only; no existing behavior changes. tsc --noEmit clean.
Verified end-to-end with a disk plugin that now tracks the focused
session across tiles.
2026-08-16 03:15:27 -07:00
Cary Palmer
be38224b49 fix(desktop): lint and map contributor email for running-is-not-busy
Drop the redundant Boolean() on selected in $primaryBusy and add the
professorpalmer9@gmail.com mapping so attribution CI can resolve the PR.
2026-08-16 03:01:45 -07:00
Cary Palmer
3bc52fb9df feat(desktop): running is not busy
Gate composer submit and plugin host busy on the target session slice, not a leftover foreground busyRef. Staff can keep typing while a worker session is running.

Includes the follow-up test that submit uses the target session busy flag.
2026-08-16 03:01:45 -07:00
Teknium
1e54e05227 feat(desktop): paste-anything MCP server import
Add a compact Import popover to the MCP Capabilities page that accepts
anything a user might copy from an MCP server README and infers the
server config:

- mcp.json snippets (mcpServers-wrapped, bare name->config maps, single
  unnamed server objects, Cursor/Claude `type` normalized to `transport`)
- bare npx/bunx/uvx/node/docker command lines (name inferred from the
  package basename, e.g. server-filesystem -> filesystem)
- `claude mcp add NAME [--transport http|sse] [-e K=V] [-H ...] [--] CMD
  ARGS...` and `claude mcp add NAME URL`
- bare http(s) URLs (name inferred from the hostname)
- Cursor deeplinks (cursor://anysphere.cursor-deeplink/mcp/install with
  a base64-encoded JSON config payload)

The parser is a pure module (src/lib/mcp-import.ts) with unit tests for
every format plus garbage input. The popover previews the inferred
name + config and, on confirm, merges the entries into the editor draft
exactly like addServer's starter entry: unique keys, dirty (unsaved)
draft, first new block focused. Placeholder env values (YOUR_KEY,
TOKEN_HERE, ...) are kept verbatim for the user to edit in the editor
before saving.

i18n keys added under settings.mcp for en, zh, zh-hant, ja (ar falls
back through defineLocale).
2026-08-16 02:46:57 -07:00
Teknium
28fc9d9c0d fix(desktop): make plugin SDK turn flags follow the focused chat
Follow-up to the salvaged #87558 commit: the PR's docs promised the flags
follow "the focused chat", but PRIMARY_SESSION_VIEW is the primary
workspace tab only — a focused session TILE would read the wrong chat.
Wire host.state.busy / host.state.awaitingResponse through the focused
slice ($focusedStoredSessionId / $focusedSessionState), same semantics
as the statusbar busy pulse, with the primary view (and its draft
fallback) while the workspace holds focus.

Adds a tile-focus vitest case and corrects the docs wording.
2026-08-16 02:44:54 -07:00
Adolanium
0a9337d2bb feat(desktop): expose busy turn flags on plugin SDK
Plugins can now read host.state.busy and host.state.awaitingResponse
for the focused chat. These follow the same session slice the chat pane
uses, so a draft falls back to the global flags and a background turn
does not leak.
2026-08-16 02:44:54 -07:00
Teknium
39bf984765 fix(desktop): sync connection atoms and share the switch mutex for agent activation
ensureGatewayForAgent (the SDK ensureAgent door) skipped the two invariants
the profile path provides:

- $connection / $activeGatewayProfile were only updated when a socket was
  freshly dialed (setConnection inside openSecondary), so activating an
  ALREADY-OPEN registry agent left both describing the previous backend —
  /api/fs, /api/media and image.attach routed to the wrong machine (same
  class as #46651) and newSessionInProfile targeted the stale profile.
- Activations bypassed the gatewaySwitch mutex, so a rapid agent/profile
  interleave could complete out of order with the earlier setActive()
  landing last.

Add profile.ts ensureGatewayAgent: the (connectionId, profile) analogue of
ensureGatewayProfile that shares the same gatewaySwitch mutex, moves
$activeGatewayProfile on every activation, and resyncs $connection from
getConnectionFor (best-effort, like the profile path). The SDK ensureAgent
now routes through it; local/null connectionId falls through to the
profile path unchanged.
2026-08-16 02:44:48 -07:00
Teknium
45398957b7 fix(desktop): never resolve a missing named gateway scope to the primary
activeGateway() fell back to the primary gateway when the active key named
a registry-agent scope (conn:<id>::<profile>) whose secondaries entry had
been evicted — e.g. closeSecondaryGateways() during a soft gateway switch —
so sends and session ops silently executed against the WRONG machine.

A named scope now resolves to its own socket or null, and every eviction
path (closeSecondaryGateways, pruneSecondaryGateways) explicitly restores
the primary as active when it evicts the active scope, keeping the
'activeKey always resolves' invariant with the atoms following.
2026-08-16 02:44:48 -07:00
Teknium
ea2daa0935 docs: full multi-gateway setup guide for Hermes Desktop
Expand user-guide/multi-connection-desktop.md into a complete setup
walkthrough: where to find the pane (settings nav, profile-rail plug,
command palette), the exact add-connection editor fields (Name,
Gateway URL, Authentication: Session token/OAuth, SSH host), Primary /
This device pills, Test semantics, agent roster + profile-rail
switching and per-profile session/cron/messaging scoping, token
storage via Electron safeStorage with the keyring-less Linux plain-
text opt-in, and troubleshooting. All quoted labels match the desktop
i18n strings. Cross-link the rail entry point from desktop.md.
2026-08-16 02:44:21 -07:00
Teknium
34271eb069 feat(desktop): make the multi-gateway Connections registry discoverable
The multi-connection registry (Settings -> Connections) shipped with no
entry point outside the settings nav, and the product-owner report was
blunt: 'I didn't see any obvious way to hook up multiple gateways.'

- Profile rail: a plug pill pinned beside Manage ('Connect another
  Hermes gateway...') deep-links to /settings?tab=connections. Always
  visible, including for single-profile first-run users.
- Command palette: Settings -> Connections is now a searchable entry
  (keywords: add gateway, remote, ssh, cloud, instances, registry).
- i18n: profiles.connectGateway added to en/types/zh; other locales
  fall back through defineLocale.
- Tests: profile-rail-connect.test.tsx covers the deep link and the
  single-profile visibility guarantee.
2026-08-16 02:44:21 -07:00
Teknium
6c745e81ae fix(tools-config): stop reconfigure flow clobbering image_gen.use_gateway on managed FAL rows
The Nous Subscription image_gen row carries imagegen_backend="fal", so
_reconfigure_provider's post-model-picker step ran

    img_cfg["use_gateway"] = False

unconditionally at two sites, immediately after the managed branch had
written use_gateway=True. A user who picked Nous Subscription and then
re-entered `hermes tools` to change the model was silently flipped onto
their personal FAL_KEY.

Same bug class as fe63353cb, which fixed the plugin-provider selector
but missed these two legacy-backend sites in the reconfigure flow. Both
now write bool(managed_feature), matching the existing correct site in
_configure_provider.

Adds regression tests driven through the real TOOL_CATEGORIES managed
row; sabotage-verified (tests fail with the old behavior restored).
2026-08-16 02:44:18 -07:00
David Dudok de Wit
58a9062f60 fix(desktop): resolve sessions from sidebar caches
Consult messaging and cron caches before the by-id fallback so opening a sidebar row neither depends on a redundant network lookup nor duplicates it into regular recents.

Co-authored-by: protas-box <protas.box@icloud.com>
2026-08-16 02:44:08 -07:00
David Dudok de Wit
4e4d37f6bf fix(desktop): harden profile-scoped refreshes 2026-08-16 02:44:08 -07:00
David Dudok de Wit
4f670a3f95 fix(desktop): reject stale profile refreshes 2026-08-16 02:44:08 -07:00
David Dudok de Wit
8477a5a83d docs(desktop): document profile scope helpers
Add JSDoc to the exported helpers introduced by the profile-scoped sidebar change.
2026-08-16 02:44:08 -07:00
David Dudok de Wit
a0f22234bc fix(desktop): ignore stale messaging page responses
Sequence per-profile platform pagination so an older overlapping response cannot replace a newer, larger page.
2026-08-16 02:44:08 -07:00
David Dudok de Wit
1f24b3ed2e fix(desktop): retain messaging totals per profile
Key resolved platform totals by Desktop profile and source so profile switches neither inherit another profile's count nor discard a count that was already resolved. Keep the full reset for connection configuration changes.

Co-authored-by: frendo <frendo.wu@gmail.com>
2026-08-16 02:44:08 -07:00
David Dudok de Wit
e264b48394 fix(desktop): scope messaging to active remote profile
Complete the sidebar profile-scope contract across remote Electron routing, older-backend fallbacks, standalone messaging refreshes, and pagination. Reject stale profile responses and keep the explicit all-profiles view unified.

Co-authored-by: 墨綠BG <s5460703@gmail.com>

Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
2026-08-16 02:44:08 -07:00
hermes-seaeye[bot]
0a3e61cf07 fmt(js): npm run fix on merge (#87607)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-16 09:43:56 +00:00
Teknium
1c3fbd21ae feat(desktop): background MCP health checks with re-auth nudges
MCP server problems (expired OAuth tokens especially) were only
discovered when the user visited the MCP page and a probe ran. Now a
renderer-side background checker (store/mcp-health.ts) sweeps the
active profile's enabled HTTP/SSE MCP servers on gateway connect and
every 30 minutes, and fires an in-app notification with a "Sign in"
action ("<name> MCP needs re-authentication") that navigates to the
MCP page with ?server=<name> so useDeepLinkHighlight focuses the
server and its Authenticate button. Navigation only — OAuth flows are
never auto-launched.

stdio servers are deliberately excluded: probing a stdio server SPAWNS
a local process, so a background timer must never touch them. Only
url-shaped servers (where OAuth expiry lives) are swept, sequentially.

The tab's probeCache/serverFingerprint/probeKey/NEEDS_AUTH_RE moved to
a shared lib/mcp-probe-cache.ts (behavior identical) so the page and
the checker share one probe cache and its 5-minute TTL — neither
surface re-probes what the other just learned.

Notifications fire only on a TRANSITION into needs-auth/error (pure
state machine, unit-tested), hard-capped at one per server per app
session, keyed per profile. Profile switches drop pending timers and
re-arm for the new profile; sweeps never run while the gateway is
disconnected. No new config knobs. i18n keys added across
en/zh/zh-hant/ja/ar + types.
2026-08-16 02:36:54 -07:00
hermes-seaeye[bot]
5d33efd990 fmt(js): npm run fix on merge (#87599)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-16 09:32:26 +00:00
Teknium
56eafcff3c feat(desktop): hermes:// deep link to install MCP servers with explicit confirmation
Adds hermes://mcp/install?name=NAME&config=B64 (base64url or standard
base64 JSON), mirroring Cursor's mcp/install deep link, so vendors and
docs can offer an "Add to Hermes" button.

- Electron: the existing generic hermes:// handler already forwards
  {kind, name, params}; only its comment is updated (no new handler).
- Renderer: use-desktop-integrations routes kind=mcp/name=install into
  a pending-install store; a new confirmation dialog shows the server
  name and the FULL pretty-printed config (attacker-controllable input),
  with a prominent caution for stdio command entries. Nothing is written
  until the user confirms; existing names require a rename or cancel.
  On confirm the server is merged over a fresh fetch of the current map
  via saveMcpServers, then navigation lands on /skills?tab=mcp&server=…
  so useDeepLinkHighlight focuses the new row.
- Validation: name ^[A-Za-z0-9._-]{1,64}$; config must decode to an
  object with a string http(s) `url` or a string `command` (never both);
  payloads over 32KB rejected; failures surface as a toast.
- Pure parser in src/lib/mcp-deeplink.ts with unit tests (url shape,
  command shape, bad base64, non-object, javascript: URL, oversized).
- i18n keys in types + en/zh/zh-hant/ja/ar.
- Docs: "Add to Hermes link" section in the MCP config reference.
2026-08-16 02:25:14 -07:00
rainbowgits
3e0bf6dcaa fix(desktop): hoist GatewayMock type into #82462 edit recovery suite
CI typecheck failed because GatewayMock lived only in the previous describe.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-16 02:24:40 -07:00
rainbowgits
e14b095f20 fix(tui): map lineage edit ordinals past compression prefix
Desktop/TUI count full displayed lineage after compression, but
prompt.submit validated truncate ordinals against tip-only history.
Translate via display_history_prefix and recover stale 4018s on Desktop.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-16 02:24:40 -07:00
Teknium
e22fa90769 feat(desktop): MCP fleet cost/usage overlay with schema token estimates and 30-day usage
Each configured server row on the MCP Capabilities page now shows what it
costs and whether it earns its keep:

- ~per-call token estimate of the server's tool schemas, summed over ENABLED
  tools only (ceil(schema_chars/4) via the existing include/exclude filter)
- 30-day usage count from getUsageAnalytics(30), cached per scope profile
  like the Toolsets tab's toolCallsCache, mapped to servers via the
  mcp__<server>__<tool> registry-name convention (tools/mcp_tool.py)
- a subtle muted "unused" pill on enabled, probed-ok servers with nonzero
  schema cost and zero 30-day uses — never a dialog

Backend: the /api/mcp/servers/{name}/test probe now fills an additive
per-tool `schema_chars` (length of the SAME converted registry schema the
agent registers). Older backends omit it → renderer shows counts only;
older renderers ignore the extra key. Display-only: nothing changes what
schemas are sent to models, no config knobs.

i18n keys (costTokens/usage30d/unusedPill) added to types/en/zh/zh-hant/ja
(ar inherits en via defineLocale overrides). Pure math lives in
lib/mcp-cost.ts with unit tests; Python wire shape pinned in
tests/hermes_cli/test_web_server_profile_unification.py.
2026-08-16 02:24:32 -07:00
Teknium
577093def2 perf(desktop): hydrate transcripts with a small tail page + on-demand older-page backfill
Replace the fixed 500-message REST hydration (getLatestSessionMessages)
with a 120-row newest-first tail page. When the page comes back full, a
new per-session tail store records "possibly truncated + next offset";
"Show earlier" — once the DOM budget and the in-memory store window are
both exhausted — fetches the next older page via the new
getOlderSessionMessages helper (order latest + offset, matching the
backend's back-from-newest paging semantics) and prepends it to the
session store, deduped by durable row id and race-guarded against
session switches. Legacy backends without pagination metadata fall back
to the one-shot full transcript and retire the action.

Tail-page refreshes (background sync, post-turn rehydrate, re-activate,
cold-resume prefetch) graft the refreshed tail onto any backfilled
prefix instead of clobbering it, preserving reference identity on
no-ops. includeCompacted stays on every read — compaction-archived rows
remain part of the durable display history.
2026-08-16 02:24:25 -07:00
Teknium
c6db20726a fix(desktop): give Windows start-marker PowerShell probe a 30s budget
PowerShell 5.1 cold starts take 2.4-8s on affected Windows hosts, so the
shared 3s execText timeout hard-failed the parent start-marker probe for
any PID that still needs the PowerShell path (e.g. backend children).
Make execText's timeout overridable and raise the marker probe to 30s.

Fixes #87169
2026-08-16 02:14:35 -07:00
yu-xin-c
c3d74603aa fix(desktop): avoid PowerShell parent marker boot gate 2026-08-16 02:14:35 -07:00
Teknium
f325008ebf chore(contributors): map emails for P2-sweep salvage wave 2026-08-16 02:13:05 -07:00