perf(mcp): keep Playwright and type-only imports off MCP startup (#1691)

* fix(build): emit no runtime imports for type-only bindings

Under verbatimModuleSyntax, an import whose specifiers all carry inline
`type` modifiers compiles to `import {} from "..."`, a side-effect import
that still resolves and evaluates the module. 78 compiled modules carried
one, including `import {} from "playwright-core"` in the browser scenario
session, which loaded Playwright's module graph at MCP startup.

Use top-level `import type` for these bindings and enable oxlint's
typescript/no-import-type-side-effects rule so the pattern cannot return.

Refs #1685

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* perf(mcp): load Playwright when a scenario launches, not at startup

The browser scenario and Electron active providers are constructed before
the stdio server serves, and both bound Playwright's launchers at module
load. Resolve `chromium` and `_electron` from playwright-core when a
capture opens instead, as the web module resolver already does.

MCP startup now resolves 1,312 modules (4,902 resolutions) instead of
1,598 (6,076) before reading the first request, and no longer loads
playwright-core. Provider construction, the tool catalog, and capability
inventory are unchanged.

A boundary test spawns the stdio server, initializes, lists tools, and
asserts playwright-core and isomorphic-git were not resolved; the CLI
probe now exercises the real launch path to prove detection.

Closes #1685

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Kaoru0822
2026-10-10 21:04:05 -07:00
committed by GitHub
co-authored by Claude Opus 5.5
parent a56f7bb668
commit 0ecf3f2438
89 changed files with 197 additions and 160 deletions
+2 -1
View File
@@ -22,7 +22,8 @@
],
"max-params": ["warn", 4],
"no-var": "warn",
"no-var-requires": "error"
"no-var-requires": "error",
"typescript/no-import-type-side-effects": "error"
},
"overrides": [
{
+1 -1
View File
@@ -4,7 +4,7 @@ import type {
AnalysisOperationPort,
} from "./AnalysisProvider.js";
import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { analysisBookmarkSchema } from "../domain/hopperValues.js";
import { resolveAnalysisDocument } from "./AnalysisDocument.js";
+1 -1
View File
@@ -12,7 +12,7 @@ import type {
CompareWebScreenshotsInput,
} from "../domain/webScreenshot.js";
import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../domain/result.js";
import type { ExecutionOptions } from "./AnalysisProvider.js";
import type { BrowserObservationPort } from "./BrowserObservationPort.js";
@@ -2,7 +2,7 @@ import type { ExecutionOptions } from "./AnalysisProvider.js";
import type { BrowserScenarioCapturePort } from "./BrowserScenarioCapturePort.js";
import { createBrowserScenarioEvidence } from "./BrowserScenarioEvidence.js";
import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { Evidence } from "../domain/evidence.js";
import type { BrowserScenario } from "../domain/browserScenario.js";
import { err, type Result } from "../domain/result.js";
+1 -1
View File
@@ -1,6 +1,6 @@
import type { AnalysisOperation } from "./AnalysisProvider.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { parseRelatedAddresses } from "../domain/hopperValues.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { ok, type Result } from "../domain/result.js";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
} from "../contracts/managed/managedToolContracts.js";
import { EvidenceIntegrityError } from "../domain/evidenceErrors.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { access } from "node:fs/promises";
import {
readAnalysisSnapshot,
+1 -1
View File
@@ -1,7 +1,7 @@
import { z } from "zod";
import type { AnalysisOperation } from "./AnalysisProvider.js";
import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { err, ok, type Result } from "../domain/result.js";
import type {
+1 -1
View File
@@ -1,7 +1,7 @@
import type { z } from "zod";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { err, type Result } from "../domain/result.js";
import {
+1 -1
View File
@@ -12,7 +12,7 @@ import {
AnalysisOutputError,
} from "../domain/analysisErrorCore.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import {
addressDistance,
functionDossierSchema,
+1 -1
View File
@@ -1,5 +1,5 @@
import { EvidenceIntegrityError } from "../domain/evidenceErrors.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { EvidenceBundle } from "../domain/evidenceBundle.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import {
createEvidence,
type Evidence,
@@ -2,7 +2,7 @@ import { z } from "zod";
import { reconstructionCoverageEvaluationInputSchema } from "../domain/reconstructionCoverageInput.js";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { evaluateReconstructionClosure } from "../domain/reconstructionCoverage.js";
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
import { err, ok, type Result } from "../domain/result.js";
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { createEvidence, type Evidence } from "../domain/evidence.js";
import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
import {
+3 -3
View File
@@ -18,9 +18,9 @@ import type {
} from "../reference/ReferenceSourceReaderTypes.js";
import { parseReferenceSourceEntries } from "./ReferenceSourceImportEntries.js";
import { readReferenceSourceVcs } from "./ReferenceSourceVcsAdapter.js";
import {
type ReferenceSourceImportError,
type ReferenceSourceImportOptions,
import type {
ReferenceSourceImportError,
ReferenceSourceImportOptions,
} from "./ReferenceSourceImportTypes.js";
import {
prepareReferenceSourceImport,
+6 -6
View File
@@ -1,10 +1,10 @@
import { skillDestinations } from "./SetupSkill.js";
import {
type ClientConfigurationInspection,
type ClientConfigurationResult,
type SetupHost,
type SetupOptions,
type SetupProviderEnvironment,
import type {
ClientConfigurationInspection,
ClientConfigurationResult,
SetupHost,
SetupOptions,
SetupProviderEnvironment,
} from "./SetupTypes.js";
import type { SetupClient } from "./SupportedClients.js";
import type { SetupHopperInstallResult } from "./SetupInstallFailure.js";
@@ -7,7 +7,7 @@ import {
AnalysisSnapshotMismatchError,
} from "../../domain/evidenceErrors.js";
import { NoBinaryOpenError } from "../../domain/configurationErrors.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../../domain/result.js";
import {
analysisQueryId,
+1 -1
View File
@@ -6,7 +6,7 @@ import {
type AnalysisProfileCommitment,
} from "../../domain/analysisProfile.js";
import { AnalysisCancelledError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../../domain/result.js";
import type { JsonValue } from "../../domain/jsonValue.js";
import { createEvidence } from "../../domain/evidence.js";
@@ -3,7 +3,7 @@ import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
import { NoBinaryOpenError } from "../../domain/configurationErrors.js";
import { ProviderAdapterError } from "../../domain/providerAdapterError.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { JsonValue } from "../../domain/jsonValue.js";
import type { EvidenceSubjectTarget } from "../../domain/evidence.js";
import { err, ok, type Result } from "../../domain/result.js";
+2 -2
View File
@@ -8,12 +8,12 @@ import {
} from "../../domain/analysisSnapshot.js";
import type { AnalysisSnapshot } from "../../domain/analysisSnapshot.js";
import { parseBinaryTarget } from "../BinaryTargetResolver.js";
import { type BinaryTarget } from "../../domain/binaryTargetTypes.js";
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import {
EvidenceIntegrityError,
AnalysisSnapshotMismatchError,
} from "../../domain/evidenceErrors.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, type Result } from "../../domain/result.js";
import type { SessionProviderRoute } from "./SessionProviderRouter.js";
import { SessionProviderRouter } from "./SessionProviderRouter.js";
@@ -9,8 +9,8 @@ import {
EvidenceIntegrityError,
AnalysisSnapshotMismatchError,
} from "../../domain/evidenceErrors.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import { type UnknownRegistryError } from "../../domain/unknownRegistryError.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { UnknownRegistryError } from "../../domain/unknownRegistryError.js";
import type {
RecordUnknownInput,
ResidualUnknown,
@@ -3,7 +3,7 @@ import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js"
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
import { ProviderSelectionError } from "../../domain/providerSelectionError.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../../domain/result.js";
import type {
AnalysisClient,
@@ -7,7 +7,7 @@ import {
AnalysisCapabilityUnavailableError,
AnalysisInputError,
} from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { Evidence } from "../../domain/evidence.js";
import type { ElectronActiveObservationInput } from "../../domain/javascript/electronActiveObservation.js";
import { err, type Result } from "../../domain/result.js";
@@ -6,7 +6,7 @@ import type {
ListElectronTargetsInput,
} from "../../domain/javascript/electronObservation.js";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../../domain/result.js";
import { createElectronEvidence } from "./ElectronEvidence.js";
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { Evidence } from "../../domain/evidence.js";
import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js";
import { compareJavaScriptApplicationVersions } from "../../domain/javascript/javascriptApplicationVersionComparison.js";
@@ -6,7 +6,7 @@ import {
AnalysisCancelledError,
AnalysisCapabilityUnavailableError,
} from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type {
ListJavaScriptRuntimeTargetsInput,
ObserveJavaScriptRuntimeInput,
@@ -2,7 +2,7 @@ import { resolve } from "node:path";
import { z } from "zod";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { Evidence } from "../../domain/evidence.js";
import { analysisInputErrorFromIssues } from "../../domain/inputIssueProjection.js";
import {
@@ -4,7 +4,7 @@ import {
AnalysisInputError,
AnalysisProtocolError,
} from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import {
applicationGraphEvidenceInputError,
parseApplicationGraphEvidence,
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import {
createEvidence,
type Evidence,
@@ -11,7 +11,7 @@ import {
import { parseManagedMemberEvidence } from "../../domain/managed/managedMemberComparisonMatch.js";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { createEvidence, type Evidence } from "../../domain/evidence.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import { parseBinaryTarget } from "../BinaryTargetResolver.js";
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { createEvidence, type Evidence } from "../../domain/evidence.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import {
@@ -1,7 +1,7 @@
import { z } from "zod";
import { AnalysisProtocolError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { createEvidence, type Evidence } from "../../domain/evidence.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import {
+1 -1
View File
@@ -28,7 +28,7 @@ import {
AnalysisUnsupportedTargetError,
} from "../domain/analysisErrorCore.js";
import { ArtifactOperationError } from "../domain/artifactOperationError.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { interfaceBuilderLimitsSchema } from "../domain/apple/interfaceBuilderGraph.js";
import { err, ok, type Result } from "../domain/result.js";
@@ -27,9 +27,9 @@ import {
type IntegrityContradiction,
} from "../../domain/artifactGraph.js";
import { AnalysisUnsupportedTargetError } from "../../domain/analysisErrorCore.js";
import {
type ArtifactResourceOwner,
type ArtifactResourceScope,
import type {
ArtifactResourceOwner,
ArtifactResourceScope,
} from "../ArtifactResourceScope.js";
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import type { ArtifactInventorySnapshot } from "../../domain/artifactInventorySnapshot.js";
+1 -1
View File
@@ -12,7 +12,7 @@ import {
zipPackageFormatForPath,
} from "../../domain/zipPackageFormat.js";
import { ArtifactReaderFailure } from "../ArtifactReader.js";
import { type ArtifactResourceOwner } from "../ArtifactResourceScope.js";
import type { ArtifactResourceOwner } from "../ArtifactResourceScope.js";
import type { HashResult } from "../ArtifactHash.js";
import {
hashStableRootArtifactHandle,
+1 -1
View File
@@ -34,7 +34,7 @@ import {
artifactManifestId,
} from "../../domain/artifactIdentity.js";
import { classifyAndHashRootForInventory } from "./classify.js";
import { type HashResult } from "../ArtifactHash.js";
import type { HashResult } from "../ArtifactHash.js";
import {
hashStableRootArtifact,
hashStableRootArtifactHandle,
+1 -1
View File
@@ -46,7 +46,7 @@ import { AnalysisError } from "../domain/analysisErrorBase.js";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { err, ok, type Result } from "../domain/result.js";
import {
discoverCdpEndpoint,
+1 -1
View File
@@ -1,6 +1,6 @@
import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { sanitizeBrowserUrl } from "../domain/browserObservation.js";
import { createWebTextArtifact } from "../domain/webContentArtifact.js";
+1 -1
View File
@@ -4,7 +4,7 @@ import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
import { AnalysisError } from "../domain/analysisErrorBase.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { CdpCommandRejection } from "./CdpCommandRejection.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { safeParseJson } from "../domain/safeJson.js";
import { WEB_RUNTIME_LIMITS } from "../domain/webRuntime.js";
+1 -1
View File
@@ -14,7 +14,7 @@ import {
import { AnalysisError } from "../domain/analysisErrorBase.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { err, ok, type Result } from "../domain/result.js";
import {
discoverCdpEndpoint,
+1 -1
View File
@@ -5,7 +5,7 @@ import { z } from "zod";
import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
import { AnalysisError } from "../domain/analysisErrorBase.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { sanitizeBrowserUrl } from "../domain/browserObservation.js";
import { safeParseJson } from "../domain/safeJson.js";
+1 -1
View File
@@ -2,7 +2,7 @@ import type { InspectWebPageInput } from "../domain/browserObservation.js";
import type { WebPageInspection } from "../domain/browserObservationSchemas.js";
import type { ProgressReporter } from "../application/ProgressReporter.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { stableWebResources } from "../domain/webInventory.js";
import type { CdpEndpointDiscovery, CdpEndpointTarget } from "./CdpEndpoint.js";
import { CdpConnection } from "./CdpConnection.js";
+1 -1
View File
@@ -1,5 +1,5 @@
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { CdpConnection } from "./CdpConnection.js";
import {
cdpTargetWebSocket,
@@ -3,7 +3,7 @@ import { dirname } from "node:path";
import { randomUUID } from "node:crypto";
import { fileURLToPath } from "node:url";
import { _electron as electron } from "playwright-core";
import type { _electron as electron } from "playwright-core";
import type {
ExecutionOptions,
@@ -60,8 +60,9 @@ type ElectronPaths = {
export class PlaywrightElectronActiveProvider implements ElectronActiveObservationPort {
constructor(
private readonly environment: Readonly<Record<string, string | undefined>>,
private readonly launch: typeof electron.launch = (options) =>
electron.launch(options),
// Load Playwright only when a capture launches; MCP startup stays off its module graph.
private readonly launch: typeof electron.launch = async (options) =>
(await import("playwright-core"))._electron.launch(options),
) {}
identity(): ProviderIdentity {
+4 -7
View File
@@ -2,12 +2,7 @@ import { chmod, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import {
chromium,
type Browser,
type BrowserContext,
type Page,
} from "playwright-core";
import type { Browser, BrowserContext, Page, chromium } from "playwright-core";
import type { BrowserScenario } from "../domain/browserScenario.js";
import { AnalysisError } from "../domain/analysisErrorBase.js";
@@ -479,7 +474,9 @@ export const openPlaywrightScenarioBrowser = async (
readonly retainCleanup?: (close: () => Promise<unknown>) => void;
} = {},
): Promise<OpenedScenarioBrowser> => {
const launcher = options.launcher ?? chromium;
// Load Playwright only when a scenario opens; MCP startup stays off its module graph.
const launcher =
options.launcher ?? (await import("playwright-core")).chromium;
if (scenario.browser.mode === "connect")
return openAttachedScenarioBrowser(
scenario.browser,
+1 -1
View File
@@ -1,4 +1,4 @@
import { type BrowserContext, type Page } from "playwright-core";
import type { BrowserContext, Page } from "playwright-core";
import type { BrowserScenario } from "../domain/browserScenario.js";
import type { BrowserScenarioAction } from "../domain/browserScenarioValues.js";
+1 -1
View File
@@ -16,7 +16,7 @@ import { CLI_COMMANDS } from "../cliCommandNames.js";
import { parseCliJsonInput } from "../cliJsonInput.js";
import { logCliCommand } from "../cliLogging.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { androidApplicationProjectionInputSchema } from "../domain/android/androidApplication.js";
import { appleApplicationProjectionInputSchema } from "../domain/apple/appleApplication.js";
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
+1 -1
View File
@@ -1,5 +1,5 @@
import { constants } from "node:buffer";
import { type Writable } from "node:stream";
import type { Writable } from "node:stream";
import { Cli, Filter } from "incur";
+1 -1
View File
@@ -10,7 +10,7 @@ import type { Logger } from "pino";
import { CLI_COMMANDS } from "./cliCommandNames.js";
import type { JsonValue } from "./domain/jsonValue.js";
import { projectAnalysisError } from "./domain/analysisErrorProjection.js";
import { type AnalysisError } from "./domain/analysisErrorBase.js";
import type { AnalysisError } from "./domain/analysisErrorBase.js";
/** Register caller-path Evidence commands. */
export const registerEvidenceCommands = (
+2 -5
View File
@@ -27,11 +27,8 @@ import {
import { ProviderSelectionError } from "./providerSelectionError.js";
import { UnknownRegistryError } from "./unknownRegistryError.js";
import { providerRetryAction } from "./providerOperationHealth.js";
import {
type AnalysisError,
type AnalysisErrorTag,
} from "./analysisErrorBase.js";
import { type AnalysisErrorProjection } from "./analysisErrorProjection.js";
import type { AnalysisError, AnalysisErrorTag } from "./analysisErrorBase.js";
import type { AnalysisErrorProjection } from "./analysisErrorProjection.js";
export const analysisErrorRemediationAction = (
error: AnalysisError,
+1 -4
View File
@@ -40,10 +40,7 @@ import { ProviderAdapterError } from "./providerAdapterError.js";
import { ProviderSelectionError } from "./providerSelectionError.js";
import { UnknownRegistryError } from "./unknownRegistryError.js";
import { providerRetryAction } from "./providerOperationHealth.js";
import {
type AnalysisError,
type AnalysisErrorTag,
} from "./analysisErrorBase.js";
import type { AnalysisError, AnalysisErrorTag } from "./analysisErrorBase.js";
/** Project expected failures into exhaustive, secret-safe caller fields. */
export const projectAnalysisError = (
+4 -4
View File
@@ -1,10 +1,10 @@
import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
import { z } from "zod";
import {
type ArtifactInventoryResult,
type ArtifactNode,
type ArtifactOccurrence,
import type {
ArtifactInventoryResult,
ArtifactNode,
ArtifactOccurrence,
} from "./artifactGraph.js";
import { evidenceSchema } from "./evidence.js";
import {
@@ -1,8 +1,8 @@
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
import type { Evidence } from "../evidence.js";
import {
type ApplicationEdge,
type ApplicationNode,
import type {
ApplicationEdge,
ApplicationNode,
} from "./javascriptApplicationGraphSchemas.js";
import type { ApplicationFeatureTraceResult } from "./javascriptFeatureTraceSchemas.js";
@@ -1,4 +1,4 @@
import { type JavaScriptApplicationGraph } from "./javascriptApplicationGraph.js";
import type { JavaScriptApplicationGraph } from "./javascriptApplicationGraph.js";
import { digestCanonicalValue } from "../canonicalDigest.js";
import { uniqueSorted } from "../canonicalOrdering.js";
import type { StaticLoadStateProjection } from "./javascriptRuntimeLoadState.js";
@@ -8,10 +8,10 @@ import type { ApplicationNode } from "../javascript/javascriptApplicationGraphSc
import { managedSourceCoverage } from "./managedApplicationGraphCoverage.js";
import type { Evidence } from "../evidence.js";
import { managedTokenScopesMatch } from "./managedInspectionEvidence.js";
import {
type ManagedArtifactInspection,
type ManagedMemberInspection,
type ManagedNativeBoundaryInspection,
import type {
ManagedArtifactInspection,
ManagedMemberInspection,
ManagedNativeBoundaryInspection,
} from "./managedArtifact.js";
import type {
GraphBuildState,
+1 -1
View File
@@ -7,7 +7,7 @@ import type { ProcessCapture } from "./processCaptureParsing.js";
import { comparableTerminalFrame } from "./processObservation.js";
import { AnalysisInputError } from "../analysisErrorCore.js";
import { jsonValueSchema } from "../jsonValue.js";
import { type ProcessTraceSpecification } from "./processTraceSpecification.js";
import type { ProcessTraceSpecification } from "./processTraceSpecification.js";
import { processTraceComparisonResultSchema } from "./processTraceEvaluation.js";
import {
dimensionsForTraceSources,
@@ -4,7 +4,7 @@ import {
parseProcessCapture,
type ProcessCapture,
} from "./processCaptureParsing.js";
import { type ProcessTraceSpecification } from "./processTraceSpecification.js";
import type { ProcessTraceSpecification } from "./processTraceSpecification.js";
export const emptyCapture = parseProcessCapture(EMPTY_PROCESS_CAPTURE_EXAMPLE);
export const terminal = { sequence: 0, at_ms: 900, data: "Ready" };
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { parseProcessCapture } from "./processCaptureParsing.js";
import { type ProcessTraceSpecification } from "./processTraceSpecification.js";
import type { ProcessTraceSpecification } from "./processTraceSpecification.js";
import { processTraceComparisonResultSchema } from "./processTraceEvaluation.js";
import {
capture,
+3 -3
View File
@@ -7,9 +7,9 @@ import type {
ManagedMemberInspection,
ManagedParseIssue,
} from "../domain/managed/managedArtifact.js";
import {
type ManagedMetadataLayout,
type MetadataTableLayout,
import type {
ManagedMetadataLayout,
MetadataTableLayout,
} from "./ManagedMetadataLayout.js";
import {
metadataRowCursor,
+1 -1
View File
@@ -8,7 +8,7 @@ import {
type ManagedNativeBoundaryInspection,
type ManagedParseIssue,
} from "../domain/managed/managedArtifact.js";
import { type ManagedMetadataLayout } from "./ManagedMetadataLayout.js";
import type { ManagedMetadataLayout } from "./ManagedMetadataLayout.js";
import {
metadataRowCursor,
metadataCodedToken,
+1 -1
View File
@@ -10,7 +10,7 @@ import {
AnalysisUnsupportedTargetError,
} from "../domain/analysisErrorCore.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../domain/result.js";
import type { GhidraInstallationInspection } from "./GhidraInstallation.js";
import {
+1 -1
View File
@@ -13,7 +13,7 @@ import {
attestGhidraDosComLoadImage,
attestGhidraDosLoadImage,
} from "./GhidraLoadImageValues.js";
import { type NativeAotPeResult } from "../domain/native/nativeAotPe.js";
import type { NativeAotPeResult } from "../domain/native/nativeAotPe.js";
import type { GhidraTargetSnapshot } from "./GhidraClient.js";
import type { GhidraSessionError } from "./GhidraSessionError.js";
+9 -9
View File
@@ -1,13 +1,13 @@
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
import {
type AnalysisClient,
type AnalysisClientContext,
type AnalysisProfileResolutionOptions,
type AnalysisProviderCandidate,
type CapabilityDescriptor,
type ProviderAvailability,
type ProviderIdentity,
type ProviderTargetSupport,
import type {
AnalysisClient,
AnalysisClientContext,
AnalysisProfileResolutionOptions,
AnalysisProviderCandidate,
CapabilityDescriptor,
ProviderAvailability,
ProviderIdentity,
ProviderTargetSupport,
} from "../application/AnalysisProvider.js";
import type { AppConfig } from "../config/types.js";
import {
+1 -1
View File
@@ -28,7 +28,7 @@ import {
AnalysisResourceConstraintError,
AnalysisTimeoutError,
} from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { err, ok, type Result } from "../domain/result.js";
+1 -1
View File
@@ -14,7 +14,7 @@ import {
} from "../domain/analysisErrorCore.js";
import { BinaryTargetError } from "../domain/configurationErrors.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../domain/result.js";
import {
+1 -1
View File
@@ -17,7 +17,7 @@ import {
HopperStartError,
HopperTimeoutError,
} from "../domain/hopperErrors.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import {
hopperStartupFailure,
type HopperStartupFailureDiagnostic,
+1 -1
View File
@@ -5,7 +5,7 @@ import type {
JavaScriptRuntimeTargetLocation,
} from "../domain/javascript/javascriptRuntimeObservation.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { parseCdpEndpointValue, readCdpJson } from "../browser/CdpEndpoint.js";
const versionSchema = z
+1 -1
View File
@@ -15,7 +15,7 @@ import { AnalysisError } from "../domain/analysisErrorBase.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import type { AnalysisPartialObservation } from "../domain/analysisErrorBase.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { err, ok, type Result } from "../domain/result.js";
import {
numberValue,
+3 -3
View File
@@ -2,9 +2,9 @@ import { mkdir, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { JavaScriptRecoveryPort } from "../../application/javascript/JavaScriptRecoveryPort.js";
import {
type AnalysisExecution,
type ExecutionOptions,
import type {
AnalysisExecution,
ExecutionOptions,
} from "../../application/AnalysisProvider.js";
import { SafeOutputTree } from "../../artifacts/SafeOutputTree.js";
import { SafeOutputTreeCreationFailure } from "../../artifacts/SafeOutputTreeCreationFailure.js";
+1 -1
View File
@@ -13,7 +13,7 @@ import {
AnalysisInputError,
} from "../domain/analysisErrorCore.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../domain/result.js";
import {
createNativeUiHelperRuntime,
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import { type ProcessOwnershipHost } from "./ProcessOwnership.js";
import type { ProcessOwnershipHost } from "./ProcessOwnership.js";
import { observeOwnedProcessLineage } from "./ProcessOwnershipObservation.js";
const ownership = {
runId: "run-token",
@@ -5,7 +5,7 @@ import { buildCaptureResult } from "./ProcessCaptureLifecycle.js";
import { isInitializedPtyRoot, readLinuxChildren } from "./ProcessSampling.js";
import { TerminalRenderer } from "./TerminalRenderer.js";
import { parseProcessScenario } from "../../domain/process/processScenario.js";
import { type ProcessCapture } from "../../domain/process/processCaptureParsing.js";
import type { ProcessCapture } from "../../domain/process/processCaptureParsing.js";
import type { ProcessCaptureTruncationDetails } from "../../domain/process/processCaptureCoverage.js";
import { emptyProcessCapture as emptyCapture } from "../../domain/process/processCapture.fixture.js";
+1 -1
View File
@@ -5,7 +5,7 @@ import type { ProcessScenario } from "../../domain/process/processScenario.js";
import { parseProcessCapture } from "../../domain/process/processCaptureParsing.js";
import { err, ok, type Result } from "../../domain/result.js";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import {
describeProcessCaptureExecutionFailure,
ProcessCaptureError,
+5 -5
View File
@@ -3,11 +3,11 @@ import { err, ok } from "../domain/result.js";
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
import type { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
import { traverseDirectory } from "./ReferenceSourceReaderEntries.js";
import {
type ReferenceSourceReaderOptions,
type ReferenceSourceRead,
type ReferenceSourceResult,
type TraversalState,
import type {
ReferenceSourceReaderOptions,
ReferenceSourceRead,
ReferenceSourceResult,
TraversalState,
} from "./ReferenceSourceReaderTypes.js";
import {
isAborted,
@@ -22,12 +22,12 @@ import {
validateDirectory,
bigLstat,
} from "./ReferenceSourceReaderValidate.js";
import {
type PendingDirectory,
type ReferenceSourceEntry,
type ReferenceSourceEntryKind,
type ReferenceSourceResult,
type TraversalState,
import type {
PendingDirectory,
ReferenceSourceEntry,
ReferenceSourceEntryKind,
ReferenceSourceResult,
TraversalState,
} from "./ReferenceSourceReaderTypes.js";
export const traverseDirectory = async (
+4 -4
View File
@@ -1,7 +1,7 @@
import {
type ReferenceSourceEntry,
type ReferenceSourceFailureCode,
type ReferenceSourceReaderError,
import type {
ReferenceSourceEntry,
ReferenceSourceFailureCode,
ReferenceSourceReaderError,
} from "./ReferenceSourceReaderTypes.js";
export const failure = (
+3 -3
View File
@@ -21,9 +21,9 @@ import {
sameFile,
validateDirectory,
} from "./ReferenceSourceReaderValidate.js";
import {
type ReferenceSourceEntry,
type StableFileRequest,
import type {
ReferenceSourceEntry,
StableFileRequest,
} from "./ReferenceSourceReaderTypes.js";
const READ_CHUNK_BYTES = 64 * 1024;
+2 -2
View File
@@ -1,6 +1,6 @@
import { type BigIntStats } from "node:fs";
import type { BigIntStats } from "node:fs";
import { type Result } from "../domain/result.js";
import type { Result } from "../domain/result.js";
import type { AnalysisCleanupObservation } from "../domain/analysisErrorBase.js";
import type { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
@@ -10,9 +10,9 @@ import {
rootFilesystemFailure,
} from "./ReferenceSourceReaderErrors.js";
import { isPathWithinRoot } from "../domain/localPath.js";
import {
type ReferenceSourceFailureCode,
type ReferenceSourceResult,
import type {
ReferenceSourceFailureCode,
ReferenceSourceResult,
} from "./ReferenceSourceReaderTypes.js";
export const bigLstat = (path: string): Promise<BigIntStats> =>
@@ -1,7 +1,7 @@
import type { BinarySessionPort } from "../../application/binary/BinarySessionPort.js";
import type { Evidence } from "../../domain/evidence.js";
import { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
import { type AnalysisError } from "../../domain/analysisErrorBase.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import { err, ok, type Result } from "../../domain/result.js";
import { recordDerivedEvidence } from "../recordDerivedEvidence.js";
import type { WorkflowUnknownInput } from "./types.js";
+1 -1
View File
@@ -3,7 +3,7 @@ import type { EvidenceMcpServer } from "./EvidenceMcpServer.js";
import type { BinarySessionPort } from "../application/binary/BinarySessionPort.js";
import { toolContract } from "../contracts/toolContracts.js";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import { describeValidationFailure } from "../domain/evidenceBundle.js";
import { EvidenceIntegrityError } from "../domain/evidenceErrors.js";
import {
+1 -1
View File
@@ -13,7 +13,7 @@ import { ProcessCaptureError } from "../process/capture/ProcessCaptureError.js";
import { toolContract } from "../contracts/toolContracts.js";
import type { AnalysisSnapshot } from "../domain/analysisSnapshot.js";
import { UnknownRegistryError } from "../domain/unknownRegistryError.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { Evidence } from "../domain/evidence.js";
import type { ProcessCapture } from "../domain/process/processCaptureParsing.js";
import { err, ok, type Result } from "../domain/result.js";
+1 -1
View File
@@ -7,7 +7,7 @@ import {
projectAnalysisError,
type AnalysisErrorProjection,
} from "../domain/analysisErrorProjection.js";
import { type AnalysisError } from "../domain/analysisErrorBase.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { JsonValue } from "../domain/jsonValue.js";
import type { Result } from "../domain/result.js";
import { AnalysisResourceConstraintError } from "../domain/analysisErrorCore.js";
+51 -7
View File
@@ -1,3 +1,5 @@
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { execFile } from "node:child_process";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
@@ -42,6 +44,14 @@ registerHooks({
});
`)}`;
const resolvedMarkers = (stderr: string): ReadonlySet<string> =>
new Set(
stderr
.split("\n")
.filter((line) => line.startsWith(MARKER))
.map((line) => line.slice(MARKER.length)),
);
const resolvedPackages = async (
arguments_: readonly string[],
): Promise<ReadonlySet<string>> => {
@@ -50,12 +60,7 @@ const resolvedPackages = async (
[`--import=${RESOLUTION_HOOK}`, ...arguments_],
{ cwd: process.cwd(), maxBuffer: 16 * 1_024 * 1_024 },
);
return new Set(
stderr
.split("\n")
.filter((line) => line.startsWith(MARKER))
.map((line) => line.slice(MARKER.length)),
);
return resolvedMarkers(stderr);
};
const evaluate = (source: string): readonly string[] => [
@@ -66,9 +71,19 @@ const evaluate = (source: string): readonly string[] => [
describe("CLI startup imports", () => {
it("detects each deferred package when its command code loads", async () => {
const missingBrowser = join(
await createTestTempDirectory("rea-startup-browser-"),
"missing-browser",
);
const scenario = {
browser: { mode: "launch", executable_path: missingBrowser },
environment: { viewport: { width: 1, height: 1 } },
};
await expect(
resolvedPackages(
evaluate('await import("./dist/composition/browserScenario.js");'),
evaluate(
`const { openPlaywrightScenarioBrowser } = await import("./dist/browser/PlaywrightScenarioBrowser.js"); await openPlaywrightScenarioBrowser(${JSON.stringify(scenario)}, {}).catch(() => undefined);`,
),
),
).resolves.toContain("playwright-core");
const source = await createTestTempDirectory("rea-startup-imports-");
@@ -124,3 +139,32 @@ describe("CLI startup imports", () => {
).resolves.toContain("binary-composition");
});
});
describe("MCP startup imports", () => {
it("does not load command-specific dependencies to initialize and list tools", async () => {
const transport = new StdioClientTransport({
command: process.execPath,
args: [`--import=${RESOLUTION_HOOK}`, "scripts/rea.mjs", "mcp"],
cwd: process.cwd(),
env: { PATH: process.env.PATH ?? "" },
stderr: "pipe",
});
let stderr = "";
transport.stderr?.on("data", (chunk: Buffer) => {
stderr += chunk.toString("utf8");
});
const client = new Client({ name: "rea-startup-imports", version: "1" });
try {
await client.connect(transport);
const { tools } = await client.listTools();
expect(tools.map((tool) => tool.name)).toContain(
"capture_browser_scenario",
);
} finally {
await client.close();
}
const resolved = resolvedMarkers(stderr);
expect(resolved).not.toContain("playwright-core");
expect(resolved).not.toContain("isomorphic-git");
});
});
@@ -4,7 +4,7 @@ import { buffer } from "node:stream/consumers";
import { describe, expect, it } from "vitest";
import { type ArtifactEntry } from "../../../src/artifacts/ArtifactReader.js";
import type { ArtifactEntry } from "../../../src/artifacts/ArtifactReader.js";
import { DirectoryArtifactReader } from "../../../src/artifacts/DirectoryArtifactReader.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -11,9 +11,9 @@ import {
readJavaScriptArtifactFiles,
} from "../../support/javascriptApplicationScope.js";
import { scanArtifactInventory } from "../../fixtures/artifactInventory.js";
import {
type ArtifactEntry,
type ArtifactReader,
import type {
ArtifactEntry,
ArtifactReader,
} from "../../../src/artifacts/ArtifactReader.js";
import { writeJavaScriptArtifactFixture } from "../../fixtures/javascriptArtifactApplication.js";
@@ -7,7 +7,7 @@ import { MANAGED_WORKFLOW_TOOL_CONTRACTS } from "../../../src/contracts/managed/
import { ENHANCED_TOOL_CONTRACTS } from "../../../src/contracts/enhancedToolContracts.js";
import { SESSION_TOOL_CONTRACTS } from "../../../src/contracts/sessionToolContracts.js";
import { TOOL_CONTRACTS } from "../../../src/contracts/toolContracts.js";
import {} from "../../../src/domain/jsonValue.js";
import type {} from "../../../src/domain/jsonValue.js";
import { createServer } from "../../../src/server/createServer.js";
import { observed as ok } from "../../fixtures/analysisExecution.js";
import { createAnalysisExecution } from "../../../src/application/AnalysisProvider.js";
@@ -23,7 +23,7 @@ import {
} from "../../../src/process/capture/ProcessCaptureLifecycle.js";
import { parseProcessScenario } from "../../../src/domain/process/processScenario.js";
import { emptyProcessCapture } from "../../../src/domain/process/processCapture.fixture.js";
import { type ProcessCapture } from "../../../src/domain/process/processCaptureParsing.js";
import type { ProcessCapture } from "../../../src/domain/process/processCaptureParsing.js";
const processFixture = fileURLToPath(
new URL("../../fixtures/processFidelity.mjs", import.meta.url),
@@ -7,7 +7,7 @@ import { EvidenceFileError } from "../../../src/domain/evidenceErrors.js";
import { HopperRemoteError } from "../../../src/domain/hopperErrors.js";
import { UnknownRegistryError } from "../../../src/domain/unknownRegistryError.js";
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
import { type AnalysisError } from "../../../src/domain/analysisErrorBase.js";
import type { AnalysisError } from "../../../src/domain/analysisErrorBase.js";
describe("analysis error projection contract", () => {
it("accepts every closed error-reason variant", () => {
+1 -1
View File
@@ -1,4 +1,4 @@
import { type WebSocket } from "ws";
import type { WebSocket } from "ws";
import type { FakeCdpCommand, FakeOptions } from "./fakeCdpBrowserTypes.js";