Commit Graph

28271 Commits

Author SHA1 Message Date
brooklyn! 9dd7ac670a Merge pull request #75126 from NousResearch/bb/terminal-links
Open links clicked in the integrated terminal
2026-07-30 21:58:20 -05:00
Brooklyn Nicholson 193e5f84f7 fix(desktop): the main tab can be closed by gesture and menu
The tab strip decided the close gesture from the `uncloseable` flag, which the
workspace sets to keep its pane in the tree — so the one tab whose close now
does something couldn't be ⌘-clicked or middle-clicked, and its right-click
menu had no Close.

Read the gesture off the pane's registered closer instead, with the workspace
registering closeWorkspaceTab. An atom rather than a lookup, since that closer
comes from a wiring effect that lands after the strip's first paint.
2026-07-30 21:43:15 -05:00
Brooklyn Nicholson c7b021ca48 fix(desktop): closing the last main tab lands on New session
The workspace pane can't leave the tree, so "close the main tab" only ever had
one answer wired: shift the next stacked session in. With main as the only tab
there was nothing to shift and ⌘W dead-ended on the tab the user was looking
at.

closeWorkspaceTab is now the one answer for every entry point — stacked
session still wins, and with nothing stacked main drops to a fresh New session
draft. A blank draft and a full-page view stay no-ops: a blank draft already
IS the post-close state.
2026-07-30 21:43:15 -05:00
Brooklyn Nicholson 463fbf5b16 fix(desktop): middle-click works on a real three-button mouse
Chromium on Windows and Linux answers a middle press inside a scroller by
starting the autoscroll pan, and the mouseup that ends the pan never becomes
an auxclick. Every surface carrying the gesture — tab strips, the session
list, the terminal rail — is a scroller, so middle-click only ever worked on
macOS, where autoscroll doesn't exist.

Arm on pointerdown, spend on the pointerup over the same element (press one
tab, release on another and nothing happens), and cancel the middle mousedown
on every press so the pan widget can't appear on a surface that owns the
button. One helper, four call sites.
2026-07-30 21:43:14 -05:00
Brooklyn Nicholson 4d6589c69c fix(desktop): stop ⌥-click spraying cursor escapes into the terminal
⌥-drag is the app's force-selection gesture over mouse-mode TUIs, but
xterm's default alt-click-moves-cursor claims the same click and emits one
cursor left/right escape per column of travel. Shells that don't consume
them echo the raw `^[[D` burst into the buffer. One gesture, one meaning.
2026-07-30 20:51:40 -05:00
Brooklyn Nicholson 0cec9896a1 fix(desktop): open links clicked in the integrated terminal
Both of xterm's link paths activate through `window.open()`, which the
window's setWindowOpenHandler denies, so ⌘-clicking a URL did nothing but
log "Opening link blocked as opener could not be cleared" — and the OSC 8
path fronted that dead end with a raw confirm() dialog. Route both through
the desktop bridge, the path every other external link in the app takes.

⌘-click on macOS, Ctrl-click elsewhere, matching VS Code's integrated
terminal, Terminal.app, and iTerm2. A bare click stays with the selection so
a misclick on a URL can't launch a browser.
2026-07-30 20:51:09 -05:00
ethernet a3fdc189a4 fix(sec): update httplib2 to 0.32.0
httplib2 0.31.0 has a known vulnerability PYSEC-2026-3444

it's fixed in >= 0.32.0
2026-07-30 21:36:47 -04:00
ethernet 9bdfa9f36e fix(sec): update cbor2 to 6.1.3
cbor2 5.8.0 has a known vulnerability PYSEC-2026-2123

