- Use fallback PR numbers after branch lookup misses, including detached HEAD
- Preserve review cards for forked or deleted-head PRs across manual refreshes
- Clear stale GitHub PR cache entries when unlinking worktree review metadata
* Squashed commits
- WIP: uncommitted changes before rebase
- ci
- Show inline PR check details in task drawer
- Add a Checks tab that opens from the PR checks cell and expands runs inline
- Fetch check output, annotations, and workflow job steps through IPC/RPC
- Improve markdown/comment wrapping so long PR content stays within the drawer
* Use app-styled confirmations for PR actions (#2324)
Co-authored-by: Orca <help@stably.ai>
* fix: pr-bug-scan validated finding from #2274 (#2296)
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
---------
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com>
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Prefer exact linked PR lookup when safe, add stale-while-revalidate for sidebar hosted review metadata, and preserve branch discovery correctness for stale linked PR metadata.
Reopening a GitHub issue/PR drawer paid full IPC + `gh` startup latency on
every open. Two changes here:
1. Module-level SWR cache in GitHubItemDialog.tsx keyed by
(repoPath, issueSourcePreference, type, number). Reopening within 30s
paints cached data instantly; older entries paint stale-then-refresh.
Concurrent opens dedupe on a shared in-flight promise. Mutation
handlers invalidate by (repo, type, number); a cache-generation
counter prevents in-flight refetches from resurrecting stale data
after a mid-flight invalidation.
2. Collapsed GraphQL query for issue details replaces 3 serial `gh`
subprocesses (REST issue + REST comments + GraphQL participants) with
one round-trip. Falls back to the legacy fan-out on any GraphQL error
so historical contract is preserved.
Cross-window invalidation rides a new `gh:workItemMutated` IPC broadcast
that skips the originating sender (the source already updated its cache
optimistically — re-broadcasting would race the optimistic write).
`addIssueComment` now takes a `type` so the broadcast scopes correctly
when a PR shares its number with an issue.
Co-authored-by: Orca <help@stably.ai>
Fixed banner Docs link to use openExternal IPC like the block variant; restricted hasKeyringFallback to same-host keyring accounts so multi-host users aren't told a fallback exists when none does.
Findings addressed:
- src/renderer/src/components/github-project/GhAuthErrorHelp.tsx:218-227 — Banner Docs link uses <a target="_blank"> instead of shell IPC
- src/main/github/auth-diagnose.ts:121-127 — hasKeyringFallback ignores host, can mislead multi-host users
Rebased onto current main to drop unrelated reverts.
Co-authored-by: orca-bot <bot@stably.ai>
Closes the race where siblings awaiting parentFieldProbeInFlight wake
between resolveProbe() and the deferred parentFieldRetriedByOwner.add()
in the outer block, see parentFieldProbeInFlight=null +
parentFieldRetriedByOwner without scopeKey, and issue duplicate
with-parent probes.
Originally raised in #1456, but that PR branched off pre-#1465 main and
its diff against current main reverted #1465's owner-keyed parent-field
caches back to global flags. This re-applies the fix on current main.
Refs #1456
Co-authored-by: nwparker <nwparker@stably.ai>
* fix(gh-project): diagnose env-shadowed gh tokens in auth errors
`gh auth refresh -s project` silently no-ops when GITHUB_TOKEN/GH_TOKEN
is exported in the user's shell — gh prefers env tokens and refuses to
modify them, exiting 0. Users follow the canned remediation, see no
error, retry, and stay stuck.
Add a one-shot `gh auth status` probe (gh:diagnoseAuth IPC) that:
- Detects env-shadowed credentials and rewrites the fix to `unset
GITHUB_TOKEN` plus a grep to find where it's exported.
- Detects missing gh install, plain missing-scope on a keyring login,
and SAML SSO authorization.
- Surfaces a tailored multi-button error UI in ProjectViewWrapper and
ProjectPicker instead of one canned 'Copy command'.
Co-authored-by: Orca <help@stably.ai>
* fix(gh-project): address review feedback
- Cross-platform shell guidance: PowerShell commands on Windows
(Get-ChildItem Env:, Remove-Item Env:, [Environment]::SetEnvironmentVariable)
via navigator.userAgent platform check.
- Use `window.api.shell.openUrl` for the docs button instead of
`window.open`, matching SidebarToolbar's external-URL pattern.
- Tighten gh auth status parser: accept single-label hostnames and
optional trailing colon; recover host from the inline 'Logged in to
<host>' line so a missed section header never silently drops accounts.
- Add tests for multi-host output and host-recovery fallback.
- Drop dead command/copy locals in ProjectViewWrapper.ErrorState by
short-circuiting the auth-error case before they're computed.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
Gate gh retries on idempotency (auto-detected from argv/-X/mutation), key parent-field probe by (owner,ownerType), accept 'to an' in not_found classifier, and replace bulk label PUT with parallel sing
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
* fix: address pr-bug-scan findings from #1444
Threaded linkedPRNumber through all ChecksPanel force-refresh paths; gated useComposerState's PR-URL-from-name recovery on selected repo slug match; wrapped main-process linkedPR fallback gh pr view i
* fix: satisfy react-hooks/exhaustive-deps in selectedRepoSlug effect
Extract selectedRepo?.path into a const so the effect's only dep is
the path string, removing the missing-dependency warning.
---------
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Neil <neil@nousresearch.com>
When a worktree is created from a PR via the source picker, the new
local branch differs from the PR's head ref, so the branch-keyed PR
lookup misses and the worktree card shows no PR strip. Pass the
worktree's linkedPR number through the IPC call and fall back to a
number-based lookup in the main process. Also recover linkedPR from
a PR URL pasted into the workspace name when the user skips the
source picker. PR strip now wraps the whole row as the PR link.
Co-authored-by: Orca <help@stably.ai>
* Fix new workspace composer focus restore
* Unify new workspace source selection
* WIP: selected source pill in smart workspace name field
Co-authored-by: Orca <help@stably.ai>
* fix(new-workspace): truncate source pill so it doesn't expand the dialog
Co-authored-by: Orca <help@stably.ai>
* feat(new-workspace): add open-in-browser button to source pill, fix vertical alignment
Co-authored-by: Orca <help@stably.ai>
* refactor(new-workspace): drop redundant kind suffix, distinct PR/issue icons, tooltips on pill actions
Co-authored-by: Orca <help@stably.ai>
* fix(new-workspace): type linked URL into agent input without auto-submit
Co-authored-by: Orca <help@stably.ai>
* fix(new-workspace): use bracketed-paste for draft URL injection so it actually appears in the agent input
Co-authored-by: Orca <help@stably.ai>
* feat(agents): per-agent draft injection strategy (codex slow paste, pi/opencode type-chars)
Co-authored-by: Orca <help@stably.ai>
* fix(agents): smarter TUI-ready heuristic + bracketed paste for codex/pi/opencode
Replaces per-agent strategy guesswork with a measured readiness check:
title-idle / non-shell-foreground stable for 1.5s / 2.5s minimum floor.
Verified against codex, pi, opencode, claude in a node-pty + xterm-headless
test rig — bracketed paste lands in the input buffer for all four.
Co-authored-by: Orca <help@stably.ai>
* refactor(agents): drop unused per-agent draft strategy abstraction
The TUI-ready heuristic in agent-paste-draft.ts works for every tested
agent (claude/codex/pi/opencode), so the AgentDraftInjectionStrategy
field, type-chars + bracketed-paste-slow code paths, and per-agent
overrides are dead. Keep the `agent` arg on pasteDraftWhenAgentReady
for future per-agent escape hatches without touching every call site.
Co-authored-by: Orca <help@stably.ai>
* feat(agents): skip draft URL injection for copilot + cursor-agent
Both TUIs open with a 'Do you trust this folder?' menu on first launch
that consumes keystrokes as menu input — pasting a URL there either
selects an arbitrary option or quits the session. Mark them with
skipDraftUrlInjection so the workspace still opens cleanly; the user
types/pastes the URL themselves once past the trust menu.
Co-authored-by: Orca <help@stably.ai>
* feat(agents): native --prefill for claude, trust pre-write for cursor/copilot
Replaces the empirical TUI-ready waits with two deterministic mechanisms:
1) `claude --prefill <text>` flag — Claude launches with the URL already in
its input box, no submit. Eliminates the readiness/paste race entirely
for the most common agent.
2) DECSET 2004 (`\x1b[?2004h`) detection on the PTY data stream for every
other agent. That escape is the protocol-level "input layer ready,
accepting bracketed paste" handshake — emitted by claude/codex/pi/
opencode/gemini/cursor-agent/copilot the moment the input box mounts.
We tap it via a sidecar subscription on pty-dispatcher (no interference
with the primary xterm handler) and paste as soon as it lands. The
8s budget is now an upper bound, not a target.
Cursor-agent and Copilot's "Do you trust this folder?" menus are bypassed
by writing the same trust artifacts the CLIs themselves write after the
user accepts:
- Cursor: `~/.cursor/projects/<slug>/.workspace-trusted` (slug = abs path
with leading `/` stripped, remaining `/` → `-`).
- Copilot: append cwd to `trustedFolders` in `~/.copilot/config.json`
(the same array the bundled `addTrustedFolder` writes).
Verified against the cursor-agent CLI bundle (versions/2026.04.17-787b533/
index.js: `_=".workspace-trusted"`) and the @github/copilot 1.0.32 bundle
(`isFolderTrusted` / `addTrustedFolder` both read/write `trustedFolders`).
Both check via realpath() before string-comparing, so the trust preset
canonicalizes too.
skipDraftUrlInjection is dropped — both agents now get the draft URL
paste once the trust menu is pre-resolved.
Tests: 24 passing across tui-agent-startup, agent-trust-presets,
pty-dispatcher routing.
Co-authored-by: Orca <help@stably.ai>
* fix(agents): wait for post-?2004h render burst to settle before paste
OpenCode emits DECSET 2004 at ~500ms during alt-screen setup, then runs
a 1.3s splash render with NO bytes on the PTY, then paints the actual
input box at ~1.85s. Pasting on the bare ?2004h signal lands during the
silent gap and the bytes are dropped.
The fix: take ?2004h as the necessary precondition, then wait for the
TUI's render burst to finish — defined as 1500ms of stream silence
after the most recent post-?2004h byte. This captures both the fast
TUIs (claude/pi/codex emit setup escapes in one burst then go quiet)
and the slow ones (opencode emits, sleeps for the splash, emits again,
then goes quiet).
Verified against opencode/claude/pi in a node-pty rig: paste lands on
the first try with the new strategy. The hard 8s timeout still caps
the wait when an agent fails to launch.
Co-authored-by: Orca <help@stably.ai>
* fix(agents): guard agentTrust IPC so stale preload doesn't crash launch
If the preload bundle is older than the renderer (a real situation in
electron-vite dev because preload changes only apply on full restart,
not HMR), `window.api.agentTrust` is undefined and the launch crashes
with "Cannot read properties of undefined (reading 'markTrusted')"
before the worktree even opens.
Guard the call sites in launch-work-item-direct and useComposerState
to skip the trust pre-write when the IPC isn't exposed, and wrap the
invoke in try/catch so an IPC error never blocks the launch — the user
just sees the trust menu and accepts it manually, same as before this
feature shipped.
Co-authored-by: Orca <help@stably.ai>
* feat(tasks): route 'Use' through the New Workspace dialog instead of yolo-create
The Use CTA on the Tasks page used to create+activate a worktree
synchronously, which surprised users — the worktree appeared in the
sidebar before they had a chance to confirm name / agent / setup. The
unified New Workspace dialog landed in this branch already supports
opening with a linked work item pre-filled (see openComposerForItem /
openComposerForLinearItem), so just route Use through it.
The launchWorkItemDirect helper stays exported for ProjectViewWrapper,
which has its own UX where the immediate-create flow is the right call.
Co-authored-by: Orca <help@stably.ai>
* test(agents): include `agent` field in autohand startup-plan assertion
Merging main brought in the Autohand Code agent test (PR #1382), which
predated this branch's addition of `agent` to AgentStartupPlan.
Aligning the assertion fixes the lone CI test failure on this PR.
Co-authored-by: Orca <help@stably.ai>
* refactor(agents): drop unused expectedProcess arg + snapshot sidecar set
Two minor follow-ups from self-review:
1. `pasteDraftWhenAgentReady` no longer reads `expectedProcess` — readiness
is gated on DECSET 2004 alone now, not on PTY foreground process. Drop
it from the signature and from the two callers (launch-work-item-direct,
new-workspace).
2. The pty-dispatcher's sidecar fan-out iterates the live Set, which is
safe against deleting the current element but not against a watcher
that synchronously subscribes a sibling. Snapshot via Array.from
before the loop. Cheap (Set is tiny) and removes the latent footgun.
No behavior change.
Co-authored-by: Orca <help@stably.ai>
* test(e2e): match the unified smart-name input's new placeholder
The CreateFromTab refactor in this branch replaced the separate "Workspace
name" Input with a single SmartWorkspaceNameField whose default-mode
placeholder is "Type a name, #1234, branch, GitHub or Linear URL". The
worktree-create e2e test was still anchoring on the old "Workspace name"
text and could not find the input.
Update the placeholder regex to match the new copy. Free-form text typed
into smart mode is treated as a workspace name by submitQuick — same
contract the test used before.
Verified locally: targeted e2e passes in 2.2s.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>