@ait-co/devtools 0.1.127 → 0.1.129

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.
Files changed (68) hide show
  1. package/dist/{attach-orchestrator-CpE0dMew.js → attach-orchestrator-Bdt5Zdo9.js} +3 -94
  2. package/dist/attach-orchestrator-Bdt5Zdo9.js.map +1 -0
  3. package/dist/{attach-orchestrator-CPMQWkGV.js → attach-orchestrator-DvrgUIx7.js} +4 -95
  4. package/dist/attach-orchestrator-DvrgUIx7.js.map +1 -0
  5. package/dist/{bundle-Cb3GFuw6.d.ts → bundle-BKqyhEK9.d.ts} +1 -1
  6. package/dist/{bundle-Cb3GFuw6.d.ts.map → bundle-BKqyhEK9.d.ts.map} +1 -1
  7. package/dist/{capture-B1zfGyTo.d.ts → capture-ltuV0gZa.d.ts} +1 -1
  8. package/dist/{capture-B1zfGyTo.d.ts.map → capture-ltuV0gZa.d.ts.map} +1 -1
  9. package/dist/{cdp-connection-Dxw_EY8s.d.ts → cdp-connection-D7AYQck2.d.ts} +1 -1
  10. package/dist/{cdp-connection-Dxw_EY8s.d.ts.map → cdp-connection-D7AYQck2.d.ts.map} +1 -1
  11. package/dist/{cell-D0dJSGHi.js → cell-DA_lcpDI.js} +2 -2
  12. package/dist/{cell-D0dJSGHi.js.map → cell-DA_lcpDI.js.map} +1 -1
  13. package/dist/{cell-CX92lDI0.js → cell-DLRv4iG6.js} +2 -2
  14. package/dist/{cell-CX92lDI0.js.map → cell-DLRv4iG6.js.map} +1 -1
  15. package/dist/{debug-server-Dctc9GAh.js → debug-server--Y0QZVJS.js} +57 -58
  16. package/dist/debug-server--Y0QZVJS.js.map +1 -0
  17. package/dist/debug-server-Bu3pCG9c.js +436 -0
  18. package/dist/debug-server-Bu3pCG9c.js.map +1 -0
  19. package/dist/debug-server-e1qPe0ZB.js +379 -0
  20. package/dist/{debug-server-BzzNkETg.js.map → debug-server-e1qPe0ZB.js.map} +1 -1
  21. package/dist/log-CUik_tHp.js +95 -0
  22. package/dist/log-CUik_tHp.js.map +1 -0
  23. package/dist/mcp/cli.js +1296 -1230
  24. package/dist/mcp/cli.js.map +1 -1
  25. package/dist/mcp/server.js +1 -1
  26. package/dist/panel/index.js +1 -1
  27. package/dist/{pool-DBLKNeRC.d.ts → pool-C0pc7T2p.d.ts} +4 -4
  28. package/dist/{pool-DBLKNeRC.d.ts.map → pool-C0pc7T2p.d.ts.map} +1 -1
  29. package/dist/{qr-http-server-Bo8LMOJQ.js → qr-http-server-HANhOFwI.js} +1 -1
  30. package/dist/{qr-http-server-Bo8LMOJQ.js.map → qr-http-server-HANhOFwI.js.map} +1 -1
  31. package/dist/{relay-factory-Dug7W6Ao.js → relay-factory-Ck3vBonr.js} +6 -6
  32. package/dist/{relay-factory-Dug7W6Ao.js.map → relay-factory-Ck3vBonr.js.map} +1 -1
  33. package/dist/{relay-secret-store-DKxs7zwq.js → relay-secret-store-DzxDsK6S.js} +1 -1
  34. package/dist/{relay-secret-store-DKxs7zwq.js.map → relay-secret-store-DzxDsK6S.js.map} +1 -1
  35. package/dist/{relay-url-store-xmUuTjXA.js → relay-url-store-D3rY-GJJ.js} +2 -2
  36. package/dist/{relay-url-store-xmUuTjXA.js.map → relay-url-store-D3rY-GJJ.js.map} +1 -1
  37. package/dist/{debug-server-BzzNkETg.js → relay-worker-Bt0QYKQH.js} +212 -346
  38. package/dist/relay-worker-Bt0QYKQH.js.map +1 -0
  39. package/dist/{relay-worker-TReZtzGl.d.ts → relay-worker-o0M2ndyJ.d.ts} +7 -7
  40. package/dist/relay-worker-o0M2ndyJ.d.ts.map +1 -0
  41. package/dist/{runtime-ozyPnRbU.d.ts → runtime-9xhN9pr8.d.ts} +1 -1
  42. package/dist/{runtime-ozyPnRbU.d.ts.map → runtime-9xhN9pr8.d.ts.map} +1 -1
  43. package/dist/test-runner/bin.js +721 -15
  44. package/dist/test-runner/bin.js.map +1 -1
  45. package/dist/test-runner/bundle.d.ts +1 -1
  46. package/dist/test-runner/capture.d.ts +1 -1
  47. package/dist/test-runner/config.d.ts +1 -1
  48. package/dist/test-runner/config.js +1 -1
  49. package/dist/test-runner/pool.d.ts +1 -1
  50. package/dist/test-runner/pool.js +1 -1
  51. package/dist/test-runner/relay-factory.d.ts +1 -1
  52. package/dist/test-runner/relay-factory.js +1 -1
  53. package/dist/test-runner/relay-worker.d.ts +1 -1
  54. package/dist/test-runner/relay-worker.js +1 -183
  55. package/dist/test-runner/report.d.ts +3 -3
  56. package/dist/test-runner/rpc.d.ts +2 -2
  57. package/dist/test-runner/rpc.js +12 -3
  58. package/dist/test-runner/rpc.js.map +1 -1
  59. package/dist/test-runner/runtime.d.ts +1 -1
  60. package/dist/test-runner/task-graph.d.ts +1 -1
  61. package/package.json +1 -1
  62. package/dist/attach-orchestrator-CPMQWkGV.js.map +0 -1
  63. package/dist/attach-orchestrator-CpE0dMew.js.map +0 -1
  64. package/dist/debug-server-1dhDA3aw.js +0 -980
  65. package/dist/debug-server-1dhDA3aw.js.map +0 -1
  66. package/dist/debug-server-Dctc9GAh.js.map +0 -1
  67. package/dist/relay-worker-TReZtzGl.d.ts.map +0 -1
  68. package/dist/test-runner/relay-worker.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import { n as BundleResult, r as bundleTestFile, t as BundleOptions } from "../bundle-Cb3GFuw6.js";
