refactor(admission): own inspector, web, and CLI state per host (#8058)

* refactor(admission): own inspector, web, and CLI state per host

Replace the process-global inspector, web-bundle, guidance, and JavaScript
counters with objects a host passes in, so independent instances do not
share admission or cleanup.

* fix(admission): keep worker and file cleanup on the host

Web-bundle and JavaScript workers retry only their host registry, and
each Inspector admission authorizes and closes its own file scope.
Browser providers can share one web-bundle admission.

* test(inspector): gate one admission's file cleanup

The isolation test delayed the first ArtifactResourceScope.retryCleanup
call, so a second call on a shared ElectronFileScope still finished.
Hold first.files.retryCleanup until the other admission's close
finishes, then release and join before restoring the method.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
morlutoandCursor Agent authored and GitHub committed 2026-10-30 05:23:33 +08:00
1 parent b663c79552
commit 395b598383
21 files changed
+782 -269

No files matched your search

@@ -4,6 +4,7 @@ import type {
} from "../../domain/javascript/javascriptSourceAnalysis.js";
import { JavaScriptAnalysisWorker } from "../../javascript/analysis/JavaScriptAnalysisWorker.js";
import type { spawnOwnedProviderProcess } from "../../process/ProviderProcess.js";
import { WorkerCleanupRegistry } from "../../process/OwnedWorkerRuntime.js";
import { ArtifactResourceScope } from "../ArtifactResourceScope.js";
interface RetainedJavaScriptSourceAnalysis {
@@ -17,6 +18,21 @@ const retained = new WeakMap<
RetainedJavaScriptSourceAnalysis
>();
const closeHookRegistered = new WeakSet<ArtifactResourceScope>();
const workerCleanups = new WeakMap<
ArtifactResourceScope,
WorkerCleanupRegistry
>();
const workerCleanupFor = (
scope: ArtifactResourceScope,
): WorkerCleanupRegistry => {
let cleanup = workerCleanups.get(scope);
if (cleanup === undefined) {
cleanup = new WorkerCleanupRegistry();
workerCleanups.set(scope, cleanup);
}
return cleanup;
};
export interface JavaScriptSourceAnalysisAcquisition {
/** Keep a healthy worker until this scope closes. */
@@ -82,7 +98,12 @@ const checkoutJavaScriptSourceAnalysis = async (
throw cause;
}
}
const worker = new JavaScriptAnalysisWorker(limits, launcher, sourceCount);
const worker = new JavaScriptAnalysisWorker(
limits,
launcher,
sourceCount,
workerCleanupFor(scope),
);
// A concurrent analysis may have parked another healthy worker while the
// replaced process was closing. Claim the slot only when it is still empty.
// This extra process is closed through the port returned below.