flakelab 0.1.0 → 0.1.2

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 (322) hide show
  1. package/README.md +225 -38
  2. package/dist/analysis/blob-report.d.ts +15 -0
  3. package/dist/analysis/blob-report.js +137 -0
  4. package/dist/analysis/blob-report.js.map +1 -0
  5. package/dist/analysis/cli.d.ts +7 -0
  6. package/dist/analysis/cli.js +28 -0
  7. package/dist/analysis/cli.js.map +1 -0
  8. package/dist/analysis/schema.d.ts +175 -0
  9. package/dist/analysis/schema.js +34 -0
  10. package/dist/analysis/schema.js.map +1 -0
  11. package/dist/analysis/zip-archive.d.ts +6 -0
  12. package/dist/analysis/zip-archive.js +193 -0
  13. package/dist/analysis/zip-archive.js.map +1 -0
  14. package/dist/artifacts/paths.d.ts +3 -0
  15. package/dist/artifacts/paths.js +34 -0
  16. package/dist/artifacts/paths.js.map +1 -0
  17. package/dist/artifacts/retention.d.ts +1 -0
  18. package/dist/artifacts/retention.js +80 -0
  19. package/dist/artifacts/retention.js.map +1 -0
  20. package/dist/bisect/engine.js +0 -1
  21. package/dist/bisect/engine.js.map +1 -1
  22. package/dist/bisect/schema.d.ts +5 -6
  23. package/dist/bisect/schema.js +1 -2
  24. package/dist/bisect/schema.js.map +1 -1
  25. package/dist/bisect/solari-evaluator.js +9 -1
  26. package/dist/bisect/solari-evaluator.js.map +1 -1
  27. package/dist/ci/job-summary.d.ts +2 -0
  28. package/dist/ci/job-summary.js +120 -2
  29. package/dist/ci/job-summary.js.map +1 -1
  30. package/dist/ci/select-command.js +1 -1
  31. package/dist/ci/select-command.js.map +1 -1
  32. package/dist/ci/summary-command.js +12 -7
  33. package/dist/ci/summary-command.js.map +1 -1
  34. package/dist/cli-arguments.d.ts +44 -0
  35. package/dist/cli-arguments.js +356 -0
  36. package/dist/cli-arguments.js.map +1 -0
  37. package/dist/cli-command-help.d.ts +11 -0
  38. package/dist/cli-command-help.js +211 -0
  39. package/dist/cli-command-help.js.map +1 -0
  40. package/dist/cli-help.d.ts +5 -2
  41. package/dist/cli-help.js +122 -45
  42. package/dist/cli-help.js.map +1 -1
  43. package/dist/cli-option-definitions.d.ts +202 -0
  44. package/dist/cli-option-definitions.js +59 -0
  45. package/dist/cli-option-definitions.js.map +1 -0
  46. package/dist/cli.js +100 -100
  47. package/dist/cli.js.map +1 -1
  48. package/dist/commands/analyze-summary.d.ts +5 -0
  49. package/dist/commands/analyze-summary.js +89 -0
  50. package/dist/commands/analyze-summary.js.map +1 -0
  51. package/dist/commands/analyze.d.ts +6 -0
  52. package/dist/commands/analyze.js +128 -0
  53. package/dist/commands/analyze.js.map +1 -0
  54. package/dist/commands/bisect.d.ts +2 -2
  55. package/dist/commands/bisect.js +32 -3
  56. package/dist/commands/bisect.js.map +1 -1
  57. package/dist/commands/diagnose.d.ts +3 -2
  58. package/dist/commands/diagnose.js +355 -23
  59. package/dist/commands/diagnose.js.map +1 -1
  60. package/dist/commands/discover.d.ts +18 -2
  61. package/dist/commands/discover.js +215 -25
  62. package/dist/commands/discover.js.map +1 -1
  63. package/dist/commands/doctor.d.ts +2 -0
  64. package/dist/commands/doctor.js +66 -25
  65. package/dist/commands/doctor.js.map +1 -1
  66. package/dist/commands/investigate.d.ts +3 -2
  67. package/dist/commands/investigate.js +22 -3
  68. package/dist/commands/investigate.js.map +1 -1
  69. package/dist/commands/options.d.ts +123 -16
  70. package/dist/commands/options.js +24 -2
  71. package/dist/commands/options.js.map +1 -1
  72. package/dist/commands/prove.d.ts +2 -2
  73. package/dist/commands/prove.js +38 -1
  74. package/dist/commands/prove.js.map +1 -1
  75. package/dist/commands/repair.d.ts +8 -2
  76. package/dist/commands/repair.js +32 -9
  77. package/dist/commands/repair.js.map +1 -1
  78. package/dist/commands/replay.d.ts +2 -2
  79. package/dist/commands/replay.js +15 -2
  80. package/dist/commands/replay.js.map +1 -1
  81. package/dist/commands/report.d.ts +2 -2
  82. package/dist/commands/report.js +35 -10
  83. package/dist/commands/report.js.map +1 -1
  84. package/dist/commands/scan-summary.d.ts +7 -0
  85. package/dist/commands/scan-summary.js +175 -0
  86. package/dist/commands/scan-summary.js.map +1 -0
  87. package/dist/commands/scan.d.ts +9 -12
  88. package/dist/commands/scan.js +66 -62
  89. package/dist/commands/scan.js.map +1 -1
  90. package/dist/core/plan.js +1 -1
  91. package/dist/core/plan.js.map +1 -1
  92. package/dist/diagnosis/checkpoint.d.ts +6 -0
  93. package/dist/diagnosis/checkpoint.js +46 -0
  94. package/dist/diagnosis/checkpoint.js.map +1 -0
  95. package/dist/diagnosis/cli.d.ts +7 -0
  96. package/dist/diagnosis/cli.js +84 -0
  97. package/dist/diagnosis/cli.js.map +1 -0
  98. package/dist/diagnosis/recommendation.d.ts +13 -0
  99. package/dist/diagnosis/recommendation.js +95 -0
  100. package/dist/diagnosis/recommendation.js.map +1 -0
  101. package/dist/diagnosis/run-state.d.ts +52 -0
  102. package/dist/diagnosis/run-state.js +173 -0
  103. package/dist/diagnosis/run-state.js.map +1 -0
  104. package/dist/diagnosis/schema.d.ts +207 -0
  105. package/dist/diagnosis/schema.js +108 -0
  106. package/dist/diagnosis/schema.js.map +1 -0
  107. package/dist/diagnosis/solari-handoff.d.ts +9 -0
  108. package/dist/diagnosis/solari-handoff.js +40 -0
  109. package/dist/diagnosis/solari-handoff.js.map +1 -0
  110. package/dist/diagnosis/summary.d.ts +3 -0
  111. package/dist/diagnosis/summary.js +115 -0
  112. package/dist/diagnosis/summary.js.map +1 -0
  113. package/dist/discovery/auth-cookie.d.ts +19 -0
  114. package/dist/discovery/auth-cookie.js +26 -0
  115. package/dist/discovery/auth-cookie.js.map +1 -0
  116. package/dist/discovery/evaluate.d.ts +35 -2
  117. package/dist/discovery/evaluate.js +136 -30
  118. package/dist/discovery/evaluate.js.map +1 -1
  119. package/dist/discovery/event-loop.d.ts +25 -0
  120. package/dist/discovery/event-loop.js +84 -0
  121. package/dist/discovery/event-loop.js.map +1 -0
  122. package/dist/discovery/minimize.d.ts +61 -1
  123. package/dist/discovery/minimize.js +179 -7
  124. package/dist/discovery/minimize.js.map +1 -1
  125. package/dist/discovery/resource-loading.d.ts +25 -0
  126. package/dist/discovery/resource-loading.js +84 -0
  127. package/dist/discovery/resource-loading.js.map +1 -0
  128. package/dist/discovery/runner-environment.d.ts +26 -0
  129. package/dist/discovery/runner-environment.js +68 -0
  130. package/dist/discovery/runner-environment.js.map +1 -0
  131. package/dist/discovery/startup-event.d.ts +25 -0
  132. package/dist/discovery/startup-event.js +84 -0
  133. package/dist/discovery/startup-event.js.map +1 -0
  134. package/dist/discovery/storage-state.d.ts +26 -0
  135. package/dist/discovery/storage-state.js +86 -0
  136. package/dist/discovery/storage-state.js.map +1 -0
  137. package/dist/discovery/temporal-environment.d.ts +31 -0
  138. package/dist/discovery/temporal-environment.js +43 -0
  139. package/dist/discovery/temporal-environment.js.map +1 -0
  140. package/dist/discovery/visual-environment.d.ts +28 -0
  141. package/dist/discovery/visual-environment.js +42 -0
  142. package/dist/discovery/visual-environment.js.map +1 -0
  143. package/dist/domain/schema.d.ts +840 -20
  144. package/dist/domain/schema.js +216 -6
  145. package/dist/domain/schema.js.map +1 -1
  146. package/dist/faults/browser-context.d.ts +16 -0
  147. package/dist/faults/browser-context.js +60 -0
  148. package/dist/faults/browser-context.js.map +1 -0
  149. package/dist/faults/cookie-header.d.ts +5 -0
  150. package/dist/faults/cookie-header.js +25 -0
  151. package/dist/faults/cookie-header.js.map +1 -0
  152. package/dist/faults/document-bootstrap.d.ts +5 -0
  153. package/dist/faults/document-bootstrap.js +141 -0
  154. package/dist/faults/document-bootstrap.js.map +1 -0
  155. package/dist/faults/install.d.ts +1 -1
  156. package/dist/faults/install.js +199 -6
  157. package/dist/faults/install.js.map +1 -1
  158. package/dist/faults/pattern.d.ts +1 -0
  159. package/dist/faults/pattern.js +24 -0
  160. package/dist/faults/pattern.js.map +1 -0
  161. package/dist/investigator/agent.js +39 -17
  162. package/dist/investigator/agent.js.map +1 -1
  163. package/dist/investigator/ledger.d.ts +1 -1
  164. package/dist/investigator/ledger.js +2 -2
  165. package/dist/investigator/ledger.js.map +1 -1
  166. package/dist/investigator/safe-source.d.ts +1 -0
  167. package/dist/investigator/safe-source.js +12 -3
  168. package/dist/investigator/safe-source.js.map +1 -1
  169. package/dist/investigator/schema.d.ts +293 -2
  170. package/dist/investigator/schema.js +100 -2
  171. package/dist/investigator/schema.js.map +1 -1
  172. package/dist/proof/cli.d.ts +7 -0
  173. package/dist/proof/cli.js +108 -0
  174. package/dist/proof/cli.js.map +1 -0
  175. package/dist/proof/preflight.d.ts +4 -0
  176. package/dist/proof/preflight.js +9 -0
  177. package/dist/proof/preflight.js.map +1 -0
  178. package/dist/repair/generator.d.ts +12 -1
  179. package/dist/repair/generator.js +30 -6
  180. package/dist/repair/generator.js.map +1 -1
  181. package/dist/repair/remote-proof-runner.js +6 -10
  182. package/dist/repair/remote-proof-runner.js.map +1 -1
  183. package/dist/repair/schema.d.ts +77 -2
  184. package/dist/repair/schema.js +23 -2
  185. package/dist/repair/schema.js.map +1 -1
  186. package/dist/repair/solari-validator.d.ts +2 -0
  187. package/dist/repair/solari-validator.js +4 -6
  188. package/dist/repair/solari-validator.js.map +1 -1
  189. package/dist/repair/summary.d.ts +10 -0
  190. package/dist/repair/summary.js +58 -0
  191. package/dist/repair/summary.js.map +1 -0
  192. package/dist/repair/validator.d.ts +1 -0
  193. package/dist/repair/validator.js +53 -12
  194. package/dist/repair/validator.js.map +1 -1
  195. package/dist/report/bundle.js +16 -37
  196. package/dist/report/bundle.js.map +1 -1
  197. package/dist/report/model.js +131 -12
  198. package/dist/report/model.js.map +1 -1
  199. package/dist/report/open.d.ts +9 -0
  200. package/dist/report/open.js +23 -0
  201. package/dist/report/open.js.map +1 -1
  202. package/dist/report/report-client.css +2 -0
  203. package/dist/report/report-client.js +58 -0
  204. package/dist/report/schema.d.ts +115 -5
  205. package/dist/report/schema.js +24 -5
  206. package/dist/report/schema.js.map +1 -1
  207. package/dist/reproducer/schema.d.ts +89 -4
  208. package/dist/reproducer/schema.js +3 -4
  209. package/dist/reproducer/schema.js.map +1 -1
  210. package/dist/runner/execution-fault.d.ts +10 -0
  211. package/dist/runner/execution-fault.js +24 -0
  212. package/dist/runner/execution-fault.js.map +1 -0
  213. package/dist/runner/fault-proxy.d.ts +7 -0
  214. package/dist/runner/fault-proxy.js +366 -0
  215. package/dist/runner/fault-proxy.js.map +1 -0
  216. package/dist/runner/local.js +2 -2
  217. package/dist/runner/local.js.map +1 -1
  218. package/dist/runner/native-scan.d.ts +25 -0
  219. package/dist/runner/native-scan.js +306 -0
  220. package/dist/runner/native-scan.js.map +1 -0
  221. package/dist/runner/playwright-executor.d.ts +3 -0
  222. package/dist/runner/playwright-executor.js +125 -66
  223. package/dist/runner/playwright-executor.js.map +1 -1
  224. package/dist/runner/process-tree.d.ts +7 -0
  225. package/dist/runner/process-tree.js +62 -0
  226. package/dist/runner/process-tree.js.map +1 -0
  227. package/dist/runner/project-bridge.d.ts +7 -0
  228. package/dist/runner/project-bridge.js +83 -0
  229. package/dist/runner/project-bridge.js.map +1 -0
  230. package/dist/runner/trial-reporter.d.ts +7 -0
  231. package/dist/runner/trial-reporter.js +47 -0
  232. package/dist/runner/trial-reporter.js.map +1 -0
  233. package/dist/scan/failure-clusters.d.ts +24 -0
  234. package/dist/scan/failure-clusters.js +74 -0
  235. package/dist/scan/failure-clusters.js.map +1 -0
  236. package/dist/scan/schema.d.ts +170 -0
  237. package/dist/scan/schema.js +71 -0
  238. package/dist/scan/schema.js.map +1 -0
  239. package/dist/solari/executor.d.ts +5 -1
  240. package/dist/solari/executor.js +25 -17
  241. package/dist/solari/executor.js.map +1 -1
  242. package/dist/solari/run-demo.d.ts +13 -1
  243. package/dist/solari/run-demo.js +35 -16
  244. package/dist/solari/run-demo.js.map +1 -1
  245. package/dist/solari/usage.d.ts +8 -2
  246. package/dist/solari/usage.js +14 -4
  247. package/dist/solari/usage.js.map +1 -1
  248. package/dist/ui/boundary.d.ts +17 -0
  249. package/dist/ui/boundary.js +18 -0
  250. package/dist/ui/boundary.js.map +1 -0
  251. package/dist/ui/console.d.ts +4 -0
  252. package/dist/ui/console.js +11 -0
  253. package/dist/ui/console.js.map +1 -0
  254. package/dist/ui/document.d.ts +40 -0
  255. package/dist/ui/document.js +120 -0
  256. package/dist/ui/document.js.map +1 -0
  257. package/dist/ui/format.d.ts +8 -0
  258. package/dist/ui/format.js +32 -0
  259. package/dist/ui/format.js.map +1 -0
  260. package/dist/ui/progress.d.ts +17 -1
  261. package/dist/ui/progress.js +51 -8
  262. package/dist/ui/progress.js.map +1 -1
  263. package/dist/ui/status.d.ts +7 -0
  264. package/dist/ui/status.js +36 -0
  265. package/dist/ui/status.js.map +1 -0
  266. package/dist/ui/style.d.ts +8 -0
  267. package/dist/ui/style.js +22 -0
  268. package/dist/ui/style.js.map +1 -0
  269. package/dist/ui/text.d.ts +17 -0
  270. package/dist/ui/text.js +123 -0
  271. package/dist/ui/text.js.map +1 -0
  272. package/dist/ui/theme.d.ts +23 -0
  273. package/dist/ui/theme.js +77 -0
  274. package/dist/ui/theme.js.map +1 -0
  275. package/dist/ui/trial-progress.d.ts +13 -0
  276. package/dist/ui/trial-progress.js +42 -0
  277. package/dist/ui/trial-progress.js.map +1 -0
  278. package/package.json +14 -19
  279. package/dist/faults/network-delay.d.ts +0 -5
  280. package/dist/faults/network-delay.js +0 -34
  281. package/dist/faults/network-delay.js.map +0 -1
  282. package/dist/faults/request-failure.d.ts +0 -5
  283. package/dist/faults/request-failure.js +0 -24
  284. package/dist/faults/request-failure.js.map +0 -1
  285. package/dist/playwright.d.ts +0 -3
  286. package/dist/playwright.js +0 -21
  287. package/dist/playwright.js.map +0 -1
  288. package/dist/report/browser-entry.d.ts +0 -2
  289. package/dist/report/browser-entry.js +0 -15
  290. package/dist/report/browser-entry.js.map +0 -1
  291. package/dist/report/components/artifacts.d.ts +0 -4
  292. package/dist/report/components/artifacts.js +0 -6
  293. package/dist/report/components/artifacts.js.map +0 -1
  294. package/dist/report/components/experiments.d.ts +0 -4
  295. package/dist/report/components/experiments.js +0 -7
  296. package/dist/report/components/experiments.js.map +0 -1
  297. package/dist/report/components/hypotheses.d.ts +0 -4
  298. package/dist/report/components/hypotheses.js +0 -26
  299. package/dist/report/components/hypotheses.js.map +0 -1
  300. package/dist/report/components/indicators.d.ts +0 -32
  301. package/dist/report/components/indicators.js +0 -42
  302. package/dist/report/components/indicators.js.map +0 -1
  303. package/dist/report/components/layout.d.ts +0 -29
  304. package/dist/report/components/layout.js +0 -20
  305. package/dist/report/components/layout.js.map +0 -1
  306. package/dist/report/components/proof.d.ts +0 -4
  307. package/dist/report/components/proof.js +0 -34
  308. package/dist/report/components/proof.js.map +0 -1
  309. package/dist/report/components/reproduction.d.ts +0 -4
  310. package/dist/report/components/reproduction.js +0 -19
  311. package/dist/report/components/reproduction.js.map +0 -1
  312. package/dist/report/components/summary.d.ts +0 -4
  313. package/dist/report/components/summary.js +0 -12
  314. package/dist/report/components/summary.js.map +0 -1
  315. package/dist/report/components/verdict.d.ts +0 -4
  316. package/dist/report/components/verdict.js +0 -27
  317. package/dist/report/components/verdict.js.map +0 -1
  318. package/dist/report/report-app.d.ts +0 -6
  319. package/dist/report/report-app.js +0 -16
  320. package/dist/report/report-app.js.map +0 -1
  321. package/dist/report/report-details.css +0 -182
  322. package/dist/report/report.css +0 -404
