mirror of
https://github.com/stablyai/orca.git
synced 2026-10-27 08:02:51 +00:00
Fix packaged shell PATH order (#5125)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
committed by
Jinwoo-H
co-authored by
Orca
parent
aabbbc2bdd
commit
eec1207b8d
@@ -186,14 +186,30 @@ describe('mergePathSegments', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('skips segments already on PATH so re-hydration is a no-op', () => {
|
||||
it('promotes shell segments already on PATH so shell ordering wins', () => {
|
||||
process.env.PATH = joinPath('/Users/tester/.cargo/bin', '/usr/bin')
|
||||
|
||||
const added = mergePathSegments(['/Users/tester/.cargo/bin', '/Users/tester/.opencode/bin'])
|
||||
|
||||
expect(added).toEqual(['/Users/tester/.opencode/bin'])
|
||||
expect(process.env.PATH).toBe(
|
||||
joinPath('/Users/tester/.opencode/bin', '/Users/tester/.cargo/bin', '/usr/bin')
|
||||
joinPath('/Users/tester/.cargo/bin', '/Users/tester/.opencode/bin', '/usr/bin')
|
||||
)
|
||||
})
|
||||
|
||||
it('moves user-local shell paths ahead of packaged Homebrew fallbacks', () => {
|
||||
process.env.PATH = joinPath(
|
||||
'/opt/homebrew/bin',
|
||||
'/Users/tester/.local/bin',
|
||||
'/usr/bin',
|
||||
'/bin'
|
||||
)
|
||||
|
||||
const added = mergePathSegments(['/Users/tester/.local/bin', '/opt/homebrew/bin'])
|
||||
|
||||
expect(added).toEqual([])
|
||||
expect(process.env.PATH).toBe(
|
||||
joinPath('/Users/tester/.local/bin', '/opt/homebrew/bin', '/usr/bin', '/bin')
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -181,25 +181,31 @@ export function hydrateShellPath(options: HydrateOptions = {}): Promise<Hydratio
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend newly-discovered PATH segments to process.env.PATH, preserving
|
||||
* existing ordering and avoiding duplicates. Returns the segments that were
|
||||
* actually added so callers can log/telemetry on nontrivial hydrations.
|
||||
* Promote shell-discovered PATH segments to the front of process.env.PATH,
|
||||
* preserving shell ordering and avoiding duplicates. Returns the segments that
|
||||
* were newly added so callers can log/telemetry on nontrivial hydrations.
|
||||
*/
|
||||
export function mergePathSegments(segments: string[]): string[] {
|
||||
if (segments.length === 0) {
|
||||
return []
|
||||
}
|
||||
const current = process.env.PATH ?? ''
|
||||
const existing = new Set(current.split(delimiter).filter(Boolean))
|
||||
// Why: Node 22+ Set.prototype.difference preserves insertion order of the
|
||||
// receiver, so [...incoming.difference(existing)] gives us the new entries
|
||||
// in the order the shell provided them (first-match-wins on PATH).
|
||||
const added = [...new Set(segments).difference(existing)]
|
||||
if (added.length === 0) {
|
||||
const currentSegments = current.split(delimiter).filter(Boolean)
|
||||
const shellSegments = [...new Set(segments)]
|
||||
const shellSegmentSet = new Set(shellSegments)
|
||||
const existing = new Set(currentSegments)
|
||||
const added = shellSegments.filter((segment) => !existing.has(segment))
|
||||
const merged = [
|
||||
...shellSegments,
|
||||
...currentSegments.filter((segment) => !shellSegmentSet.has(segment))
|
||||
]
|
||||
const next = merged.join(delimiter)
|
||||
if (next === current) {
|
||||
return []
|
||||
}
|
||||
// Why: prepend so shell-provided entries win over the hardcoded fallbacks.
|
||||
// The user's rc files are the source of truth for `which`-style resolution.
|
||||
process.env.PATH = [...added, ...current.split(delimiter).filter(Boolean)].join(delimiter)
|
||||
// Why: shell-provided entries must win over hardcoded packaged-app fallbacks.
|
||||
// A seeded fallback can point at a stale CLI while the user's shell resolves
|
||||
// a healthy one from the same directory list in a different order.
|
||||
process.env.PATH = next
|
||||
return added
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user