The project catalog keys a repo by its first network remote (upstream,
origin, then the rest), but GitHub issue and PR lookups only read the
remotes named origin and upstream. A repo whose origin is a local bare
repo and whose GitHub remote has another name showed as GitHub-backed
yet Tasks said no GitHub source was detected. Origin's role now falls to
the same remote the project identity picks.
Fixes#42102
* fix(github): keep the selected workspace's PR on its one-minute refresh
Follow-up reads inherited the priority of whatever entry ran last. A workspace
selected while its cached PR was still fresh never got a foreground entry, so
its follow-ups competed with every visible card for the shared list budget and
were read about every five minutes with 25 visible open PRs. Previously
selected workspaces kept priority 80 forever. Follow-ups now take foreground
priority only while their workspace is selected.
* feat(source-control): say when a merged workspace is safe to delete
Source Control's committed list is a merge-base diff against the base ref. A
squash or rebase merge copies the commits onto the base with new IDs, so the
list looks the same after the merge as before it. A notice now states whether
the merged review contains everything: HEAD is the review's head (or the
provider confirmed it is contained) and nothing is uncommitted.
* fix(sidebar): keep PR status visible on sleeping workspaces
The sleeping moon replaced the review glyph, hiding whether a sleeping
workspace's PR was open, failing or merged. Review status now keeps the lane;
the dimmed row already shows sleep and the accessible label names both.
Co-authored-by: Tobias Diez <code@tobiasdiez.com>
Co-authored-by: alpenshtokk <wawesandways@gmail.com>
* fix(source-control): wait for a git status read before judging a merged workspace
Before the first status read the change count is zero and HEAD may be stale,
so the notice could call a dirty workspace safe to delete. Use the HEAD from
the latest successful status read and say nothing until one completes.
* chore(i18n): ship the merged-review plural copy in the runtime English catalog
* fix: satisfy design-system, cast and flaky-test gates for the merged notice
Use the callout-important token instead of raw purple, let Button own its
type size, build the fixture worktree with the shared factory, pin the test
clock and give the long simulated-time tests a reason for their timeout.
* fix(github): align selected-refresh regression with feature ownership
* refactor(github): give refresh queue aliases their concrete owner
* fix(source-control): preserve cleanup warnings and reserve refresh fairness
* fix(source-control): describe missing merged-head proof as unverified
---------
Co-authored-by: Tobias Diez <code@tobiasdiez.com>
Co-authored-by: alpenshtokk <wawesandways@gmail.com>
* fix(source-control): keep merged reviews visible after an equivalent local rebase
* fix(source-control): retry proofs after fetching missing review heads
* fix(source-control): compare merged-review deltas without decoding
* fix(source-control): retry unproven equivalence after history fetches
Callers such as getRepoUpstream and the tracked-upstream branch fallback called getGitHubApiRepositoryForRemote without checking the cached remote listing, causing repos without an upstream remote to run failing git remote get-url upstream execs on cold lookups. Gate non-origin remotes on shouldProbeGitRemote at the shared entry point while keeping origin unconditional.
Refs #22684
Co-authored-by: h5k <31630310+h5kk@users.noreply.github.com>
* fix(github): show Actions jobs as checks when a token cannot read check runs
A fine-grained personal access token cannot be granted the Checks
permission, so GitHub refuses every check-run read and the checks panel
failed with 'Resource not accessible by personal access token'. When the
REST check-run read is refused that way, the fallback now lists the head
commit's GitHub Actions jobs (Actions: read) in their place; a job's id is
its check run's id, so job logs keep working.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(github): read Actions jobs in the shared REST check pages
Moves the fine-grained token fallback into readRestPRCheckRuns and
readRestPRCheckSuites so it reuses the existing pagination and also
covers the CI summary and PR watch reads. Check details skip the
refused check-run read and still load the workflow jobs and logs.
* fix(github): read refused check details from the Actions job
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* fix(github): title GitHub issue links that were saved without one
A workspace linked to a GitHub issue from the CLI (`--issue N`), a phone, the paired web
client or a typed number kept only the number, so search could match its issue title only
while a client happened to hold that issue. The host that owns the workspace now reads each
newly linked untitled issue once, after the write returns, the way its card would, and saves
the title on the link. It keeps the current review selection and never resurrects a removed link.
* fix(github): bound and publish issue-title fills like other metadata writes
Skip writes that leave links untouched before normalizing, check a queued link is still wanted
before reading it, publish filled titles once per repo per 2 s window, refresh the resolved rows
remote clients read, never wake a stopped WSL distro for a background read, keep a selected
review's PR suppression, and keep a failing write observer from failing a saved write.
* fix(github): keep link-title fills off unrelated writes and out of per-title refreshes
Ignore linkedWorkItem in the unchanged-links check (it is rebuilt on every write and always
titled), publish filled titles at once on a quiet host and at most once per repo per 30 s
during a burst on a timer, and only lift a PR suppression when the selected PR changes, so
restating the current PR (as a title fill does) keeps a hidden branch PR hidden.
* perf(github): publish filled link titles as addressed workspace metadata
Instead of a whole-repo worktreesChanged refresh per burst window, the host publishes one
addressed workspaceMetadata set record {hostId, epoch, seq, id, row} for the workspace whose
link was titled: to its desktop window over IPC and to paired clients as a runtime client event.
Clients patch that one row (Cmd-J reads it) and drop replayed records; older clients ignore the
new event and see the title on their next listing.
* fix(github): agreed workspaceMetadata record shape, per-id seqs and late-listing refill
Records name their kind and domain, clients keep the last applied seq per workspace for each
producer epoch (dropped when the epoch changes), and a listing that read metadata before the
title write cannot drop the title: recorded titles refill rows that still hold the same untitled
link for 60 s, never restoring a removed link. The IPC channel is marked as interim transport.
* fix(github): title-only, host-addressed application of workspaceMetadata records
Clients fill the record's issue titles into the named row's still-untitled links and never take
its links over the row's current ones, so a record that arrives after an unlink cannot restore
the issue. A paired host's records reach the row of their own execution host (an SSH twin is a
different row), and go through the bridge's connection-generation check like other host events.
* test(github): type the metadata-record test helper as AppState
* fix(github): keep recorded titles until expiry, refill only changed repos, retire with the pairing
A record that beats the listing adding its link keeps its titles for the full window; the refill
runs only for repos whose listing changed, indexes that repo's rows once and skips rows already
checked; per-workspace seqs live in the expiring entries; a re-pair or reconnect of the producing
environment retires its titles.
* fix(github): read the listing through the workspace record selector
* fix(github): keep link titles until their producer changes; fall back to a listing on eviction
Recorded issue titles no longer expire on a timer (a slow listing could outlast it): they live until
the producer's epoch, pairing or connection changes, refilling only present untitled links. When
more than the cap are in flight the oldest is evicted and its repo is listed afresh, which carries
the saved title. The refill runs in updater form so it never merges a stale store snapshot.
* fix(github): sequenced listings replace the retained-title refill
Per the re-plan ruling: the store keeps one workspaceMetadata cursor per process; a title record takes
the next seq in the same turn as its write, and each listing records the cursor when it reads metadata.
Clients note each record's seq per producer and repo; a listing at or past it ends the obligation, an
older one keeps titles the rows already show and lists the repo afresh (a new invocation, never joining
the stale one), a record whose row or link isn't listed yet asks for a fresh listing, and a seq gap
lists every repo of that producer. The retained-title table, its watcher, TTL and cap are gone.
* test(github): stamp capture, gap, restart and recovery coverage for workspace metadata listings
Also retire an environment's earlier coverage bookkeeping when it is re-paired or reconnects.
* fix(space): keep issue-title coverage per repo and host until a newer listing lands
Coverage now keeps each projection's newest record seq after its covering listing settles, so an older listing that finishes later still keeps shown titles. Projections are keyed by repo and host, paired producers keep their stream cursor, retired pairings and unlisted projections are dropped, every listing served by this host carries its metadata stamp, and a record with any unlisted titled link asks for a listing.
* fix(space): re-list after any stale listing and drop retired metadata producers
A stale listing now always asks for one fresh listing, so a link it dropped comes back and a failed scan can no longer end the wait. Removed environments drop their producer state, the producer's repo list is built only on a gap or a first-seen projection, and recovery listings skip the lineage refresh.
* perf(space): filter current rows only for listings that keep titles
* fix(space): forget removed repos on a metadata gap; keep titles for another producer run's listing
* fix(palette): search a linked issue by its saved title before its card renders
The issue's search entry took its title only from the issue cache, which fills when the card renders, and it shadowed the saved link's titled entry under the same id. It now falls back to the link's saved title.
* perf(palette): read a row's links once per palette document
* fix(palette): give each saved link its own search unit
Saved-link evidence was meant to carry an `attachment:` id but the override set an unused field, so a link shared the `issue:N` unit id with the legacy issue field and with same-number links from other repos, and only the first (often untitled) survived. The id now applies to the unit and its fields, so every saved link's title is searchable. Replaces the cache-title fallback.
* fix(space): keep the title queue draining past a failed link; encode environment ids in coverage keys
---------
The strict target check added in #38514 rejected a preview answer whose type
differed from the request, so every /issues/N link to a pull request (all bare
#N references in chat) showed "Preview unavailable.". Previews now match on
repository and number and accept either type; other callers stay strict.
Also log the failure class of a swallowed owner/repo lookup error.
* feat(runtime): tell phones when the desktop refreshes a PR
* fix(runtime): name every checkout a coalesced PR read stood for
* fix(runtime): don't count a read that couldn't load checks as a checks change
* perf(github): answer phone PR lookups from the desktop's last result
* fix(github): order last PR outcomes by lookup start sequence
* fix(github): keep reused phone PR outcomes out of the refresh observers
* fix(github): reuse a fallback-found PR only for the same fallback number
* perf(github): use the desktop's PR fallback rule on the phone and forward refreshes
* fix(github): keep a merged fallback PR while the phone has no head
* fix(github): stop PR pages from hanging when the rate-limit cache expires
Slot holders await assertRateLimitBudget -> getRateLimit while holding a
gh semaphore slot, and the /rate_limit probe queued for a slot behind
them. With all four slots held by budget waiters nothing ever released.
The probe is quota-exempt and deduped, so it no longer takes a slot.
* fix(github): bound rate-limit probe concurrency without the gh semaphore
Forced getRateLimit calls now join an in-flight probe, and all /rate_limit
probes share a small probe-only limiter that acquires nothing else.
Fold the deadlock regression test into rate-limit.test.ts as a direct await.
* fix(github): make forced rate-limit probes read quota after the call
Forced callers (403 reset refinement) share one follow-up probe queued
behind the running one instead of joining a probe that may predate the
403, so a stale positive budget cannot clear a fresh breaker block.
* fix(github): hand forced rate-limit follow-ups off synchronously
A pending forced follow-up could outlive its probe's settlement, so a
later forced caller joined a probe that predated it. Settlement now
detaches the shared deferred follow-up and starts its probe in one
synchronous step. Run rate-limit.test.ts on the Node runtime, where the
V8 scheduling that opens the race is reproducible.
* refactor: import journal queue state from defining owners
* refactor(shared): organize execution and automation owners
* fix: retain type imports used by surviving test cases
* refactor: finish work item owners and refresh validation metadata
* test: infer reconnect status fixture type
* test(claude): resolve source files beside same-named directories
* test(runtime): group repository creation mock registrations
* chore(lint): bump oxlint to 1.91, add perf lint rules and perf audits
* fix(lint): await promises returned inside try/catch/finally for return-await
Prepare typescript/return-await with error-handling-correctness-only: await
returns whose catch or finally was meant to cover them, and suppress the eight
sites where the catch must not re-handle the returned promise.
* chore(lint): enable return-await (error-handling-correctness-only); exempt secondary-scan directives in the changed gate
* refactor(mobile): move file preview discard modal into its own module
Keeps MobileFilePreviewScreen under the 400-line limit after merging main.
---------
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
RpcDispatcher now requires its method list, so these suites can no longer consume
the default manifest. Suites that still reach the registry through the RPC server
keep the guard.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Shows CI result lines in the chat that opened or pushed to a pull request. They're hidden in the terminal overlay and on the phone until the phone app gets the setting.
* fix(tasks): confirm a lost Tasks comment by author on GitLab and GitHub REST reads
Only GitHub GraphQL's viewerDidAuthor marked the viewer's comments, so on GitLab,
the GitHub REST fallbacks (including issues with more than 100 comments) and the
gh view fallbacks the phone kept an unconfirmed draft even after the comment
posted. Those reads now match the login of the account that made them, and an
explicit PR refresh reads comments uncached.
* fix(mobile): settle an unconfirmed comment only on one posted after the send
A refresh of an issue with more than 100 comments reads comments the first
load never showed, so an older identical comment by the same account looked
new and could clear the draft.
* refactor(gitlab): share the glab viewer read and skip it on Checks polling
* test(mobile): pin the clock in the unconfirmed comment test
An unconfirmed send settled as posted when the refreshed thread had any new
comment with the same text, so another person's identical comment cleared the
draft. The host now passes GitHub's viewerDidAuthor, and the phone settles only
on a comment the viewer wrote. Without it (GitLab, REST fallbacks, older hosts)
the draft stays with the check-the-thread notice.
* Upload GitHub images when pasted or dropped
Keep image bytes out of issue and review bodies by uploading from the owning composer and inserting hosted attachment URLs.
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>
* Preserve GitHub image intake across editor and thread states
* Keep image placeholder boundaries and ordinary HTML paste intact
* Match the native replace overload in the image projection fixture
* Use typed element queries in the image intake fixture
* Narrow textarea elements at the fixture boundary
* Show failed GitHub draft images as filename links
* Keep GitHub draft attachment links current across updates
* Supply the repository address in the attachment preview fixture
---------
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>