@@ -1,46 +1,236 @@
1
1
  import { writeFile } from "node:fs/promises";
2
2
  import { basename, dirname, extname, resolve } from "node:path";
3
- import { discoverNetworkDelay } from "../discovery/minimize.js";
3
+ import { discoverAuthCookieExpiry } from "../discovery/auth-cookie.js";
4
+ import { discoverEventLoopStall } from "../discovery/event-loop.js";
5
+ import { discoverNetworkDelay, discoverResponseDuplication, discoverResponseReordering, discoverResponseTruncation, } from "../discovery/minimize.js";
6
+ import { discoverResourceLoadingDelay } from "../discovery/resource-loading.js";
7
+ import { discoverStartupEventDelay } from "../discovery/startup-event.js";
8
+ import { discoverStorageStateDelay } from "../discovery/storage-state.js";
9
+ import { discoverClockJump, discoverLocale, discoverTimezone, } from "../discovery/temporal-environment.js";
10
+ import { discoverAnimationSpeed, discoverReducedMotion, discoverViewport, } from "../discovery/visual-environment.js";
11
+ import { discoverSharedStateInterference, discoverWorkerPressure, } from "../discovery/runner-environment.js";
12
+ import { browserStorageAreaSchema, browserStorageKeySchema, cookieNameSchema, loadingResourceTypeSchema, localeSchema, startupEventSchema, timeZoneSchema, } from "../domain/schema.js";
4
13
  import { writeReproducer } from "../reproducer/file.js";
