同步操作将从 ZeroFreeze/claude-code-source-code 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import { mkdir, readFile, unlink, writeFile } from 'fs/promises'import { join } from 'path'import { getSessionId } from '../../bootstrap/state.js'import { registerCleanup } from '../../utils/cleanupRegistry.js'import { logForDebugging } from '../../utils/debug.js'import { getClaudeConfigHomeDir } from '../../utils/envUtils.js'import { jsonParse, jsonStringify } from '../../utils/slowOperations.js'import { getErrnoCode } from '../errors.js'const LOCK_FILENAME = 'computer-use.lock'// Holds the unregister function for the shutdown cleanup handler.// Set when the lock is acquired, cleared when released.let unregisterCleanup: (() => void) | undefinedtype ComputerUseLock = {readonly sessionId: stringreadonly pid: numberreadonly acquiredAt: number}export type AcquireResult =| { readonly kind: 'acquired'; readonly fresh: boolean }| { readonly kind: 'blocked'; readonly by: string }export type CheckResult =| { readonly kind: 'free' }| { readonly kind: 'held_by_self' }| { readonly kind: 'blocked'; readonly by: string }const FRESH: AcquireResult = { kind: 'acquired', fresh: true }const REENTRANT: AcquireResult = { kind: 'acquired', fresh: false }function isComputerUseLock(value: unknown): value is ComputerUseLock {if (typeof value !== 'object' || value === null) return falsereturn ('sessionId' in value &&typeof value.sessionId === 'string' &&'pid' in value &&typeof value.pid === 'number')}function getLockPath(): string {return join(getClaudeConfigHomeDir(), LOCK_FILENAME)}async function readLock(): Promise<ComputerUseLock | undefined> {try {const raw = await readFile(getLockPath(), 'utf8')const parsed: unknown = jsonParse(raw)return isComputerUseLock(parsed) ? parsed : undefined} catch {return undefined}}/*** Check whether a process is still running (signal 0 probe).** Note: there is a small window for PID reuse — if the owning process* exits and an unrelated process is assigned the same PID, the check* will return true. This is extremely unlikely in practice.*/function isProcessRunning(pid: number): boolean {try {process.kill(pid, 0)return true} catch {return false}}/*** Attempt to create the lock file atomically with O_EXCL.* Returns true on success, false if the file already exists.* Throws for other errors.*/async function tryCreateExclusive(lock: ComputerUseLock): Promise<boolean> {try {await writeFile(getLockPath(), jsonStringify(lock), { flag: 'wx' })return true} catch (e: unknown) {if (getErrnoCode(e) === 'EEXIST') return falsethrow e}}/*** Register a shutdown cleanup handler so the lock is released even if* turn-end cleanup is never reached (e.g. the user runs /exit while* a tool call is in progress).*/function registerLockCleanup(): void {unregisterCleanup?.()unregisterCleanup = registerCleanup(async () => {await releaseComputerUseLock()})}/*** Check lock state without acquiring. Used for `request_access` /* `list_granted_applications` — the package's `defersLockAcquire` contract:* these tools check but don't take the lock, so the enter-notification and* overlay don't fire while the model is only asking for permission.** Does stale-PID recovery (unlinks) so a dead session's lock doesn't block* `request_access`. Does NOT create — that's `tryAcquireComputerUseLock`'s job.*/export async function checkComputerUseLock(): Promise<CheckResult> {const existing = await readLock()if (!existing) return { kind: 'free' }if (existing.sessionId === getSessionId()) return { kind: 'held_by_self' }if (isProcessRunning(existing.pid)) {return { kind: 'blocked', by: existing.sessionId }}logForDebugging(`Recovering stale computer-use lock from session ${existing.sessionId} (PID ${existing.pid})`,)await unlink(getLockPath()).catch(() => {})return { kind: 'free' }}/*** Zero-syscall check: does THIS process believe it holds the lock?* True iff `tryAcquireComputerUseLock` succeeded and `releaseComputerUseLock`* hasn't run yet. Used to gate the per-turn release in `cleanup.ts` so* non-CU turns don't touch disk.*/export function isLockHeldLocally(): boolean {return unregisterCleanup !== undefined}/*** Try to acquire the computer-use lock for the current session.** `{kind: 'acquired', fresh: true}` — first tool call of a CU turn. Callers fire* enter notifications on this. `{kind: 'acquired', fresh: false}` — re-entrant,* same session already holds it. `{kind: 'blocked', by}` — another live session* holds it.** Uses O_EXCL (open 'wx') for atomic test-and-set — the OS guarantees at* most one process sees the create succeed. If the file already exists,* we check ownership and PID liveness; for a stale lock we unlink and* retry the exclusive create once. If two sessions race to recover the* same stale lock, only one create succeeds (the other reads the winner).*/export async function tryAcquireComputerUseLock(): Promise<AcquireResult> {const sessionId = getSessionId()const lock: ComputerUseLock = {sessionId,pid: process.pid,acquiredAt: Date.now(),}await mkdir(getClaudeConfigHomeDir(), { recursive: true })// Fresh acquisition.if (await tryCreateExclusive(lock)) {registerLockCleanup()return FRESH}const existing = await readLock()// Corrupt/unparseable — treat as stale (can't extract a blocking ID).if (!existing) {await unlink(getLockPath()).catch(() => {})if (await tryCreateExclusive(lock)) {registerLockCleanup()return FRESH}return { kind: 'blocked', by: (await readLock())?.sessionId ?? 'unknown' }}// Already held by this session.if (existing.sessionId === sessionId) return REENTRANT// Another live session holds it — blocked.if (isProcessRunning(existing.pid)) {return { kind: 'blocked', by: existing.sessionId }}// Stale lock — recover. Unlink then retry the exclusive create.// If another session is also recovering, one EEXISTs and reads the winner.logForDebugging(`Recovering stale computer-use lock from session ${existing.sessionId} (PID ${existing.pid})`,)await unlink(getLockPath()).catch(() => {})if (await tryCreateExclusive(lock)) {registerLockCleanup()return FRESH}return { kind: 'blocked', by: (await readLock())?.sessionId ?? 'unknown' }}/*** Release the computer-use lock if the current session owns it. Returns* `true` if we actually unlinked the file (i.e., we held it) — callers fire* exit notifications on this. Idempotent: subsequent calls return `false`.*/export async function releaseComputerUseLock(): Promise<boolean> {unregisterCleanup?.()unregisterCleanup = undefinedconst existing = await readLock()if (!existing || existing.sessionId !== getSessionId()) return falsetry {await unlink(getLockPath())logForDebugging('Released computer-use lock')return true} catch {return false}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。