@ait-co/devtools 0.1.107 → 0.1.108

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 (54) hide show
  1. package/dist/bundle-BJm5jk56.d.ts +49 -0
  2. package/dist/bundle-BJm5jk56.d.ts.map +1 -0
  3. package/dist/cdp-connection-C0AP0tH2.d.ts +277 -0
  4. package/dist/cdp-connection-C0AP0tH2.d.ts.map +1 -0
  5. package/dist/in-app/auto.d.ts +17 -0
  6. package/dist/in-app/auto.d.ts.map +1 -1
  7. package/dist/in-app/auto.js +76 -0
  8. package/dist/in-app/auto.js.map +1 -1
  9. package/dist/in-app/index.d.ts +48 -1
  10. package/dist/in-app/index.d.ts.map +1 -1
  11. package/dist/in-app/index.js +60 -1
  12. package/dist/in-app/index.js.map +1 -1
  13. package/dist/mcp/cli.js +502 -6
  14. package/dist/mcp/cli.js.map +1 -1
  15. package/dist/mcp/server.d.ts.map +1 -1
  16. package/dist/mcp/server.js +59 -2
  17. package/dist/mcp/server.js.map +1 -1
  18. package/dist/panel/index.js +1 -1
  19. package/dist/pool-Dkp7I9Bf.d.ts +14577 -0
  20. package/dist/pool-Dkp7I9Bf.d.ts.map +1 -0
  21. package/dist/relay-worker-BzFQ3fv9.d.ts +74 -0
  22. package/dist/relay-worker-BzFQ3fv9.d.ts.map +1 -0
  23. package/dist/runtime-ORdrpizY.d.ts +50 -0
  24. package/dist/runtime-ORdrpizY.d.ts.map +1 -0
  25. package/dist/test-runner/bundle.d.ts +2 -0
  26. package/dist/test-runner/bundle.js +95 -0
  27. package/dist/test-runner/bundle.js.map +1 -0
  28. package/dist/test-runner/cli.d.ts +417 -0
  29. package/dist/test-runner/cli.d.ts.map +1 -0
  30. package/dist/test-runner/cli.js +377 -0
  31. package/dist/test-runner/cli.js.map +1 -0
  32. package/dist/test-runner/config.d.ts +80 -0
  33. package/dist/test-runner/config.d.ts.map +1 -0
  34. package/dist/test-runner/config.js +54 -0
  35. package/dist/test-runner/config.js.map +1 -0
  36. package/dist/test-runner/pool.d.ts +2 -0
  37. package/dist/test-runner/pool.js +136 -0
  38. package/dist/test-runner/pool.js.map +1 -0
  39. package/dist/test-runner/relay-worker.d.ts +2 -0
  40. package/dist/test-runner/relay-worker.js +96 -0
  41. package/dist/test-runner/relay-worker.js.map +1 -0
  42. package/dist/test-runner/rpc.d.ts +53 -0
  43. package/dist/test-runner/rpc.d.ts.map +1 -0
  44. package/dist/test-runner/rpc.js +78 -0
  45. package/dist/test-runner/rpc.js.map +1 -0
  46. package/dist/test-runner/task-graph.d.ts +38 -0
  47. package/dist/test-runner/task-graph.d.ts.map +1 -0
  48. package/dist/test-runner/task-graph.js +182 -0
  49. package/dist/test-runner/task-graph.js.map +1 -0
  50. package/dist/unplugin/index.d.cts +13 -32
  51. package/dist/unplugin/index.d.cts.map +1 -1
  52. package/dist/unplugin/index.d.ts +13 -32
  53. package/dist/unplugin/index.d.ts.map +1 -1
  54. package/package.json +13 -3