1
+ import { n as BundleResult, r as bundleTestFile, t as BundleOptions } from "../bundle-BKqyhEK9.js";
2
2
  export { BundleOptions, BundleResult, bundleTestFile };
@@ -1,2 +1,2 @@
1
- import { n as parseCaptureLines, t as AitCaptureLine } from "../capture-B1zfGyTo.js";
1
+ import { n as parseCaptureLines, t as AitCaptureLine } from "../capture-ltuV0gZa.js";
2
2
  export { AitCaptureLine, parseCaptureLines };
@@ -1,4 +1,4 @@
1
- import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-DBLKNeRC.js";
1
+ import { i as createRelayPool, n as RelayConnectionFactory, t as RELAY_POOL_NAME } from "../pool-C0pc7T2p.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-Dug7W6Ao.js";
2
+ import { t as createRelayConnectionFactory } from "../relay-factory-Ck3vBonr.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-DBLKNeRC.js";
1
+ import { i as createRelayPool, n as RelayConnectionFactory, r as RelayPoolOptions, t as RELAY_POOL_NAME } from "../pool-C0pc7T2p.js";
2
2
  export { RELAY_POOL_NAME, RelayConnectionFactory, RelayPoolOptions, createRelayPool };
@@ -1,4 +1,4 @@
1
- import { runTestFilesOverRelay } from "./relay-worker.js";
1
+ import { r as runTestFilesOverRelay } from "../relay-worker-Bt0QYKQH.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,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import * as fs from "node:fs";
3
- import { URL as URL$1 } from "node:url";
4
3
  import { EventEmitter } from "node:events";
4
+ import { URL as URL$1 } from "node:url";
5
5
  import * as http from "node:http";
6
6
  import { Agent, ClientRequest, ClientRequestArgs, OutgoingHttpHeaders } from "node:http";
7
7
  import * as net from "node:net";
