@ait-co/devtools 0.1.131 → 0.1.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{attach-orchestrator-ca34r46y.js → attach-orchestrator-CE0S09YU.js} +110 -5
- package/dist/attach-orchestrator-CE0S09YU.js.map +1 -0
- package/dist/{attach-orchestrator-BiaYiNOr.js → attach-orchestrator-CMoDuG2A.js} +110 -5
- package/dist/attach-orchestrator-CMoDuG2A.js.map +1 -0
- package/dist/cell-BIdSQb9T.js +201 -0
- package/dist/cell-BIdSQb9T.js.map +1 -0
- package/dist/{cell-Cw4fVOl2.js → cell-D1y4shoV.js} +1 -21
- package/dist/cell-D1y4shoV.js.map +1 -0
- package/dist/cell-DHA578lX.js +200 -0
- package/dist/cell-DHA578lX.js.map +1 -0
- package/dist/{debug-server-qRSRG7YZ.js → debug-server-CS1BS2BX.js} +21 -3
- package/dist/debug-server-CS1BS2BX.js.map +1 -0
- package/dist/{debug-server-BSbfnFR5.js → debug-server-DmzuK2c6.js} +26 -9
- package/dist/debug-server-DmzuK2c6.js.map +1 -0
- package/dist/{debug-server-CD4zYBq4.js → debug-server-DnNCoNiR.js} +7 -7
- package/dist/{debug-server-CD4zYBq4.js.map → debug-server-DnNCoNiR.js.map} +1 -1
- package/dist/mcp/cli.js +180 -8
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/panel/index.js +1 -1
- package/dist/{pool-BaSCZALv.d.ts → pool-x28Wv1ty.d.ts} +16 -2
- package/dist/{pool-BaSCZALv.d.ts.map → pool-x28Wv1ty.d.ts.map} +1 -1
- package/dist/{qr-http-server-DCbjORFa.js → qr-http-server-C_DTp9WU.js} +3 -2
- package/dist/{qr-http-server-DCbjORFa.js.map → qr-http-server-C_DTp9WU.js.map} +1 -1
- package/dist/{qr-http-server-BxoRp2w7.cjs → qr-http-server-DX_9UA-p.cjs} +3 -2
- package/dist/qr-http-server-DX_9UA-p.cjs.map +1 -0
- package/dist/{qr-http-server-BdNGPRoL.js → qr-http-server-DeRrKp_R.js} +3 -2
- package/dist/{qr-http-server-BdNGPRoL.js.map → qr-http-server-DeRrKp_R.js.map} +1 -1
- package/dist/{qr-http-server-cKbciY5k.js → qr-http-server-FVn61xAq.js} +3 -2
- package/dist/{qr-http-server-Bq9zR7-z.js.map → qr-http-server-FVn61xAq.js.map} +1 -1
- package/dist/{qr-http-server-Bq9zR7-z.js → qr-http-server-V0xuU5TJ.js} +3 -2
- package/dist/{qr-http-server-cKbciY5k.js.map → qr-http-server-V0xuU5TJ.js.map} +1 -1
- package/dist/{qr-http-server-CV6TA9ZN.cjs → qr-http-server-iH_Hh_si.cjs} +3 -2
- package/dist/qr-http-server-iH_Hh_si.cjs.map +1 -0
- package/dist/{relay-factory-Cloog1jb.js → relay-factory-BQfmK7RP.js} +14 -8
- package/dist/relay-factory-BQfmK7RP.js.map +1 -0
- package/dist/{relay-secret-store-CFc9n0OA.js → relay-secret-store-CLEGyHou.js} +2 -2
- package/dist/{relay-secret-store-CFc9n0OA.js.map → relay-secret-store-CLEGyHou.js.map} +1 -1
- package/dist/{relay-secret-store-DzxDsK6S.js → relay-secret-store-DGduVJhs.js} +2 -2
- package/dist/{relay-secret-store-DzxDsK6S.js.map → relay-secret-store-DGduVJhs.js.map} +1 -1
- package/dist/{relay-url-store-D3rY-GJJ.js → relay-url-store-B0X8TsGr.js} +2 -2
- package/dist/{relay-url-store-D3rY-GJJ.js.map → relay-url-store-B0X8TsGr.js.map} +1 -1
- package/dist/{relay-url-store-DGQ-HPQC.js → relay-url-store-CKW8RQzf.js} +2 -2
- package/dist/{relay-url-store-DGQ-HPQC.js.map → relay-url-store-CKW8RQzf.js.map} +1 -1
- package/dist/{relay-worker-o0M2ndyJ.d.ts → relay-worker-DtX_eszH.d.ts} +51 -2
- package/dist/relay-worker-DtX_eszH.d.ts.map +1 -0
- package/dist/{relay-worker-CCAHLC4a.js → relay-worker-MZq4fLv8.js} +27 -6
- package/dist/{relay-worker-CCAHLC4a.js.map → relay-worker-MZq4fLv8.js.map} +1 -1
- package/dist/rolldown-runtime-DGkTqVfb.js +15 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/test-runner/bin.js +173 -119
- package/dist/test-runner/bin.js.map +1 -1
- package/dist/test-runner/config.d.ts +1 -1
- package/dist/test-runner/config.js +1 -1
- package/dist/test-runner/pool.d.ts +1 -1
- package/dist/test-runner/pool.js +1 -1
- package/dist/test-runner/pool.js.map +1 -1
- package/dist/test-runner/relay-factory.d.ts +14 -0
- package/dist/test-runner/relay-factory.d.ts.map +1 -1
- package/dist/test-runner/relay-factory.js +11 -5
- package/dist/test-runner/relay-factory.js.map +1 -1
- package/dist/test-runner/relay-worker.d.ts +2 -2
- package/dist/test-runner/relay-worker.js +2 -2
- package/dist/test-runner/report.d.ts +35 -4
- package/dist/test-runner/report.d.ts.map +1 -1
- package/dist/test-runner/report.js +42 -7
- package/dist/test-runner/report.js.map +1 -1
- package/dist/{totp-DvOYkYim.js → totp-CZLLKfOC.js} +2 -14
- package/dist/{totp-DvOYkYim.js.map → totp-CZLLKfOC.js.map} +1 -1
- package/dist/totp-DAxys-r0.js +199 -0
- package/dist/totp-DAxys-r0.js.map +1 -0
- package/dist/{tunnel-B2UCKAc7.cjs → tunnel-DP453L4e.cjs} +2 -2
- package/dist/{tunnel-B2UCKAc7.cjs.map → tunnel-DP453L4e.cjs.map} +1 -1
- package/dist/{tunnel-C-rQ34dM.js → tunnel-Djf-zmjJ.js} +2 -2
- package/dist/{tunnel-C-rQ34dM.js.map → tunnel-Djf-zmjJ.js.map} +1 -1
- package/dist/unplugin/index.cjs +1 -1
- package/dist/unplugin/index.js +1 -1
- package/dist/unplugin/tunnel.cjs +1 -1
- package/dist/unplugin/tunnel.js +1 -1
- package/package.json +1 -1
- package/dist/attach-orchestrator-BiaYiNOr.js.map +0 -1
- package/dist/attach-orchestrator-ca34r46y.js.map +0 -1
- package/dist/cell-Bi8MAPA8.js +0 -88
- package/dist/cell-Bi8MAPA8.js.map +0 -1
- package/dist/cell-Cw4fVOl2.js.map +0 -1
- package/dist/cell-rr6gL9AT.js +0 -89
- package/dist/cell-rr6gL9AT.js.map +0 -1
- package/dist/debug-server-BSbfnFR5.js.map +0 -1
- package/dist/debug-server-qRSRG7YZ.js.map +0 -1
- package/dist/log-CUik_tHp.js +0 -95
- package/dist/log-CUik_tHp.js.map +0 -1
- package/dist/qr-http-server-BxoRp2w7.cjs.map +0 -1
- package/dist/qr-http-server-CV6TA9ZN.cjs.map +0 -1
- package/dist/relay-factory-Cloog1jb.js.map +0 -1
- package/dist/relay-worker-o0M2ndyJ.d.ts.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-
|
|
1
|
+
import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-x28Wv1ty.js";
|
|
2
2
|
|
|
3
3
|
//#region src/test-runner/relay-factory.d.ts
|
|
4
4
|
/** Options for {@link createRelayConnectionFactory}. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RELAY_POOL_NAME, createRelayPool } from "./pool.js";
|
|
2
|
-
import { t as createRelayConnectionFactory } from "../relay-factory-
|
|
2
|
+
import { t as createRelayConnectionFactory } from "../relay-factory-BQfmK7RP.js";
|
|
3
3
|
//#region src/test-runner/config.ts
|
|
4
4
|
const DEFAULT_CONFIG = {
|
|
5
5
|
include: ["**/*.ait.test.ts"],
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-
|
|
1
|
+
import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-x28Wv1ty.js";
|
|
2
2
|
export { RELAY_POOL_NAME, RelayConnectionFactory, RelayPoolOptions, createRelayPool };
|
package/dist/test-runner/pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as runTestFilesOverRelay } from "../relay-worker-MZq4fLv8.js";
|
|
2
2
|
import { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from "./task-graph.js";
|
|
3
3
|
//#region src/test-runner/pool.ts
|
|
4
4
|
/** The pool name Vitest matches against `getFilePoolName(project)`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.js","names":[],"sources":["../../src/test-runner/pool.ts"],"sourcesContent":["/**\n * Vitest 4.x custom pool: runs mini-app tests on a real device WebView over a\n * CDP relay instead of in a Node child process.\n *\n * Vitest's pool abstraction lets a `PoolRunnerInitializer` create a `PoolWorker`\n * that the core drives via a `WorkerRequest`/`WorkerResponse` message protocol.\n * Built-in pools (`forks`/`threads`) fork a child process; the `typecheck` pool\n * runs in-process and handles messages synchronously. We follow the in-process\n * `TypecheckPoolWorker` shape: a single long-lived \"worker\" that, on a `run`\n * request, bundles + injects + collects each file over the relay (#644's\n * `runTestFilesOverRelay`), synthesises a Vitest task graph (`task-graph.ts`),\n * and reports it through `vitest.state` so reporters/watch/UI/snapshot all work.\n *\n * Single-attach constraint: the relay supports one active page, so we keep one\n * worker for the whole run (`isolate: false`) rather than starting/stopping per\n * file — per-file start/stop would re-attach the relay on every file.\n *\n * SECRET-HANDLING: the relay connection (wss/TOTP) is supplied by the caller's\n * factory and never logged here; bundle code and result values are not logged.\n */\n\nimport type { PoolOptions, PoolWorker, TestProject, WorkerRequest } from 'vitest/node';\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RelayRunOptions } from './relay-worker.js';\nimport { runTestFilesOverRelay } from './relay-worker.js';\nimport { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from './task-graph.js';\n\n/** The pool name Vitest matches against `getFilePoolName(project)`. */\nexport const RELAY_POOL_NAME = 'ait-relay';\n\n/**\n * Factory the caller provides to open (and later close) the CDP relay\n * connection. Called once per worker lifecycle (`start`). The returned\n * `close` runs on `stop`.\n *\n * Kept as a factory (not a live connection) so the pool can be constructed in\n * config before any device is attached, and so `start`/`stop` own the lifecycle.\n */\nexport interface RelayConnectionFactory {\n /** Opens the relay connection. Resolves once the page is attached & ready. */\n open(): Promise<CdpConnection>;\n /** Closes the relay connection opened by {@link open}. */\n close(connection: CdpConnection): Promise<void>;\n /**\n * CLI-only session-phase hook (#730) — drives the QR dashboard's `phase`\n * field (`'running'` on run start, `'complete'` on run end) so the\n * dashboard can push an immediate SSE update instead of waiting for a\n * poll/watchdog. The pool (this file) has no equivalent lifecycle and\n * omits it; only `createRelayConnectionFactory` (relay-factory.ts) sets it.\n */\n onSessionPhase?(phase: 'running' | 'complete'): void;\n}\n\n/** Options for {@link createRelayPool}. */\nexport interface RelayPoolOptions {\n /** Opens/closes the relay connection. */\n connection: RelayConnectionFactory;\n /** Forwarded to `runTestFilesOverRelay` (bundle options, per-file timeout). */\n run?: RelayRunOptions;\n}\n\n/* -------------------------------------------------------------------------- */\n/* WorkerResponse helpers */\n/* -------------------------------------------------------------------------- */\n\n/** Minimal `WorkerResponse` shape we emit. Matches vitest/node's union. */\ntype EmittedResponse =\n | { __vitest_worker_response__: true; type: 'started'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'stopped'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'testfileFinished'; error?: unknown };\n\n/* -------------------------------------------------------------------------- */\n/* The in-process relay PoolWorker */\n/* -------------------------------------------------------------------------- */\n\n/**\n * In-process `PoolWorker` backed by a CDP relay. Mirrors `TypecheckPoolWorker`:\n * `send` handles the message in-process and emits a `WorkerResponse` via the\n * `'message'` listener registered by the core's pool driver.\n */\nclass RelayPoolWorker implements PoolWorker {\n readonly name = RELAY_POOL_NAME;\n readonly cacheFs = false;\n\n private readonly project: TestProject;\n private readonly factory: RelayConnectionFactory;\n private readonly runOpts: RelayRunOptions | undefined;\n private readonly listeners = new Map<string, Set<(arg: unknown) => void>>();\n private connection: CdpConnection | undefined;\n\n constructor(project: TestProject, opts: RelayPoolOptions) {\n this.project = project;\n this.factory = opts.connection;\n this.runOpts = opts.run;\n }\n\n on(event: string, callback: (arg: unknown) => void): void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(callback);\n }\n\n off(event: string, callback: (arg: unknown) => void): void {\n this.listeners.get(event)?.delete(callback);\n }\n\n private emit(event: string, arg: unknown): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const cb of set) cb(arg);\n }\n\n deserialize(data: unknown): unknown {\n // Relay results arrive as plain JSON objects already — identity is correct.\n return data;\n }\n\n async start(): Promise<void> {\n // Lifecycle ownership lives here, but the connection is opened lazily on the\n // first `run`/`collect` so a never-run worker never touches the device.\n }\n\n async stop(): Promise<void> {\n if (this.connection) {\n const conn = this.connection;\n this.connection = undefined;\n await this.factory.close(conn);\n }\n }\n\n send(message: WorkerRequest): void {\n // Fire-and-forget like TypecheckPoolWorker: handle async, emit on settle.\n void this.handle(message).then((response) => {\n if (response) this.emit('message', response);\n });\n }\n\n private async handle(message: WorkerRequest): Promise<EmittedResponse | undefined> {\n switch (message.type) {\n case 'start':\n return { __vitest_worker_response__: true, type: 'started' };\n case 'run':\n case 'collect': {\n const files = message.context.files.map((s) => s.filepath);\n const error = await this.runFiles(files).catch((e) => e);\n return { __vitest_worker_response__: true, type: 'testfileFinished', error };\n }\n case 'stop':\n return { __vitest_worker_response__: true, type: 'stopped' };\n case 'cancel':\n return undefined;\n }\n }\n\n /**\n * Bundles + injects + collects the given files over the relay, synthesises a\n * Vitest task graph per file, and reports it through `vitest.state` so the\n * reporter/watch/UI ecosystem sees real results.\n *\n * Returns nothing on success; a thrown error is surfaced as the\n * `testfileFinished` error (a whole-pool failure, e.g. relay unreachable).\n */\n private async runFiles(files: string[]): Promise<void> {\n const conn = await this.ensureConnection();\n const report = await runTestFilesOverRelay(conn, files, this.runOpts);\n\n const root = this.project.config.root;\n const projectName = this.project.name || undefined;\n const state = this.project.vitest.state;\n\n for (const fileResult of report.files) {\n const perFile =\n 'error' in fileResult.result\n ? // Whole-file bundle/inject error → synthesise a failed file with no tests.\n {\n startedAt: report.startedAt,\n duration: 0,\n passed: 0,\n failed: 1,\n skipped: 0,\n tests: [],\n }\n : fileResult.result;\n\n const fileTask = synthesizeFileTask(\n fileResult.file,\n root,\n projectName,\n RELAY_POOL_NAME,\n perFile,\n );\n\n state.collectFiles(this.project, [fileTask]);\n state.updateTasks(toTaskResultPacks(fileTask));\n // Event packs drive reporter progress; updateTasks already recorded\n // results, so events are advisory but keep watch/UI output coherent.\n void toTaskEventPacks(fileTask);\n }\n }\n\n private async ensureConnection(): Promise<CdpConnection> {\n if (!this.connection) {\n this.connection = await this.factory.open();\n }\n return this.connection;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* PoolRunnerInitializer factory */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Creates the Vitest `PoolRunnerInitializer` for the relay pool.\n *\n * Wire it into a Vitest config as `pool: createRelayPool({ connection })`.\n * Vitest moves an object `pool` into `config.poolRunner` and dispatches files\n * whose pool name equals `RELAY_POOL_NAME` to our `createPoolWorker`.\n *\n * @example\n * // vitest.config.ts\n * import { createRelayPool } from '@ait-co/devtools/test-runner';\n * export default defineConfig({\n * test: { pool: createRelayPool({ connection: myFactory }) },\n * });\n */\nexport function createRelayPool(opts: RelayPoolOptions): {\n readonly name: string;\n createPoolWorker: (options: PoolOptions) => PoolWorker;\n} {\n return {\n name: RELAY_POOL_NAME,\n createPoolWorker(options: PoolOptions): PoolWorker {\n return new RelayPoolWorker(options.project, opts);\n },\n };\n}\n"],"mappings":";;;;AA4BA,MAAa,kBAAkB;;;;;;AAoD/B,IAAM,kBAAN,MAA4C;CAC1C,OAAgB;CAChB,UAAmB;CAEnB;CACA;CACA;CACA,4BAA6B,IAAI,KAA0C;CAC3E;CAEA,YAAY,SAAsB,MAAwB;AACxD,OAAK,UAAU;AACf,OAAK,UAAU,KAAK;AACpB,OAAK,UAAU,KAAK;;CAGtB,GAAG,OAAe,UAAwC;EACxD,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM;AACnC,MAAI,CAAC,KAAK;AACR,yBAAM,IAAI,KAAK;AACf,QAAK,UAAU,IAAI,OAAO,IAAI;;AAEhC,MAAI,IAAI,SAAS;;CAGnB,IAAI,OAAe,UAAwC;AACzD,OAAK,UAAU,IAAI,MAAM,EAAE,OAAO,SAAS;;CAG7C,KAAa,OAAe,KAAoB;EAC9C,MAAM,MAAM,KAAK,UAAU,IAAI,MAAM;AACrC,MAAI,CAAC,IAAK;AACV,OAAK,MAAM,MAAM,IAAK,IAAG,IAAI;;CAG/B,YAAY,MAAwB;AAElC,SAAO;;CAGT,MAAM,QAAuB;CAK7B,MAAM,OAAsB;AAC1B,MAAI,KAAK,YAAY;GACnB,MAAM,OAAO,KAAK;AAClB,QAAK,aAAa,KAAA;AAClB,SAAM,KAAK,QAAQ,MAAM,KAAK;;;CAIlC,KAAK,SAA8B;AAE5B,OAAK,OAAO,QAAQ,CAAC,MAAM,aAAa;AAC3C,OAAI,SAAU,MAAK,KAAK,WAAW,SAAS;IAC5C;;CAGJ,MAAc,OAAO,SAA8D;AACjF,UAAQ,QAAQ,MAAhB;GACE,KAAK,QACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK;GACL,KAAK,WAAW;IACd,MAAM,QAAQ,QAAQ,QAAQ,MAAM,KAAK,MAAM,EAAE,SAAS;AAE1D,WAAO;KAAE,4BAA4B;KAAM,MAAM;KAAoB,OADvD,MAAM,KAAK,SAAS,MAAM,CAAC,OAAO,MAAM,EAAE;KACoB;;GAE9E,KAAK,OACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK,SACH;;;;;;;;;;;CAYN,MAAc,SAAS,OAAgC;EAErD,MAAM,SAAS,MAAM,sBADR,MAAM,KAAK,kBAAkB,EACO,OAAO,KAAK,QAAQ;EAErE,MAAM,OAAO,KAAK,QAAQ,OAAO;EACjC,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAA;EACzC,MAAM,QAAQ,KAAK,QAAQ,OAAO;AAElC,OAAK,MAAM,cAAc,OAAO,OAAO;GACrC,MAAM,UACJ,WAAW,WAAW,SAElB;IACE,WAAW,OAAO;IAClB,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO,EAAE;IACV,GACD,WAAW;GAEjB,MAAM,WAAW,mBACf,WAAW,MACX,MACA,aACA,iBACA,QACD;AAED,SAAM,aAAa,KAAK,SAAS,CAAC,SAAS,CAAC;AAC5C,SAAM,YAAY,kBAAkB,SAAS,CAAC;AAGzC,oBAAiB,SAAS;;;CAInC,MAAc,mBAA2C;AACvD,MAAI,CAAC,KAAK,WACR,MAAK,aAAa,MAAM,KAAK,QAAQ,MAAM;AAE7C,SAAO,KAAK;;;;;;;;;;;;;;;;;AAsBhB,SAAgB,gBAAgB,MAG9B;AACA,QAAO;EACL,MAAM;EACN,iBAAiB,SAAkC;AACjD,UAAO,IAAI,gBAAgB,QAAQ,SAAS,KAAK;;EAEpD"}
|
|
1
|
+
{"version":3,"file":"pool.js","names":[],"sources":["../../src/test-runner/pool.ts"],"sourcesContent":["/**\n * Vitest 4.x custom pool: runs mini-app tests on a real device WebView over a\n * CDP relay instead of in a Node child process.\n *\n * Vitest's pool abstraction lets a `PoolRunnerInitializer` create a `PoolWorker`\n * that the core drives via a `WorkerRequest`/`WorkerResponse` message protocol.\n * Built-in pools (`forks`/`threads`) fork a child process; the `typecheck` pool\n * runs in-process and handles messages synchronously. We follow the in-process\n * `TypecheckPoolWorker` shape: a single long-lived \"worker\" that, on a `run`\n * request, bundles + injects + collects each file over the relay (#644's\n * `runTestFilesOverRelay`), synthesises a Vitest task graph (`task-graph.ts`),\n * and reports it through `vitest.state` so reporters/watch/UI/snapshot all work.\n *\n * Single-attach constraint: the relay supports one active page, so we keep one\n * worker for the whole run (`isolate: false`) rather than starting/stopping per\n * file — per-file start/stop would re-attach the relay on every file.\n *\n * SECRET-HANDLING: the relay connection (wss/TOTP) is supplied by the caller's\n * factory and never logged here; bundle code and result values are not logged.\n */\n\nimport type { PoolOptions, PoolWorker, TestProject, WorkerRequest } from 'vitest/node';\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RelayRunOptions } from './relay-worker.js';\nimport { runTestFilesOverRelay } from './relay-worker.js';\nimport { synthesizeFileTask, toTaskEventPacks, toTaskResultPacks } from './task-graph.js';\n\n/** The pool name Vitest matches against `getFilePoolName(project)`. */\nexport const RELAY_POOL_NAME = 'ait-relay';\n\n/**\n * Factory the caller provides to open (and later close) the CDP relay\n * connection. Called once per worker lifecycle (`start`). The returned\n * `close` runs on `stop`.\n *\n * Kept as a factory (not a live connection) so the pool can be constructed in\n * config before any device is attached, and so `start`/`stop` own the lifecycle.\n */\nexport interface RelayConnectionFactory {\n /** Opens the relay connection. Resolves once the page is attached & ready. */\n open(): Promise<CdpConnection>;\n /** Closes the relay connection opened by {@link open}. */\n close(connection: CdpConnection): Promise<void>;\n /**\n * CLI-only session-phase hook (#730) — drives the QR dashboard's `phase`\n * field (`'running'` on run start, `'complete'` on run end) so the\n * dashboard can push an immediate SSE update instead of waiting for a\n * poll/watchdog. The pool (this file) has no equivalent lifecycle and\n * omits it; only `createRelayConnectionFactory` (relay-factory.ts) sets it.\n */\n onSessionPhase?(phase: 'running' | 'complete'): void;\n /**\n * CLI-only manual-blocking prompt hook (devtools#741) — pushes the QR\n * dashboard's `manualPrompt` field before each manual-tagged file is\n * injected, so a human watching the dashboard sees which file is next and\n * how far along the manual queue is. Pass `null` to clear the prompt (the\n * CLI does this once all manual files have run). The pool has no\n * equivalent lifecycle and omits it; only `createRelayConnectionFactory`\n * sets it.\n */\n onManualPrompt?(prompt: { file: string; index: number; total: number } | null): void;\n}\n\n/** Options for {@link createRelayPool}. */\nexport interface RelayPoolOptions {\n /** Opens/closes the relay connection. */\n connection: RelayConnectionFactory;\n /** Forwarded to `runTestFilesOverRelay` (bundle options, per-file timeout). */\n run?: RelayRunOptions;\n}\n\n/* -------------------------------------------------------------------------- */\n/* WorkerResponse helpers */\n/* -------------------------------------------------------------------------- */\n\n/** Minimal `WorkerResponse` shape we emit. Matches vitest/node's union. */\ntype EmittedResponse =\n | { __vitest_worker_response__: true; type: 'started'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'stopped'; error?: unknown }\n | { __vitest_worker_response__: true; type: 'testfileFinished'; error?: unknown };\n\n/* -------------------------------------------------------------------------- */\n/* The in-process relay PoolWorker */\n/* -------------------------------------------------------------------------- */\n\n/**\n * In-process `PoolWorker` backed by a CDP relay. Mirrors `TypecheckPoolWorker`:\n * `send` handles the message in-process and emits a `WorkerResponse` via the\n * `'message'` listener registered by the core's pool driver.\n */\nclass RelayPoolWorker implements PoolWorker {\n readonly name = RELAY_POOL_NAME;\n readonly cacheFs = false;\n\n private readonly project: TestProject;\n private readonly factory: RelayConnectionFactory;\n private readonly runOpts: RelayRunOptions | undefined;\n private readonly listeners = new Map<string, Set<(arg: unknown) => void>>();\n private connection: CdpConnection | undefined;\n\n constructor(project: TestProject, opts: RelayPoolOptions) {\n this.project = project;\n this.factory = opts.connection;\n this.runOpts = opts.run;\n }\n\n on(event: string, callback: (arg: unknown) => void): void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(callback);\n }\n\n off(event: string, callback: (arg: unknown) => void): void {\n this.listeners.get(event)?.delete(callback);\n }\n\n private emit(event: string, arg: unknown): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const cb of set) cb(arg);\n }\n\n deserialize(data: unknown): unknown {\n // Relay results arrive as plain JSON objects already — identity is correct.\n return data;\n }\n\n async start(): Promise<void> {\n // Lifecycle ownership lives here, but the connection is opened lazily on the\n // first `run`/`collect` so a never-run worker never touches the device.\n }\n\n async stop(): Promise<void> {\n if (this.connection) {\n const conn = this.connection;\n this.connection = undefined;\n await this.factory.close(conn);\n }\n }\n\n send(message: WorkerRequest): void {\n // Fire-and-forget like TypecheckPoolWorker: handle async, emit on settle.\n void this.handle(message).then((response) => {\n if (response) this.emit('message', response);\n });\n }\n\n private async handle(message: WorkerRequest): Promise<EmittedResponse | undefined> {\n switch (message.type) {\n case 'start':\n return { __vitest_worker_response__: true, type: 'started' };\n case 'run':\n case 'collect': {\n const files = message.context.files.map((s) => s.filepath);\n const error = await this.runFiles(files).catch((e) => e);\n return { __vitest_worker_response__: true, type: 'testfileFinished', error };\n }\n case 'stop':\n return { __vitest_worker_response__: true, type: 'stopped' };\n case 'cancel':\n return undefined;\n }\n }\n\n /**\n * Bundles + injects + collects the given files over the relay, synthesises a\n * Vitest task graph per file, and reports it through `vitest.state` so the\n * reporter/watch/UI ecosystem sees real results.\n *\n * Returns nothing on success; a thrown error is surfaced as the\n * `testfileFinished` error (a whole-pool failure, e.g. relay unreachable).\n */\n private async runFiles(files: string[]): Promise<void> {\n const conn = await this.ensureConnection();\n const report = await runTestFilesOverRelay(conn, files, this.runOpts);\n\n const root = this.project.config.root;\n const projectName = this.project.name || undefined;\n const state = this.project.vitest.state;\n\n for (const fileResult of report.files) {\n const perFile =\n 'error' in fileResult.result\n ? // Whole-file bundle/inject error → synthesise a failed file with no tests.\n {\n startedAt: report.startedAt,\n duration: 0,\n passed: 0,\n failed: 1,\n skipped: 0,\n tests: [],\n }\n : fileResult.result;\n\n const fileTask = synthesizeFileTask(\n fileResult.file,\n root,\n projectName,\n RELAY_POOL_NAME,\n perFile,\n );\n\n state.collectFiles(this.project, [fileTask]);\n state.updateTasks(toTaskResultPacks(fileTask));\n // Event packs drive reporter progress; updateTasks already recorded\n // results, so events are advisory but keep watch/UI output coherent.\n void toTaskEventPacks(fileTask);\n }\n }\n\n private async ensureConnection(): Promise<CdpConnection> {\n if (!this.connection) {\n this.connection = await this.factory.open();\n }\n return this.connection;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* PoolRunnerInitializer factory */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Creates the Vitest `PoolRunnerInitializer` for the relay pool.\n *\n * Wire it into a Vitest config as `pool: createRelayPool({ connection })`.\n * Vitest moves an object `pool` into `config.poolRunner` and dispatches files\n * whose pool name equals `RELAY_POOL_NAME` to our `createPoolWorker`.\n *\n * @example\n * // vitest.config.ts\n * import { createRelayPool } from '@ait-co/devtools/test-runner';\n * export default defineConfig({\n * test: { pool: createRelayPool({ connection: myFactory }) },\n * });\n */\nexport function createRelayPool(opts: RelayPoolOptions): {\n readonly name: string;\n createPoolWorker: (options: PoolOptions) => PoolWorker;\n} {\n return {\n name: RELAY_POOL_NAME,\n createPoolWorker(options: PoolOptions): PoolWorker {\n return new RelayPoolWorker(options.project, opts);\n },\n };\n}\n"],"mappings":";;;;AA4BA,MAAa,kBAAkB;;;;;;AA8D/B,IAAM,kBAAN,MAA4C;CAC1C,OAAgB;CAChB,UAAmB;CAEnB;CACA;CACA;CACA,4BAA6B,IAAI,KAA0C;CAC3E;CAEA,YAAY,SAAsB,MAAwB;AACxD,OAAK,UAAU;AACf,OAAK,UAAU,KAAK;AACpB,OAAK,UAAU,KAAK;;CAGtB,GAAG,OAAe,UAAwC;EACxD,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM;AACnC,MAAI,CAAC,KAAK;AACR,yBAAM,IAAI,KAAK;AACf,QAAK,UAAU,IAAI,OAAO,IAAI;;AAEhC,MAAI,IAAI,SAAS;;CAGnB,IAAI,OAAe,UAAwC;AACzD,OAAK,UAAU,IAAI,MAAM,EAAE,OAAO,SAAS;;CAG7C,KAAa,OAAe,KAAoB;EAC9C,MAAM,MAAM,KAAK,UAAU,IAAI,MAAM;AACrC,MAAI,CAAC,IAAK;AACV,OAAK,MAAM,MAAM,IAAK,IAAG,IAAI;;CAG/B,YAAY,MAAwB;AAElC,SAAO;;CAGT,MAAM,QAAuB;CAK7B,MAAM,OAAsB;AAC1B,MAAI,KAAK,YAAY;GACnB,MAAM,OAAO,KAAK;AAClB,QAAK,aAAa,KAAA;AAClB,SAAM,KAAK,QAAQ,MAAM,KAAK;;;CAIlC,KAAK,SAA8B;AAE5B,OAAK,OAAO,QAAQ,CAAC,MAAM,aAAa;AAC3C,OAAI,SAAU,MAAK,KAAK,WAAW,SAAS;IAC5C;;CAGJ,MAAc,OAAO,SAA8D;AACjF,UAAQ,QAAQ,MAAhB;GACE,KAAK,QACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK;GACL,KAAK,WAAW;IACd,MAAM,QAAQ,QAAQ,QAAQ,MAAM,KAAK,MAAM,EAAE,SAAS;AAE1D,WAAO;KAAE,4BAA4B;KAAM,MAAM;KAAoB,OADvD,MAAM,KAAK,SAAS,MAAM,CAAC,OAAO,MAAM,EAAE;KACoB;;GAE9E,KAAK,OACH,QAAO;IAAE,4BAA4B;IAAM,MAAM;IAAW;GAC9D,KAAK,SACH;;;;;;;;;;;CAYN,MAAc,SAAS,OAAgC;EAErD,MAAM,SAAS,MAAM,sBADR,MAAM,KAAK,kBAAkB,EACO,OAAO,KAAK,QAAQ;EAErE,MAAM,OAAO,KAAK,QAAQ,OAAO;EACjC,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAA;EACzC,MAAM,QAAQ,KAAK,QAAQ,OAAO;AAElC,OAAK,MAAM,cAAc,OAAO,OAAO;GACrC,MAAM,UACJ,WAAW,WAAW,SAElB;IACE,WAAW,OAAO;IAClB,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO,EAAE;IACV,GACD,WAAW;GAEjB,MAAM,WAAW,mBACf,WAAW,MACX,MACA,aACA,iBACA,QACD;AAED,SAAM,aAAa,KAAK,SAAS,CAAC,SAAS,CAAC;AAC5C,SAAM,YAAY,kBAAkB,SAAS,CAAC;AAGzC,oBAAiB,SAAS;;;CAInC,MAAc,mBAA2C;AACvD,MAAI,CAAC,KAAK,WACR,MAAK,aAAa,MAAM,KAAK,QAAQ,MAAM;AAE7C,SAAO,KAAK;;;;;;;;;;;;;;;;;AAsBhB,SAAgB,gBAAgB,MAG9B;AACA,QAAO;EACL,MAAM;EACN,iBAAiB,SAAkC;AACjD,UAAO,IAAI,gBAAgB,QAAQ,SAAS,KAAK;;EAEpD"}
|
|
@@ -11072,6 +11072,20 @@ interface RelayConnectionFactory {
|
|
|
11072
11072
|
* omits it; only `createRelayConnectionFactory` (relay-factory.ts) sets it.
|
|
11073
11073
|
*/
|
|
11074
11074
|
onSessionPhase?(phase: 'running' | 'complete'): void;
|
|
11075
|
+
/**
|
|
11076
|
+
* CLI-only manual-blocking prompt hook (devtools#741) — pushes the QR
|
|
11077
|
+
* dashboard's `manualPrompt` field before each manual-tagged file is
|
|
11078
|
+
* injected, so a human watching the dashboard sees which file is next and
|
|
11079
|
+
* how far along the manual queue is. Pass `null` to clear the prompt (the
|
|
11080
|
+
* CLI does this once all manual files have run). The pool has no
|
|
11081
|
+
* equivalent lifecycle and omits it; only `createRelayConnectionFactory`
|
|
11082
|
+
* sets it.
|
|
11083
|
+
*/
|
|
11084
|
+
onManualPrompt?(prompt: {
|
|
11085
|
+
file: string;
|
|
11086
|
+
index: number;
|
|
11087
|
+
total: number;
|
|
11088
|
+
} | null): void;
|
|
11075
11089
|
}
|
|
11076
11090
|
//#endregion
|
|
11077
11091
|
//#region src/test-runner/relay-factory.d.ts
|