The New Workspace flow built a bare launch command client-side and sent it as
`startupCommand`, so the host ran it verbatim and never applied the default
launch args. The first Claude session therefore started in manual mode, while
opening another Claude via the "+" tab (which sends the agent id and lets the
host resolve args) started with `--dangerously-skip-permissions`.
Send `startupAgent` from every client-built create path (blank, reuse-branch,
and new-branch) so the host resolves the launch command, args, env, and
host-shell quoting through the same path the "+" new-tab and CLI use. The
work-item path already delegated via `startupDraft`. Custom `agentDefaultArgs`
are now honored on all paths.
Adds a shared `agentLaunchCreateFields` helper and removes the now-unused
client-side command map, which had also drifted from the canonical launch
commands for continue, hermes, command-code, kiro, and mistral-vibe.
Claude-Session: https://claude.ai/code/session_014iufZnQwPD2obYuvdahjaE
Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
* fix(mobile): report interrupted native chat sends as delivery-unknown, not failed
A terminal.send interrupted mid-flight showed a definite "Message not sent"
even when the desktop may have already delivered the text. Three paths were
misclassified as definite failures:
- Logical relay/direct cutover: migrateTo rejects in-flight requests with
LogicalClientCutoverError, which mapped to 'rejected'. Now maps to 'unknown'
(held unconfirmed + transcript-echo verification; never retried since
terminal.send is non-idempotent).
- Suspend/close of a half-open session: the stable logical client blanket-
rejected in-flight pendings with plain 'Client suspended'/'Client closed',
preempting the physical layer's delivery-unknown marking. It now lets the
physical close settle them, so post-write failures stay marked and pre-write
failures stay definite.
- Relay path: mobile-relay-rpc-session never marked delivery ambiguity at all
(timeout, close, link failure). Post-write rejections are now marked;
pending entries only exist after the frame reached the authenticated link.
Permission, ask-answer, and cancel-Escape surfaces now show "unconfirmed —
check chat before retrying" instead of a definite "not sent" on ambiguous
outcomes (still not-accepted, never retried). Also consolidates a private
copy of isLogicalClientCutoverError in worktree-create-retry.
Co-authored-by: Orca <help@stably.ai>
* chore(skills): regenerate skill-bundle manifest artifacts
---------
Co-authored-by: Orca <help@stably.ai>
* fix(mobile): retry session capability probe so tab-row actions survive relay cutover
The session screen learned host capabilities (quick commands, browser
screencast, agent history, query-reply input) from a single status.get
fired when the screen connected. Over relay, a relay-to-direct transport
cutover rejects every in-flight request while connState stays
'connected', and a request timeout does the same — so one transient
failure latched the capability flags false (or left them null on an
ok:false reply) and the quick-commands tab-row button stayed hidden
until the screen was remounted.
Replace the one-shot probe with startRuntimeCapabilityProbe: retry
promptly after a cutover (the replacement transport is already
authenticated) and with capped exponential backoff on other failures,
until a probe lands or the effect is cleaned up. Also export the
cutover-error predicate from stable-logical-rpc-client and reuse it in
worktree-create-capability instead of a local copy.
* fix(mobile): reset runtime gates before capability reprobe
* fix(github): load PR diffs for Enterprise remotes
* fix(github): encode PR content paths by segment
* Fix PR review actions failing on GitHub Enterprise remotes
- Threads GitHub host identity (not just owner/repo) through the client,
work-item-details, issues, and RPC layers so gh commands target the
correct Enterprise server instead of silently falling back to github.com
- Adds a shared github-api-repository helper to resolve/host-qualify repo
identity consistently across REST, GraphQL, and CLI shorthand calls
- Scopes the gh rate-limit breaker and singleton rate-limit snapshot by
host/runtime so a github.com block or probe can't affect GHES or WSL
- Coalesces concurrent host-auth probes and paginates PR file fetching
beyond 100 results
- Propagates `host` through renderer PR caches, checks-panel keys, and
preload IPC types so Enterprise and github.com data never collide
* Route gh host qualification through runner options instead of argv sniff
Move GHES/GH_HOST resolution from parsing --hostname/--repo out of gh argv to an explicit options.host passed through ghExecFileAsync, since SSH-backed repos spawn gh with no cwd and argv sniffing couldn't reliably detect the target host. The runner now injects --hostname and qualifies --repo/-R at spawn time from options.host, and rate-limit scoping/guards use the same explicit host instead of inferring it. Also adds a shared githubRepoIdentityKey helper to keep cache/store keys consistent with the new host-aware repository identity.
* Fix gh CLI GHES host pinning and rate-limit scope leaks
- Pin `--host` on every gh call site so a process-level GH_HOST can't
silently redirect requests, and qualify `-R`/`-R=` repo shorthand
alongside the existing `--repo=` handling.
- Check the target scope for an active rate-limit block before each
WSL/native or host fallback retry, not just on the initial attempt,
so a blocked scope can't be hit again through a fallback path.
- Compute idempotency once per call instead of re-deriving it after
fallback reassigns args.
* Fix GitHub Enterprise host identity loss across PR/work-item paths
- Thread `host` through mobile PR RPC params, IPC work-item lookups, and
RPC schemas so GHES identity survives the renderer/mobile/main boundary
instead of silently falling back to a same-named github.com repo.
- Qualify `--repo`/`-R` args for github.com too (not just GHES), since
gh resolves bare shorthand against a process-level GH_HOST that can
redirect pinned github.com commands.
- Cache `getOriginGitHubApiRepository` to avoid a per-call uncached
`git remote get-url` round trip on connection-backed repos.
- Add a local-fork fallback in `getWorkItemDetails` so PRs living on a
base repo (not visible via the origin slug) still resolve via cwd.
- Centralize the github.com-vs-GHES host predicate in
`isDefaultGitHubHost` so cache keys, quota scoping, and identity
checks can't drift out of sync.
* Make repository identity host-aware across all GitHub surfaces
Generalize the auth-gated enterprise resolver to any remote and build a
cached hosted-identity family (origin/issue/candidates/source) on top of
it, then migrate every github.com-only consumer: Tasks listing/counting,
branch-to-PR discovery, push targets, fork upstream, issue operations,
Projects, web links, avatars, and PR-link facts. Scope the rate-limit
breaker probe per runtime:host and classify WSL UNC cwds correctly.
Co-authored-by: Orca <help@stably.ai>
* Fix expected slug to include host field in GitHub PR link test
Updates the smart-source paste-intent test fixture to match the
repository slug shape that now carries a `host` field, keeping GHES
host identity intact through the paste-intent parsing path.
* Surface per-host gh auth state for GitHub Enterprise
diagnoseGhAuth accepts the host a surface needs credentials for, scopes
the account/scope diagnosis to that host, and reports whether gh has any
login there; GhAuthErrorHelp renders host-qualified login/refresh
commands so an unauthenticated GHES host stops masquerading as a
github.com scope problem. Also fixes the mobile paste-intent expectation
for host-carrying parsed links.
Co-authored-by: Orca <help@stably.ai>
* Bound GHES identity caches and preserve non-default ports in host identity
Cap the origin-repo and host-auth caches like ownerRepoCache; keep ports
from remote/link URLs so GHES on a non-default port is a distinct
identity; make positional github.com slugs explicit against GH_HOST;
compare work-item sources by host-aware identity key; bail cwd-less
branch lookups when no repository candidate resolved; thread host
through the renderer work-item slug lookup.
Co-authored-by: Orca <help@stably.ai>
* Thread GitHub host through issue detail requests
Incorporates ghes-issue-host-support (ed6bb96ef): one hosted issue
repository identity is resolved before the details fan-out so comments,
timeline, participants, and mention lookups cannot drift across hosts,
with SSH guards so unresolved issue/PR repositories never fall through
to gh's default host.
Co-authored-by: Orca <help@stably.ai>
* Scope remaining GitHub rate-limit accounting
* Resolve typed PR lookups across hosted repository candidates
getWorkItem's PR path probes upstream-then-origin hosted candidates
instead of origin alone, so fork checkouts resolve the base repo's PR
with the right host; issue detail resolution reuses the up-front hosted
identity and keeps the SSH unresolved-host guards.
Co-authored-by: Orca <help@stably.ai>
* Refactor GitHub repository execution setup
* Carry host on smart-submit link intents
Co-authored-by: Orca <help@stably.ai>
* Carry the project host on GitHub item dialog origins
Co-authored-by: Orca <help@stably.ai>
* Keep GHES web ports but drop SSH transport ports in host identity
Supersedes PR #9118 on this branch: http(s) remote ports identify the
Enterprise web/API endpoint and are preserved, while ssh/git transport
ports (including ssh.github.com:443) never leak into gh's host identity.
Replaces the ssh.github.com:443 special case with the structural
protocol split and ports the PR's parsing test suite.
Co-authored-by: Orca <help@stably.ai>
* Support GitHub Enterprise diffs and mutations with host-scoped caches
Parse GitHub host identity from work-item URLs and carry it through PR/issue mutations, labels, and assignments. Bound rate-limit and scope-probe caches (1024 and 512 entries) to prevent unbounded growth when interacting with multiple GHES instances. Normalize repository identity keys to include host so github.com and GHES slugs don't collide in cache and equality checks.
* Support GitHub Enterprise diffs and mutations with host-scoped caches
- Carry host identity through PR mutations and reads so fork PRs on
different GHES instances don't collide in cache or state tracking.
- Validate host authentication before routing requests to unconfigured
Enterprise servers; ambient credentials must never reach untrusted hosts.
- Scope rate-limit guards and spend tracking per host so GHES quota stays
independent from github.com quota.
- Respect explicit --hostname arguments in gh CLI calls ahead of GH_HOST or
ambient defaults, so breaker state follows the actual request target.
- Detect implicit WSL runtimes from UNC paths for consistent host auth and
execution-options scoping across mobile and desktop clients.
* Support GitHub Enterprise work-item diffs with host-scoped execution
Enterprise PRs must use their selected host consistently across diff, comments,
and file-content loads. Validate repository slugs before authenticated execution
to prevent path-injection via renderer overrides. Scope project browsing cache
and rate-limit tracking by host to prevent cross-host pollution. Use parsed
URLs as authoritative over ambient hosts for project resolution.
* Support GitHub Enterprise work-item diffs with host-scoped execution
Preserve host identity on PR/issue work items throughout the mutation and diff
pipeline so Enterprise instances (including ported endpoints like
github.acme.test:8443) can execute mutations without ambiguity. Rate-limit gh
commands by the pre-qualified --repo host, cache auth state per ported host,
and surface Enterprise hosts in project metadata and error messages.
* fix(review): drop dead rateLimitGuard/noteRateLimitSpend re-export
Both callers (project-view.ts, mutations.ts) moved to the host-scoped
repositoryRateLimitGuard/noteRepositoryRateLimitSpend; the bucket-only
re-export in internals.ts had zero importers left.
Co-authored-by: Orca <help@stably.ai>
* fix(ci): split Enterprise host work-item tests under max-lines
Move GHES/SSH host-routing cases out of work-item-details.test.ts so
the suite stays within the 800-line test max-lines budget.
* test(github): align mocks with host-scoped repository resolution
- Route origin repository resolution through getOwnerRepoForRemote, not getOwnerRepo, to match production path
- Pin github.com host on origin results so host-less fixtures pass host gate in resolveGitHubApiRepository
- Add generation-based invalidation to prevent stale slug-cache writes from in-flight resolutions
- Fix ref-sync race in ProjectPicker: use useLayoutEffect so committed tree owns browse cache key
- Defer handledCrossRepoUrlRef assignment in SmartWorkspaceNameField until resolution succeeds
- Update Enterprise host routing: found work items must not silently fall back to default host when unresolved
- Normalize GHES avatar URLs: accept explicit port 443 as canonical form, not a fallback trigger
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* fix(mobile): survive connection-migration cutovers during worktree create
A worktree.create in flight when the mobile transport migrates (relay/direct
hand-off on shoddy cellular, relay lease rotation, relay recovery) rejects with
"RPC interrupted by connection migration" even though the host completed it —
leaving the Create Workspace modal stuck while the worktree exists on desktop.
A naive retry hits a name collision and spawns a duplicate.
Mirror the existing mobile terminal-create idempotency: worktree.create now
accepts an optional clientMutationId that the host dedupes (in-flight + brief
post-success TTL), and mobile mints one key per candidate name and re-issues
the create on a cutover so the retry reconciles instead of duplicating.
* fix(mobile): gate worktree cutover replay by capability
* fix(mobile): await worktree replay capability
* feat(mobile): start a workspace from a branch, issue/PR, or Linear ticket
Unify mobile workspace creation with desktop. The "+" Create Workspace
modal now has a primary "Start from" field that opens a tabbed search
drawer (Branch · GitHub · GitLab · Linear), letting a user start a
workspace from an existing/new git branch, a GitHub issue/PR, a GitLab
issue/MR, or a Linear ticket — in addition to the default blank workspace.
No new backend is required: the search RPCs (github.listWorkItems,
gitlab.listWorkItems, linear.searchIssues/listIssues, repo.searchRefs) and
the worktree.create linked-item params were already used by the mobile
Tasks screen. This surfaces them in the create flow, reusing the existing
pure modules (buildTaskWorkspaceCreateParams, shouldResolveHostedReviewStartPoint,
filterAvailableTaskProviders).
Details:
- New pure modules: workspace-source-selection, use-workspace-source-search,
source-workspace-create, worktree-create-retry, blank-workspace-create
(the blank/retry path extracted from the modal for reuse + line budget).
- New UI: WorkspaceSourcePickerDrawer (+ row) and SetupHookTrustDrawer
(extracted from the modal).
- Older paired desktops (missing the mobile.tasks.v1 capability) degrade to
Branch + Blank only; GitLab/Linear tabs appear only when available.
- GitHub/GitLab sources pin their repo; switching repos resets the source.
PR/MR sources resolve their base branch at create time; SSH repos gate
search until connected (Linear search is repo/SSH-independent).
* fix(mobile): hydrate settings/trust before availability probes settle
Review fixes for #7985: setTrustedOrcaHooks/setRuntimeSettings no longer
wait on status.get/preflight.check/linear.status (a first-open
preflight.check can take seconds, widening the spurious setup-trust
re-prompt window). Also adds param-parity tests for createBlankWorkspace
and a GitLab MR base-resolve test.
* feat(mobile): match desktop's Smart source picker exactly
Rework the mobile create-workspace source picker to be a faithful port of
desktop's Smart picker instead of the earlier divergent "Start from" drawer.
The mobile field is now the workspace-name input AND the source search, with the
exact desktop tabs — Smart · GitHub · Linear · GitLab · Branch · Name. "Smart"
fans out across GitHub + GitLab + Linear + branches, prepends a "Use '<name>'"
row, and resolves pasted URLs / #123 / STA-42 to exact items (with a cross-repo
switch prompt). Selecting a source shows a pill and moves the editable name into
Advanced. The invented "Blank workspace" concept is removed — the neutral state
is just a typed/empty name (blank submit still yields a creature name).
DRY: the pure desktop logic (smart-workspace-source-results, -command-value,
github-links, gitlab-links, work-item-link-query-bounds, github-work-item-identity)
moves to src/shared/new-workspace/ with re-export shims at the old renderer paths,
so both renderer and mobile share one implementation. composer-branch-selection
and workspace-name were already shared and are reused directly.
Two read-only lookup RPCs are allowlisted for mobile so pasted GitLab URLs and
cross-repo GitHub URLs resolve to exact items (github.workItemByOwnerRepo,
gitlab.workItemByPath).
New mobile modules are split for max-lines: use-mobile-composer-source (selection
state + desktop-parity handlers, PR/MR base resolve), use-smart-workspace-source
+ smart-source-fan-out/-search-requests/-paste-intent (RPC orchestration),
composer-linked-work-item / work-item-lookup-text / mobile-smart-source-modes
(pure logic), and SmartWorkspaceSourceField/Drawer/Row + SmartWorkspaceAdvancedFields.
Replaces WorkspaceSourcePickerDrawer/Row, workspace-source-selection,
use-workspace-source-search, and MobileWorkspaceNameInput.
Reviewed by three adversarial agents + re-reviewed after fixes: GitHub search now
returns issues AND PRs (not issues-only), Linear defaults to assigned, create-branch
preserves slashy names, cross-repo PR base resolves against the item's own repo,
displayName is suppressed for user-edited names, and the smart-mode GitHub fan-out
respects availability. tsc/oxlint/max-lines-ratchet clean; 1328 mobile tests pass.
* fix(mobile): keep smart source drawer fully visible
* refactor: share workspace creation behavior across clients
* fix: address workspace creation review findings
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
Migrate fileURLToPath(import.meta.url) / dirname(...) boilerplate to the
native import.meta.dirname / import.meta.filename, then enable the rule
at error so new code stays on the native form.
The oxlint autofix rewrites the expression but leaves the now-unused
node:url / node:path imports behind (which the already-enabled
no-unused-vars=error would then flag), so this commit also removes those
34 orphaned imports — trimming the named import where other names are
still used, deleting the line where it was the sole import.
Scope is build scripts + Node-env tests only (config/scripts, tools/
benchmarks, *.test.{ts,mjs}, vitest configs); zero shipped runtime code.
The native properties are exact equivalents (Node >= 20.11; repo is on
24), so behavior is unchanged.
Verified: oxlint 0 errors tree-wide (root + mobile), oxfmt clean,
typecheck (node+cli+web) + mobile tsc pass, root vitest 22825 passed /
0 failed, mobile vitest 1018 passed. Exercised the rewritten scripts
directly: build:relay (6 targets), ensure-native-runtime,
verify-macos-entitlements all run correctly with import.meta.dirname.
* feat(agents): native Xiaomi MiMo Code support
Add mimo-code TUI agent (detect mimo, --prompt, --session resume).
Inject MIMOCODE_HOME overlay and /hook/mimo-code status plugin on mimo
launch when agent status hooks are enabled; restore via shell-ready
wrappers. Reuse OpenCode-family hook normalization in the listener.
SSH remote MiMo hook overlays are not included (local/daemon first).
Closes#6220
* fix(mimo): remirror overlay config idempotently
rmSync overlay config before mirror so a second mimo launch does not
hit EEXIST in mirrorEntry and fall back to the user MIMOCODE_HOME.
* review: harden mimo code support
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Doan Bac Tam <24356000+doanbactam@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Removed duplicate 'openclaude' entry at index 3 of MOBILE_TUI_AGENT_AUTO_PICK_ORDER so mobile pickers no longer render two OpenClaude rows or emit duplicate-key warnings.
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* Add agent enablement controls
Implements the Enable/Disable Agents Dashboard behavior described in docs/enable-disable-agents-dashboard.md, including persisted agent enablement state, filtered launch surfaces, and settings UI affordances.
* Clarify agent availability controls
* Respect disabled agents across workspace and AI defaults
- Filter disabled TUI agents from mobile and quick workspace selection
- Avoid implicitly choosing disabled agents for commit/PR AI settings
- Broadcast settings changes to open windows for disabled-agent updates
* rm design doc
* fix: complete agent enablement propagation