mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 10:37:35 +00:00
macOS ps formats lstart with the user's locale (%c) and vis-encodes non-ASCII argv when no UTF-8 locale is set. Under de_DE/en_NZ/ja_JP the process-table parsers dropped tty/startTime and folded them into command, breaking agent recognition, pane fingerprints, agent-session start times and daemon identity. Run those ps readers with LC_ALL=en_US.UTF-8 on macOS; other platforms keep the inherited env. Fixes #27004 Co-authored-by: outof-place <contact@outofplace.space>
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
import { runProcess } from '@orca/process-host'
|
|
import {
|
|
CHEAP_PS_ARGS,
|
|
PS_MAX_BUFFER_BYTES,
|
|
ProcessTableCaptureError,
|
|
parseCheapProcessTableRows,
|
|
type CheapProcessTableRow
|
|
} from './process-table-snapshot'
|
|
import {
|
|
PS_TIMEOUT_MS,
|
|
createProcessTableSnapshotReader,
|
|
withEvidenceBudget
|
|
} from './process-table-snapshot-reader'
|
|
import { psLocaleEnvironment } from './ps-locale-environment'
|
|
|
|
/** Keep cheap captures separate: without tty=/command= they parse differently and cannot serve strict evidence readers. Share coalescing/TTL policy. */
|
|
const cheapProcessTableReader = createProcessTableSnapshotReader<CheapProcessTableRow[]>({
|
|
runPs: async () => {
|
|
const result = await runProcess({
|
|
program: 'ps',
|
|
args: CHEAP_PS_ARGS,
|
|
env: psLocaleEnvironment(),
|
|
timeoutMs: PS_TIMEOUT_MS,
|
|
maxOutputBytes: PS_MAX_BUFFER_BYTES
|
|
})
|
|
// A ceiling hit is truncation, not absence: name it in the domain vocabulary.
|
|
if (result.outputTruncated) {
|
|
throw new ProcessTableCaptureError('capture_truncated')
|
|
}
|
|
if (result.timedOut) {
|
|
throw new ProcessTableCaptureError('capture_timeout')
|
|
}
|
|
if (result.code !== 0) {
|
|
throw new ProcessTableCaptureError(`ps_exit_${result.code ?? result.signal ?? 'unknown'}`)
|
|
}
|
|
return parseCheapProcessTableRows(result.stdout)
|
|
},
|
|
now: () => Date.now()
|
|
})
|
|
|
|
/** Bound stalled cheap reads so the full path can handle fallback instead of pinning a poll tick. */
|
|
export async function getCheapProcessTableSnapshot(): Promise<CheapProcessTableRow[]> {
|
|
return withEvidenceBudget(cheapProcessTableReader.getSnapshot())
|
|
}
|
|
|
|
export function resetCheapProcessTableSnapshotForTests(): void {
|
|
cheapProcessTableReader.reset()
|
|
}
|