{"version":3,"sources":["../src/reporter/index.ts","../src/streaming/http.ts","../src/reporter/errors.ts","../src/reporter/test-controls.ts","../src/streaming/kafka.ts","../src/utils/logger.ts","../src/utils/kafka-timeout-warning.ts","../src/utils/sizeOf.ts","../src/streaming/buffer.ts","../src/streaming/delivery.ts","../src/metadata/git.ts","../src/utils/index.ts","../src/metadata/base.ts","../src/metadata/detect-ci-provider.ts","../src/metadata/ci.ts","../src/metadata/system.ts","../src/utils/package-version.ts","../src/metadata/playwright.ts","../src/metadata/index.ts","../src/types/index.ts","../src/uploads/artifact-upload-client.ts","../src/utils/ui.ts","../src/utils/update-notifier.ts","../src/reporter/log.ts","../src/reporter/heartbeat.ts"],"sourcesContent":["import type {\n  Reporter,\n  FullConfig,\n  Suite,\n  TestCase,\n  TestResult,\n  TestStep,\n  FullResult,\n  TestError,\n} from '@playwright/test/reporter';\nimport { randomUUID } from 'crypto';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { readFile, stat } from 'fs/promises';\nimport { basename } from 'path';\nimport { HttpClient } from '../streaming/http.js';\nimport {\n  decideTestControls,\n  type TestControlsDecision,\n  type FinishedTest,\n  type QuarantineFetchOutcome,\n} from './test-controls.js';\nimport { KafkaEventProducer } from '../streaming/kafka.js';\n\nimport { EventBuffer } from '../streaming/buffer.js';\nimport { EventDeliveryManager } from '../streaming/delivery.js';\nimport { createMetadataCollector } from '../metadata/index.js';\nimport type {\n  TestdinoConfig,\n  TestEvent,\n  TestRunBeginEvent,\n  TestBeginEvent,\n  TestStepBeginEvent,\n  TestStepEndEvent,\n  TestEndEvent,\n  TestRunEndEvent,\n  TestRunErrorEvent,\n  TestConsoleOutEvent,\n  TestConsoleErrEvent,\n  RunHeartbeatEvent,\n  RunMetadata,\n  Annotation,\n} from '../types/index.js';\nimport { DEFAULT_SERVER_URL } from '../types/index.js';\nimport {\n  ArtifactUploadClient,\n  ArtifactUploadTokenError,\n  isAllowedExtension,\n  isWithinSizeLimit,\n  type UploadFileRequest,\n  type UploadTokenResult,\n} from '../uploads/index.js';\nimport { createReporterLog, type ReporterLog, type RunSummaryData } from './log.js';\nimport { symbols } from '../utils/ui.js';\nimport {\n  ForbiddenAuthError,\n  HttpDeliveryError,\n  isBlockedRunError,\n  isQuotaError,\n  InvalidTokenTypeError,\n  PartialBatchError,\n  ServerEndpointError,\n  UnauthorizedError,\n  isPermanentHttpStatus,\n} from './errors.js';\nimport { isDebugEnabled, normalizePath, sleep, waitAtMost, withTimeout } from '../utils/index.js';\nimport { awaitUpdateResult, checkForUpdate, getPackageVersion } from '../utils/update-notifier.js';\nimport { HEARTBEAT_POLL_INTERVAL_MS, HEARTBEAT_SILENCE_THRESHOLD_MS } from './heartbeat.js';\n\n// Maximum console chunk size (10KB in characters)\nconst MAX_CONSOLE_CHUNK_SIZE = 10_000;\n\n// Events per flush. Sized so one in-flight request covers what arrives during its\n// round trip (rate x RTT): a fast suite emits ~3,900 events/s, so a smaller cap\n// drains slower than events arrive and the buffer grows for the whole run.\n// Measured against the real endpoint at 3,937 events/s over a 50ms RTT: a 10-event\n// cap stranded 31,780 of 39,000 events; 500 delivered all of them, peak depth 507.\nconst MAX_BUFFER_SIZE = 500;\n\n// Byte ceiling per flush — the binding limit when events are heavy (large errors),\n// because Event Hubs rejects any single message over 1 MiB. Whichever cap trips first.\nconst MAX_BUFFER_BYTES = 1_000_000;\n\n// Periodic flush interval (ms) — ensures events are sent even when the buffer isn't\n// full. This bounds latency on slow suites, so the size cap above costs them nothing.\nconst FLUSH_INTERVAL_MS = 250;\n\n// Maximum consecutive delivery failures before discarding events (prevents unbounded buffer growth)\nconst MAX_DELIVERY_FAILURES = 3;\n\n// How long onEnd waits for a Test Controls list still in flight (the request\n// itself times out at 5 s); past it the build behaves as without Test Controls.\nconst QUARANTINE_END_WAIT_MS = 3000;\n\n// Runs inside init, which the buffer's onFlush awaits — the whole budget is\n// time the first events cannot be delivered.\nconst RUN_LINK_MAX_ATTEMPTS = 3;\nconst RUN_LINK_RETRY_DELAY_MS = 400;\nconst RUN_LINK_ATTEMPT_TIMEOUT_MS = 1000;\nconst RUN_LINK_TOTAL_BUDGET_MS = 3000;\n\n// Internal intermediate representations threaded through the uploadAttachments\n// pipeline (statAttachments → filterAllowedExtensions → putBatch). Kept close\n// to the class since no other module needs them.\ntype StatedAttachment =\n  | { name: string; contentType: string; path: string; sizeBytes: number }\n  | { name: string; contentType: string; unavailable: true };\n\ntype UploadableAttachment = { name: string; contentType: string; path: string; sizeBytes: number };\n\nexport class TestdinoReporter implements Reporter {\n  private config: TestdinoConfig;\n  private buffer: EventBuffer | null = null;\n  private runId: string;\n  private sequenceNumber = 0;\n\n  private shardInfo?: { current: number; total: number };\n  // Manual-split correlation, reaching the reporter via the CLI temp-config like shardInfo (not this.config). splitId = group key; splitInfo = position.\n  private splitInfo?: { current: number; total: number };\n  private splitId?: string;\n  // injectedRunId replaces the fresh UUID so the dispatcher ack and this reporter's\n  // run:begin/end carry the same identity (the manifest contract).\n  private swarmId?: string;\n  private injectedRunId?: string;\n  // This machine's id under swarm; emitted on run:begin so ingestion stamps\n  // test_cases.machine_id for the per-machine breakdown.\n  private machineId?: string;\n  private rerunOf?: string;\n  private runStartTime?: number;\n\n  private sigintHandler?: () => void;\n  private sigtermHandler?: () => void;\n  private isShuttingDown = false;\n  private shutdownResolve: (() => void) | null = null;\n  private shutdownPromise: Promise<void> | null = null;\n\n  private deliveryFailureCount = 0;\n\n  private quotaExceeded = false;\n  private pendingQuotaError: unknown = null;\n  // Set after run:begin is delivered when auth reports the project over its\n  // execution quota: suppress all further streaming without failing the build.\n  private overLimitBlocked = false;\n\n  private httpClient: HttpClient | null = null;\n  private runUrlPromise: Promise<string | undefined> | null = null;\n  private resolvedRunUrl: string | undefined;\n  private resolvedTestRunId: string | undefined;\n  private projectId: string | null = null;\n\n  private kafkaProducer: KafkaEventProducer | null = null;\n\n  private deliveryManager: EventDeliveryManager | null = null;\n\n  // Constructed at init when enabled; no network call happens until the first\n  // test:end that has file attachments. Upload-token issuance is per-test.\n  private artifactUploadClient: ArtifactUploadClient | null = null;\n  private artifactsEnabled = true; // Default: enabled\n\n  // Deferred initialization - resolves true on success, false on failure\n  private initPromise: Promise<boolean> | null = null;\n  private initFailed = false;\n\n  // Test Controls list, fetched while tests run; onEnd waits a little longer.\n  private quarantineFetch: Promise<QuarantineFetchOutcome> | null = null;\n  // Counted even when init failed: an error outside a test must never go green.\n  private globalErrorCount = 0;\n  private rootSuite: Suite | null = null;\n\n  // Promises for onTestEnd; must be awaited in onEnd to prevent data loss\n  private pendingTestEndPromises: Set<Promise<void>> = new Set();\n  private openAttempts = new Set<string>();\n  private openAttemptsFinalized = false;\n\n  // Started in onBegin so the registry round trip overlaps the run; read in onEnd\n  private updateCheckPromise: Promise<string | undefined> | null = null;\n\n  private artifactCounts = { screenshots: 0, videos: 0, traces: 0, other: 0, unavailable: 0 };\n\n  // Logger for consistent output\n  private log: ReporterLog;\n\n  private testCounts = { passed: 0, failed: 0, skipped: 0, timedOut: 0, interrupted: 0, flaky: 0, retried: 0 };\n  private totalTests = 0;\n  // Incremented ahead of the init guard so a batch that ran during a TestDino\n  // outage (initFailed) still counts and stays ack-eligible.\n  private executedTests = 0;\n  private beganEmpty = false;\n  private inBeginReplay = false;\n  private failedBeforeBegin = false;\n  private summaryPrinted = false;\n\n  private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n\n  private projectNames = new Set<string>();\n  private runMetadata: RunMetadata | null = null;\n  private rootDir = '';\n  private workerCount = 0;\n\n  constructor(config: TestdinoConfig = {}) {\n    const cliConfig = this.loadCliConfig();\n\n    this.config = { ...config, ...cliConfig };\n\n    this.runId = this.injectedRunId ?? randomUUID();\n\n    this.log = createReporterLog({ debug: this.config.debug ?? false });\n\n    this.artifactsEnabled = this.config.artifacts !== false;\n\n    this.buffer = new EventBuffer({\n      maxSize: MAX_BUFFER_SIZE,\n      maxBytes: MAX_BUFFER_BYTES,\n      flushIntervalMs: FLUSH_INTERVAL_MS,\n      logger: this.log,\n      onFlush: async (events) => {\n        if (this.initPromise) {\n          const success = await this.initPromise;\n          if (!success) return; // Init failed - discard events\n        }\n        // Events buffered before overLimitBlocked was set (init runs unawaited)\n        // must be dropped here too — the hook guards only stop future calls.\n        if (this.overLimitBlocked) return;\n        await this.sendEvents(events);\n      },\n    });\n  }\n\n  private loadCliConfig(): TestdinoConfig {\n    const cliConfigPath = process.env.TESTDINO_CLI_CONFIG_PATH;\n\n    if (!cliConfigPath) {\n      return {};\n    }\n\n    try {\n      if (!existsSync(cliConfigPath)) {\n        return {};\n      }\n\n      const configContent = readFileSync(cliConfigPath, 'utf-8');\n      const cliConfig = JSON.parse(configContent) as Record<string, unknown>;\n\n      const mappedConfig: TestdinoConfig = {};\n\n      if (cliConfig.token !== undefined && typeof cliConfig.token === 'string') {\n        mappedConfig.token = cliConfig.token;\n      }\n\n      if (cliConfig.serverUrl !== undefined && typeof cliConfig.serverUrl === 'string') {\n        mappedConfig.serverUrl = cliConfig.serverUrl;\n      }\n\n      if (cliConfig.debug !== undefined && typeof cliConfig.debug === 'boolean') {\n        mappedConfig.debug = cliConfig.debug;\n      }\n\n      // CI run ID for grouping sharded runs\n      if (cliConfig.ciRunId !== undefined && typeof cliConfig.ciRunId === 'string') {\n        mappedConfig.ciRunId = cliConfig.ciRunId;\n      }\n\n      // Handle artifacts flag\n      if (cliConfig.artifacts !== undefined && typeof cliConfig.artifacts === 'boolean') {\n        mappedConfig.artifacts = cliConfig.artifacts;\n      }\n\n      // Without this, --tags / TESTDINO_TAGS / --rerun-tags resolve in the CLI and never reach run:begin.\n      if (Array.isArray(cliConfig.tags)) {\n        const tags = cliConfig.tags.filter((tag): tag is string => typeof tag === 'string');\n        if (tags.length > 0) {\n          mappedConfig.tags = tags;\n        }\n      }\n\n      // Split correlation — CLI-only, stored outside this.config like shardInfo.\n      const rawSplit = cliConfig.split;\n      if (rawSplit !== null && typeof rawSplit === 'object') {\n        const { current, total } = rawSplit as { current?: unknown; total?: unknown };\n        if (typeof current === 'number' && typeof total === 'number') {\n          this.splitInfo = { current, total };\n        }\n      }\n      if (typeof cliConfig.splitId === 'string' && cliConfig.splitId.length > 0) {\n        this.splitId = cliConfig.splitId;\n      }\n      if (typeof cliConfig.rerunOf === 'string' && cliConfig.rerunOf.length > 0) {\n        this.rerunOf = cliConfig.rerunOf;\n      }\n      // A narrowed in-run re-run executes --shard=1/1, so Playwright's own shard\n      // no longer identifies the job; the CLI sends the real one here.\n      const rawShard = cliConfig.shard;\n      if (rawShard !== null && typeof rawShard === 'object') {\n        const { current, total } = rawShard as { current?: unknown; total?: unknown };\n        if (typeof current === 'number' && typeof total === 'number') {\n          this.shardInfo = { current, total };\n        }\n      }\n\n      // Swarm correlation — CLI-only, stored outside this.config like split.\n      if (typeof cliConfig.swarmId === 'string' && cliConfig.swarmId.length > 0) {\n        this.swarmId = cliConfig.swarmId;\n      }\n      if (typeof cliConfig.runId === 'string' && cliConfig.runId.length > 0) {\n        this.injectedRunId = cliConfig.runId;\n      }\n      if (typeof cliConfig.machineId === 'string' && cliConfig.machineId.length > 0) {\n        this.machineId = cliConfig.machineId;\n      }\n      // Swarm is the definitive grouping mode. A co-present split id (which\n      // the CLI validator already rejects) must never diverge the reporter rail from\n      // the dispatcher's completion manifest — swarm wins, split is dropped.\n      if (this.swarmId) {\n        this.splitId = undefined;\n        this.splitInfo = undefined;\n      }\n      return mappedConfig;\n    } catch (error) {\n      // Silently fail - CLI config is optional\n      if (isDebugEnabled()) {\n        console.warn(\n          '⚠️  TestDino: Failed to load CLI config:',\n          error instanceof Error ? error.message : String(error)\n        );\n      }\n      return {};\n    }\n  }\n\n  // Wire fields for manual-split mode: splitId top-level, split nested (mirrors\n  // shard). Both present or neither, so events never carry a half-set pair.\n  private splitFields(): { splitId: string; split: { current: number; total: number } } | undefined {\n    return this.splitId && this.splitInfo ? { splitId: this.splitId, split: this.splitInfo } : undefined;\n  }\n\n  // swarmId is top-level (no declared total); splitId is dropped in\n  // loadCliConfig when it is set, so the two never co-emit.\n  private orchFields(): { swarmId: string; machineId?: string } | undefined {\n    if (!this.swarmId) return undefined;\n    return {\n      swarmId: this.swarmId,\n      ...(this.machineId ? { machineId: this.machineId } : {}),\n    };\n  }\n\n  async onBegin(config: FullConfig, suite: Suite): Promise<void> {\n    // When global setup or test loading fails, Playwright calls onBegin itself\n    // from onEnd with an empty root suite, then synchronously replays the errors\n    // it deferred. Only errors inside that replay predate the first test; a\n    // teardown error arrives later. Recorded before any early return.\n    this.beganEmpty = suite?.allTests?.().length === 0;\n    this.inBeginReplay = true;\n    queueMicrotask(() => {\n      this.inBeginReplay = false;\n    });\n\n    // Check if we're a duplicate instance (CLI-injected when already in config)\n    if (config && this.isDuplicateInstance(config.reporter)) {\n      if (this.config.debug) {\n        this.log.debug('Reporter already configured in playwright.config, skipping duplicate instance');\n      }\n      return;\n    }\n\n    this.rootDir = config?.rootDir ?? '';\n    this.rootSuite = suite ?? null;\n    const token = this.getToken();\n\n    if (!token) {\n      this.printConfigurationError('Token is required but not provided', [\n        'Set environment variable: export TESTDINO_TOKEN=your-token',\n        'In CI, store it as a secret named TESTDINO_TOKEN and pass it to the test step',\n        'Read it in playwright.config.ts: token: process.env.TESTDINO_TOKEN',\n        'Use CLI wrapper: npx tdpw test --token your-token',\n      ]);\n      return;\n    }\n\n    // Store shard info and run start time for potential interruption handling\n    // Already set when the CLI sent the job's real shard (in-run re-run).\n    if (config?.shard && !this.shardInfo) {\n      this.shardInfo = {\n        current: config.shard.current,\n        total: config.shard.total,\n      };\n    }\n    this.runStartTime = Date.now();\n\n    // Under `tdpw test` the CLI prints this notice itself; checking here too would print it twice.\n    if (!process.env.TESTDINO_CLI_CONFIG_PATH) {\n      this.updateCheckPromise = checkForUpdate(getPackageVersion());\n    }\n\n    // Kick off async initialization without awaiting - Playwright does not await onBegin. Events will be buffered and transmitted once init completes.\n    this.initPromise = this.performAsyncInit(config, suite, token);\n  }\n\n  private async performAsyncInit(config: FullConfig, suite: Suite, token: string): Promise<boolean> {\n    const serverUrl = this.getBaseServerUrl();\n\n    try {\n      // Register signal handlers early so SIGINT during init still cleans up\n      this.registerSignalHandlers();\n\n      // Authenticate with the TestDino server\n      this.httpClient = new HttpClient({ token, serverUrl });\n      const auth = await this.httpClient.authenticate();\n      this.projectId = auth.projectId;\n      this.log.success('Authenticated successfully');\n      if (!auth.overLimit) {\n        this.log.info('TestDino Test Controls: fetching rules…');\n        this.quarantineFetch = this.httpClient.fetchQuarantineList() ?? null;\n      }\n\n      // Initialize artifact upload client if enabled. Under the new\n      // data-handler contract there is NO network call at init — upload\n      // tokens are minted per-test at test:end. Constructing the client is\n      // free.\n      if (this.artifactsEnabled) {\n        this.artifactUploadClient = new ArtifactUploadClient({\n          token,\n          serverUrl: this.getBaseServerUrl(),\n          runId: this.runId,\n          onDebug: (message) => this.log.debug(message),\n        });\n        this.log.debug('Artifact upload client ready (upload tokens minted per-test at test:end)');\n      } else {\n        this.log.info('Artifact upload disabled (artifacts: false) — screenshots, videos, and traces stay local');\n      }\n\n      // Collect metadata\n      const metadata = await this.collectMetadata(config, suite);\n      this.runMetadata = metadata;\n      this.workerCount = config.workers;\n\n      // Build run:begin event — sent directly (not via buffer) to guarantee\n      // it is the first event. initPromise resolves only after delivery,\n      // so buffer's onFlush will transmit buffered events after run:begin.\n      const beginEvent: TestRunBeginEvent = {\n        type: 'run:begin',\n        runId: this.runId,\n        projectId: this.projectId!,\n        metadata,\n        ciRunId: this.config.ciRunId,\n        shard: this.shardInfo,\n        ...this.splitFields(),\n        ...this.orchFields(),\n        ...(this.config.tags && this.config.tags.length > 0 && { tags: this.config.tags }),\n        ...(this.rerunOf && { rerunOf: this.rerunOf }),\n        timestamp: Date.now(),\n        sequence: 0,\n      };\n\n      this.log.debug(`Run ${this.runId.slice(0, 8)} — ${metadata.skeleton?.totalTests ?? 0} tests`);\n\n      // Connect to Kafka using config from auth response\n      let kafkaConnected = false;\n      if (auth.kafka) {\n        try {\n          if (!auth.kafka.channel) {\n            throw new Error('Server did not assign a Kafka channel (contract violation)');\n          }\n          this.kafkaProducer = new KafkaEventProducer({\n            brokers: auth.kafka.brokers,\n            channel: auth.kafka.channel,\n            clientId: `testdino-reporter-${this.runId.slice(0, 8)}`,\n            logger: this.log,\n            ...(auth.kafka.sasl && { sasl: auth.kafka.sasl }),\n            ...(auth.kafka.ssl !== undefined && { ssl: auth.kafka.ssl }),\n          });\n          await this.kafkaProducer.connect();\n          kafkaConnected = true;\n        } catch (kafkaError) {\n          this.log.warn(\n            `Kafka connection failed: ${kafkaError instanceof Error ? kafkaError.message : String(kafkaError)}. ` +\n              'Falling back to HTTP delivery.'\n          );\n          await this.kafkaProducer?.close();\n          this.kafkaProducer = null;\n        }\n      }\n\n      if (kafkaConnected && this.kafkaProducer) {\n        if (!auth.httpFallback) {\n          this.log.warn('Server omitted httpFallback URL — kafka-only mode, no recovery on kafka failure');\n        }\n        this.deliveryManager = new EventDeliveryManager({\n          kafkaProducer: this.kafkaProducer,\n          httpClient: this.httpClient!,\n          ...(auth.httpFallback && { httpFallbackUrl: auth.httpFallback }),\n          logger: this.log,\n        });\n      } else if (auth.httpFallback) {\n        this.deliveryManager = new EventDeliveryManager({\n          httpClient: this.httpClient!,\n          httpFallbackUrl: auth.httpFallback,\n          logger: this.log,\n        });\n      }\n\n      // Send run:begin via delivery manager (Kafka primary + HTTP fallback, or HTTP-only)\n      if (this.deliveryManager) {\n        // Set before the send: over HTTP, ingestion answers a blocked run:begin\n        // with a 402 and the catch below must already know the run is blocked.\n        if (auth.overLimit) this.overLimitBlocked = true;\n        this.log.debug(\n          kafkaConnected ? 'Delivery channel: kafka (primary) + http (fallback)' : 'Delivery channel: http only'\n        );\n        await this.deliveryManager.send(beginEvent);\n        this.log.success(kafkaConnected ? 'run:begin delivered' : 'run:begin delivered (HTTP fallback)');\n\n        // Over limit: run:begin was delivered (so ingestion surfaces the blocked\n        // run), but stop before the run URL + heartbeat so nothing else streams.\n        if (this.overLimitBlocked) {\n          this.log.warn(\n            'Over execution limit — this run will not be recorded on TestDino. Tests will continue to run.'\n          );\n          return true;\n        }\n\n        // Not backgrounded: the list reporter erases the preceding line to\n        // repaint, wiping anything printed once it starts rendering. Every shard\n        // announces its own — separate processes, often separate machines.\n        this.resolvedRunUrl = await this.resolveRunUrl();\n        this.runUrlPromise = Promise.resolve(this.resolvedRunUrl);\n        const startLink = this.sliceScopedUrl(this.resolvedRunUrl);\n        // Under swarm each batch is a separate reporter process and none knows the\n        // merged run's link; the dashboard is the place to watch a swarm run.\n        if (startLink && !this.swarmId) this.log.runLink(startLink);\n\n        // Start heartbeat monitor now that delivery channel is ready\n        this.startHeartbeatMonitor();\n      }\n\n      return true;\n    } catch (error) {\n      // Ingestion refused the run:begin as over limit (HTTP path): a blocked run,\n      // not a reporter failure, so the build stays green and the notice prints.\n      if (isBlockedRunError(error) || (this.overLimitBlocked && isQuotaError(error))) {\n        this.overLimitBlocked = true;\n        this.log.warn('Over execution limit — this run will not be recorded on TestDino. Tests will continue to run.');\n        return true;\n      }\n      this.initFailed = true;\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      if (isQuotaError(error)) {\n        this.quotaExceeded = true;\n        this.pendingQuotaError = error;\n      } else if (error instanceof InvalidTokenTypeError) {\n        this.printConfigurationError('Invalid token type', [\n          error.message,\n          'Generate a pipeline API key (td_api_...) from your TestDino project settings',\n          `Server URL: ${serverUrl}`,\n        ]);\n      } else if (error instanceof ForbiddenAuthError) {\n        this.printConfigurationError('Authentication forbidden', [\n          error.message,\n          'Verify your project has access to this server',\n          `Server URL: ${serverUrl}`,\n        ]);\n      } else if (error instanceof ServerEndpointError) {\n        this.printConfigurationError('Wrong server URL', [\n          error.message,\n          'Check serverUrl in your config (CLI > testdino.config > playwright.config > env)',\n        ]);\n      } else if (error instanceof UnauthorizedError) {\n        this.printConfigurationError('Authentication failed - Invalid or expired token', [\n          'Verify your token is correct',\n          'Check if the token has expired',\n          'Generate a new token from TestDino dashboard',\n          `Server URL: ${serverUrl}`,\n        ]);\n      } else {\n        this.printConfigurationError(`Failed to initialize TestDino reporter: ${errorMessage}`, [\n          'Check if TestDino server is running and accessible',\n          `Verify server URL is correct: ${serverUrl}`,\n          'Check network connectivity',\n          'Review server logs for details',\n        ]);\n      }\n      this.log.error(`Failed to initialize reporter: ${errorMessage}`);\n      return false;\n    }\n  }\n\n  async onTestBegin(test: TestCase, result: TestResult): Promise<void> {\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    const key = this.attemptKey(test, result);\n    this.openAttempts.add(key);\n\n    const event: TestBeginEvent = {\n      type: 'test:begin',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      // Test identification\n      testId: test.id,\n      title: test.title,\n      titlePath: test.titlePath(),\n\n      // Location information (normalized to repo-relative)\n      location: {\n        file: this.normalizeFilePath(test.location.file),\n        line: test.location.line,\n        column: test.location.column,\n      },\n\n      // Test configuration\n      tags: test.tags,\n      expectedStatus: test.expectedStatus,\n      timeout: test.timeout,\n      retries: test.retries,\n      annotations: this.extractAnnotations(test.annotations),\n\n      // Execution context\n      retry: result.retry,\n      workerIndex: result.workerIndex,\n      parallelIndex: result.parallelIndex,\n      repeatEachIndex: test.repeatEachIndex,\n\n      // Hierarchy information\n      parentSuite: this.extractParentSuite(test.parent),\n\n      // Timing\n      startTime: result.startTime.getTime(),\n    };\n\n    try {\n      await this.buffer!.add(event);\n    } catch {\n      this.openAttempts.delete(key);\n    }\n  }\n\n  private attemptKey(test: TestCase, result: Pick<TestResult, 'retry'>): string {\n    return `${test.id}:${result.retry}`;\n  }\n\n  private didNotStart(status: FullResult['status']): boolean {\n    return this.beganEmpty && this.failedBeforeBegin && status !== 'passed';\n  }\n\n  private finalizeOpenAttemptsAsInterrupted(): void {\n    if (this.openAttemptsFinalized) return;\n    this.openAttemptsFinalized = true;\n    const n = this.openAttempts.size;\n    if (n === 0) return;\n    this.testCounts.interrupted += n;\n    this.totalTests += n;\n    // These attempts began (onTestBegin fired) but never reached onTestEnd, so bump the\n    // ack-gate count here too — an interrupted-but-started batch genuinely ran.\n    this.executedTests += n;\n    this.openAttempts.clear();\n  }\n\n  async onStepBegin(test: TestCase, result: TestResult, step: TestStep): Promise<void> {\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    const event: TestStepBeginEvent = {\n      type: 'step:begin',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      testId: test.id,\n      stepId: `${test.id}-${step.titlePath().join('-')}`,\n      title: step.title,\n      titlePath: step.titlePath(),\n\n      category: step.category,\n\n      // Location Information (normalized to repo-relative)\n      location: step.location\n        ? {\n            file: this.normalizeFilePath(step.location.file),\n            line: step.location.line,\n            column: step.location.column,\n          }\n        : undefined,\n\n      parentStep: step.parent ? this.extractParentStep(step.parent) : undefined,\n\n      // Timing\n      startTime: step.startTime.getTime(),\n\n      retry: result.retry,\n\n      workerIndex: result.workerIndex,\n      parallelIndex: result.parallelIndex,\n\n      // Annotations\n      annotations: this.extractAnnotations(step.annotations),\n    };\n\n    await this.buffer!.add(event);\n  }\n\n  async onStepEnd(test: TestCase, result: TestResult, step: TestStep): Promise<void> {\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    // Derive status from error presence\n    const status: 'passed' | 'failed' = step.error ? 'failed' : 'passed';\n\n    const event: TestStepEndEvent = {\n      type: 'step:end',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      testId: test.id,\n      stepId: `${test.id}-${step.titlePath().join('-')}`,\n      title: step.title,\n      titlePath: step.titlePath(),\n\n      // Timing\n      duration: step.duration,\n\n      error: this.extractError(step.error),\n\n      // Status Information\n      status,\n\n      // Child Steps Summary\n      childSteps: this.extractChildSteps(step),\n\n      attachments: this.extractAttachments(step),\n\n      // Annotations\n      annotations: this.extractAnnotations(step.annotations),\n\n      retry: result.retry,\n\n      workerIndex: result.workerIndex,\n      parallelIndex: result.parallelIndex,\n    };\n\n    await this.buffer!.add(event);\n  }\n\n  onTestEnd(test: TestCase, result: TestResult): void {\n    // Ack-gate count first — before the init guard — so a batch that genuinely ran\n    // during a TestDino outage (initFailed) is still recorded as having produced results.\n    this.executedTests++;\n\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    this.openAttempts.delete(this.attemptKey(test, result));\n\n    // Track project name\n    const projectName = this.getProjectName(test);\n    if (projectName) {\n      this.projectNames.add(projectName);\n    }\n\n    if (!this.openAttemptsFinalized) {\n      // Track test result counts for summary table display\n      if (result.retry > 0) {\n        this.testCounts.retried++;\n      }\n      // Playwright only retries an `unexpected` outcome, so anything else is\n      // already the last attempt. Keying on status dropped every test whose\n      // final attempt was failed or skipped below the retry ceiling, and\n      // counted a passing attempt once per retry.\n      const isFinalAttempt =\n        result.status === 'interrupted' || test.outcome() !== 'unexpected' || result.retry === test.retries;\n      if (isFinalAttempt) {\n        this.totalTests++;\n        // Bucket on Playwright's verdict: `status` describes one attempt and\n        // disagrees with it for a `test.fail()` test.\n        const outcome = test.outcome();\n        if (outcome === 'flaky') {\n          this.testCounts.flaky++;\n        } else if (outcome === 'skipped') {\n          this.testCounts.skipped++;\n        } else if (outcome === 'expected') {\n          this.testCounts.passed++;\n        } else if (result.status === 'timedOut') {\n          this.testCounts.timedOut++;\n        } else if (result.status === 'interrupted') {\n          this.testCounts.interrupted++;\n        } else {\n          this.testCounts.failed++;\n        }\n      }\n    }\n\n    // Create and track the async work - Playwright does not await onTestEnd\n    const workPromise = this.processTestEnd(test, result);\n    this.pendingTestEndPromises.add(workPromise);\n\n    // Remove from tracking when complete (success or failure)\n    workPromise.finally(() => {\n      this.pendingTestEndPromises.delete(workPromise);\n    });\n  }\n\n  private waitForShutdown(): Promise<void> {\n    if (this.isShuttingDown) return Promise.resolve();\n    if (!this.shutdownPromise) {\n      this.shutdownPromise = new Promise((resolve) => {\n        this.shutdownResolve = resolve;\n      });\n    }\n    return this.shutdownPromise;\n  }\n\n  private async processTestEnd(test: TestCase, result: TestResult): Promise<void> {\n    try {\n      let attachmentsWithUrls: TestEndEvent['attachments'];\n      if (this.isShuttingDown) {\n        attachmentsWithUrls = this.attachmentsAsUnavailable(result.attachments);\n      } else {\n        attachmentsWithUrls = await Promise.race([\n          this.uploadAttachments(result.attachments, test.id),\n          this.waitForShutdown().then(() => this.attachmentsAsUnavailable(result.attachments)),\n        ]);\n        if (this.isShuttingDown) {\n          attachmentsWithUrls = this.attachmentsAsUnavailable(result.attachments);\n        } else {\n          this.tallyArtifacts(attachmentsWithUrls);\n        }\n      }\n\n      const event: TestEndEvent = {\n        type: 'test:end',\n        runId: this.runId,\n        ...this.getEventMetadata(),\n\n        testId: test.id,\n\n        // Status Information\n        status: result.status as 'passed' | 'failed' | 'skipped' | 'timedOut' | 'interrupted',\n        outcome: test.outcome(),\n\n        // Timing\n        duration: result.duration,\n\n        // Execution Context\n        retry: result.retry,\n\n        workerIndex: result.workerIndex,\n        parallelIndex: result.parallelIndex,\n\n        annotations: this.extractAnnotations(result.annotations),\n\n        errors: result.errors\n          .map((e) => this.extractError(e))\n          .filter((e): e is NonNullable<typeof e> => e !== undefined),\n\n        steps: this.extractTestStepsSummary(result),\n\n        // Attachments Metadata (with Azure URLs when uploaded)\n        attachments: attachmentsWithUrls,\n\n        stdout: result.stdout.length > 0 ? this.extractConsoleOutput(result.stdout) : undefined,\n        stderr: result.stderr.length > 0 ? this.extractConsoleOutput(result.stderr) : undefined,\n      };\n\n      this.buffer!.enqueue(event);\n    } catch (error) {\n      // Log error but don't throw - one test failure shouldn't break others\n      this.log.error(`Failed to process test:end event: ${error instanceof Error ? error.message : String(error)}`);\n    }\n  }\n\n  async onEnd(result: FullResult): Promise<{ status?: FullResult['status'] } | void> {\n    // Written FIRST, before any early return, so the spawner can tell an empty batch\n    // from one that ran even during a TestDino outage; a write failure never fails the build.\n    const resultPath = process.env.TESTDINO_RUN_RESULT_PATH;\n    if (resultPath) {\n      try {\n        writeFileSync(resultPath, JSON.stringify({ totalTests: this.executedTests }));\n      } catch {\n        // reporter-isolation: never let a sentinel write break the customer run.\n      }\n    }\n\n    if (!this.initPromise) {\n      await this.printUpdateNoticeIfAvailable();\n      return;\n    }\n\n    // Await init before reading quotaExceeded — the init catch sets it async\n    // and onEnd can fire before it lands.\n    const success = await this.initPromise;\n\n    if (this.overLimitBlocked) {\n      this.stopHeartbeatMonitor();\n      if (this.pendingTestEndPromises.size > 0) {\n        await Promise.allSettled(Array.from(this.pendingTestEndPromises));\n      }\n      this.printOverLimitNotice();\n      this.log.success('Tests completed — this run was not recorded on TestDino (over execution limit)');\n      this.buffer?.destroy();\n      await this.kafkaProducer?.close();\n      await this.printUpdateNoticeIfAvailable();\n      this.removeSignalHandlers();\n      // Return void, never { status: 'failed' } — an over-limit run must not fail\n      // the customer's build; Playwright's own exit status stands.\n      return;\n    }\n\n    if (this.quotaExceeded) {\n      this.stopHeartbeatMonitor();\n      if (this.pendingTestEndPromises.size > 0) {\n        await Promise.allSettled(Array.from(this.pendingTestEndPromises));\n      }\n      if (this.pendingQuotaError) {\n        this.printQuotaError(this.pendingQuotaError);\n      }\n      this.log.success('Tests completed (quota limit reached; not streamed to TestDino)');\n      this.buffer?.destroy();\n      await this.kafkaProducer?.close();\n      await this.printUpdateNoticeIfAvailable();\n      this.removeSignalHandlers();\n      return { status: 'failed' };\n    }\n\n    if (!success) {\n      // don't fire after resources are torn down (floating promise prevention)\n      if (this.pendingTestEndPromises.size > 0) {\n        await Promise.allSettled(Array.from(this.pendingTestEndPromises));\n      }\n      this.buffer?.destroy();\n      this.pendingTestEndPromises.clear();\n      await this.kafkaProducer?.close();\n      await this.printUpdateNoticeIfAvailable();\n      this.removeSignalHandlers();\n      return;\n    }\n\n    // Stop heartbeat monitor — run is ending, no more heartbeats needed\n    this.stopHeartbeatMonitor();\n\n    // Await completion of all pending test:end events before flushing final events\n    if (this.pendingTestEndPromises.size > 0) {\n      this.log.debug(`Waiting for ${this.pendingTestEndPromises.size} pending test:end events...`);\n      // Use Promise.allSettled for error isolation - one failed test shouldn't block others\n      await Promise.allSettled(Array.from(this.pendingTestEndPromises));\n    }\n\n    const testControls = await this.decideTestControls(result);\n\n    const event: TestRunEndEvent = {\n      type: 'run:end',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      // The test results' status, never Test Controls' decision: a run with a\n      // failed test is failed even when quarantine passed the build.\n      status: result.status as 'passed' | 'failed' | 'timedout' | 'interrupted',\n\n      // Timing\n      duration: result.duration,\n      startTime: result.startTime.getTime(),\n\n      shard: this.shardInfo,\n      ...this.splitFields(),\n      ...this.orchFields(),\n\n      quarantine: testControls.block,\n\n      executedTests: this.totalTests + this.openAttempts.size,\n      ...(this.didNotStart(result.status) && { notStarted: true as const }),\n    };\n\n    // Stop the periodic flush timer before the final explicit flush\n    this.buffer?.destroy();\n\n    // Flush any remaining buffered events first (retry once — doFlush restores events on failure)\n    try {\n      await this.buffer?.flush();\n    } catch (error) {\n      this.log.warn(`Failed to flush buffered events, retrying: ${error}`);\n      try {\n        await this.buffer?.flush();\n      } catch (retryError) {\n        this.log.error(`Retry flush also failed, some events may be lost: ${retryError}`);\n      }\n    }\n\n    // Deliver run:end via delivery manager (Kafka primary, HTTP fallback)\n    // Skip if SIGINT handler is already sending an interruption event\n    if (this.deliveryManager && !this.isShuttingDown) {\n      try {\n        await this.deliveryManager.send(event);\n        this.log.success('run:end delivered');\n      } catch (error) {\n        this.log.error(`Failed to deliver run:end event: ${error instanceof Error ? error.message : String(error)}`);\n      }\n    }\n\n    // Print comprehensive run summary\n    if (!this.summaryPrinted) {\n      this.summaryPrinted = true;\n      const summaryData: RunSummaryData = {\n        runId: this.resolvedTestRunId ?? this.runId,\n        runMetadata: this.runMetadata,\n        testCounts: this.testCounts,\n        artifactCounts: this.artifactCounts,\n        totalTests: this.totalTests,\n        workerCount: this.workerCount,\n        projectNames: this.projectNames,\n        shardInfo: this.shardInfo,\n        artifactsDisabled: !this.artifactsEnabled,\n        // Never re-resolves: a second loop would add its timeout budget to shutdown.\n        runUrl: this.sliceScopedUrl(this.resolvedRunUrl ?? (await this.runUrlPromise) ?? undefined),\n      };\n      this.log.printRunSummary(result, summaryData);\n    }\n    for (const line of testControls.report) this.log[line.tone](line.text);\n\n    // initFailed excluded: a TestDino outage during init must not fail the\n    // customer's build (reporter-isolation). Quota is handled by the early\n    // return above.\n    const discardedEvents = this.deliveryManager?.discardCount ?? 0;\n    const deliveryFailed = discardedEvents > 0 && !this.initFailed;\n\n    if (deliveryFailed) {\n      this.printDeliveryDiscardBanner(discardedEvents);\n    }\n\n    // Close connections and remove signal handlers\n    if (!this.isShuttingDown) {\n      await this.kafkaProducer?.close();\n      await this.printUpdateNoticeIfAvailable();\n      this.removeSignalHandlers();\n    }\n\n    if (deliveryFailed) return { status: 'failed' };\n    if (testControls.status) return { status: testControls.status };\n  }\n\n  private async decideTestControls(result: FullResult): Promise<TestControlsDecision> {\n    const fetch = this.quarantineFetch\n      ? await waitAtMost(this.quarantineFetch, QUARANTINE_END_WAIT_MS, { reason: 'timeout' } as const)\n      : ({ reason: 'unreachable' } as const);\n    return decideTestControls({\n      fetch,\n      tests: this.finishedTests(),\n      runStatus: result.status,\n      globalErrorCount: this.globalErrorCount,\n    });\n  }\n\n  private finishedTests(): FinishedTest[] {\n    return (this.rootSuite?.allTests() ?? []).map((test) => {\n      const last = test.results[test.results.length - 1];\n      return {\n        id: test.id,\n        title: test.title,\n        outcome: test.outcome(),\n        errorMessage: last?.error?.message ?? last?.errors?.[0]?.message ?? '',\n      };\n    });\n  }\n\n  private printDeliveryDiscardBanner(count: number): void {\n    const border = '═'.repeat(70);\n    console.error('');\n    console.error(border);\n    console.error('  ⚠️  TestDino Reporter dropped events — run marked FAILED');\n    console.error(border);\n    console.error(`  ${count} event${count === 1 ? '' : 's'} were not delivered to TestDino.`);\n    console.error('');\n    console.error('  The dashboard for this run will show incomplete data.');\n    console.error('  CI exit code is non-zero so this cannot be misread as a passing build.');\n    console.error(border);\n    console.error('');\n  }\n\n  async onError(error: TestError): Promise<void> {\n    this.globalErrorCount++;\n    if (this.inBeginReplay) this.failedBeforeBegin = true;\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    const event: TestRunErrorEvent = {\n      type: 'run:error',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      // Error Information (with cause support)\n      error: this.extractGlobalError(error),\n    };\n\n    await this.buffer!.add(event);\n  }\n\n  async onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult): Promise<void> {\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    const { text, truncated } = this.truncateChunk(chunk);\n\n    const event: TestConsoleOutEvent = {\n      type: 'console:out',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      text,\n\n      // Test Association (optional)\n      testId: test?.id,\n      retry: result?.retry,\n\n      // Truncation Indicator\n      truncated,\n    };\n\n    await this.buffer!.add(event);\n  }\n\n  async onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult): Promise<void> {\n    if (!this.initPromise || this.initFailed || this.overLimitBlocked) return;\n\n    const { text, truncated } = this.truncateChunk(chunk);\n\n    const event: TestConsoleErrEvent = {\n      type: 'console:err',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n\n      // Console Error Output\n      text,\n\n      // Test Association (optional)\n      testId: test?.id,\n      retry: result?.retry,\n\n      // Truncation Indicator\n      truncated,\n    };\n\n    await this.buffer!.add(event);\n  }\n\n  printsToStdio(): boolean {\n    return false;\n  }\n\n  private async sendEvents(events: TestEvent[]): Promise<void> {\n    if (events.length === 0) return;\n\n    // Deliver via delivery manager (Kafka primary, HTTP fallback with retry)\n    // Debug logging happens at the delivery layer (batch-level, not per-event)\n    if (this.deliveryManager) {\n      try {\n        await this.deliveryManager.sendBatch(events);\n        this.deliveryFailureCount = 0;\n      } catch (error) {\n        if (error instanceof HttpDeliveryError && isPermanentHttpStatus(error.status)) {\n          this.log.error(`Permanent delivery error (HTTP ${error.status}) — discarding ${events.length} events`);\n          this.deliveryManager.recordDiscard(events.length);\n          return;\n        }\n        if (isBlockedRunError(error)) {\n          this.log.warn(\n            'Over execution limit — this run will not be recorded on TestDino. Tests will continue to run.'\n          );\n          this.overLimitBlocked = true;\n          // Init already started the heartbeat for this run; ingestion refused it.\n          this.stopHeartbeatMonitor();\n          this.deliveryManager.recordDiscard(events.length);\n          return;\n        }\n        // Quota errors bypass HttpDeliveryError, so the permanent-status branch\n        // above misses them. Set quotaExceeded so onEnd's early return fires.\n        if (isQuotaError(error)) {\n          this.log.error(`Permanent delivery error (402 quota) — discarding ${events.length} events`);\n          this.quotaExceeded = true;\n          this.pendingQuotaError = error;\n          this.deliveryManager.recordDiscard(events.length);\n          return;\n        }\n\n        // Partial-batch → some sub-batches shipped; reset the consecutive-failure\n        // counter (a peer succeeding is progress).\n        if (error instanceof PartialBatchError) {\n          this.deliveryFailureCount = 0;\n          throw error;\n        }\n\n        this.deliveryFailureCount++;\n        this.log.error(`Failed to deliver events: ${error instanceof Error ? error.message : String(error)}`);\n\n        if (this.deliveryFailureCount <= MAX_DELIVERY_FAILURES) {\n          throw error; // Let buffer restore events for retry on next flush\n        }\n        // Sustained outage — discard to prevent unbounded buffer growth\n        this.log.warn(\n          `Delivery failed ${MAX_DELIVERY_FAILURES} consecutive times — discarding events to prevent memory growth`\n        );\n        this.deliveryManager.recordDiscard(events.length);\n        this.deliveryFailureCount = 0;\n      }\n    } else {\n      this.log.debug(`No delivery manager — ${events.length} events dropped`);\n    }\n  }\n\n  private getToken(): string | undefined {\n    return this.config.token || process.env.TESTDINO_TOKEN;\n  }\n\n  private getBaseServerUrl(): string {\n    return this.config.serverUrl || process.env.TESTDINO_SERVER_URL || DEFAULT_SERVER_URL;\n  }\n\n  private printConfigurationError(message: string, solutions: string[]): void {\n    const border = '═'.repeat(70);\n    console.error('');\n    console.error(border);\n    console.error(`  ${symbols.error} TestDino Reporter Configuration Error`);\n    console.error(border);\n    console.error(`  ${message}`);\n    console.error('');\n    console.error('  Solutions:');\n    solutions.forEach((solution, index) => {\n      console.error(`    ${index + 1}. ${solution}`);\n    });\n    console.error(border);\n    console.error('');\n  }\n\n  private async collectMetadata(playwrightConfig: FullConfig, playwrightSuite: Suite): Promise<RunMetadata> {\n    try {\n      const metadataCollector = createMetadataCollector(playwrightConfig, playwrightSuite);\n      const result = await metadataCollector.collectAll();\n\n      if (result.failureCount > 0) {\n        this.log.warn(`${result.failureCount}/${result.results.length} metadata collectors failed`);\n      }\n\n      // Build skeleton from suite\n      const skeleton = metadataCollector.buildSkeleton(playwrightSuite);\n\n      // The collector reads Playwright's own shard, which a narrowed in-run\n      // re-run has replaced with 1/1; shardInfo holds the job's real one, and\n      // it is what groups an attempt's jobs into a single run.\n      const playwright = this.shardInfo\n        ? { ...result.metadata.playwright, shard: this.shardInfo }\n        : result.metadata.playwright;\n\n      // Add skeleton to metadata\n      return {\n        ...result.metadata,\n        ...(playwright && { playwright }),\n        skeleton,\n      };\n    } catch (error) {\n      this.log.warn(`Metadata collection failed: ${error instanceof Error ? error.message : String(error)}`);\n      return {}; // Return empty metadata as fallback\n    }\n  }\n\n  private normalizeFilePath(filePath: string): string {\n    return normalizePath(filePath, this.rootDir);\n  }\n\n  private getEventMetadata() {\n    return {\n      timestamp: Date.now(),\n      sequence: ++this.sequenceNumber,\n    };\n  }\n\n  private extractAnnotations(annotations: Array<Annotation> | undefined): Array<Annotation> {\n    if (!annotations || annotations.length === 0) {\n      return [];\n    }\n\n    return annotations.map((a) => ({\n      type: a.type,\n      description: a.description,\n    }));\n  }\n\n  private extractParentSuite(parent: Suite): TestBeginEvent['parentSuite'] {\n    return {\n      title: parent.title,\n      type: parent.type,\n      location: parent.location\n        ? {\n            file: this.normalizeFilePath(parent.location.file),\n            line: parent.location.line,\n            column: parent.location.column,\n          }\n        : undefined,\n    };\n  }\n\n  private extractParentStep(parent: TestStep): TestStepBeginEvent['parentStep'] {\n    return {\n      title: parent.title,\n      category: parent.category,\n      location: parent.location\n        ? {\n            file: this.normalizeFilePath(parent.location.file),\n            line: parent.location.line,\n            column: parent.location.column,\n          }\n        : undefined,\n    };\n  }\n\n  private extractChildSteps(step: TestStep): TestStepEndEvent['childSteps'] {\n    return {\n      count: step.steps.length,\n      steps: step.steps.map((child) => ({\n        title: child.title,\n        status: child.error ? 'failed' : 'passed',\n      })),\n    };\n  }\n\n  private extractError(error: TestError | undefined): TestStepEndEvent['error'] {\n    if (!error) return undefined;\n\n    return {\n      message: error.message || String(error),\n      stack: error.stack,\n      snippet: error.snippet,\n      value: error.value,\n      location: error.location\n        ? {\n            file: this.normalizeFilePath(error.location.file),\n            line: error.location.line,\n            column: error.location.column,\n          }\n        : undefined,\n    };\n  }\n\n  private extractGlobalError(error: TestError): TestRunErrorEvent['error'] {\n    return {\n      message: error.message ?? String(error.value ?? 'Unknown error'),\n      stack: error.stack,\n      snippet: error.snippet,\n      value: error.value,\n      location: error.location\n        ? {\n            file: this.normalizeFilePath(error.location.file),\n            line: error.location.line,\n            column: error.location.column,\n          }\n        : undefined,\n      // Handle nested error cause (v1.49+)\n      cause: error.cause\n        ? {\n            message: error.cause.message,\n            stack: error.cause.stack,\n            snippet: error.cause.snippet,\n            value: error.cause.value,\n            location: error.cause.location\n              ? {\n                  file: this.normalizeFilePath(error.cause.location.file),\n                  line: error.cause.location.line,\n                  column: error.cause.location.column,\n                }\n              : undefined,\n          }\n        : undefined,\n    };\n  }\n\n  // Advisory, non-failing notice — deliberately worded to NOT collide with\n  // printQuotaError's build-failing \"Execution Limit Reached\" banner, and on\n  // console.warn (a heads-up, not an error). The overLimit flag carries no quota\n  // detail payload (plan, reset date, usage), so there is nothing to render from.\n  private printOverLimitNotice(): void {\n    const border = '═'.repeat(70);\n    console.warn('');\n    console.warn(border);\n    console.warn('  ⚠️  TestDino: this run was not recorded');\n    console.warn(border);\n    console.warn('');\n    console.warn('  Your organization has reached its execution limit.');\n    console.warn('  This run was not saved to TestDino and will not appear later.');\n    console.warn('  Your tests and CI build status are unaffected.');\n    console.warn('');\n    console.warn('  To resume recording runs, upgrade your plan, or on Pro and Team');\n    console.warn('  plans an org admin can add executions for this billing cycle');\n    console.warn('  in Settings → Billing & Usage.');\n    console.warn(border);\n    console.warn('');\n  }\n\n  private printQuotaError(error: unknown): void {\n    const border = '═'.repeat(70);\n    const errorData = error as Record<string, unknown>;\n    const details = errorData.details as Record<string, unknown>;\n    const planName = (details?.planName as string) || 'Unknown';\n    const resetDate = details?.resetDate;\n    const formattedResetDate = resetDate\n      ? new Date(resetDate as string).toLocaleDateString('en-US', {\n          day: '2-digit',\n          month: 'short',\n          year: 'numeric',\n        })\n      : undefined;\n\n    console.error('');\n    console.error(border);\n\n    if (errorData.code === 'QUOTA_EXCEEDED') {\n      const exceeded = details as {\n        total?: number;\n        used?: number;\n        remaining?: number;\n        totalTests?: number;\n        projectName?: string;\n        projectLimit?: number;\n        projectUsed?: number;\n        projectBorrowed?: number;\n      };\n\n      // Always calculate remaining from total - used (don't trust server's remaining field)\n      const orgRemaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);\n      const effectiveLimit = (exceeded.projectLimit ?? 0) + (exceeded.projectBorrowed ?? 0);\n\n      console.error(`  ${symbols.error} TestDino Project Execution Limit Reached`);\n      console.error(border);\n      console.error('');\n      console.error('  The test case limit allocated to this project has been exceeded.');\n      console.error('');\n      console.error('  Project Usage:');\n      if (exceeded.projectName) {\n        console.error(`    Project:          ${exceeded.projectName}`);\n      }\n      if (exceeded.projectLimit != null) {\n        console.error(\n          `    Limit:            ${effectiveLimit} test cases${exceeded.projectBorrowed ? ` (${exceeded.projectLimit} allocated + ${exceeded.projectBorrowed} borrowed)` : ''}`\n        );\n      }\n      if (exceeded.projectUsed != null) {\n        console.error(`    Used:             ${exceeded.projectUsed}`);\n      }\n      console.error(`    This run:         ${exceeded.totalTests || 'Unknown'} test cases`);\n      console.error('    Status:           Project quota exhausted');\n      console.error('');\n      console.error('  Organization Usage:');\n      console.error(`    Plan:             ${planName} (${exceeded.total || 'Unknown'} test cases / month)`);\n      console.error(`    Used:             ${exceeded.used || 'Unknown'}`);\n      console.error(`    Remaining:        ${orgRemaining}`);\n      if (orgRemaining > 0) {\n        console.error('');\n        console.error('  Note:');\n        console.error(`  Your organization still has ${orgRemaining} test cases available,`);\n        console.error('  but they are not allocated to this project.');\n      }\n      console.error('');\n      console.error('  Solutions:');\n      console.error('    1. Allocate more test case quota to this project in');\n      console.error('       Settings → Billing & Usage → Test Limits');\n      console.error('    2. Enable Auto Allocation to automatically distribute');\n      console.error('       remaining organization quota');\n    } else if (errorData.code === 'QUOTA_EXHAUSTED') {\n      console.error(`  ${symbols.error} TestDino Organization Execution Limit Reached`);\n      console.error(border);\n      console.error('');\n      console.error('  Your organization has exhausted its monthly test case limit.');\n      console.error('');\n      console.error('  Organization Usage:');\n      console.error(`    Plan:             ${planName} (${details.totalLimit || 'Unknown'} test cases / month)`);\n      console.error(`    Used:             ${details.used || 'Unknown'}`);\n      console.error('    Remaining:        0');\n      console.error('');\n      console.error('  Solutions:');\n      console.error('    1. Upgrade your plan, or on Pro and Team plans an org admin can');\n      console.error('       add executions for this billing cycle in Settings → Billing & Usage');\n    }\n\n    if (formattedResetDate) {\n      console.error('');\n      console.error('  Monthly Reset:');\n      console.error(`    ${formattedResetDate}`);\n    }\n\n    console.error('');\n    console.error('  Docs:    https://docs.testdino.com/platform/billing-and-usage/test-limits');\n    console.error('  Pricing: https://testdino.com/pricing');\n    console.error('');\n    console.error('  CI exit code is non-zero — this run may be missing data in TestDino.');\n    console.error(border);\n    console.error('');\n  }\n\n  private truncateChunk(chunk: string | Buffer): { text: string; truncated?: boolean } {\n    // Convert Buffer to string (UTF-8)\n    let convertedText: string;\n    if (Buffer.isBuffer(chunk)) {\n      convertedText = chunk.toString('utf-8');\n    } else {\n      convertedText = chunk;\n    }\n\n    // Check if truncation is needed\n    if (convertedText.length > MAX_CONSOLE_CHUNK_SIZE) {\n      return {\n        text: convertedText.substring(0, MAX_CONSOLE_CHUNK_SIZE) + '\\n[truncated]',\n        truncated: true,\n      };\n    }\n\n    return { text: convertedText };\n  }\n\n  private extractAttachments(step: TestStep): TestStepEndEvent['attachments'] {\n    // step:end never carries a path — uploads happen once, in bulk, at\n    // test:end. Emitting the local path here would leak the reporter's\n    return step.attachments.map((a) => ({\n      name: a.name,\n      contentType: a.contentType,\n    }));\n  }\n\n  private extractTestStepsSummary(result: TestResult): TestEndEvent['steps'] {\n    return {\n      total: result.steps.length,\n      passed: result.steps.filter((s) => !s.error).length,\n      failed: result.steps.filter((s) => s.error).length,\n    };\n  }\n\n  private extractConsoleOutput(output: Array<string | Buffer>): string[] {\n    return output.map((item) => (typeof item === 'string' ? item : item.toString()));\n  }\n\n  private isDuplicateInstance(reporters: unknown[]): boolean {\n    const count = this.countTestdinoReporters(reporters);\n\n    // If count > 1, it means we have both:\n    // - One from playwright.config (user's manual config)\n    // - One from CLI injection (our --reporter flag)\n    // The config-based instance should handle reporting, so we exit\n    return count > 1;\n  }\n\n  private countTestdinoReporters(reporters: unknown): number {\n    // Guard against undefined or non-array reporters\n    if (!reporters || !Array.isArray(reporters)) {\n      return 0;\n    }\n\n    let count = 0;\n\n    for (const reporter of reporters) {\n      // Reporters can be in multiple formats:\n      // - ['@testdino/playwright'] - string in array\n      // - ['@testdino/playwright', options] - string with options\n      // - Class instance (when instantiated with new)\n\n      if (Array.isArray(reporter) && reporter.length > 0) {\n        const reporterName = reporter[0];\n        if (this.isTestdinoReporter(reporterName)) {\n          count++;\n        }\n      } else if (reporter instanceof TestdinoReporter) {\n        count++;\n      }\n    }\n\n    return count;\n  }\n\n  private isTestdinoReporter(value: unknown): boolean {\n    if (typeof value !== 'string') {\n      return false;\n    }\n\n    // Check various forms our reporter might appear as:\n    // - '@testdino/playwright' (npm package name)\n    // - 'TestdinoReporter' (class name)\n    // - Path ending with 'testdino-playwright'\n    return (\n      value.includes('@testdino/playwright') ||\n      value.includes('TestdinoReporter') ||\n      value.endsWith('testdino-playwright')\n    );\n  }\n\n  private startHeartbeatMonitor(): void {\n    if (!this.deliveryManager) return;\n\n    // Seed lastDeliveryAt so the first heartbeat waits a full silence window\n    this.deliveryManager.lastDeliveryAt = Date.now();\n\n    this.heartbeatTimer = setInterval(() => {\n      if (!this.deliveryManager) return;\n\n      const silenceMs = Date.now() - this.deliveryManager.lastDeliveryAt;\n      if (silenceMs >= HEARTBEAT_SILENCE_THRESHOLD_MS) {\n        const event: RunHeartbeatEvent = {\n          type: 'run:heartbeat',\n          runId: this.runId,\n          timestamp: Date.now(),\n        };\n        this.log.debug(`Sending heartbeat (${Math.round(silenceMs / 1000)}s silence)`);\n        // Fire-and-forget — heartbeat is non-critical, must never block\n        void this.deliveryManager.send(event).catch(() => {});\n      }\n    }, HEARTBEAT_POLL_INTERVAL_MS);\n\n    // Don't let heartbeat timer keep the process alive during shutdown\n    this.heartbeatTimer.unref();\n  }\n\n  private stopHeartbeatMonitor(): void {\n    if (this.heartbeatTimer) {\n      clearInterval(this.heartbeatTimer);\n      this.heartbeatTimer = null;\n    }\n  }\n\n  private registerSignalHandlers(): void {\n    // Remove any existing handlers first to prevent listener accumulation\n    this.removeSignalHandlers();\n\n    let lastSignalTime = 0;\n    this.sigintHandler = () => {\n      const now = Date.now();\n      // Debounce: ignore signals within 500ms of the first (signal propagation noise).\n      // A real second Ctrl+C from the user will be >500ms later.\n      if (this.isShuttingDown) {\n        if (now - lastSignalTime > 500) {\n          this.log.error('Force exit');\n          process.exit(130);\n        }\n        return;\n      }\n      lastSignalTime = now;\n      this.handleInterruption('SIGINT', 130);\n    };\n\n    this.sigtermHandler = () => {\n      if (this.isShuttingDown) return;\n      this.handleInterruption('SIGTERM', 143);\n    };\n\n    process.on('SIGINT', this.sigintHandler);\n    process.on('SIGTERM', this.sigtermHandler);\n  }\n\n  private async resolveRunUrl(): Promise<string | undefined> {\n    if (!this.httpClient || this.initFailed) return undefined;\n    const client = this.httpClient;\n\n    const deadline = Date.now() + RUN_LINK_TOTAL_BUDGET_MS;\n    for (let attempt = 0; attempt < RUN_LINK_MAX_ATTEMPTS; attempt++) {\n      try {\n        // Per-attempt, so one hung call cannot spend the retries' budget.\n        const link = await withTimeout(\n          client.resolveRunLink(this.runId),\n          Math.max(0, Math.min(RUN_LINK_ATTEMPT_TIMEOUT_MS, deadline - Date.now())),\n          'run link resolve'\n        );\n        if (link) {\n          this.resolvedTestRunId = link.testRunId;\n          return link.url;\n        }\n      } catch (error) {\n        this.log.debug(`Run link unavailable: ${error instanceof Error ? error.message : String(error)}`);\n        // Transient errors fall through to a retry: run:begin was just sent, so a\n        // cold connection pool lands exactly here.\n        if (error instanceof HttpDeliveryError && isPermanentHttpStatus(error.status)) return undefined;\n      }\n      if (Date.now() + RUN_LINK_RETRY_DELAY_MS >= deadline) break;\n      if (attempt < RUN_LINK_MAX_ATTEMPTS - 1) await sleep(RUN_LINK_RETRY_DELAY_MS);\n    }\n    return undefined;\n  }\n\n  // Scope the printed run URL to this process's own slice (split and/or shard),\n  // so each CI job links straight to what it ran instead of the whole merged run.\n  private sliceScopedUrl(url: string | undefined): string | undefined {\n    if (!url) return undefined;\n    const params = new URLSearchParams();\n    if (this.splitInfo) params.set('split', String(this.splitInfo.current));\n    if (this.shardInfo) params.set('shard', String(this.shardInfo.current));\n    const query = params.toString();\n    return query ? `${url}?${query}` : url;\n  }\n\n  private async printUpdateNoticeIfAvailable(): Promise<void> {\n    if (!this.updateCheckPromise) return;\n    const pending = this.updateCheckPromise;\n    this.updateCheckPromise = null;\n    try {\n      const latestVersion = await awaitUpdateResult(pending);\n      if (latestVersion) {\n        this.log.printUpdateNotice(getPackageVersion(), latestVersion);\n      }\n    } catch {\n      // A version check must never fail the user's run.\n    }\n  }\n\n  private removeSignalHandlers(): void {\n    if (this.sigintHandler) {\n      process.removeListener('SIGINT', this.sigintHandler);\n    }\n    if (this.sigtermHandler) {\n      process.removeListener('SIGTERM', this.sigtermHandler);\n    }\n  }\n\n  private handleInterruption(signal: string, exitCode: number): void {\n    if (this.isShuttingDown) return;\n    this.isShuttingDown = true;\n    this.shutdownResolve?.();\n    this.shutdownResolve = null;\n\n    // Stop periodic flush timer and heartbeat monitor — interruption sends directly\n    this.buffer?.destroy();\n    this.stopHeartbeatMonitor();\n\n    this.log.warn(`Received ${signal}, sending interruption event...`);\n\n    if (!this.initPromise) {\n      // Init never started, just exit\n      process.exit(exitCode);\n    }\n\n    const waitForPending = async () => {\n      const deadline = Date.now() + 2500;\n      while (this.pendingTestEndPromises.size > 0 && Date.now() < deadline) {\n        try {\n          await Promise.race([\n            Promise.allSettled(Array.from(this.pendingTestEndPromises)),\n            this.timeoutPromise(Math.max(50, Math.min(500, deadline - Date.now())), 'Pending events timeout'),\n          ]);\n        } catch {\n          // Keep draining until empty or deadline.\n        }\n      }\n    };\n\n    // Create interruption event\n    const event: TestRunEndEvent = {\n      type: 'run:end',\n      runId: this.runId,\n      ...this.getEventMetadata(),\n      status: 'interrupted',\n      duration: this.runStartTime ? Date.now() - this.runStartTime : 0,\n      startTime: this.runStartTime ?? Date.now(),\n      shard: this.shardInfo,\n      ...this.splitFields(),\n      ...this.orchFields(),\n    };\n\n    // Keep event loop alive with interval - CRITICAL for ensuring async operations complete\n    const keepAlive = setInterval(() => {\n      // Empty interval to keep process alive\n    }, 100);\n\n    // Hard timeout to force exit if send hangs.\n    // Budget: init 2s + pending 2.5s + flush 1s + emergency 1s + send 2.5s ≈ 9s worst case.\n    const forceExitTimer = setTimeout(() => {\n      clearInterval(keepAlive);\n      this.log.error('Force exit — send timeout exceeded');\n      process.exit(exitCode);\n    }, 10000);\n\n    // Send interruption event directly (bypass buffer to avoid flush delays)\n    const sendAndExit = async () => {\n      try {\n        // Wait for init to complete so kafkaProducer/deliveryManager are available\n        if (this.initPromise) {\n          await Promise.race([this.initPromise, this.timeoutPromise(2000, 'Init timeout')]).catch(() => {});\n        }\n\n        // Wait briefly for pending test:end events (best effort)\n        await waitForPending();\n\n        // Drain buffered events before run:end — destroy() stopped the timer, so this\n        // is the only remaining path to deliver events accumulated since the last tick.\n        if (this.buffer) {\n          await Promise.race([this.buffer.flush(), this.timeoutPromise(1000, 'Buffer flush timeout')]).catch(() => {});\n          // Hung in-flight flush holds the lock; leftovers enqueued after it still need a send.\n          // drain() (not getEvents()+clear()) so a late enqueue during the send isn't lost or double-sent.\n          if (this.buffer.size() > 0 && this.deliveryManager) {\n            const leftover = this.buffer.drain();\n            try {\n              await Promise.race([\n                this.deliveryManager.sendUrgent(leftover),\n                this.timeoutPromise(1000, 'Emergency drain timeout'),\n              ]);\n            } catch {\n              // Best-effort; run:end still follows.\n            }\n          }\n        }\n\n        // Counted at send time: test:end events drained above are only now in totalTests.\n        event.executedTests = this.totalTests + this.openAttempts.size;\n\n        // Send directly without buffering for speed\n        await Promise.race([this.sendInterruptionEvent(event), this.timeoutPromise(2500, 'Send timeout')]);\n\n        this.log.success('Interruption event sent');\n      } catch (error) {\n        const errorMsg = error instanceof Error ? error.message : String(error);\n        this.log.error(`Failed to send interruption event: ${errorMsg}`);\n      } finally {\n        this.finalizeOpenAttemptsAsInterrupted();\n\n        if (!this.summaryPrinted) {\n          this.summaryPrinted = true;\n          const summaryData: RunSummaryData = {\n            runId: this.resolvedTestRunId ?? this.runId,\n            runMetadata: this.runMetadata,\n            testCounts: this.testCounts,\n            artifactCounts: this.artifactCounts,\n            totalTests: this.totalTests,\n            workerCount: this.workerCount,\n            projectNames: this.projectNames,\n            shardInfo: this.shardInfo,\n            artifactsDisabled: !this.artifactsEnabled,\n            runUrl: this.sliceScopedUrl(this.resolvedRunUrl),\n          };\n          this.log.printRunSummary(\n            { status: 'interrupted', duration: event.duration, startTime: new Date(event.startTime) } as FullResult,\n            summaryData\n          );\n        }\n\n        clearTimeout(forceExitTimer);\n        clearInterval(keepAlive);\n        process.exit(exitCode);\n      }\n    };\n\n    // Execute\n    sendAndExit().catch(() => {\n      clearTimeout(forceExitTimer);\n      clearInterval(keepAlive);\n      process.exit(exitCode);\n    });\n  }\n\n  // Throws so the caller cannot log an undelivered event as sent.\n  private async sendInterruptionEvent(event: TestRunEndEvent): Promise<void> {\n    if (this.deliveryManager) {\n      await this.deliveryManager.sendUrgent([event]);\n    } else if (this.kafkaProducer?.isConnected) {\n      await this.kafkaProducer.send(event);\n      await this.kafkaProducer.close();\n    }\n  }\n\n  private timeoutPromise(ms: number, message: string): Promise<never> {\n    return new Promise((_, reject) => {\n      const timer = setTimeout(() => reject(new Error(message)), ms);\n      timer.unref?.();\n    });\n  }\n\n  // Counts are per attempt, not per test: onTestEnd fires once per retry and each\n  // attempt uploads its own artifacts, so a retried test contributes twice. The\n  // total therefore matches what was actually stored, not the test count above it.\n  //\n  // Playwright names attachments 'screenshot' / 'video' / 'trace'; contentType is the\n  // fallback for custom names (test.info().attach) that carry no recognizable name.\n  private tallyArtifacts(attachments: TestEndEvent['attachments']): void {\n    for (const a of attachments) {\n      if ('unavailable' in a) {\n        this.artifactCounts.unavailable++;\n        continue;\n      }\n\n      const name = a.name.toLowerCase();\n      const type = a.contentType.toLowerCase();\n\n      if (name.includes('screenshot') || type.startsWith('image/')) {\n        this.artifactCounts.screenshots++;\n      } else if (name.includes('video') || type.startsWith('video/')) {\n        this.artifactCounts.videos++;\n      } else if (name.includes('trace') && type === 'application/zip') {\n        this.artifactCounts.traces++;\n      } else {\n        this.artifactCounts.other++;\n      }\n    }\n  }\n\n  private attachmentsAsUnavailable(\n    attachments: Array<{ name: string; contentType: string; path?: string; body?: Buffer }>\n  ): TestEndEvent['attachments'] {\n    return attachments\n      .filter((a): a is { name: string; contentType: string; path: string } => !!a.path)\n      .map((a) => ({ name: a.name, contentType: a.contentType, unavailable: true }));\n  }\n\n  private async uploadAttachments(\n    attachments: Array<{ name: string; contentType: string; path?: string; body?: Buffer }>,\n    testId: string\n  ): Promise<TestEndEvent['attachments']> {\n    // In-memory attachments (no path) are never uploaded.\n    const fileCandidates = attachments.filter(\n      (a): a is { name: string; contentType: string; path: string } => !!a.path\n    );\n    if (fileCandidates.length === 0) return [];\n\n    if (this.isShuttingDown) {\n      return fileCandidates.map((a) => ({ name: a.name, contentType: a.contentType, unavailable: true }));\n    }\n\n    // Uploads disabled or client not constructed → every file unavailable.\n    // Never emit the local path.\n    if (!this.artifactsEnabled || !this.artifactUploadClient) {\n      return fileCandidates.map((a) => ({ name: a.name, contentType: a.contentType, unavailable: true }));\n    }\n\n    const stated = await this.statAttachments(fileCandidates);\n    if (this.isShuttingDown) {\n      return fileCandidates.map((a) => ({ name: a.name, contentType: a.contentType, unavailable: true }));\n    }\n\n    const { uploadable, preFiltered } = this.filterUploadable(stated);\n    if (uploadable.length === 0) return preFiltered;\n\n    const uploaded = await this.putBatch(uploadable, testId, this.artifactUploadClient);\n    if (this.isShuttingDown) {\n      return fileCandidates.map((a) => ({ name: a.name, contentType: a.contentType, unavailable: true }));\n    }\n    return [...preFiltered, ...uploaded];\n  }\n\n  private async statAttachments(\n    files: Array<{ name: string; contentType: string; path: string }>\n  ): Promise<StatedAttachment[]> {\n    const results = await Promise.allSettled(files.map((f) => stat(f.path)));\n    return files.map((f, i) => {\n      const r = results[i];\n      if (r.status === 'fulfilled') {\n        return { name: f.name, contentType: f.contentType, path: f.path, sizeBytes: r.value.size };\n      }\n      this.log.warn(\n        `Attachment '${f.name}' unavailable: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`\n      );\n      return { name: f.name, contentType: f.contentType, unavailable: true };\n    });\n  }\n\n  private filterUploadable(stated: StatedAttachment[]): {\n    uploadable: UploadableAttachment[];\n    preFiltered: TestEndEvent['attachments'];\n  } {\n    const uploadable: UploadableAttachment[] = [];\n    const preFiltered: TestEndEvent['attachments'] = [];\n    for (const item of stated) {\n      if ('unavailable' in item) {\n        preFiltered.push({ name: item.name, contentType: item.contentType, unavailable: true });\n        continue;\n      }\n      // Extension lives in the file path (e.g. test-failed-1.png), NOT the\n      // Playwright attachment name (\"screenshot\"/\"video\"/\"trace\"), which has\n      // none — checking the name would reject every real artifact.\n      if (isAllowedExtension(basename(item.path)) && isWithinSizeLimit(item.sizeBytes)) {\n        uploadable.push(item);\n      } else {\n        const reason = isAllowedExtension(basename(item.path))\n          ? `${item.sizeBytes} bytes exceeds the size limit`\n          : `extension not in the allowlist`;\n        this.log.debug(`Attachment '${basename(item.path)}' skipped: ${reason}`);\n        preFiltered.push({ name: item.name, contentType: item.contentType, unavailable: true });\n      }\n    }\n    return { uploadable, preFiltered };\n  }\n\n  private async putBatch(\n    uploadable: UploadableAttachment[],\n    testId: string,\n    client: ArtifactUploadClient\n  ): Promise<TestEndEvent['attachments']> {\n    const { ready, readFailed } = await this.snapshotAttachments(uploadable);\n    if (ready.length === 0) return readFailed;\n\n    const asUnavailable = (): TestEndEvent['attachments'] => [\n      ...readFailed,\n      ...ready.map((f) => ({ name: f.name, contentType: f.contentType, unavailable: true as const })),\n    ];\n\n    let tokens: UploadTokenResult;\n    try {\n      const request: UploadFileRequest[] = ready.map((f) => ({\n        // Send the file's basename (with extension) — the server's allowlist and\n        // the blob key's Content-Type (rsct) derive from the extension, which the\n        // bare attachment name (\"screenshot\") lacks. The display name is kept\n        // unchanged on the returned wire attachment below. sizeBytes is the\n        // ACTUAL snapshot length, not stat — the server accounts on this value\n        // and it must match the Content-Length on the PUT.\n        name: basename(f.path),\n        testId,\n        contentType: f.contentType,\n        sizeBytes: f.bytes.length,\n      }));\n      tokens = await client.requestUploadTokens(request);\n    } catch (error) {\n      const detail =\n        error instanceof ArtifactUploadTokenError\n          ? `${error.kind}${error.serverCode ? `/${error.serverCode}` : ''}: ${error.message}`\n          : error instanceof Error\n            ? error.message\n            : String(error);\n      this.log.warn(`Upload-token request failed for test ${testId}: ${detail}. Attachments marked unavailable.`);\n      return asUnavailable();\n    }\n\n    // uploads is index-aligned with the request (data-handler contract:\n    // handler.go iterates req.Files in order and appends to uploads).\n    if (tokens.uploads.length !== ready.length) {\n      this.log.warn(\n        `Upload-token response length mismatch for test ${testId} (expected ${ready.length}, got ${tokens.uploads.length}). Attachments marked unavailable.`\n      );\n      return asUnavailable();\n    }\n\n    const settled = await Promise.allSettled(\n      ready.map((f, i) => client.uploadFile(tokens.uploads[i].uploadUrl, f.bytes, f.contentType))\n    );\n\n    const uploaded = ready.map((f, i) => {\n      const outcome = settled[i];\n      if (outcome.status === 'fulfilled') {\n        return { name: f.name, contentType: f.contentType, blobKey: tokens.uploads[i].blobKey };\n      }\n      this.log.warn(\n        `Upload failed for '${f.name}' (test ${testId}): ${outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason)}`\n      );\n      return { name: f.name, contentType: f.contentType, unavailable: true as const };\n    });\n\n    return [...readFailed, ...uploaded];\n  }\n\n  private async snapshotAttachments(uploadable: UploadableAttachment[]): Promise<{\n    ready: Array<{ name: string; contentType: string; path: string; sizeBytes: number; bytes: Buffer }>;\n    readFailed: TestEndEvent['attachments'];\n  }> {\n    const reads = await Promise.allSettled(uploadable.map((f) => readFile(f.path)));\n    const ready: Array<{ name: string; contentType: string; path: string; sizeBytes: number; bytes: Buffer }> = [];\n    const readFailed: TestEndEvent['attachments'] = [];\n    uploadable.forEach((f, i) => {\n      const r = reads[i];\n      if (r.status === 'fulfilled') {\n        ready.push({ name: f.name, contentType: f.contentType, path: f.path, sizeBytes: f.sizeBytes, bytes: r.value });\n      } else {\n        this.log.warn(\n          `Attachment '${f.name}' unavailable (snapshot failed): ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`\n        );\n        readFailed.push({ name: f.name, contentType: f.contentType, unavailable: true });\n      }\n    });\n    return { ready, readFailed };\n  }\n\n  private getProjectName(test: TestCase): string | undefined {\n    let suite: Suite | undefined = test.parent;\n    while (suite) {\n      const project = suite.project();\n      if (project) {\n        return project.name || project.use?.defaultBrowserType || 'default';\n      }\n      suite = suite.parent;\n    }\n    return undefined;\n  }\n}\n","import axios, { type AxiosInstance } from 'axios';\nimport type { TestEvent, SessionCreationQuotaResponse, QuarantineList } from '../types/index.js';\nimport type { QuarantineFetchOutcome } from '../reporter/test-controls.js';\nimport {\n  ForbiddenAuthError,\n  HttpDeliveryError,\n  InvalidTokenTypeError,\n  QuotaExceededError,\n  QuotaExhaustedError,\n  ServerEndpointError,\n  UnauthorizedError,\n} from '../reporter/errors.js';\n\nexport const AUTH_PATH = '/api/v1/reporter/auth';\nexport const QUARANTINE_PATH = '/api/v1/reporter/quarantine';\n// Tests are already running while this is in flight; past this the build\n// behaves as it would without Test Controls.\nconst QUARANTINE_TIMEOUT_MS = 5000;\n\nconst VALID_SASL_MECHANISMS = ['plain', 'scram-sha-256', 'scram-sha-512'] as const;\ntype SaslMechanism = (typeof VALID_SASL_MECHANISMS)[number];\n\nexport interface HttpClientOptions {\n  token: string;\n  serverUrl: string;\n}\n\nexport interface RunLink {\n  url: string;\n  testRunId?: string;\n}\n\nexport interface AuthResponse {\n  projectId: string;\n  kafka?: {\n    brokers: string[];\n    channel?: string;\n    sasl?: {\n      mechanism: SaslMechanism;\n      username: string;\n      password: string;\n    };\n    ssl?: boolean;\n  };\n  httpFallback?: string;\n  /**\n   * Advisory: when true the project is past its execution quota, so this run's\n   * events will be blocked at ingestion. The reporter still sends run:begin\n   * (which surfaces the blocked run on the dashboard) but stops streaming the\n   * rest. Absent on older servers — treated as false.\n   */\n  overLimit?: boolean;\n}\n\nexport class HttpClient {\n  private client: AxiosInstance;\n\n  constructor(options: HttpClientOptions) {\n    this.client = axios.create({\n      baseURL: options.serverUrl,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${options.token}`,\n      },\n      timeout: 10000,\n    });\n  }\n\n  async authenticate(): Promise<AuthResponse> {\n    try {\n      const response = await this.client.post(AUTH_PATH);\n      return normalizeAuthResponse(response.data);\n    } catch (error) {\n      if (axios.isAxiosError(error) && error.response) {\n        const status = error.response.status;\n\n        if (status === 402) {\n          const data = error.response.data as Partial<SessionCreationQuotaResponse> | undefined;\n          throw new QuotaExhaustedError(\n            data?.message ?? 'Quota exhausted',\n            data?.details ?? { planName: 'Unknown', totalLimit: 0, used: 0 }\n          );\n        }\n\n        if (status === 403) {\n          const data = error.response.data as { code?: string; message?: string } | undefined;\n          if (data?.code === 'TOKEN_TYPE_NOT_ALLOWED') throw new InvalidTokenTypeError(data.message);\n          throw new ForbiddenAuthError(data?.message);\n        }\n\n        if (status === 401) {\n          const data = error.response.data as { message?: string } | undefined;\n          throw new UnauthorizedError(data?.message);\n        }\n\n        if (status === 405) throw new ServerEndpointError(AUTH_PATH);\n      }\n\n      throw new Error(`Authentication failed: ${this.getErrorMessage(error)}`, { cause: error });\n    }\n  }\n\n  async sendEvents(url: string, events: TestEvent[]): Promise<void> {\n    try {\n      await this.client.post(url, { events });\n    } catch (error) {\n      // Quota is permanent — do not retry.\n      if (axios.isAxiosError(error) && error.response?.status === 402) {\n        const data = error.response.data;\n        const details = data?.details;\n        if (data?.error === 'QUOTA_EXCEEDED' && details) {\n          throw new QuotaExceededError(data.message || 'Quota exceeded', details);\n        }\n        throw new QuotaExhaustedError(\n          data?.message ?? 'Quota exhausted',\n          details ?? { planName: 'Unknown', totalLimit: 0, used: 0 }\n        );\n      }\n      if (axios.isAxiosError(error) && error.response) {\n        throw new HttpDeliveryError(error.response.status, this.getErrorMessage(error), { cause: error });\n      }\n      throw error;\n    }\n  }\n\n  /** The project's Test Controls list. Never throws: a failure is a reason. */\n  async fetchQuarantineList(): Promise<QuarantineFetchOutcome> {\n    try {\n      const response = await this.client.get(QUARANTINE_PATH, { timeout: QUARANTINE_TIMEOUT_MS });\n      const list = normalizeQuarantineList(response.data);\n      return list ? { list } : { reason: 'unreachable' };\n    } catch (error) {\n      if (axios.isAxiosError(error)) {\n        if (error.response?.status === 404) return { reason: 'not_found' };\n        if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') return { reason: 'timeout' };\n      }\n      return { reason: 'unreachable' };\n    }\n  }\n\n  /** Returns null when the mapping is not recorded yet (404); throws otherwise. */\n  async resolveRunLink(runId: string): Promise<RunLink | null> {\n    try {\n      const response = await this.client.get(runLinkPath(runId));\n      const data = response.data as { url?: unknown; test_run_id?: unknown } | undefined;\n      const url = data?.url;\n      if (typeof url !== 'string' || url.length === 0) return null;\n      const testRunId = data?.test_run_id;\n      return typeof testRunId === 'string' && testRunId.length > 0 ? { url, testRunId } : { url };\n    } catch (error) {\n      if (axios.isAxiosError(error) && error.response?.status === 404) return null;\n      // Carries the status so the caller can tell a blip from a refusal.\n      if (axios.isAxiosError(error) && error.response) {\n        throw new HttpDeliveryError(error.response.status, this.getErrorMessage(error), { cause: error });\n      }\n      throw error;\n    }\n  }\n\n  private getErrorMessage(error: unknown): string {\n    if (axios.isAxiosError(error)) return error.response?.data?.message || error.message;\n    if (error instanceof Error) return error.message;\n    return String(error);\n  }\n}\n\nfunction runLinkPath(runId: string): string {\n  return `/api/v1/reporter/runs/${encodeURIComponent(runId)}/link`;\n}\n\n// Server emits SASL mechanism uppercase; KafkaJS demands lowercase.\nfunction normalizeAuthResponse(raw: unknown): AuthResponse {\n  const data = (raw ?? {}) as AuthResponse;\n  if (!data.kafka?.sasl) return data;\n  const lowered = data.kafka.sasl.mechanism.toLowerCase();\n  if (!(VALID_SASL_MECHANISMS as readonly string[]).includes(lowered)) {\n    throw new Error(`Unsupported SASL mechanism from server: ${data.kafka.sasl.mechanism}`);\n  }\n  return {\n    ...data,\n    kafka: {\n      ...data.kafka,\n      sasl: { ...data.kafka.sasl, mechanism: lowered as SaslMechanism },\n    },\n  };\n}\n\n// A body without the list is not a list: recorded as not applied, never as an\n// applied empty one.\nfunction normalizeQuarantineList(raw: unknown): QuarantineList | null {\n  const data = (raw ?? {}) as Partial<QuarantineList>;\n  if (!Array.isArray(data.quarantined)) return null;\n  const ids = (value: unknown): string[] =>\n    Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\n  const rules = ruleCounts(data.rules);\n  return {\n    quarantined: ids(data.quarantined),\n    critical: ids(data.critical),\n    knownErrors: Array.isArray(data.knownErrors)\n      ? data.knownErrors\n          .filter((k) => k && typeof k.pattern === 'string')\n          .map((k) => ({ testIds: ids(k.testIds), pattern: k.pattern }))\n      : [],\n    ...(typeof data.generatedAt === 'string' && { generatedAt: data.generatedAt }),\n    ...(rules && { rules }),\n  };\n}\n\nfunction ruleCounts(raw: unknown): QuarantineList['rules'] | undefined {\n  const r = (raw ?? {}) as Record<string, unknown>;\n  const n = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 0;\n  return n(r.quarantined) && n(r.knownErrors) && n(r.critical)\n    ? { quarantined: r.quarantined, knownErrors: r.knownErrors, critical: r.critical }\n    : undefined;\n}\n","import type { TestEvent } from '../types/index.js';\n\nexport class TestDinoServerError extends Error {\n  public readonly code: string;\n\n  constructor(code: string, message: string) {\n    super(message);\n    this.name = 'TestDinoServerError';\n    this.code = code;\n    Error.captureStackTrace(this, this.constructor);\n  }\n}\n\n// HTTP 402 — organization pool exhausted at session creation.\nexport class QuotaExhaustedError extends TestDinoServerError {\n  public readonly details: {\n    planName: string;\n    totalLimit: number;\n    used: number;\n    resetDate?: string;\n  };\n\n  constructor(\n    message: string,\n    details: {\n      planName: string;\n      totalLimit: number;\n      used: number;\n      resetDate?: string;\n    }\n  ) {\n    super('QUOTA_EXHAUSTED', message);\n    this.name = 'QuotaExhaustedError';\n    this.details = details;\n  }\n}\n\n// WebSocket NACK on run:begin — test count exceeds available quota.\nexport class QuotaExceededError extends TestDinoServerError {\n  public readonly details: {\n    planName: string;\n    totalTests: number;\n    remaining: number;\n    used: number;\n    total: number;\n    resetDate?: string;\n    canPartialSubmit: boolean;\n    allowedCount: number;\n    projectName?: string;\n    projectLimit?: number;\n    projectUsed?: number;\n    projectBorrowed?: number;\n  };\n\n  constructor(\n    message: string,\n    details: {\n      planName: string;\n      totalTests: number;\n      remaining: number;\n      used: number;\n      total: number;\n      resetDate?: string;\n      canPartialSubmit: boolean;\n      allowedCount: number;\n      projectName?: string;\n      projectLimit?: number;\n      projectUsed?: number;\n      projectBorrowed?: number;\n    }\n  ) {\n    super('QUOTA_EXCEEDED', message);\n    this.name = 'QuotaExceededError';\n    this.details = details;\n  }\n}\n\n// HTTP 403 TOKEN_TYPE_NOT_ALLOWED — bearer is a td_pat_ or cookie JWT, not a td_api_ pipeline key.\nexport class InvalidTokenTypeError extends TestDinoServerError {\n  constructor(message?: string) {\n    super(\n      'TOKEN_TYPE_NOT_ALLOWED',\n      message ??\n        'This endpoint requires a pipeline API key (td_api_...). ' +\n          'Personal access tokens and session cookies are not accepted.'\n    );\n    this.name = 'InvalidTokenTypeError';\n  }\n}\n\nexport class ForbiddenAuthError extends TestDinoServerError {\n  constructor(message?: string) {\n    super('AUTH_FORBIDDEN', message ?? 'Authentication forbidden by server');\n    this.name = 'ForbiddenAuthError';\n  }\n}\n\n// HTTP 405 — serverUrl points at the wrong service.\nexport class ServerEndpointError extends TestDinoServerError {\n  constructor(path: string) {\n    super(\n      'WRONG_AUTH_ENDPOINT',\n      `Server rejected POST ${path} (405 Method Not Allowed). Verify serverUrl points at the data-handler service.`\n    );\n    this.name = 'ServerEndpointError';\n  }\n}\n\n// HTTP 401 — invalid or expired token at authentication.\nexport class UnauthorizedError extends TestDinoServerError {\n  constructor(message?: string) {\n    super('UNAUTHORIZED', message ?? 'Authentication failed — invalid or expired token');\n    this.name = 'UnauthorizedError';\n  }\n}\n\n// Wraps any HTTP failure from HttpClient so callers can branch on error.status\n// (typed) instead of digging into axios internals with unsafe casts.\nexport class HttpDeliveryError extends Error {\n  public readonly status: number;\n\n  constructor(status: number, message: string, options?: { cause?: unknown }) {\n    super(message, options);\n    this.name = 'HttpDeliveryError';\n    this.status = status;\n    Error.captureStackTrace(this, this.constructor);\n  }\n}\n\n// 413 is permanent on the auth endpoint; on the events endpoint the chunker\n// splits and retries before reaching this classifier.\n// 409: the server refused a run:begin whose --split slot was already reported\n// under this split-id (two runs sharing a split-id); retrying cannot change that.\nconst PERMANENT_HTTP_STATUSES = new Set([400, 401, 402, 403, 404, 405, 409, 413]);\n\nexport function isPermanentHttpStatus(status: number | undefined): boolean {\n  return status !== undefined && PERMANENT_HTTP_STATUSES.has(status);\n}\n\n// `count` may exceed 1 when the halving path collapses N per-half floor errors\n// into a single throw; the outer accounting must use it (not +1) or the discard\n// counter under-reports when multiple oversize events share a sub-batch.\nexport class EventTooLargeError extends HttpDeliveryError {\n  public readonly count: number;\n\n  constructor(message: string, options?: { cause?: unknown; count?: number }) {\n    super(413, message, options);\n    this.name = 'EventTooLargeError';\n    this.count = options?.count ?? 1;\n  }\n}\n\n// Restore only `.failed` to the buffer's front; earlier sub-batches already\n// acked and re-sending them would duplicate on the server.\nexport class PartialBatchError extends Error {\n  public readonly failed: TestEvent[];\n  public readonly succeeded: number;\n\n  constructor(failed: TestEvent[], succeeded: number, message: string, options?: { cause?: unknown }) {\n    super(message, options);\n    this.name = 'PartialBatchError';\n    this.failed = failed;\n    this.succeeded = succeeded;\n    Error.captureStackTrace(this, this.constructor);\n  }\n}\n\nexport type ServerError =\n  | QuotaExhaustedError\n  | QuotaExceededError\n  | InvalidTokenTypeError\n  | ForbiddenAuthError\n  | ServerEndpointError\n  | UnauthorizedError;\n\nexport function isServerError(error: unknown): error is ServerError {\n  return error instanceof TestDinoServerError;\n}\n\nexport function isQuotaError(error: unknown): error is QuotaExhaustedError | QuotaExceededError {\n  return error instanceof QuotaExhaustedError || error instanceof QuotaExceededError;\n}\n\n// Ingestion's 402 for a refused run:begin carries only { projectId }: the run is\n// blocked by the execution-quota gate, the same outcome as the auth endpoint's\n// overLimit flag, not a session-pool exhaustion with plan/usage figures.\nexport function isBlockedRunError(error: unknown): error is QuotaExceededError {\n  return error instanceof QuotaExceededError && (error.details as { total?: number } | undefined)?.total === undefined;\n}\n","import type { FullResult } from '@playwright/test/reporter';\nimport type { QuarantineList, RunQuarantineBlock } from '../types/index.js';\n\nexport type QuarantineUnavailableReason = 'unreachable' | 'timeout' | 'not_found';\n\nexport type QuarantineFetchOutcome = { list: QuarantineList } | { reason: QuarantineUnavailableReason };\n\nexport interface FinishedTest {\n  id: string;\n  title: string;\n  outcome: 'expected' | 'unexpected' | 'flaky' | 'skipped';\n  /** Message of the final attempt's first error; empty when it has none. */\n  errorMessage: string;\n}\n\nexport interface TestControlsInput {\n  fetch: QuarantineFetchOutcome;\n  tests: FinishedTest[];\n  runStatus: FullResult['status'];\n  globalErrorCount: number;\n}\n\nexport interface TestControlsDecision {\n  block: RunQuarantineBlock;\n  /** Status to return from onEnd, or undefined to leave Playwright's. */\n  status?: 'passed' | 'failed';\n  /** Console lines, printed in order at the end of the run. */\n  report: ReportLine[];\n}\n\nexport interface ReportLine {\n  tone: 'info' | 'success' | 'error' | 'warn';\n  text: string;\n}\n\n// eslint-disable-next-line no-control-regex -- stripping ANSI is the point\nconst ANSI = /\\u001b\\[[0-9;]*m/g;\n\n/**\n * The line a known-error pattern is tested against: the first non-empty line,\n * without ANSI colour, whitespace collapsed. The server builds patterns for\n * exactly this shape (root docs/QUARANTINE.md).\n */\nexport function firstErrorLine(message: string): string {\n  for (const raw of message.replace(ANSI, '').split('\\n')) {\n    const line = raw.replace(/\\s+/g, ' ').trim();\n    if (line) return line;\n  }\n  return '';\n}\n\ninterface KnownError {\n  testIds: Set<string>;\n  pattern: RegExp;\n}\n\n// A pattern that does not compile forgives nothing.\nfunction compileKnownErrors(list: QuarantineList): KnownError[] {\n  const out: KnownError[] = [];\n  for (const entry of list.knownErrors ?? []) {\n    try {\n      out.push({ testIds: new Set(entry.testIds), pattern: new RegExp(entry.pattern) });\n    } catch {\n      continue;\n    }\n  }\n  return out;\n}\n\nconst UNAVAILABLE_TEXT: Record<QuarantineUnavailableReason, string> = {\n  unreachable: \"couldn't reach TestDino\",\n  timeout: 'TestDino did not answer in time',\n  not_found: 'the project was not found',\n};\n\nconst plural = (n: number, one: string, many: string): string => `${n} ${n === 1 ? one : many}`;\n\nfunction rulesLine(list: QuarantineList): ReportLine {\n  const counts = list.rules;\n  if (!counts) return { tone: 'info', text: 'TestDino Test Controls: rules loaded' };\n  const parts = [\n    counts.quarantined > 0 && `${counts.quarantined} quarantined`,\n    counts.knownErrors > 0 && plural(counts.knownErrors, 'known error', 'known errors'),\n    counts.critical > 0 && `${counts.critical} critical`,\n  ].filter(Boolean);\n  const total = counts.quarantined + counts.knownErrors + counts.critical;\n  const detail = parts.length > 0 ? ` (${parts.join(', ')})` : '';\n  return { tone: 'info', text: `TestDino Test Controls: ${plural(total, 'rule', 'rules')}${detail}` };\n}\n\ntype Decided = Omit<TestControlsDecision, 'block'> & { block: Omit<RunQuarantineBlock, 'build'> };\n\n/** Decides the build outcome under Test Controls and records it in the block. */\nexport function decideTestControls(input: TestControlsInput): TestControlsDecision {\n  const decision = decide(input);\n  const build = decision.status ?? (input.runStatus === 'passed' ? 'passed' : 'failed');\n  return { ...decision, block: { ...decision.block, build } };\n}\n\n/**\n * Decides the build outcome under Test Controls. Quarantined and known-error\n * failures stop failing the build only when every unexpected test is forgiven,\n * nothing failed outside a test, and Playwright reported a plain failure. A\n * critical test that passed only on retry fails the build. Without the list,\n * nothing changes.\n */\nfunction decide(input: TestControlsInput): Decided {\n  if (!('list' in input.fetch)) {\n    const reason = input.fetch.reason;\n    return {\n      block: { state: 'not_applied', reason },\n      report: [\n        {\n          tone: 'warn',\n          text: `TestDino Test Controls: rules not loaded (${UNAVAILABLE_TEXT[reason]}); failures count as usual`,\n        },\n      ],\n    };\n  }\n\n  const list = input.fetch.list;\n  const quarantined = new Set(list.quarantined ?? []);\n  const critical = new Set(list.critical ?? []);\n  const knownErrors = compileKnownErrors(list);\n  const matchesKnownError = (test: FinishedTest): boolean => {\n    const line = firstErrorLine(test.errorMessage);\n    return knownErrors.some((k) => k.testIds.has(test.id) && k.pattern.test(line));\n  };\n  const isKnownErrorTest = (id: string): boolean => knownErrors.some((k) => k.testIds.has(id));\n\n  const testIds: string[] = [];\n  const forgiven = new Set<string>();\n  const criticalFlaky: FinishedTest[] = [];\n  const unexpected: FinishedTest[] = [];\n\n  for (const test of input.tests) {\n    if (test.outcome === 'skipped') continue;\n    if (test.outcome === 'unexpected') unexpected.push(test);\n    if (test.outcome === 'flaky' && critical.has(test.id)) criticalFlaky.push(test);\n\n    if (quarantined.has(test.id)) {\n      testIds.push(test.id);\n      if (test.outcome === 'unexpected') forgiven.add(test.id);\n    } else if (isKnownErrorTest(test.id)) {\n      if (test.outcome !== 'unexpected') {\n        testIds.push(test.id);\n      } else if (matchesKnownError(test)) {\n        testIds.push(test.id);\n        forgiven.add(test.id);\n      }\n    }\n  }\n\n  const block: Decided['block'] = {\n    state: 'applied',\n    ...(testIds.length > 0 && { testIds }),\n    ...(criticalFlaky.length > 0 && { criticalFlakyTestIds: criticalFlaky.map((t) => t.id) }),\n  };\n\n  // Nothing quarantined ran and no critical test flaked: the rules line alone\n  // shows Test Controls was active.\n  const report: ReportLine[] = [rulesLine(list)];\n  if (testIds.length === 0 && criticalFlaky.length === 0) return { block, report };\n\n  const excluded = forgiven.size;\n  if (testIds.length > 0) {\n    const failed = excluded > 0 ? `${excluded} failed, excluded from the build` : 'none failed';\n    report.push({ tone: 'info', text: `Quarantined tests in this run: ${testIds.length} (${failed})` });\n  }\n\n  const isPlainEnd = input.runStatus === 'passed' || input.runStatus === 'failed';\n  if (isPlainEnd && criticalFlaky.length > 0) {\n    const names = criticalFlaky.map((t) => t.title).join(', ');\n    const what = criticalFlaky.length === 1 ? 'critical test' : 'critical tests';\n    report.push({ tone: 'error', text: `Build fails: ${what} passed only on retry (${names})` });\n    return { block, status: 'failed', report };\n  }\n\n  const stillFailing = unexpected.filter((t) => !forgiven.has(t.id)).length;\n  if (!isPlainEnd) {\n    report.push({ tone: 'warn', text: `The run ended ${input.runStatus}, so its status stands` });\n    return { block, report };\n  }\n  if (stillFailing > 0) {\n    report.push({ tone: 'error', text: `Build fails: ${plural(stillFailing, 'failure', 'failures')} not quarantined` });\n    return { block, report };\n  }\n  if (input.globalErrorCount > 0) {\n    report.push({ tone: 'error', text: 'Build fails: an error outside a test' });\n    return { block, report };\n  }\n  if (excluded > 0) {\n    report.push({ tone: 'success', text: 'Build passes: every failure was quarantined' });\n    return { block, status: input.runStatus === 'failed' ? 'passed' : undefined, report };\n  }\n  report.push({ tone: 'success', text: 'No failures' });\n  return { block, report };\n}\n","import { Kafka, Partitioners, type Producer, type RecordMetadata, type SASLOptions } from 'kafkajs';\nimport type { TestEvent } from '../types/index.js';\nimport type { Logger } from '../utils/logger.js';\nimport { createNoopLogger } from '../utils/logger.js';\nimport { suppressKafkaTimeoutWarning, restoreKafkaTimeoutWarning } from '../utils/kafka-timeout-warning.js';\n\nexport interface KafkaProducerOptions {\n  brokers: string[];\n  channel: string;\n  clientId?: string;\n  sasl?: SASLOptions;\n  ssl?: boolean;\n  connectionTimeout?: number;\n  requestTimeout?: number; // Azure Event Hubs recommends 60_000.\n  debug?: boolean;\n  logger?: Logger;\n}\n\nexport class KafkaEventProducer {\n  private kafka: Kafka;\n  private producer: Producer | null = null;\n  private channel: string;\n  private options: KafkaProducerOptions;\n  private readonly logger: Logger;\n  private connected = false;\n  private connectPromise: Promise<void> | null = null;\n\n  constructor(options: KafkaProducerOptions) {\n    this.options = options;\n    this.channel = options.channel;\n    this.logger = options.logger ?? createNoopLogger();\n\n    this.kafka = new Kafka({\n      clientId: options.clientId ?? 'testdino-reporter',\n      brokers: options.brokers,\n      connectionTimeout: options.connectionTimeout ?? 10_000,\n      requestTimeout: options.requestTimeout ?? 60_000,\n      enforceRequestTimeout: true,\n      ...(options.sasl && { sasl: options.sasl }),\n      ...(options.ssl !== undefined && { ssl: options.ssl }),\n    });\n  }\n\n  async connect(): Promise<void> {\n    if (this.connected) return;\n    // Serialize concurrent callers.\n    if (this.connectPromise) return this.connectPromise;\n\n    this.connectPromise = this.doConnect();\n    try {\n      await this.connectPromise;\n    } finally {\n      this.connectPromise = null;\n    }\n  }\n\n  private async doConnect(): Promise<void> {\n    // Install BEFORE connect: kafkajs schedules the negative-delay requestQueue\n    // timer while the connection handshake drains, so a post-connect install\n    // misses the warning it fires during connect().\n    suppressKafkaTimeoutWarning();\n    const producer = this.kafka.producer({\n      createPartitioner: Partitioners.DefaultPartitioner,\n    });\n    try {\n      await producer.connect();\n    } catch (error) {\n      // Leave the warning filter installed — a failed attempt may be followed by\n      // a reconnect (Event Hubs resets flap connections). Only close() tears it\n      // down; the reporter always close()s, even on the HTTP-fallback path.\n      await producer.disconnect().catch(() => {});\n      throw error;\n    }\n    this.producer = producer;\n    this.connected = true;\n    this.logger.debug(`Kafka connected to ${this.options.brokers.join(', ')}`);\n  }\n\n  async send(event: TestEvent): Promise<RecordMetadata[]> {\n    const producer = this.producer;\n    if (!producer) throw new Error('KafkaEventProducer not connected — call connect() first');\n\n    try {\n      return await producer.send({\n        topic: this.channel,\n        acks: 1,\n        messages: [{ key: event.runId, value: JSON.stringify(event) }],\n      });\n    } catch (error) {\n      this.connected = false;\n      const orphaned = this.producer;\n      this.producer = null;\n      orphaned?.disconnect().catch(() => {});\n      throw error;\n    }\n  }\n\n  // On error: resets connected + nulls producer so the delivery-manager retry\n  // reconnects with a fresh producer instance.\n  async sendBatch(events: TestEvent[]): Promise<RecordMetadata[]> {\n    const producer = this.producer;\n    if (!producer) throw new Error('KafkaEventProducer not connected — call connect() first');\n    if (events.length === 0) return [];\n\n    try {\n      return await producer.send({\n        topic: this.channel,\n        acks: 1,\n        messages: events.map((event) => ({ key: event.runId, value: JSON.stringify(event) })),\n      });\n    } catch (error) {\n      this.connected = false;\n      const orphaned = this.producer;\n      this.producer = null;\n      orphaned?.disconnect().catch(() => {});\n      throw error;\n    }\n  }\n\n  async close(): Promise<void> {\n    if (this.producer) {\n      const producer = this.producer;\n      this.producer = null;\n      this.connected = false;\n      try {\n        await producer.disconnect();\n      } catch {\n        // Ignore EPIPE — connection may already be dead.\n      }\n      this.logger.debug('Kafka producer closed');\n    }\n    restoreKafkaTimeoutWarning();\n  }\n\n  get isConnected(): boolean {\n    return this.connected;\n  }\n}\n","export interface Logger {\n  success(msg: string): void;\n  info(msg: string): void;\n  warn(msg: string): void;\n  error(msg: string, error?: Error): void;\n  debug(msg: string): void;\n}\n\nexport function createNoopLogger(): Logger {\n  return {\n    success: () => {},\n    info: () => {},\n    warn: () => {},\n    error: () => {},\n    debug: () => {},\n  };\n}\n","// Drops kafkajs 2.2.4's cosmetic TimeoutNegativeWarning; scoped so our own\n// negative-timeout bugs still surface. Rationale + design: ISSUES.md § KAFKAJS-TIMEOUT-WARNING.\n\ntype EmitWarning = typeof process.emitWarning;\n\nlet originalEmitWarning: EmitWarning | null = null;\nlet patchedEmitWarning: EmitWarning | null = null;\n\nexport function isKafkaTimeoutNegativeWarning(name: string | undefined, stack: string | undefined): boolean {\n  return name === 'TimeoutNegativeWarning' && (stack ?? '').includes('kafkajs');\n}\n\n// Process-global singleton (no ref-count): the reporter owns exactly one\n// KafkaEventProducer, so install/teardown track that single lifecycle.\nexport function suppressKafkaTimeoutWarning(): void {\n  if (patchedEmitWarning) return;\n  const original = process.emitWarning;\n  const callOriginal = original.bind(process) as (w: string | Error, ...a: unknown[]) => void;\n  const patched = ((warning: string | Error, ...rest: unknown[]): void => {\n    const type = typeof rest[0] === 'string' ? rest[0] : (rest[0] as { type?: string } | null | undefined)?.type;\n    const name = warning instanceof Error ? warning.name : type;\n    // Name check first so the stack is only materialized for the candidate warning.\n    if (name === 'TimeoutNegativeWarning' && isKafkaTimeoutNegativeWarning(name, new Error().stack ?? undefined)) {\n      return;\n    }\n    callOriginal(warning, ...rest);\n  }) as EmitWarning;\n  originalEmitWarning = original;\n  patchedEmitWarning = patched;\n  process.emitWarning = patched;\n}\n\nexport function restoreKafkaTimeoutWarning(): void {\n  // Only tear down when OUR patch is still the current emitWarning. If something\n  // layered another patch on top, leave our refs intact so we neither orphan the\n  // buried patch nor let a later suppress() double-wrap.\n  if (process.emitWarning !== patchedEmitWarning) return;\n  if (originalEmitWarning) process.emitWarning = originalEmitWarning;\n  originalEmitWarning = null;\n  patchedEmitWarning = null;\n}\n","import type { TestEvent } from '../types/index.js';\n\nexport function sizeOf(event: TestEvent): number {\n  try {\n    return Buffer.byteLength(JSON.stringify(event));\n  } catch {\n    return 0;\n  }\n}\n","import type { TestEvent } from '../types/index.js';\nimport type { Logger } from '../utils/logger.js';\nimport { createNoopLogger } from '../utils/logger.js';\nimport { sizeOf } from '../utils/sizeOf.js';\nimport { PartialBatchError } from '../reporter/errors.js';\n\nexport interface EventBufferOptions {\n  maxSize?: number;\n  maxBytes?: number;\n  flushIntervalMs?: number;\n  onFlush?: (events: TestEvent[]) => Promise<void>;\n  logger?: Logger;\n}\n\nexport class EventBuffer {\n  private events: TestEvent[] = [];\n  private pendingBytes = 0;\n  private maxSize: number;\n  private maxBytes: number;\n  private flushIntervalMs: number;\n  private flushTimer: ReturnType<typeof setInterval> | null = null;\n  private onFlush: (events: TestEvent[]) => Promise<void>;\n  private flushPromise: Promise<void> | null = null;\n  private readonly logger: Logger;\n\n  constructor(options: EventBufferOptions) {\n    this.maxSize = options.maxSize ?? 10;\n    this.maxBytes = options.maxBytes ?? Number.POSITIVE_INFINITY;\n    this.flushIntervalMs = options.flushIntervalMs ?? 250;\n    this.onFlush = options.onFlush ?? (async () => {});\n    this.logger = options.logger ?? createNoopLogger();\n    this.startTimer();\n  }\n\n  // Sync path for test:end — void flush so a stuck Kafka send cannot block enqueue.\n  enqueue(event: TestEvent): void {\n    this.events.push(event);\n    this.pendingBytes += sizeOf(event);\n    if (this.events.length >= this.maxSize || this.pendingBytes >= this.maxBytes) {\n      void this.flush();\n    }\n  }\n\n  async add(event: TestEvent): Promise<void> {\n    this.events.push(event);\n    this.pendingBytes += sizeOf(event);\n    if (this.events.length >= this.maxSize || this.pendingBytes >= this.maxBytes) {\n      await this.flush();\n    }\n  }\n\n  // Resolves only when nothing is in flight AND the buffer is empty: a waiter\n  // that returned on \"empty\" alone let onEnd send run:end while a flush started\n  // by another waiter was still in flight (the server then finalized early).\n  async flush(): Promise<void> {\n    while (this.flushPromise) {\n      try {\n        await this.flushPromise;\n      } catch {\n        /* fall through: restored events retry on the next flush */\n      }\n    }\n\n    if (this.events.length === 0) return;\n\n    this.flushPromise = this.doFlush();\n    try {\n      await this.flushPromise;\n    } finally {\n      this.flushPromise = null;\n    }\n    if (this.events.length > 0) return this.flush();\n  }\n\n  private async doFlush(): Promise<void> {\n    const eventsToFlush = [...this.events];\n    const bytesToFlush = this.pendingBytes;\n    this.events = [];\n    this.pendingBytes = 0;\n    try {\n      await this.onFlush(eventsToFlush);\n    } catch (error) {\n      // Restore only the failed suffix; peers already acked in this flush.\n      if (error instanceof PartialBatchError) {\n        this.events = [...error.failed, ...this.events];\n        this.pendingBytes += error.failed.reduce((sum, e) => sum + sizeOf(e), 0);\n        this.logger.error(\n          `Partial flush failure: ${error.succeeded} events delivered, ${error.failed.length} restored — ${error.message}`\n        );\n        throw error;\n      }\n      // Restore to FRONT — preserves order; next flush retries.\n      this.events = [...eventsToFlush, ...this.events];\n      this.pendingBytes += bytesToFlush;\n      this.logger.error(`Failed to flush events: ${error instanceof Error ? error.message : String(error)}`);\n      throw error;\n    }\n  }\n\n  size(): number {\n    return this.events.length;\n  }\n\n  clear(): void {\n    this.events = [];\n    this.pendingBytes = 0;\n  }\n\n  private startTimer(): void {\n    if (this.flushIntervalMs > 0) {\n      this.flushTimer = setInterval(() => {\n        // void: doFlush restores events on failure, next cycle retries.\n        void this.flush();\n      }, this.flushIntervalMs);\n    }\n  }\n\n  // Does NOT flush — caller does a final explicit flush before destroy.\n  destroy(): void {\n    if (this.flushTimer !== null) {\n      clearInterval(this.flushTimer);\n      this.flushTimer = null;\n    }\n  }\n\n  getEvents(): TestEvent[] {\n    return [...this.events];\n  }\n\n  // Sync take-and-reset (no await between) so an enqueue racing the returned batch's send is neither double-sent nor dropped.\n  drain(): TestEvent[] {\n    const events = this.events;\n    this.events = [];\n    this.pendingBytes = 0;\n    return events;\n  }\n}\n","import type { TestEvent } from '../types/index.js';\nimport type { KafkaEventProducer } from './kafka.js';\nimport type { HttpClient } from './http.js';\nimport type { Logger } from '../utils/logger.js';\nimport { createNoopLogger } from '../utils/logger.js';\nimport {\n  EventTooLargeError,\n  HttpDeliveryError,\n  PartialBatchError,\n  isPermanentHttpStatus,\n  isQuotaError,\n} from '../reporter/errors.js';\nimport { sizeOf } from '../utils/sizeOf.js';\n\n// Sit under the server's 1000-event / 5-MiB per-POST caps with headroom for\n// JSON envelope, proxies, and auth headers.\nconst HTTP_CHUNK_MAX_EVENTS = 900;\nconst HTTP_CHUNK_MAX_BYTES = 4 * 1024 * 1024;\n\nexport interface DeliveryManagerOptions {\n  kafkaProducer?: KafkaEventProducer;\n  httpClient: HttpClient;\n  httpFallbackUrl?: string;\n  maxAttempts?: number;\n  baseDelayMs?: number;\n  kafkaRecoveryThreshold?: number;\n  logger?: Logger;\n}\n\ntype DeliveryChannel = 'kafka' | 'http';\n\nexport class EventDeliveryManager {\n  private readonly kafkaProducer: KafkaEventProducer | null;\n  private readonly httpClient: HttpClient;\n  private readonly httpFallbackUrl: string | null;\n  private readonly maxAttempts: number;\n  private readonly baseDelayMs: number;\n  private readonly logger: Logger;\n\n  private kafkaHealthy = true;\n  private readonly kafkaRecoveryThreshold: number;\n  private httpSuccessCount = 0;\n  private discardedCount = 0;\n\n  lastDeliveryAt = 0;\n\n  constructor(options: DeliveryManagerOptions) {\n    this.kafkaProducer = options.kafkaProducer ?? null;\n    this.httpClient = options.httpClient;\n    this.httpFallbackUrl = options.httpFallbackUrl ?? null;\n    this.maxAttempts = options.maxAttempts ?? 3;\n    this.baseDelayMs = options.baseDelayMs ?? 500;\n    this.logger = options.logger ?? createNoopLogger();\n    this.kafkaRecoveryThreshold = options.kafkaRecoveryThreshold ?? 3;\n  }\n\n  async sendBatch(events: TestEvent[]): Promise<void> {\n    if (events.length === 0) return;\n\n    if (this.kafkaProducer && this.kafkaHealthy) {\n      const kafkaSuccess = await this.tryKafkaWithRetry(events);\n      if (kafkaSuccess) {\n        this.lastDeliveryAt = Date.now();\n        return;\n      }\n      this.kafkaHealthy = false;\n      this.logger.warn('Kafka failed — switching to HTTP fallback');\n    }\n\n    await this.tryHttpWithRetry(events);\n  }\n\n  // run:end goes through here direct, never buffered — must stay last on the partition.\n  async send(event: TestEvent): Promise<void> {\n    await this.sendBatch([event]);\n  }\n\n  // One attempt per channel: the mid-run backoff alone outlasts the shutdown\n  // budget, so the HTTP fallback never starts.\n  async sendUrgent(events: TestEvent[]): Promise<void> {\n    if (events.length === 0) return;\n\n    if (this.kafkaProducer && this.kafkaHealthy) {\n      if (await this.tryKafkaWithRetry(events, 1)) {\n        this.lastDeliveryAt = Date.now();\n        return;\n      }\n      this.kafkaHealthy = false;\n      this.logger.warn('Kafka failed — switching to HTTP fallback');\n    }\n\n    await this.tryHttpWithRetry(events, 1);\n  }\n\n  private async tryKafkaWithRetry(events: TestEvent[], maxAttempts = this.maxAttempts): Promise<boolean> {\n    if (!this.kafkaProducer) return false;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      try {\n        if (!this.kafkaProducer.isConnected) {\n          this.logger.debug(`Kafka reconnect attempt ${attempt}/${maxAttempts}`);\n          await this.kafkaProducer.connect();\n        }\n\n        await this.kafkaProducer.sendBatch(events);\n\n        const first = events[0];\n        const last = events[events.length - 1];\n        const seqRange = 'sequence' in first ? `(seq ${first.sequence}-${(last as typeof first).sequence})` : '';\n        this.logger.debug(`Flushed ${events.length} events via kafka ${seqRange}`.trim());\n        return true;\n      } catch (error) {\n        const message = error instanceof Error ? error.message : String(error);\n        if (attempt < maxAttempts) {\n          const delay = this.getBackoffDelay(attempt);\n          this.logger.debug(\n            `Kafka send failed: ${message} (attempt ${attempt}/${maxAttempts}, retrying in ${delay}ms)`\n          );\n          await this.sleep(delay);\n        } else {\n          this.logger.error(`Kafka delivery failed after ${maxAttempts} attempts: ${message}`);\n        }\n      }\n    }\n\n    return false;\n  }\n\n  private async tryHttpWithRetry(events: TestEvent[], maxAttempts = this.maxAttempts): Promise<void> {\n    if (!this.httpFallbackUrl) {\n      throw new Error('HTTP fallback not configured — server did not return httpFallback URL');\n    }\n\n    const fallbackUrl = this.httpFallbackUrl;\n    const subBatches = chunkForHttp(events);\n    let succeeded = 0;\n\n    for (let i = 0; i < subBatches.length; i++) {\n      const subBatch = subBatches[i];\n      try {\n        await this.sendSubBatchWithSplit(fallbackUrl, subBatch, maxAttempts);\n        succeeded += subBatch.length;\n      } catch (error) {\n        if (error instanceof EventTooLargeError) {\n          this.discardedCount += error.count;\n          continue;\n        }\n        // Quota must propagate raw so isQuotaError() upstream still matches;\n        // wrapping in PartialBatchError would hide it and cause an infinite\n        // restore-and-retry loop.\n        if (isQuotaError(error)) throw error;\n        // With prior sub-batches acked, wrap the un-attempted tail so the\n        // buffer restores only what wasn't sent.\n        if (succeeded === 0) throw error;\n        const failed = subBatches.slice(i).flat();\n        const message = error instanceof Error ? error.message : String(error);\n        throw new PartialBatchError(\n          failed,\n          succeeded,\n          `HTTP fallback failed at sub-batch ${i + 1}/${subBatches.length}: ${message}`,\n          {\n            cause: error,\n          }\n        );\n      }\n    }\n\n    const first = events[0];\n    const last = events[events.length - 1];\n    const seqRange =\n      first && last && 'sequence' in first ? `(seq ${first.sequence}-${(last as typeof first).sequence})` : '';\n    this.logger.debug(\n      `Flushed ${events.length} events via http in ${subBatches.length} sub-batches ${seqRange}`.trim()\n    );\n    this.lastDeliveryAt = Date.now();\n\n    if (!this.kafkaHealthy) {\n      this.httpSuccessCount++;\n      if (this.httpSuccessCount >= this.kafkaRecoveryThreshold) {\n        this.logger.debug(\n          `HTTP success ${this.kafkaRecoveryThreshold}/${this.kafkaRecoveryThreshold} — probing Kafka recovery`\n        );\n        this.tryKafkaRecovery().catch(() => {});\n      }\n    }\n  }\n\n  private async sendSubBatchWithSplit(url: string, events: TestEvent[], maxAttempts = this.maxAttempts): Promise<void> {\n    let lastError: Error | undefined;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      try {\n        await this.httpClient.sendEvents(url, events);\n        return;\n      } catch (error) {\n        if (error instanceof HttpDeliveryError && error.status === 413 && events.length === 1) {\n          this.logger.error(`Single event exceeds server cap (413) — discarding one event`);\n          throw new EventTooLargeError('event exceeds server per-request cap', { cause: error });\n        }\n        // Halve and recurse. A too-large half is swallowed so the peer half\n        // still ships; any other error propagates (server upserts absorb any\n        // duplicate re-send of the sibling).\n        if (error instanceof HttpDeliveryError && error.status === 413) {\n          const mid = Math.floor(events.length / 2);\n          this.logger.debug(`413 on ${events.length}-event sub-batch — halving into ${mid} + ${events.length - mid}`);\n          const halves = [events.slice(0, mid), events.slice(mid)];\n          let allTooLarge = true;\n          let tooLargeCount = 0;\n          for (const half of halves) {\n            try {\n              await this.sendSubBatchWithSplit(url, half, maxAttempts);\n              allTooLarge = false;\n            } catch (halfError) {\n              if (halfError instanceof EventTooLargeError) {\n                tooLargeCount += halfError.count;\n                continue;\n              }\n              throw halfError;\n            }\n          }\n          if (allTooLarge) {\n            throw new EventTooLargeError('all halves exceed server cap', { cause: error, count: tooLargeCount });\n          }\n          if (tooLargeCount > 0) this.discardedCount += tooLargeCount;\n          return;\n        }\n        if (error instanceof HttpDeliveryError && isPermanentHttpStatus(error.status)) {\n          this.logger.error(`HTTP fallback permanent error (${error.status}) — sub-batch discarded`);\n          throw error;\n        }\n        if (isQuotaError(error)) {\n          this.logger.error(`HTTP fallback permanent error (402 quota) — sub-batch discarded`);\n          throw error;\n        }\n\n        lastError = error instanceof Error ? error : new Error(String(error));\n        if (attempt < maxAttempts) {\n          const delay = this.getBackoffDelay(attempt);\n          this.logger.debug(\n            `HTTP sub-batch attempt ${attempt}/${maxAttempts} failed: ${lastError.message} (retrying in ${delay}ms)`\n          );\n          await this.sleep(delay);\n        } else {\n          this.logger.error(`HTTP sub-batch delivery failed after ${maxAttempts} attempts: ${lastError.message}`);\n        }\n      }\n    }\n\n    throw lastError ?? new Error('HTTP sub-batch delivery failed — no attempts made (maxAttempts must be >= 1)');\n  }\n\n  private async tryKafkaRecovery(): Promise<void> {\n    if (!this.kafkaProducer) return;\n    this.httpSuccessCount = 0;\n    try {\n      await this.kafkaProducer.connect();\n      this.kafkaHealthy = true;\n      this.logger.debug('Kafka connection recovered — resuming primary channel');\n    } catch {\n      this.logger.debug('Kafka recovery failed — staying on HTTP');\n    }\n  }\n\n  private getBackoffDelay(attempt: number): number {\n    return this.baseDelayMs * Math.pow(2, attempt - 1);\n  }\n\n  private sleep(ms: number): Promise<void> {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n\n  get activeChannel(): DeliveryChannel {\n    if (!this.kafkaProducer) return 'http';\n    return this.kafkaHealthy ? 'kafka' : 'http';\n  }\n\n  get discardCount(): number {\n    return this.discardedCount;\n  }\n\n  // Monotonic — 0/negative counts are dropped so a caller bug can't silently\n  // un-fail a run.\n  recordDiscard(count: number): void {\n    if (count > 0) this.discardedCount += count;\n  }\n}\n\n// FIFO across sub-batches; a lone event over the byte cap gets its own chunk\n// and trips EventTooLargeError at send time.\nfunction chunkForHttp(events: TestEvent[]): TestEvent[][] {\n  if (events.length === 0) return [];\n  const chunks: TestEvent[][] = [];\n  let current: TestEvent[] = [];\n  let currentBytes = 0;\n\n  for (const event of events) {\n    const eventBytes = sizeOf(event);\n    const wouldExceedBytes = currentBytes + eventBytes > HTTP_CHUNK_MAX_BYTES && current.length > 0;\n    const wouldExceedCount = current.length >= HTTP_CHUNK_MAX_EVENTS;\n    if (wouldExceedBytes || wouldExceedCount) {\n      chunks.push(current);\n      current = [];\n      currentBytes = 0;\n    }\n    current.push(event);\n    currentBytes += eventBytes;\n  }\n  if (current.length > 0) chunks.push(current);\n  return chunks;\n}\n","/**\n * Git metadata collector\n *\n * Primary source is local git commands. In CI, provider env vars take\n * precedence (they describe the *triggering* ref/commit, which git checkout may\n * have rewritten — e.g. PR merge commits). GitHub Actions keeps its richer\n * event-file PR path; the other providers are resolved from env vars.\n *\n * Provider env var references:\n * - GitHub Actions: https://docs.github.com/en/actions/reference/environment-variables\n * - GitLab CI:      https://docs.gitlab.com/ee/ci/variables/predefined_variables.html\n * - CircleCI:       https://circleci.com/docs/reference/variables/\n * - Azure DevOps:   https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables\n * - AWS CodeBuild:  https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html\n * - Bitbucket:      https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/\n */\n\nimport { readFile } from 'fs/promises';\nimport { isAbsolute, normalize } from 'path';\nimport { BaseMetadataCollector } from './base.js';\nimport { detectCIProvider } from './detect-ci-provider.js';\nimport type { GitMetadata, PRMetadata } from './types.js';\n\n// Dynamic import for execa (ESM-only package, needs dynamic import in CJS context)\nlet execaPromise: Promise<typeof import('execa').execa> | null = null;\n\n/**\n * Dynamically import execa (ESM-only package) for CJS compatibility only once per process using memoization.\n *\n * @returns Promise resolving to the execa function\n * @throws Error if execa cannot be imported\n */\nasync function getExeca(): Promise<typeof import('execa').execa> {\n  if (!execaPromise) {\n    execaPromise = import('execa')\n      .then((m) => m.execa)\n      .catch((error) => {\n        console.error('Failed to import execa:', error.message);\n        // Reset so the next call can retry the import\n        execaPromise = null;\n        throw new Error('Failed to load execa. Ensure execa is installed: npm install execa');\n      });\n  }\n  return execaPromise;\n}\n\n/**\n * Upper bound for the local git-command layer.\n *\n * MetadataAggregator wraps each collector in a 5s budget. Local git commands are\n * best-effort *enrichment*: CI providers already expose branch/commit/repo via\n * env vars (no subprocess). On a busy/CPU-starved runner the git subprocess\n * callbacks can be starved past the budget, so we bound them well under it and\n * fall back to the env-derived metadata. Kept comfortably below 5s so the env\n * merge + return still fit.\n */\nconst GIT_COMMAND_BUDGET_MS = 2500;\n\n/** Splits a `Name <email>` author (GitLab's CI_COMMIT_AUTHOR); a bare name passes through. */\nfunction parseNameEmail(raw: string): { name: string; email?: string } {\n  const match = /^(.*?)\\s*<([^<>]+)>\\s*$/.exec(raw.trim());\n  return match ? { name: match[1].trim(), email: match[2].trim() } : { name: raw.trim() };\n}\n\n/**\n * Minimal GitHub event data interface for type safety\n */\ninterface GitHubEventData {\n  ref?: unknown;\n  head_commit?: {\n    id?: unknown;\n    message?: unknown;\n    timestamp?: unknown;\n    author?: { name?: unknown; email?: unknown; username?: unknown };\n  };\n  repository?: { html_url?: unknown };\n  pull_request?: {\n    title?: unknown;\n    number?: unknown;\n    state?: unknown;\n    head?: { ref?: unknown; sha?: unknown };\n    base?: { ref?: unknown };\n    user?: { login?: unknown };\n    labels?: Array<{ name?: unknown }>;\n    merged?: unknown;\n    mergeable?: unknown;\n    merge_commit_sha?: unknown;\n  };\n}\n\n/**\n * Resolved GitHub author information for deduplication and canonical naming\n */\ninterface GitHubAuthorInfo {\n  authorId: string;\n  authorLogin?: string;\n  // True only when the login is the commit's own account, not the GITHUB_ACTOR fallback.\n  fromCommit?: boolean;\n}\n\n/**\n * Git metadata collected from local git commands (the base layer)\n */\ninterface GitCommandBase {\n  branch?: string;\n  hash?: string;\n  message?: string;\n  author?: string;\n  email?: string;\n  timestamp?: string;\n  repoUrl?: string;\n  isDirty?: boolean;\n}\n\n/**\n * Git metadata extracted from CI provider environment variables\n */\ninterface EnvironmentGitInfo {\n  branch?: string;\n  commitHash?: string;\n  commitMessage?: string;\n  author?: string;\n  email?: string;\n  repoUrl?: string;\n  prId?: string;\n  prTitle?: string;\n  prUrl?: string;\n  prStatus?: string;\n  prBranch?: string;\n  prTargetBranch?: string;\n}\n\n/**\n * Final resolved commit/branch/repo values after merging git + CI env sources\n */\ninterface ResolvedGit {\n  branch?: string;\n  hash?: string;\n  message?: string;\n  author?: string;\n  email?: string;\n  verifiedLogin?: string;\n  timestamp?: string;\n  repoUrl?: string;\n  pr?: PRMetadata;\n}\n\nexport interface GitCollectorOptions {\n  /**\n   * Timeout for git commands in milliseconds\n   * @default 3000\n   */\n  timeout?: number;\n\n  /**\n   * Working directory for git commands\n   * @default process.cwd()\n   */\n  cwd?: string;\n}\n\n/**\n * Collects git repository metadata\n */\nexport class GitMetadataCollector extends BaseMetadataCollector<GitMetadata> {\n  private options: Required<GitCollectorOptions>;\n\n  constructor(options: GitCollectorOptions = {}) {\n    super('git');\n    this.options = {\n      timeout: options.timeout || 3000,\n      cwd: options.cwd || process.cwd(),\n    };\n  }\n\n  /**\n   * Collect git metadata\n   */\n  protected async collectMetadata(): Promise<GitMetadata> {\n    const provider = detectCIProvider();\n\n    // Git commands are best-effort enrichment, bounded so a slow or CPU-starved\n    // runner (e.g. a busy container) can't blow the metadata budget. CI\n    // providers expose branch/commit/repo via env vars (no subprocess), so that\n    // data survives even when the git commands don't finish in time.\n    const base = await this.collectGitCommandBase();\n\n    // GitHub Actions keeps the richer event-file PR path; other providers\n    // (and local runs) resolve from CI env vars layered over git commands.\n    const resolved =\n      provider === 'github-actions' ? await this.applyGitHubContext(base) : this.applyCIEnvContext(base, provider);\n\n    // Resolve GitHub author info: numeric ID for deduplication, login for canonical name\n    const githubAuthor = await this.resolveGitHubAuthor(resolved.hash);\n\n    // Nothing usable (not a git repo and not in a recognized CI) → empty.\n    if (!this.hasGitData(resolved, base)) {\n      return this.getEmptyMetadata();\n    }\n\n    return {\n      branch: resolved.branch,\n      commit: {\n        hash: resolved.hash,\n        message: resolved.message,\n        author: githubAuthor.authorLogin || resolved.author,\n        authorId: githubAuthor.authorId,\n        email: resolved.email,\n        verifiedLogin: (githubAuthor.fromCommit ? githubAuthor.authorLogin : undefined) ?? resolved.verifiedLogin,\n        timestamp: resolved.timestamp,\n        isDirty: base.isDirty,\n      },\n      repository: {\n        name: this.extractRepoName(resolved.repoUrl),\n        url: resolved.repoUrl,\n      },\n      ...(resolved.pr ? { pr: resolved.pr } : {}),\n    };\n  }\n\n  /**\n   * Whether any meaningful git/CI metadata was resolved. Used to preserve the\n   * \"empty when not a git repo and not in CI\" contract.\n   */\n  private hasGitData(resolved: ResolvedGit, base: GitCommandBase): boolean {\n    return Boolean(\n      resolved.branch ||\n      resolved.hash ||\n      resolved.message ||\n      resolved.author ||\n      resolved.email ||\n      resolved.repoUrl ||\n      resolved.pr ||\n      base.isDirty !== undefined\n    );\n  }\n\n  /**\n   * Get empty metadata\n   */\n  protected getEmptyMetadata(): GitMetadata {\n    return {};\n  }\n\n  /**\n   * Collect base git metadata. The GIT_COMMAND_BUDGET_MS bound is on how long we\n   * *wait* (withTimeout is a Promise.race, not cancellation) — on timeout the\n   * git subprocesses keep running detached and are reaped by execa's own\n   * per-command `timeout: this.options.timeout`. We just stop awaiting and return\n   * an empty base so a slow or CPU-starved runner can't discard CI env-derived\n   * metadata (which needs no git subprocess).\n   */\n  private async collectGitCommandBase(): Promise<GitCommandBase> {\n    try {\n      return await this.withTimeout(this.runGitCommands(), GIT_COMMAND_BUDGET_MS, 'git command metadata');\n    } catch {\n      // Slow/starved/unavailable git → CI env metadata still covers providers.\n      return {};\n    }\n  }\n\n  /**\n   * Run the local git commands: verify the repo, then collect\n   * branch/commit/url/dirty in parallel. Promise.allSettled isolates failures so\n   * a single broken command never loses the rest of the data.\n   */\n  private async runGitCommands(): Promise<GitCommandBase> {\n    // Not a git repository → nothing to collect from commands\n    if (!(await this.isGitRepository())) {\n      return {};\n    }\n\n    const results = await Promise.allSettled([\n      this.getBranch(),\n      this.getCommitHash(),\n      this.getCommitInfo(),\n      this.getRepoUrl(),\n      this.isDirtyWorkingTree(),\n    ]);\n\n    const value = <T>(index: number): T | undefined =>\n      results[index]?.status === 'fulfilled' ? (results[index] as PromiseFulfilledResult<T>).value : undefined;\n\n    const commitInfo = value<{ message?: string; author?: string; email?: string; timestamp?: string }>(2);\n\n    return {\n      branch: value<string>(0),\n      hash: value<string>(1),\n      message: commitInfo?.message,\n      author: commitInfo?.author,\n      email: commitInfo?.email,\n      timestamp: commitInfo?.timestamp,\n      repoUrl: value<string>(3),\n      isDirty: value<boolean>(4),\n    };\n  }\n\n  /**\n   * Apply GitHub Actions PR context over the git command base.\n   * Overrides merge-commit data with the real PR head commit and builds rich\n   * PR metadata from the event file.\n   */\n  private async applyGitHubContext(base: GitCommandBase): Promise<ResolvedGit> {\n    const resolved: ResolvedGit = { ...base };\n    const event = await this.readGitHubEventFile();\n    const isPullRequest = process.env.GITHUB_EVENT_NAME === 'pull_request';\n\n    // Branch: the *triggering* ref is authoritative. Under actions/checkout the\n    // local ref is a detached HEAD, so git's `base.branch` is the literal \"HEAD\"\n    // and must not win. PR → source branch; push/other → the ref name.\n    const branch = this.resolveGitHubBranch(isPullRequest, event);\n    if (this.isNonEmptyString(branch)) {\n      resolved.branch = branch;\n    }\n\n    if (isPullRequest && event?.pull_request) {\n      // Rich PR path: real head commit (not the ephemeral merge commit) + PR block.\n      // The PR event payload lacks the commit message/author, so enrich via git.\n      resolved.pr = this.extractPRMetadata(event);\n      const headSha = this.asString(event.pull_request.head?.sha);\n      if (headSha) {\n        resolved.hash = headSha;\n        const realCommit = await this.getCommitInfoFromSha(headSha);\n        if (realCommit) {\n          resolved.message = realCommit.message ?? resolved.message;\n          resolved.author = realCommit.author ?? resolved.author;\n          resolved.email = realCommit.email ?? resolved.email;\n          resolved.timestamp = realCommit.timestamp ?? resolved.timestamp;\n        }\n      }\n    } else if (event?.head_commit) {\n      // Push path: the event payload carries the full commit — no git subprocess,\n      // so commit/message/author survive even when the git probe times out.\n      const commit = event.head_commit;\n      resolved.hash = this.asString(commit.id) ?? resolved.hash;\n      resolved.message = this.asString(commit.message) ?? resolved.message;\n      resolved.author = this.asString(commit.author?.name) ?? resolved.author;\n      resolved.email = this.asString(commit.author?.email) ?? resolved.email;\n      resolved.timestamp = this.asString(commit.timestamp) ?? resolved.timestamp;\n      resolved.verifiedLogin = this.asString(commit.author?.username);\n    }\n\n    // Subprocess-free env fallbacks: cover a missing/unreadable event file and a\n    // timed-out git probe. GITHUB_SHA is the pushed commit on non-PR events; on a\n    // PR it is the merge commit, so only fill it when nothing better was resolved.\n    if (!this.isNonEmptyString(resolved.hash)) {\n      resolved.hash = this.asString(process.env.GITHUB_SHA) ?? resolved.hash;\n    }\n    if (!this.isNonEmptyString(resolved.repoUrl)) {\n      resolved.repoUrl = this.resolveGitHubRepoUrl(event) ?? resolved.repoUrl;\n    }\n\n    return resolved;\n  }\n\n  /**\n   * The branch that triggered a GitHub Actions run, from env/event only — never\n   * the local git ref, which actions/checkout leaves detached (\"HEAD\").\n   */\n  private resolveGitHubBranch(isPullRequest: boolean, event: GitHubEventData | undefined): string | undefined {\n    if (isPullRequest) {\n      return this.asString(process.env.GITHUB_HEAD_REF) ?? this.asString(event?.pull_request?.head?.ref);\n    }\n    const refName = this.asString(process.env.GITHUB_REF_NAME);\n    if (refName) return refName;\n    const eventRef = this.asString(event?.ref);\n    return eventRef ? this.extractBranchFromRef(eventRef) : undefined;\n  }\n\n  /**\n   * Repo URL from GitHub env (GITHUB_SERVER_URL + GITHUB_REPOSITORY) or the event\n   * payload, credentials stripped defensively.\n   */\n  private resolveGitHubRepoUrl(event: GitHubEventData | undefined): string | undefined {\n    const serverUrl = this.asString(process.env.GITHUB_SERVER_URL);\n    const repository = this.asString(process.env.GITHUB_REPOSITORY);\n    if (serverUrl && repository) {\n      return `${serverUrl}/${repository}`;\n    }\n    const htmlUrl = this.asString(event?.repository?.html_url);\n    return htmlUrl ? this.stripCredentials(htmlUrl) : undefined;\n  }\n\n  private asString(value: unknown): string | undefined {\n    return this.isNonEmptyString(value) ? value : undefined;\n  }\n\n  /**\n   * Apply CI provider env vars over the git command base.\n   *\n   * For known CI providers env vars win (they describe the triggering ref,\n   * which checkout may have rewritten). For local/unknown runs git wins and env\n   * only fills gaps.\n   */\n  private applyCIEnvContext(base: GitCommandBase, provider: string | undefined): ResolvedGit {\n    const env = this.getEnvironmentGitInfo(provider);\n    const prioritizeEnv = provider !== undefined;\n    const pick = (envVal?: string, gitVal?: string): string | undefined =>\n      prioritizeEnv ? envVal || gitVal : gitVal || envVal;\n\n    return {\n      branch: pick(env.branch, base.branch),\n      hash: pick(env.commitHash, base.hash),\n      message: pick(env.commitMessage, base.message),\n      author: pick(env.author, base.author),\n      email: pick(env.email, base.email),\n      timestamp: base.timestamp, // env sources don't carry a timestamp\n      repoUrl: pick(env.repoUrl, base.repoUrl),\n      pr: this.buildPRMetadata(env),\n    };\n  }\n\n  /**\n   * Map CI env PR fields onto the PRMetadata shape. Returns undefined when no\n   * PR data is present.\n   */\n  private buildPRMetadata(env: EnvironmentGitInfo): PRMetadata | undefined {\n    const pr: PRMetadata = {};\n\n    if (env.prId) {\n      const num = Number(env.prId);\n      if (Number.isFinite(num)) pr.number = num;\n    }\n    if (env.prTitle) pr.title = env.prTitle;\n    if (env.prUrl) pr.url = env.prUrl;\n    if (env.prStatus) pr.status = env.prStatus;\n    if (env.prBranch) pr.branch = env.prBranch;\n    if (env.prTargetBranch) pr.targetBranch = env.prTargetBranch;\n\n    return Object.keys(pr).length > 0 ? pr : undefined;\n  }\n\n  /**\n   * Extract git metadata from CI provider environment variables. The\n   * provider-specific block runs first, then generic CI vars fill any gaps.\n   */\n  private getEnvironmentGitInfo(provider: string | undefined): EnvironmentGitInfo {\n    const info: EnvironmentGitInfo = {};\n\n    switch (provider) {\n      case 'gitlab-ci':\n        this.collectGitLabEnv(info);\n        break;\n      case 'azure-devops':\n        this.collectAzureDevOpsEnv(info);\n        break;\n      case 'jenkins':\n        this.collectJenkinsEnv(info);\n        break;\n      case 'circleci':\n        this.collectCircleCIEnv(info);\n        break;\n      case 'aws-codebuild':\n        this.collectAWSCodeBuildEnv(info);\n        break;\n      case 'bitbucket-pipelines':\n        this.collectBitbucketEnv(info);\n        break;\n      case 'buildkite':\n        this.collectBuildkiteEnv(info);\n        break;\n      case 'harness':\n        this.collectHarnessEnv(info);\n        break;\n      default:\n        break;\n    }\n\n    this.collectGenericEnv(info);\n    return info;\n  }\n\n  /**\n   * GitLab CI env extraction\n   */\n  private collectGitLabEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.CI_COMMIT_BRANCH) info.branch = env.CI_COMMIT_BRANCH;\n    else if (env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) info.branch = env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;\n    else if (env.CI_COMMIT_REF_NAME) info.branch = env.CI_COMMIT_REF_NAME;\n\n    if (env.CI_COMMIT_SHA) info.commitHash = env.CI_COMMIT_SHA;\n    if (env.CI_COMMIT_MESSAGE) info.commitMessage = env.CI_COMMIT_MESSAGE;\n    if (env.CI_COMMIT_AUTHOR) {\n      const { name, email } = parseNameEmail(env.CI_COMMIT_AUTHOR);\n      if (name) info.author = name;\n      if (email) info.email = email;\n    }\n    if (env.CI_COMMIT_AUTHOR_EMAIL) info.email = env.CI_COMMIT_AUTHOR_EMAIL;\n\n    // CI_REPOSITORY_URL embeds a gitlab-ci-token — strip it before storing\n    if (env.CI_REPOSITORY_URL) info.repoUrl = this.cleanGitLabUrl(env.CI_REPOSITORY_URL);\n    else if (env.CI_PROJECT_URL) info.repoUrl = env.CI_PROJECT_URL;\n\n    if (env.CI_MERGE_REQUEST_IID) {\n      info.prId = env.CI_MERGE_REQUEST_IID;\n      if (env.CI_MERGE_REQUEST_TITLE) info.prTitle = env.CI_MERGE_REQUEST_TITLE;\n      if (env.CI_PROJECT_URL) {\n        info.prUrl = `${env.CI_PROJECT_URL}/-/merge_requests/${env.CI_MERGE_REQUEST_IID}`;\n      }\n      if (env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) info.prBranch = env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;\n      if (env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME) info.prTargetBranch = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;\n    }\n  }\n\n  /**\n   * Azure DevOps env extraction\n   */\n  private collectAzureDevOpsEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.BUILD_REASON === 'PullRequest' && env.SYSTEM_PULLREQUEST_SOURCEBRANCH) {\n      info.branch = this.extractBranchFromRef(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);\n    } else if (env.BUILD_SOURCEBRANCH) {\n      info.branch = this.extractBranchFromRef(env.BUILD_SOURCEBRANCH);\n    } else if (env.BUILD_SOURCEBRANCHNAME) {\n      info.branch = env.BUILD_SOURCEBRANCHNAME;\n    }\n\n    if (env.BUILD_SOURCEVERSION) info.commitHash = env.BUILD_SOURCEVERSION;\n    if (env.BUILD_SOURCEVERSIONMESSAGE) info.commitMessage = env.BUILD_SOURCEVERSIONMESSAGE;\n    // BUILD_REQUESTEDFOR is who started the build (sent as ci.build.actor); the author comes from git.\n    if (env.BUILD_REPOSITORY_URI) info.repoUrl = this.cleanAzureDevOpsUrl(env.BUILD_REPOSITORY_URI);\n\n    if (env.SYSTEM_PULLREQUEST_PULLREQUESTID) {\n      info.prId = env.SYSTEM_PULLREQUEST_PULLREQUESTID;\n      if (env.SYSTEM_PULLREQUEST_PULLREQUESTTITLE) info.prTitle = env.SYSTEM_PULLREQUEST_PULLREQUESTTITLE;\n      if (env.SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI) {\n        // R6: SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI can carry PAT auth\n        // (https://user:PAT@dev.azure.com/...). Strip before templating.\n        const cleaned = this.stripCredentials(env.SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI);\n        if (cleaned) info.prUrl = `${cleaned}/pullrequest/${env.SYSTEM_PULLREQUEST_PULLREQUESTID}`;\n      }\n    }\n  }\n\n  /**\n   * Jenkins env extraction (git-plugin + GitHub PR Builder plugin)\n   */\n  private collectJenkinsEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    const gitBranch = env.BRANCH_NAME || env.GIT_BRANCH;\n    if (gitBranch) info.branch = gitBranch.replace('origin/', '');\n    if (env.GIT_COMMIT) info.commitHash = env.GIT_COMMIT;\n    if (env.GIT_AUTHOR_NAME) info.author = env.GIT_AUTHOR_NAME;\n    if (env.GIT_AUTHOR_EMAIL) info.email = env.GIT_AUTHOR_EMAIL;\n    // R2: Jenkins git-plugin sets GIT_URL to the fetch URL, commonly\n    // https://user:pat@host/... — strip creds before we persist.\n    if (env.GIT_URL) info.repoUrl = this.stripCredentials(env.GIT_URL);\n\n    if (env.ghprbPullId) {\n      info.prId = env.ghprbPullId;\n      if (env.ghprbPullTitle) info.prTitle = env.ghprbPullTitle;\n      // ghprbPullLink is user-facing but still worth cleaning defensively.\n      if (env.ghprbPullLink) info.prUrl = this.stripCredentials(env.ghprbPullLink);\n    }\n  }\n\n  /**\n   * CircleCI env extraction\n   */\n  private collectCircleCIEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.CIRCLE_BRANCH) info.branch = env.CIRCLE_BRANCH;\n    if (env.CIRCLE_SHA1) info.commitHash = env.CIRCLE_SHA1;\n    // CIRCLE_USERNAME is who started the build, not the commit author; the author comes from git.\n\n    if (env.CIRCLE_REPOSITORY_URL) {\n      info.repoUrl = this.cleanCircleCIUrl(env.CIRCLE_REPOSITORY_URL);\n    } else if (env.CIRCLE_PROJECT_USERNAME && env.CIRCLE_PROJECT_REPONAME) {\n      // CircleCI supports GitHub, GitLab, and Bitbucket. Hard-coding\n      // github.com would silently mislabel every non-GitHub project — instead\n      // resolve the host from a signal:\n      //   1. CIRCLE_PROJECT_TYPE (explicit: 'github' / 'bitbucket' / 'gitlab')\n      //   2. host of CIRCLE_PULL_REQUEST if a PR run\n      // If neither is available, leave repoUrl unset rather than guess.\n      const host = this.resolveCircleCIHost();\n      if (host) info.repoUrl = `${host}/${env.CIRCLE_PROJECT_USERNAME}/${env.CIRCLE_PROJECT_REPONAME}`;\n    }\n\n    if (env.CIRCLE_PULL_REQUEST || env.CIRCLE_PR_NUMBER) {\n      if (env.CIRCLE_PR_NUMBER) {\n        info.prId = env.CIRCLE_PR_NUMBER;\n      } else if (env.CIRCLE_PULL_REQUEST) {\n        const prMatch = env.CIRCLE_PULL_REQUEST.match(/\\/pull\\/(\\d+)$/);\n        if (prMatch?.[1]) info.prId = prMatch[1];\n      }\n\n      // R2: CIRCLE_PULL_REQUEST is normally clean (public PR page) but strip\n      // defensively — some proxied setups append tokens.\n      if (env.CIRCLE_PULL_REQUEST) info.prUrl = this.stripCredentials(env.CIRCLE_PULL_REQUEST);\n      if (!env.CIRCLE_TAG && env.CIRCLE_PULL_REQUEST) info.prStatus = 'open';\n    }\n  }\n\n  /**\n   * AWS CodeBuild env extraction\n   */\n  private collectAWSCodeBuildEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.CODEBUILD_WEBHOOK_HEAD_REF) {\n      info.branch = env.CODEBUILD_WEBHOOK_HEAD_REF.replace('refs/heads/', '');\n    } else if (env.CODEBUILD_SOURCE_VERSION) {\n      const sourceVersion = env.CODEBUILD_SOURCE_VERSION;\n      // Skip PR refs (pr/123) and raw commit hashes — only branch names are useful here\n      if (!sourceVersion.startsWith('pr/') && !/^[0-9a-f]{40}$/.test(sourceVersion)) {\n        info.branch = sourceVersion.replace('refs/heads/', '');\n      }\n    }\n\n    if (env.CODEBUILD_RESOLVED_SOURCE_VERSION) info.commitHash = env.CODEBUILD_RESOLVED_SOURCE_VERSION;\n    if (env.CODEBUILD_SOURCE_REPO_URL) info.repoUrl = this.convertCodeCommitToConsoleUrl(env.CODEBUILD_SOURCE_REPO_URL);\n\n    if (env.CODEBUILD_WEBHOOK_TRIGGER) {\n      const prMatch = env.CODEBUILD_WEBHOOK_TRIGGER.match(/^pr\\/(\\d+)$/);\n      if (prMatch?.[1]) {\n        info.prId = prMatch[1];\n        info.prStatus = 'open';\n        if (env.CODEBUILD_SOURCE_REPO_URL) {\n          info.prUrl = this.buildProviderPRUrl(env.CODEBUILD_SOURCE_REPO_URL, prMatch[1]);\n        }\n      }\n    }\n  }\n\n  /**\n   * Build a PR URL from a repo remote URL, parsing the hostname so\n   * `github.com` doesn't false-positive against `evil-github.com.attacker.com`\n   * and self-hosted / Enterprise hosts (`github.mycompany.com`,\n   * `gitlab.internal`, `bitbucket-server.corp`) are still recognized.\n   * Accepts HTTPS and SSH remotes (Buildkite's BUILDKITE_REPO is often SSH).\n   * Returns undefined when the host is not recognizable — safer than a wrong\n   * link.\n   */\n  private buildProviderPRUrl(repoUrl: string, prId: string): string | undefined {\n    // normalizeRemoteToHttps preserves userinfo by contract; strip before pr.url becomes user-visible.\n    const normalized = this.normalizeRemoteToHttps(repoUrl);\n    const cleaned = this.stripCredentials(normalized) ?? normalized;\n    let host: string;\n    try {\n      host = new URL(cleaned).hostname.toLowerCase();\n    } catch {\n      return undefined;\n    }\n    // R4: host === 'X' or host.endsWith('.X') — the leading dot in the suffix\n    // check is critical, otherwise `github.evil.com` matches. `startsWith('X.')`\n    // was the vulnerable variant: `github.` matches `github.evil.com` and would\n    // synthesise a phishing PR link into the dashboard.\n    // GitHub Enterprise Server customers can whitelist their host via\n    // TESTDINO_GHE_HOSTS (CSV) — off by default because most GHE customers\n    // won't run PRs through CodeBuild. See ISSUES.md R4.\n    if (host === 'github.com' || host.endsWith('.github.com') || this.isAllowlistedHost(host, 'TESTDINO_GHE_HOSTS')) {\n      return `${cleaned}/pull/${prId}`;\n    }\n    if (host === 'bitbucket.org' || host.endsWith('.bitbucket.org')) {\n      return `${cleaned}/pull-requests/${prId}`;\n    }\n    if (host === 'gitlab.com' || host.endsWith('.gitlab.com')) {\n      return `${cleaned}/-/merge_requests/${prId}`;\n    }\n    return undefined;\n  }\n\n  /**\n   * Normalize a git remote to an `https://host/path` form (no `.git` suffix) so\n   * hostname parsing works uniformly. Handles SSH shorthand\n   * (`git@host:org/repo.git`) and `ssh://` / `git://` remotes; HTTPS remotes are\n   * returned unchanged apart from the `.git` strip. Credential stripping is left\n   * to callers via stripCredentials — this only reshapes the transport.\n   */\n  private normalizeRemoteToHttps(url: string): string {\n    const trimmed = url.trim();\n\n    // git@host:org/repo(.git) → https://host/org/repo\n    const sshShorthand = trimmed.match(/^git@([^:]+):(.+?)(?:\\.git)?$/i);\n    if (sshShorthand) return `https://${sshShorthand[1]}/${sshShorthand[2]}`;\n\n    // ssh://[git@]host/org/repo(.git) or git://host/org/repo(.git) → https://host/org/repo\n    const sshProto = trimmed.match(/^(?:ssh|git):\\/\\/(?:[^@/]+@)?([^/]+)\\/(.+?)(?:\\.git)?$/i);\n    if (sshProto) return `https://${sshProto[1]}/${sshProto[2]}`;\n\n    return trimmed.replace(/\\.git$/, '');\n  }\n\n  /**\n   * Optional user-supplied allowlist for self-hosted git provider hosts.\n   * Format: `TESTDINO_GHE_HOSTS=host1,host2`. Empty / unset → no extra hosts.\n   */\n  private isAllowlistedHost(host: string, envKey: string): boolean {\n    const raw = process.env[envKey];\n    if (!raw) return false;\n    return raw\n      .split(',')\n      .map((h) => h.trim().toLowerCase())\n      .filter(Boolean)\n      .includes(host);\n  }\n\n  /**\n   * Bitbucket Pipelines env extraction\n   */\n  private collectBitbucketEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.BITBUCKET_BRANCH) info.branch = env.BITBUCKET_BRANCH;\n    if (env.BITBUCKET_COMMIT) info.commitHash = env.BITBUCKET_COMMIT;\n\n    if (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG) {\n      info.repoUrl = `https://bitbucket.org/${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}`;\n    } else if (env.BITBUCKET_GIT_HTTP_ORIGIN) {\n      // R2: Bitbucket Pipelines documents BITBUCKET_GIT_HTTP_ORIGIN as\n      // http://x-token-auth:<token>@bitbucket.org/... — live token in the\n      // env var. Strip before we persist.\n      info.repoUrl = this.stripCredentials(env.BITBUCKET_GIT_HTTP_ORIGIN);\n    }\n\n    if (env.BITBUCKET_PR_ID) {\n      info.prId = env.BITBUCKET_PR_ID;\n      if (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG) {\n        info.prUrl = `https://bitbucket.org/${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}/pull-requests/${env.BITBUCKET_PR_ID}`;\n      }\n      // Bitbucket does not expose PR state via env vars; in-PR runs default to\n      // 'open'. Post-merge runs (no BITBUCKET_PR_ID) are reclassified to\n      // 'merged' by CIMetadataCollector.reconcileWithGit.\n      info.prStatus = 'open';\n    }\n  }\n\n  /**\n   * Buildkite env extraction.\n   *\n   * On PR builds the agent checks out a detached HEAD, so the local git branch\n   * is unreliable — BUILDKITE_BRANCH carries the real triggering ref. BUILDKITE_REPO\n   * may be SSH (`git@host:org/repo.git`) or HTTPS; the PR URL is reconstructed\n   * from it host-aware so we never synthesise a wrong link.\n   */\n  private collectBuildkiteEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.BUILDKITE_BRANCH) info.branch = env.BUILDKITE_BRANCH;\n    if (env.BUILDKITE_COMMIT && env.BUILDKITE_COMMIT !== 'HEAD') info.commitHash = env.BUILDKITE_COMMIT;\n    if (env.BUILDKITE_MESSAGE) info.commitMessage = env.BUILDKITE_MESSAGE;\n    if (env.BUILDKITE_BUILD_AUTHOR) info.author = env.BUILDKITE_BUILD_AUTHOR;\n    if (env.BUILDKITE_BUILD_AUTHOR_EMAIL) info.email = env.BUILDKITE_BUILD_AUTHOR_EMAIL;\n    if (env.BUILDKITE_REPO) info.repoUrl = this.stripCredentials(this.normalizeRemoteToHttps(env.BUILDKITE_REPO));\n\n    // BUILDKITE_PULL_REQUEST is the PR number, or the literal 'false' otherwise.\n    if (env.BUILDKITE_PULL_REQUEST && env.BUILDKITE_PULL_REQUEST !== 'false') {\n      info.prId = env.BUILDKITE_PULL_REQUEST;\n      info.prBranch = env.BUILDKITE_BRANCH;\n      if (env.BUILDKITE_PULL_REQUEST_BASE_BRANCH) info.prTargetBranch = env.BUILDKITE_PULL_REQUEST_BASE_BRANCH;\n      // Buildkite exposes no direct PR URL; reconstruct from the repo remote.\n      if (env.BUILDKITE_REPO) info.prUrl = this.buildProviderPRUrl(env.BUILDKITE_REPO, env.BUILDKITE_PULL_REQUEST);\n      // No PR state is exposed via env; an in-PR build is 'open'.\n      info.prStatus = 'open';\n    }\n  }\n\n  /**\n   * Harness CI env extraction.\n   *\n   * Harness CI is built on Drone and mirrors the documented DRONE_* vars into\n   * the step container; those are the reliable source for git context (the\n   * HARNESS_* vars cover pipeline/build identity only). On a PR build DRONE_BRANCH\n   * is the target branch, so DRONE_SOURCE_BRANCH / DRONE_COMMIT_BRANCH are\n   * preferred for the triggering ref.\n   */\n  private collectHarnessEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (env.DRONE_SOURCE_BRANCH) info.branch = env.DRONE_SOURCE_BRANCH;\n    else if (env.DRONE_COMMIT_BRANCH) info.branch = env.DRONE_COMMIT_BRANCH;\n    else if (env.DRONE_BRANCH) info.branch = env.DRONE_BRANCH;\n\n    if (env.DRONE_COMMIT_SHA) info.commitHash = env.DRONE_COMMIT_SHA;\n    if (env.DRONE_COMMIT_MESSAGE) info.commitMessage = env.DRONE_COMMIT_MESSAGE;\n    if (env.DRONE_COMMIT_AUTHOR) info.author = env.DRONE_COMMIT_AUTHOR;\n    if (env.DRONE_COMMIT_AUTHOR_EMAIL) info.email = env.DRONE_COMMIT_AUTHOR_EMAIL;\n    if (env.DRONE_REPO_LINK) info.repoUrl = this.stripCredentials(this.normalizeRemoteToHttps(env.DRONE_REPO_LINK));\n\n    if (env.DRONE_PULL_REQUEST) {\n      info.prId = env.DRONE_PULL_REQUEST;\n      if (env.DRONE_SOURCE_BRANCH) info.prBranch = env.DRONE_SOURCE_BRANCH;\n      if (env.DRONE_TARGET_BRANCH) info.prTargetBranch = env.DRONE_TARGET_BRANCH;\n      if (env.DRONE_REPO_LINK) info.prUrl = this.buildProviderPRUrl(env.DRONE_REPO_LINK, env.DRONE_PULL_REQUEST);\n      info.prStatus = 'open';\n    }\n  }\n\n  /**\n   * Generic CI env vars — only fills fields not already set by a provider\n   */\n  private collectGenericEnv(info: EnvironmentGitInfo): void {\n    const { env } = process;\n\n    if (!info.branch) info.branch = env.CI_BRANCH || env.BRANCH_NAME || env.GIT_BRANCH || undefined;\n    if (!info.commitHash) info.commitHash = env.CI_COMMIT || env.COMMIT_SHA || env.GIT_COMMIT || undefined;\n    if (!info.author) info.author = env.CI_AUTHOR || env.GIT_AUTHOR || env.COMMIT_AUTHOR || undefined;\n    // R2: generic CI env repo URLs can carry credentials too. Any provider we\n    // haven't specifically mapped falls through here; strip defensively.\n    if (!info.repoUrl) {\n      info.repoUrl = this.stripCredentials(env.CI_REPOSITORY_URL || env.REPOSITORY_URL || env.GIT_URL || undefined);\n    }\n  }\n\n  /**\n   * Extract a branch name from a git ref (refs/heads/main → main, refs/tags/v1 → v1)\n   */\n  private extractBranchFromRef(ref: string): string {\n    if (ref.startsWith('refs/heads/')) return ref.slice('refs/heads/'.length);\n    if (ref.startsWith('refs/tags/')) return ref.slice('refs/tags/'.length);\n    return ref;\n  }\n\n  /**\n   * Strip the gitlab-ci-token credentials from a GitLab repository URL\n   */\n  private cleanGitLabUrl(url: string): string {\n    try {\n      const urlObj = new URL(url);\n      urlObj.username = '';\n      urlObj.password = '';\n      return urlObj.toString();\n    } catch {\n      return url.replace(/gitlab-ci-token:[^@]+@/, '');\n    }\n  }\n\n  /**\n   * Resolve the CircleCI project's host origin (https://<host>). Returns\n   * undefined when no reliable signal is available so callers can skip\n   * constructing a mislabeled URL rather than defaulting to github.com.\n   */\n  private resolveCircleCIHost(): string | undefined {\n    const { env } = process;\n    const hostByType: Record<string, string> = {\n      github: 'https://github.com',\n      gitlab: 'https://gitlab.com',\n      bitbucket: 'https://bitbucket.org',\n    };\n    if (env.CIRCLE_PROJECT_TYPE) {\n      const host = hostByType[env.CIRCLE_PROJECT_TYPE.toLowerCase()];\n      if (host) return host;\n    }\n    if (env.CIRCLE_PULL_REQUEST) {\n      try {\n        return new URL(env.CIRCLE_PULL_REQUEST).origin;\n      } catch {\n        /* fall through */\n      }\n    }\n    return undefined;\n  }\n\n  /**\n   * Normalize a CircleCI repository URL: SSH → HTTPS, strip creds and .git\n   */\n  private cleanCircleCIUrl(url: string): string {\n    if (!url) return '';\n\n    try {\n      if (url.startsWith('git@')) {\n        const sshMatch = url.match(/git@([^:]+):([^/]+)\\/(.+?)(?:\\.git)?$/);\n        if (sshMatch && sshMatch.length >= 4) {\n          const [, host, user, repo] = sshMatch;\n          return `https://${host}/${user}/${repo}`;\n        }\n      }\n\n      const urlObj = new URL(url);\n      urlObj.username = '';\n      urlObj.password = '';\n      if (urlObj.pathname.endsWith('.git')) {\n        urlObj.pathname = urlObj.pathname.slice(0, -4);\n      }\n      return urlObj.toString();\n    } catch {\n      try {\n        return url\n          .replace(/^git@([^:]+):/, 'https://$1/')\n          .replace(/\\.git$/, '')\n          .replace(/\\/+$/, '');\n      } catch {\n        return url;\n      }\n    }\n  }\n\n  /**\n   * Convert an AWS CodeCommit clone URL to its AWS Console repository URL\n   */\n  private convertCodeCommitToConsoleUrl(url: string): string {\n    if (!url) return '';\n\n    try {\n      const match = url.match(/git-codecommit\\.([^.]+)\\.amazonaws\\.com\\/v1\\/repos\\/(.+?)(?:\\.git)?$/);\n      if (match?.[1] && match[2]) {\n        const region = match[1];\n        const repoName = match[2];\n        return `https://${region}.console.aws.amazon.com/codesuite/codecommit/repositories/${repoName}`;\n      }\n    } catch {\n      // Fall through to returning the original URL\n    }\n\n    return url;\n  }\n\n  /**\n   * Generic credential-stripping for any URL that flows into `run:begin`.\n   * Every user-visible URL emitted to ingestion (repository.url, pr.url) MUST\n   * go through this — provider env vars routinely embed short-lived tokens\n   * (Jenkins `GIT_URL`, Bitbucket `BITBUCKET_GIT_HTTP_ORIGIN`, Azure DevOps\n   * `SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI`, and even the local\n   * `git config remote.origin.url` when a dev clones with basic auth).\n   * Persisted verbatim, those tokens live forever in ingestion JSONB and\n   * render on the dashboard.\n   *\n   * The provider-specific cleaners (cleanGitLabUrl, cleanCircleCIUrl,\n   * cleanAzureDevOpsUrl) still exist for provider-specific normalization\n   * (SSH→HTTPS, .git-suffix stripping, ci-token regex fallback); they call\n   * this as their credential-stripping primitive.\n   */\n  private stripCredentials(url: string | undefined): string | undefined {\n    if (!url) return url;\n    try {\n      const parsed = new URL(url);\n      parsed.username = '';\n      parsed.password = '';\n      return parsed.toString();\n    } catch {\n      // Not a URL we can parse — fall back to a defensive substring strip\n      // (protocol://user:pass@ → protocol://). Refuses to run on git@ SSH\n      // shorthand (no creds to strip there anyway).\n      return url.replace(/^([a-z][a-z0-9+.-]*):\\/\\/[^/@\\s]*@/i, '$1://');\n    }\n  }\n\n  /**\n   * Strip credentials from an Azure DevOps repository URL (keeps encoding intact)\n   */\n  private cleanAzureDevOpsUrl(url: string): string {\n    if (!url) return '';\n\n    try {\n      const urlObj = new URL(url);\n      urlObj.username = '';\n      urlObj.password = '';\n      return urlObj.toString();\n    } catch {\n      try {\n        return url.replace(/\\/\\/[^@]+@/, '//');\n      } catch {\n        return url;\n      }\n    }\n  }\n\n  /**\n   * Read and parse the GitHub Actions event file\n   */\n  private async readGitHubEventFile(): Promise<GitHubEventData | undefined> {\n    const eventPath = process.env.GITHUB_EVENT_PATH;\n    if (!eventPath) return undefined;\n\n    if (!isAbsolute(normalize(eventPath))) {\n      console.warn('⚠️  TestDino: GITHUB_EVENT_PATH is not an absolute path, skipping');\n      return undefined;\n    }\n\n    try {\n      const content = await this.withTimeout(\n        readFile(eventPath, 'utf-8'),\n        this.options.timeout,\n        'GitHub event file read'\n      );\n      return this.safeJsonParse<GitHubEventData>(content, {});\n    } catch (error) {\n      console.warn(\n        '⚠️  TestDino: Failed to read GitHub event data:',\n        error instanceof Error ? error.message : String(error)\n      );\n      return undefined;\n    }\n  }\n\n  /**\n   * Extract PR metadata from GitHub event data\n   */\n  private extractPRMetadata(eventData: GitHubEventData): PRMetadata | undefined {\n    const pullRequest = eventData?.pull_request;\n    if (!pullRequest) return undefined;\n\n    const prMetadata: PRMetadata = {};\n\n    // Basic PR information\n    if (this.isNonEmptyString(pullRequest.title)) {\n      prMetadata.title = pullRequest.title;\n    }\n\n    if (typeof pullRequest.number === 'number') {\n      prMetadata.number = pullRequest.number;\n    }\n\n    if (this.isNonEmptyString(pullRequest.state)) {\n      prMetadata.status = pullRequest.state;\n    }\n\n    // Build PR URL\n    const serverUrl = process.env.GITHUB_SERVER_URL;\n    const repository = process.env.GITHUB_REPOSITORY;\n    if (prMetadata.number && serverUrl && repository) {\n      prMetadata.url = `${serverUrl}/${repository}/pull/${prMetadata.number}`;\n    }\n\n    // Branch information\n    if (pullRequest.head?.ref && this.isNonEmptyString(pullRequest.head.ref)) {\n      prMetadata.branch = pullRequest.head.ref;\n    }\n\n    if (pullRequest.base?.ref && this.isNonEmptyString(pullRequest.base.ref)) {\n      prMetadata.targetBranch = pullRequest.base.ref;\n    }\n\n    // Author information\n    if (pullRequest.user?.login && this.isNonEmptyString(pullRequest.user.login)) {\n      prMetadata.author = pullRequest.user.login;\n    }\n\n    // Labels\n    if (Array.isArray(pullRequest.labels) && pullRequest.labels.length > 0) {\n      const labels = pullRequest.labels\n        .map((label) => label?.name)\n        .filter((name): name is string => this.isNonEmptyString(name));\n\n      if (labels.length > 0) {\n        prMetadata.labels = labels;\n      }\n    }\n\n    // Merge status\n    if (typeof pullRequest.merged === 'boolean') {\n      prMetadata.merged = pullRequest.merged;\n    }\n\n    if (typeof pullRequest.mergeable === 'boolean') {\n      prMetadata.mergeable = pullRequest.mergeable;\n    }\n\n    if (this.isNonEmptyString(pullRequest.merge_commit_sha)) {\n      prMetadata.mergeCommitSha = pullRequest.merge_commit_sha;\n    }\n\n    // Return undefined if no meaningful data was extracted\n    const hasData = Object.keys(prMetadata).length > 0;\n    return hasData ? prMetadata : undefined;\n  }\n\n  /**\n   * Get commit details for a specific SHA using git show\n   * Used to resolve real commit data in PR context (instead of merge commit)\n   */\n  private async getCommitInfoFromSha(sha: string): Promise<\n    | {\n        message?: string;\n        author?: string;\n        email?: string;\n        timestamp?: string;\n      }\n    | undefined\n  > {\n    try {\n      const result = await this.execGit(['show', '-s', '--format=%s%n%an%n%ae%n%aI', sha]);\n      const lines = result.split('\\n');\n      if (lines.length < 4) return undefined;\n\n      return {\n        message: this.isNonEmptyString(lines[0]) ? lines[0] : undefined,\n        author: this.isNonEmptyString(lines[1]) ? lines[1] : undefined,\n        email: this.isNonEmptyString(lines[2]) ? lines[2] : undefined,\n        timestamp: this.isNonEmptyString(lines[3]) ? lines[3] : undefined,\n      };\n    } catch (error) {\n      console.warn(\n        '⚠️  TestDino: Failed to get commit info from SHA:',\n        error instanceof Error ? error.message : String(error)\n      );\n      return undefined;\n    }\n  }\n\n  /**\n   * Resolve GitHub author info via the Commits API.\n   * Only runs on GitHub Actions where GITHUB_REPOSITORY is available.\n   *\n   * R3 (2026-07-04): honours GITHUB_API_URL (set by both public GitHub Actions\n   * and GitHub Enterprise Server Actions). GITHUB_TOKEN is forwarded ONLY to\n   * that same host — a GHES token must never be sent to api.github.com.\n   * Users can disable the whole lookup with\n   * TESTDINO_DISABLE_GITHUB_AUTHOR_LOOKUP=true.\n   */\n  private async resolveGitHubAuthor(commitHash: string | undefined): Promise<GitHubAuthorInfo> {\n    const empty: GitHubAuthorInfo = { authorId: '' };\n\n    if (this.isGitHubAuthorLookupDisabled()) return empty;\n    if (process.env.GITHUB_ACTIONS !== 'true') return empty;\n    if (!commitHash) return empty;\n\n    const repository = process.env.GITHUB_REPOSITORY;\n    if (!repository) return empty;\n\n    const apiBase = this.resolveGitHubApiBase();\n    const url = `${apiBase}/repos/${repository}/commits/${commitHash}`;\n\n    try {\n      const response = await this.withTimeout(\n        fetch(url, { headers: this.buildGitHubHeaders(apiBase) }),\n        this.options.timeout,\n        'GitHub Commits API'\n      );\n\n      if (!response.ok) {\n        return empty;\n      }\n\n      const data = (await response.json()) as {\n        author?: { id?: number; login?: string } | null;\n      };\n\n      if (data?.author?.id) {\n        const authorId = String(data.author.id);\n        const authorLogin = this.isNonEmptyString(data.author.login) ? data.author.login : undefined;\n        return { authorId, authorLogin, fromCommit: true };\n      }\n\n      return this.resolveGitHubAuthorFromActor();\n    } catch (error) {\n      console.warn(\n        '⚠️  TestDino: Failed to resolve GitHub author from Commits API:',\n        error instanceof Error ? error.message : String(error)\n      );\n      return this.resolveGitHubAuthorFromActor();\n    }\n  }\n\n  /**\n   * True when the user opted out of remote author lookup entirely.\n   * Honours TESTDINO_DISABLE_GITHUB_AUTHOR_LOOKUP = '1' | 'true' (case-insensitive).\n   */\n  private isGitHubAuthorLookupDisabled(): boolean {\n    const raw = process.env.TESTDINO_DISABLE_GITHUB_AUTHOR_LOOKUP;\n    if (!raw) return false;\n    const v = raw.toLowerCase();\n    return v === '1' || v === 'true';\n  }\n\n  /**\n   * Resolve the GitHub API base URL. GitHub Actions on public GitHub sets\n   * GITHUB_API_URL to https://api.github.com; on GitHub Enterprise Server it\n   * sets the enterprise host (e.g. https://api.github.acme.com). Falling back\n   * to the hard-coded public URL would silently break GHES author resolution\n   * AND (with GITHUB_TOKEN forwarded unconditionally) leak the enterprise\n   * bearer to a third-party host. Trailing slash trimmed.\n   */\n  private resolveGitHubApiBase(): string {\n    const raw = process.env.GITHUB_API_URL;\n    if (this.isNonEmptyString(raw)) {\n      return raw.replace(/\\/+$/, '');\n    }\n    return 'https://api.github.com';\n  }\n\n  /**\n   * Build the GitHub API request headers. Authorization is attached ONLY when\n   * the token is being sent to the same host GITHUB_API_URL resolves to — this\n   * is the defense-in-depth guard on top of resolveGitHubApiBase(): even if a\n   * misconfiguration leaves apiBase pointing at api.github.com on a GHES\n   * runner, we won't forward the (unrelated) GHES token to it.\n   */\n  private buildGitHubHeaders(apiBase: string): Record<string, string> {\n    const headers: Record<string, string> = {\n      Accept: 'application/vnd.github.v3+json',\n      'User-Agent': 'testdino-playwright',\n    };\n    const token = process.env.GITHUB_TOKEN;\n    if (!token) return headers;\n    try {\n      const apiHost = new URL(apiBase).hostname.toLowerCase();\n      const rawApiUrl = process.env.GITHUB_API_URL;\n      const envHost = this.isNonEmptyString(rawApiUrl) ? new URL(rawApiUrl).hostname.toLowerCase() : 'api.github.com';\n      if (apiHost === envHost) {\n        headers.Authorization = `token ${token}`;\n      }\n    } catch {\n      // If either URL is malformed, err on the safe side: no Authorization.\n    }\n    return headers;\n  }\n\n  /**\n   * Fallback: resolve GitHub author info from GITHUB_ACTOR via the Users API.\n   * Uses the same GITHUB_API_URL + token-scope guard as resolveGitHubAuthor (R3).\n   */\n  private async resolveGitHubAuthorFromActor(): Promise<GitHubAuthorInfo> {\n    if (this.isGitHubAuthorLookupDisabled()) return { authorId: '' };\n    const actor = process.env.GITHUB_ACTOR;\n    if (!actor) {\n      return { authorId: '' };\n    }\n\n    const apiBase = this.resolveGitHubApiBase();\n    const url = `${apiBase}/users/${actor}`;\n\n    try {\n      const response = await this.withTimeout(\n        fetch(url, { headers: this.buildGitHubHeaders(apiBase) }),\n        this.options.timeout,\n        'GitHub Users API'\n      );\n\n      if (!response.ok) {\n        return { authorId: '' };\n      }\n\n      const data = (await response.json()) as {\n        id?: number;\n        login?: string;\n      };\n\n      const authorId = data?.id ? String(data.id) : '';\n      const authorLogin = this.isNonEmptyString(data?.login) ? data.login : actor;\n\n      return { authorId, authorLogin };\n    } catch (error) {\n      console.warn(\n        '⚠️  TestDino: Failed to resolve GitHub author from GITHUB_ACTOR:',\n        error instanceof Error ? error.message : String(error)\n      );\n      return { authorId: '' };\n    }\n  }\n\n  /**\n   * Check if current directory is a git repository\n   */\n  private async isGitRepository(): Promise<boolean> {\n    try {\n      await this.execGit(['rev-parse', '--git-dir']);\n      return true;\n    } catch {\n      return false;\n    }\n  }\n\n  /**\n   * Get current branch name\n   * Uses: git rev-parse --abbrev-ref HEAD\n   */\n  private async getBranch(): Promise<string | undefined> {\n    try {\n      const result = await this.execGit(['rev-parse', '--abbrev-ref', 'HEAD']);\n      return this.isNonEmptyString(result) ? result : undefined;\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Get current commit hash (full SHA)\n   * Uses: git rev-parse HEAD\n   */\n  private async getCommitHash(): Promise<string | undefined> {\n    try {\n      const result = await this.execGit(['rev-parse', 'HEAD']);\n      return this.isNonEmptyString(result) ? result : undefined;\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Get commit message, author name, email, and timestamp in a single git process.\n   * Uses: git log -1 --pretty=format:%s%n%an%n%ae%n%aI\n   */\n  private async getCommitInfo(): Promise<\n    { message?: string; author?: string; email?: string; timestamp?: string } | undefined\n  > {\n    try {\n      const result = await this.execGit(['log', '-1', '--pretty=format:%s%n%an%n%ae%n%aI']);\n      const lines = result.split('\\n');\n      if (lines.length < 4) return undefined;\n\n      return {\n        message: this.isNonEmptyString(lines[0]) ? lines[0] : undefined,\n        author: this.isNonEmptyString(lines[1]) ? lines[1] : undefined,\n        email: this.isNonEmptyString(lines[2]) ? lines[2] : undefined,\n        timestamp: this.isNonEmptyString(lines[3]) ? lines[3] : undefined,\n      };\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Get remote origin URL\n   * Uses: git config --get remote.origin.url\n   */\n  private async getRepoUrl(): Promise<string | undefined> {\n    try {\n      const result = await this.execGit(['config', '--get', 'remote.origin.url']);\n      if (!this.isNonEmptyString(result)) return undefined;\n      // R1: dev/CI clones with credentials embedded — e.g.\n      // https://user:ghp_XXX@github.com/org/repo.git — get baked into\n      // git config remote.origin.url. Strip before returning so the\n      // token never reaches ingestion / the dashboard.\n      return this.stripCredentials(result);\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Check if working tree has uncommitted changes\n   * Uses: git status --porcelain\n   * Returns true if there are any changes (staged, unstaged, or untracked)\n   */\n  private async isDirtyWorkingTree(): Promise<boolean | undefined> {\n    try {\n      const result = await this.execGit(['status', '--porcelain']);\n      // If output is non-empty, there are changes\n      return result.trim().length > 0;\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Extract repository name from remote URL\n   * e.g., \"https://github.com/user/repo.git\" → \"repo\"\n   */\n  private extractRepoName(repoUrl: string | undefined): string | undefined {\n    if (!repoUrl) return undefined;\n    return repoUrl.split('/').pop()?.replace('.git', '') || undefined;\n  }\n\n  /**\n   * Execute git command with timeout.\n   *\n   * `-c safe.directory=<cwd>` is prepended in CI so a workspace mounted with\n   * different ownership (a common Docker / GitHub-Actions runner shape)\n   * doesn't trigger the dubious-ownership refusal. `-c` is per-invocation and\n   * writes NOTHING to `~/.gitconfig` — safe on shared runners.\n   */\n  private async execGit(args: string[]): Promise<string> {\n    const execa = await getExeca();\n    const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';\n    const finalArgs = isCI ? ['-c', `safe.directory=${this.options.cwd}`, ...args] : args;\n    const { stdout } = await execa('git', finalArgs, {\n      cwd: this.options.cwd,\n      timeout: this.options.timeout,\n      reject: true,\n    });\n\n    return stdout.trim();\n  }\n}\n","import { relative } from 'path';\n\nexport function normalizePath(filePath: string, rootDir?: string): string {\n  if (rootDir) {\n    // Strip trailing slash so boundary check uses consistent form\n    const root = rootDir.endsWith('/') ? rootDir.slice(0, -1) : rootDir;\n    if (filePath === root || filePath.startsWith(`${root}/`)) {\n      return relative(root, filePath);\n    }\n  }\n  return filePath;\n}\n\nexport function sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function isDebugEnabled(): boolean {\n  return process.env.TESTDINO_DEBUG === 'true' || process.env.TESTDINO_DEBUG === '1';\n}\n\n/** Settles with `fallback` after `ms`; clears its timer so it never holds the process open. */\nexport async function waitAtMost<T, F>(promise: Promise<T>, ms: number, fallback: F): Promise<T | F> {\n  let timer: ReturnType<typeof setTimeout> | undefined;\n  const late = new Promise<F>((resolve) => {\n    timer = setTimeout(() => resolve(fallback), ms);\n  });\n  try {\n    return await Promise.race([promise, late]);\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, operation: string): Promise<T> {\n  let timer: ReturnType<typeof setTimeout> | undefined;\n  const timeoutPromise = new Promise<never>((_, reject) => {\n    timer = setTimeout(() => reject(new Error(`${operation} timed out after ${timeoutMs}ms`)), timeoutMs);\n  });\n  try {\n    return await Promise.race([promise, timeoutPromise]);\n  } finally {\n    clearTimeout(timer);\n  }\n}\n","import type { MetadataCollector, MetadataCollectionResult } from './types.js';\nimport { withTimeout as withTimeoutUtil } from '../utils/index.js';\n\nexport abstract class BaseMetadataCollector<T = Record<string, unknown>> implements MetadataCollector<T> {\n  protected name: string;\n\n  constructor(name: string) {\n    this.name = name;\n  }\n\n  getName(): string {\n    return this.name;\n  }\n\n  async collect(): Promise<T> {\n    const result = await this.collectWithResult();\n    return result.data;\n  }\n\n  async collectWithResult(): Promise<MetadataCollectionResult<T>> {\n    const startTime = Date.now();\n    const collector = this.getName();\n\n    try {\n      const data = await this.collectMetadata();\n      return {\n        data,\n        success: true,\n        duration: Date.now() - startTime,\n        collector,\n      };\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      console.warn(`⚠️  TestDino: ${collector} metadata collection failed:`, errorMessage);\n      return {\n        data: this.getEmptyMetadata(),\n        success: false,\n        error: errorMessage,\n        duration: Date.now() - startTime,\n        collector,\n      };\n    }\n  }\n\n  protected abstract collectMetadata(): Promise<T>;\n  protected abstract getEmptyMetadata(): T;\n\n  protected async withTimeout<R>(promise: Promise<R>, timeoutMs: number, operation: string): Promise<R> {\n    return withTimeoutUtil(promise, timeoutMs, operation);\n  }\n\n  protected safeJsonParse<R>(jsonString: string, fallback: R): R {\n    try {\n      return JSON.parse(jsonString);\n    } catch {\n      return fallback;\n    }\n  }\n\n  protected isNonEmptyString(value: unknown): value is string {\n    return typeof value === 'string' && value.trim().length > 0;\n  }\n}\n","/**\n * Shared CI provider detection.\n *\n * Single source of truth for both the CI and Git metadata collectors so they\n * can never disagree on which provider a run belongs to. Order matches\n * testdino-cli so the same run maps to the same provider regardless of which\n * CLI produced it.\n */\n\n/**\n * Detect the CI provider from environment variables, or `undefined` when not\n * running under a recognized provider (i.e. a local run).\n */\nexport function detectCIProvider(): string | undefined {\n  const { env } = process;\n\n  if (env.GITHUB_ACTIONS === 'true') return 'github-actions';\n  if (env.GITLAB_CI === 'true') return 'gitlab-ci';\n  if (env.JENKINS_URL) return 'jenkins';\n  if (env.TF_BUILD === 'True' || env.AZURE_HTTP_USER_AGENT) return 'azure-devops';\n  if (env.CIRCLECI === 'true') return 'circleci';\n  if (env.CODEBUILD_BUILD_ID) return 'aws-codebuild';\n  if (env.BITBUCKET_BUILD_NUMBER) return 'bitbucket-pipelines';\n  if (env.BUILDKITE === 'true') return 'buildkite';\n  if (env.HARNESS_BUILD_ID || env.HARNESS_PIPELINE_ID) return 'harness';\n  if (env.TEAMCITY_VERSION) return 'teamcity';\n\n  return undefined;\n}\n","/**\n * CI metadata collector\n *\n * Collects CI/CD environment information across the major providers. Detection\n * mirrors the standalone testdino-cli precedence so a run reports the same\n * provider regardless of which CLI produced it.\n *\n * Provider env var references:\n * - GitHub Actions: https://docs.github.com/en/actions/reference/workflows-and-actions/variables\n * - GitLab CI:      https://docs.gitlab.com/ci/variables/predefined_variables/\n * - CircleCI:       https://circleci.com/docs/reference/variables/\n * - Jenkins:        https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables\n * - Azure DevOps:   https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables\n * - AWS CodeBuild:  https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html\n * - Bitbucket:      https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/\n * - Buildkite:      https://buildkite.com/docs/pipelines/configure/environment-variables\n * - Harness:        https://developer.harness.io/docs/platform/variables-and-expressions/harness-variables/\n */\n\nimport { type as osType, release as osRelease } from 'os';\nimport { BaseMetadataCollector } from './base.js';\nimport { detectCIProvider } from './detect-ci-provider.js';\nimport type { CIMetadata, GitMetadata, PRMetadata } from './types.js';\n\n/**\n * Provider-specific pipeline + build slice. Environment info is collected once\n * and shared, so providers only resolve the fields that differ between them.\n */\ntype ProviderMetadata = Pick<CIMetadata, 'pipeline' | 'build'>;\n\n/**\n * Collects CI environment metadata\n */\nexport class CIMetadataCollector extends BaseMetadataCollector<CIMetadata> {\n  constructor() {\n    super('ci');\n  }\n\n  /**\n   * Collect CI metadata\n   */\n  protected async collectMetadata(): Promise<CIMetadata> {\n    const provider = detectCIProvider();\n\n    if (!provider) {\n      return {\n        provider: 'local',\n        environment: this.collectEnvironment(),\n      };\n    }\n\n    const { pipeline, build } = this.getProviderMetadata(provider);\n\n    return {\n      provider,\n      pipeline,\n      build,\n      environment: this.collectEnvironment(),\n    };\n  }\n\n  /**\n   * Get empty metadata\n   */\n  protected getEmptyMetadata(): CIMetadata {\n    return {};\n  }\n\n  /**\n   * Route to the provider-specific pipeline/build extractor\n   */\n  private getProviderMetadata(provider: string): ProviderMetadata {\n    switch (provider) {\n      case 'github-actions':\n        return this.getGitHubActionsMetadata();\n      case 'gitlab-ci':\n        return this.getGitLabCIMetadata();\n      case 'circleci':\n        return this.getCircleCIMetadata();\n      case 'jenkins':\n        return this.getJenkinsMetadata();\n      case 'azure-devops':\n        return this.getAzureDevOpsMetadata();\n      case 'aws-codebuild':\n        return this.getAWSCodeBuildMetadata();\n      case 'bitbucket-pipelines':\n        return this.getBitbucketPipelinesMetadata();\n      case 'buildkite':\n        return this.getBuildkiteMetadata();\n      case 'harness':\n        return this.getHarnessMetadata();\n      default:\n        return this.getGenericMetadata();\n    }\n  }\n\n  /**\n   * GitHub Actions pipeline + build\n   */\n  private getGitHubActionsMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.GITHUB_RUN_ID,\n        name: env.GITHUB_WORKFLOW,\n        url: this.buildGitHubPipelineUrl(),\n        attempt: parseRunAttempt(env.GITHUB_RUN_ATTEMPT),\n      },\n      build: {\n        number: env.GITHUB_RUN_NUMBER,\n        trigger: env.GITHUB_EVENT_NAME,\n        // GITHUB_ACTOR stays the first attempt's initiator on a re-run.\n        actor: env.GITHUB_TRIGGERING_ACTOR || env.GITHUB_ACTOR,\n      },\n    };\n  }\n\n  /**\n   * Build the GitHub Actions pipeline URL when all parts are present\n   */\n  private buildGitHubPipelineUrl(): string | undefined {\n    const { env } = process;\n    const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;\n\n    if (GITHUB_SERVER_URL && GITHUB_REPOSITORY && GITHUB_RUN_ID) {\n      return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;\n    }\n\n    return undefined;\n  }\n\n  /**\n   * GitLab CI pipeline + build\n   */\n  private getGitLabCIMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.CI_PIPELINE_ID,\n        name: this.getGitLabPipelineName(),\n        url: env.CI_PIPELINE_URL,\n      },\n      build: {\n        number: env.CI_JOB_ID || env.CI_PIPELINE_IID,\n        trigger: env.CI_PIPELINE_SOURCE,\n        actor: env.GITLAB_USER_NAME || env.GITLAB_USER_LOGIN,\n      },\n    };\n  }\n\n  /**\n   * Derive a human-readable GitLab pipeline name\n   */\n  private getGitLabPipelineName(): string | undefined {\n    const { CI_PIPELINE_SOURCE, CI_COMMIT_TITLE, CI_PIPELINE_NAME } = process.env;\n\n    if (CI_PIPELINE_SOURCE) return `${CI_PIPELINE_SOURCE} pipeline`;\n\n    return CI_COMMIT_TITLE || CI_PIPELINE_NAME || undefined;\n  }\n\n  /**\n   * CircleCI pipeline + build\n   */\n  private getCircleCIMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.CIRCLE_PIPELINE_ID || env.CIRCLE_BUILD_NUM,\n        name: env.CIRCLE_JOB,\n        url: env.CIRCLE_BUILD_URL,\n      },\n      build: {\n        number: env.CIRCLE_BUILD_NUM,\n        trigger: this.getCircleCIBuildTrigger(),\n      },\n    };\n  }\n\n  /**\n   * Determine CircleCI build trigger from available env vars\n   */\n  private getCircleCIBuildTrigger(): string {\n    const { env } = process;\n\n    if (env.CIRCLE_TAG) return 'tag';\n    if (env.CIRCLE_PR_NUMBER || env.CIRCLE_PULL_REQUEST) return 'pr';\n\n    return 'push';\n  }\n\n  /**\n   * Jenkins pipeline + build\n   */\n  private getJenkinsMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.BUILD_ID,\n        name: env.JOB_NAME,\n        url: env.BUILD_URL,\n      },\n      build: {\n        number: env.BUILD_NUMBER,\n        trigger: this.getJenkinsBuildTrigger(),\n      },\n    };\n  }\n\n  /**\n   * Jenkins doesn't expose a single BUILD_CAUSE env var — it exposes each cause\n   * as a separate boolean (BUILD_CAUSE_MANUALTRIGGER, BUILD_CAUSE_SCMTRIGGER,\n   * etc.) that the Groovy env-vars plugin sets. Prefer these; fall back to the\n   * legacy BUILD_CAUSE if a customer sets it manually in their pipeline.\n   */\n  private getJenkinsBuildTrigger(): string | undefined {\n    const { env } = process;\n\n    if (env.BUILD_CAUSE_MANUALTRIGGER === 'true') return 'manual';\n    if (env.BUILD_CAUSE_SCMTRIGGER === 'true') return 'push';\n    if (env.BUILD_CAUSE_TIMERTRIGGER === 'true') return 'scheduled';\n    if (env.BUILD_CAUSE_UPSTREAMTRIGGER === 'true') return 'upstream';\n    if (env.BUILD_CAUSE_REMOTECAUSE === 'true') return 'remote';\n\n    return env.BUILD_CAUSE;\n  }\n\n  /**\n   * Azure DevOps pipeline + build\n   */\n  private getAzureDevOpsMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.BUILD_BUILDID,\n        name: env.BUILD_DEFINITIONNAME,\n        url: this.buildAzureDevOpsPipelineUrl(),\n      },\n      build: {\n        number: env.BUILD_BUILDNUMBER,\n        trigger: env.BUILD_REASON,\n        actor: env.BUILD_REQUESTEDFOR,\n      },\n    };\n  }\n\n  /**\n   * Construct the Azure DevOps build-results URL when all parts are present\n   */\n  private buildAzureDevOpsPipelineUrl(): string | undefined {\n    const { SYSTEM_TEAMFOUNDATIONSERVERURI, SYSTEM_TEAMPROJECT, BUILD_BUILDID } = process.env;\n\n    if (!SYSTEM_TEAMFOUNDATIONSERVERURI || !SYSTEM_TEAMPROJECT || !BUILD_BUILDID) {\n      return undefined;\n    }\n\n    try {\n      const baseUrl = SYSTEM_TEAMFOUNDATIONSERVERURI.replace(/\\/$/, '');\n      const encodedProject = encodeURIComponent(SYSTEM_TEAMPROJECT);\n      return `${baseUrl}/${encodedProject}/_build/results?buildId=${BUILD_BUILDID}`;\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * AWS CodeBuild pipeline + build\n   */\n  private getAWSCodeBuildMetadata(): ProviderMetadata {\n    const { env } = process;\n    const buildId = env.CODEBUILD_BUILD_ID || '';\n    // Build ID format is `project-name:build-uuid`\n    const projectName = buildId.split(':')[0] || undefined;\n\n    return {\n      pipeline: {\n        id: env.CODEBUILD_BUILD_ID,\n        name: projectName,\n        url: env.CODEBUILD_BUILD_URL,\n      },\n      build: {\n        number: env.CODEBUILD_BUILD_NUMBER,\n        trigger: this.getAWSCodeBuildTrigger(),\n      },\n    };\n  }\n\n  /**\n   * Determine the AWS CodeBuild trigger from webhook/initiator env vars\n   */\n  private getAWSCodeBuildTrigger(): string | undefined {\n    const { env } = process;\n\n    if (env.CODEBUILD_WEBHOOK_EVENT) return env.CODEBUILD_WEBHOOK_EVENT;\n\n    if (env.CODEBUILD_INITIATOR) {\n      return env.CODEBUILD_INITIATOR.startsWith('codepipeline/') ? 'codepipeline' : 'manual';\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Bitbucket Pipelines pipeline + build\n   */\n  private getBitbucketPipelinesMetadata(): ProviderMetadata {\n    const { env } = process;\n    const { BITBUCKET_WORKSPACE, BITBUCKET_REPO_SLUG, BITBUCKET_BUILD_NUMBER } = env;\n\n    const url =\n      BITBUCKET_WORKSPACE && BITBUCKET_REPO_SLUG && BITBUCKET_BUILD_NUMBER\n        ? `https://bitbucket.org/${BITBUCKET_WORKSPACE}/${BITBUCKET_REPO_SLUG}/pipelines/results/${BITBUCKET_BUILD_NUMBER}`\n        : undefined;\n\n    let trigger = 'push';\n    if (env.BITBUCKET_PR_ID) {\n      trigger = 'pull_request';\n    } else if (env.BITBUCKET_TAG) {\n      trigger = 'tag';\n    }\n\n    return {\n      pipeline: {\n        id: env.BITBUCKET_PIPELINE_UUID,\n        name: 'Bitbucket Pipeline',\n        url,\n      },\n      build: {\n        number: BITBUCKET_BUILD_NUMBER,\n        trigger,\n      },\n    };\n  }\n\n  /**\n   * Buildkite pipeline + build\n   */\n  private getBuildkiteMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.BUILDKITE_PIPELINE_ID || env.BUILDKITE_PIPELINE_SLUG,\n        name: env.BUILDKITE_PIPELINE_NAME || env.BUILDKITE_PIPELINE_SLUG,\n        url: env.BUILDKITE_BUILD_URL,\n      },\n      build: {\n        number: env.BUILDKITE_BUILD_NUMBER,\n        trigger: this.getBuildkiteTrigger(),\n        actor: env.BUILDKITE_BUILD_CREATOR,\n      },\n    };\n  }\n\n  /**\n   * Determine the Buildkite trigger. BUILDKITE_PULL_REQUEST is the PR number or\n   * the literal string 'false' when the build is not for a PR.\n   *\n   * BUILDKITE_SOURCE describes what started the build (webhook, ui, api,\n   * schedule, trigger_job). It's normalized to the same push/manual/scheduled\n   * vocabulary the other providers emit — an ordinary git push arrives as\n   * 'webhook', which would otherwise leak as a trigger value. Unknown sources\n   * pass through so no signal is lost.\n   */\n  private getBuildkiteTrigger(): string {\n    const { env } = process;\n\n    if (env.BUILDKITE_TAG) return 'tag';\n    if (env.BUILDKITE_PULL_REQUEST && env.BUILDKITE_PULL_REQUEST !== 'false') return 'pull_request';\n\n    switch (env.BUILDKITE_SOURCE) {\n      case undefined:\n      case '':\n      case 'webhook':\n        return 'push';\n      case 'ui':\n        return 'manual';\n      case 'schedule':\n        return 'scheduled';\n      default:\n        return env.BUILDKITE_SOURCE;\n    }\n  }\n\n  /**\n   * Harness CI pipeline + build.\n   *\n   * Harness CI is built on Drone and mirrors the documented DRONE_* vars into\n   * the step container; those are the reliable source for build number and\n   * trigger. The HARNESS_* vars carry pipeline identity. The results URL is\n   * account/module-specific and not reliably reconstructable from env, so it is\n   * left undefined. `name` is omitted rather than duplicating the identifier —\n   * Harness exposes no distinct pipeline-name env var.\n   */\n  private getHarnessMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {\n        id: env.HARNESS_PIPELINE_ID,\n      },\n      build: {\n        number: env.HARNESS_BUILD_ID || env.DRONE_BUILD_NUMBER,\n        trigger: this.getHarnessTrigger(),\n      },\n    };\n  }\n\n  /**\n   * Normalize the Harness/Drone build event. Drone emits 'cron' for scheduled\n   * builds; align it with the 'scheduled' vocabulary the other providers use.\n   * Other events (push, pull_request, tag) pass through unchanged.\n   */\n  private getHarnessTrigger(): string | undefined {\n    const event = process.env.DRONE_BUILD_EVENT;\n    if (!event) return undefined;\n    return event === 'cron' ? 'scheduled' : event;\n  }\n\n  /**\n   * Fallback for a detected-but-unmapped CI provider.\n   *\n   * Kept intentionally narrow: only reads env vars that are truly widely-shared\n   * across generic CI images (CI_BUILD_NUMBER, BUILD_NUMBER). Does NOT leak\n   * GitLab-specific vars (CI_PIPELINE_ID / CI_PIPELINE_NAME / CI_PIPELINE_URL /\n   * CI_PIPELINE_SOURCE), which would falsely attribute an unknown provider's\n   * run to GitLab semantics in the dashboard.\n   */\n  private getGenericMetadata(): ProviderMetadata {\n    const { env } = process;\n\n    return {\n      pipeline: {},\n      build: {\n        number: env.CI_BUILD_NUMBER || env.BUILD_NUMBER,\n      },\n    };\n  }\n\n  /**\n   * Collect runner environment information\n   */\n  private collectEnvironment(): CIMetadata['environment'] {\n    try {\n      return {\n        name: osType(),\n        type: process.platform,\n        os: `${osType()} ${osRelease()}`,\n        node: process.version,\n      };\n    } catch {\n      return {};\n    }\n  }\n\n  /**\n   * Whether the person who started the run wrote the commit, from evidence only\n   * (an account login or matching emails); left unset when the provider cannot tell.\n   */\n  static resolveActorIsAuthor(ci: CIMetadata, git: GitMetadata): void {\n    const verifiedLogin = git.commit?.verifiedLogin;\n    if (git.commit) delete git.commit.verifiedLogin;\n\n    const actor = ci.build?.actor;\n    if (!ci.build || !actor) return;\n\n    const { env } = process;\n    const commitEmail = git.commit?.email;\n    const sameEmail = (a?: string, b?: string): boolean | undefined =>\n      a && b ? a.toLowerCase() === b.toLowerCase() : undefined;\n\n    let result: boolean | undefined;\n    switch (ci.provider) {\n      case 'github-actions':\n        result = verifiedLogin\n          ? verifiedLogin.toLowerCase() === actor.toLowerCase()\n          : CIMetadataCollector.isNoreplyEmailOf(commitEmail, actor) || undefined;\n        break;\n      case 'gitlab-ci':\n        result = sameEmail(env.GITLAB_USER_EMAIL, commitEmail);\n        break;\n      case 'azure-devops':\n        result = sameEmail(env.BUILD_REQUESTEDFOREMAIL, commitEmail);\n        break;\n      case 'buildkite':\n        result = sameEmail(env.BUILDKITE_BUILD_CREATOR_EMAIL, env.BUILDKITE_BUILD_AUTHOR_EMAIL || commitEmail);\n        break;\n    }\n    if (result !== undefined) ci.build.actorIsAuthor = result;\n  }\n\n  // GitHub's `{id}+{login}@users.noreply.github.com` (or the older `{login}@...`) belongs to that login.\n  private static isNoreplyEmailOf(email: string | undefined, login: string): boolean {\n    if (!email) return false;\n    const match = /^(?:\\d+\\+)?([^@]+)@users\\.noreply\\.github\\.com$/i.exec(email);\n    return match !== null && match[1].toLowerCase() === login.toLowerCase();\n  }\n\n  /**\n   * Reconcile CI and Git metadata after both collectors complete.\n   *\n   * Bitbucket Pipelines runs that fire on the target branch after a PR merge do\n   * not expose `BITBUCKET_PR_ID`, so env-only detection reports `push`. The\n   * auto-merge commit subject (`Merged in <branch> (pull request #N)`) is the\n   * reliable signal that the push originated from a PR — when present we surface\n   * the run as a `pull_request` trigger and backfill PR number/url/status/title.\n   *\n   * No-op for every other provider.\n   */\n  static reconcileWithGit(ci: CIMetadata, git: GitMetadata): void {\n    if (ci.provider !== 'bitbucket-pipelines') return;\n    if (ci.build?.trigger !== 'push') return;\n\n    const message = git.commit?.message || '';\n    // Anchored to Bitbucket's auto-merge subject so we don't false-positive on\n    // commits that merely quote the phrase (e.g. `Revert \"Merged in ...\"`).\n    const match = message.match(/^Merged in [^\\n]+\\(pull request #(\\d+)\\)/i);\n    const prId = match?.[1];\n    if (!prId) return;\n\n    if (ci.build) ci.build.trigger = 'pull_request';\n\n    const pr: PRMetadata = git.pr ?? {};\n\n    if (pr.number === undefined) {\n      pr.number = Number(prId);\n      if (git.repository?.url) {\n        const base = git.repository.url.replace(/\\.git$/, '').replace(/\\/$/, '');\n        pr.url = `${base}/pull-requests/${prId}`;\n      }\n      pr.status = 'merged';\n      pr.merged = true;\n    }\n\n    // The auto-merge subject is the only place the PR title lives for post-merge\n    // runs; use it when nothing better is available.\n    if (!pr.title) {\n      const subject = message.split('\\n')[0]?.trim();\n      if (subject) pr.title = subject;\n    }\n\n    git.pr = pr;\n  }\n}\n\n// The server reads only a positive integer, so anything else is omitted.\nexport function parseRunAttempt(value: string | undefined): number | undefined {\n  return value !== undefined && /^[1-9]\\d*$/.test(value) ? Number(value) : undefined;\n}\n","import { platform, release, cpus, totalmem, hostname } from 'os';\nimport { version } from 'process';\nimport { BaseMetadataCollector } from './base.js';\nimport { getPackageVersion, UNRESOLVED_VERSION } from '../utils/package-version.js';\nimport type { SystemMetadata } from './types.js';\n\nexport class SystemMetadataCollector extends BaseMetadataCollector<SystemMetadata> {\n  constructor() {\n    super('system');\n  }\n\n  protected async collectMetadata(): Promise<SystemMetadata> {\n    return {\n      os: this.getOperatingSystem(),\n      cpu: this.getCpuInfo(),\n      memory: this.getMemoryInfo(),\n      nodeVersion: this.getNodeVersion(),\n      platform: this.getPlatform(),\n      hostname: this.getHostname(),\n      ...this.getReporterVersion(),\n      launcher: process.env.TESTDINO_CLI_CONFIG_PATH ? 'tdpw' : 'playwright',\n    };\n  }\n\n  // An unreadable package.json yields the sentinel, which must not be stored as if\n  // it were a published version.\n  private getReporterVersion(): Pick<SystemMetadata, 'reporterVersion'> {\n    const version = getPackageVersion();\n    return version === UNRESOLVED_VERSION ? {} : { reporterVersion: version };\n  }\n\n  protected getEmptyMetadata(): SystemMetadata {\n    return {};\n  }\n\n  private getOperatingSystem(): string {\n    let platformName = 'unknown';\n    let releaseVersion = 'unknown';\n    try {\n      platformName = platform();\n    } catch {\n      /* keep default */\n    }\n    try {\n      releaseVersion = release();\n    } catch {\n      /* keep default */\n    }\n    return `${platformName} ${releaseVersion}`;\n  }\n\n  private getCpuInfo(): string {\n    try {\n      const cpuList = cpus();\n      if (cpuList.length === 0) return 'unknown';\n      return `${cpuList[0].model.trim()} (${cpuList.length} cores)`;\n    } catch {\n      return 'unknown';\n    }\n  }\n\n  private getMemoryInfo(): string {\n    try {\n      return `${(totalmem() / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n    } catch {\n      return 'unknown';\n    }\n  }\n\n  private getNodeVersion(): string {\n    try {\n      return version;\n    } catch {\n      return 'unknown';\n    }\n  }\n\n  private getPlatform(): string {\n    try {\n      return platform();\n    } catch {\n      return 'unknown';\n    }\n  }\n\n  private getHostname(): string {\n    try {\n      return hostname();\n    } catch {\n      return 'unknown';\n    }\n  }\n}\n","import { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst PACKAGE_NAME = '@testdino/playwright';\nexport const UNRESOLVED_VERSION = '0.0.0';\n\n// Resolves in both the CJS and ESM bundles: import.meta.url is unavailable in one\n// and __dirname in the other, so try each.\nfunction getModuleDir(): string {\n  const metaUrl = typeof import.meta === 'object' ? import.meta?.url : undefined;\n  if (metaUrl) return dirname(fileURLToPath(metaUrl));\n  return __dirname;\n}\n\nexport function getPackageVersion(): string {\n  // dist/index.js and dist/cli/index.mjs sit at different depths under the package root.\n  const candidates = ['../package.json', '../../package.json'];\n\n  for (const candidate of candidates) {\n    try {\n      const raw = readFileSync(join(getModuleDir(), candidate), 'utf-8');\n      const parsed = JSON.parse(raw) as { name?: unknown; version?: unknown };\n      if (parsed.name === PACKAGE_NAME && typeof parsed.version === 'string') {\n        return parsed.version;\n      }\n    } catch {\n      continue;\n    }\n  }\n  return UNRESOLVED_VERSION;\n}\n","import { readFile } from 'fs/promises';\nimport { BaseMetadataCollector } from './base.js';\nimport { normalizePath } from '../utils/index.js';\nimport type {\n  PlaywrightMetadata,\n  ProjectConfig,\n  ProjectUseOptions,\n  RunSkeleton,\n  SkeletonSuite,\n  SkeletonTest,\n} from './types.js';\n\nexport interface PlaywrightFullProject {\n  name?: string;\n  testDir?: string;\n  timeout?: number;\n  retries?: number;\n  repeatEach?: number;\n  dependencies?: string[];\n  grep?: RegExp | RegExp[];\n  use?: {\n    browserName?: 'chromium' | 'firefox' | 'webkit';\n    defaultBrowserType?: 'chromium' | 'firefox' | 'webkit';\n    channel?: string;\n    headless?: boolean;\n    viewport?: { width: number; height: number } | null;\n    baseURL?: string;\n    trace?: string | { mode: string };\n    screenshot?: string | { mode: string };\n    video?: string | { mode: string };\n    isMobile?: boolean;\n    locale?: string;\n    [key: string]: unknown;\n  };\n}\n\n// testDir/timeout/retries live on FullProject, not FullConfig.\nexport interface PlaywrightFullConfig {\n  fullyParallel?: boolean;\n  workers?: number;\n  shard?: { current: number; total: number } | null;\n  projects?: PlaywrightFullProject[];\n  version?: string;\n  configFile?: string;\n  forbidOnly?: boolean;\n  globalTimeout?: number;\n  grep?: RegExp | RegExp[];\n  maxFailures?: number;\n  metadata?: Record<string, unknown>;\n  reportSlowTests?: { max: number; threshold: number } | null;\n  rootDir?: string;\n  tags?: string[];\n  webServer?: unknown;\n}\n\nexport interface PlaywrightSuite {\n  title: string;\n  type: 'root' | 'project' | 'file' | 'describe';\n  location?: { file: string; line: number; column: number };\n  suites: PlaywrightSuite[];\n  tests: PlaywrightTestCase[];\n  allTests(): PlaywrightTestCase[];\n}\n\nexport interface PlaywrightTestCase {\n  id: string;\n  title: string;\n  location: { file: string; line: number; column: number };\n  tags: string[];\n  expectedStatus: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';\n  annotations: Array<{ type: string; description?: string }>;\n}\n\nexport interface PlaywrightCollectorOptions {\n  timeout?: number;\n  config?: PlaywrightFullConfig;\n  suite?: PlaywrightSuite;\n  packageJsonPath?: string;\n}\n\nexport class PlaywrightMetadataCollector extends BaseMetadataCollector<PlaywrightMetadata> {\n  private options: Required<Omit<PlaywrightCollectorOptions, 'config' | 'suite' | 'packageJsonPath'>> &\n    Pick<PlaywrightCollectorOptions, 'config' | 'suite' | 'packageJsonPath'>;\n\n  constructor(options: PlaywrightCollectorOptions = {}) {\n    super('playwright');\n    this.options = {\n      timeout: options.timeout || 3000,\n      config: options.config,\n      suite: options.suite,\n      packageJsonPath: options.packageJsonPath,\n    };\n  }\n\n  protected async collectMetadata(): Promise<PlaywrightMetadata> {\n    const metadata: PlaywrightMetadata = {};\n\n    const version = await this.getPlaywrightVersion();\n    if (version) metadata.version = version;\n\n    if (this.options.config) {\n      Object.assign(metadata, this.extractConfigMetadata(this.options.config));\n    }\n\n    return metadata;\n  }\n\n  protected getEmptyMetadata(): PlaywrightMetadata {\n    return {};\n  }\n\n  private async getPlaywrightVersion(): Promise<string | undefined> {\n    try {\n      const packageJsonPath = this.options.packageJsonPath || this.resolvePlaywrightPackageJson();\n      if (!packageJsonPath) return undefined;\n\n      const content = await this.withTimeout(\n        readFile(packageJsonPath, 'utf-8'),\n        this.options.timeout,\n        'Playwright package.json read'\n      );\n      const packageJson = this.safeJsonParse<{ version?: string }>(content, {});\n      return this.isNonEmptyString(packageJson.version) ? packageJson.version : undefined;\n    } catch (error) {\n      console.warn(\n        '⚠️  TestDino: Failed to read Playwright version:',\n        error instanceof Error ? error.message : String(error)\n      );\n      return undefined;\n    }\n  }\n\n  private resolvePlaywrightPackageJson(): string | undefined {\n    try {\n      return require.resolve('@playwright/test/package.json');\n    } catch {\n      return undefined;\n    }\n  }\n\n  private extractConfigMetadata(config: PlaywrightFullConfig): Partial<PlaywrightMetadata> {\n    const metadata: Partial<PlaywrightMetadata> = {};\n\n    if (this.isNonEmptyString(config.configFile)) metadata.configFile = config.configFile;\n    if (typeof config.forbidOnly === 'boolean') metadata.forbidOnly = config.forbidOnly;\n\n    if (typeof config.fullyParallel === 'boolean') {\n      metadata.fullyParallel = config.fullyParallel;\n      metadata.parallel = config.fullyParallel;\n    }\n\n    if (typeof config.globalTimeout === 'number') metadata.globalTimeout = config.globalTimeout;\n\n    if (config.grep) {\n      const patterns = Array.isArray(config.grep) ? config.grep : [config.grep];\n      metadata.grep = patterns.map((p) => p.source);\n    }\n\n    if (typeof config.maxFailures === 'number') metadata.maxFailures = config.maxFailures;\n    if (config.metadata && typeof config.metadata === 'object') metadata.metadata = config.metadata;\n    if (typeof config.workers === 'number') metadata.workers = config.workers;\n\n    if (Array.isArray(config.projects) && config.projects.length > 0) {\n      const projectConfigs = config.projects\n        .filter((project) => this.isNonEmptyString(project.name))\n        .map((project) => this.extractProjectConfig(project));\n\n      if (projectConfigs.length > 0) {\n        metadata.projects = projectConfigs;\n        const browsers = this.extractBrowsersFromProjects(config.projects);\n        if (browsers.length > 0) metadata.browsers = browsers;\n      }\n    }\n\n    if (config.reportSlowTests && typeof config.reportSlowTests === 'object') {\n      metadata.reportSlowTests = {\n        max: config.reportSlowTests.max,\n        threshold: config.reportSlowTests.threshold,\n      };\n    }\n\n    if (this.isNonEmptyString(config.rootDir)) metadata.rootDir = config.rootDir;\n\n    if (config.shard && typeof config.shard.current === 'number' && typeof config.shard.total === 'number') {\n      metadata.shard = { current: config.shard.current, total: config.shard.total };\n    }\n\n    if (Array.isArray(config.tags) && config.tags.length > 0) metadata.tags = config.tags;\n    if (config.webServer && typeof config.webServer === 'object') {\n      metadata.webServer = config.webServer as Record<string, unknown>;\n    }\n\n    return metadata;\n  }\n\n  private extractProjectConfig(project: PlaywrightFullProject): ProjectConfig {\n    const config: ProjectConfig = { name: project.name || '' };\n\n    if (this.isNonEmptyString(project.testDir)) config.testDir = project.testDir;\n    if (typeof project.timeout === 'number') config.timeout = project.timeout;\n    if (typeof project.retries === 'number') config.retries = project.retries;\n    if (typeof project.repeatEach === 'number' && project.repeatEach > 1) config.repeatEach = project.repeatEach;\n\n    if (Array.isArray(project.dependencies) && project.dependencies.length > 0) {\n      config.dependencies = project.dependencies;\n    }\n\n    if (project.grep) {\n      const patterns = Array.isArray(project.grep) ? project.grep : [project.grep];\n      const grepStrings = patterns.map((p) => p.source);\n      if (grepStrings.length > 0) config.grep = grepStrings;\n    }\n\n    if (project.use) {\n      const useOptions = this.extractUseOptions(project.use);\n      if (Object.keys(useOptions).length > 0) config.use = useOptions;\n    }\n\n    return config;\n  }\n\n  private extractUseOptions(use: PlaywrightFullProject['use']): ProjectUseOptions {\n    const options: ProjectUseOptions = {};\n    if (!use) return options;\n\n    if (this.isNonEmptyString(use.channel)) options.channel = use.channel;\n\n    const browserName = this.resolveBrowserName(use.browserName, use.defaultBrowserType, use.channel);\n    if (browserName) options.browserName = browserName;\n\n    if (typeof use.headless === 'boolean') options.headless = use.headless;\n\n    if (use.viewport && typeof use.viewport === 'object') {\n      options.viewport = { width: use.viewport.width, height: use.viewport.height };\n    } else if (use.viewport === null) {\n      options.viewport = null;\n    }\n\n    if (this.isNonEmptyString(use.baseURL)) options.baseURL = use.baseURL;\n\n    const trace = this.normalizeArtifactMode(use.trace);\n    if (trace) options.trace = trace;\n\n    const screenshot = this.normalizeArtifactMode(use.screenshot);\n    if (screenshot) options.screenshot = screenshot;\n\n    const video = this.normalizeArtifactMode(use.video);\n    if (video) options.video = video;\n\n    if (typeof use.isMobile === 'boolean') options.isMobile = use.isMobile;\n    if (this.isNonEmptyString(use.locale)) options.locale = use.locale;\n\n    return options;\n  }\n\n  // trace/screenshot/video can be string or { mode: string }.\n  private normalizeArtifactMode(value: unknown): string | undefined {\n    if (!value) return undefined;\n    if (typeof value === 'string' && value !== 'off') return value;\n    if (typeof value === 'object' && value !== null && 'mode' in value) {\n      const mode = (value as { mode: string }).mode;\n      if (mode && mode !== 'off') return mode;\n    }\n    return undefined;\n  }\n\n  // Priority: explicit browserName > defaultBrowserType (device presets) > channel inference.\n  private resolveBrowserName(\n    browserName: string | undefined,\n    defaultBrowserType: string | undefined,\n    channel: string | undefined\n  ): 'chromium' | 'firefox' | 'webkit' | undefined {\n    const validBrowsers = ['chromium', 'firefox', 'webkit'];\n\n    if (browserName && validBrowsers.includes(browserName)) {\n      return browserName as 'chromium' | 'firefox' | 'webkit';\n    }\n    if (defaultBrowserType && validBrowsers.includes(defaultBrowserType)) {\n      return defaultBrowserType as 'chromium' | 'firefox' | 'webkit';\n    }\n    if (channel) {\n      const chromiumChannels = [\n        'chrome',\n        'chrome-beta',\n        'chrome-dev',\n        'chrome-canary',\n        'msedge',\n        'msedge-beta',\n        'msedge-dev',\n        'msedge-canary',\n      ];\n      if (chromiumChannels.includes(channel)) return 'chromium';\n    }\n    return undefined;\n  }\n\n  private extractBrowsersFromProjects(projects: PlaywrightFullProject[]): string[] {\n    const browsers = new Set<string>();\n    for (const project of projects) {\n      const browserName = this.resolveBrowserName(\n        project.use?.browserName,\n        project.use?.defaultBrowserType,\n        project.use?.channel\n      );\n      if (browserName) browsers.add(browserName);\n    }\n    return Array.from(browsers);\n  }\n\n  buildSkeleton(suite: PlaywrightSuite): RunSkeleton {\n    return {\n      totalTests: suite.allTests().length,\n      suites: this.buildSuiteTree(suite),\n    };\n  }\n\n  private buildSuiteTree(suite: PlaywrightSuite): SkeletonSuite[] {\n    const suites: SkeletonSuite[] = [];\n\n    for (const childSuite of suite.suites) {\n      const skeletonSuite: SkeletonSuite = {\n        title: childSuite.title,\n        type: childSuite.type === 'file' ? 'file' : 'describe',\n        tests: childSuite.tests.map((test) => this.buildSkeletonTest(test)),\n      };\n\n      if (childSuite.type === 'file' && childSuite.location) {\n        skeletonSuite.file = normalizePath(childSuite.location.file, this.options.config?.rootDir);\n      }\n\n      if (childSuite.location) {\n        skeletonSuite.location = {\n          file: normalizePath(childSuite.location.file, this.options.config?.rootDir),\n          line: childSuite.location.line,\n          column: childSuite.location.column,\n        };\n      }\n\n      if (childSuite.suites.length > 0) {\n        skeletonSuite.suites = this.buildSuiteTree(childSuite);\n      }\n\n      suites.push(skeletonSuite);\n    }\n\n    return suites;\n  }\n\n  private buildSkeletonTest(test: PlaywrightTestCase): SkeletonTest {\n    const skeletonTest: SkeletonTest = {\n      testId: test.id,\n      title: test.title,\n      location: {\n        file: normalizePath(test.location.file, this.options.config?.rootDir),\n        line: test.location.line,\n        column: test.location.column,\n      },\n    };\n\n    if (test.tags && test.tags.length > 0) skeletonTest.tags = test.tags;\n    if (test.expectedStatus) skeletonTest.expectedStatus = test.expectedStatus;\n    if (test.annotations && test.annotations.length > 0) {\n      skeletonTest.annotations = test.annotations.map((ann) => ({\n        type: ann.type,\n        description: ann.description,\n      }));\n    }\n\n    return skeletonTest;\n  }\n}\n","import type {\n  MetadataCollectionOptions,\n  MetadataCollectionResult,\n  MetadataCollectionSummary,\n  CompleteMetadata,\n  GitMetadata,\n  CIMetadata,\n  SystemMetadata,\n  PlaywrightMetadata,\n} from './types.js';\nimport { GitMetadataCollector } from './git.js';\nimport { CIMetadataCollector } from './ci.js';\nimport { SystemMetadataCollector } from './system.js';\nimport { PlaywrightMetadataCollector } from './playwright.js';\nimport { withTimeout as withTimeoutUtil } from '../utils/index.js';\nimport type { PlaywrightFullConfig, PlaywrightSuite } from './playwright.js';\n\nconst DEFAULT_METADATA_OPTIONS: Required<MetadataCollectionOptions> = {\n  timeout: 5000,\n  debug: false,\n};\n\nexport class MetadataAggregator {\n  private options: Required<MetadataCollectionOptions>;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private collectors: Array<{ collectWithResult: () => Promise<MetadataCollectionResult<any>> }> = [];\n  private playwrightCollector?: PlaywrightMetadataCollector;\n\n  constructor(options: MetadataCollectionOptions = {}) {\n    this.options = { ...DEFAULT_METADATA_OPTIONS, ...options };\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  registerCollector(collector: { collectWithResult: () => Promise<MetadataCollectionResult<any>> }): void {\n    this.collectors.push(collector);\n    if (collector instanceof PlaywrightMetadataCollector) {\n      this.playwrightCollector = collector;\n    }\n  }\n\n  buildSkeleton(suite: PlaywrightSuite): CompleteMetadata['skeleton'] {\n    if (!this.playwrightCollector) return undefined;\n    return this.playwrightCollector.buildSkeleton(suite);\n  }\n\n  async collectAll(): Promise<MetadataCollectionSummary> {\n    const startTime = Date.now();\n\n    const settledResults = await Promise.allSettled(\n      this.collectors.map((collector) =>\n        this.withTimeout(collector.collectWithResult(), this.options.timeout, 'Metadata collection')\n      )\n    );\n\n    const results: MetadataCollectionResult[] = [];\n    const metadata: CompleteMetadata = {};\n\n    for (const settledResult of settledResults) {\n      if (settledResult.status === 'fulfilled') {\n        const result = settledResult.value;\n        results.push(result);\n        this.aggregateMetadata(metadata, result);\n      } else {\n        const error = settledResult.reason;\n        console.warn('⚠️  TestDino: Metadata collector promise rejected:', error);\n        results.push({\n          data: {},\n          success: false,\n          error: error instanceof Error ? error.message : String(error),\n          duration: 0,\n          collector: 'unknown',\n        });\n      }\n    }\n\n    // Cross-collector reconciliation: needs both git + ci results. Bitbucket\n    // post-merge runs are reclassified from push → pull_request here.\n    if (metadata.ci && metadata.git) {\n      CIMetadataCollector.reconcileWithGit(metadata.ci, metadata.git);\n      CIMetadataCollector.resolveActorIsAuthor(metadata.ci, metadata.git);\n    }\n    delete metadata.git?.commit?.verifiedLogin;\n\n    const totalDuration = Date.now() - startTime;\n    const successCount = results.filter((r) => r.success).length;\n    return {\n      metadata,\n      results,\n      totalDuration,\n      successCount,\n      failureCount: results.length - successCount,\n    };\n  }\n\n  private aggregateMetadata(metadata: CompleteMetadata, result: MetadataCollectionResult): void {\n    const { collector, data } = result;\n    switch (collector) {\n      case 'git':\n        metadata.git = data as GitMetadata;\n        break;\n      case 'ci':\n        metadata.ci = data as CIMetadata;\n        break;\n      case 'system':\n        metadata.system = data as SystemMetadata;\n        break;\n      case 'playwright':\n        metadata.playwright = data as PlaywrightMetadata;\n        break;\n      default:\n        if (this.options.debug) {\n          console.warn(`⚠️  TestDino: Unknown metadata collector: ${collector}`);\n        }\n    }\n  }\n\n  private async withTimeout<T>(promise: Promise<T>, timeoutMs: number, operation: string): Promise<T> {\n    return withTimeoutUtil(promise, timeoutMs, operation);\n  }\n}\n\nexport type {\n  MetadataCollectionOptions,\n  MetadataCollectionResult,\n  MetadataCollectionSummary,\n  CompleteMetadata,\n  GitMetadata,\n  CIMetadata,\n  SystemMetadata,\n  PlaywrightMetadata,\n  PRMetadata,\n  ShardMetadata,\n  MetadataCollector,\n  RunSkeleton,\n  SkeletonSuite,\n  SkeletonTest,\n} from './types.js';\n\nexport { BaseMetadataCollector } from './base.js';\nexport { GitMetadataCollector } from './git.js';\nexport { CIMetadataCollector } from './ci.js';\nexport { SystemMetadataCollector } from './system.js';\nexport { PlaywrightMetadataCollector } from './playwright.js';\n\nexport function createMetadataCollector(\n  playwrightConfig?: PlaywrightFullConfig,\n  playwrightSuite?: PlaywrightSuite\n): MetadataAggregator {\n  const aggregator = new MetadataAggregator();\n  aggregator.registerCollector(new GitMetadataCollector());\n  aggregator.registerCollector(new CIMetadataCollector());\n  aggregator.registerCollector(new SystemMetadataCollector());\n  aggregator.registerCollector(\n    new PlaywrightMetadataCollector({\n      config: playwrightConfig,\n      suite: playwrightSuite,\n    })\n  );\n  return aggregator;\n}\n","export const DEFAULT_SERVER_URL = 'https://reporter.testdino.com';\n\nimport type { CompleteMetadata } from '../metadata/types.js';\n\nexport type {\n  CompleteMetadata as RunMetadata,\n  GitMetadata,\n  CIMetadata,\n  PRMetadata,\n  SystemMetadata,\n  PlaywrightMetadata,\n  ShardMetadata,\n  MetadataCollectionResult,\n  MetadataCollectionSummary,\n  MetadataCollector,\n} from '../metadata/types.js';\n\nexport type { QuotaExhaustedError, QuotaExceededError, ServerError } from '../reporter/errors.js';\nexport type { SessionCreationQuotaResponse, NackMessage } from './errors.js';\n\nexport interface TestdinoConfig {\n  token?: string;\n  ciRunId?: string;\n  // Manual-split group id — correlation key like ciRunId (CLI flag, testdino.config, reporter opts, or TESTDINO_SPLIT_ID env). The split position stays CLI-only.\n  splitId?: string;\n  // Swarm id — set only by `tdpw swarm --id` (CLI flag, threaded to the reporter via temp-config). Mutually exclusive with splitId.\n  swarmId?: string;\n  serverUrl?: string;\n  debug?: boolean;\n  artifacts?: boolean;\n  tags?: string[];\n}\n\nexport type TestEvent =\n  | TestRunBeginEvent\n  | TestBeginEvent\n  | TestStepBeginEvent\n  | TestStepEndEvent\n  | TestEndEvent\n  | TestRunEndEvent\n  | TestRunErrorEvent\n  | TestConsoleOutEvent\n  | TestConsoleErrEvent\n  | RunHeartbeatEvent;\n\nexport interface Annotation {\n  type: string;\n  description?: string;\n}\n\nexport interface BaseEvent {\n  type: string;\n  timestamp: number;\n  runId: string;\n  sequence: number;\n}\n\nexport interface TestRunBeginEvent extends BaseEvent {\n  type: 'run:begin';\n  projectId: string;\n  metadata: CompleteMetadata;\n  ciRunId?: string;\n  shard?: {\n    current: number;\n    total: number;\n  };\n  splitId?: string;\n  swarmId?: string;\n  // machineId: the reporting machine under swarm; ingestion stamps it on every case for attribution.\n  machineId?: string;\n  split?: {\n    current: number;\n    total: number;\n  };\n  tags?: string[];\n  // The run whose failed/flaky selection this run re-executes.\n  rerunOf?: string;\n}\n\nexport interface TestBeginEvent extends BaseEvent {\n  type: 'test:begin';\n  testId: string;\n  title: string;\n  titlePath: Array<string>;\n  location: {\n    file: string;\n    line: number;\n    column: number;\n  };\n  tags: Array<string>;\n  expectedStatus: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';\n  timeout: number;\n  retries: number;\n  annotations: Array<Annotation>;\n  retry: number;\n  workerIndex: number;\n  parallelIndex: number;\n  repeatEachIndex?: number;\n  parentSuite: {\n    title: string;\n    type: 'root' | 'project' | 'file' | 'describe';\n    location?: {\n      file: string;\n      line: number;\n      column: number;\n    };\n  };\n  startTime: number;\n}\n\nexport interface TestStepBeginEvent extends BaseEvent {\n  type: 'step:begin';\n  testId: string;\n  stepId: string;\n  title: string;\n  titlePath: Array<string>;\n  category: string;\n  location?: {\n    file: string;\n    line: number;\n    column: number;\n  };\n  parentStep?: {\n    title: string;\n    category: string;\n    location?: {\n      file: string;\n      line: number;\n      column: number;\n    };\n  };\n  startTime: number;\n  retry: number;\n  workerIndex: number;\n  parallelIndex: number;\n  annotations: Array<Annotation>;\n}\n\nexport interface TestStepEndEvent extends BaseEvent {\n  type: 'step:end';\n  testId: string;\n  stepId: string;\n  title?: string;\n  titlePath?: string[];\n  duration: number;\n  error?: {\n    message: string;\n    stack?: string;\n    snippet?: string;\n    value?: string;\n    location?: {\n      file: string;\n      line: number;\n      column: number;\n    };\n  };\n  status: 'passed' | 'failed';\n  childSteps: {\n    count: number;\n    steps: Array<{\n      title: string;\n      status: 'passed' | 'failed';\n    }>;\n  };\n  workerIndex: number;\n  parallelIndex: number;\n  // step attachments never carry path — would leak local FS.\n  attachments: Array<{\n    name: string;\n    contentType: string;\n  }>;\n  annotations?: Array<Annotation>;\n  retry: number;\n}\n\nexport interface TestEndEvent extends BaseEvent {\n  type: 'test:end';\n  testId: string;\n  status: 'passed' | 'failed' | 'skipped' | 'timedOut' | 'interrupted';\n  outcome: 'expected' | 'unexpected' | 'flaky' | 'skipped';\n  duration: number;\n  retry: number;\n  workerIndex: number;\n  parallelIndex: number;\n  annotations: Array<Annotation>;\n  errors: Array<{\n    message: string;\n    stack?: string;\n    snippet?: string;\n    value?: string;\n    location?: {\n      file: string;\n      line: number;\n      column: number;\n    };\n  }>;\n  steps: {\n    total: number;\n    passed: number;\n    failed: number;\n  };\n  // Three mutually-exclusive states: uploaded (blobKey) / failed (unavailable) / in-memory (excluded upstream).\n  // path never emitted — non-dereferenceable + PII.\n  attachments: Array<{\n    name: string;\n    contentType: string;\n    blobKey?: string;\n    unavailable?: boolean;\n  }>;\n  stdout?: string[];\n  stderr?: string[];\n}\n\nexport interface TestRunEndEvent extends BaseEvent {\n  type: 'run:end';\n  status: 'passed' | 'failed' | 'timedout' | 'interrupted';\n  duration: number;\n  startTime: number;\n  shard?: {\n    current: number;\n    total: number;\n  };\n  splitId?: string;\n  swarmId?: string;\n  // machineId: the reporting machine under swarm; ingestion stamps it on every case for attribution.\n  machineId?: string;\n  split?: {\n    current: number;\n    total: number;\n  };\n  // Test Controls: what this process did with the quarantine list. Absent from\n  // reporters that predate it; the server then stores no quarantine state.\n  quarantine?: RunQuarantineBlock;\n  // Tests this process brought to a final verdict, plus attempts still open at\n  // interruption. The server compares its recorded results against this rather\n  // than the run:begin skeleton, which cannot tell a short run from lost events.\n  executedTests?: number;\n  // Set when the run failed before its first test began (global setup or test\n  // loading failed), so its run:begin declared no tests although some were meant\n  // to run. Absent otherwise.\n  notStarted?: true;\n}\n\n/** GET /api/v1/reporter/quarantine — Playwright test ids per Test Controls rule. */\nexport interface QuarantineList {\n  quarantined: string[];\n  knownErrors: { testIds: string[]; pattern: string }[];\n  critical: string[];\n  // One per rule, however many browser variants it expands to. Absent on\n  // servers older than the count.\n  rules?: { quarantined: number; knownErrors: number; critical: number };\n  generatedAt?: string;\n}\n\nexport interface RunQuarantineBlock {\n  state: 'applied' | 'not_applied';\n  reason?: 'unreachable' | 'timeout' | 'not_found';\n  // Quarantined tests that ran here; a known-error test only if it passed or\n  // its failure matched.\n  testIds?: string[];\n  // Critical tests that passed only on retry; the reporter failed the build.\n  criticalFlakyTestIds?: string[];\n  // The build result Test Controls ended with: its override, else Playwright's.\n  // The server cannot rebuild it from counts (an error outside any test is\n  // invisible there).\n  build: 'passed' | 'failed';\n}\n\n// No sequence — not part of event ordering.\nexport interface RunHeartbeatEvent {\n  type: 'run:heartbeat';\n  runId: string;\n  timestamp: number;\n}\n\nexport interface TestRunErrorEvent extends BaseEvent {\n  type: 'run:error';\n  error: {\n    message?: string;\n    stack?: string;\n    value?: string;\n    snippet?: string;\n    location?: {\n      file: string;\n      line: number;\n      column: number;\n    };\n    // v1.49+\n    cause?: {\n      message?: string;\n      stack?: string;\n      value?: string;\n      snippet?: string;\n      location?: {\n        file: string;\n        line: number;\n        column: number;\n      };\n    };\n  };\n}\n\nexport interface TestConsoleOutEvent extends BaseEvent {\n  type: 'console:out';\n  text: string; // Chunk, UTF-8, max 10KB.\n  testId?: string;\n  retry?: number;\n  truncated?: boolean;\n}\n\nexport interface TestConsoleErrEvent extends BaseEvent {\n  type: 'console:err';\n  text: string; // Chunk, UTF-8, max 10KB.\n  testId?: string;\n  retry?: number;\n  truncated?: boolean;\n}\n","import axios, { type AxiosInstance, isAxiosError } from 'axios';\nimport { extname } from 'path';\nimport { sleep } from '../utils/index.js';\nimport type {\n  UploadFileRequest,\n  UploadTokenResult,\n  UploadTokenRequestBody,\n  UploadTokenResponseBody,\n  UploadTokenErrorBody,\n} from './types.js';\n\n// Sync with data-handler ARTIFACT_ALLOWED_FILE_TYPES.\nexport const DEFAULT_ALLOWED_FILE_TYPES: readonly string[] = ['png', 'jpeg', 'jpg', 'webm', 'zip', 'json', 'txt', 'md'];\n\nexport function isAllowedExtension(fileName: string, allowed: readonly string[] = DEFAULT_ALLOWED_FILE_TYPES): boolean {\n  const ext = extname(fileName).slice(1).toLowerCase();\n  return ext.length > 0 && allowed.includes(ext);\n}\n\n// Sync with data-handler ARTIFACT_MAX_SIZE_BYTES. Server 400s the whole batch\n// on the first oversized file — pre-filter locally.\nexport const DEFAULT_MAX_SIZE_BYTES = 50 * 1024 * 1024;\n\nexport function isWithinSizeLimit(sizeBytes: number, max: number = DEFAULT_MAX_SIZE_BYTES): boolean {\n  return sizeBytes <= max;\n}\n\n// 400 → bad batch. 401/403 → auth. 404 → wrong route or missing blob. 405 → method not allowed.\nconst PERMANENT_CLIENT_STATUSES: readonly number[] = [400, 401, 403, 404, 405];\n\nexport interface ArtifactUploadClientOptions {\n  token: string;\n  serverUrl: string;\n  runId: string;\n  maxAttempts?: number;\n  retryDelay?: number;\n  putTimeout?: number;\n  tokenRequestTimeout?: number;\n  onDebug?: (message: string) => void;\n}\n\nexport class ArtifactUploadTokenError extends Error {\n  readonly kind: 'client' | 'server_error' | 'storage' | 'network';\n  readonly httpStatus?: number;\n  readonly serverCode?: string;\n\n  constructor(\n    message: string,\n    kind: 'client' | 'server_error' | 'storage' | 'network',\n    httpStatus?: number,\n    serverCode?: string\n  ) {\n    super(message);\n    this.name = 'ArtifactUploadTokenError';\n    this.kind = kind;\n    this.httpStatus = httpStatus;\n    this.serverCode = serverCode;\n  }\n}\n\nexport class ArtifactPutError extends Error {\n  readonly kind: 'client' | 'server_error' | 'network';\n  readonly httpStatus?: number;\n\n  constructor(message: string, kind: 'client' | 'server_error' | 'network', httpStatus?: number) {\n    super(message);\n    this.name = 'ArtifactPutError';\n    this.kind = kind;\n    this.httpStatus = httpStatus;\n  }\n}\n\nexport class ArtifactUploadClient {\n  private readonly http: AxiosInstance;\n  private readonly runId: string;\n  private readonly maxAttempts: number;\n  private readonly retryDelay: number;\n  private readonly putTimeout: number;\n  private readonly onDebug: (message: string) => void;\n\n  constructor(options: ArtifactUploadClientOptions) {\n    this.runId = options.runId;\n    this.maxAttempts = options.maxAttempts ?? 2;\n    this.retryDelay = options.retryDelay ?? 1000;\n    this.putTimeout = options.putTimeout ?? 60_000;\n    this.onDebug = options.onDebug ?? (() => {});\n\n    // data-handler middleware reads only Authorization: Bearer; x-api-key is rejected.\n    this.http = axios.create({\n      baseURL: options.serverUrl,\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${options.token}`,\n      },\n      timeout: options.tokenRequestTimeout ?? 10_000,\n    });\n  }\n\n  async requestUploadTokens(files: UploadFileRequest[]): Promise<UploadTokenResult> {\n    if (files.length === 0) {\n      throw new ArtifactUploadTokenError('Cannot request upload tokens for an empty batch', 'client');\n    }\n\n    const body: UploadTokenRequestBody = {\n      files: files.map((f) => ({\n        name: f.name,\n        test_id: f.testId,\n        content_type: f.contentType,\n        size_bytes: f.sizeBytes,\n      })),\n    };\n    const path = `/api/v1/reporter/runs/${encodeURIComponent(this.runId)}/artifacts/upload-token`;\n\n    let lastError: ArtifactUploadTokenError | null = null;\n\n    for (let attempt = 0; attempt < this.maxAttempts; attempt++) {\n      try {\n        this.onDebug(`upload-token request attempt ${attempt + 1}/${this.maxAttempts} (files=${files.length})`);\n        const response = await this.http.post<UploadTokenResponseBody>(path, body);\n        return {\n          uploads: response.data.uploads.map((u) => ({\n            attachmentId: u.attachment_id,\n            blobKey: u.blob_key,\n            uploadUrl: u.upload_url,\n          })),\n          expiresAt: response.data.expires_at,\n          maxSizeBytes: response.data.max_size_bytes,\n          allowedFileTypes: response.data.allowed_file_types,\n        };\n      } catch (error) {\n        const classified = classifyTokenError(error);\n        lastError = classified;\n        if (classified.kind === 'client') {\n          this.onDebug(\n            `upload-token permanent client error (${classified.httpStatus ?? '?'}/${classified.serverCode ?? '?'}) — not retrying`\n          );\n          throw classified;\n        }\n        if (attempt < this.maxAttempts - 1) {\n          const delay = this.retryDelay * Math.pow(2, attempt);\n          this.onDebug(\n            `upload-token transient failure (kind=${classified.kind}, status=${classified.httpStatus ?? '?'}) — retrying in ${delay}ms`\n          );\n          await sleep(delay);\n        }\n      }\n    }\n\n    throw lastError ?? new ArtifactUploadTokenError('Upload-token request failed', 'network');\n  }\n\n  async uploadFile(uploadUrl: string, body: Buffer, contentType: string): Promise<void> {\n    let lastError: ArtifactPutError | null = null;\n\n    for (let attempt = 0; attempt < this.maxAttempts; attempt++) {\n      try {\n        await this.doPut(uploadUrl, body, contentType);\n        return;\n      } catch (error) {\n        const classified = classifyPutError(error);\n        lastError = classified;\n        if (classified.kind === 'client') {\n          this.onDebug(`PUT permanent client error (${classified.httpStatus ?? '?'}) — not retrying`);\n          throw classified;\n        }\n        if (attempt < this.maxAttempts - 1) {\n          const delay = this.retryDelay * Math.pow(2, attempt);\n          this.onDebug(\n            `PUT transient failure (kind=${classified.kind}, status=${classified.httpStatus ?? '?'}) — retrying in ${delay}ms`\n          );\n          await sleep(delay);\n        }\n      }\n    }\n\n    throw lastError ?? new ArtifactPutError('Artifact PUT failed', 'network');\n  }\n\n  // Buffer, not stream: caller snapshots before token round-trip so a file\n  // Playwright cleans up mid-run can't vanish under an in-flight PUT.\n  private async doPut(uploadUrl: string, body: Buffer, contentType: string): Promise<void> {\n    await axios.put(uploadUrl, body, {\n      headers: {\n        'Content-Type': contentType,\n        'Content-Length': body.length,\n        'x-ms-blob-type': 'BlockBlob',\n      },\n      timeout: this.putTimeout,\n      maxContentLength: Infinity,\n      maxBodyLength: Infinity,\n    });\n  }\n}\n\nfunction classifyTokenError(error: unknown): ArtifactUploadTokenError {\n  if (isAxiosError(error)) {\n    const status = error.response?.status;\n    const body = error.response?.data as UploadTokenErrorBody | undefined;\n    const code = body?.error?.code;\n    const message = body?.error?.message ?? error.message;\n\n    if (status !== undefined && PERMANENT_CLIENT_STATUSES.includes(status)) {\n      return new ArtifactUploadTokenError(message, 'client', status, code);\n    }\n    if (status === 503) return new ArtifactUploadTokenError(message, 'storage', status, code);\n    if (status !== undefined && status >= 500) {\n      return new ArtifactUploadTokenError(message, 'server_error', status, code);\n    }\n    if (status !== undefined && status >= 400) {\n      // Unusual 4xx (409/429) — treat as client; server contract offers no headroom.\n      return new ArtifactUploadTokenError(message, 'client', status, code);\n    }\n    return new ArtifactUploadTokenError(message, 'network');\n  }\n  const message = error instanceof Error ? error.message : String(error);\n  return new ArtifactUploadTokenError(message, 'network');\n}\n\nfunction classifyPutError(error: unknown): ArtifactPutError {\n  if (isAxiosError(error)) {\n    const status = error.response?.status;\n    const message = error.message;\n\n    if (status !== undefined && PERMANENT_CLIENT_STATUSES.includes(status)) {\n      return new ArtifactPutError(message, 'client', status);\n    }\n    // Azure Blob throttles PUTs with 429 — genuine transient, retry.\n    if (status === 429) return new ArtifactPutError(message, 'server_error', status);\n    if (status !== undefined && status >= 500) return new ArtifactPutError(message, 'server_error', status);\n    if (status !== undefined && status >= 400) return new ArtifactPutError(message, 'client', status);\n    return new ArtifactPutError(message, 'network');\n  }\n  const message = error instanceof Error ? error.message : String(error);\n  return new ArtifactPutError(message, 'network');\n}\n","import chalk from 'chalk';\n\nexport function supportsColor(): boolean {\n  if (process.env.NO_COLOR) return false;\n  if (process.env.FORCE_COLOR) return true;\n  return Boolean(process.stdout.isTTY);\n}\n\nexport const colors = {\n  success: (text: string) => (supportsColor() ? chalk.green(text) : text),\n  error: (text: string) => (supportsColor() ? chalk.red(text) : text),\n  warning: (text: string) => (supportsColor() ? chalk.yellow(text) : text),\n  info: (text: string) => (supportsColor() ? chalk.cyan(text) : text),\n  bold: (text: string) => (supportsColor() ? chalk.bold(text) : text),\n  dim: (text: string) => (supportsColor() ? chalk.dim(text) : text),\n  white: (text: string) => (supportsColor() ? chalk.white(text) : text),\n  gray: (text: string) => (supportsColor() ? chalk.gray(text) : text),\n  blue: (text: string) => (supportsColor() ? chalk.blue(text) : text),\n  url: (text: string) => (supportsColor() ? chalk.blue.underline(text) : text),\n};\n\nexport const symbols = {\n  success: '\\u2713', // ✓\n  error: '\\u2716', // ✖\n  warning: '!',\n  info: 'i',\n  debug: '[debug]',\n  bullet: '\\u2022', // •\n  pointer: '\\u276F', // ❯\n  line: '\\u2500', // ─\n};\n\n// Chalk emits SGR sequences only; this is not a full ECMA-48 parser.\nconst ESC = String.fromCharCode(27);\nconst ANSI_PATTERN = `${ESC}\\\\[[0-9;]*[a-zA-Z]`;\nconst ANSI_GLOBAL = new RegExp(ANSI_PATTERN, 'g');\nconst ANSI_SEQUENCE = new RegExp(`^${ANSI_PATTERN}`);\n\nexport function stripAnsi(str: string): string {\n  return str.replace(ANSI_GLOBAL, '');\n}\n\nexport function pad(str: string, len: number): string {\n  const vLen = stripAnsi(str).length;\n  return vLen >= len ? str : str + ' '.repeat(len - vLen);\n}\n\n// Terminal display columns, not UTF-16 code units. A CJK commit subject measured\n// by .length renders at twice its measured width and pushes the box border out.\nexport function visibleWidth(str: string): number {\n  let width = 0;\n  for (const ch of stripAnsi(str)) {\n    const cp = ch.codePointAt(0)!;\n    if (isZeroWidth(cp)) continue;\n    width += isWide(cp) ? 2 : 1;\n  }\n  return width;\n}\n\nfunction isZeroWidth(cp: number): boolean {\n  // Combining marks and zero-width joiners/selectors occupy no column of their own.\n  return (\n    (cp >= 0x0300 && cp <= 0x036f) || (cp >= 0x200b && cp <= 0x200f) || cp === 0xfeff || (cp >= 0xfe00 && cp <= 0xfe0f)\n  );\n}\n\nfunction isWide(cp: number): boolean {\n  return (\n    (cp >= 0x1100 && cp <= 0x115f) ||\n    (cp >= 0x2e80 && cp <= 0xa4cf) ||\n    (cp >= 0xac00 && cp <= 0xd7a3) ||\n    (cp >= 0xf900 && cp <= 0xfaff) ||\n    (cp >= 0xfe30 && cp <= 0xfe6f) ||\n    (cp >= 0xff00 && cp <= 0xff60) ||\n    (cp >= 0xffe0 && cp <= 0xffe6) ||\n    (cp >= 0x1f300 && cp <= 0x1faff) ||\n    (cp >= 0x20000 && cp <= 0x3fffd)\n  );\n}\n\n// Pads like pad(), but also truncates when the visible content overruns `len`.\n// A fixed-width box row must never exceed its budget or the border is pushed out.\nexport function fit(str: string, len: number): string {\n  if (len <= 0) return '';\n  const vLen = visibleWidth(str);\n  if (vLen === len) return str;\n  if (vLen < len) return str + ' '.repeat(len - vLen);\n\n  // Iterate by code point so a surrogate pair is copied or dropped whole; a split\n  // pair would emit a lone surrogate and still miscount the column.\n  let out = '';\n  let width = 0;\n  let hasStyle = false;\n  let i = 0;\n  while (i < str.length) {\n    if (str[i] === ESC) {\n      const match = ANSI_SEQUENCE.exec(str.slice(i));\n      if (match) {\n        out += match[0];\n        hasStyle = true;\n        i += match[0].length;\n        continue;\n      }\n    }\n    const ch = String.fromCodePoint(str.codePointAt(i)!);\n    const cw = visibleWidth(ch);\n    if (width + cw > len - 1) {\n      out += '\\u2026';\n      break;\n    }\n    out += ch;\n    width += cw;\n    i += ch.length;\n  }\n  // Reset styling so a truncated color cannot leak into the border.\n  return hasStyle ? `${out}${ESC}[0m` : out;\n}\n\ninterface BoxOptions {\n  borderColor?: 'green' | 'red' | 'yellow' | 'cyan' | 'white';\n  title?: string;\n  padding?: number;\n}\n\nexport function box(content: string[], options: BoxOptions = {}): string {\n  if (content.length === 0 && !options.title) return '';\n\n  const { padding = 1, borderColor = 'white', title } = options;\n\n  const maxContentWidth = Math.max(\n    0,\n    ...content.map((line) => stripAnsi(line).length),\n    title ? stripAnsi(title).length : 0\n  );\n  const boxWidth = maxContentWidth + padding * 2 + 2;\n\n  const colorFn =\n    borderColor === 'green'\n      ? colors.success\n      : borderColor === 'red'\n        ? colors.error\n        : borderColor === 'yellow'\n          ? colors.warning\n          : borderColor === 'cyan'\n            ? colors.info\n            : colors.white;\n\n  const lines: string[] = [];\n\n  // Top border with optional title\n  if (title) {\n    const titleText = ` ${title} `;\n    const remainingWidth = boxWidth - 2 - titleText.length;\n    const leftPad = Math.floor(remainingWidth / 2);\n    const rightPad = remainingWidth - leftPad;\n    lines.push(\n      colorFn('\\u250C') +\n        colorFn('\\u2500'.repeat(leftPad)) +\n        colors.bold(titleText) +\n        colorFn('\\u2500'.repeat(rightPad)) +\n        colorFn('\\u2510')\n    );\n  } else {\n    lines.push(colorFn('\\u250C') + colorFn('\\u2500'.repeat(boxWidth - 2)) + colorFn('\\u2510'));\n  }\n\n  // Top padding\n  if (padding > 0) {\n    lines.push(colorFn('\\u2502') + ' '.repeat(boxWidth - 2) + colorFn('\\u2502'));\n  }\n\n  // Content lines\n  for (const line of content) {\n    const lineLength = stripAnsi(line).length;\n    const rightSpace = boxWidth - 2 - padding - lineLength - padding;\n    lines.push(\n      colorFn('\\u2502') + ' '.repeat(padding) + line + ' '.repeat(Math.max(0, rightSpace + padding)) + colorFn('\\u2502')\n    );\n  }\n\n  // Bottom padding\n  if (padding > 0) {\n    lines.push(colorFn('\\u2502') + ' '.repeat(boxWidth - 2) + colorFn('\\u2502'));\n  }\n\n  // Bottom border\n  lines.push(colorFn('\\u2514') + colorFn('\\u2500'.repeat(boxWidth - 2)) + colorFn('\\u2518'));\n\n  return lines.join('\\n');\n}\n\nexport function formatDuration(ms: number): string {\n  if (ms < 1000) return `${ms}ms`;\n  const seconds = ms / 1000;\n  if (seconds < 60) return `${seconds.toFixed(1)}s`;\n  const minutes = Math.floor(seconds / 60);\n  const remainingSeconds = (seconds % 60).toFixed(0);\n  return `${minutes}m ${remainingSeconds}s`;\n}\n\n// OSC 8 makes the text itself clickable in a terminal; CI log viewers do not\n// render it, so there the URL is printed in full, where they link it.\nexport function hyperlink(text: string, url: string): string {\n  if (process.env.CI || process.env.NO_COLOR || !process.stderr.isTTY) return `${text}: ${url}`;\n  return `\\u001b]8;;${url}\\u0007${colors.url(text)}\\u001b]8;;\\u0007`;\n}\n","import axios from 'axios';\nimport { readFileSync, writeFileSync } from 'fs';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { colors } from './ui.js';\nimport { getPackageVersion, UNRESOLVED_VERSION } from './package-version.js';\n\n// The packument root, not /latest: the abbreviated-packument Accept header below is\n// only content-negotiable here, and /latest answers it with HTTP 406.\nconst REGISTRY_URL = 'https://registry.npmjs.org/@testdino%2fplaywright';\nconst CHECK_TIMEOUT_MS = 1500;\nconst PACKAGE_NAME = '@testdino/playwright';\nconst CHANGELOG_URL = 'https://changelog.testdino.com/?type=cli';\n\n// Without this the registry is hit on every single run — once per shard, per retry,\n// per CI job — for a notice that changes at most a few times a year.\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst CACHE_FILE = join(tmpdir(), 'testdino-playwright-update-check.json');\n\ninterface UpdateCache {\n  checkedAt: number;\n  latest: string;\n}\n\nfunction readCachedLatest(): string | undefined {\n  try {\n    const parsed = JSON.parse(readFileSync(CACHE_FILE, 'utf-8')) as Partial<UpdateCache>;\n    if (typeof parsed.checkedAt !== 'number' || typeof parsed.latest !== 'string') return undefined;\n    // A clock moved backwards would otherwise pin a stale entry as fresh forever.\n    const age = Date.now() - parsed.checkedAt;\n    if (age < 0 || age >= CACHE_TTL_MS) return undefined;\n    return parsed.latest;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction writeCachedLatest(latest: string): void {\n  try {\n    const entry: UpdateCache = { checkedAt: Date.now(), latest };\n    writeFileSync(CACHE_FILE, JSON.stringify(entry), 'utf-8');\n  } catch {\n    // A cache that cannot be written just means we check again next run.\n  }\n}\n\n// Shared by the CLI and reporter renderers so the two surfaces cannot drift apart.\nexport function buildUpdateNoticeLines(currentVersion: string, latestVersion: string): string[] {\n  // Pad before coloring, since padEnd on a colored string counts invisible ANSI bytes.\n  const label = (text: string): string => colors.dim(text.padEnd('Current:'.length));\n\n  return [\n    `A new version of ${colors.info(PACKAGE_NAME)} is available`,\n    '',\n    `${label('Current:')} ${colors.error(currentVersion)}`,\n    `${label('Latest:')} ${colors.success(latestVersion)}`,\n    '',\n    'Update with:',\n    `npm install --save-dev ${PACKAGE_NAME}@latest`,\n    '',\n    `Release notes: ${colors.url(CHANGELOG_URL)}`,\n  ];\n}\n\nexport function compareVersions(a: string, b: string): number {\n  const parse = (v: string): number[] =>\n    v\n      .replace(/^v/, '')\n      .split('+')[0]\n      .split('-')[0]\n      .split('.')\n      .map((part) => Number.parseInt(part, 10));\n\n  const left = parse(a);\n  const right = parse(b);\n\n  if (left.some(Number.isNaN) || right.some(Number.isNaN)) return 0;\n\n  for (let i = 0; i < 3; i++) {\n    const diff = (left[i] ?? 0) - (right[i] ?? 0);\n    if (diff !== 0) return diff > 0 ? 1 : -1;\n  }\n  return 0;\n}\n\n// A prerelease (2.1.0-beta.1) must not be told it's behind the stable it precedes.\nfunction isPrerelease(version: string): boolean {\n  return version.includes('-');\n}\n\nexport async function fetchLatestVersion(): Promise<string | undefined> {\n  try {\n    const response = await axios.get(REGISTRY_URL, {\n      timeout: CHECK_TIMEOUT_MS,\n      headers: { Accept: 'application/vnd.npm.install-v1+json' },\n    });\n    const version = (response.data as { 'dist-tags'?: { latest?: unknown } })?.['dist-tags']?.latest;\n    return typeof version === 'string' ? version : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nexport async function checkForUpdate(currentVersion: string): Promise<string | undefined> {\n  // UNRESOLVED_VERSION means we could not read our own package.json. Comparing it\n  // would report \"Current: 0.0.0\" as a real upgrade on every run.\n  if (currentVersion === UNRESOLVED_VERSION) return undefined;\n  if (isPrerelease(currentVersion)) return undefined;\n\n  const cached = readCachedLatest();\n  const latest = cached ?? (await fetchLatestVersion());\n  if (!latest || isPrerelease(latest)) return undefined;\n  if (!cached) writeCachedLatest(latest);\n\n  return compareVersions(latest, currentVersion) > 0 ? latest : undefined;\n}\n\n// The check runs concurrently with the test run. When the run finishes first,\n// the notice is worth at most a brief wait, never the full request timeout,\n// which would make a fast suite appear to hang after its results are printed.\nconst SETTLE_GRACE_MS = 150;\n\nexport async function awaitUpdateResult(pending: Promise<string | undefined>): Promise<string | undefined> {\n  let timer: ReturnType<typeof setTimeout> | undefined;\n  const grace = new Promise<undefined>((resolve) => {\n    timer = setTimeout(() => resolve(undefined), SETTLE_GRACE_MS);\n    timer.unref?.();\n  });\n\n  try {\n    return await Promise.race([pending.catch(() => undefined), grace]);\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nexport { getPackageVersion };\n","import type { FullResult } from '@playwright/test/reporter';\nimport type { RunMetadata } from '../types/index.js';\nimport type { Logger } from '../utils/logger.js';\nimport { colors, symbols, box, pad, fit, formatDuration } from '../utils/ui.js';\nimport { buildUpdateNoticeLines } from '../utils/update-notifier.js';\n\n// Summary box dimensions\nconst BOX_WIDTH = 72;\nconst LABEL_WIDTH = 11;\n\nexport interface ReporterLogOptions {\n  debug: boolean;\n}\n\nexport interface RunSummaryData {\n  runId: string;\n  runMetadata: RunMetadata | null;\n  testCounts: {\n    passed: number;\n    failed: number;\n    skipped: number;\n    timedOut: number;\n    interrupted: number;\n    flaky: number;\n    retried: number;\n  };\n  artifactCounts: {\n    screenshots: number;\n    videos: number;\n    traces: number;\n    other: number;\n    unavailable: number;\n  };\n  artifactsDisabled?: boolean;\n  totalTests: number;\n  workerCount: number;\n  projectNames: Set<string>;\n  shardInfo?: { current: number; total: number };\n  runUrl?: string;\n}\n\ntype BoxRow = (content: string) => string;\ntype BoxLabel = (text: string) => string;\n\nfunction createBoxHelpers(): {\n  row: BoxRow;\n  label: BoxLabel;\n  topBorder: string;\n  bottomBorder: string;\n  divider: string;\n} {\n  const topBorder = `  ${colors.dim(`\\u250C${'\\u2500'.repeat(BOX_WIDTH)}\\u2510`)}`;\n  const bottomBorder = `  ${colors.dim(`\\u2514${'\\u2500'.repeat(BOX_WIDTH)}\\u2518`)}`;\n  const divider = `  ${colors.dim(`\\u251C${'\\u2500'.repeat(BOX_WIDTH)}\\u2524`)}`;\n  const row: BoxRow = (content) => `  ${colors.dim('\\u2502')} ${fit(content, BOX_WIDTH - 1)}${colors.dim('\\u2502')}`;\n  const label: BoxLabel = (text) => colors.dim(pad(text, LABEL_WIDTH));\n  return { row, label, topBorder, bottomBorder, divider };\n}\n\nfunction printArtifactsRow(\n  row: BoxRow,\n  label: BoxLabel,\n  counts: RunSummaryData['artifactCounts'],\n  isSharded: boolean,\n  artifactsDisabled?: boolean\n): void {\n  // Dim, not the warning-yellow \"unavailable\" row: an opt-out is not a failure.\n  if (artifactsDisabled) {\n    console.log(row(`${label('Artifacts')}${colors.dim('not configured (artifacts: false)')}`));\n    return;\n  }\n\n  const uploaded = counts.screenshots + counts.videos + counts.traces + counts.other;\n  if (uploaded === 0 && counts.unavailable === 0) return;\n\n  const parts: string[] = [];\n  if (counts.screenshots > 0) parts.push(`${counts.screenshots} screenshots`);\n  if (counts.videos > 0) parts.push(`${counts.videos} videos`);\n  if (counts.traces > 0) parts.push(`${counts.traces} traces`);\n  if (counts.other > 0) parts.push(`${counts.other} other`);\n\n  const summary = parts.length > 0 ? parts.join(colors.dim(' · ')) : colors.dim('none uploaded');\n  const failed = counts.unavailable > 0 ? `  ${colors.warning(`${counts.unavailable} unavailable`)}` : '';\n  // Each shard reports its own totals; without this the row reads as whole-run.\n  const scope = isSharded ? `  ${colors.dim('(this shard)')}` : '';\n  console.log(row(`${label('Artifacts')}${summary}${failed}${scope}`));\n}\n\nfunction printResultsSection(row: BoxRow, label: BoxLabel, result: FullResult, data: RunSummaryData): void {\n  const statusColor =\n    result.status === 'passed' ? colors.success : result.status === 'failed' ? colors.error : colors.warning;\n  const statusLabel = result.status === 'timedout' ? 'timed out' : result.status;\n  console.log(\n    row(`${label('Status')}${statusColor(statusLabel.toUpperCase())}  ${colors.dim(formatDuration(result.duration))}`)\n  );\n\n  const counts: string[] = [];\n  if (data.testCounts.passed > 0) counts.push(colors.success(`${data.testCounts.passed} passed`));\n  if (data.testCounts.failed > 0) counts.push(colors.error(`${data.testCounts.failed} failed`));\n  if (data.testCounts.flaky > 0) counts.push(colors.warning(`${data.testCounts.flaky} flaky`));\n  if (data.testCounts.skipped > 0) counts.push(colors.dim(`${data.testCounts.skipped} skipped`));\n  if (data.testCounts.timedOut > 0) counts.push(colors.error(`${data.testCounts.timedOut} timed out`));\n  if (data.testCounts.interrupted > 0) counts.push(colors.warning(`${data.testCounts.interrupted} interrupted`));\n  const retriedStr = data.testCounts.retried > 0 ? `  ${colors.dim(`(${data.testCounts.retried} retries)`)}` : '';\n  console.log(\n    row(\n      `${label('Results')}${counts.join(colors.dim(' \\u00B7 '))}  ${colors.dim(`of ${data.totalTests}`)}${retriedStr}`\n    )\n  );\n}\n\nfunction printRunSummary(result: FullResult, data: RunSummaryData): void {\n  const { row, label, topBorder, bottomBorder, divider } = createBoxHelpers();\n\n  console.log('');\n  console.log(topBorder);\n  console.log(row(colors.bold('TestDino Run Summary')));\n  console.log(divider);\n\n  // Run & Git\n  console.log(row(`${label('Run')}${data.runId}`));\n  const git = data.runMetadata?.git;\n  if (git?.branch || git?.commit?.hash) {\n    const branch = git.branch ? colors.info(git.branch) : '';\n    const sha = git.commit?.hash ? ` ${colors.dim('@')} ${colors.dim(git.commit.hash.slice(0, 7))}` : '';\n    const msg = git.commit?.message ? `  ${colors.dim(git.commit.message.split('\\n')[0].slice(0, 40))}` : '';\n    console.log(row(`${label('Git')}${branch}${sha}${msg}`));\n  }\n\n  console.log(divider);\n  printResultsSection(row, label, result, data);\n  console.log(divider);\n\n  // Workers, Shard, Projects\n  const shardStr = data.shardInfo ? `${data.shardInfo.current}/${data.shardInfo.total}` : '\\u2014';\n  console.log(\n    row(\n      `${label('Workers')}${pad(String(data.workerCount > 0 ? data.workerCount : '\\u2014'), 14)}` +\n        `${colors.dim(pad('Shard', 8))}${shardStr}`\n    )\n  );\n  console.log(\n    row(`${label('Projects')}${data.projectNames.size > 0 ? Array.from(data.projectNames).join(', ') : '\\u2014'}`)\n  );\n\n  printArtifactsRow(row, label, data.artifactCounts, Boolean(data.shardInfo), data.artifactsDisabled);\n\n  console.log(bottomBorder);\n\n  // Outside the box: `fit` would truncate a run URL past BOX_WIDTH.\n  if (data.runUrl) {\n    console.log('');\n    console.log(`  ${colors.dim('View run')}  ${data.runUrl}`);\n  }\n\n  console.log('');\n}\n\nconst RUN_LINK_FALLBACK_WIDTH = 100;\n\n// Rules, not a box: nothing sits right of the URL, so it is never split —\n// terminals only linkify an unbroken string.\nfunction printRunLinkBox(url: string): void {\n  const width = process.stdout.columns ?? RUN_LINK_FALLBACK_WIDTH;\n  // Indent plus a spare column: filling the width exactly makes it wrap.\n  const rule = colors.info(symbols.line.repeat(Math.max(1, width - 4)));\n  console.log('');\n  console.log(`  ${rule}`);\n  console.log('');\n  console.log(`  ${colors.blue(symbols.info)} ${colors.bold('See live results')}`);\n  console.log('');\n  console.log(`  ${colors.url(url)}`);\n  console.log('');\n  console.log(`  ${rule}`);\n  console.log('');\n}\n\nfunction printUpdateNotice(currentVersion: string, latestVersion: string): void {\n  console.log(box(buildUpdateNoticeLines(currentVersion, latestVersion), { borderColor: 'white' }));\n  console.log('');\n}\n\nexport function createReporterLog(options: ReporterLogOptions): ReporterLog {\n  return {\n    success: (msg: string) => console.log(`  ${colors.success(symbols.success)} ${msg}`),\n    warn: (msg: string) => console.warn(`  ${colors.warning(symbols.warning)} ${colors.warning(msg)}`),\n    error: (msg: string) => console.error(`  ${colors.error(symbols.error)} ${colors.error(msg)}`),\n    info: (msg: string) => console.log(`  ${colors.info(symbols.info)} ${msg}`),\n    debug: (msg: string) => {\n      if (options.debug) {\n        console.log(`  ${colors.dim(symbols.debug)} ${colors.dim(msg)}`);\n      }\n    },\n    runLink: (url: string) => printRunLinkBox(url),\n    printRunSummary,\n    printUpdateNotice,\n  };\n}\n\nexport type ReporterLog = Logger & {\n  runLink(url: string): void;\n  printRunSummary(result: FullResult, data: RunSummaryData): void;\n  printUpdateNotice(currentVersion: string, latestVersion: string): void;\n};\n","export const HEARTBEAT_POLL_INTERVAL_MS = 30_000;\nexport const HEARTBEAT_SILENCE_THRESHOLD_MS = 60_000;\n\n// Ingestion's stall detection budgets for this many ms between deliveries of a\n// silent live run (docs/HEARTBEAT.md, \"Contract with ingestion\").\nexport const HEARTBEAT_MAX_GAP_MS = 90_000;\n"],"mappings":"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","names":["readFileSync","writeFileSync","readFile","version","readFile","version","readFile","axios","axios","message","axios","readFileSync","join","PACKAGE_NAME","join","readFileSync","version","axios","readFileSync","writeFileSync","fetch","readFile"]}