@@ -0,0 +1,74 @@
1
+ import { t as BundleOptions } from "./bundle-BJm5jk56.js";
2
+ import { t as CdpConnection } from "./cdp-connection-C0AP0tH2.js";
3
+ import { n as TestResult, t as RunReport } from "./runtime-ORdrpizY.js";
4
+
5
+ //#region src/test-runner/relay-worker.d.ts
6
+ /** Per-file result in the aggregate `RunReport`. */
7
+ interface FileResult {
8
+ /** Absolute or relative path to the test file. */
9
+ file: string;
10
+ /** Full run report for this file, or an error if bundling/injection failed. */
11
+ result: RunReport | {
12
+ error: string;
13
+ };
14
+ }
15
+ /** Aggregate report returned by `runTestFilesOverRelay`. */
16
+ interface RelayRunReport {
17
+ /** ISO timestamp of when the run started. */
18
+ startedAt: string;
19
+ /** Total elapsed wall-clock milliseconds. */
20
+ duration: number;
21
+ /** Per-file results in execution order. */
22
+ files: FileResult[];
23
+ /** Flattened totals across all files. */
24
+ totals: {
25
+ passed: number;
26
+ failed: number;
27
+ skipped: number;
28
+ total: number;
29
+ };
30
+ }
31
+ /** Options for `runTestFilesOverRelay`. */
32
+ interface RelayRunOptions {
33
+ /**
34
+ * Options forwarded to `bundleTestFile` for each file.
35
+ */
36
+ bundleOptions?: BundleOptions;
37
+ /**
38
+ * Per-file evaluate timeout in milliseconds. Defaults to 30 000.
39
+ * Increase for long-running suites or split the file.
40
+ */
41
+ timeoutMs?: number;
42
+ }
43
+ /**
44
+ * Runs all `files` sequentially over the given CDP `connection`.
45
+ *
46
+ * For each file:
47
+ * 1. Bundle with esbuild (includes SDK shim + runtime).
48
+ * 2. Inject into the attached page via `Runtime.evaluate`.
49
+ * 3. Await the `RunReport` JSON response.
50
+ * 4. Accumulate results.
51
+ *
52
+ * Returns a `RelayRunReport` with per-file results and flattened totals.
53
+ *
54
+ * This function does NOT open or manage the relay connection — the caller
55
+ * is responsible for attaching and closing it.
56
+ *
57
+ * TODO (#645): implement the Vitest `PoolRunnerInitializer` interface here
58
+ * so that `runTestFilesOverRelay` can be used as a Vitest pool entry.
59
+ *
60
+ * @param connection - Active CDP connection (relay or local kind).
61
+ * @param files - Absolute paths to test files, run in order.
62
+ * @param opts - Optional per-run overrides.
63
+ */
64
+ declare function runTestFilesOverRelay(connection: CdpConnection, files: string[], opts?: RelayRunOptions): Promise<RelayRunReport>;
65
+ /**
66
+ * Flattens all test results from a `RelayRunReport` into a single array.
67
+ * Files that errored during bundle/inject produce a synthetic failed entry.
68
+ */
69
+ declare function flattenResults(report: RelayRunReport): Array<TestResult & {
70
+ file: string;
71
+ }>;
72
+ //#endregion
73
+ export { runTestFilesOverRelay as a, flattenResults as i, RelayRunOptions as n, RelayRunReport as r, FileResult as t };
74
+ //# sourceMappingURL=relay-worker-BzFQ3fv9.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-worker-BzFQ3fv9.d.ts","names":[],"sources":["../src/test-runner/relay-worker.ts"],"mappings":";;;;;;UAsBiB,UAAA;EAYf;EAVA,IAAA;EAYO;EAVP,MAAA,EAAQ,SAAA;IAAc,KAAA;EAAA;AAAA;;UAIP,cAAA;EAYR;EAVP,SAAA;EAe8B;EAb9B,QAAA;EAiB6B;EAf7B,KAAA,EAAO,UAAA;EAeS;EAbhB,MAAA;IACE,MAAA;IACA,MAAA;IACA,OAAA;IACA,KAAA;EAAA;AAAA;;UAKa,eAAA;EAqCd;;;EAjCD,aAAA,GAAgB,aAAA;EA8BhB;;;;EAzBA,SAAA;AAAA;;;AAoFF;;;;;;;;;;;;;;;;;;;iBA5DsB,qBAAA,CACpB,UAAA,EAAY,aAAA,EACZ,KAAA,YACA,IAAA,GAAO,eAAA,GACN,OAAA,CAAQ,cAAA;;;;;iBAwDK,cAAA,CAAe,MAAA,EAAQ,cAAA,GAAiB,KAAA,CAAM,UAAA;EAAe,IAAA;AAAA"}
@@ -0,0 +1,50 @@
1
+ //#region src/test-runner/runtime.d.ts
2
+ /**
3
+ * Thin test runtime for WebView execution.
4
+ *
5
+ * This file is bundled by `bundle.ts` together with the user's test file
6
+ * into a single IIFE injected into the WebView via `Runtime.evaluate`.
7
+ * It MUST stay browser-compatible — no Node.js APIs allowed.
8
+ *
9
+ * Design: rather than shipping @vitest/runner verbatim into a WebView (where
10
+ * its Node-side internals cause issues), this runtime provides a minimal
11
+ * compatible API surface — describe/it/test/expect globals — collects results
12
+ * into a plain JSON-safe object, and exports `runTestModule` as the entry point.
13
+ *
14
+ * @vitest/runner and @vitest/expect are listed as dependencies so that the
15
+ * package's type contracts are available and so the browser-compatible subsets
16
+ * can be referenced. Full pool integration (PoolRunnerInitializer) is tracked
17
+ * in issue #645.
18
+ *
19
+ * NOTE: this file is imported by type from Node-side code (rpc.ts / relay-worker.ts)
20
+ * for the RunReport / TestResult type shapes. The runtime ITSELF is not imported
21
+ * at runtime on the Node side — only the types are used.
22
+ */
23
+ /**
24
+ * Result of a single test case.
25
+ * All fields are JSON-serialisable.
26
+ */
27
+ interface TestResult {
28
+ /** Full dot-joined test name including nested suite names. */
29
+ name: string;
30
+ /** `'pass'` or `'fail'`. `'skip'` for skipped tests. */
31
+ status: 'pass' | 'fail' | 'skip';
32
+ /** Duration in milliseconds. */
33
+ duration: number;
34
+ /** Error message (fail only). Does NOT include the expression/secret. */
35
+ error?: string;
36
+ }
37
+ /** Aggregate report returned by `runTestModule`. */
38
+ interface RunReport {
39
+ /** ISO timestamp of when `runTestModule` was called. */
40
+ startedAt: string;
41
+ /** Total elapsed milliseconds (wall-clock). */
42
+ duration: number;
43
+ passed: number;
44
+ failed: number;
45
+ skipped: number;
46
+ tests: TestResult[];
47
+ }
48
+ //#endregion
49
+ export { TestResult as n, RunReport as t };
50
+ //# sourceMappingURL=runtime-ORdrpizY.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-ORdrpizY.d.ts","names":[],"sources":["../src/test-runner/runtime.ts"],"mappings":";;AA8BA;;;;;;;;;;AAYA;;;;;;;;;;;;;;UAZiB,UAAA;;EAEf,IAAA;;EAEA,MAAA;;EAEA,QAAA;;EAEA,KAAA;AAAA;;UAIe,SAAA;;EAEf,SAAA;;EAEA,QAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA,EAAO,UAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import { n as BundleResult, r as bundleTestFile, t as BundleOptions } from "../bundle-BJm5jk56.js";
2
+ export { BundleOptions, BundleResult, bundleTestFile };
@@ -0,0 +1,95 @@
1
+ import * as path from "node:path";
2
+ //#region src/test-runner/bundle.ts
3
+ /**
4
+ * esbuild-based bundler for user test files.
5
+ *
6
+ * Bundles a single test file into a self-contained IIFE string that can be
7
+ * injected into a WebView via `Runtime.evaluate`. The user's SDK imports
8
+ * (`@apps-in-toss/web-framework` and sub-paths) are intercepted via an
9
+ * esbuild plugin that redirects them to `window.__sdk`, which the in-app
10
+ * debug gate (`src/in-app/auto.ts`) installs as a namespace mirror of the
11
+ * SDK exports (works for both 2.x and 3.x SDK).
12
+ *
13
+ * SECRET-HANDLING: the returned bundle code is caller-managed; never log it.
14
+ */
15
+ /**
16
+ * Matches the bare SDK package and any sub-path import
17
+ * (`@apps-in-toss/web-framework`, `@apps-in-toss/web-framework/foo`).
18
+ * Built from {@link SDK_PACKAGE} so the package name has a single source.
19
+ */
20
+ const SDK_IMPORT_FILTER = new RegExp(`^${"@apps-in-toss/web-framework".replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`);
21
+ /**
22
+ * esbuild plugin that intercepts SDK imports and redirects them to the
23
+ * `window.__sdk` proxy that `src/in-app/auto.ts` installs at runtime.
24
+ *
25
+ * Strategy: for every import of `@apps-in-toss/web-framework` (or sub-paths),
26
+ * esbuild resolves it to a virtual module that re-exports all named exports
27
+ * via `window.__sdk[name]`. This avoids bundling the real SDK (which may not
28
+ * be available in the test environment) while still making named imports work.
29
+ *
30
+ * If `window.__sdk` is absent (non-dog-food build), every access throws a
31
+ * descriptive error rather than returning `undefined` silently.
32
+ */
33
+ function sdkRedirectPlugin() {
34
+ return {
35
+ name: "sdk-redirect",
36
+ setup(build) {
37
+ build.onResolve({ filter: SDK_IMPORT_FILTER }, (args) => ({
38
+ path: args.path,
39
+ namespace: "sdk-redirect"
40
+ }));
41
+ build.onLoad({
42
+ filter: /.*/,
43
+ namespace: "sdk-redirect"
44
+ }, () => ({
45
+ contents: `
46
+ var __proxy = (typeof window !== 'undefined' && window.__sdk)
47
+ ? window.__sdk
48
+ : new Proxy({}, {
49
+ get: function(_t, p) {
50
+ throw new Error('window.__sdk is not installed — run in a dog-food build. Missing: ' + String(p));
51
+ }
52
+ });
53
+ module.exports = __proxy;
54
+ `,
55
+ loader: "js"
56
+ }));
57
+ }
58
+ };
59
+ }
60
+ /**
61
+ * Bundles `absPath` into a single IIFE string suitable for `Runtime.evaluate`.
62
+ *
63
+ * The IIFE installs `window.__testBundle` (or the custom `globalName`) with
64
+ * `runTestModule` as the callable entry point.
65
+ *
66
+ * @param absPath - Absolute path to the user test file.
67
+ * @param opts - Optional bundling overrides.
68
+ */
69
+ async function bundleTestFile(absPath, opts) {
70
+ const globalName = opts?.globalName ?? "__testBundle";
71
+ const extraExternals = opts?.extraExternals ?? [];
72
+ const result = await (await import("esbuild")).build({
73
+ entryPoints: [absPath],
74
+ bundle: true,
75
+ format: "iife",
76
+ globalName,
77
+ platform: "browser",
78
+ target: "es2022",
79
+ write: false,
80
+ plugins: [sdkRedirectPlugin()],
81
+ external: extraExternals,
82
+ treeShaking: true
83
+ });
84
+ const warnings = result.warnings.map((w) => `${path.relative(process.cwd(), w.location?.file ?? "")}:${w.location?.line ?? "?"}: ${w.text}`);
85
+ const outputFile = result.outputFiles?.[0];
86
+ if (!outputFile) throw new Error("bundleTestFile: esbuild produced no output — check entryPoints");
87
+ return {
88
+ code: outputFile.text,
89
+ warnings
90
+ };
91
+ }
92
+ //#endregion
93
+ export { bundleTestFile };
94
+
95
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","names":[],"sources":["../../src/test-runner/bundle.ts"],"sourcesContent":["/**\n * esbuild-based bundler for user test files.\n *\n * Bundles a single test file into a self-contained IIFE string that can be\n * injected into a WebView via `Runtime.evaluate`. The user's SDK imports\n * (`@apps-in-toss/web-framework` and sub-paths) are intercepted via an\n * esbuild plugin that redirects them to `window.__sdk`, which the in-app\n * debug gate (`src/in-app/auto.ts`) installs as a namespace mirror of the\n * SDK exports (works for both 2.x and 3.x SDK).\n *\n * SECRET-HANDLING: the returned bundle code is caller-managed; never log it.\n */\n\nimport * as path from 'node:path';\n// esbuild is imported for TYPES only at module scope; the runtime module is\n// loaded lazily inside `bundleTestFile` via dynamic import. esbuild runs a\n// startup invariant check (`TextEncoder().encode('') instanceof Uint8Array`)\n// that fails in a jsdom realm — a static import would break every MCP/test\n// module that merely *imports* this file's transitive graph (e.g. debug-server →\n// run_tests). Lazy load keeps esbuild off the import graph until a bundle is\n// actually built, and mirrors the cloudflared/chii dynamic-import precedent.\nimport type * as esbuild from 'esbuild';\n\n/** Options accepted by `bundleTestFile`. */\nexport interface BundleOptions {\n /**\n * Additional esbuild `external` patterns. The SDK package\n * (`@apps-in-toss/web-framework` and `@apps-in-toss/web-framework/*`) is\n * always handled by the SDK redirect plugin — callers may add more patterns\n * to be left as globals.\n */\n extraExternals?: string[];\n /**\n * Global name for the IIFE output object. Defaults to `__testBundle`.\n * The runtime entry uses this to call `__testBundle.runTestModule()`.\n */\n globalName?: string;\n}\n\n/**\n * The result of bundling a test file.\n * `code` is a self-contained IIFE string ready for `Runtime.evaluate`.\n */\nexport interface BundleResult {\n code: string;\n warnings: string[];\n}\n\n/** The SDK package name that mini-app test code imports from. */\nconst SDK_PACKAGE = '@apps-in-toss/web-framework';\n\n/**\n * Matches the bare SDK package and any sub-path import\n * (`@apps-in-toss/web-framework`, `@apps-in-toss/web-framework/foo`).\n * Built from {@link SDK_PACKAGE} so the package name has a single source.\n */\nconst SDK_IMPORT_FILTER = new RegExp(`^${SDK_PACKAGE.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}`);\n\n/**\n * esbuild plugin that intercepts SDK imports and redirects them to the\n * `window.__sdk` proxy that `src/in-app/auto.ts` installs at runtime.\n *\n * Strategy: for every import of `@apps-in-toss/web-framework` (or sub-paths),\n * esbuild resolves it to a virtual module that re-exports all named exports\n * via `window.__sdk[name]`. This avoids bundling the real SDK (which may not\n * be available in the test environment) while still making named imports work.\n *\n * If `window.__sdk` is absent (non-dog-food build), every access throws a\n * descriptive error rather than returning `undefined` silently.\n */\nfunction sdkRedirectPlugin(): esbuild.Plugin {\n return {\n name: 'sdk-redirect',\n setup(build) {\n // Match the bare package and any sub-path imports\n build.onResolve({ filter: SDK_IMPORT_FILTER }, (args) => ({\n path: args.path,\n namespace: 'sdk-redirect',\n }));\n\n build.onLoad({ filter: /.*/, namespace: 'sdk-redirect' }, () => ({\n // Generate a virtual CommonJS-style module so that esbuild does NOT perform\n // strict named-export matching. When `format:'iife'` bundles a CJS module,\n // it wraps it with its own __toCommonJS helper and satisfies named imports\n // via property access on the module.exports object — which is our Proxy.\n // This means `import { getPlatformOS } from '...'` becomes\n // `__proxy.getPlatformOS` at runtime, which correctly reads from window.__sdk.\n contents: `\nvar __proxy = (typeof window !== 'undefined' && window.__sdk)\n ? window.__sdk\n : new Proxy({}, {\n get: function(_t, p) {\n throw new Error('window.__sdk is not installed — run in a dog-food build. Missing: ' + String(p));\n }\n });\nmodule.exports = __proxy;\n`,\n loader: 'js',\n }));\n },\n };\n}\n\n/**\n * Bundles `absPath` into a single IIFE string suitable for `Runtime.evaluate`.\n *\n * The IIFE installs `window.__testBundle` (or the custom `globalName`) with\n * `runTestModule` as the callable entry point.\n *\n * @param absPath - Absolute path to the user test file.\n * @param opts - Optional bundling overrides.\n */\nexport async function bundleTestFile(absPath: string, opts?: BundleOptions): Promise<BundleResult> {\n const globalName = opts?.globalName ?? '__testBundle';\n const extraExternals = opts?.extraExternals ?? [];\n\n // Lazy load esbuild at call time (see the module-scope import note).\n const esbuild = await import('esbuild');\n\n const result = await esbuild.build({\n entryPoints: [absPath],\n bundle: true,\n format: 'iife',\n globalName,\n platform: 'browser',\n target: 'es2022',\n write: false,\n plugins: [sdkRedirectPlugin()],\n // Extra externals are left as global references (caller's responsibility\n // to ensure they exist in the WebView context).\n external: extraExternals,\n // Keep bundle self-contained; no dynamic require/import at runtime.\n treeShaking: true,\n });\n\n const warnings = result.warnings.map(\n (w) =>\n `${path.relative(process.cwd(), w.location?.file ?? '')}:${w.location?.line ?? '?'}: ${w.text}`,\n );\n\n const outputFile = result.outputFiles?.[0];\n if (!outputFile) {\n throw new Error('bundleTestFile: esbuild produced no output — check entryPoints');\n }\n\n return { code: outputFile.text, warnings };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAwDA,MAAM,oBAAoB,IAAI,OAAO,IAPjB,8BAOiC,QAAQ,uBAAuB,OAAO,GAAG;;;;;;;;;;;;;AAc9F,SAAS,oBAAoC;AAC3C,QAAO;EACL,MAAM;EACN,MAAM,OAAO;AAEX,SAAM,UAAU,EAAE,QAAQ,mBAAmB,GAAG,UAAU;IACxD,MAAM,KAAK;IACX,WAAW;IACZ,EAAE;AAEH,SAAM,OAAO;IAAE,QAAQ;IAAM,WAAW;IAAgB,SAAS;IAO/D,UAAU;;;;;;;;;;IAUV,QAAQ;IACT,EAAE;;EAEN;;;;;;;;;;;AAYH,eAAsB,eAAe,SAAiB,MAA6C;CACjG,MAAM,aAAa,MAAM,cAAc;CACvC,MAAM,iBAAiB,MAAM,kBAAkB,EAAE;CAKjD,MAAM,SAAS,OAFC,MAAM,OAAO,YAEA,MAAM;EACjC,aAAa,CAAC,QAAQ;EACtB,QAAQ;EACR,QAAQ;EACR;EACA,UAAU;EACV,QAAQ;EACR,OAAO;EACP,SAAS,CAAC,mBAAmB,CAAC;EAG9B,UAAU;EAEV,aAAa;EACd,CAAC;CAEF,MAAM,WAAW,OAAO,SAAS,KAC9B,MACC,GAAG,KAAK,SAAS,QAAQ,KAAK,EAAE,EAAE,UAAU,QAAQ,GAAG,CAAC,GAAG,EAAE,UAAU,QAAQ,IAAI,IAAI,EAAE,OAC5F;CAED,MAAM,aAAa,OAAO,cAAc;AACxC,KAAI,CAAC,WACH,OAAM,IAAI,MAAM,iEAAiE;AAGnF,QAAO;EAAE,MAAM,WAAW;EAAM;EAAU"}
@@ -0,0 +1,417 @@
1
+
2
+ //#region src/mcp/cdp-connection.d.ts
3
+ /**
4
+ * Injectable CDP connection abstraction for the debug-mode MCP server.
5
+ *
6
+ * The Phase 1 tool layer (`list_console_messages`, `list_network_requests`,
7
+ * `list_pages`) reads from CDP events captured off a Chii relay connection.
8
+ * To keep that tool layer CI-verifiable without a phone roundtrip, the actual
9
+ * relay websocket sits behind this interface. Production wires
10
+ * `ChiiCdpConnection` (see `chii-connection.ts`); tests inject a fake that
11
+ * emits canned `Runtime.consoleAPICalled` / `Network.*` events.
12
+ *
13
+ * Phase 2 adds CDP *commands* (request→response): `DOM.getDocument`,
14
+ * `DOMSnapshot.captureSnapshot`, `Page.captureScreenshot`. Unlike Phase 1's
15
+ * event streams these need a `send(method, params)` round-trip, so the
16
+ * connection grows a typed `send`. The fake returns canned command results.
17
+ *
18
+ * Phase 2 extension: `Runtime.evaluate` (read-only probe) added for the
19
+ * `measure_safe_area` tool — executes a JS snippet on the attached page and
20
+ * returns the result as a `RemoteObject`. The fake returns canned results for
21
+ * unit tests without a phone roundtrip.
22
+ *
23
+ * Only the slice of the Chrome DevTools Protocol the tools need is typed here.
24
+ */
25
+ /** A target (page) the Chii relay currently sees attached. */
26
+ interface CdpTarget {
27
+ /** Chii's internal target id (session UUID). */
28
+ id: string;
29
+ /** Page title reported by the in-app target. */
30
+ title: string;
31
+ /** Page URL reported by the in-app target. */
32
+ url: string;
33
+ }
34
+ /** `Runtime.RemoteObject` subset we surface for console args. */
35
+ interface CdpRemoteObject {
36
+ type: string;
37
+ subtype?: string;
38
+ value?: unknown;
39
+ description?: string;
40
+ className?: string;
41
+ }
42
+ /** Payload of a `Runtime.consoleAPICalled` event. */
43
+ interface ConsoleApiCalledEvent {
44
+ /** log | warning | error | info | debug | … */
45
+ type: string;
46
+ args: CdpRemoteObject[];
47
+ /** Milliseconds since epoch (CDP `Runtime.Timestamp`). */
48
+ timestamp: number;
49
+ executionContextId?: number;
50
+ stackTrace?: {
51
+ callFrames: Array<{
52
+ functionName: string;
53
+ url: string;
54
+ lineNumber: number;
55
+ columnNumber: number;
56
+ }>;
57
+ };
58
+ }
59
+ /** Payload of a `Network.requestWillBeSent` event (subset). */
60
+ interface NetworkRequestWillBeSentEvent {
61
+ requestId: string;
62
+ request: {
63
+ url: string;
64
+ method: string;
65
+ headers?: Record<string, string>;
66
+ };
67
+ /** CDP `Network.MonotonicTime` (seconds). */
68
+ timestamp: number;
69
+ /** Wall-clock seconds since epoch, when available. */
70
+ wallTime?: number;
71
+ type?: string;
72
+ }
73
+ /** Payload of a `Network.responseReceived` event (subset). */
74
+ interface NetworkResponseReceivedEvent {
75
+ requestId: string;
76
+ response: {
77
+ url: string;
78
+ status: number;
79
+ statusText: string;
80
+ mimeType?: string;
81
+ };
82
+ timestamp: number;
83
+ type?: string;
84
+ }
85
+ /**
86
+ * A single call frame in a `Runtime.exceptionThrown` stack trace.
87
+ * Subset of the CDP `Runtime.CallFrame` shape.
88
+ */
89
+ interface CdpCallFrame {
90
+ functionName: string;
91
+ scriptId?: string;
92
+ url: string;
93
+ lineNumber: number;
94
+ columnNumber: number;
95
+ }
96
+ /** Payload of a `Runtime.exceptionThrown` event. */
97
+ interface RuntimeExceptionThrownEvent {
98
+ /** Milliseconds since epoch (CDP `Runtime.Timestamp`). */
99
+ timestamp: number;
100
+ exceptionDetails: {
101
+ exceptionId: number;
102
+ text: string;
103
+ lineNumber: number;
104
+ columnNumber: number;
105
+ scriptId?: string;
106
+ url?: string;
107
+ stackTrace?: {
108
+ callFrames: CdpCallFrame[];
109
+ }; /** The thrown value as a CDP `RemoteObject`. */
110
+ exception?: CdpRemoteObject;
111
+ };
112
+ }
113
+ /** Map of the CDP event names Phase 1 consumes to their payload shapes. */
114
+ interface CdpEventMap {
115
+ 'Runtime.consoleAPICalled': ConsoleApiCalledEvent;
116
+ 'Network.requestWillBeSent': NetworkRequestWillBeSentEvent;
117
+ 'Network.responseReceived': NetworkResponseReceivedEvent;
118
+ 'Runtime.exceptionThrown': RuntimeExceptionThrownEvent;
119
+ }
120
+ type CdpEventName = keyof CdpEventMap;
121
+ /** A `DOM.Node` subset (recursive) returned by `DOM.getDocument`. */
122
+ interface CdpDomNode {
123
+ nodeId: number;
124
+ /** CDP node type (1 = element, 3 = text, 9 = document, …). */
125
+ nodeType: number;
126
+ nodeName: string;
127
+ /** Tag/local name for elements. */
128
+ localName?: string;
129
+ nodeValue?: string;
130
+ /** Flattened attribute list: `[name, value, name, value, …]`. */
131
+ attributes?: string[];
132
+ childNodeCount?: number;
133
+ children?: CdpDomNode[];
134
+ documentURL?: string;
135
+ baseURL?: string;
136
+ }
137
+ /** Result of `DOM.getDocument`. */
138
+ interface DomGetDocumentResult {
139
+ root: CdpDomNode;
140
+ }
141
+ /** Result of `DOMSnapshot.captureSnapshot` (subset we surface). */
142
+ interface DomSnapshotResult {
143
+ documents: unknown[];
144
+ strings: string[];
145
+ }
146
+ /** Result of `Page.captureScreenshot`. */
147
+ interface PageCaptureScreenshotResult {
148
+ /** Base64-encoded image bytes (PNG by default). */
149
+ data: string;
150
+ }
151
+ /**
152
+ * Params for `Runtime.evaluate`.
153
+ * Covers the subset used by the `measure_safe_area` read-only probe.
154
+ */
155
+ interface RuntimeEvaluateParams {
156
+ /** JavaScript expression to evaluate in the page context. */
157
+ expression: string;
158
+ /** Return the result as a plain JSON value (vs. a handle). Default false. */
159
+ returnByValue?: boolean;
160
+ /** Await a returned Promise before resolving. Default false. */
161
+ awaitPromise?: boolean;
162
+ }
163
+ /** Result of `Runtime.evaluate`. */
164
+ interface RuntimeEvaluateResult {
165
+ /** The evaluation result. */
166
+ result: CdpRemoteObject;
167
+ /** Present when evaluation threw an uncaught exception. */
168
+ exceptionDetails?: {
169
+ text: string;
170
+ exception?: CdpRemoteObject;
171
+ };
172
+ }
173
+ /**
174
+ * Map of CDP command method → params/result shape. Keeps `send` typed so a
175
+ * `DOM.getDocument` call resolves to a `DomGetDocumentResult`, etc.
176
+ */
177
+ interface CdpCommandMap {
178
+ 'DOM.getDocument': {
179
+ params: {
180
+ depth?: number;
181
+ pierce?: boolean;
182
+ };
183
+ result: DomGetDocumentResult;
184
+ };
185
+ 'DOMSnapshot.captureSnapshot': {
186
+ params: {
187
+ computedStyles?: string[];
188
+ };
189
+ result: DomSnapshotResult;
190
+ };
191
+ 'Page.captureScreenshot': {
192
+ params: {
193
+ format?: 'png' | 'jpeg' | 'webp';
194
+ quality?: number;
195
+ };
196
+ result: PageCaptureScreenshotResult;
197
+ };
198
+ 'Runtime.evaluate': {
199
+ params: RuntimeEvaluateParams;
200
+ result: RuntimeEvaluateResult;
201
+ };
202
+ }
203
+ type CdpCommandName = keyof CdpCommandMap;
204
+ /**
205
+ * The connection the tool layer reads from. The production implementation
206
+ * wraps the Chii relay's CDP websocket; tests inject a fake.
207
+ *
208
+ * Implementations are expected to maintain an internal ring buffer of recent
209
+ * events (so a tool call returns recent history rather than only live events).
210
+ */
211
+ interface CdpConnection {
212
+ /**
213
+ * Authoritative kind of this connection's transport (issue #348).
214
+ *
215
+ * - `'relay'` — backed by the Chii relay + cloudflared tunnel (a real-device
216
+ * WebView, env 3/4). `ChiiCdpConnection`.
217
+ * - `'local'` — backed by a direct CDP websocket to a local Chromium (env 1).
218
+ * `LocalCdpConnection`.
219
+ *
220
+ * This replaces the old `getEnvironment()` URL-pattern sniffing: the
221
+ * `mock` vs `relay` split is now a free, authoritative property of the
222
+ * connection itself, known before any target attaches. The `relay-dev` vs
223
+ * `relay-live` distinction is orthogonal (operator-supplied `liveIntent`,
224
+ * see `environment.ts`) because dog-food and production relays are
225
+ * byte-identical on the wire.
226
+ */
227
+ readonly kind: 'relay' | 'local';
228
+ /**
229
+ * Enable the CDP domains Phase 1 needs (`Runtime.enable`, `Network.enable`).
230
+ * Idempotent. Resolves once the relay has acknowledged (or immediately for a
231
+ * fake connection).
232
+ */
233
+ enableDomains(): Promise<void>;
234
+ /** Targets (pages) the relay currently sees attached. */
235
+ listTargets(): CdpTarget[];
236
+ /** Recent buffered events for a domain, oldest-first. */
237
+ getBufferedEvents<E extends CdpEventName>(event: E): ReadonlyArray<CdpEventMap[E]>;
238
+ /** Subscribe to live events. Returns an unsubscribe function. */
239
+ on<E extends CdpEventName>(event: E, listener: (payload: CdpEventMap[E]) => void): () => void;
240
+ /**
241
+ * Issue a CDP command (request → response). Phase 2's DOM/snapshot/screenshot
242
+ * tools use this; resolves with the typed result or rejects on a CDP error.
243
+ * Implementations must have called {@link enableDomains} first.
244
+ */
245
+ send<M extends CdpCommandName>(method: M, params?: CdpCommandMap[M]['params']): Promise<CdpCommandMap[M]['result']>;
246
+ /**
247
+ * Close the underlying transport and reject any in-flight commands.
248
+ * Optional so that minimal test fakes that don't need teardown remain
249
+ * compatible without change. Both `ChiiCdpConnection` and
250
+ * `LocalCdpConnection` already implement this.
251
+ */
252
+ close?(): void;
253
+ /**
254
+ * Refresh the attached-target list from the relay and return the result.
255
+ * Emits an internal `'target:attached'` event when a new target appears so
256
+ * that {@link waitForFirstTarget} can race against the polling round.
257
+ *
258
+ * Optional — only `ChiiCdpConnection` (relay mode) supports this; local
259
+ * connections and test fakes may omit it. Callers should guard with
260
+ * `connection.refreshTargets?.()`.
261
+ */
262
+ refreshTargets?(): Promise<CdpTarget[]>;
263
+ /**
264
+ * Waits until at least one target satisfying `filterFn` is attached, then
265
+ * resolves with the full target list at that moment.
266
+ *
267
+ * Optional — only `ChiiCdpConnection` provides the event-driven
268
+ * implementation. When absent, callers fall back to a generic polling loop.
269
+ *
270
+ * @param filterFn - Predicate the resolved targets must satisfy.
271
+ * @param timeoutMs - Reject after this many ms (default 90 000).
272
+ * @param pollIntervalMs - Fallback poll interval (default 500 ms).
273
+ */
274
+ waitForFirstTarget?(filterFn: (targets: CdpTarget[]) => boolean, timeoutMs?: number, pollIntervalMs?: number): Promise<CdpTarget[]>;
275
+ }
276
+ //#endregion
277
+ //#region src/test-runner/bundle.d.ts
278
+ /**
279
+ * esbuild-based bundler for user test files.
280
+ *
281
+ * Bundles a single test file into a self-contained IIFE string that can be
282
+ * injected into a WebView via `Runtime.evaluate`. The user's SDK imports
283
+ * (`@apps-in-toss/web-framework` and sub-paths) are intercepted via an
284
+ * esbuild plugin that redirects them to `window.__sdk`, which the in-app
285
+ * debug gate (`src/in-app/auto.ts`) installs as a namespace mirror of the
286
+ * SDK exports (works for both 2.x and 3.x SDK).
287
+ *
288
+ * SECRET-HANDLING: the returned bundle code is caller-managed; never log it.
289
+ */
290
+ /** Options accepted by `bundleTestFile`. */
291
+ interface BundleOptions {
292
+ /**
293
+ * Additional esbuild `external` patterns. The SDK package
294
+ * (`@apps-in-toss/web-framework` and `@apps-in-toss/web-framework/*`) is
295
+ * always handled by the SDK redirect plugin — callers may add more patterns
296
+ * to be left as globals.
297
+ */
298
+ extraExternals?: string[];
299
+ /**
300
+ * Global name for the IIFE output object. Defaults to `__testBundle`.
301
+ * The runtime entry uses this to call `__testBundle.runTestModule()`.
302
+ */
303
+ globalName?: string;
304
+ }
305
+ //#endregion
306
+ //#region src/test-runner/runtime.d.ts
307
+ /**
308
+ * Thin test runtime for WebView execution.
309
+ *
310
+ * This file is bundled by `bundle.ts` together with the user's test file
311
+ * into a single IIFE injected into the WebView via `Runtime.evaluate`.
312
+ * It MUST stay browser-compatible — no Node.js APIs allowed.
313
+ *
314
+ * Design: rather than shipping @vitest/runner verbatim into a WebView (where
315
+ * its Node-side internals cause issues), this runtime provides a minimal
316
+ * compatible API surface — describe/it/test/expect globals — collects results
317
+ * into a plain JSON-safe object, and exports `runTestModule` as the entry point.
318
+ *
319
+ * @vitest/runner and @vitest/expect are listed as dependencies so that the
320
+ * package's type contracts are available and so the browser-compatible subsets
321
+ * can be referenced. Full pool integration (PoolRunnerInitializer) is tracked
322
+ * in issue #645.
323
+ *
324
+ * NOTE: this file is imported by type from Node-side code (rpc.ts / relay-worker.ts)
325
+ * for the RunReport / TestResult type shapes. The runtime ITSELF is not imported
326
+ * at runtime on the Node side — only the types are used.
327
+ */
328
+ /**
329
+ * Result of a single test case.
330
+ * All fields are JSON-serialisable.
331
+ */
332
+ interface TestResult {
333
+ /** Full dot-joined test name including nested suite names. */
334
+ name: string;
335
+ /** `'pass'` or `'fail'`. `'skip'` for skipped tests. */
336
+ status: 'pass' | 'fail' | 'skip';
337
+ /** Duration in milliseconds. */
338
+ duration: number;
339
+ /** Error message (fail only). Does NOT include the expression/secret. */
340
+ error?: string;
341
+ }
342
+ /** Aggregate report returned by `runTestModule`. */
343
+ interface RunReport {
344
+ /** ISO timestamp of when `runTestModule` was called. */
345
+ startedAt: string;
346
+ /** Total elapsed milliseconds (wall-clock). */
347
+ duration: number;
348
+ passed: number;
349
+ failed: number;
350
+ skipped: number;
351
+ tests: TestResult[];
352
+ }
353
+ //#endregion
354
+ //#region src/test-runner/relay-worker.d.ts
355
+ /** Per-file result in the aggregate `RunReport`. */
356
+ interface FileResult {
357
+ /** Absolute or relative path to the test file. */
358
+ file: string;
359
+ /** Full run report for this file, or an error if bundling/injection failed. */
360
+ result: RunReport | {
361
+ error: string;
362
+ };
363
+ }
364
+ /** Aggregate report returned by `runTestFilesOverRelay`. */
365
+ interface RelayRunReport {
366
+ /** ISO timestamp of when the run started. */
367
+ startedAt: string;
368
+ /** Total elapsed wall-clock milliseconds. */
369
+ duration: number;
370
+ /** Per-file results in execution order. */
371
+ files: FileResult[];
372
+ /** Flattened totals across all files. */
373
+ totals: {
374
+ passed: number;
375
+ failed: number;
376
+ skipped: number;
377
+ total: number;
378
+ };
379
+ }
380
+ /** Options for `runTestFilesOverRelay`. */
381
+ interface RelayRunOptions {
382
+ /**
383
+ * Options forwarded to `bundleTestFile` for each file.
384
+ */
385
+ bundleOptions?: BundleOptions;
386
+ /**
387
+ * Per-file evaluate timeout in milliseconds. Defaults to 30 000.
388
+ * Increase for long-running suites or split the file.
389
+ */
390
+ timeoutMs?: number;
391
+ }
392
+ //#endregion
393
+ //#region src/test-runner/cli.d.ts
394
+ /** Options for `runWithConnection`. */
395
+ interface RunWithConnectionOptions extends RelayRunOptions {
396
+ /** If true, print a summary to stdout. Defaults to false in tests. */
397
+ printSummary?: boolean;
398
+ }
399
+ /**
400
+ * Runs `files` over `connection` and returns the aggregate report.
401
+ * This pure function is the testable core of the CLI; it is separate from
402
+ * `main()` so tests can call it without spawning a subprocess.
403
+ *
404
+ * TODO (#645): add real relay attach/detach lifecycle here (connect via
405
+ * Chii relay URL, call enableDomains, run, then close).
406
+ */
407
+ declare function runWithConnection(connection: CdpConnection, files: string[], opts?: RunWithConnectionOptions): Promise<RelayRunReport>;
408
+ /**
409
+ * CLI entry point.
410
+ *
411
+ * MVP: prints usage and a "relay attach required" notice. Real relay wiring
412
+ * (resolve CDP URL, attach, run, close) is tracked in issues #645 / #646.
413
+ */
414
+ declare function main(argv?: string[]): Promise<void>;
415
+ //#endregion
416
+ export { RunWithConnectionOptions, main, runWithConnection };
417
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","names":[],"sources":["../../src/mcp/cdp-connection.ts","../../src/test-runner/bundle.ts","../../src/test-runner/runtime.ts","../../src/test-runner/relay-worker.ts","../../src/test-runner/cli.ts"],"mappings":"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"}