* feat(git-status): batch, cancel, and cache git status polling to cut idl
- Add a single duty-cycled refresh scheduler (activity debounce + 60s
safety timer) replacing multiple overlapping intervals, so status
polling no longer runs near-continuously on large repos (#7983).
- Let safety refreshes reuse cached numstat line counts instead of
re-running diff --numstat every cycle, invalidated by head change,
known mutations, and a bounded TTL.
- Thread AbortSignal/request-token cancellation through IPC, RPC, and
relay layers so a superseded or backgrounded git:status call is
killed instead of finishing wastefully.
- Fix automatic upstream/status apply ordering so a slow, older
refresh can no longer clobber a newer result, and so an earlier
refresh still applies when a later one fails.
* Fix aborted git status scans being mistaken for completed empty results
- An aborted scan/numstat pass now always rejects instead of silently
resolving, so a cancelled request can't look like a valid empty status.
- Stop clearing the line-stats cache key on abort, since an aborted pass
never wrote to it — clearing was evicting a concurrent scan's healthy
snapshot and forcing a redundant numstat recompute.
* Fix aborted git status scans resolving as completed results
Cancelled scans could still resolve with partial or stale data instead of
rejecting, letting callers treat an aborted refresh as a valid status. Also
stop counting aborted scan duration toward catch-up refresh pacing, which
was stretching the next refresh interval by the full length of a cancelled
(often slow) scan.
* Add cancellable, generation-aware git status polling to cut stale scans
- Route git.status through an abortable subscription per requestToken so
cancelStatus can actually abort the remote scan instead of being a
no-op, preventing wasted work and stale responses overwriting fresher
state.
- Bump the git status polling generation on push-target changes so an
in-flight refresh against the old remote/branch can't apply stale
upstream data to the new one.
- Guard the stale-conflict poller against writes after unmount.
- Retire pre-purge line-stat scans in the cache so an older in-flight
scan can't repopulate a key after a token-scoped purge.
* feat(source-control): show submodule diffs with lazy expansion
Dirty submodules now expand inline in Source Control to reveal their
inner changes, with file-level diffs that are read-only from the parent
worktree. Inner status is fetched lazily only when a submodule is
expanded, so status polling never recurses into (possibly nested)
submodules. Adds a submodule-status path across local and SSH runtimes
and git providers.
* feat(source-control): add compare-against-current-branch setting
Adds a global setting (default off) that defaults the Source Control
compare base to the current branch's upstream so the panel prioritizes
local changes instead of the full delta versus the repository default
branch. When the branch has no upstream, the compare view falls back to
working-tree-only. This affects only the compare/diff view; the Pull
Request and rebase merge target are unchanged.
* refactor(source-control): extract submodule status hook and entry-action gates
Moves the lazy submodule-expansion state into a useSourceControlSubmoduleStatus
hook and centralizes per-row stage/unstage/discard eligibility into
source-control-entry-actions, shrinking SourceControl.tsx and keeping the
read-only submodule rules consistent across the row UI, bulk actions, and tests.
The hook adds a generation guard so a slow submodule-status response from a
previous worktree (common over SSH) can't write stale status into the current
panel. On the relay side, configured submodule paths are read through a
short-TTL per-instance cache so a burst of diff clicks does not re-read
.gitmodules over the SSH link. Adds tests for the new modules.
* fix(source-control): address submodule/compare review feedback
- Degrade git.submoduleStatus to an actionable reconnect hint when an older
SSH relay lacks the RPC, mirroring clone()/worktreeIsClean fallbacks.
- Keep the branch-compare summary while upstream status is still loading so
it no longer flickers when switching worktrees with prefer-upstream on.
- Mark the compare-base switch as type="button" to avoid form submission.
- Add diff base / source control keywords to the Git settings search catalog.
- Assert the compare-base toggle's own switch state and updateSettings call.
* fix(source-control): address second-round submodule/compare review feedback
- Route submodule inner diffs through resolveSubmoduleWorktreePath so a
crafted .gitmodules path can't escape the selected worktree
- Clear statusReadsInFlight alongside the diff dedupe on git mutations so a
post-mutation getStatus() can't join a stale in-flight read
- Clear the SSH diff dedupe in getSubmoduleStatus to mirror getStatus
- Derive list-view selection from the submodule-injected rows so expanded
submodule children are selectable
- Refresh commit history when the upstream compare base changes
* Support staged submodule expansion and refine default compare base
- Support expanding and diffing staged submodule changes (HEAD vs index) independently of unstaged changes (index vs worktree).
- Track submodule expansion states using a compound key of area and path to prevent conflicts between staged and unstaged listings.
- Update the compare-against-upstream setting to a segmented control for the "Default Compare Base" policy.
- Fall back to the repository default branch when comparing a branch with no upstream, preventing comparison views from unexpectedly disappearing.
* Fix submodule staging behavior, WSL caching, and double-click toggles
- Namespace submodule path cache per WSL distro to prevent cross-distro
collisions.
- Preserve the staged area of child entries when expanding unstaged
submodules so staged inner changes do not open empty diffs.
- Prefix oldPath with the submodule path for renamed inner entries.
- Ignore click events where detail > 1 to prevent double-clicks from
instantly collapsing newly expanded submodules.
* Secure submodule path resolution and prevent stale status updates
* Extract and centralize submodule path validation into a new
`resolveSubmoduleWorktreePath` helper to prevent path traversal
exploits when resolving paths from untrusted `.gitmodules` files.
* Invalidate submodule expansion state and increment the query
generation whenever the active runtime environment or connection
route changes, preventing out-of-order responses from writing
stale data.
* Set git identity via CLI config options in test commits
- Extract test email and name into constants.
- Use `-c` config flags to pass user identity to `git commit` dynamically.
- This ensures commits succeed in submodule checkouts or CI environments
where a local or global identity is not configured.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Add Source Control Create PR intent flow
Implements the Source Control Create PR flow described in docs/source-control-create-pr-flow.md.
* Keep Commit visible beside Create PR
* Fix Create PR partial staging action band
* Integrate hosted review creation into Create PR intent flow
- Automatically create the pull or merge request on GitHub/GitLab after
successfully staging, committing, and pushing in the intent flow.
- Introduce a unified `updateCommitDrafts` helper to keep React state and
its ref synchronized, preventing draft-overwrite race conditions.
- Split primary action tests into focused files to satisfy the ESLint
`max-lines` rule.
- Replace hardcoded "Local Mac" strings with dynamic host labels.
* Support Azure DevOps and Gitea PR creation and limit large diffs
Implement automated pull request creation for Azure DevOps and Gitea
repositories. This includes REST API integration, credential checks via
environment variables, template support, and error classification.
Additionally, introduce limits on large diff payloads in git status
extraction to prevent renderer-freezing performance bottlenecks when
loading extremely large files.
* Skip source control refetches when PR creation intent is in flight
Avoid recomputing branch eligibility while isCreatePrIntentInFlight is true.
This prevents tearing down the PR composer or rotating dropdown hints
prematurely if ahead/behind or dirty states are temporarily perturbed
temporarily perturbed mid-flow.
* Expose manual prerequisite actions next to Create PR button
Previously, the Create PR intent only supported "Stage All" as a
sibling action. This expands prerequisite resolution to handle other
intermediate steps such as committing, publishing, and pushing
(including force pushing).
This ensures the edit-commit-push-review loop remains streamlined
directly within the CommitArea by displaying the specific required
next action beside the primary Create PR button.
* Move PR creation actions from CommitArea to sidebar header
- Decouples PR creation and PR intent actions from the local commit area
primary button, ensuring local/remote git actions remain primary.
- Renders a dedicated PR creation button in the source control header
beside the hosted review status.
- Simplifies CommitArea by removing prerequisite split-button rendering
and review composer logic.
* Delete source control create PR flow design document
Remove the design document for the source control create PR flow as the feature has been successfully implemented.
* Display PR creation errors in inline notice
Unify PR/review creation error reporting by replacing the duplicate
createPrErrors state with the shared createPrIntentNotice. Validation
and API errors are now shown directly within the visible inline alert
notice to improve layout consistency and visibility.
Also refactor the execution host platform label lookup to use simple
if statements instead of a switch block.
* Improve Create PR intent flow safety and provider awareness
- Integrate the hosted review composer directly into the Source Control
panel when a direct review creation action is available.
- Abort the in-flight PR creation intent flow early if the current git
branch changes to prevent staging or committing on the wrong target.
- Keep in-flight action labels provider-aware (e.g., "Create MR" on GitLab)
by passing hosted review inputs to the action resolver.
- Omit large diff text payloads from git status responses when line counts
exceed safe rendering limits to avoid UI performance degradation.
- Ensure field generation does not retarget the base branch of a PR/MR without
explicit user confirmation.
* Preserve PR and MR templates in AI pull request generation
- Preload templates (including GitLab merge requests) into the AI
context before generation to prevent bypassing provider-side fallbacks.
- Instruct the AI generator to fill out and preserve existing template
headings, required sections, and checklists instead of deleting them.
- Pass provider and template settings from the renderer to the backend
RPC and runtime handlers.
* Mock DropdownMenuShortcut in tab-title-tooltip test
Add a mock for the DropdownMenuShortcut component in the dropdown menu
mock to prevent test failures.
* feat: expandable commits and actions in the git history panel
Expand a commit row in the Commits panel to see its changed files inline; click a file to open that file's commit diff. Author and date surface on expand, so the dense row itself stays subject-only.
Right-click a commit for: open in the in-app browser, copy hash, copy message, and explain changes (spawns the default agent seeded with the commit context).
Open-in-browser resolves the provider commit URL in the main process via a new remoteCommitUrl resolver (GitHub/GitLab/Bitbucket), mirroring the existing remoteFileUrl chain end-to-end (repo, IPC, SSH provider, runtime RPC, preload) so it works for local and SSH/remote workspaces.
Layout: subject-first single-line rows with a tighter graph, refs moved inline, and local/remote ref pills deduped when they point at the same commit.
* fix: address git history review feedback
* fix: address PR review feedback on the git history panel
- Trim commit SHA before building the remote URL so whitespace input returns null instead of an invalid %20 URL.
- Gate commit-row expansion on the file loader (onLoadCommitFiles) so a row can't expand into a perpetual loading state.
- Harden the explain prompt: treat the commit subject and diff as untrusted data and run git show --no-ext-diff.
- Keep ambiguous multi-segment remote refs instead of mis-deduping them against a local branch.
- Use standard 10-char i18n keys for the new commit-history strings and translate them into es/ja/ko/zh.
* refactor: extract commit-history actions into useGitHistoryCommitActions hook
Moves the commit load/open/context-menu action callbacks (and the per-commit compare cache) out of SourceControl.tsx — which already carries a max-lines disable — into a focused hook, addressing the PR review nitpick. Behavior is unchanged.
* Refine git history row rendering, ref deduplication, and OID validation
- Prevent deduplication of remote branch badges in the history view
when multiple remotes exist or when a ref is explicitly preserved.
- Render GitHistoryRow as an accessible button with dynamic ARIA labels
for expansion states.
- Add double-click handler on commit files to open them permanently.
- Validate commit SHAs as full 40-character Git object IDs before
requesting remote commit URLs.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* WIP: Changes before auto-review fixes
* Customize Source Control AI action recipes
- Add per-action CLI arguments for generation and launch flows so saved
recipes can select model flags without putting prompts in argv.
- Share the text-generation dialog between commit messages and hosted-review
details, with first-run defaults and repo/global recipe support.
- Launch fix-check agents directly from saved recipes and harden prompt/template
handling for invalid args, blank prompts, and inherited variables.
* Allow custom commands for source control action recipes
- Let text action recipes save and resolve the custom-command sentinel
- Add settings UI for custom command recipes and preserve per-action defaults
- Split large source-control dialogs and direct launch helpers into focused modules
- Keep launch actions from treating custom text agents as runnable TUI agents
* Add per-repo Source Control AI enablement, custom command, and save-targ
- Repo overrides now support `enabled` and `customAgentCommand`, letting
repositories opt in/out of Source Control AI independently and supply a
repo-scoped custom command that takes precedence over the global one.
- Recipe-save dialogs gained a save-target selector ("Don't save / Save for
this repo / Save as global default") replacing the old boolean checkbox,
routing saves through the new `saveSourceControlActionRecipe` helper in
`source-control-ai-recipe-save.ts`.
- `normalizeRepoSourceControlAiOverrides` now returns `undefined` for empty
objects and passes the `null` sentinel through the IPC/RPC layer so the
persistence layer can clear repo overrides cleanly.
- `resolveSourceControlLaunchPlatform` resolves the correct shell platform
for SSH and WSL worktrees so agent launch commands are built correctly.
- Settings UI gained `RepositorySourceControlAiEnablement` and
`RepositorySourceControlAiCustomCommand` rows; draft/label logic was
extracted into focused modules to stay within lint line limits.
* Extract action recipe defaults into own component and use id-prefixed wo
- Move action recipe draft state and UI out of CommitMessageAiPane into SourceControlAiActionRecipeDefaults and source-control-ai-action-recipe-draft.ts to respect the max-lines lint rule
- Use toRuntimeWorktreeSelector() across all runtime git RPC calls so the runtime can resolve worktrees by ID rather than path
- Fix SSH launch platform resolution to use the repo's connection when the newly created worktree isn't hydrated yet
- Add edit and delete handlers for PR conversation comments with confirmation dialog
- Use text-status-success design token instead of hardcoded text-emerald-500
* add more search keyword
* Rename "Enable Source Control AI defaults" to "Show Source Control AI ac
* fix test
* Remove unused imports and variable assignment in launch-work-item-direct
* Fix test mocks to use `mocks.store` instead of `storeState.value` for di
* Extract Source Control AI logic into focused modules with fix-checks dia
---------
Co-authored-by: Orca <help@stably.ai>
* Create PRs directly from Source Control
- Replace the modal flow with an inline PR composer in the sidebar
- Keep PR creation state and validation scoped per worktree
- Rename the recovery action to clarify it only pushes before creating PRs
* Clean up fork PR remotes after worktree deletion
- Track Orca-created push target remotes in worktree metadata
- Reuse ownership markers when later worktrees share the same fork remote
- Fetch only the selected PR base instead of every remote before drafting PRs
- Mirror local branch cleanup for SSH worktree deletion
* Stabilize pull request creation flow
- Keep PR actions and composer fields locked while generation or creation is in flight
- Refresh git status, branch comparison, and history after remote actions settle
- Disable push-only actions on diverged branches so users sync first
* Make PR context generation read-only
- Stop rebasing or probing HEAD before collecting PR draft context
- Allow git operations on known repo roots without refreshing worktree cache
Co-authored-by: Orca <help@stably.ai>
* fix: address review findings
---------
Co-authored-by: Orca <help@stably.ai>
* feat(file-explorer): show gitignored files with dimmed italic decoration
Surfaces `.gitignore`d files in the right-sidebar file explorer with an
italicised, dimmed filename and a CircleSlash icon in the same trailing
slot used by the git status letter. A tracked change always wins — the
ignored decoration only applies when no other git status is present.
Gated behind a new `showGitIgnoredFiles` global setting (default on) so
heavy SSH workspaces can keep the smaller payload by skipping
`--ignored=matching` on `git status`.
`ignoredPaths` lives as a peer field on GitStatusResult rather than an
extension of GitFileStatus/GitStagingArea, so Source Control's
staging-area grouping is untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(file-explorer): trim redundant comments from gitignored decoration
Removes duplicated "Why:" explanations that ended up restating the same
backward-compat rationale across five files (relay, ssh provider, runtime
git commands, RPC handler, renderer git client) plus a few comments that
narrated the mechanism the code already shows.
Net: -39 lines of comment across 10 files; no behavior change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(file-explorer): drop remaining comments from gitignored decoration
The code reads well without them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* review: harden gitignored file decorations
- clear ignored decoration cache when ignored status is disabled or omitted
- keep ignored decoration state scoped across worktree and runtime cleanup
- add coverage for local, SSH, runtime, relay, and Explorer precedence
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>