5
14
  import { createPlaywrightExecutor } from "../runner/playwright-executor.js";
6
- import { integerOption, rateOption, withInterruption } from "./options.js";
7
- export async function discover(selector, values) {
8
- const projectRoot = process.cwd();
9
- const outputPath = resolve(projectRoot, values.output);
10
- const seed = integerOption(values.seed, "seed");
11
- const trials = integerOption(values.trials, "trials");
12
- const minimumFailureRate = rateOption(values["min-rate"]);
13
- const result = await withInterruption(async (signal) => discoverNetworkDelay(createPlaywrightExecutor(projectRoot, selector, { signal }), {
14
- concurrency: integerOption(values.concurrency, "concurrency"),
15
- maximumDelayMs: integerOption(values["max-delay"], "max-delay"),
16
- minimumFailureRate,
17
- pattern: values.pattern,
18
- seed,
19
- signal,
20
- trials,
21
- }));
22
- await writeReproducer(outputPath, {
23
- version: 1,
24
- test: selector,
15
+ import { formatSeconds } from "../ui/format.js";
16
+ import { ProgressReporter } from "../ui/progress.js";
17
+ import { TrialProgress } from "../ui/trial-progress.js";
18
+ import { integerOption, positiveNumberOption, rateOption, withInterruption } from "./options.js";
19
+ function requiredFaultOption(value, option, fault) {
20
+ if (!value) {
21
+ throw new Error(`${fault} requires --${option} <value>`);
22
+ }
23
+ return value;
24
+ }
25
+ export function buildDiscoveredReproducer(test, seed, minimumRate, trigger, triggerResult) {
26
+ return {
27
+ test,
25
28
  seed,
26
- trials,
27
- faults: [result.trigger],
29
+ trials: triggerResult.trials,
30
+ faults: [trigger],
28
31
  expectedFailure: {
29
- minimumRate: minimumFailureRate,
30
- ...(result.triggerResult.dominantFailureSignature
31
- ? { signature: result.triggerResult.dominantFailureSignature }
32
+ minimumRate,
33
+ ...(triggerResult.dominantFailureSignature
34
+ ? { signature: triggerResult.dominantFailureSignature }
32
35
  : {}),
33
36
  },
37
+ };
38
+ }
39
+ async function runEnvironmentDiscovery(execute, values, common) {
40
+ if (values.fault === "animation-speed") {
41
+ return discoverAnimationSpeed(execute, {
42
+ ...common,
43
+ rate: positiveNumberOption(values["animation-rate"], "animation-rate"),
44
+ });
45
+ }
46
+ if (values.fault === "auth-cookie-expiry") {
47
+ return discoverAuthCookieExpiry(execute, {
48
+ ...common,
49
+ cookieName: cookieNameSchema.parse(requiredFaultOption(values["cookie-name"], "cookie-name", "auth-cookie-expiry")),
50
+ });
51
+ }
52
+ if (values.fault === "clock-jump") {
53
+ return discoverClockJump(execute, {
54
+ ...common,
55
+ jumpAfterMs: integerOption(values["jump-after-ms"], "jump-after-ms"),
56
+ offsetMs: integerOption(values["clock-offset-ms"], "clock-offset-ms"),
57
+ });
58
+ }
59
+ if (values.fault === "event-loop-stall") {
60
+ return discoverEventLoopStall(execute, {
61
+ ...common,
62
+ maximumDurationMs: integerOption(values["max-stall-ms"], "max-stall-ms"),
63
+ startAfterMs: integerOption(values["stall-after-ms"], "stall-after-ms"),
64
+ });
65
+ }
66
+ if (values.fault === "locale") {
67
+ return discoverLocale(execute, { ...common, locale: localeSchema.parse(values.locale) });
68
+ }
69
+ if (values.fault === "reduced-motion") {
70
+ return discoverReducedMotion(execute, common);
71
+ }
72
+ if (values.fault === "storage-state-delay") {
73
+ return discoverStorageStateDelay(execute, {
74
+ ...common,
75
+ key: browserStorageKeySchema.parse(requiredFaultOption(values["storage-key"], "storage-key", "storage-state-delay")),
76
+ maximumDelayMs: integerOption(values["max-delay"], "max-delay"),
77
+ storage: browserStorageAreaSchema.parse(values.storage),
78
+ });
79
+ }
80
+ if (values.fault === "timezone") {
81
+ return discoverTimezone(execute, {
82
+ ...common,
83
+ timezoneId: timeZoneSchema.parse(values.timezone),
84
+ });
85
+ }
86
+ if (values.fault === "viewport") {
87
+ return discoverViewport(execute, {
88
+ ...common,
89
+ height: integerOption(values["viewport-height"], "viewport-height"),
90
+ width: integerOption(values["viewport-width"], "viewport-width"),
91
+ });
92
+ }
93
+ return undefined;
94
+ }
95
+ async function runRunnerDiscovery(execute, selector, values, common) {
96
+ if (values.fault === "shared-state-interference") {
97
+ return discoverSharedStateInterference(execute, {
98
+ ...common,
99
+ maximumCopies: integerOption(values["max-copies"], "max-copies"),
100
+ pattern: selector,
101
+ });
102
+ }
103
+ if (values.fault === "worker-pressure") {
104
+ return discoverWorkerPressure(execute, {
105
+ ...common,
106
+ maximumWorkers: integerOption(values["max-workers"], "max-workers"),
107
+ pattern: selector,
108
+ });
109
+ }
110
+ return undefined;
111
+ }
112
+ /**
113
+ * Reports one line per completed trial: the running count, the outcome, how long
114
+ * the trial took, and how much of the elapsed-time budget remains. Nothing else
115
+ * about an individual trial reaches the terminal.
116
+ */
117
+ function countedExecutor(executeTrial, progress) {
118
+ return async (trial) => {
119
+ const outcome = await executeTrial(trial);
120
+ progress.trial(outcome.status, outcome.durationMs);
121
+ return outcome;
122
+ };
123
+ }
124
+ async function runDiscovery(selector, values, progress, signal) {
125
+ const common = {
126
+ concurrency: integerOption(values.concurrency, "concurrency"),
127
+ minimumFailureRate: rateOption(values["min-rate"]),
128
+ pattern: values.pattern,
129
+ seed: integerOption(values.seed, "seed"),
130
+ signal,
131
+ trials: integerOption(values.trials, "trials"),
132
+ };
133
+ const executeTrial = createPlaywrightExecutor(process.cwd(), selector, { signal });
134
+ const execute = countedExecutor(executeTrial, progress);
135
+ const runnerResult = await runRunnerDiscovery(execute, selector, values, common);
136
+ if (runnerResult) {
137
+ return runnerResult;
138
+ }
139
+ const environmentResult = await runEnvironmentDiscovery(execute, values, common);
140
+ if (environmentResult) {
141
+ return environmentResult;
142
+ }
143
+ if (values.fault === "network-delay") {
144
+ return discoverNetworkDelay(execute, {
145
+ ...common,
146
+ maximumDelayMs: integerOption(values["max-delay"], "max-delay"),
147
+ });
148
+ }
149
+ if (values.fault === "response-truncation") {
150
+ return discoverResponseTruncation(execute, {
151
+ ...common,
152
+ maximumRemoveBytes: integerOption(values["max-remove-bytes"], "max-remove-bytes"),
153
+ });
154
+ }
155
+ if (values.fault === "response-duplication") {
156
+ return discoverResponseDuplication(execute, {
157
+ ...common,
158
+ maximumDuplicateBytes: integerOption(values["max-duplicate-bytes"], "max-duplicate-bytes"),
159
+ });
160
+ }
161
+ if (values.fault === "response-reordering") {
162
+ return discoverResponseReordering(execute, {
163
+ ...common,
164
+ maximumHoldMs: integerOption(values["max-hold-ms"], "max-hold-ms"),
165
+ });
166
+ }
167
+ if (values.fault === "resource-loading-delay") {
168
+ return discoverResourceLoadingDelay(execute, {
169
+ ...common,
170
+ maximumDelayMs: integerOption(values["max-delay"], "max-delay"),
171
+ resourceType: loadingResourceTypeSchema.parse(values["resource-type"]),
172
+ });
173
+ }
174
+ if (values.fault === "startup-event-delay") {
175
+ return discoverStartupEventDelay(execute, {
176
+ ...common,
177
+ event: startupEventSchema.parse(values["startup-event"]),
178
+ maximumDelayMs: integerOption(values["max-delay"], "max-delay"),
179
+ });
180
+ }
181
+ throw new Error("fault must be animation-speed, auth-cookie-expiry, clock-jump, event-loop-stall, locale, network-delay, reduced-motion, resource-loading-delay, response-duplication, response-reordering, response-truncation, shared-state-interference, startup-event-delay, storage-state-delay, timezone, viewport, or worker-pressure");
182
+ }
183
+ function describeTrigger(result) {
184
+ const parts = [result.trigger.kind];
185
+ if ("minimumDelayMs" in result) {
186
+ parts.push(`minimum delay ${result.minimumDelayMs} ms`);
187
+ }
188
+ if ("minimumDurationMs" in result) {
189
+ parts.push(`minimum duration ${result.minimumDurationMs} ms`);
190
+ }
191
+ const observed = result.triggerResult;
192
+ parts.push(`${observed.failed}/${observed.trials} failures confirmed`);
193
+ return parts.join(" · ");
194
+ }
195
+ async function runBoundedDiscovery(selector, values, progress, maxSeconds) {
196
+ return withInterruption(async (signal) => runDiscovery(selector, values, progress, signal), {
197
+ maxSeconds,
198
+ timeoutMessage: `Discovery stopped after reaching --max-seconds ${maxSeconds}`,
34
199
  });
200
+ }
201
+ async function reportedDiscovery(selector, values, progress, maxSeconds, reporter) {
202
+ try {
203
+ return await runBoundedDiscovery(selector, values, progress, maxSeconds);
204
+ }
205
+ catch (error) {
206
+ reporter.fail(`no confirmed trigger · ${progress.completed} trials`);
207
+ throw error;
208
+ }
209
+ }
210
+ export async function discover(selector, values) {
211
+ const projectRoot = process.cwd();
212
+ const outputPath = resolve(projectRoot, values.output);
213
+ const seed = integerOption(values.seed, "seed");
214
+ const minimumFailureRate = rateOption(values["min-rate"]);
215
+ const maxSeconds = positiveNumberOption(values["max-seconds"], "max-seconds");
216
+ const reporter = new ProgressReporter();
217
+ reporter.start(`discovery · ${values.fault}`, `bounded to ${formatSeconds(maxSeconds)} · stable triggers receive a 12-trial confirmation`);
218
+ const progress = new TrialProgress(reporter, maxSeconds);
219
+ const result = await reportedDiscovery(selector, values, progress, maxSeconds, reporter);
220
+ reporter.done(`${describeTrigger(result)} · ${progress.completed} trials`);
221
+ await writeReproducer(outputPath, buildDiscoveredReproducer(selector, seed, minimumFailureRate, result.trigger, result.triggerResult));
35
222
  const discoveryPath = resolve(dirname(outputPath), `${basename(outputPath, extname(outputPath))}.discovery.json`);
36
223
  await writeFile(discoveryPath, `${JSON.stringify(result, null, 2)}\n`, { encoding: "utf8" });
37
224
  console.log(JSON.stringify({
38
225
  baseline: result.baseline,
39
226
  experiments: result.experiments.length,
227
+ ...("minimumDelayMs" in result ? { minimumDelayMs: result.minimumDelayMs } : {}),
228
+ ...("minimumDurationMs" in result ? { minimumDurationMs: result.minimumDurationMs } : {}),
40
229
  reproducerPath: outputPath,
41
230
  discoveryPath,
42
231
  trigger: result.trigger,
43
232
  triggerResult: result.triggerResult,
44
233
  }, null, 2));
234
+ return result;
45
235
  }
46
236
  //# sourceMappingURL=discover.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/commands/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;AAE3E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB,EAAE,MAAiB;IAChE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACjC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACtD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACrD,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;IACzD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAC1E,wBAAwB,CAAC,WAAW,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAC3D;QACE,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC;QAC7D,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;QAC/D,kBAAkB;QAClB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI;QACJ,MAAM;QACN,MAAM;KACP,CACF,CAAC,CAAA;IACF,MAAM,eAAe,CAAC,UAAU,EAAE;QAChC,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,QAAQ;QACd,IAAI;QACJ,MAAM;QACN,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;QACxB,eAAe,EAAE;YACf,WAAW,EAAE,kBAAkB;YAC/B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,wBAAwB;gBAC/C,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,aAAa,CAAC,wBAAwB,EAAE;gBAC9D,CAAC,CAAC,EAAE,CAAC;SACR;KACF,CAAC,CAAA;IACF,MAAM,aAAa,GAAG,OAAO,CAC3B,OAAO,CAAC,UAAU,CAAC,EACnB,GAAG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAC9D,CAAA;IACD,MAAM,SAAS,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;IAC5F,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM;QACtC,cAAc,EAAE,UAAU;QAC1B,aAAa;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;KACpC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AACd,CAAC"}
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/commands/discover.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
+ import type { TerminalTheme } from "../ui/theme.js";
1
2
  interface DoctorOptions {
2
3
  environment?: NodeJS.ProcessEnv;
3
4
  loadEnvironmentFile?: boolean;
4
5
  projectRoot?: string;
6
+ theme?: TerminalTheme;
5
7
  write?: (message: string) => void;
6
8
  }
7
9
  export declare function doctor(options?: DoctorOptions): Promise<void>;
@@ -4,6 +4,9 @@ import { existsSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
  import { promisify } from "node:util";
6
6
  import { credentialStatus } from "../security/credentials.js";
7
+ import { TerminalDocument } from "../ui/document.js";
8
+ import { formatCount } from "../ui/format.js";
9
+ import { PLAIN_THEME, stdoutTheme } from "../ui/theme.js";
7
10
  const execFileAsync = promisify(execFile);
8
11
  const PLAYWRIGHT_CONFIGS = [
9
12
  "playwright.config.ts",
@@ -13,8 +16,17 @@ const PLAYWRIGHT_CONFIGS = [
13
16
  "playwright.config.cts",
14
17
  "playwright.config.cjs",
15
18
  ];
16
- function check(label, passed, detail) {
17
- return { detail, label, status: passed ? "pass" : "warn" };
19
+ const CHECK_TONES = {
20
+ pass: "success",
21
+ warn: "warning",
22
+ };
23
+ function check(label, passed, detail, remedy) {
24
+ return {
25
+ detail,
26
+ label,
27
+ ...(passed || remedy === undefined ? {} : { remedy }),
28
+ status: passed ? "pass" : "warn",
29
+ };
18
30
  }
19
31
  function credentialCheck(provider, status) {
20
32
  if (status.configured) {
@@ -44,35 +56,64 @@ async function evidenceDirectoryIgnored(projectRoot) {
44
56
  return false;
45
57
  }
46
58
  }
47
- function formatCheck(result) {
48
- const symbol = result.status === "pass" ? "" : "!";
49
- return `${symbol} ${result.label} · ${result.detail}`;
59
+ function environmentChecks(projectRoot, evidenceIgnored) {
60
+ const majorNodeVersion = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
61
+ const hasPlaywrightConfig = PLAYWRIGHT_CONFIGS.some((file) => existsSync(resolve(projectRoot, file)));
62
+ const chromiumInstalled = existsSync(chromium.executablePath());
63
+ return [
64
+ check("Node.js", majorNodeVersion >= 20, `${process.versions.node} · requires 20 or newer`),
65
+ check("Playwright project", hasPlaywrightConfig, hasPlaywrightConfig ? "configuration detected" : "no playwright.config file detected", "npm init playwright@latest"),
66
+ check("Chromium", chromiumInstalled, chromiumInstalled ? "browser executable available" : "browser executable is missing", "npx playwright install chromium"),
67
+ check("Evidence privacy", evidenceIgnored, evidenceIgnored
68
+ ? ".flakelab output is ignored by Git"
69
+ : ".flakelab output is not ignored by Git", "echo .flakelab/ >> .gitignore"),
70
+ ];
71
+ }
72
+ function appendChecks(document, title, results) {
73
+ document.section(title);
74
+ for (const result of results) {
75
+ document.entry(CHECK_TONES[result.status], `${result.label} · ${result.detail}`);
76
+ }
77
+ }
78
+ function renderDoctor(theme, environment, credentials) {
79
+ const results = [...environment, ...credentials];
80
+ const warnings = results.filter((result) => result.status === "warn");
81
+ const document = new TerminalDocument(theme);
82
+ document.heading("doctor");
83
+ document.verdict(warnings.length === 0 ? "success" : "warning", warnings.length === 0 ? "ready" : "ready with warnings", warnings.length === 0
84
+ ? `${formatCount(results.length, "check")} passed`
85
+ : `${results.length - warnings.length} of ${results.length} checks passed`
86
+ + ` · ${formatCount(warnings.length, "item")} to review`);
87
+ appendChecks(document, "Environment", environment);
88
+ appendChecks(document, "Credentials", credentials);
89
+ const remedies = warnings
90
+ .map((result) => result.remedy)
91
+ .filter((remedy) => remedy !== undefined);
92
+ if (remedies.length > 0) {
93
+ document.section("Next");
94
+ for (const remedy of remedies) {
95
+ document.command(remedy);
96
+ }
97
+ }
98
+ return document.render();
50
99
  }
51
100
  export async function doctor(options = {}) {
52
101
  const projectRoot = options.projectRoot ?? process.cwd();
53
102
  const environment = options.environment ?? process.env;
54
- const majorNodeVersion = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
55
- const hasPlaywrightConfig = PLAYWRIGHT_CONFIGS.some((file) => existsSync(resolve(projectRoot, file)));
56
- const results = [
57
- check("Node.js", majorNodeVersion >= 20, `${process.versions.node} · requires 20 or newer`),
58
- check("Playwright project", hasPlaywrightConfig, hasPlaywrightConfig
59
- ? "configuration detected"
60
- : "no playwright.config file detected"),
61
- check("Chromium", existsSync(chromium.executablePath()), existsSync(chromium.executablePath())
62
- ? "browser executable available"
63
- : "run npx playwright install chromium"),
64
- check("Evidence privacy", await evidenceDirectoryIgnored(projectRoot), ".flakelab output is ignored by Git"),
65
- credentialCheck("groq", credentialStatus("groq", {
66
- environment,
67
- loadEnvironmentFile: options.loadEnvironmentFile,
68
- })),
69
- credentialCheck("solari", credentialStatus("solari", {
70
- environment,
71
- loadEnvironmentFile: options.loadEnvironmentFile,
72
- })),
103
+ const credentialOptions = {
104
+ environment,
105
+ ...(options.loadEnvironmentFile === undefined
106
+ ? {}
107
+ : { loadEnvironmentFile: options.loadEnvironmentFile }),
108
+ };
109
+ const checks = environmentChecks(projectRoot, await evidenceDirectoryIgnored(projectRoot));
110
+ const credentials = [
111
+ credentialCheck("groq", credentialStatus("groq", credentialOptions)),
112
+ credentialCheck("solari", credentialStatus("solari", credentialOptions)),
73
113
  check("Credential isolation", true, "provider keys are removed from Playwright processes"),
74
114
  ];
75
115
  const write = options.write ?? ((message) => process.stdout.write(message));
76
- write(`FlakeLab doctor\n\n${results.map(formatCheck).join("\n")}\n`);
116
+ const theme = options.theme ?? (options.write ? PLAIN_THEME : stdoutTheme());
117
+ write(`${renderDoctor(theme, checks, credentials)}\n`);
77
118
  }
78
119
  //# sourceMappingURL=doctor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAK7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEzD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AACzC,MAAM,kBAAkB,GAAG;IACzB,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;CACxB,CAAA;AAiBD,MAAM,WAAW,GAA8C;IAC7D,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;CAChB,CAAA;AAED,SAAS,KAAK,CACZ,KAAa,EACb,MAAe,EACf,MAAc,EACd,MAAe;IAEf,OAAO;QACL,MAAM;QACN,KAAK;QACL,GAAG,CAAC,MAAM,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QACrD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;KACjC,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,QAA4B,EAAE,MAAwB;IAC7E,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,OAAO;YACL,MAAM,EAAE,kBAAkB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,eAAe,EAAE;YAClF,KAAK,EAAE,MAAM,CAAC,eAAe;YAC7B,MAAM,EAAE,MAAM;SACf,CAAA;IACH,CAAC;IACD,OAAO;QACL,MAAM,EAAE,QAAQ,KAAK,MAAM;YACzB,CAAC,CAAC,yDAAyD;YAC3D,CAAC,CAAC,qEAAqE;QACzE,KAAK,EAAE,MAAM,CAAC,eAAe;QAC7B,MAAM,EAAE,MAAM;KACf,CAAA;AACH,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,WAAmB;IACzD,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,0BAA0B,CAAC,EAAE;YAClF,GAAG,EAAE,WAAW;YAChB,WAAW,EAAE,IAAI;SAClB,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,WAAmB,EAAE,eAAwB;IACtE,MAAM,gBAAgB,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAA;IACxF,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,IAAI,CACjD,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CACjD,CAAA;IACD,MAAM,iBAAiB,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAA;IAC/D,OAAO;QACL,KAAK,CAAC,SAAS,EAAE,gBAAgB,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,yBAAyB,CAAC;QAC3F,KAAK,CACH,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,oCAAoC,EACrF,4BAA4B,CAC7B;QACD,KAAK,CACH,UAAU,EACV,iBAAiB,EACjB,iBAAiB,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,+BAA+B,EACpF,iCAAiC,CAClC;QACD,KAAK,CACH,kBAAkB,EAClB,eAAe,EACf,eAAe;YACb,CAAC,CAAC,oCAAoC;YACtC,CAAC,CAAC,wCAAwC,EAC5C,+BAA+B,CAChC;KACF,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CACnB,QAA0B,EAC1B,KAAa,EACb,OAAsB;IAEtB,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACvB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAClF,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CACnB,KAAoB,EACpB,WAA0B,EAC1B,WAA0B;IAE1B,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAA;IACrE,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAC5C,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC1B,QAAQ,CAAC,OAAO,CACd,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAC7C,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,EACvD,QAAQ,CAAC,MAAM,KAAK,CAAC;QACnB,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS;QAClD,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,gBAAgB;cACtE,MAAM,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,CAC7D,CAAA;IACD,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IAClD,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IAClD,MAAM,QAAQ,GAAG,QAAQ;SACtB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;SAC9B,MAAM,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;IAC7D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACxB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAA;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACtD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACxD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAA;IACtD,MAAM,iBAAiB,GAAG;QACxB,WAAW;QACX,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS;YAC3C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;KAC1D,CAAA;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,EAAE,MAAM,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAA;IAC1F,MAAM,WAAW,GAAG;QAClB,eAAe,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;QACpE,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QACxE,KAAK,CAAC,sBAAsB,EAAE,IAAI,EAAE,qDAAqD,CAAC;KAC3F,CAAA;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACnF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;IAC5E,KAAK,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;AACxD,CAAC"}
@@ -1,2 +1,3 @@
1
- import type { CliValues } from "./options.js";
2
- export declare function investigate(selector: string, values: CliValues): Promise<void>;
1
+ import type { InvestigationReport } from "../investigator/schema.js";
2
+ import type { InvestigateOptions } from "./options.js";
3
+ export declare function investigate(selector: string, values: InvestigateOptions): Promise<InvestigationReport>;
@@ -4,18 +4,34 @@ import { runInvestigation } from "../investigator/agent.js";
4
4
  import { createGroqInvestigatorModel, QWEN_INPUT_USD_PER_MILLION, QWEN_OUTPUT_USD_PER_MILLION, } from "../investigator/groq.js";
5
5
  import { createPlaywrightExecutor } from "../runner/playwright-executor.js";
6
6
  import { requireCredential } from "../security/credentials.js";
7
+ import { formatProviderBoundary } from "../ui/boundary.js";
8
+ import { writeStderr } from "../ui/console.js";
9
+ import { formatCount, formatUsd } from "../ui/format.js";
7
10
  import { ProgressReporter } from "../ui/progress.js";
11
+ import { stderrTheme } from "../ui/theme.js";
8
12
  import { integerOption, positiveNumberOption, rateOption, withInterruption, } from "./options.js";
9
13
  export async function investigate(selector, values) {
14
+ writeStderr(formatProviderBoundary({
15
+ credentials: ["GROQ_API_KEY"],
16
+ detail: "Only compact experiment results and redacted failure metadata are sent."
17
+ + " Source files, browser storage, and full logs are not transmitted.",
18
+ rows: [
19
+ { label: "Model", value: values.model },
20
+ { label: "Cost ceiling", value: `$${values["max-cost"]}` },
21
+ { label: "Time ceiling", value: `${values["max-seconds"]}s` },
22
+ { label: "Experiments", value: `at most ${values["max-experiments"]}` },
23
+ ],
24
+ stage: "bounded Groq investigation",
25
+ }, stderrTheme()));
10
26
  const apiKey = await requireCredential("groq", {
11
27
  forcePrompt: values["prompt-credentials"],
12
28
  });
13
29
  const projectRoot = process.cwd();
14
30
  const progress = new ProgressReporter();
15
- progress.start("Planning and running causal experiments");
31
+ progress.start("investigation", "planning and running causal experiments");
16
32
  const report = await withInterruption(async (signal) => runInvestigation({
17
33
  concurrency: integerOption(values.concurrency, "concurrency"),
18
- execute: createPlaywrightExecutor(projectRoot, selector, { signal }),
34
+ execute: createPlaywrightExecutor(projectRoot, selector, { captureTrace: true, signal }),
19
35
  inputUsdPerMillion: QWEN_INPUT_USD_PER_MILLION,
20
36
  maxCostUsd: positiveNumberOption(values["max-cost"], "max-cost"),
21
37
  maxExperiments: integerOption(values["max-experiments"], "max-experiments"),
@@ -35,9 +51,12 @@ export async function investigate(selector, values) {
35
51
  test: selector,
36
52
  trialsPerExperiment: integerOption(values.trials, "trials"),
37
53
  }));
38
- progress.done(`${report.experiments.length} experiments`);
54
+ progress.done(`${formatCount(report.experiments.length, "experiment")}`
55
+ + ` · ${report.usage.inputTokens + report.usage.outputTokens} tokens`
56
+ + ` · ${formatUsd(report.usage.estimatedCostUsd, 4)}`);
39
57
  const reportPath = resolve(projectRoot, values.report);
40
58
  await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, { encoding: "utf8" });
41
59
  console.log(JSON.stringify({ reportPath, ...report }, null, 2));
60
+ return report;
42
61
  }
43
62
  //# sourceMappingURL=investigate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"investigate.js","sourceRoot":"","sources":["../../src/commands/investigate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"investigate.js","sourceRoot":"","sources":["../../src/commands/investigate.ts"],"names":[],"mappings":"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"}