fix(preflight): ship worker and preserve CLI liveness

This commit is contained in:
Jinjing
2026-10-28 17:51:53 -07:00
parent 0eb18d9775
commit 5af784a77e
6 changed files with 116 additions and 17 deletions
@@ -66,8 +66,8 @@ export class DetectionDirectoryWorkerClient {
this.host.clearIdleTimer()
const id = this.nextId++
return new Promise((resolve) => {
// Keep plain-Node CLI invocations alive until their listings settle.
const timer = setTimeout(() => this.dispose(), REQUEST_TIMEOUT_MS)
timer.unref?.()
this.pending.set(id, { resolve, timer })
const request: DetectionDirectoryRequest = { id, dir }
try {
@@ -2,7 +2,7 @@ import fs from 'node:fs'
import fsp from 'node:fs/promises'
import { registerHooks, syncBuiltinESMExports } from 'node:module'
import path from 'node:path'
import { workerData } from 'node:worker_threads'
import { Worker, workerData } from 'node:worker_threads'
// Run unbuilt production TS in Node workers, including extensionless source imports.
registerHooks({
@@ -22,7 +22,7 @@ registerHooks({
}
})
if (workerData.blockedDirectory) {
if (workerData?.blockedDirectory) {
const originalOpen = fsp.opendir
fsp.opendir = (directory, options) =>
directory === workerData.blockedDirectory
@@ -31,7 +31,7 @@ if (workerData.blockedDirectory) {
syncBuiltinESMExports()
}
if (workerData.unknownDirectory) {
if (workerData?.unknownDirectory) {
const { dir, names, counters: buffer, holdMetadata } = workerData.unknownDirectory
const counters = new Int32Array(buffer)
const originalOpen = fsp.opendir
@@ -77,4 +77,37 @@ if (workerData.unknownDirectory) {
syncBuiltinESMExports()
}
await import(workerData.entry)
if (workerData) {
await import(workerData.entry)
} else {
const { transformSync } = await import('esbuild')
registerHooks({
load(url, context, nextLoad) {
if (url.endsWith('.ts')) {
return {
format: 'module',
source: transformSync(fs.readFileSync(new URL(url), 'utf8'), {
loader: 'ts',
format: 'esm',
target: 'esnext'
}).code,
shortCircuit: true
}
}
return nextLoad(url, context)
}
})
const { DetectionDirectoryWorkerClient } =
await import('./command-path-directory-worker-client.ts')
const client = new DetectionDirectoryWorkerClient(
() =>
new Worker(new URL(import.meta.url), {
workerData: {
entry: new URL('./command-path-directory-worker-entry.ts', import.meta.url).href
}
})
)
void client.read(process.argv[2]).then((names) => {
console.log(JSON.stringify(names === null ? null : [...names]))
})
}
@@ -4,6 +4,7 @@ import { tmpdir } from 'node:os'
import path from 'node:path'
import { pathToFileURL } from 'node:url'
import { Worker } from 'node:worker_threads'
import { runProcess } from '@orca/process-host'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type * as DirectoryWorkerClient from './command-path-directory-worker-client'
import { DetectionDirectoryWorkerClient } from './command-path-directory-worker-client'
@@ -42,6 +43,18 @@ afterEach(async () => {
})
describe('detection directory worker boundary', () => {
it('keeps a plain Node CLI alive for pending listings and lets it exit while idle', async () => {
await writeFile(path.join(dir, 'found'), '')
const result = await runProcess({
program: process.execPath,
args: [fixture, dir],
env: { ...process.env, ORCA_BACKGROUND_LAUNCH: '1' },
timeoutMs: 5_000
})
expect(result.code, result.stderr).toBe(0)
expect(result.stdout.trim()).toBe(JSON.stringify([['found', 'found']]))
})
it('keeps real unknown-Dirent metadata off the caller and closes the bounded listing before candidate fallback', async () => {
const names = Array.from({ length: 129 }, (_, index) => `unrelated-${index}`)
await Promise.all(names.map((name) => writeFile(path.join(dir, name), '')))
@@ -85,6 +98,31 @@ describe('detection directory worker boundary', () => {
await expect(value.read(path.join(dir, 'missing'))).resolves.toEqual(new Map())
})
it('still finds a stable executable when an unknown Dirent disappears during iteration', async () => {
await writeFile(path.join(dir, 'found'), '')
await chmod(path.join(dir, 'found'), 0o755)
const counters = new Int32Array(new SharedArrayBuffer(5 * Int32Array.BYTES_PER_ELEMENT))
client(
() =>
new Worker(fixture, {
workerData: {
entry,
unknownDirectory: {
dir,
names: ['deleted-neighbor', 'found'],
counters: counters.buffer
}
}
})
)
await expect(
findCommandsOnLocalPath(['found', 'b', 'c', 'd', 'e'], { env: { PATH: dir }, cwd: dir })
).resolves.toEqual(new Set(['found']))
expect(Atomics.load(counters, 0)).toBe(1)
expect(Atomics.load(counters, 1)).toBe(1)
expect(Atomics.load(counters, 2)).toBe(1)
})
it('uses async executable probes when the worker cannot start', async () => {
await writeFile(path.join(dir, 'found'), '')
await chmod(path.join(dir, 'found'), 0o755)
+18 -11
View File
@@ -1,3 +1,4 @@
import type { Dir } from 'node:fs'
import { opendir } from 'node:fs/promises'
const MAX_DETECTION_DIRECTORY_ENTRIES = 128
@@ -7,8 +8,22 @@ export function directoryNameKey(name: string): string {
}
export async function readDetectionDirectory(dir: string): Promise<Map<string, string> | null> {
let directory: Dir
try {
directory = await opendir(dir, { bufferSize: MAX_DETECTION_DIRECTORY_ENTRIES + 1 })
} catch (error) {
if (
error &&
typeof error === 'object' &&
'code' in error &&
(error.code === 'ENOENT' || error.code === 'ENOTDIR')
) {
return new Map()
}
// Searchable-but-unreadable directories still admit stat on known names.
return null
}
try {
const directory = await opendir(dir, { bufferSize: MAX_DETECTION_DIRECTORY_ENTRIES + 1 })
const names = new Map<string, string>()
let entries = 0
for await (const entry of directory) {
@@ -23,16 +38,8 @@ export async function readDetectionDirectory(dir: string): Promise<Map<string, s
names.set(directoryNameKey(entry.name), entry.name)
}
return names
} catch (error) {
if (
error &&
typeof error === 'object' &&
'code' in error &&
(error.code === 'ENOENT' || error.code === 'ENOTDIR')
) {
return new Map()
}
// Searchable-but-unreadable directories still admit stat on known names.
} catch {
// A vanished entry during Dirent conversion cannot prove the directory empty.
return null
}
}
+21 -1
View File
@@ -1,7 +1,16 @@
import { access, chmod, mkdir, mkdtemp, readdir, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
// Exercise Windows filename folding through source listings on case-sensitive hosts.
vi.mock('./command-path-directory-worker-client', async () => ({
readDetectionDirectoryViaWorker: vi.fn(
(await import('./command-path-directory')).readDetectionDirectory
)
}))
import { readDetectionDirectoryViaWorker } from './command-path-directory-worker-client'
import {
findCommandsOnLocalPath,
isCommandOnLocalPath,
@@ -313,6 +322,17 @@ describe('findCommandsOnLocalPath', () => {
).resolves.toEqual(new Set(['mixed']))
})
it('probes exact host filenames when the directory worker is unavailable', async () => {
vi.mocked(readDetectionDirectoryViaWorker).mockResolvedValueOnce(null)
await expect(
findCommandsOnLocalPath(['tool', 'missing'], {
platform: 'win32',
env: { Path: dir, PATHEXT: '.CMD' },
cwd: dir
})
).resolves.toEqual(new Set(['tool']))
})
it('matches extensionless executable names checked by the agent fallback', async () => {
await expect(
findCommandsOnLocalPath(['literal-cli'], {
+1
View File
@@ -227,6 +227,7 @@ export const ORCAD_ARTIFACTS: readonly OrcadArtifact[] = [
{ filename: 'daemon-entry.js' },
{ filename: 'profile-state-writer-worker-entry.js' },
{ filename: 'profile-state-backup-worker-entry.js' },
{ filename: 'command-path-directory-worker-entry.js' },
// Worker thread that reads other apps' SQLite (the OpenCode binder and history) off the event loop.
{ filename: ORCAD_FOREIGN_SQLITE_READER_ENTRY },
{ filename: ORCAD_PORT_SCAN_COMMAND_WORKER_ENTRY },