it's fixed in >= 5.9.0
2026-07-30 21:36:47 -04:00
ethernet e9f64e83c1 fix(sec): update setuptools to 83 2026-07-30 21:36:47 -04:00
Teknium cc4cab2f59 chore: release v0.19.1 (2026.7.30) 2026-07-30 16:45:08 -07:00
Teknium c0689c3bcb test(tui): make _load_enabled_toolsets assertions tolerant of first-release back-filled toolsets
The two exact-list assertions in test_tui_gateway_server froze the toolset
list and broke the moment _RECENTLY_SHIPPED_TOOLSETS back-filled bfl onto a
saved platform list — the exact behavior the sibling change ships on purpose.
Assert the invariant instead: the expected base set is present, and anything
extra must be inside _RECENTLY_SHIPPED_TOOLSETS (vacuously exact again once
that set empties between releases).
2026-07-30 16:34:08 -07:00
rob-maron 97c6a183af auto populate flux3 in tools for nous portal users 2026-07-30 16:34:08 -07:00
Teknium 524ab53994 fix(telegram): apply media read_timeout to all upload send paths, not just video
send_video got the 60s read_timeout but send_voice/send_audio/send_photo/
send_document/send_media_group/send_animation upload through the same PTB
request path and hit the same server-side processing wait before the
response arrives. Same class, all sites: they all pass
_MEDIA_SEND_READ_TIMEOUT now. Also drops an unused test helper.
2026-07-30 15:20:09 -07:00
rob-maron 0a2859cf9a drop env var 2026-07-30 15:20:09 -07:00
rob-maron 88f6949097 more conservative 2026-07-30 15:20:09 -07:00
rob-maron 061b04ebb4 fix video delivery 2026-07-30 15:20:09 -07:00
rob-maron 5932ec4552 more conservative to 120s 2026-07-30 15:20:09 -07:00
rob-maron dcd7a95704 higher telegram media limits 2026-07-30 15:20:09 -07:00
rob-maron 4c7cc62f9f flux3 messaging system fixes 2026-07-30 15:20:09 -07:00
hermes-seaeye[bot] 5d6aae02bf fmt(js): npm run fix on merge (#75055)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-30 22:06:42 +00:00
brooklyn! 3a2b332985 Merge pull request #74938 from NousResearch/bb/rail-own-worktree
fix(desktop): a session's coding rail follows its own worktree
2026-07-30 16:54:37 -05:00
rob-maron 4a798f4bce improve polling for FLUX3 video gen (#75010)
* wait between polls
2026-07-30 16:29:27 -04:00
Andrew Fiebert c9de69c6d5 fix(desktop): keep queued prompts bound to their origin session
ChatView migrated tip-keyed composer queue/draft entries onto queueSessionKey
whenever the two ids differed. queueSessionKey is route-driven and can flip to
Session B a frame before the store selection leaves Session A, so migrate
re-homed A queue entries onto B and the idle ChatBar auto-drained them into
the wrong chat.

Gate migrate on same-conversation lineage only (tip to root). Also honor
lineage when background queue drain decides selected/busy, so a root queue key
is not treated as idle/offscreen while the compression tip is still working.
2026-07-30 15:08:31 -04:00
rob-maron 07447bd5db nous portal video gen (#74963) 2026-07-30 14:52:15 -04:00
Alex Fournier c0369f0891 Merge remote-tracking branch 'origin/main' into feat/hermes-relay-model-metrics
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-30 11:12:51 -07:00
Brooklyn Nicholson 8f4ab7ad2c fix(desktop): coding rail reads only its own worktree
The row fell back to the global $repoStatus whenever repoPath was blank,
painting the main pane's branch and ± onto a tile whose cwd hadn't
resolved yet. The fallback bought nothing — the primary computed is keyed
to $currentCwd, which is empty in exactly that case — and cost a rail
showing a tree the session was never in.
2026-07-30 12:27:23 -05:00
Brooklyn Nicholson c48d9a9c6d fix(desktop): mark tile and branch runtimes as background
A tile and a branched session each live in their own worktree and render
from their own SessionView slice, so neither is the main pane's session.
Pass foreground: false at both call sites.
2026-07-30 12:27:23 -05:00
Brooklyn Nicholson dd762d07bb fix(desktop): only the foreground session may write the composer atoms
applyRuntimeInfo unconditionally mirrored a runtime's cwd, branch, model
and usage into the global composer atoms. Every tile create and session
branch called it, so opening a session in another worktree re-pointed the
MAIN pane's coding rail at that tile's repo — and persisted it, so the
wrong workspace cwd survived a restart.

Collect the patch first, then mirror it once behind a `foreground` gate.
Background callers still get the full patch for their own session state;
they just stop publishing into state they don't own.
2026-07-30 12:27:16 -05:00
brooklyn! 8defb9fd60 Merge pull request #74833 from NousResearch/bb/status-stack-seam
fix(desktop): fuse the status stack to the composer again
2026-07-30 12:06:36 -05:00
Austin Pickett 1fd7548b49 test(desktop): query the profile row kebab by its own label
main now labels each panel row's kebab with the row's name
(menuLabel={profile.name}), so the hardcoded "Actions" default this test
relied on no longer exists. The name alone is ambiguous — the row-select
button carries it too — so match the menu trigger via `expanded`.

Neither side conflicts textually, so this only surfaced once main merged in.
2026-07-30 12:31:38 -04:00
Austin Pickett 95571de9d7 fix(desktop): fold delete dialog into shared, level up name field, test the view
Addresses review on #73013.

1. Manage Profiles used a hand-rolled delete Dialog next to the shared
   DeleteProfileDialog in the same folder. That copy missed the active-
   profile re-home fix (f764b0400): deleting the profile the gateway is
   on stranded it on a dead backend. Switch to the shared dialog, which
   owns the deleteProfile call and re-homes to default. Drops
   handleConfirmDelete, the deleting state, and the now-unused Dialog*
   imports.

2. The name field regressed to a plain Input during the create-dialog
   dedup, losing live slugging. Level both shared dialogs up to
   SanitizedInput sanitize={slug} so every entry point gets the behavior
   Manage Profiles had — the sanitize primitive means callers never
   validate-then-reject.

3. Nothing rendered ProfilesView, which is how the drift got in. Add a
   behavior test: create dialog exposes SOUL.md, deleting the active
   profile re-homes to default, deleting a non-active one does not.
2026-07-30 12:31:38 -04:00
Austin Pickett 4d9b7718d9 fix(desktop): use shared create-profile dialog on Manage Profiles page
The Manage Profiles page had its own local CreateProfileDialog/
RenameProfileDialog copies that predated the shared dialogs in
create-profile-dialog.tsx / rename-profile-dialog.tsx. The local
create copy lacked the SOUL.md textarea, so New Profile from the
sidebar rail and New Profile from Manage Profiles rendered different
modals.

Delete both local duplicates and reuse the shared self-contained
dialogs (they own the createProfile/renameProfile/updateProfileSoul
calls), so both entry points show the same modal including SOUL.md.
2026-07-30 12:31:38 -04:00
kshitij 14abd64b00 test: drop change-detector test, keep behavioral test
test_generated_script_contains_umask_else_branch asserted on shell
script text ('else', 'umask', '(0666 & ~0', 'chmod') rather than
behavior — a change-detector test per AGENTS.md. The behavioral
test (test_new_file_gets_umask_default_permissions) already
covers the actual behavior end-to-end via real subprocess.
2026-07-30 21:53:38 +05:30
webtecnica fbfee8e405 fix(file_ops): apply umask-default permissions in _atomic_write for new files (#70856) 2026-07-30 21:53:38 +05:30
kshitij 9ceac1896e Merge pull request #74902 from kshitijk4poor/chore/author-map-webtecnica-email
chore: add contato@webtecnica.com.br → webtecnica to AUTHOR_MAP
2026-07-30 21:47:06 +05:30
kshitij ad12233f76 chore: add contato@webtecnica.com.br → webtecnica to AUTHOR_MAP
Required for PR #70888 salvage attribution audit.
webtecnica already has a noreply entry (75556242+webtecnica@users.noreply.github.com);
this adds their commit-email identity.
2026-07-30 20:52:19 +05:00
Kshitij Kapoor acfd376d66 ci(docker): retry buildx setup on transient Docker Hub failures
The Docker Build, Test, and Publish workflow fails when
docker/setup-buildx-action can't pull the moby/buildkit:buildx-stable-1
image from Docker Hub. The failure happens during builder bootstrap at
the auth token exchange — a transient network blip (connection reset,
read timeout, rate limiting) that self-resolves on re-run.

Recent failure (run 30449230291, merge job):
  read tcp 10.1.0.171:45666->104.18.43.178:443: read: connection reset by peer

This has hit us before and will again — it's the same class of
transient Docker Hub flake that the merge job already retries for
imagetools create. But buildx setup had no retry, so a single network
hiccup killed the entire job (build, publish, or merge) even though
nothing was wrong with the code or the image.

Fix: wrap each of the 3 buildx setup steps (build, publish, merge jobs)
with continue-on-error + a conditional retry step. The maintained action
is preserved as-is — we just give it a second attempt if the first
fails. The action generates a unique builder name per invocation, so the
retry never collides with the failed first attempt. The second attempt
has no continue-on-error, so genuine persistent failures still fail the
job.

The docker/setup-buildx-action maintainer has explicitly said retry
belongs at the workflow level, not inside the action [1], and other
repos use this same continue-on-error pattern for this exact issue [2].

[1] docker/setup-buildx-action#510
[2] joshjhall/containers#688, ethpandaops/eth-client-docker-image-builder#391
2026-07-30 21:12:59 +05:30
Matt Ezell 7965462d6c fix(compression): choose summary role by template-visible alternation
The compaction summary's role was selected against the LITERAL
neighbouring messages (compressed[-1] / tail_messages[0]). Mistral-family
chat templates (Devstral, Mistral Small 3.x, Magistral) enforce
user/assistant alternation but exempt the tool flow (tool results and
assistant messages carrying tool_calls) from the check, so a protected
head ending [user, assistant(tool_calls), tool] pinned the summary to
role="user" while the last role the template counts is "user": the
backend rejects the whole request with a Jinja alternation error
(HTTP 500). The summary persists in the stored conversation, every
retry replays the identical poisoned history, and the session is
permanently unrecoverable. Fires on EVERY compaction against a
Mistral-strict backend, captured byte-exact via a tee-proxy in front of
a llama.cpp/llama-swap Devstral deployment.

Fix: compute both neighbour roles through _template_visible_role(),
which skips template-exempt messages. The #52160 (Anthropic user-first)
and #58753 (zero-user-turn) forced-user guards are preserved; their
forced shapes (summary-user followed only by exempt messages) are
alternation-safe. When the visible head ends "assistant" and the
visible tail opens "user", no standalone role can alternate and the
existing merge-into-tail fallback now correctly fires (the literal
logic emitted a standalone user summary there: a second poisoning
shape).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGN45sMMbwM8cW9T9ga4ou
2026-07-30 21:07:36 +05:30
ethernet 36e41c09ed fix(nix): include new flat modules at the root (#74362) 2026-07-30 20:28:36 +05:30
Brooklyn Nicholson 77bdf932fc fix(desktop): fuse the status stack to the composer again
pb-2 on the in-flow stack wrapper opened an 8px gap under the card and
broke the shared seam the dock card is built for.
2026-07-30 07:47:02 -05:00
hermes-seaeye[bot] b4f8c491d3 fmt(js): npm run fix on merge (#74827)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-30 12:46:25 +00:00
brooklyn! fd90ef77be Merge pull request #74815 from NousResearch/bb/composer-clear-parity
Clearing the composer empties it whichever way you do it
2026-07-30 07:36:28 -05:00
brooklyn! 466e6402f6 Merge pull request #74806 from NousResearch/bb/ref-parity
A sent reference renders as the chip the composer showed
2026-07-30 07:32:22 -05:00
hermes-seaeye[bot] 84d71fb88f fmt(js): npm run fix on merge (#74814)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-30 12:31:53 +00:00
Brooklyn Nicholson 570337c099 fix(desktop): clearing the composer lands on the same empty state every way
Select-all + Delete cleared the composer; select-all + Cut left it holding
a draft. Both produce identical DOM, so the split was in the reader.

An emptied editor keeps a placeholder <br> \u2014 scaffolding
normalizeComposerEditorDom adds so the contenteditable doesn't collapse to
a sliver, not a line the user typed. composerPlainText read it as "\n",
and syncDraftFromEditor (session swap, pagehide) skipped the
normalize+sanitize its rAF twin runs. Cut's residue reached that reader;
Delete's went through the flush path and got cleaned.

Fixed where the two disagree rather than at each call site: an editor
holding nothing but its placeholder break reads as empty. A real
Shift+Enter break, a trailing break after text, and a nested lone <br>
are all unchanged \u2014 the exemption is scoped to the editor root by its slot
marker. syncDraftFromEditor now normalizes and sanitizes like the flush
path, so both readers see one truth.
2026-07-30 07:29:31 -05:00
brooklyn! 3eebb99ca8 Merge pull request #74804 from NousResearch/bb/tab-close-stay-right
Closing a tab leaves you on the one that fills its slot
2026-07-30 07:23:00 -05:00
Brooklyn Nicholson 1238efce13 fix(desktop): track kanban lane phase in state, not a mirrored ref
main landed a lint rule banning refs mirrored from reactive values in an
effect — they lag a render and cause stale reads. The lane-collapse
override tracker did exactly that with a counts ref.

Hold the empty/non-empty signature in state instead. React bails out
when it's unchanged, so a poll where no lane's emptiness moved costs no
extra render, and the comparison always sees the current value.
2026-07-30 07:18:45 -05:00
Brooklyn Nicholson 81e196f236 feat(desktop): kanban new-task hotkey — the plugin command pattern
Creating a task was mouse-only: the header button, the empty state, or a
per-column hover +. Kanban now ships a real command, wired the way any
plugin should wire one.

One action id (kanban.newTask) registered into two areas: KEYBINDS_AREA
gives it dispatch plus a rebindable row in the shortcuts panel, and a
palette row whose `action` field points back at the same id so the live
combo renders as its hotkey hint. The handler is route-independent — it
parks the lane in $newTaskLane and navigates, so the page picks the
request up whether it was already mounted or is mounting for the first
time, then clears it so a remount can't reopen a dismissed dialog.

Default is mod+alt+n (⌘⌥N). mod+n and mod+shift+n are core built-ins a
plugin can't shadow; core uses alt only for the mod+alt+1…9 profile
slots, never with a letter, which leaves ⌘⌥<letter> free as the natural
namespace for plugin commands.

Label ships in the plugin's own locale bundles (en/ja/zh/zh-hant) via
ctx.i18n, so it localizes without a core en.ts edit.
2026-07-30 07:18:45 -05:00
Brooklyn Nicholson 6a67a4e952 fix(desktop): resolve contributed keybinds through the fallback chain
$bindings is seeded at module init from the actions known then, so an
action a plugin contributes later is absent from it. Both hotkey-hint
call sites did a raw bindings[id] lookup, so a plugin command rendered
with no combo in the palette and no hint on its tooltip even though the
dispatcher (which goes through $comboIndex → bindingsFor) fired it fine.

Route both through bindingsFor, the resolver that already falls back to
the stored override and the action's shipped defaults, and subscribe the
hint hook to the registry version so a late registration repaints.

Covered by behavior tests over the contributed-action contract: dispatch,
combo resolution, panel row, teardown, and the no-shadowing guard.
2026-07-30 07:18:45 -05:00
Brooklyn Nicholson eaa61d2aa6 i18n(desktop): move kanban to plugin-scoped ctx.i18n (per #67303)
Now that #67303 shipped the plugin-scoped i18n door, the kanban plugin ships
its OWN locale bundles via ctx.i18n.register instead of a core t.kanban
namespace — nothing added to core en.ts/ja/zh/zh-hant/types.ts. useKanban()
binds usePluginI18n('kanban') to the message SHAPE (one tiny generic) so
components keep their typed k.newTask / k.moveTo(label) access unchanged.
2026-07-30 07:18:08 -05:00