@@ -24,7 +24,7 @@ function createRelayConnectionFactory(opts) {
24
24
  const { prepareAttach, renderAndMaybeWait, mintAttachUrl } = await import("../attach-orchestrator-RhOdO3DS.js");
25
25
  const { injectDebugIndicator, injectGlobals } = await import("../cell-Ba9lCI3B.js");
26
26
  const { loadRelaySecretReadOnly } = await import("../relay-secret-store-BcVrWwTq.js");
27
- const { bootRelayFamily, buildRelayVerifyAuth } = await import("../debug-server-Dctc9GAh.js");
27
+ const { bootRelayFamily, buildRelayVerifyAuth } = await import("../debug-server--Y0QZVJS.js");
28
28
  await loadRelaySecretReadOnly({ projectRoot });
29
29
  let resolveTunnelUp;
30
30
  const tunnelReady = new Promise((resolve) => {
@@ -1,2 +1,2 @@
1
- import { a as flattenResults, i as RelayRunReport, n as FileResult, o as runTestFilesOverRelay, r as RelayRunOptions, t as EVALUATE_TIMEOUT_MARKER } from "../relay-worker-TReZtzGl.js";
1
+ import { a as flattenResults, i as RelayRunReport, n as FileResult, o as runTestFilesOverRelay, r as RelayRunOptions, t as EVALUATE_TIMEOUT_MARKER } from "../relay-worker-o0M2ndyJ.js";
2
2
  export { EVALUATE_TIMEOUT_MARKER, FileResult, RelayRunOptions, RelayRunReport, flattenResults, runTestFilesOverRelay };
@@ -1,184 +1,2 @@
1
- import { bundleTestFile } from "./bundle.js";
2
- import { parseCaptureLines } from "./capture.js";
3
- import { injectAndRunBundle } from "./rpc.js";
4
- //#region src/test-runner/relay-worker.ts
5
- /**
6
- * Sentinel string embedded in the error message by `injectAndRunBundle` when
7
- * the per-file evaluate race hits the timeout. Used by the retry guard so only
8
- * genuine timeouts get a second attempt — not bundle errors or parse failures.
9
- *
10
- * Exported for unit tests that assert the retry path is taken.
11
- */
12
- const EVALUATE_TIMEOUT_MARKER = "rpc: evaluate timed out after";
13
- /**
14
- * Runs all `files` sequentially over the given CDP `connection`.
15
- *
16
- * For each file:
17
- * 1. Bundle with esbuild (includes SDK shim + runtime).
18
- * 2. Inject into the attached page via `Runtime.evaluate`.
19
- * 3. Await the `RunReport` JSON response.
20
- * 4. Accumulate results.
21
- *
22
- * Returns a `RelayRunReport` with per-file results and flattened totals.
23
- *
24
- * This function does NOT open or manage the relay connection — the caller
25
- * is responsible for attaching and closing it.
26
- *
27
- * TODO (#645): implement the Vitest `PoolRunnerInitializer` interface here
28
- * so that `runTestFilesOverRelay` can be used as a Vitest pool entry.
29
- *
30
- * @param connection - Active CDP connection (relay or local kind).
31
- * @param files - Absolute paths to test files, run in order.
32
- * @param opts - Optional per-run overrides.
33
- */
34
- async function runTestFilesOverRelay(connection, files, opts) {
35
- const wallStart = Date.now();
36
- const startedAt = new Date(wallStart).toISOString();
37
- const fileResults = [];
38
- let domainsEnabled = false;
39
- try {
40
- await connection.enableDomains();
41
- domainsEnabled = true;
42
- } catch (e) {
43
- process.stderr.write(`relay-worker: enableDomains() failed before run — console capture may be empty (${e instanceof Error ? e.message : String(e)})\n`);
44
- }
45
- const collectCaptures = opts?.collectCaptures === true;
46
- const liveConsole = [];
47
- let unsubscribeConsole;
48
- if (collectCaptures && domainsEnabled) unsubscribeConsole = connection.on("Runtime.consoleAPICalled", (event) => {
49
- liveConsole.push(event);
50
- });
51
- try {
52
- for (const file of files) {
53
- let fileEntry;
54
- try {
55
- const { code } = await bundleTestFile(file, opts?.bundleOptions);
56
- /**
57
- * Runs one evaluate attempt and returns a FileResult, or `null` when the
58
- * result is a genuine timeout and the caller should retry.
59
- *
60
- * We need to distinguish:
61
- * - `rpcResult.ok = false` + timeout error → retry candidate
62
- * - `rpcResult.ok = false` + other error → final error, no retry
63
- * - `injectAndRunBundle` throws → treated like a final error
64
- * (throws happen on CDP exceptionDetails, not on the Promise.race
65
- * timeout — the timeout produces `rpcResult.ok=false` with the
66
- * EVALUATE_TIMEOUT_MARKER message)
67
- */
68
- const attempt = async () => {
69
- let rpcResult;
70
- try {
71
- rpcResult = await injectAndRunBundle(connection, code, opts?.timeoutMs);
72
- } catch (e) {
73
- return {
74
- file,
75
- result: { error: e instanceof Error ? e.message : String(e) }
76
- };
77
- }
78
- if (rpcResult.ok) return {
79
- file,
80
- result: rpcResult.report
81
- };
82
- if (rpcResult.error.includes("rpc: evaluate timed out after")) return null;
83
- return {
84
- file,
85
- result: { error: rpcResult.error }
86
- };
87
- };
88
- const firstResult = await attempt();
89
- if (firstResult !== null) fileEntry = firstResult;
90
- else {
91
- process.stderr.write(`relay-worker: evaluate timed out for ${file} — retrying once\n`);
92
- const retryResult = await attempt();
93
- if (retryResult !== null) fileEntry = retryResult;
94
- else fileEntry = {
95
- file,
96
- result: { error: `${EVALUATE_TIMEOUT_MARKER} ${opts?.timeoutMs ?? 3e4}ms (after retry)` }
97
- };
98
- }
99
- } catch (e) {
100
- fileEntry = {
101
- file,
102
- result: { error: e instanceof Error ? e.message : String(e) }
103
- };
104
- }
105
- fileResults.push(fileEntry);
106
- }
107
- } finally {
108
- unsubscribeConsole?.();
109
- }
110
- const captures = collectCaptures ? parseCaptureLines(liveConsole.map((e) => ({ text: renderConsoleLineText(e) }))) : [];
111
- const totals = fileResults.reduce((acc, { result }) => {
112
- if ("error" in result) {
113
- acc.failed += 1;
114
- acc.total += 1;
115
- } else {
116
- acc.passed += result.passed;
117
- acc.failed += result.failed;
118
- acc.skipped += result.skipped;
119
- acc.total += result.passed + result.failed + result.skipped;
120
- }
121
- return acc;
122
- }, {
123
- passed: 0,
124
- failed: 0,
125
- skipped: 0,
126
- total: 0
127
- });
128
- return {
129
- startedAt,
130
- duration: Date.now() - wallStart,
131
- files: fileResults,
132
- totals,
133
- captures
134
- };
135
- }
136
- /**
137
- * Renders one `Runtime.consoleAPICalled` event to a single line of text, the
138
- * same way `tools.ts#normalizeConsoleMessage` does (args rendered + space-
139
- * joined). Inlined here (≈8 lines) so this module avoids importing `tools.ts`,
140
- * which would drag the heavy MCP/Node graph (server-lock, parent-watcher, …)
141
- * onto the test-runner entry.
142
- *
143
- * SECRET-HANDLING: this only stringifies console args; the caller's
144
- * allowlist-prefix parser then discards everything that is not a genuine
145
- * `__AIT_CAPTURE__` line.
146
- */
147
- function renderConsoleLineText(event) {
148
- return event.args.map((arg) => {
149
- if (arg.value !== void 0) {
150
- if (typeof arg.value === "string") return arg.value;
151
- try {
152
- return JSON.stringify(arg.value);
153
- } catch {
154
- return String(arg.value);
155
- }
156
- }
157
- if (arg.description !== void 0) return arg.description;
158
- if (arg.className !== void 0) return arg.className;
159
- return arg.subtype ?? arg.type;
160
- }).join(" ");
161
- }
162
- /**
163
- * Flattens all test results from a `RelayRunReport` into a single array.
164
- * Files that errored during bundle/inject produce a synthetic failed entry.
165
- */
166
- function flattenResults(report) {
167
- const out = [];
168
- for (const { file, result } of report.files) if ("error" in result) out.push({
169
- file,
170
- name: `<bundle/inject error>`,
171
- status: "fail",
172
- duration: 0,
173
- error: result.error
174
- });
175
- else for (const t of result.tests) out.push({
176
- ...t,
177
- file
178
- });
179
- return out;
180
- }
181
- //#endregion
1
+ import { n as flattenResults, r as runTestFilesOverRelay, t as EVALUATE_TIMEOUT_MARKER } from "../relay-worker-Bt0QYKQH.js";
182
2
  export { EVALUATE_TIMEOUT_MARKER, flattenResults, runTestFilesOverRelay };
183
-
184
- //# sourceMappingURL=relay-worker.js.map
@@ -1,6 +1,6 @@
1
- import { t as AitCaptureLine } from "../capture-B1zfGyTo.js";
2
- import { n as TestResult } from "../runtime-ozyPnRbU.js";
3
- import { i as RelayRunReport } from "../relay-worker-TReZtzGl.js";
1
+ import { t as AitCaptureLine } from "../capture-ltuV0gZa.js";
2
+ import { n as TestResult } from "../runtime-9xhN9pr8.js";
3
+ import { i as RelayRunReport } from "../relay-worker-o0M2ndyJ.js";
4
4
 
5
5
  //#region src/test-runner/report.d.ts
6
6
  /** The cell axes a report is stamped with — the test-matrix coordinates. */
@@ -1,5 +1,5 @@
1
- import { t as CdpConnection } from "../cdp-connection-Dxw_EY8s.js";
2
- import { t as RunReport } from "../runtime-ozyPnRbU.js";
1
+ import { t as CdpConnection } from "../cdp-connection-D7AYQck2.js";
2
+ import { t as RunReport } from "../runtime-9xhN9pr8.js";
3
3
 
4
4
  //#region src/test-runner/rpc.d.ts
5
5
  /**
@@ -1,6 +1,6 @@
1
1
  //#region src/test-runner/rpc.ts
2
2
  /** Maximum milliseconds to wait for a single evaluate round-trip. */
3
- const DEFAULT_TIMEOUT_MS = 3e4;
3
+ const DEFAULT_TIMEOUT_MS = 6e4;
4
4
  /**
5
5
  * Wraps bundle code in a self-executing IIFE that:
6
6
  * 1. Evaluates the bundle (registering describe/it/test).
@@ -59,13 +59,22 @@ function parseRunTestsResult(rawValue) {
59
59
  */
60
60
  async function injectAndRunBundle(connection, bundleCode, timeoutMs = DEFAULT_TIMEOUT_MS) {
61
61
  const expression = buildRunTestsExpression(bundleCode);
62
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`rpc: evaluate timed out after ${timeoutMs}ms`)), timeoutMs));
62
+ const TIMEOUT_SENTINEL = Symbol("timeout");
63
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs));
63
64
  const evalPromise = connection.send("Runtime.evaluate", {
64
65
  expression,
65
66
  returnByValue: true,
66
67
  awaitPromise: true
67
68
  });
