Merge branch 'main' into dev

Resolve 38 conflicts preserving both sides' work:
- Server: DB-based registries (dev) + WorkspaceGitService/DaemonConfigStore (main)
- App: script proxy/voice MCP (dev) + pin/hide tabs/bootstrap boundary (main)
- Shared: WorkspaceScriptPayload (dev) + git/GitHub runtime schemas (main)
- Deleted workspace-registry-bootstrap.ts (dev's DB approach supersedes)
This commit is contained in:
Mohamed Boudra
2026-04-14 03:05:45 +07:00
333 changed files with 13490 additions and 6317 deletions
+19 -20
View File
@@ -191,7 +191,6 @@ type CheckoutFileChange = {
isUntracked?: boolean;
};
function normalizeBranchSuggestionName(raw: string): string | null {
const trimmed = raw.trim();
if (!trimmed) {
@@ -678,7 +677,7 @@ async function requireGitRepo(cwd: string): Promise<void> {
}
}
async function getCurrentBranch(cwd: string): Promise<string | null> {
export async function getCurrentBranch(cwd: string): Promise<string | null> {
const { stdout } = await execAsync("git rev-parse --abbrev-ref HEAD", {
cwd,
env: READ_ONLY_GIT_ENV,
@@ -700,7 +699,7 @@ async function getWorktreeRoot(cwd: string): Promise<string | null> {
}
}
async function getMainRepoRoot(cwd: string): Promise<string> {
export async function getMainRepoRoot(cwd: string): Promise<string> {
const { stdout: commonDirOut } = await execAsync(
"git rev-parse --path-format=absolute --git-common-dir",
{ cwd, env: READ_ONLY_GIT_ENV },
@@ -717,9 +716,7 @@ async function getMainRepoRoot(cwd: string): Promise<string> {
env: READ_ONLY_GIT_ENV,
});
const worktrees = parseWorktreeList(worktreeOut);
const nonBareNonPaseo = worktrees.filter(
(wt) => !wt.isBare && !isPaseoWorktreePath(wt.path),
);
const nonBareNonPaseo = worktrees.filter((wt) => !wt.isBare && !isPaseoWorktreePath(wt.path));
const childrenOfBareRepo = nonBareNonPaseo.filter((wt) => isDescendantPath(wt.path, normalized));
const mainChild = childrenOfBareRepo.find((wt) => basename(wt.path) === "main");
return mainChild?.path ?? childrenOfBareRepo[0]?.path ?? nonBareNonPaseo[0]?.path ?? normalized;
@@ -844,7 +841,7 @@ async function isWorkingTreeDirty(cwd: string): Promise<boolean> {
return stdout.trim().length > 0;
}
async function getOriginRemoteUrl(cwd: string): Promise<string | null> {
export async function getOriginRemoteUrl(cwd: string): Promise<string | null> {
try {
const { stdout } = await execAsync("git config --get remote.origin.url", {
cwd,
@@ -857,12 +854,12 @@ async function getOriginRemoteUrl(cwd: string): Promise<string | null> {
}
}
async function hasOriginRemote(cwd: string): Promise<boolean> {
export async function hasOriginRemote(cwd: string): Promise<boolean> {
const url = await getOriginRemoteUrl(cwd);
return url !== null;
}
async function resolveAbsoluteGitDir(cwd: string): Promise<string | null> {
export async function resolveAbsoluteGitDir(cwd: string): Promise<string | null> {
try {
const { stdout } = await execAsync("git rev-parse --absolute-git-dir", {
cwd,
@@ -1042,7 +1039,16 @@ async function getAheadOfOrigin(cwd: string, currentBranch: string): Promise<num
const count = Number.parseInt(stdout.trim(), 10);
return Number.isNaN(count) ? null : count;
} catch {
return null;
try {
const { stdout } = await execAsync(`git rev-list --count ${currentBranch}`, {
cwd,
env: READ_ONLY_GIT_ENV,
});
const count = Number.parseInt(stdout.trim(), 10);
return Number.isNaN(count) ? null : count;
} catch {
return null;
}
}
}
@@ -1630,11 +1636,7 @@ export async function getCheckoutDiff(
if (diffBytes >= TOTAL_DIFF_MAX_BYTES) {
break;
}
const { text, truncated, stat } = await getUntrackedDiffText(
cwd,
change,
ignoreWhitespace,
);
const { text, truncated, stat } = await getUntrackedDiffText(cwd, change, ignoreWhitespace);
if (!compare.includeStructured) {
if (stat?.isBinary) {
@@ -2015,7 +2017,7 @@ type CheckRunNode = z.infer<typeof CheckRunNodeSchema>;
type StatusContextNode = z.infer<typeof StatusContextNodeSchema>;
async function resolveGhPath(): Promise<string> {
export async function resolveGhPath(): Promise<string> {
if (cachedGhPath === undefined) {
cachedGhPath = await findExecutable("gh");
}
@@ -2238,7 +2240,6 @@ async function resolveGitHubRepo(cwd: string): Promise<string | null> {
return null;
}
export async function createPullRequest(
cwd: string,
options: CreatePullRequestOptions,
@@ -2340,9 +2341,7 @@ async function getPullRequestStatusUncached(cwd: string): Promise<PullRequestSta
return { status: null, githubFeaturesEnabled: true };
}
const mergedAt =
typeof pr.mergedAt === "string" && pr.mergedAt.trim().length > 0
? pr.mergedAt
: null;
typeof pr.mergedAt === "string" && pr.mergedAt.trim().length > 0 ? pr.mergedAt : null;
const state =
mergedAt !== null
? "merged"