mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* Fix automatic branch rename for non-English git locales A gettext-enabled git (Homebrew git, most Linux distro gits) under a non-English locale translates every diagnostic, including the `fatal:` prefix, so Orca's stderr phrase parsers stop matching. The first-message branch auto-rename was the headline casualty: isNoUpstreamError missed the translated no-upstream error, branchHasUpstream failed closed to "has upstream", and the rename settled silently and permanently. - Force LC_ALL=C on all Orca-spawned machine-parsed git: the local prompt-guard env chokepoint, the three relay git spawn sites, and both local clone spawns (progress + failure-message parsing). User terminals are untouched. - Replace the boolean upstream check with a tri-state probe: rename proceeds only on a proven missing upstream; an unreadable probe now raises the rename-failed badge and retries instead of settling. Fixes #7808 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * Consolidate untranslated-git-locale into runner and relay primitives Replace the five per-site LC_ALL=C patches with one shared UNTRANSLATED_GIT_OUTPUT_ENV (LANGUAGE=en LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8) injected inside the git runner primitives (promptGuardGitEnv, gitSpawn, gitExecFileSync, gitExecFileAsyncBuffer) and a relay buildRelayGitEnv() helper, so every current and future machine-parsed git spawn is covered by construction — including the fs-handler-git-fallback sites the per-site approach missed. The UTF-8 English locale keeps a UTF-8 LC_CTYPE for hooks git spawns; LANGUAGE is pinned because gettext consults it before LC_ALL. WSL-routed git gets the same values as a shell assignment prefix built in resolveCommand, since spawn env cannot cross the wsl.exe boundary — closing the WSL gap the first pass accepted. Also scrub credential-bearing remote URLs from the probe-failed message surfaced on the worktree card. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * Scrub credential-bearing URLs from clone failure messages --------- Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com>
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
import { stripCredentialsFromMessage } from './git-remote-error'
|
|
|
|
export function getGitCloneFailureMessage(
|
|
stderr: string,
|
|
options: { clonePath?: string | null } = {}
|
|
): string {
|
|
let fallbackLine: string | null = null
|
|
|
|
// Why: clone errors echo the URL the user typed, which is the most likely
|
|
// git error to embed a live token (`https://user:ghp_…@host/repo.git`).
|
|
// Scrub up-front so every return branch operates on already-redacted text,
|
|
// matching normalizeGitErrorMessage.
|
|
const scrubbedStderr = stripCredentialsFromMessage(stderr)
|
|
|
|
for (const rawLine of iterateLinesFromEnd(scrubbedStderr)) {
|
|
const line = stripAnsi(rawLine).trim()
|
|
if (!line) {
|
|
continue
|
|
}
|
|
fallbackLine ??= line
|
|
const fatalIndex = line.indexOf('fatal:')
|
|
if (fatalIndex !== -1) {
|
|
return formatGitCloneFailureLine(line.slice(fatalIndex), options)
|
|
}
|
|
const errorIndex = line.indexOf('error:')
|
|
if (errorIndex !== -1) {
|
|
return formatGitCloneFailureLine(line.slice(errorIndex), options)
|
|
}
|
|
}
|
|
|
|
return formatGitCloneFailureLine(fallbackLine ?? 'unknown error', options)
|
|
}
|
|
|
|
function* iterateLinesFromEnd(value: string): Generator<string> {
|
|
let lineEnd = value.length
|
|
let index = value.length - 1
|
|
|
|
while (index >= 0) {
|
|
const code = value.charCodeAt(index)
|
|
if (code !== 10 && code !== 13) {
|
|
index--
|
|
continue
|
|
}
|
|
|
|
const delimiterStart =
|
|
code === 10 && index > 0 && value.charCodeAt(index - 1) === 13 ? index - 1 : index
|
|
yield value.slice(index + 1, lineEnd)
|
|
lineEnd = delimiterStart
|
|
index = delimiterStart - 1
|
|
}
|
|
|
|
yield value.slice(0, lineEnd)
|
|
}
|
|
|
|
function stripAnsi(value: string): string {
|
|
return value.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, 'g'), '')
|
|
}
|
|
|
|
function formatGitCloneFailureLine(line: string, options: { clonePath?: string | null }): string {
|
|
const destinationMatch = line.match(
|
|
/^fatal:\s+destination path '([^']+)' already exists and is not an empty directory\.$/
|
|
)
|
|
if (destinationMatch || /repository exists/i.test(line)) {
|
|
const destination = options.clonePath?.trim() || destinationMatch?.[1] || null
|
|
const target = destination ? `: ${destination}` : ''
|
|
return `Destination already exists and is not empty${target}. Choose a different parent folder, delete the existing folder, or add the existing repository instead.`
|
|
}
|
|
return line
|
|
}
|