68
- const cdpResult = await Promise.race([evalPromise, timeoutPromise]);
69
+ const raceResult = await Promise.race([evalPromise.then((v) => ({
70
+ tag: "eval",
71
+ v
72
+ })), timeoutPromise.then(() => ({ tag: "timeout" }))]);
73
+ if (raceResult.tag === "timeout") return {
74
+ ok: false,
75
+ error: `rpc: evaluate timed out after ${timeoutMs}ms`
76
+ };
77
+ const cdpResult = raceResult.v;
69
78
  if (cdpResult.exceptionDetails) {
70
79
  const msg = cdpResult.exceptionDetails.exception?.description ?? cdpResult.exceptionDetails.text ?? "Runtime.evaluate threw an exception";
71
80
  throw new Error(`rpc.injectAndRunBundle: ${msg}`);
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.js","names":[],"sources":["../../src/test-runner/rpc.ts"],"sourcesContent":["/**\n * Node-side RPC helpers for injecting and collecting test execution over CDP.\n *\n * Uses the same IIFE + JSON.stringify envelope pattern as `buildCallSdkExpression`\n * in `src/mcp/tools.ts` to reliably shuttle structured results through\n * `Runtime.evaluate`'s `returnByValue: true` boundary.\n *\n * SECRET-HANDLING: bundle code, relay URLs, and result values are NOT logged.\n */\n\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RunReport } from './runtime.js';\n\n/** Maximum milliseconds to wait for a single evaluate round-trip. */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Wraps bundle code in a self-executing IIFE that:\n * 1. Evaluates the bundle (registering describe/it/test).\n * 2. Calls `__testBundle.runTestModule(...)` — the entry the runtime exports.\n * 3. Returns a JSON-serialised `RunReport` string.\n *\n * The double-serialisation (RunReport → JSON string → returnByValue string)\n * is intentional: CDP `returnByValue` reliably transports strings; deeply\n * nested objects can lose fidelity across the Chii relay.\n *\n * SECRET-HANDLING: `bundleCode` MUST NOT be logged by callers.\n */\nexport function buildRunTestsExpression(bundleCode: string): string {\n // We trust bundleCode is already a self-contained IIFE that installs\n // `window.__testBundle` (or `globalThis.__testBundle`).\n // We then call `__testBundle.runTestModule()` and return a JSON string.\n return (\n `(async () => {` +\n // Step 1: evaluate the bundle to register tests\n ` try { ${bundleCode} } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'bundle-eval: ' + String(e && e.message || e)});` +\n ` }` +\n // Step 2: check that the expected exports are present\n ` if (typeof globalThis.__testBundle !== 'object' || typeof globalThis.__testBundle.runTestModule !== 'function' || typeof globalThis.__testBundle.__userFactory !== 'function') {` +\n ` return JSON.stringify({ok:false,error:'bundle-missing-export: __testBundle.runTestModule or __userFactory is not a function'});` +\n ` }` +\n // Step 3: run tests — pass the factory so runTestModule installs globals\n // first, then invokes the factory to register describe/it/test blocks.\n ` try {` +\n ` const report = await globalThis.__testBundle.runTestModule(globalThis.__testBundle.__userFactory);` +\n ` return JSON.stringify({ok:true,value:report});` +\n ` } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'test-run: ' + String(e && e.message || e)});` +\n ` }` +\n `})()`\n );\n}\n\n/**\n * Result of `injectAndRunBundle`.\n */\nexport type RpcRunResult = { ok: true; report: RunReport } | { ok: false; error: string };\n\n/**\n * Parses the raw CDP `returnByValue` result from a `buildRunTestsExpression`\n * evaluate call into a typed `RpcRunResult`.\n *\n * Throws only on parse failure — an `ok:false` envelope is a normal result.\n *\n * SECRET-HANDLING: `rawValue` is not included in error messages.\n */\nexport function parseRunTestsResult(rawValue: unknown): RpcRunResult {\n if (typeof rawValue !== 'string') {\n throw new Error(\n `rpc.parseRunTestsResult: unexpected return type \"${typeof rawValue}\" — expected JSON string`,\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawValue);\n } catch {\n // Do NOT include rawValue — could contain secrets.\n throw new Error('rpc.parseRunTestsResult: bridge returned non-JSON string');\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('rpc.parseRunTestsResult: parsed result is not an object');\n }\n const obj = parsed as Record<string, unknown>;\n if (obj.ok === true) {\n return { ok: true, report: obj.value as RunReport };\n }\n if (obj.ok === false) {\n return {\n ok: false,\n error: typeof obj.error === 'string' ? obj.error : String(obj.error),\n };\n }\n throw new Error('rpc.parseRunTestsResult: result missing \"ok\" field');\n}\n\n/**\n * Injects `bundleCode` into the attached page and awaits test execution.\n *\n * Uses `Runtime.evaluate` with `awaitPromise: true` to wait for the\n * async IIFE to settle. The 30-second CDP command timeout covers even\n * long-running test suites; split into smaller files if you hit it.\n *\n * @param connection - Active CDP connection (relay or local).\n * @param bundleCode - IIFE bundle string from `bundleTestFile`.\n * @param timeoutMs - Override the default 30 s timeout.\n *\n * SECRET-HANDLING: `bundleCode` and the raw CDP result value are never logged.\n */\nexport async function injectAndRunBundle(\n connection: CdpConnection,\n bundleCode: string,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<RpcRunResult> {\n const expression = buildRunTestsExpression(bundleCode);\n\n // Use AbortSignal-style timeout via Promise.race so we surface a clear\n // message rather than hanging indefinitely.\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`rpc: evaluate timed out after ${timeoutMs}ms`)), timeoutMs),\n );\n\n const evalPromise = connection.send('Runtime.evaluate', {\n expression,\n returnByValue: true,\n awaitPromise: true,\n });\n\n const cdpResult = await Promise.race([evalPromise, timeoutPromise]);\n\n if (cdpResult.exceptionDetails) {\n // Surface only the engine error string — not the expression or value.\n const msg =\n cdpResult.exceptionDetails.exception?.description ??\n cdpResult.exceptionDetails.text ??\n 'Runtime.evaluate threw an exception';\n throw new Error(`rpc.injectAndRunBundle: ${msg}`);\n }\n\n return parseRunTestsResult(cdpResult.result.value);\n}\n"],"mappings":";;AAcA,MAAM,qBAAqB;;;;;;;;;;;;;AAc3B,SAAgB,wBAAwB,YAA4B;AAIlE,QACE,yBAEW,WAAW;;;;;;;;;;AAgC1B,SAAgB,oBAAoB,UAAiC;AACnE,KAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MACR,oDAAoD,OAAO,SAAS,0BACrE;CAEH,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,SAAS;SACvB;AAEN,QAAM,IAAI,MAAM,2DAA2D;;AAE7E,KAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,OAAO,CACxE,OAAM,IAAI,MAAM,0DAA0D;CAE5E,MAAM,MAAM;AACZ,KAAI,IAAI,OAAO,KACb,QAAO;EAAE,IAAI;EAAM,QAAQ,IAAI;EAAoB;AAErD,KAAI,IAAI,OAAO,MACb,QAAO;EACL,IAAI;EACJ,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ,OAAO,IAAI,MAAM;EACrE;AAEH,OAAM,IAAI,MAAM,uDAAqD;;;;;;;;;;;;;;;AAgBvE,eAAsB,mBACpB,YACA,YACA,YAAY,oBACW;CACvB,MAAM,aAAa,wBAAwB,WAAW;CAItD,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAC5C,iBAAiB,uBAAO,IAAI,MAAM,iCAAiC,UAAU,IAAI,CAAC,EAAE,UAAU,CAC/F;CAED,MAAM,cAAc,WAAW,KAAK,oBAAoB;EACtD;EACA,eAAe;EACf,cAAc;EACf,CAAC;CAEF,MAAM,YAAY,MAAM,QAAQ,KAAK,CAAC,aAAa,eAAe,CAAC;AAEnE,KAAI,UAAU,kBAAkB;EAE9B,MAAM,MACJ,UAAU,iBAAiB,WAAW,eACtC,UAAU,iBAAiB,QAC3B;AACF,QAAM,IAAI,MAAM,2BAA2B,MAAM;;AAGnD,QAAO,oBAAoB,UAAU,OAAO,MAAM"}
1
+ {"version":3,"file":"rpc.js","names":[],"sources":["../../src/test-runner/rpc.ts"],"sourcesContent":["/**\n * Node-side RPC helpers for injecting and collecting test execution over CDP.\n *\n * Uses the same IIFE + JSON.stringify envelope pattern as `buildCallSdkExpression`\n * in `src/mcp/tools.ts` to reliably shuttle structured results through\n * `Runtime.evaluate`'s `returnByValue: true` boundary.\n *\n * SECRET-HANDLING: bundle code, relay URLs, and result values are NOT logged.\n */\n\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RunReport } from './runtime.js';\n\n/** Maximum milliseconds to wait for a single evaluate round-trip. */\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\n/**\n * Wraps bundle code in a self-executing IIFE that:\n * 1. Evaluates the bundle (registering describe/it/test).\n * 2. Calls `__testBundle.runTestModule(...)` — the entry the runtime exports.\n * 3. Returns a JSON-serialised `RunReport` string.\n *\n * The double-serialisation (RunReport → JSON string → returnByValue string)\n * is intentional: CDP `returnByValue` reliably transports strings; deeply\n * nested objects can lose fidelity across the Chii relay.\n *\n * SECRET-HANDLING: `bundleCode` MUST NOT be logged by callers.\n */\nexport function buildRunTestsExpression(bundleCode: string): string {\n // We trust bundleCode is already a self-contained IIFE that installs\n // `window.__testBundle` (or `globalThis.__testBundle`).\n // We then call `__testBundle.runTestModule()` and return a JSON string.\n return (\n `(async () => {` +\n // Step 1: evaluate the bundle to register tests\n ` try { ${bundleCode} } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'bundle-eval: ' + String(e && e.message || e)});` +\n ` }` +\n // Step 2: check that the expected exports are present\n ` if (typeof globalThis.__testBundle !== 'object' || typeof globalThis.__testBundle.runTestModule !== 'function' || typeof globalThis.__testBundle.__userFactory !== 'function') {` +\n ` return JSON.stringify({ok:false,error:'bundle-missing-export: __testBundle.runTestModule or __userFactory is not a function'});` +\n ` }` +\n // Step 3: run tests — pass the factory so runTestModule installs globals\n // first, then invokes the factory to register describe/it/test blocks.\n ` try {` +\n ` const report = await globalThis.__testBundle.runTestModule(globalThis.__testBundle.__userFactory);` +\n ` return JSON.stringify({ok:true,value:report});` +\n ` } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'test-run: ' + String(e && e.message || e)});` +\n ` }` +\n `})()`\n );\n}\n\n/**\n * Result of `injectAndRunBundle`.\n */\nexport type RpcRunResult = { ok: true; report: RunReport } | { ok: false; error: string };\n\n/**\n * Parses the raw CDP `returnByValue` result from a `buildRunTestsExpression`\n * evaluate call into a typed `RpcRunResult`.\n *\n * Throws only on parse failure — an `ok:false` envelope is a normal result.\n *\n * SECRET-HANDLING: `rawValue` is not included in error messages.\n */\nexport function parseRunTestsResult(rawValue: unknown): RpcRunResult {\n if (typeof rawValue !== 'string') {\n throw new Error(\n `rpc.parseRunTestsResult: unexpected return type \"${typeof rawValue}\" — expected JSON string`,\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawValue);\n } catch {\n // Do NOT include rawValue — could contain secrets.\n throw new Error('rpc.parseRunTestsResult: bridge returned non-JSON string');\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('rpc.parseRunTestsResult: parsed result is not an object');\n }\n const obj = parsed as Record<string, unknown>;\n if (obj.ok === true) {\n return { ok: true, report: obj.value as RunReport };\n }\n if (obj.ok === false) {\n return {\n ok: false,\n error: typeof obj.error === 'string' ? obj.error : String(obj.error),\n };\n }\n throw new Error('rpc.parseRunTestsResult: result missing \"ok\" field');\n}\n\n/**\n * Injects `bundleCode` into the attached page and awaits test execution.\n *\n * Uses `Runtime.evaluate` with `awaitPromise: true` to wait for the\n * async IIFE to settle. The 30-second CDP command timeout covers even\n * long-running test suites; split into smaller files if you hit it.\n *\n * @param connection - Active CDP connection (relay or local).\n * @param bundleCode - IIFE bundle string from `bundleTestFile`.\n * @param timeoutMs - Override the default 30 s timeout.\n *\n * SECRET-HANDLING: `bundleCode` and the raw CDP result value are never logged.\n */\nexport async function injectAndRunBundle(\n connection: CdpConnection,\n bundleCode: string,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<RpcRunResult> {\n const expression = buildRunTestsExpression(bundleCode);\n\n // Use a tagged race so we can distinguish \"timeout won\" from \"evaluate won\"\n // without relying on exception identity. The timeout arm RETURNS a typed\n // RpcRunResult (ok:false + EVALUATE_TIMEOUT_MARKER) so the caller (relay-\n // worker's attempt()) can detect it via `.error.includes(EVALUATE_TIMEOUT_MARKER)`\n // and trigger the one-retry path.\n //\n // Genuine CDP `exceptionDetails` (engine exceptions thrown inside the page)\n // still THROW — those are deterministic failures that a retry cannot fix and\n // relay-worker's catch block finalises them correctly.\n //\n // DO NOT change the literal string below — relay-worker.ts imports\n // EVALUATE_TIMEOUT_MARKER = 'rpc: evaluate timed out after' and uses\n // `.includes()` to recognise this exact prefix.\n const TIMEOUT_SENTINEL = Symbol('timeout');\n const timeoutPromise = new Promise<typeof TIMEOUT_SENTINEL>((resolve) =>\n setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs),\n );\n\n const evalPromise = connection.send('Runtime.evaluate', {\n expression,\n returnByValue: true,\n awaitPromise: true,\n });\n\n const raceResult = await Promise.race([\n evalPromise.then((v) => ({ tag: 'eval' as const, v })),\n timeoutPromise.then(() => ({ tag: 'timeout' as const })),\n ]);\n\n if (raceResult.tag === 'timeout') {\n return { ok: false, error: `rpc: evaluate timed out after ${timeoutMs}ms` };\n }\n\n const cdpResult = raceResult.v;\n\n if (cdpResult.exceptionDetails) {\n // Surface only the engine error string — not the expression or value.\n const msg =\n cdpResult.exceptionDetails.exception?.description ??\n cdpResult.exceptionDetails.text ??\n 'Runtime.evaluate threw an exception';\n throw new Error(`rpc.injectAndRunBundle: ${msg}`);\n }\n\n return parseRunTestsResult(cdpResult.result.value);\n}\n"],"mappings":";;AAcA,MAAM,qBAAqB;;;;;;;;;;;;;AAc3B,SAAgB,wBAAwB,YAA4B;AAIlE,QACE,yBAEW,WAAW;;;;;;;;;;AAgC1B,SAAgB,oBAAoB,UAAiC;AACnE,KAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MACR,oDAAoD,OAAO,SAAS,0BACrE;CAEH,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,SAAS;SACvB;AAEN,QAAM,IAAI,MAAM,2DAA2D;;AAE7E,KAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,OAAO,CACxE,OAAM,IAAI,MAAM,0DAA0D;CAE5E,MAAM,MAAM;AACZ,KAAI,IAAI,OAAO,KACb,QAAO;EAAE,IAAI;EAAM,QAAQ,IAAI;EAAoB;AAErD,KAAI,IAAI,OAAO,MACb,QAAO;EACL,IAAI;EACJ,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ,OAAO,IAAI,MAAM;EACrE;AAEH,OAAM,IAAI,MAAM,uDAAqD;;;;;;;;;;;;;;;AAgBvE,eAAsB,mBACpB,YACA,YACA,YAAY,oBACW;CACvB,MAAM,aAAa,wBAAwB,WAAW;CAetD,MAAM,mBAAmB,OAAO,UAAU;CAC1C,MAAM,iBAAiB,IAAI,SAAkC,YAC3D,iBAAiB,QAAQ,iBAAiB,EAAE,UAAU,CACvD;CAED,MAAM,cAAc,WAAW,KAAK,oBAAoB;EACtD;EACA,eAAe;EACf,cAAc;EACf,CAAC;CAEF,MAAM,aAAa,MAAM,QAAQ,KAAK,CACpC,YAAY,MAAM,OAAO;EAAE,KAAK;EAAiB;EAAG,EAAE,EACtD,eAAe,YAAY,EAAE,KAAK,WAAoB,EAAE,CACzD,CAAC;AAEF,KAAI,WAAW,QAAQ,UACrB,QAAO;EAAE,IAAI;EAAO,OAAO,iCAAiC,UAAU;EAAK;CAG7E,MAAM,YAAY,WAAW;AAE7B,KAAI,UAAU,kBAAkB;EAE9B,MAAM,MACJ,UAAU,iBAAiB,WAAW,eACtC,UAAU,iBAAiB,QAC3B;AACF,QAAM,IAAI,MAAM,2BAA2B,MAAM;;AAGnD,QAAO,oBAAoB,UAAU,OAAO,MAAM"}
@@ -1,2 +1,2 @@
1
- import { i as runtimeGlobals, n as TestResult, r as runTestModule, t as RunReport } from "../runtime-ozyPnRbU.js";
1
+ import { i as runtimeGlobals, n as TestResult, r as runTestModule, t as RunReport } from "../runtime-9xhN9pr8.js";
2
2
  export { RunReport, TestResult, runTestModule, runtimeGlobals };
@@ -1,4 +1,4 @@
1
- import { t as RunReport } from "../runtime-ozyPnRbU.js";
1
+ import { t as RunReport } from "../runtime-9xhN9pr8.js";
2
2
  import { File, TaskEventPack, TaskResultPack } from "@vitest/runner";
3
3
 
4
4
  //#region src/test-runner/task-graph.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ait-co/devtools",
3
- "version": "0.1.127",
3
+ "version": "0.1.129",
4
4
  "description": "Development tools for Apps in Toss mini-apps — mock SDK, floating devtools panel, and universal bundler plugin",
5
5
  "type": "module",
6
6
  "engines": {