mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* fix(wsl): background Git and the roots catalog never start a stopped WSL distro git status ran on the UNC project root 0.45 s after a terminate, next to the explorer read; either boots the distro. Background Git (status, conflict operation, upstream status, branch compare, the upstream-ref watch) now asks the shared running gate first and refuses for a stopped distro, including host paths whose Git runs through wsl.exe. The authorized-roots rebuild skips a stopped distro's repo and leaves it dirty, and the detected-worktree scan fails as unavailable, so rows are kept and the next scan after the distro runs lists it. * fix(wsl): the active workspace's first status and a wake read's roots rebuild may start WSL - Drive-path projects whose Git runs through WSL had no wake path: the active workspace's first git:status after it becomes active now passes wakeWslDistro, so Source Control starts the distro; later polls stay gated. - A user act runs in an async scope naming its distro; gated work inside it (the authorized-roots rebuild an authorization miss triggers, the detected scan, the Git) may start that distro and no other. External worktrees on a stopped distro no longer fail a wake read with access denied. - After a user act wakes a distro, background reads stop trusting the older 'stopped' read and probe again. * fix(wsl): explicit WSL launches refresh the running read; wake only on tab change; gate the home probe - Any wsl.exe Git/CLI run (commit, push, fetch) or WSL terminal spawn for a distro last read as stopped records that it started, so background reads probe again instead of refusing for up to 60 s. - The active editor tab wakes only when the active tab changes; effect re-runs driven by git status or overview views read without waking. - The authorization roots' WSL home probe no longer runs wsl.exe in a stopped distro when the home is uncached. - The settle window no longer imports the orcad liveness module (it pulled main code into the web typecheck); a test pins it to EXIT_SETTLE_MS. * fix(wsl): deferred work and running-list listeners never inherit a user act A user act's async scope could leak into work it triggers indirectly: a drain of deferred tasks it caused, or listeners of a running-list probe started inside it. Both now run outside the scope, so only the act's own work may start its distro. * fix(wsl): keep shared modules free of main-only gate imports worktree-logic.ts and wsl-running-distro-cache.ts are also compiled by the web project, which cannot see main-only modules (AsyncLocalStorage, wsl.exe). getAllowedRoots now injects the gated home lookup into computeWorkspaceRootWithin, and the background gate's own cache subscriptions run outside the user-act scope instead of the cache knowing about it.
205 lines
7.6 KiB
TypeScript
205 lines
7.6 KiB
TypeScript
import { ipcRenderer } from 'electron'
|
|
import type { GitForkSyncExpectedUpstream, GitForkSyncResult } from '../../shared/git-fork-sync'
|
|
import type { GitStagingArea, GitUpstreamStatus } from '../../shared/git-status-types'
|
|
import type { GitPushTarget } from '../../shared/worktree/types'
|
|
import type { GitStageWorktreeScope } from '../../shared/git-stage-worktree-scope'
|
|
import type { GitHistoryOptions, GitHistoryResult } from '../../shared/git-history'
|
|
import type { PreloadApi } from '../api-types'
|
|
|
|
export const gitApi = {
|
|
status: (args: {
|
|
worktreePath: string
|
|
connectionId?: string
|
|
includeIgnored?: boolean
|
|
bypassEffectiveUpstreamNegativeCache?: boolean
|
|
reuseLineStats?: boolean
|
|
branchLineTotalMergeBase?: string
|
|
requestToken?: string
|
|
wakeWslDistro?: boolean
|
|
}) => ipcRenderer.invoke('git:status', args),
|
|
cancelStatus: (args: { requestToken: string }): Promise<void> =>
|
|
ipcRenderer.invoke('git:cancelStatus', args),
|
|
setStatusUpstreamRefWatch: (args: {
|
|
worktreeId: string
|
|
worktreePath: string
|
|
executionHostId: string
|
|
connectionId?: string
|
|
branch?: string
|
|
upstreamName?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:setStatusUpstreamRefWatch', args),
|
|
submoduleStatus: (args: {
|
|
worktreePath: string
|
|
submodulePath: string
|
|
connectionId?: string
|
|
area?: GitStagingArea
|
|
}) => ipcRenderer.invoke('git:submoduleStatus', args),
|
|
checkIgnored: (args: {
|
|
worktreePath: string
|
|
paths: string[]
|
|
connectionId?: string
|
|
}): Promise<string[]> => ipcRenderer.invoke('git:checkIgnored', args),
|
|
findHugeFoldersToIgnore: (args: { worktreePath: string }): Promise<string[]> =>
|
|
ipcRenderer.invoke('git:findHugeFoldersToIgnore', args),
|
|
appendGitignore: (args: { worktreePath: string; folderName: string }): Promise<boolean> =>
|
|
ipcRenderer.invoke('git:appendGitignore', args),
|
|
history: (
|
|
args: { worktreePath: string; connectionId?: string } & GitHistoryOptions
|
|
): Promise<GitHistoryResult> => ipcRenderer.invoke('git:history', args),
|
|
conflictOperation: (args: { worktreePath: string; connectionId?: string }) =>
|
|
ipcRenderer.invoke('git:conflictOperation', args),
|
|
mutationInFlight: (args: { worktreePath: string; connectionId?: string }) =>
|
|
ipcRenderer.invoke('git:mutationInFlight', args),
|
|
abortMerge: (args: { worktreePath: string; connectionId?: string }): Promise<void> =>
|
|
ipcRenderer.invoke('git:abortMerge', args),
|
|
abortRebase: (args: { worktreePath: string; connectionId?: string }): Promise<void> =>
|
|
ipcRenderer.invoke('git:abortRebase', args),
|
|
diff: (args: {
|
|
worktreePath: string
|
|
filePath: string
|
|
staged: boolean
|
|
compareAgainstHead?: boolean
|
|
connectionId?: string
|
|
}) => ipcRenderer.invoke('git:diff', args),
|
|
branchCompare: (args: { worktreePath: string; baseRef: string; connectionId?: string }) =>
|
|
ipcRenderer.invoke('git:branchCompare', args),
|
|
commitCompare: (args: { worktreePath: string; commitId: string; connectionId?: string }) =>
|
|
ipcRenderer.invoke('git:commitCompare', args),
|
|
upstreamStatus: (args: {
|
|
worktreePath: string
|
|
connectionId?: string
|
|
pushTarget?: GitPushTarget
|
|
}): Promise<GitUpstreamStatus> => ipcRenderer.invoke('git:upstreamStatus', args),
|
|
fetch: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
connectionId?: string
|
|
pushTarget?: GitPushTarget
|
|
}): Promise<void> => ipcRenderer.invoke('git:fetch', args),
|
|
syncFork: (args: {
|
|
worktreePath: string
|
|
connectionId?: string
|
|
expectedUpstream: GitForkSyncExpectedUpstream
|
|
}): Promise<GitForkSyncResult> => ipcRenderer.invoke('git:syncFork', args),
|
|
push: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
publish?: boolean
|
|
forceWithLease?: boolean
|
|
connectionId?: string
|
|
pushTarget?: unknown
|
|
}): Promise<void> => ipcRenderer.invoke('git:push', args),
|
|
pull: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
connectionId?: string
|
|
pushTarget?: GitPushTarget
|
|
}): Promise<void> => ipcRenderer.invoke('git:pull', args),
|
|
fastForward: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
connectionId?: string
|
|
pushTarget?: GitPushTarget
|
|
}): Promise<void> => ipcRenderer.invoke('git:fastForward', args),
|
|
rebaseFromBase: (args: {
|
|
worktreePath: string
|
|
baseRef: string
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:rebaseFromBase', args),
|
|
branchDiff: (args: {
|
|
worktreePath: string
|
|
compare: { baseRef: string; baseOid: string; headOid: string; mergeBase: string }
|
|
filePath: string
|
|
oldPath?: string
|
|
connectionId?: string
|
|
}) => ipcRenderer.invoke('git:branchDiff', args),
|
|
commitDiff: (args: {
|
|
worktreePath: string
|
|
commitOid: string
|
|
parentOid?: string | null
|
|
filePath: string
|
|
oldPath?: string
|
|
connectionId?: string
|
|
}) => ipcRenderer.invoke('git:commitDiff', args),
|
|
commit: (args: {
|
|
worktreePath: string
|
|
message: string
|
|
connectionId?: string
|
|
}): Promise<{ success: boolean; error?: string }> => ipcRenderer.invoke('git:commit', args),
|
|
generateCommitMessage: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
repoId?: string
|
|
connectionId?: string
|
|
sourceControlAiResolvedParams?: unknown
|
|
sourceControlAi?: unknown
|
|
agentCmdOverrides?: Record<string, string>
|
|
}) => ipcRenderer.invoke('git:generateCommitMessage', args),
|
|
discoverCommitMessageModels: (args: {
|
|
agentId: string
|
|
worktreePath?: string
|
|
connectionId?: string
|
|
}) => ipcRenderer.invoke('git:discoverCommitMessageModels', args),
|
|
cancelGenerateCommitMessage: (args: {
|
|
worktreePath: string
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:cancelGenerateCommitMessage', args),
|
|
generatePullRequestFields: (args: {
|
|
worktreePath: string
|
|
worktreeId?: string
|
|
repoId?: string
|
|
base: string
|
|
title: string
|
|
body: string
|
|
draft: boolean
|
|
provider?: unknown
|
|
useTemplate?: boolean
|
|
connectionId?: string
|
|
sourceControlAiResolvedParams?: unknown
|
|
sourceControlAi?: unknown
|
|
agentCmdOverrides?: Record<string, string>
|
|
}) => ipcRenderer.invoke('git:generatePullRequestFields', args),
|
|
cancelGeneratePullRequestFields: (args: {
|
|
worktreePath: string
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:cancelGeneratePullRequestFields', args),
|
|
stage: (args: { worktreePath: string; filePath: string; connectionId?: string }): Promise<void> =>
|
|
ipcRenderer.invoke('git:stage', args),
|
|
bulkStage: (args: {
|
|
worktreePath: string
|
|
filePaths: string[]
|
|
connectionId?: string
|
|
scope?: GitStageWorktreeScope
|
|
}): Promise<void> => ipcRenderer.invoke('git:bulkStage', args),
|
|
unstage: (args: {
|
|
worktreePath: string
|
|
filePath: string
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:unstage', args),
|
|
bulkUnstage: (args: {
|
|
worktreePath: string
|
|
filePaths: string[]
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:bulkUnstage', args),
|
|
discard: (args: {
|
|
worktreePath: string
|
|
filePath: string
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:discard', args),
|
|
bulkDiscard: (args: {
|
|
worktreePath: string
|
|
filePaths: string[]
|
|
connectionId?: string
|
|
}): Promise<void> => ipcRenderer.invoke('git:bulkDiscard', args),
|
|
remoteFileUrl: (args: {
|
|
worktreePath: string
|
|
relativePath: string
|
|
line: number
|
|
connectionId?: string
|
|
}): Promise<string | null> => ipcRenderer.invoke('git:remoteFileUrl', args),
|
|
remoteCommitUrl: (args: {
|
|
worktreePath: string
|
|
sha: string
|
|
connectionId?: string
|
|
}): Promise<string | null> => ipcRenderer.invoke('git:remoteCommitUrl', args)
|
|
} satisfies PreloadApi['git']
|