Commit Graph
5907 Commits
Author SHA1 Message Date
mehmet turac ca36072295 Handle GitHub attachment image load failures (#6759) 2026-07-03 17:32:08 -07:00
PPandping 69415946dd fix(github): count PR diff lines whose added content starts with ++ (#6819)
Co-authored-by: ping <ping6174@gmail.com>
2026-07-03 17:25:32 -07:00
github-actions[bot] 41e395b66b release: v1.4.121-rc.6 v1.4.121-rc.6 2026-07-04 00:24:44 +00:00
8796261eed feat: allow custom worktree branch names (#6454)
* feat: allow custom worktree branch names

* refactor(ui): render custom branch name field unconditionally under advanced container

* fix(composer): hide manual branch field when a work-item source drives the branch

A tracked PR/issue/MR/Linear source derives the branch itself, and a linked
GitHub PR re-resolves the branch name at submit — so an override typed in the
Advanced branch field was silently ignored. Only render the field for the
typed-name and base-branch flows, where the manual override is honored.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 17:21:50 -07:00
9f31826e79 fix(ssh): surface stdout alongside stderr in execCommand errors instead of masking (#6865)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 17:20:25 -07:00
6fbfb8d921 fix: strip trailing whitespace from PROMPT_COMMAND in bash wrapper (#6897)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Super User <root@localhost.localdomain>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 17:16:29 -07:00
Brennan BensonandOrca a4661f15d3 Inject serve-sim camera dylib from an unquarantined runtime copy (#7174)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 17:12:47 -07:00
d9e0b9e759 fix(mobile): avoid SF Mono fallback on iOS terminal (#6761)
* fix(mobile): avoid SF Mono fallback on iOS terminal

* test(mobile): cover touch iPadOS terminal font fallback

* refactor(mobile): share terminal font fallback tail across platforms

Dedup the identical fallback chain that the iOS/non-iOS branches each
repeated so the two platforms can only differ in the lead family and
cannot silently drift. Make the regression tests behavioral: assert the
resolved chain always terminates in the generic monospace (the real iOS
bug) and that both platforms share an identical tail.

Co-authored-by: Orca <help@stably.ai>

* test(mobile): anchor font-block extraction on font markers only

The VM-slice end boundary was an unrelated text-scale comment; re-anchor
it on the terminalFontFamily declaration so edits below the font block
cannot break the extraction.

Co-authored-by: Orca <help@stably.ai>

* chore(mobile): bump terminal-webview-html max-lines ratchet to match file size

The iOS-safe font selection block adds a few code lines to
terminal-webview-html.ts, pushing it to 1784. Bump the grandfathered
per-file ratchet to match, consistent with prior ratchet bumps.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 17:11:24 -07:00
m11yandClaude Fable 5 4c78440f70 Fix Codex hook trust hash for matcherless events (UserPromptSubmit/Stop) (#7110)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:07:42 -07:00
Soichi Sumi 5e9db83c48 fix: add 'hooks' to CODEX_SYSTEM_RESOURCE_ENTRIES (#7120) 2026-07-03 17:06:09 -07:00
haozhenfei 547afc2264 fix(rate-limits): route hidden Claude usage PTY through the configured proxy (#7245) 2026-07-03 17:04:25 -07:00
2789a67604 feat(browser): add Copy to context menu when text is selected (#7159)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 16:52:08 -07:00
473c4e8680 fix(markdown): restore TOC navigation for h4 and h5 (#7063)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <charlie-eng@stably.ai>
2026-07-03 16:51:26 -07:00
e8c2b79a93 Fix mobile live input keyboard and Korean IME (#7273)
* feat: 모바일 터미널 한글 미러 스텝 순수 모델 추가

* feat: 미러 델타 순서 보장용 send 체인 추가

* fix: 모바일 터미널 한글 입력을 미러 모델로 전환

* fix: 탭 상태 지연 중 한글 조합 상태 소실 방지

* fix: 미러 가드와 send 체인 리뷰 지적사항 반영

탭 상태 지연으로 활성 탭 타입이 일시적으로 null이 될 때 runMirrorStep의 stale-handle 가드가 조합 중 음절을 버리지 않도록 pending-clear 효과와 동일한 null 허용 패턴 적용. 테스트 하네스가 ref와 prop을 동일 소스에서 파생하도록 결합해 실제 경로의 lag 프레임을 검증. queueTerminalLiveMirrorSend의 previousSend await를 catch로 보호.

* refactor(mobile): drop dead queueTerminalLivePendingFlush orphaned by the mirror model

The mirror model migrated all live-input sends to queueTerminalLiveMirrorSend,
leaving queueTerminalLivePendingFlush referenced only by its own tests. Remove
the dead function and its three tests.

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): expose live terminal keyboard target

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): refocus live keyboard after dismissal

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: realitsyourman <wongil@demodev.io>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:47:59 -07:00
2c03133975 fix(i18n): apply persisted UI language at startup instead of OS locale (#7193)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: rubin <RubinCarter@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 16:44:56 -07:00
github-actions[bot] 0bc417e04d release: v1.4.121-rc.5 v1.4.121-rc.5 2026-07-03 23:41:58 +00:00
Jinwoo Hong 2f3c7e8660 Fix Windows slow startup and multi-minute UI freezes (#7225) (#7266) 2026-07-03 19:40:45 -04:00
4797cf81a4 fix(agent-hooks): stream hook payload to a temp file instead of inlining it on the curl command line (#4475)
The POSIX agent-hook script for every curl-based agent inlined the full
event payload via `curl --data-urlencode "payload=${payload}"`. Tool
output can be tens of KB, so the resulting process command line could be
multi-KB — which endpoint security tools (e.g. Microsoft Defender for
Endpoint) flag as an oversized/suspicious command line. That produced a
false-positive detection on Orca's own loopback (127.0.0.1) telemetry POST.

Stream the payload to an mktemp file and post it with
`--data-urlencode "payload@$payload_file"` instead. The urlencoded body on
the wire is byte-identical, so the agent-hook receiver is unchanged; the
payload simply never appears on a process command line. `trap ... EXIT`
removes the temp file on every exit path. Small bounded metadata fields
(paneKey/tabId/worktreeId/env/version) stay inline.

Applied to all curl-based agents: claude, codex, command-code, copilot,
cursor, droid, gemini, grok, antigravity. (amp/hermes/opencode post via
the HTTP request body and were never affected.) The Windows post-command
shares the same latent pattern and is flagged as follow-up.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:26:53 -07:00
a10e1d7584 fix(gitlab): recognize self-hosted GitLab on non-default ports over SSH connections; stop one project failing the whole issues panel (#5400)
* fix(gitlab): port-aware self-hosted host recognition

Use the URL host (including a non-default web/API port) as the GitLab
host identity instead of the port-less hostname, and match known hosts
port-aware:

- A known-host entry without a port matches any port of the same
  hostname (preserves legacy bare-host and gitlab.com recognition).
- A known-host entry WITH a port matches only that exact host:port, so
  two services sharing a hostname on different ports (e.g. a GitLab and
  a Gitea) are no longer conflated.
- For ssh/git remotes the port is a transport port (e.g. ssh :2222) and
  is dropped; for http(s) remotes the port is the endpoint and kept.
- Also capture an optional :port in parseGlabAuthStatusHosts so a
  self-hosted GitLab on a non-default port is discovered correctly.

* fix(gitlab): per-connection known-hosts cache + port-aware auth-status parsing

getGlabKnownHosts() was connection-blind and cached process-globally,
and on any failure it cached [gitlab.com] forever — so a repo on an SSH
connection never discovered its self-hosted host once a probe failed
before the tunnel was ready.

- getGlabKnownHosts(connectionId?) now caches per connection so a
  connected repo's authenticated hosts don't leak into the local
  context (or vice versa).
- The failure fallback (canonical default) is no longer cached, so a
  later probe can re-discover the real host once auth/tunnel is ready.
- parseGlabAuthStatusHosts captures an optional :port on both the
  'Logged in to <host>' and header-style lines, keeping two services on
  the same hostname distinct by port.

* fix(gitlab): isolate unresolvable projects instead of cwd-fallback that hits exit 128

listIssues/getIssue fell back to an unscoped 'glab issue list' / 'glab
issue view' that infers the project from cwd. For a repo on an SSH
connection cwd is not the repo dir, so glab runs git resolution in a
non-repo dir and fails with 'git: exit status 128'. In an 'All projects'
aggregate one such failure could sink the whole issues panel.

When a projectRef cannot be resolved, return a structured, isolated
per-project result (listIssues: { items: [], error: not_found };
getIssue: null) and spawn no glab subprocess. Behavior is unchanged when
a projectRef IS resolved (the scoped '-R' / 'api projects/...' path).

* fix(gitlab): recognize modern /-/work_items/<iid> issue URLs

Modern GitLab emits issue URLs as /-/work_items/<iid> in addition to the
legacy /-/issues/<iid>. The URL classifiers only matched /-/issues/, so
work-item-form issue links went unrecognized.

Extend the gitlab-links parsers (parseGitLabIssueOrMRNumber /
parseGitLabIssueOrMRLink, which also backs isWorkItemLookupText) and
isGitLabIssueUrl to accept /-/work_items/<iid>, mapping it to an issue
work item with the same project-path + iid extraction.

* fix(gitlab): thread connectionId into getGlabKnownHosts call sites

Follow the existing connectionId-threading pattern: pass the repo's
connectionId into every getGlabKnownHosts() call (client.ts,
work-item-details.ts, orca-runtime.ts) so the per-connection known-hosts
cache is keyed correctly and self-hosted hosts are discovered against
the right glab context.

* docs(gitlab): use generic example hosts in comments

* fix(gitlab): pass self-hosted host:port via GITLAB_HOST (glab --hostname rejects ports)

* polish: satisfy oxlint curly + oxfmt on merged gitlab port-recognition code

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Ptah-CT <auctor@xinfty.space>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:24:01 -07:00
Jinwoo HongandOrca 25896f2cdb fix(mobile): keep Android release versionCode committed (#7271)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 15:26:11 -07:00
Brennan BensonandOrca f4790e9fac Fix blank mobile terminal on Android devices with outdated WebViews or blocked CDN (#7186)
* fix(mobile): bundle terminal engine and show load errors instead of a blank pane

The mobile terminal WebView loaded xterm.js from cdn.jsdelivr.net at
runtime; old WebViews (< Chrome 85) fail to parse the modern bundle and
blocked-CDN networks fail to fetch it, and the resulting error was
silently dropped, leaving the pane permanently blank (#7030).

Bundle the engine into the app via exact-pinned npm deps + a postinstall
esbuild step (chrome74 target, guarded WeakRef/structuredClone/
replaceChildren shims) emitting a gitignored generated module, inline it
into the terminal document, and surface fatal engine failures as a
visible overlay with diagnostics and a Reload wired into the existing
resubscribe path. Non-fatal errors log without covering a live terminal.

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): add a native watchdog so a dead terminal document can't stay silently blank

CodeRabbit round: if the webview document dies before the glue can post
anything (or the RN message bridge never comes up), no error message and
no native handler fires. Arm a 15s foreground-gated watchdog per document
generation that paints the fatal overlay when web-ready never arrives;
first fatal diagnostics win over later cascades. Extract the watchdog and
the public contract types to keep TerminalWebView under the line cap, and
document the SVG xmlns percent-encoding transform.

Co-authored-by: Orca <help@stably.ai>

* test(mobile): unmount TerminalWebView renderers so watchdog timers can't leak across tests

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-03 15:22:00 -07:00
github-actions[bot] f3e103ebe7 release: v1.4.121-rc.3 v1.4.121-rc.3 2026-07-03 21:28:43 +00:00
Brennan BensonandOrca 6213f43016 Wake hibernated agent panes on reveal instead of leaving an inert ghost (#7145)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:27:36 -07:00
Alexander 99d61b13b2 Bound generated release notes by previous tag (#5649)
Fixes #5579. Pass previous_tag_name to GitHub generate-notes so draft-release notes stop accumulating across releases; omit it safely on first release. Adds tag parse/compare + paginated tag fetch and regression tests.
2026-07-03 14:22:47 -07:00
332490e919 Fix stale GitHub repo avatars after owner changes (#6507)
* Fix stale GitHub repo avatars after owner changes

* Simplify avatar-refresh effect deps (repo covers its fields)

Co-authored-by: Orca <help@stably.ai>

* Preserve known fork identity when live upstream lookup is inconclusive

Co-authored-by: Orca <help@stably.ai>

* Remove dead avatar-icon wrapper; drop no-op update fallbacks

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:20:30 -07:00
5124b0d0ad fix(serve): install orca CLI in headless serve so orca claude-teams resolves (takeover of #5766) (#7267)
* fix(serve): install the orca CLI in headless serve mode

In headless serve mode the orca CLI command (~/.local/bin/orca on Linux,
/usr/local/bin/orca on macOS) is never created, so the in-app Claude Team
launcher (orca claude-teams) opened by 'Start new agent' fails with
command-not-found. CliInstaller.install() is only invoked from renderer/desktop
flows (onboarding, Settings 'Install CLI', feature tips) via the cli:install IPC;
headless serve has no renderer. Run the existing idempotent installer on the
serve startup path, best-effort so a failure never blocks serve startup.

Fixes #5763.

* fix(serve): install a bare `orca` dispatcher on Linux for Claude Team

On Linux CliInstaller installs the CLI as `orca-ide` (to avoid shadowing GNOME
Orca's /usr/bin/orca), not bare `orca`. But the Claude Team launcher (`orca
claude-teams`), composed client-side by both the desktop renderer and the
mobile app and written verbatim to the host PTY, invokes bare `orca` — which
is unresolved in the initial managed terminal (no agent-teams shim on PATH
yet). The serve-mode CLI install therefore fixed macOS but not Linux.

Add a bare-`orca` dispatcher in the serve branch (host-side, Linux only) that
execs the bundled CLI wrapper. ~/.local/bin is hardcoded ahead of /usr/bin on
the managed-terminal PATH, so it resolves. Plain file (not a managed symlink)
so CliInstaller.removeLegacyLinuxCommandIfManaged leaves it untouched.

* Restore ai-vault files to origin/main (drop stale pre-0.52 oxfmt merge artifact)

Co-authored-by: Orca <help@stably.ai>

* Harden serve CLI install: AppImage-safe dispatcher, no-prompt macOS, skip Windows, conflict guard

- Gate CliInstaller.install() to macOS+Linux; Windows would only mutate the
  persistent user-registry PATH without helping the current serve's terminals.
- Inject a non-prompting privilegedRunner so headless macOS never pops an
  osascript admin dialog when /usr/local/bin isn't writable (skips instead).
- Linux dispatcher: exec the stable $APPIMAGE via buildAppImageCliWrapper when
  running from an AppImage (resourcesPath is an ephemeral FUSE mount); skip when
  the bundled orca-ide launcher is absent; never clobber a user-owned ~/.local/bin/orca.
- Single-quote the exec target; add coverage for all new branches.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Daniel Rudaev <daniel@d1dx.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:12:33 -07:00
cede986d38 fix(browser): restore programmatic focus for CDP text insertion (#7041)
* fix(browser): restore programmatic focus for CDP text insertion

* test(browser): cover the DOM focus replay error path

* fix(browser): serialize DOM.focus replay against pipelined Input.insertText

* refactor(browser): consolidate pending-focus invalidation into one guard

Collapse the three per-handler deletes (Page.bringToFront, Page.captureScreenshot,
catch-all) of the pending DOM.focus replay into a single guarded delete keyed on
'not DOM.focus and not Input.insertText'. States the invariant in one place and
removes the trap where a future early-returning handler forgets to clear the
stale focus. Also clear the map on client teardown and shorten the field comment.

Co-authored-by: Orca <help@stably.ai>

* test(browser): annotate mock webContents return type for portable declaration emit

Co-authored-by: Orca <help@stably.ai>

* fix(browser): drop pending focus replay when the client disconnects mid-flight

Co-authored-by: Orca <help@stably.ai>

* fix(browser): re-check active client after DOM.focus replay round-trip

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:12:18 -07:00
3614cbc40c Add default browser action for terminal links (#6129)
* Add terminal link browser context action

* Polish terminal link default-browser action

- Route Open in Default Browser through the shared openHttpLink funnel
  (forceSystemBrowser) so loopback dev-server links get the same
  worktree-label rewrite as shift+click's system-browser path.
- Translate the new menu label in es/ja/ko/zh (was en-only).
- Extract TerminalQuickCommandMenuItem to keep TerminalContextMenu under
  the max-lines lint after adding the link item.
- Hit-test the link only when the menu actually opens (skip on Windows
  right-click copy/paste path).
- Add scheme-safety unit tests (file:/javascript:/smb:/vscode: rejected)
  and a menu-item render/callback test; fix TerminalContextMenu.test
  props for the new required fields.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:09:52 -07:00
42de074152 fix(browser): keep isolated profile storage on its partition (#6958)
* fix(browser): keep isolated profile storage on its partition

* fix(browser): keep cloned isolated tabs on their resolved partition

* fix(browser): thread resolved partition through UI profile switches

Keep the isolated-storage invariant universal: UI-initiated profile
switch/create now persist the resolved partition alongside the profile
id, matching the runtime path, so a tab stays on its partition even if
the renderer profile mirror is later stale (issue #6923).

Co-authored-by: Orca <help@stably.ai>

* fix(browser): persist resolved partition through session restore

Add sessionPartition to the workspace-session zod schema so the resolved
partition survives persist->load; without it zod strips the field and a
restored isolated tab whose profile mirror is stale at startup falls back
to the shared default partition, reopening the storage leak (#6923).

Fold the webview teardown branches (parent drift or partition mismatch)
into one and re-resolve the viewport container once, matching the
pre-refactor null-guard behavior.

Split the sleeping-agent parse tests into their own file to keep both
under the 800-line cap.

Co-authored-by: Orca <help@stably.ai>

* fix(browser): keep CLI-created tabs inheriting the default profile

browserTabCreate without an explicit profile was sending sessionProfileId:
null, which the renderer store treats as 'no inheritance' (its guard is
!== undefined). That forced CLI-created tabs onto the shared default
partition even when the user had configured a default browser session
profile, silently changing behavior a #6923 fix should not touch.

Leave sessionProfileId/sessionPartition undefined when no profile is named
so the renderer applies default-profile inheritance; thread the resolved
partition only when a profile is explicitly chosen.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:58:40 -07:00
Brennan BensonandOrca d8921a22ad Bump mobile app.json to 0.0.22 (#7261)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:42:09 -07:00
Brennan BensonandOrca 133ebcee5d Update stale mobile Android download links to 0.0.21 (#7262)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:42:02 -07:00
97c30c5ccc fix: drop stale repos fetches so deleted projects don't reappear (#7020) (#7024)
* fix: drop stale repos fetches so deleted projects don't reappear

Deleting a project group with "Remove contained projects" could leave the
removed projects as stale, unusable sidebar rows until an app restart (#7020).
`repos:changed` fires once per removal and the renderer starts an unsequenced
repos fetch per event; an earlier fetch that read pre-removal state could
resolve last and overwrite the newer result, reintroducing the deleted repos.

Guard fetchRepos and fetchReposForAllHosts with a monotonic token so a fetch
drops its own result once a newer repos fetch has superseded it — only the
latest fetch, which reads the final persisted state, applies. Add a regression
test that a stale fetch resolving after a newer one can't resurrect a removed
repo.

* test: isolate stale-fetch race in a dedicated file; scope guard to fetchRepos

Move the #7020 regression test out of repos.test.ts into a focused
repos-stale-fetch.test.ts and add a reject-path case (a superseding fetch
that later rejects must still block the older stale fetch). Scope the
monotonic guard to fetchRepos only: the original shared-counter guard on
fetchReposForAllHosts let an unrelated fetchRepos bump the counter and
abort an in-flight all-host load, dropping every host's repos.

Co-authored-by: Orca <help@stably.ai>

* chore: restore origin/main cdp-ws-proxy.test.ts (drop merge artifact)

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:40:17 -07:00
2c0be62df6 Fix empty nested import folder fallback (#6719)
* fix: allow empty nested import as folder

* Track open-as-folder recovery action and localize its strings

Completes the empty-nested-import fallback: adds the open_as_folder action to the existing add_repo_nested_import_action funnel (integer counts only, no paths) so adoption of the recovery path is measurable, and lands the five-locale catalog entries the new UI strings require.

Co-authored-by: Orca <help@stably.ai>

* Pin runtime-kind mock return to the literal union in nested import flow test

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:38:20 -07:00
Brennan BensonandOrca 700b492b1b Fix main typecheck: pin Buffer<ArrayBuffer> in cdp-ws-proxy mid-print test (#7263)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:30:55 -07:00
Parker Rex 02dfb4b334 Fix Discord icon and CreateWorktree label spacing (#6505)
* Fix landing create worktree label

* Update Discord help menu icon
2026-07-03 13:12:14 -07:00
273fee79fa Fix CDP Page.printToPDF support (#7044)
* Fix CDP printToPDF proxy

* Harden CDP PDF stream handling

* Fix PDF margin units

* refactor(cdp): extract printToPDF param mapping + stream store into cdp-print-to-pdf

Move the CDP Page.printToPDF option translation and the ReturnAsStream handle
store out of cdp-ws-proxy into a focused cdp-print-to-pdf module, mirroring the
existing cdp-screenshot sibling. Keeps the over-budget proxy from growing
further and gives the PDF logic direct unit coverage.

No behavior change: all existing proxy tests pass unmodified.

Co-authored-by: Orca <help@stably.ai>

* fix(cdp): drop print result if client disconnected during printToPDF

A ReturnAsStream print that resolved after the requesting client
disconnected (or was replaced) registered its buffer in pdfStreams after
the disconnect's clear() already ran, orphaning a potentially large PDF
until the 5-minute TTL. Re-check isActiveClient after the await, mirroring
navigateWithLifecycle/reloadWithLifecycle.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <foxtrot-eng@stably.ai>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:06:43 -07:00
9aeaf0728f Fix git worktree list fallback for older Git (#7235)
* fix git worktree list fallback for localized errors

* Polish worktree -z fallback: clarify comment, add localized + negative tests

Co-authored-by: Orca <help@stably.ai>

* Extend -z fallback to relay/SSH worktree path; tighten comments; add relay tests

Co-authored-by: Orca <help@stably.ai>

* Isolate regex-fallback path in relay test

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: yuqili03 <yuqili03@deeproute.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 12:56:38 -07:00
2153ef9456 Accept any hostname (and optional :port) in manual network address entry (#7223)
* Allow arbitrary hostnames in manual network address entry

parseManualNetworkAddress only accepted an IPv4 address or a Tailscale
MagicDNS (*.ts.net) hostname, so users behind a dynamic residential IP
who rely on a DDNS domain or self-hosted relay had no way to enter it
in the desktop UI short of bypassing validation via DevTools/IPC.

The main process already resolves any host: resolvePairingEndpoint
and parsePairingAddressOverride in src/main/runtime/runtime-rpc.ts
accept an arbitrary hostname and an optional host:port. This change
brings the renderer-side validation in line with what pairing already
supports: any RFC 1123 hostname (a superset that still covers
*.ts.net), optionally suffixed with :port (1-65535). IPv4 validation
is unchanged, including still rejecting malformed dotted-numeric input
instead of silently treating it as an all-digit hostname.

Updates the custom-address dialog copy in NetworkInterfacePicker.tsx
to describe the wider grammar.

* Polish manual-address takeover: fix bare-numeric guard, sync 5 locales, lint

- Require a dot in the IPv4-typo guard so a bare numeric label (`123`)
  validates as a legal RFC 1123 hostname, matching the code's own comment
  and the main-process resolver; add coverage.
- Update en.json + es/ja/ko/zh placeholder/hint to the broadened grammar
  (translate() reads en.json before the TSX fallback, so the copy change
  was previously inert; the other locales described the old ts.net-only rule).
- Replace indexOf(...)!==-1 with includes() to satisfy oxlint.

Co-authored-by: Orca <help@stably.ai>

* Keep validator a strict subset of the backend resolver

Review surfaced two ways the renderer could accept an address the main
process handles differently:
- All-numeric hosts (bare `123` and dotted `256.0.0.1`) are now rejected.
  The WHATWG URL host parser downstream reinterprets a numeric host as IPv4
  (`123` -> `0.0.0.123`), so accepting one would validate an address the
  pairing resolver silently dials as a different host.
- Ports with leading zeros are rejected. `^[0-9]+$` let an arbitrarily long
  zero-padded string past the range check and inflate the returned address
  beyond the hostname length cap that the old whole-string check enforced.

Co-authored-by: Orca <help@stably.ai>

* Reject any numeric final label, not just fully-numeric hosts

WHATWG URL host parsing treats a host whose last label is numeric
(`foo.123`, `foo.0x1`) as an IPv4 signal, so the pairing resolver would
fail to parse it and silently dial a fallback host. Widen the ambiguous-IP
guard to a single last-label check that subsumes the earlier all-numeric
case, keeping the renderer a strict subset of what the backend resolves
correctly. Normal hostnames whose last label merely contains digits
(`host2.example.com`) are unaffected.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 12:52:55 -07:00
492306f223 fix(sidebar): keep independent same-host checkouts of one repo as separate projects (#7237)
* fix(sidebar): keep independent same-host checkouts of one repo as separate projects

Re-regression of #5374: PR #6320 removed the per-host-surface separation
added by #5375, so independent local clones of the same repo (shared origin
=> same github:owner/repo identity) collapse into one sidebar project again.

Restore the surface-key separation in worktree-list-groups.ts, scoped by
ProjectHostSetup.setupMethod: 'provisioned' (ephemeral-VM runtime copies)
still nest under the project header (preserving #6320), while real user
checkouts (legacy-repo / imported-existing-folder / cloned) each get their
own header when duplicated on one host surface.

Revert the two tests #6320 inverted and add coverage for a provisioned copy
nesting alongside a same-host user checkout.

* test(cmd-j): update palette grouping tests for same-host checkout split

The Cmd+J palette shares getProjectGroupingForRepo (via
getProjectHeaderRevealTarget) with the sidebar, so restoring same-host
checkout separation also splits independent `cloned` checkouts into
per-setup palette entries. Update the multi-setup test to assert the split
and add coverage that a `provisioned` runtime copy still nests under one
project key.

* test(sidebar): cover split + provisioned-nest on one host together

Guard the intersection of #5374 and #6320: when a project has two real
same-host user checkouts AND a provisioned copy, the real checkouts each get
their own per-setup header while the provisioned copy stays under the plain
project key (never a path-scoped ::setup: header). Locks the two features'
combined behavior so a future change can't silently regress either half.

* refactor(sidebar): reuse shared Windows-path helper, single-pass surface count

Take-over polish of #7237:
- Use shared isWindowsAbsolutePathLike instead of an inline drive-letter
  regex, deduplicating the pattern and also bucketing UNC \\server\share
  paths as a Windows surface instead of falling through to default.
- Collapse buildProjectGroupingIndex's two passes over projectHostSetups into
  one, computing each surface key once and flagging ambiguous projects from
  the aggregated counts.
- Tighten why-comments to AGENTS.md's two-line rule.

No behavior change to the fix; all 123 sidebar/palette grouping tests pass.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 12:44:34 -07:00
37c8ff4935 fix: block resuming host-stored AI Vault sessions into SSH workspaces (#7130)
* fix: block resuming host-stored AI Vault sessions into SSH workspaces

AI Vault scans session history from this machine's disk only (host home
dirs plus local WSL homes), but since #6685 resume actions accepted any
SSH workspace as a target. Resuming a host-stored session there queues
cd '<local cwd>' && <agent> --resume <id> into a remote shell where
neither the cwd nor the session file exists, so it always fails.

Gate resume targets on where the session file lives: local targets stay
unrestricted, SSH targets now require a WSL-stored session (the
SSH-to-local-WSL setup #6685 was built for). Applies to the sidebar
resume buttons, direct resume, and pane drag-and-drop, with a toast
explaining the host mismatch. Catalog sync also picked up two
pre-existing drifts (missing failedUnnestWorkspace fallback, two
unreferenced SSH-timeout keys).

* i18n: translate host-session SSH-resume block message (es/ja/ko/zh)

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 12:44:31 -07:00
1fd9547501 fix(agent-completion): stop PermissionRequest hooks from firing false completion notifications (#6316)
* test(agent-completion): cover done after waiting pause

Co-authored-by: Orca <help@stably.ai>

* test(agent-completion): assert attention fires alongside done-after-waiting

Wire dispatchAttention into the done-after-waiting regression test so it
verifies both halves of the #5698 fix: the mid-turn permission pause
surfaces as attention exactly once, and the later genuine 'done' still
completes exactly once. Matches sibling tests that assert on both paths.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: brennanb2025 <brennankbenson@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 12:44:28 -07:00
Neil 96481b1eab Stop scheduled release cuts (#7258) 2026-07-03 11:03:28 -07:00
github-actions[bot] 14034678cc Update README downloads badge 2026-07-03 12:56:28 +00:00
github-actions[bot] a4f9dda71a release: v1.4.121-rc.1 [rc-slot:2026-07-03-03] v1.4.121-rc.1 2026-07-03 10:57:58 +00:00
Neil c8e571f40c fix(sidebar): prevent hovercard text selection drags (#7228) 2026-07-03 03:07:17 -07:00
Brennan Benson 653f349b5f Fix terminal theme selection persistence (#7227)
Fixes #7166.
2026-07-03 02:55:27 -07:00
Neil ce680071a2 Place terminal URL tooltip at pane corner (#7221) 2026-07-03 02:15:24 -07:00
Neil a84f737cf7 fix(terminals): restore pane detach tab placement (#7215)
* fix(tabs): restore deferred tab activation so dragging a terminal tab doesn't switch panes mid-gesture

PR #5927 shipped terminal-pane drag (reorder tabs, move a tab into another
pane, edge-split into a new column). It deliberately DEFERRED tab activation
to pointer-up and suppressed it during a drag, so pressing a tab to drag it
never switched the active tab or stole terminal focus mid-gesture.

PR #6395 (d32d62a395) deleted tab-strip-pointer-activation.ts and made
SortableTab/EditorFileTab/BrowserTab activate eagerly on pointerdown — fixing
click-to-switch-after-reorder but regressing the drag: grabbing a tab now
flips the active tab + focused pane and yanks xterm keyboard focus before the
drag is even recognized (aggravated by PR #6210 raising the dnd-kit threshold
5px->12px). The move itself still lands, but the gesture feels broken.

Restore the deferred-activation hook, but gate it on measured pointer
DISPLACEMENT instead of the drag-active context ref the old hook used — that
ref clears asynchronously relative to the drop's pointerup, which is exactly
what made #6395's click-after-reorder misfire. Displacement mirrors dnd-kit's
own activation threshold: a release within TAB_DRAG_ACTIVATION_DISTANCE_PX is
a click (activate); crossing it is a drag (suppress). Because each press
measures its own gesture, a click after a reorder always activates.

- Recreate src/renderer/src/components/tab-bar/tab-strip-pointer-activation.ts
  (displacement-gated) + unit tests, incl. an explicit #6395 regression case.
- Rewire onPointerDown in SortableTab, EditorFileTab, BrowserTab to use it.
- BrowserTab.test.tsx shallow-renders via mocked React hooks; add useRef/
  useCallback stubs so the new hook works under that harness.

Verified end-to-end in a dev build via CDP: pressing a tab no longer
activates/steals focus on pointerdown; a click still activates on release;
dragging a tab into another pane still moves it; clicking tabs after a drag
still switches (the #6395 guard in tests/e2e/tabs.spec.ts stays green because
it uses zero-displacement clicks). 233 unit tests pass; oxlint + renderer
typecheck clean.

* fix: restore pane detach tab placement
2026-07-03 01:45:15 -07:00
Neil 7c9059c4d4 Restore desktop terminal URL modifier clicks
Restore desktop terminal URL and OSC link activation to require Cmd/Ctrl while preserving mobile tap routing.
2026-07-03 01:32:22 -07:00
Jinjing 471881c14f Update WeChat QR code 2026-07-03 01:06:24 -07:00