@reportforge/playwright-pdf 0.19.1 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1229,13 +1229,13 @@ var require_ast = __commonJS({
1229
1229
  helperExpression: function helperExpression(node) {
1230
1230
  return node.type === "SubExpression" || (node.type === "MustacheStatement" || node.type === "BlockStatement") && !!(node.params && node.params.length || node.hash);
1231
1231
  },
1232
- scopedId: function scopedId(path15) {
1233
- return /^\.|this\b/.test(path15.original);
1232
+ scopedId: function scopedId(path17) {
1233
+ return /^\.|this\b/.test(path17.original);
1234
1234
  },
1235
1235
  // an ID is simple if it only has one part, and that part is not
1236
1236
  // `..` or `this`.
1237
- simpleId: function simpleId(path15) {
1238
- return path15.parts.length === 1 && !AST.helpers.scopedId(path15) && !path15.depth;
1237
+ simpleId: function simpleId(path17) {
1238
+ return path17.parts.length === 1 && !AST.helpers.scopedId(path17) && !path17.depth;
1239
1239
  }
1240
1240
  }
1241
1241
  };
@@ -2309,12 +2309,12 @@ var require_helpers2 = __commonJS({
2309
2309
  loc
2310
2310
  };
2311
2311
  }
2312
- function prepareMustache(path15, params, hash, open, strip, locInfo) {
2312
+ function prepareMustache(path17, params, hash, open, strip, locInfo) {
2313
2313
  var escapeFlag = open.charAt(3) || open.charAt(2), escaped = escapeFlag !== "{" && escapeFlag !== "&";
2314
2314
  var decorator = /\*/.test(open);
2315
2315
  return {
2316
2316
  type: decorator ? "Decorator" : "MustacheStatement",
2317
- path: path15,
2317
+ path: path17,
2318
2318
  params,
2319
2319
  hash,
2320
2320
  escaped,
@@ -2634,9 +2634,9 @@ var require_compiler = __commonJS({
2634
2634
  },
2635
2635
  DecoratorBlock: function DecoratorBlock(decorator) {
2636
2636
  var program = decorator.program && this.compileProgram(decorator.program);
2637
- var params = this.setupFullMustacheParams(decorator, program, void 0), path15 = decorator.path;
2637
+ var params = this.setupFullMustacheParams(decorator, program, void 0), path17 = decorator.path;
2638
2638
  this.useDecorators = true;
2639
- this.opcode("registerDecorator", params.length, path15.original);
2639
+ this.opcode("registerDecorator", params.length, path17.original);
2640
2640
  },
2641
2641
  PartialStatement: function PartialStatement(partial) {
2642
2642
  this.usePartial = true;
@@ -2700,46 +2700,46 @@ var require_compiler = __commonJS({
2700
2700
  }
2701
2701
  },
2702
2702
  ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) {
2703
- var path15 = sexpr.path, name = path15.parts[0], isBlock = program != null || inverse != null;
2704
- this.opcode("getContext", path15.depth);
2703
+ var path17 = sexpr.path, name = path17.parts[0], isBlock = program != null || inverse != null;
2704
+ this.opcode("getContext", path17.depth);
2705
2705
  this.opcode("pushProgram", program);
2706
2706
  this.opcode("pushProgram", inverse);
2707
- path15.strict = true;
2708
- this.accept(path15);
2707
+ path17.strict = true;
2708
+ this.accept(path17);
2709
2709
  this.opcode("invokeAmbiguous", name, isBlock);
2710
2710
  },
2711
2711
  simpleSexpr: function simpleSexpr(sexpr) {
2712
- var path15 = sexpr.path;
2713
- path15.strict = true;
2714
- this.accept(path15);
2712
+ var path17 = sexpr.path;
2713
+ path17.strict = true;
2714
+ this.accept(path17);
2715
2715
  this.opcode("resolvePossibleLambda");
2716
2716
  },
2717
2717
  helperSexpr: function helperSexpr(sexpr, program, inverse) {
2718
- var params = this.setupFullMustacheParams(sexpr, program, inverse), path15 = sexpr.path, name = path15.parts[0];
2718
+ var params = this.setupFullMustacheParams(sexpr, program, inverse), path17 = sexpr.path, name = path17.parts[0];
2719
2719
  if (this.options.knownHelpers[name]) {
2720
2720
  this.opcode("invokeKnownHelper", params.length, name);
2721
2721
  } else if (this.options.knownHelpersOnly) {
2722
2722
  throw new _exception2["default"]("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
2723
2723
  } else {
2724
- path15.strict = true;
2725
- path15.falsy = true;
2726
- this.accept(path15);
2727
- this.opcode("invokeHelper", params.length, path15.original, _ast2["default"].helpers.simpleId(path15));
2724
+ path17.strict = true;
2725
+ path17.falsy = true;
2726
+ this.accept(path17);
2727
+ this.opcode("invokeHelper", params.length, path17.original, _ast2["default"].helpers.simpleId(path17));
2728
2728
  }
2729
2729
  },
2730
- PathExpression: function PathExpression(path15) {
2731
- this.addDepth(path15.depth);
2732
- this.opcode("getContext", path15.depth);
2733
- var name = path15.parts[0], scoped = _ast2["default"].helpers.scopedId(path15), blockParamId = !path15.depth && !scoped && this.blockParamIndex(name);
2730
+ PathExpression: function PathExpression(path17) {
2731
+ this.addDepth(path17.depth);
2732
+ this.opcode("getContext", path17.depth);
2733
+ var name = path17.parts[0], scoped = _ast2["default"].helpers.scopedId(path17), blockParamId = !path17.depth && !scoped && this.blockParamIndex(name);
2734
2734
  if (blockParamId) {
2735
- this.opcode("lookupBlockParam", blockParamId, path15.parts);
2735
+ this.opcode("lookupBlockParam", blockParamId, path17.parts);
2736
2736
  } else if (!name) {
2737
2737
  this.opcode("pushContext");
2738
- } else if (path15.data) {
2738
+ } else if (path17.data) {
2739
2739
  this.options.data = true;
2740
- this.opcode("lookupData", path15.depth, path15.parts, path15.strict);
2740
+ this.opcode("lookupData", path17.depth, path17.parts, path17.strict);
2741
2741
  } else {
2742
- this.opcode("lookupOnContext", path15.parts, path15.falsy, path15.strict, scoped);
2742
+ this.opcode("lookupOnContext", path17.parts, path17.falsy, path17.strict, scoped);
2743
2743
  }
2744
2744
  },
2745
2745
  StringLiteral: function StringLiteral(string) {
@@ -3095,16 +3095,16 @@ var require_util = __commonJS({
3095
3095
  }
3096
3096
  exports.urlGenerate = urlGenerate;
3097
3097
  function normalize(aPath) {
3098
- var path15 = aPath;
3098
+ var path17 = aPath;
3099
3099
  var url = urlParse(aPath);
3100
3100
  if (url) {
3101
3101
  if (!url.path) {
3102
3102
  return aPath;
3103
3103
  }
3104
- path15 = url.path;
3104
+ path17 = url.path;
3105
3105
  }
3106
- var isAbsolute = exports.isAbsolute(path15);
3107
- var parts = path15.split(/\/+/);
3106
+ var isAbsolute = exports.isAbsolute(path17);
3107
+ var parts = path17.split(/\/+/);
3108
3108
  for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
3109
3109
  part = parts[i];
3110
3110
  if (part === ".") {
@@ -3121,15 +3121,15 @@ var require_util = __commonJS({
3121
3121
  }
3122
3122
  }
3123
3123
  }
3124
- path15 = parts.join("/");
3125
- if (path15 === "") {
3126
- path15 = isAbsolute ? "/" : ".";
3124
+ path17 = parts.join("/");
3125
+ if (path17 === "") {
3126
+ path17 = isAbsolute ? "/" : ".";
3127
3127
  }
3128
3128
  if (url) {
3129
- url.path = path15;
3129
+ url.path = path17;
3130
3130
  return urlGenerate(url);
3131
3131
  }
3132
- return path15;
3132
+ return path17;
3133
3133
  }
3134
3134
  exports.normalize = normalize;
3135
3135
  function join(aRoot, aPath) {
@@ -5932,8 +5932,8 @@ var require_printer = __commonJS({
5932
5932
  return this.accept(sexpr.path) + " " + params + hash;
5933
5933
  };
5934
5934
  PrintVisitor.prototype.PathExpression = function(id) {
5935
- var path15 = id.parts.join("/");
5936
- return (id.data ? "@" : "") + "PATH:" + path15;
5935
+ var path17 = id.parts.join("/");
5936
+ return (id.data ? "@" : "") + "PATH:" + path17;
5937
5937
  };
5938
5938
  PrintVisitor.prototype.StringLiteral = function(string) {
5939
5939
  return '"' + string.value + '"';
@@ -5974,8 +5974,8 @@ var require_lib = __commonJS({
5974
5974
  handlebars.print = printer.print;
5975
5975
  module.exports = handlebars;
5976
5976
  function extension(module2, filename) {
5977
- var fs14 = __require("fs");
5978
- var templateString = fs14.readFileSync(filename, "utf8");
5977
+ var fs16 = __require("fs");
5978
+ var templateString = fs16.readFileSync(filename, "utf8");
5979
5979
  module2.exports = handlebars.compile(templateString);
5980
5980
  }
5981
5981
  if (typeof __require !== "undefined" && __require.extensions) {
@@ -6004,7 +6004,7 @@ var require_util2 = __commonJS({
6004
6004
  "node_modules/chrome-finder/lib/util.js"(exports, module) {
6005
6005
  "use strict";
6006
6006
  init_esm_shims();
6007
- var fs14 = __require("fs");
6007
+ var fs16 = __require("fs");
6008
6008
  var newLineRegex = /\r?\n/;
6009
6009
  function sort(installations, priorities) {
6010
6010
  const defaultPriority = 10;
@@ -6022,7 +6022,7 @@ var require_util2 = __commonJS({
6022
6022
  return false;
6023
6023
  }
6024
6024
  try {
6025
- fs14.accessSync(file);
6025
+ fs16.accessSync(file);
6026
6026
  return true;
6027
6027
  } catch (e) {
6028
6028
  return false;
@@ -6033,7 +6033,7 @@ var require_util2 = __commonJS({
6033
6033
  return false;
6034
6034
  }
6035
6035
  try {
6036
- var stat = fs14.statSync(file);
6036
+ var stat = fs16.statSync(file);
6037
6037
  return stat && typeof stat.isFile === "function" && stat.isFile();
6038
6038
  } catch (e) {
6039
6039
  return false;
@@ -6053,7 +6053,7 @@ var require_win32 = __commonJS({
6053
6053
  "node_modules/chrome-finder/lib/win32.js"(exports, module) {
6054
6054
  "use strict";
6055
6055
  init_esm_shims();
6056
- var path15 = __require("path");
6056
+ var path17 = __require("path");
6057
6057
  var { canAccess } = require_util2();
6058
6058
  function win32() {
6059
6059
  const installations = [];
@@ -6067,7 +6067,7 @@ var require_win32 = __commonJS({
6067
6067
  const prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env["PROGRAMFILES(X86)"]];
6068
6068
  prefixes.forEach((prefix) => suffixes.forEach((suffix) => {
6069
6069
  if (prefix) {
6070
- const chromePath = path15.join(prefix, suffix);
6070
+ const chromePath = path17.join(prefix, suffix);
6071
6071
  if (canAccess(chromePath)) {
6072
6072
  installations.push(chromePath);
6073
6073
  }
@@ -6085,7 +6085,7 @@ var require_darwin = __commonJS({
6085
6085
  "use strict";
6086
6086
  init_esm_shims();
6087
6087
  var { execSync: execSync3 } = __require("child_process");
6088
- var path15 = __require("path");
6088
+ var path17 = __require("path");
6089
6089
  var { canAccess, newLineRegex, sort } = require_util2();
6090
6090
  function darwin() {
6091
6091
  const suffixes = ["/Contents/MacOS/Google Chrome Canary", "/Contents/MacOS/Google Chrome", "/Contents/MacOS/Chromium"];
@@ -6095,7 +6095,7 @@ var require_darwin = __commonJS({
6095
6095
  ${LSREGISTER} -dump | grep -E -i -o '/.+(google chrome( canary)?|chromium)\\.app(\\s|$)' | grep -E -v 'Caches|TimeMachine|Temporary|/Volumes|\\.Trash'
6096
6096
  `).toString().split(newLineRegex).forEach((inst) => {
6097
6097
  suffixes.forEach((suffix) => {
6098
- const execPath = path15.join(inst.trim(), suffix);
6098
+ const execPath = path17.join(inst.trim(), suffix);
6099
6099
  if (canAccess(execPath)) {
6100
6100
  installations.push(execPath);
6101
6101
  }
@@ -6124,8 +6124,8 @@ var require_linux = __commonJS({
6124
6124
  "use strict";
6125
6125
  init_esm_shims();
6126
6126
  var { execSync: execSync3, execFileSync: execFileSync2 } = __require("child_process");
6127
- var path15 = __require("path");
6128
- var fs14 = __require("fs");
6127
+ var path17 = __require("path");
6128
+ var fs16 = __require("fs");
6129
6129
  var { canAccess, sort, isExecutable, newLineRegex } = require_util2();
6130
6130
  function findChromeExecutablesForLinuxDesktop(folder) {
6131
6131
  const argumentsRegex = /(^[^ ]+).*/;
@@ -6142,7 +6142,7 @@ var require_linux = __commonJS({
6142
6142
  function linux() {
6143
6143
  let installations = [];
6144
6144
  const desktopInstallationFolders = [
6145
- path15.join(__require("os").homedir(), ".local/share/applications/"),
6145
+ path17.join(__require("os").homedir(), ".local/share/applications/"),
6146
6146
  "/usr/share/applications/"
6147
6147
  ];
6148
6148
  desktopInstallationFolders.forEach((folder) => {
@@ -6168,7 +6168,7 @@ var require_linux = __commonJS({
6168
6168
  ].map((possiblePath) => {
6169
6169
  try {
6170
6170
  const chromePathToTest = possiblePath + "/" + executable;
6171
- if (fs14.existsSync(chromePathToTest) && canAccess(chromePathToTest) && isExecutable(chromePathToTest)) {
6171
+ if (fs16.existsSync(chromePathToTest) && canAccess(chromePathToTest) && isExecutable(chromePathToTest)) {
6172
6172
  installations.push(chromePathToTest);
6173
6173
  return chromePathToTest;
6174
6174
  }
@@ -6750,8 +6750,8 @@ function getErrorMap() {
6750
6750
  // node_modules/zod/v3/helpers/parseUtil.js
6751
6751
  init_esm_shims();
6752
6752
  var makeIssue = (params) => {
6753
- const { data, path: path15, errorMaps, issueData } = params;
6754
- const fullPath = [...path15, ...issueData.path || []];
6753
+ const { data, path: path17, errorMaps, issueData } = params;
6754
+ const fullPath = [...path17, ...issueData.path || []];
6755
6755
  const fullIssue = {
6756
6756
  ...issueData,
6757
6757
  path: fullPath
@@ -6871,11 +6871,11 @@ var errorUtil;
6871
6871
 
6872
6872
  // node_modules/zod/v3/types.js
6873
6873
  var ParseInputLazyPath = class {
6874
- constructor(parent, value, path15, key) {
6874
+ constructor(parent, value, path17, key) {
6875
6875
  this._cachedPath = [];
6876
6876
  this.parent = parent;
6877
6877
  this.data = value;
6878
- this._path = path15;
6878
+ this._path = path17;
6879
6879
  this._key = key;
6880
6880
  }
6881
6881
  get path() {
@@ -10482,9 +10482,17 @@ var failureAnalysisConfigSchema = external_exports.object({
10482
10482
  // Qualitative floor (not a numeric % — consistent with the match-strength design).
10483
10483
  minStrength: external_exports.enum(["weak", "moderate", "strong"]).default("weak"),
10484
10484
  maxFailuresToAnalyse: external_exports.number().int().min(1).default(500),
10485
- // Consumed by the Plan 3 feedback collector; inert until then.
10486
10485
  collectUnclassified: external_exports.boolean().default(true),
10487
- autoUpdateModel: external_exports.boolean().default(true)
10486
+ // What the feedback collector stores (while collectUnclassified is on):
10487
+ // 'blind-spots' = unknown/low-confidence only; 'all' = every model-scored
10488
+ // failure, so wrong-but-confident verdicts can be corrected by labeling.
10489
+ collectScope: external_exports.enum(["blind-spots", "all"]).default("blind-spots"),
10490
+ autoUpdateModel: external_exports.boolean().default(true),
10491
+ // Use the on-device trained model (when present and its evaluation gate passed).
10492
+ localModel: external_exports.boolean().default(true),
10493
+ // Override the local model file location (default ~/.reportforge/model-local.json).
10494
+ // Point at a repo-committed file to share a team-trained model with ephemeral CI.
10495
+ localModelPath: external_exports.string().optional()
10488
10496
  }).default({});
10489
10497
  var captureConfigSchema = external_exports.object({
10490
10498
  steps: external_exports.boolean().default(false),
@@ -10850,7 +10858,48 @@ import { createPublicKey as createPublicKey2, verify as verify2 } from "crypto";
10850
10858
 
10851
10859
  // src/analysis/model-bundle.ts
10852
10860
  init_esm_shims();
10853
- var MODEL = { "alpha": 1, "labels": ["assertion", "env-config", "flaky-by-retry", "locator-not-found", "navigation", "network", "timeout"], "logLikelihoods": { "assertion": { "NUM": -4.574710978503383, "assertionerror": -4.980176086611547, "be": -4.980176086611547, "cart": -4.980176086611547, "checkout": -4.980176086611547, "com": -4.980176086611547, "dashboard": -4.980176086611547, "deep": -4.980176086611547, "equal": -4.980176086611547, "equality": -4.980176086611547, "error": -4.980176086611547, "expect": -3.5938817254916566, "expected": -3.1083739097099556, "failed": -4.980176086611547, "false": -4.980176086611547, "got": -4.980176086611547, "id": -4.574710978503383, "john": -4.980176086611547, "locator": -4.574710978503383, "login": -4.980176086611547, "must": -4.980176086611547, "page": -4.980176086611547, "pattern": -4.980176086611547, "received": -3.275427994373122, "string": -4.980176086611547, "to": -4.980176086611547, "tobe": -4.980176086611547, "tobetruthy": -4.980176086611547, "toequal": -4.980176086611547, "tohavecount": -4.980176086611547, "tohavetext": -4.980176086611547, "tohavetitle": -4.980176086611547, "tohavevalue": -4.980176086611547, "truthy": -4.980176086611547, "value": -4.980176086611547 }, "env-config": { "NUM": -4.997212273764115, "api": -4.997212273764115, "at": -4.997212273764115, "back": -4.997212273764115, "base": -4.997212273764115, "baseurl": -4.997212273764115, "browsers": -4.997212273764115, "cannot": -4.997212273764115, "ci": -4.997212273764115, "config": -4.304065093204169, "directory": -4.591747165655951, "dotenv": -4.997212273764115, "enoent": -4.997212273764115, "env": -4.591747165655951, "environment": -4.591747165655951, "error": -4.08092154188996, "existent": -4.997212273764115, "failed": -4.997212273764115, "falling": -4.997212273764115, "file": -4.997212273764115, "find": -4.997212273764115, "from": -4.997212273764115, "in": -4.591747165655951, "invalid": -4.997212273764115, "is": -4.997212273764115, "json": -4.591747165655951, "key": -4.997212273764115, "load": -4.997212273764115, "missing": -4.997212273764115, "module": -4.997212273764115, "no": -4.997212273764115, "non": -4.997212273764115, "not": -4.997212273764115, "open": -4.997212273764115, "or": -4.997212273764115, "path": -4.997212273764115, "playwright": -4.591747165655951, "points": -4.997212273764115, "position": -4.997212273764115, "required": -4.997212273764115, "set": -4.997212273764115, "spec": -4.997212273764115, "such": -4.997212273764115, "syntaxerror": -4.997212273764115, "test": -4.997212273764115, "to": -4.304065093204169, "token": -4.997212273764115, "ts": -4.997212273764115, "tsconfig": -4.997212273764115, "undefined": -4.591747165655951, "unexpected": -4.997212273764115, "url": -4.997212273764115, "values": -4.997212273764115, "variable": -4.591747165655951 }, "flaky-by-retry": { "after": -4.58836306767171, "and": -4.993828175779875, "animation": -4.993828175779875, "attempt": -4.07753744390572, "between": -4.993828175779875, "blip": -4.993828175779875, "cause": -4.993828175779875, "change": -4.993828175779875, "click": -4.993828175779875, "code": -4.993828175779875, "commit": -4.993828175779875, "condition": -4.993828175779875, "dependency": -4.993828175779875, "detached": -4.993828175779875, "deterministic": -4.993828175779875, "element": -4.993828175779875, "failed": -4.300680995219929, "fails": -4.993828175779875, "flaky": -4.07753744390572, "green": -4.993828175779875, "in": -4.993828175779875, "intermittent": -4.993828175779875, "locator": -4.993828175779875, "marked": -4.993828175779875, "network": -4.993828175779875, "no": -4.993828175779875, "non": -4.993828175779875, "on": -3.895215887111765, "order": -4.993828175779875, "passed": -3.895215887111765, "quarantined": -4.993828175779875, "race": -4.993828175779875, "reproducible": -4.993828175779875, "rerun": -4.993828175779875, "retry": -4.07753744390572, "runs": -4.993828175779875, "same": -4.993828175779875, "second": -4.993828175779875, "stale": -4.993828175779875, "succeeded": -4.993828175779875, "test": -4.58836306767171, "the": -4.993828175779875, "then": -4.993828175779875, "timeout": -4.993828175779875, "unstable": -4.993828175779875, "with": -4.993828175779875, "without": -4.993828175779875 }, "locator-not-found": { "an": -4.993828175779875, "attached": -4.993828175779875, "btn": -4.993828175779875, "button": -4.58836306767171, "cart": -4.993828175779875, "checkout": -4.993828175779875, "click": -4.993828175779875, "data": -4.993828175779875, "div": -4.993828175779875, "dom": -4.993828175779875, "element": -4.07753744390572, "elements": -4.300680995219929, "error": -4.58836306767171, "find": -4.993828175779875, "for": -4.58836306767171, "found": -4.58836306767171, "getbyrole": -4.993828175779875, "getbytext": -4.993828175779875, "icon": -4.993828175779875, "id": -4.993828175779875, "is": -4.993828175779875, "locator": -4.07753744390572, "matched": -4.993828175779875, "matches": -4.993828175779875, "missing": -4.993828175779875, "mode": -4.58836306767171, "name": -4.993828175779875, "no": -4.58836306767171, "node": -4.993828175779875, "not": -4.58836306767171, "resolved": -4.58836306767171, "save": -4.993828175779875, "selector": -4.58836306767171, "strict": -4.58836306767171, "submit": -4.993828175779875, "testid": -4.993828175779875, "textcontent": -4.993828175779875, "the": -4.58836306767171, "to": -4.07753744390572, "total": -4.993828175779875, "unable": -4.993828175779875, "violation": -4.58836306767171, "waiting": -4.993828175779875, "with": -4.993828175779875, "xpath": -4.993828175779875 }, "navigation": { "NUM": -4.983606621708336, "aborted": -4.983606621708336, "another": -4.983606621708336, "back": -4.983606621708336, "because": -4.578141513600172, "by": -4.578141513600172, "checkout": -4.983606621708336, "context": -4.983606621708336, "crashed": -4.983606621708336, "dashboard": -4.983606621708336, "destroyed": -4.983606621708336, "detached": -4.983606621708336, "entry": -4.983606621708336, "err": -4.578141513600172, "exceeded": -4.983606621708336, "execution": -4.983606621708336, "failed": -4.983606621708336, "frame": -4.578141513600172, "goback": -4.983606621708336, "goto": -4.290459441148391, "history": -4.983606621708336, "home": -4.983606621708336, "interrupted": -4.578141513600172, "is": -4.983606621708336, "likely": -4.983606621708336, "login": -4.983606621708336, "many": -4.983606621708336, "maybe": -4.983606621708336, "most": -4.983606621708336, "navigate": -4.983606621708336, "navigating": -4.983606621708336, "navigation": -3.7308436532129683, "net": -4.578141513600172, "no": -4.983606621708336, "of": -4.983606621708336, "page": -3.884994333040227, "redirects": -4.983606621708336, "timeout": -4.983606621708336, "to": -3.7308436532129683, "too": -4.983606621708336, "waitforurl": -4.983606621708336, "was": -4.578141513600172 }, "network": { "NUM": -4.57126863431241, "URL": -4.283586561860629, "again": -4.976733742420574, "api": -4.976733742420574, "apirequestcontext": -4.976733742420574, "at": -4.976733742420574, "body": -4.976733742420574, "connect": -4.976733742420574, "connection": -4.57126863431241, "disconnected": -4.976733742420574, "eai": -4.976733742420574, "econnrefused": -4.976733742420574, "err": -3.8781214537524646, "error": -4.976733742420574, "failed": -4.283586561860629, "fetch": -4.976733742420574, "fetching": -4.976733742420574, "from": -4.976733742420574, "get": -4.976733742420574, "getaddrinfo": -4.976733742420574, "goto": -4.976733742420574, "hang": -4.976733742420574, "internet": -4.976733742420574, "loading": -4.976733742420574, "name": -4.976733742420574, "net": -3.8781214537524646, "not": -4.976733742420574, "on": -4.976733742420574, "out": -4.976733742420574, "page": -4.57126863431241, "products": -4.976733742420574, "protocol": -4.976733742420574, "reading": -4.976733742420574, "reason": -4.976733742420574, "refused": -4.976733742420574, "request": -4.57126863431241, "resolved": -4.976733742420574, "resource": -4.976733742420574, "response": -4.976733742420574, "route": -4.976733742420574, "socket": -4.976733742420574, "ssl": -4.976733742420574, "timed": -4.976733742420574, "to": -4.976733742420574, "up": -4.976733742420574, "upstream": -4.976733742420574, "while": -4.976733742420574 }, "timeout": { "NUM": -3.4965075614664802, "after": -5.000584958242754, "be": -4.59511985013459, "cart": -5.000584958242754, "click": -5.000584958242754, "element": -5.000584958242754, "event": -5.000584958242754, "exceeded": -3.6142905971228636, "expect": -5.000584958242754, "fill": -5.000584958242754, "for": -3.7478219897473863, "function": -5.000584958242754, "load": -5.000584958242754, "locator": -4.084294226368599, "navigation": -5.000584958242754, "of": -5.000584958242754, "out": -5.000584958242754, "page": -4.59511985013459, "running": -5.000584958242754, "selector": -5.000584958242754, "submit": -5.000584958242754, "test": -4.59511985013459, "timed": -5.000584958242754, "timeout": -3.6142905971228636, "timeouterror": -4.59511985013459, "to": -4.59511985013459, "tobevisible": -5.000584958242754, "visible": -4.59511985013459, "waitforloadstate": -5.000584958242754, "waitforselector": -5.000584958242754, "waiting": -3.7478219897473863, "while": -5.000584958242754 } }, "playwrightVersion": "1.59.1", "priors": { "assertion": -1.9636097261547143, "env-config": -1.9636097261547143, "flaky-by-retry": -1.9636097261547143, "locator-not-found": -1.9636097261547143, "navigation": -1.9636097261547143, "network": -1.9636097261547143, "timeout": -1.845826690498331 }, "totals": { "assertion": 64, "env-config": 69, "flaky-by-retry": 68, "locator-not-found": 68, "navigation": 65, "network": 63, "timeout": 70 }, "version": 1, "vocabSize": 227 };
10861
+ var MODEL = { "alpha": 1, "labels": ["assertion", "env-config", "flaky-by-retry", "locator-not-found", "navigation", "network", "timeout"], "logLikelihoods": { "assertion": { "13": -6.424058322604399, "16": -6.424058322604399, "17": -6.424058322604399, "20": -6.424058322604399, "21": -6.018593214496234, "22": -6.424058322604399, "23": -6.424058322604399, "25": -6.424058322604399, "30": -6.424058322604399, "41": -6.424058322604399, "43": -6.424058322604399, "61": -6.424058322604399, "00": -6.018593214496234, "03": -6.424058322604399, "12t07": -6.424058322604399, "6s": -6.424058322604399, "NUM": -4.283992159108128, "URL": -6.424058322604399, "actual": -6.018593214496234, "am": -6.424058322604399, "assertionerror": -6.424058322604399, "assertionname": -6.424058322604399, "async": -6.424058322604399, "at": -5.507767590730244, "await": -5.32544603393629, "basic": -5.507767590730244, "be": -5.730911142044453, "below": -6.424058322604399, "button": -6.424058322604399, "call": -5.507767590730244, "cart": -6.424058322604399, "checkout": -6.424058322604399, "com": -6.424058322604399, "const": -6.424058322604399, "count": -5.730911142044453, "dashboard": -6.424058322604399, "deep": -6.424058322604399, "downloads": -6.018593214496234, "equal": -6.424058322604399, "equality": -6.424058322604399, "error": -5.32544603393629, "example": -5.171295354109031, "expect": -4.283992159108128, "expected": -3.9817112872351945, "failed": -6.018593214496234, "false": -6.424058322604399, "field": -6.424058322604399, "for": -5.507767590730244, "getbytext": -6.018593214496234, "getting": -6.424058322604399, "ggorlen": -6.424058322604399, "got": -6.424058322604399, "goto": -6.424058322604399, "id": -6.018593214496234, "in": -6.018593214496234, "inner": -6.018593214496234, "internal": -6.018593214496234, "isnot": -6.018593214496234, "john": -6.424058322604399, "js": -5.32544603393629, "lib": -6.424058322604399, "locator": -4.478148173549085, "log": -5.507767590730244, "logged": -6.018593214496234, "login": -6.424058322604399, "matcherhint": -6.424058322604399, "matcherresult": -5.507767590730244, "modules": -6.424058322604399, "must": -6.424058322604399, "my": -6.424058322604399, "name": -6.018593214496234, "navbar": -5.507767590730244, "node": -5.507767590730244, "not": -6.424058322604399, "npx": -6.424058322604399, "page": -5.171295354109031, "pattern": -6.424058322604399, "playwright": -5.32544603393629, "printexpected": -6.018593214496234, "printreceived": -6.018593214496234, "process": -6.424058322604399, "processimmediate": -6.424058322604399, "queues": -6.424058322604399, "received": -4.22683374526818, "reply": -6.424058322604399, "return": -6.424058322604399, "runnextticks": -6.424058322604399, "running": -6.424058322604399, "runtestwithbeforehooks": -6.424058322604399, "selector": -6.424058322604399, "should": -6.018593214496234, "spec": -5.32544603393629, "string": -5.037763961484508, "task": -6.424058322604399, "test": -4.814620410170298, "tests": -5.507767590730244, "text": -6.424058322604399, "this": -5.171295354109031, "timeout": -5.730911142044453, "timers": -6.424058322604399, "title": -5.507767590730244, "to": -6.424058322604399, "tobe": -6.424058322604399, "tobetruthy": -6.424058322604399, "tobevisible": -6.018593214496234, "toequal": -6.424058322604399, "tohavecount": -6.424058322604399, "tohavetext": -4.919980925828125, "tohavetitle": -6.424058322604399, "tohavevalue": -6.424058322604399, "truthy": -6.424058322604399, "ts": -6.424058322604399, "undefined": -6.018593214496234, "users": -6.018593214496234, "using": -6.424058322604399, "utils": -5.32544603393629, "value": -6.424058322604399, "vu": -6.018593214496234, "waiting": -5.507767590730244, "with": -5.730911142044453, "worker": -6.424058322604399, "workerrunner": -6.018593214496234 }, "env-config": { "16": -6.687108607866515, "44": -6.687108607866515, "64": -6.687108607866515, "66": -6.687108607866515, "70": -5.77081787599236, "00": -6.28164349975835, "05": -6.687108607866515, "16t15": -6.687108607866515, "51z": -6.687108607866515, "8hauptrolle": -6.687108607866515, "NUM": -5.18303121109024, "activity": -6.687108607866515, "add": -6.687108607866515, "additional": -6.687108607866515, "aimed": -6.687108607866515, "alderoberge": -6.687108607866515, "alejo": -6.687108607866515, "also": -5.588496319198405, "and": -5.588496319198405, "any": -6.28164349975835, "anyone": -6.28164349975835, "api": -6.687108607866515, "assist": -6.687108607866515, "at": -5.434345639371147, "available": -6.28164349975835, "awb": -6.28164349975835, "back": -6.687108607866515, "base": -6.687108607866515, "baseurl": -6.687108607866515, "be": -6.28164349975835, "believe": -6.687108607866515, "binary": -6.687108607866515, "box": -6.28164349975835, "bridge": -6.687108607866515, "browser": -6.687108607866515, "browsername": -5.588496319198405, "browsers": -5.18303121109024, "browsertype": -4.9823605156280895, "but": -6.28164349975835, "by": -6.687108607866515, "cache": -5.77081787599236, "can": -6.28164349975835, "cannot": -6.687108607866515, "channel": -5.077670695432414, "cheron": -6.687108607866515, "chrome": -5.18303121109024, "chromium": -4.9823605156280895, "ci": -6.687108607866515, "cmu": -4.9823605156280895, "cmulex": -6.687108607866515, "command": -5.993961427306569, "commented": -6.687108607866515, "config": -5.993961427306569, "default": -6.687108607866515, "dependencies": -5.588496319198405, "deps": -5.993961427306569, "despite": -6.687108607866515, "difference": -6.687108607866515, "different": -6.687108607866515, "directory": -6.28164349975835, "displays": -6.687108607866515, "distros": -5.993961427306569, "do": -6.28164349975835, "docker": -6.687108607866515, "doesn": -5.434345639371147, "dotenv": -6.687108607866515, "download": -6.28164349975835, "edit": -6.687108607866515, "effort": -6.687108607866515, "elementary": -6.687108607866515, "enoent": -6.687108607866515, "env": -6.28164349975835, "environment": -6.28164349975835, "error": -4.741198458811201, "example": -6.687108607866515, "exec": -6.687108607866515, "executable": -5.77081787599236, "exist": -5.77081787599236, "existent": -6.687108607866515, "explain": -6.28164349975835, "eyes": -6.687108607866515, "failed": -6.687108607866515, "fak3": -6.687108607866515, "falling": -6.687108607866515, "file": -6.28164349975835, "files": -6.687108607866515, "find": -6.687108607866515, "firefox": -6.28164349975835, "fix": -6.687108607866515, "fixing": -6.687108607866515, "following": -6.28164349975835, "for": -5.588496319198405, "from": -6.687108607866515, "gnu": -6.687108607866515, "goes": -6.687108607866515, "goto": -6.687108607866515, "grapheme": -6.28164349975835, "guess": -6.28164349975835, "has": -6.28164349975835, "have": -6.28164349975835, "having": -6.28164349975835, "home": -6.687108607866515, "hopefully": -6.687108607866515, "host": -5.77081787599236, "if": -6.28164349975835, "image": -6.687108607866515, "in": -6.28164349975835, "incompatible": -6.687108607866515, "indic": -6.28164349975835, "information": -6.687108607866515, "insights": -6.687108607866515, "install": -5.588496319198405, "installed": -5.993961427306569, "instead": -6.687108607866515, "into": -6.687108607866515, "invalid": -6.687108607866515, "is": -5.077670695432414, "isn": -6.687108607866515, "issue": -5.588496319198405, "it": -4.9823605156280895, "js": -6.687108607866515, "json": -6.28164349975835, "just": -5.588496319198405, "kal": -6.687108607866515, "kal16": -6.687108607866515, "keep": -6.687108607866515, "key": -6.687108607866515, "kunukn": -6.687108607866515, "lang": -6.28164349975835, "launch": -4.9823605156280895, "leo": -6.687108607866515, "lex": -6.28164349975835, "lib": -6.687108607866515, "libatk": -6.28164349975835, "libatspi": -6.687108607866515, "libcups": -6.687108607866515, "libdbus": -6.687108607866515, "libdrm": -6.687108607866515, "libexpat": -6.687108607866515, "libflite": -4.741198458811201, "libgio": -6.687108607866515, "libglib": -6.687108607866515, "libgobject": -6.687108607866515, "libgstcodecparsers": -6.687108607866515, "libicu70": -6.687108607866515, "libicudata": -6.687108607866515, "libicui18n": -6.687108607866515, "libicuio": -6.687108607866515, "libicuuc": -6.687108607866515, "libnspr4": -6.687108607866515, "libnss3": -6.687108607866515, "libnssutil3": -6.687108607866515, "libpthread": -6.687108607866515, "libraries": -5.77081787599236, "libsmime3": -6.687108607866515, "libx264": -6.687108607866515, "libxcb": -6.687108607866515, "libxkbcommon": -6.687108607866515, "like": -5.77081787599236, "linux": -4.895349138638459, "load": -6.687108607866515, "looks": -5.993961427306569, "lookup": -6.687108607866515, "lot": -6.687108607866515, "make": -6.687108607866515, "malaver": -6.687108607866515, "matching": -6.687108607866515, "may": -6.28164349975835, "meant": -6.687108607866515, "message": -6.687108607866515, "minibrowser": -6.687108607866515, "mint": -5.77081787599236, "missing": -5.077670695432414, "module": -6.687108607866515, "more": -6.687108607866515, "most": -6.28164349975835, "ms": -5.77081787599236, "must": -6.687108607866515, "my": -6.687108607866515, "name": -6.687108607866515, "need": -6.687108607866515, "new": -6.28164349975835, "newer": -6.687108607866515, "no": -6.687108607866515, "non": -6.687108607866515, "not": -5.993961427306569, "npx": -6.28164349975835, "of": -5.434345639371147, "old": -6.687108607866515, "on": -5.18303121109024, "one": -6.28164349975835, "open": -6.687108607866515, "or": -5.77081787599236, "other": -6.687108607866515, "out": -5.77081787599236, "package": -6.687108607866515, "page": -6.687108607866515, "parameter": -6.687108607866515, "path": -6.687108607866515, "platforms": -6.687108607866515, "playwright": -4.435816809260019, "please": -6.28164349975835, "pnpm": -6.687108607866515, "points": -6.687108607866515, "popular": -6.28164349975835, "position": -6.687108607866515, "prompt": -6.687108607866515, "provided": -6.687108607866515, "quick": -6.687108607866515, "react": -6.687108607866515, "related": -6.687108607866515, "replace": -6.687108607866515, "reply": -6.687108607866515, "repositories": -6.28164349975835, "required": -6.687108607866515, "rms": -6.687108607866515, "root": -5.993961427306569, "run": -5.300814246746624, "running": -5.993961427306569, "safari": -6.28164349975835, "same": -5.77081787599236, "seems": -6.687108607866515, "set": -6.687108607866515, "should": -6.28164349975835, "simensbat": -6.687108607866515, "simply": -6.687108607866515, "slt": -6.687108607866515, "so": -3.742669628700074, "some": -6.28164349975835, "spec": -6.28164349975835, "such": -6.687108607866515, "super": -6.687108607866515, "support": -6.687108607866515, "symbol": -6.28164349975835, "syntaxerror": -6.687108607866515, "system": -5.588496319198405, "team": -6.687108607866515, "test": -6.28164349975835, "tests": -6.687108607866515, "the": -4.547042444370244, "there": -5.77081787599236, "this": -5.77081787599236, "time": -6.687108607866515, "title": -6.687108607866515, "tls": -6.687108607866515, "to": -4.489884030530295, "token": -6.687108607866515, "tried": -6.28164349975835, "troubleshooting": -6.687108607866515, "ts": -6.687108607866515, "tsconfig": -6.687108607866515, "ubuntu": -5.588496319198405, "undefined": -5.993961427306569, "unexpected": -6.687108607866515, "unsupported": -5.588496319198405, "updated": -6.28164349975835, "url": -6.687108607866515, "us": -5.588496319198405, "use": -6.687108607866515, "usenglish": -6.687108607866515, "uses": -6.28164349975835, "using": -6.28164349975835, "usr": -6.687108607866515, "value": -6.687108607866515, "values": -6.687108607866515, "variable": -6.28164349975835, "version": -6.28164349975835, "vsts": -6.687108607866515, "was": -5.993961427306569, "way": -6.687108607866515, "webkit": -5.77081787599236, "which": -6.28164349975835, "why": -6.28164349975835, "with": -5.300814246746624, "work": -5.77081787599236, "worker": -6.687108607866515, "works": -6.28164349975835, "would": -6.687108607866515, "x86": -6.687108607866515, "you": -6.28164349975835 }, "flaky-by-retry": { "after": -5.786897381366708, "and": -6.192362489474872, "animation": -6.192362489474872, "attempt": -5.276071757600717, "between": -6.192362489474872, "blip": -6.192362489474872, "cause": -6.192362489474872, "change": -6.192362489474872, "click": -6.192362489474872, "code": -6.192362489474872, "commit": -6.192362489474872, "condition": -6.192362489474872, "dependency": -6.192362489474872, "detached": -6.192362489474872, "deterministic": -6.192362489474872, "element": -6.192362489474872, "failed": -5.499215308914927, "fails": -6.192362489474872, "flaky": -5.276071757600717, "green": -6.192362489474872, "in": -6.192362489474872, "intermittent": -6.192362489474872, "locator": -6.192362489474872, "marked": -6.192362489474872, "network": -6.192362489474872, "no": -6.192362489474872, "non": -6.192362489474872, "on": -5.093750200806762, "order": -6.192362489474872, "passed": -5.093750200806762, "quarantined": -6.192362489474872, "race": -6.192362489474872, "reproducible": -6.192362489474872, "rerun": -6.192362489474872, "retry": -5.276071757600717, "runs": -6.192362489474872, "same": -6.192362489474872, "second": -6.192362489474872, "stale": -6.192362489474872, "succeeded": -6.192362489474872, "test": -5.786897381366708, "the": -6.192362489474872, "then": -6.192362489474872, "timeout": -6.192362489474872, "unstable": -6.192362489474872, "with": -6.192362489474872, "without": -6.192362489474872 }, "locator-not-found": { "25": -6.459904454377535, "30": -5.3612921657094255, "46": -6.459904454377535, "06": -6.459904454377535, "NUM": -5.5436137225033795, "aka": -4.588102277475944, "alert": -6.459904454377535, "all": -6.459904454377535, "an": -6.459904454377535, "api": -6.459904454377535, "aria": -6.05443934626937, "async": -6.459904454377535, "attached": -6.459904454377535, "based": -6.459904454377535, "being": -6.459904454377535, "birth": -6.459904454377535, "btn": -6.459904454377535, "button": -4.588102277475944, "by": -6.459904454377535, "captura": -6.459904454377535, "cart": -6.459904454377535, "carteiras": -6.05443934626937, "cell": -6.05443934626937, "checkout": -6.459904454377535, "checks": -6.459904454377535, "click": -5.5436137225033795, "cns": -5.766757273817589, "columns": -6.459904454377535, "const": -6.459904454377535, "contains": -6.459904454377535, "copy": -6.05443934626937, "count": -6.459904454377535, "cpf": -5.766757273817589, "da": -6.05443934626937, "data": -6.05443934626937, "de": -6.459904454377535, "div": -5.2071414858821665, "does": -6.459904454377535, "dom": -6.459904454377535, "easiest": -6.459904454377535, "element": -5.5436137225033795, "elements": -4.755156362139109, "error": -4.513994305322221, "even": -6.459904454377535, "exact": -5.766757273817589, "expected": -6.459904454377535, "fail": -6.459904454377535, "field": -6.459904454377535, "filtering": -6.459904454377535, "find": -6.459904454377535, "first": -5.766757273817589, "for": -6.05443934626937, "found": -6.05443934626937, "frame": -6.459904454377535, "from": -6.459904454377535, "getbyrole": -5.3612921657094255, "getbytext": -5.073610093257644, "icon": -6.459904454377535, "id": -5.766757273817589, "if": -6.459904454377535, "iframe": -6.459904454377535, "in": -5.766757273817589, "into": -6.459904454377535, "is": -5.5436137225033795, "issue": -6.05443934626937, "it": -5.766757273817589, "javascript": -6.459904454377535, "just": -6.459904454377535, "kb": -6.459904454377535, "label": -6.05443934626937, "licenses": -6.459904454377535, "link": -6.459904454377535, "list": -6.459904454377535, "locator": -4.2626798770413155, "match": -6.459904454377535, "matched": -6.459904454377535, "matches": -6.459904454377535, "mean": -6.459904454377535, "method": -6.459904454377535, "missing": -6.459904454377535, "mode": -4.66814498514948, "mother": -6.459904454377535, "munic": -6.05443934626937, "municipality": -6.459904454377535, "my": -6.459904454377535, "name": -5.2071414858821665, "nascimento": -6.05443934626937, "new": -6.05443934626937, "no": -6.05443934626937, "node": -6.459904454377535, "nome": -5.5436137225033795, "not": -6.05443934626937, "note": -6.459904454377535, "nov": -6.05443934626937, "novalistagem": -6.459904454377535, "nth": -6.459904454377535, "of": -6.459904454377535, "or": -5.766757273817589, "page": -6.459904454377535, "passes": -6.459904454377535, "pio": -6.05443934626937, "playwright": -6.05443934626937, "position": -5.766757273817589, "question": -6.459904454377535, "resolve": -6.459904454377535, "resolved": -4.955827057601261, "response": -6.459904454377535, "rest": -6.459904454377535, "result": -5.766757273817589, "results": -6.459904454377535, "role": -6.459904454377535, "run": -6.459904454377535, "save": -6.459904454377535, "selection": -6.459904454377535, "selector": -6.05443934626937, "simplest": -6.459904454377535, "solution": -6.459904454377535, "span": -5.766757273817589, "specify": -6.459904454377535, "specifying": -6.459904454377535, "state": -6.459904454377535, "strict": -4.66814498514948, "submit": -6.459904454377535, "tabindex": -6.05443934626937, "table": -6.459904454377535, "take": -6.459904454377535, "td": -6.459904454377535, "tela": -6.459904454377535, "test": -6.05443934626937, "testid": -6.459904454377535, "text": -5.766757273817589, "textcontent": -6.459904454377535, "that": -6.05443934626937, "the": -4.513994305322221, "thead": -6.459904454377535, "this": -5.5436137225033795, "title": -6.459904454377535, "to": -4.513994305322221, "total": -6.459904454377535, "tr": -6.459904454377535, "true": -5.766757273817589, "type": -6.05443934626937, "uf": -6.05443934626937, "unable": -6.459904454377535, "validate": -6.459904454377535, "validatefieldvalue": -6.459904454377535, "validation": -6.459904454377535, "violation": -4.755156362139109, "waitfor": -6.459904454377535, "waiting": -6.459904454377535, "we": -6.459904454377535, "what": -6.459904454377535, "when": -6.459904454377535, "whether": -6.459904454377535, "will": -6.459904454377535, "with": -6.459904454377535, "xpath": -6.459904454377535 }, "navigation": { "14": -6.304448802421981, "19": -6.709913910530146, "25": -6.709913910530146, "27": -6.304448802421981, "39": -6.709913910530146, "49": -6.709913910530146, "66": -6.709913910530146, "0ms": -6.304448802421981, "6ms": -6.709913910530146, "NUM": -4.569847747033875, "URL": -5.793623178655991, "abort": -6.0167667299702, "aborted": -4.91815444130209, "acting": -6.709913910530146, "additional": -6.709913910530146, "adjusting": -6.709913910530146, "after": -6.0167667299702, "an": -6.304448802421981, "and": -6.304448802421981, "another": -6.709913910530146, "api": -5.611301621862036, "appends": -6.709913910530146, "are": -6.709913910530146, "argument": -6.709913910530146, "as": -6.709913910530146, "async": -6.0167667299702, "at": -5.457150942034778, "avoid": -6.709913910530146, "await": -4.91815444130209, "back": -6.709913910530146, "base": -6.709913910530146, "be": -6.709913910530146, "because": -5.457150942034778, "before": -6.304448802421981, "behavior": -6.709913910530146, "being": -6.709913910530146, "both": -6.709913910530146, "browser": -6.0167667299702, "bug": -6.304448802421981, "but": -6.304448802421981, "by": -6.0167667299702, "call": -5.457150942034778, "callback": -6.709913910530146, "called": -6.709913910530146, "calling": -6.709913910530146, "cancelled": -6.709913910530146, "cannot": -6.709913910530146, "caused": -6.709913910530146, "causes": -6.709913910530146, "certain": -6.709913910530146, "chain": -6.304448802421981, "channel": -6.709913910530146, "checkout": -6.709913910530146, "chrome": -6.709913910530146, "click": -6.709913910530146, "close": -6.709913910530146, "closed": -6.709913910530146, "code": -6.709913910530146, "comment": -6.709913910530146, "commented": -6.709913910530146, "common": -6.304448802421981, "complicated": -6.709913910530146, "connection": -6.709913910530146, "const": -6.709913910530146, "context": -6.304448802421981, "copy": -6.0167667299702, "crashed": -5.793623178655991, "create": -6.709913910530146, "dashboard": -6.0167667299702, "debugging": -6.709913910530146, "describe": -6.709913910530146, "destroyed": -6.0167667299702, "detached": -5.100475998096045, "developer": -6.709913910530146, "didn": -6.709913910530146, "different": -6.709913910530146, "directly": -6.709913910530146, "document": -6.709913910530146, "does": -6.709913910530146, "domcontentloaded": -6.304448802421981, "dowrite": -6.709913910530146, "during": -6.304448802421981, "en": -6.709913910530146, "entry": -6.709913910530146, "err": -4.695010889987881, "error": -4.838111733628554, "event": -6.304448802421981, "example": -6.709913910530146, "exceeded": -6.304448802421981, "execution": -6.709913910530146, "expect": -6.709913910530146, "expected": -6.709913910530146, "facing": -6.709913910530146, "failed": -5.611301621862036, "file": -5.323619549410255, "fine": -6.304448802421981, "fired": -6.304448802421981, "firefox": -6.709913910530146, "for": -5.793623178655991, "frame": -4.6304723688503096, "frames": -6.709913910530146, "frequent": -6.709913910530146, "from": -6.709913910530146, "frompromise": -6.709913910530146, "full": -6.709913910530146, "future": -6.709913910530146, "getbyrole": -6.709913910530146, "getting": -6.709913910530146, "given": -6.709913910530146, "goback": -6.709913910530146, "going": -6.709913910530146, "goto": -4.312018637731775, "handler": -6.709913910530146, "happens": -6.709913910530146, "have": -6.709913910530146, "headless": -6.709913910530146, "helper": -6.0167667299702, "hint": -6.709913910530146, "history": -6.709913910530146, "home": -5.323619549410255, "html": -6.0167667299702, "impl": -6.709913910530146, "in": -5.457150942034778, "include": -6.709913910530146, "info": -6.709913910530146, "initial": -6.709913910530146, "innerhtml": -6.709913910530146, "inside": -6.709913910530146, "instead": -6.709913910530146, "internal": -6.709913910530146, "interrupted": -6.304448802421981, "is": -6.304448802421981, "issue": -5.457150942034778, "it": -6.304448802421981, "its": -6.709913910530146, "js": -5.611301621862036, "jul": -6.304448802421981, "lang": -6.709913910530146, "last": -6.304448802421981, "lib": -5.793623178655991, "likely": -6.709913910530146, "line": -5.457150942034778, "link": -5.793623178655991, "load": -5.793623178655991, "loads": -6.304448802421981, "locals": -5.793623178655991, "log": -6.0167667299702, "login": -6.0167667299702, "logs": -6.304448802421981, "main": -6.709913910530146, "many": -6.304448802421981, "maxschmitt": -6.709913910530146, "may": -6.709913910530146, "maybe": -5.100475998096045, "means": -6.709913910530146, "message": -6.709913910530146, "method": -6.709913910530146, "mistake": -6.709913910530146, "mjs": -6.709913910530146, "mobile": -6.709913910530146, "mode": -6.709913910530146, "more": -6.709913910530146, "most": -6.0167667299702, "my": -6.709913910530146, "name": -6.304448802421981, "navigate": -6.709913910530146, "navigates": -6.709913910530146, "navigatetojobs": -6.709913910530146, "navigating": -5.323619549410255, "navigation": -4.695010889987881, "net": -4.838111733628554, "new": -5.205836513753871, "next": -6.709913910530146, "no": -6.304448802421981, "node": -6.0167667299702, "non": -6.709913910530146, "none": -6.709913910530146, "oauth": -6.709913910530146, "obj": -6.709913910530146, "of": -5.457150942034778, "on": -6.0167667299702, "open": -6.304448802421981, "options": -6.709913910530146, "or": -6.304448802421981, "other": -6.709913910530146, "out": -6.709913910530146, "packages": -5.793623178655991, "page": -3.9065535296236105, "pages": -6.0167667299702, "params": -6.304448802421981, "per": -6.709913910530146, "playwright": -4.91815444130209, "pretty": -6.709913910530146, "process": -6.709913910530146, "promises": -6.709913910530146, "pw": -5.793623178655991, "py": -5.457150942034778, "python3": -5.793623178655991, "randomly": -6.709913910530146, "rebuilds": -6.709913910530146, "received": -6.709913910530146, "recent": -6.304448802421981, "redirect": -6.0167667299702, "redirects": -6.709913910530146, "reload": -6.304448802421981, "removed": -6.304448802421981, "removes": -6.709913910530146, "replaced": -6.709913910530146, "replaces": -6.709913910530146, "replicate": -6.709913910530146, "request": -6.709913910530146, "resolved": -6.709913910530146, "response": -6.709913910530146, "result": -6.709913910530146, "retrieving": -6.709913910530146, "return": -6.709913910530146, "returns": -6.709913910530146, "root": -6.709913910530146, "route": -6.0167667299702, "run": -6.709913910530146, "same": -6.709913910530146, "script": -6.304448802421981, "selector": -6.709913910530146, "self": -5.611301621862036, "send": -6.304448802421981, "sends": -6.709913910530146, "settings": -6.304448802421981, "site": -5.793623178655991, "skip": -6.709913910530146, "socket": -6.709913910530146, "some": -6.304448802421981, "somepage": -6.709913910530146, "spa": -6.304448802421981, "started": -6.709913910530146, "states": -6.709913910530146, "stcpage": -6.304448802421981, "stcunregisteredpage": -6.709913910530146, "stephen100mwangi": -6.709913910530146, "stream": -5.793623178655991, "suddenly": -6.709913910530146, "suspects": -6.709913910530146, "test": -5.457150942034778, "tests": -6.709913910530146, "than": -6.709913910530146, "that": -5.793623178655991, "the": -4.695010889987881, "then": -6.709913910530146, "there": -6.709913910530146, "thing": -6.709913910530146, "this": -6.709913910530146, "through": -6.709913910530146, "timeout": -6.304448802421981, "to": -4.4073288175361, "too": -6.709913910530146, "totally": -6.709913910530146, "traceback": -6.0167667299702, "tried": -6.709913910530146, "triggers": -6.709913910530146, "triggeruncaughtexception": -6.709913910530146, "true": -6.709913910530146, "trying": -6.709913910530146, "uid": -6.709913910530146, "unhandledpromiserejectionwarning": -6.709913910530146, "until": -5.793623178655991, "url": -5.611301621862036, "users": -6.709913910530146, "v18": -6.709913910530146, "variant": -6.304448802421981, "venv": -5.793623178655991, "wait": -6.709913910530146, "waitforurl": -6.304448802421981, "waiting": -6.0167667299702, "waituntil": -6.709913910530146, "was": -4.6304723688503096, "way": -6.709913910530146, "website": -6.709913910530146, "were": -6.709913910530146, "when": -6.0167667299702, "which": -6.709913910530146, "while": -6.304448802421981, "with": -6.0167667299702, "worked": -6.709913910530146, "works": -6.709913910530146, "writable": -6.0167667299702, "write": -6.304448802421981, "writeorbuffer": -6.709913910530146, "your": -6.709913910530146 }, "network": { "10": -5.903316160331277, "11": -5.680172609017068, "12": -4.804703871663167, "13": -6.190998232783058, "14": -4.345171542284727, "15": -4.345171542284727, "16": -5.343700372395855, "17": -4.345171542284727, "19": -6.596463340891223, "20": -6.596463340891223, "21": -6.190998232783058, "23": -6.596463340891223, "31": -5.210168979771332, "34": -6.596463340891223, "48": -6.596463340891223, "51": -6.596463340891223, "61": -6.596463340891223, "64": -6.596463340891223, "65": -6.596463340891223, "69": -6.596463340891223, "77": -6.596463340891223, "95": -6.596463340891223, "98": -6.596463340891223, "NUM": -5.210168979771332, "URL": -4.345171542284727, "access": -6.190998232783058, "again": -6.596463340891223, "am": -6.596463340891223, "and": -6.190998232783058, "anonymous": -6.596463340891223, "api": -6.190998232783058, "apirequestcontext": -6.596463340891223, "applicationurl": -6.596463340891223, "async": -6.190998232783058, "at": -4.070734696582967, "await": -5.903316160331277, "basepage": -6.596463340891223, "before": -6.190998232783058, "beforeeach": -6.596463340891223, "body": -6.596463340891223, "bundle": -6.190998232783058, "capture": -6.596463340891223, "capturestacktrace": -6.596463340891223, "channelowner": -6.190998232783058, "check": -5.680172609017068, "checkout": -6.596463340891223, "chromium": -6.596463340891223, "client": -5.497851052223113, "clientrequest": -6.190998232783058, "close": -6.596463340891223, "code": -6.190998232783058, "common": -6.596463340891223, "connect": -6.596463340891223, "connection": -4.8917152486527975, "const": -6.596463340891223, "dashboardpage": -5.343700372395855, "day": -6.596463340891223, "debug": -6.596463340891223, "deliver": -6.596463340891223, "disconnected": -6.596463340891223, "domcontentloaded": -6.190998232783058, "each": -6.596463340891223, "eai": -6.596463340891223, "econnrefused": -6.596463340891223, "econnreset": -6.596463340891223, "emit": -6.190998232783058, "environment": -6.596463340891223, "err": -4.650553191835909, "error": -4.581560320348958, "events": -6.190998232783058, "failed": -5.903316160331277, "fetch": -6.596463340891223, "fetching": -6.596463340891223, "for": -6.596463340891223, "frame": -5.680172609017068, "from": -6.596463340891223, "get": -6.596463340891223, "getaddrinfo": -6.596463340891223, "git": -6.190998232783058, "goto": -4.650553191835909, "gotosearchproduct": -6.596463340891223, "handler": -6.596463340891223, "hang": -6.190998232783058, "hook": -6.596463340891223, "http": -6.596463340891223, "internet": -6.596463340891223, "js": -4.581560320348958, "lib": -5.343700372395855, "load": -6.190998232783058, "loadapplication": -6.596463340891223, "loading": -6.596463340891223, "login": -5.680172609017068, "logs": -5.092385944114948, "modules": -4.724661163989631, "name": -5.497851052223113, "navigating": -5.210168979771332, "net": -4.517021799211387, "networkidle": -5.680172609017068, "new": -5.903316160331277, "node": -4.724661163989631, "not": -5.903316160331277, "note": -6.596463340891223, "object": -6.596463340891223, "on": -6.190998232783058, "out": -6.190998232783058, "page": -4.456397177394951, "pages": -6.596463340891223, "personal": -6.190998232783058, "playwright": -4.154116305522018, "pnpm": -5.343700372395855, "product": -6.596463340891223, "producteditpage": -6.190998232783058, "products": -6.596463340891223, "productsearchpage": -6.190998232783058, "project": -6.190998232783058, "promises": -6.596463340891223, "protocol": -6.596463340891223, "proxy": -6.596463340891223, "proxyerror": -6.596463340891223, "public": -6.596463340891223, "pw": -6.596463340891223, "reading": -6.596463340891223, "reason": -6.596463340891223, "recording": -6.596463340891223, "refused": -5.343700372395855, "request": -6.190998232783058, "resolved": -5.903316160331277, "resource": -6.596463340891223, "response": -6.596463340891223, "route": -6.596463340891223, "runner": -6.190998232783058, "same": -6.596463340891223, "sauce": -6.190998232783058, "saucelabintegration": -6.596463340891223, "scheduleedit": -6.596463340891223, "sendmessagetoserver": -6.596463340891223, "server": -6.596463340891223, "settings": -6.596463340891223, "single": -6.596463340891223, "socket": -5.680172609017068, "socketcloselistener": -6.596463340891223, "spec": -6.190998232783058, "ssl": -6.596463340891223, "stacktrace": -6.596463340891223, "started": -6.596463340891223, "starting": -6.596463340891223, "tcp": -6.596463340891223, "test": -6.596463340891223, "tests": -5.680172609017068, "this": -6.596463340891223, "timed": -6.190998232783058, "timeouts": -6.596463340891223, "to": -4.987025428457122, "token": -6.190998232783058, "trace": -6.596463340891223, "ts": -6.596463340891223, "until": -5.210168979771332, "up": -6.190998232783058, "update": -6.190998232783058, "upstream": -6.596463340891223, "url": -6.190998232783058, "use": -6.596463340891223, "user": -5.903316160331277, "utils": -6.596463340891223, "valueof": -6.596463340891223, "variable": -6.596463340891223, "waiting": -5.210168979771332, "waituntil": -6.596463340891223, "while": -6.596463340891223, "wo": -6.596463340891223, "work": -5.343700372395855, "wrapapicall": -6.596463340891223, "your": -6.596463340891223 }, "timeout": { "10": -6.434546518787453, "15": -6.840011626895618, "16": -6.840011626895618, "17": -6.840011626895618, "18": -6.840011626895618, "19": -6.840011626895618, "20": -6.434546518787453, "21": -6.434546518787453, "22": -6.840011626895618, "23": -6.840011626895618, "30": -5.741399338227508, "31": -6.840011626895618, "54": -6.840011626895618, "58": -6.840011626895618, "59": -6.840011626895618, "60": -6.146864446335672, "61": -6.434546518787453, "62": -6.840011626895618, "63": -6.840011626895618, "64": -6.840011626895618, "73": -6.840011626895618, "79": -6.840011626895618, "83": -6.840011626895618, "00": -6.434546518787453, "NUM": -3.7719586917620003, "URL": -6.434546518787453, "action": -5.453717265775727, "actiontimeout": -6.840011626895618, "actual": -6.146864446335672, "after": -6.840011626895618, "afterall": -6.840011626895618, "all": -6.840011626895618, "amount": -6.840011626895618, "an": -5.741399338227508, "and": -5.135263534657192, "angle": -6.840011626895618, "anush": -6.434546518787453, "anzeigen": -6.840011626895618, "api": -5.923720895021463, "app": -6.840011626895618, "appeared": -6.840011626895618, "apply": -6.840011626895618, "are": -6.840011626895618, "areas": -6.840011626895618, "aren": -6.840011626895618, "as": -6.840011626895618, "assertions": -6.840011626895618, "async": -6.840011626895618, "at": -4.968209449994026, "attempt": -6.840011626895618, "attempting": -6.434546518787453, "attributetopage": -6.840011626895618, "auth": -6.146864446335672, "av": -6.434546518787453, "available": -6.840011626895618, "await": -5.453717265775727, "baseurl": -6.434546518787453, "basic": -6.146864446335672, "be": -5.741399338227508, "been": -5.923720895021463, "beforeall": -6.840011626895618, "beforeeach": -6.434546518787453, "between": -6.840011626895618, "bin": -6.840011626895618, "binding": -6.840011626895618, "br": -4.825108606353353, "browser": -5.58724865840025, "browsertype": -6.840011626895618, "btn": -6.840011626895618, "but": -6.840011626895618, "button": -5.923720895021463, "by": -6.434546518787453, "cache": -6.434546518787453, "call": -6.434546518787453, "can": -6.840011626895618, "capture": -6.840011626895618, "cart": -6.840011626895618, "case": -6.434546518787453, "certificates": -6.840011626895618, "chromium": -5.335934230119343, "class": -6.840011626895618, "click": -5.135263534657192, "closed": -5.230573714461517, "config": -5.58724865840025, "configured": -6.840011626895618, "const": -5.923720895021463, "consume": -6.840011626895618, "context": -5.923720895021463, "copy": -6.840011626895618, "core20": -6.840011626895618, "correlation": -6.840011626895618, "could": -6.146864446335672, "ctaheader": -6.840011626895618, "current": -6.840011626895618, "data": -6.146864446335672, "debug": -6.840011626895618, "default": -6.434546518787453, "defer": -6.840011626895618, "describe": -6.840011626895618, "deutschland": -6.434546518787453, "div": -6.146864446335672, "domcontentloaded": -6.434546518787453, "done": -6.840011626895618, "down": -6.840011626895618, "dropdown": -6.840011626895618, "during": -6.434546518787453, "each": -6.434546518787453, "element": -5.741399338227508, "enabled": -5.58724865840025, "entire": -6.840011626895618, "environment": -6.434546518787453, "err": -6.840011626895618, "error": -4.825108606353353, "event": -6.146864446335672, "exceeded": -4.699945463399347, "expect": -6.146864446335672, "fail": -6.840011626895618, "fill": -6.840011626895618, "filter": -6.840011626895618, "fired": -6.840011626895618, "first": -6.840011626895618, "fixture": -6.146864446335672, "for": -4.588719828289123, "force": -6.840011626895618, "form": -5.741399338227508, "frame": -6.434546518787453, "frames": -6.434546518787453, "from": -6.146864446335672, "function": -6.840011626895618, "glibc": -6.840011626895618, "global": -6.434546518787453, "globaltimeout": -6.840011626895618, "gnu": -6.840011626895618, "goto": -5.230573714461517, "gtk": -6.840011626895618, "has": -5.741399338227508, "hastext": -6.434546518787453, "have": -6.434546518787453, "helper": -6.840011626895618, "hold": -6.434546518787453, "home": -6.146864446335672, "hook": -6.146864446335672, "httpcredentials": -6.434546518787453, "icon": -6.840011626895618, "id": -6.840011626895618, "if": -6.146864446335672, "in": -4.825108606353353, "inaccurate": -6.146864446335672, "indexof": -6.840011626895618, "individual": -6.840011626895618, "init": -6.840011626895618, "insert": -6.840011626895618, "inspector": -6.840011626895618, "into": -6.434546518787453, "invalid": -6.840011626895618, "is": -5.048252157667562, "isn": -6.840011626895618, "issues": -6.840011626895618, "it": -6.434546518787453, "javascript": -6.840011626895618, "js": -5.230573714461517, "just": -5.923720895021463, "label": -6.840011626895618, "launch": -6.840011626895618, "league": -6.840011626895618, "leagues": -6.840011626895618, "lib": -5.335934230119343, "libc": -6.840011626895618, "libpthread": -6.840011626895618, "likely": -6.840011626895618, "link": -6.840011626895618, "linux": -6.840011626895618, "load": -6.434546518787453, "loading": -6.840011626895618, "locator": -4.699945463399347, "log": -6.434546518787453, "logs": -5.923720895021463, "lookup": -6.840011626895618, "may": -6.840011626895618, "message": -6.840011626895618, "minibrowser": -6.434546518787453, "minutes": -6.840011626895618, "module": -6.840011626895618, "modules": -5.453717265775727, "more": -6.840011626895618, "ms": -5.923720895021463, "my": -6.840011626895618, "navigated": -6.840011626895618, "navigating": -6.840011626895618, "navigation": -5.335934230119343, "navigationtimeout": -6.840011626895618, "needed": -6.840011626895618, "network": -6.840011626895618, "new": -6.840011626895618, "newcontext": -6.840011626895618, "news": -6.840011626895618, "ng": -6.434546518787453, "no": -5.453717265775727, "node": -5.335934230119343, "not": -5.923720895021463, "note": -6.840011626895618, "nth": -6.840011626895618, "occur": -6.840011626895618, "of": -5.230573714461517, "on": -6.434546518787453, "open": -6.146864446335672, "option": -6.840011626895618, "options": -5.923720895021463, "or": -5.741399338227508, "out": -6.840011626895618, "override": -6.434546518787453, "page": -4.1658629774690885, "pages": -6.840011626895618, "password": -5.923720895021463, "pbutton": -6.840011626895618, "pid": -6.434546518787453, "pipe": -6.840011626895618, "playwright": -4.642787049559399, "private": -6.840011626895618, "problematic": -6.840011626895618, "progress": -6.840011626895618, "progresscontroller": -6.840011626895618, "protocol": -6.840011626895618, "pthread": -6.840011626895618, "pw": -6.434546518787453, "question": -6.840011626895618, "rather": -6.840011626895618, "reason": -6.146864446335672, "regexp": -6.840011626895618, "release": -6.434546518787453, "rerun": -6.840011626895618, "resolved": -6.434546518787453, "retrieve": -6.840011626895618, "retry": -6.840011626895618, "run": -6.146864446335672, "runnavigationtask": -6.840011626895618, "running": -6.434546518787453, "say": -6.840011626895618, "scope": -6.840011626895618, "scrolling": -6.434546518787453, "seconds": -6.840011626895618, "select": -6.146864446335672, "selector": -5.923720895021463, "self": -6.840011626895618, "session": -6.840011626895618, "set": -5.58724865840025, "sets": -6.840011626895618, "settimeout": -6.840011626895618, "sh": -6.840011626895618, "share": -6.434546518787453, "show": -6.840011626895618, "sidebar": -6.434546518787453, "signed": -6.840011626895618, "similar": -6.840011626895618, "single": -6.840011626895618, "site": -6.146864446335672, "slow": -6.840011626895618, "snap": -6.840011626895618, "so": -6.840011626895618, "sometimes": -6.840011626895618, "span": -6.840011626895618, "spec": -6.434546518787453, "specific": -6.434546518787453, "src": -6.840011626895618, "ssl": -6.840011626895618, "stable": -6.146864446335672, "startup": -6.840011626895618, "statement": -6.840011626895618, "status": -6.840011626895618, "stuck": -6.146864446335672, "submit": -6.840011626895618, "symbol": -6.434546518787453, "target": -4.825108606353353, "teaser": -6.840011626895618, "test": -4.642787049559399, "tests": -6.146864446335672, "text": -6.434546518787453, "that": -5.923720895021463, "the": -4.314282982587362, "there": -5.923720895021463, "this": -5.923720895021463, "throw": -6.840011626895618, "throws": -6.840011626895618, "time": -6.840011626895618, "timed": -6.840011626895618, "timeout": -3.9222408948113383, "timeouterror": -5.923720895021463, "timeouts": -5.923720895021463, "to": -4.588719828289123, "tobevisible": -6.840011626895618, "tried": -6.840011626895618, "ts": -6.434546518787453, "undefined": -6.840011626895618, "unhandledpromiserejectionwarning": -6.840011626895618, "until": -6.840011626895618, "url": -5.923720895021463, "use": -5.923720895021463, "user": -6.434546518787453, "username": -6.434546518787453, "using": -6.840011626895618, "usr": -6.840011626895618, "variable": -6.840011626895618, "version": -6.840011626895618, "view": -6.840011626895618, "visible": -5.453717265775727, "wait": -6.840011626895618, "waitforloadstate": -6.840011626895618, "waitforselector": -6.434546518787453, "waitfortimeout": -6.434546518787453, "waiting": -4.894101477840304, "waituntil": -6.840011626895618, "wamdata": -6.840011626895618, "was": -5.58724865840025, "way": -6.840011626895618, "we": -6.840011626895618, "webkit": -6.434546518787453, "when": -6.840011626895618, "while": -6.146864446335672, "whole": -6.840011626895618, "will": -6.840011626895618, "window": -6.840011626895618, "with": -6.146864446335672, "wrapper": -5.923720895021463, "x86": -6.840011626895618, "yet": -6.840011626895618, "your": -6.434546518787453 } }, "playwrightVersion": "1.61.1", "priors": { "assertion": -2.2472349979108808, "env-config": -1.6766901394432678, "flaky-by-retry": -2.7327428136925813, "locator-not-found": -2.0395956331326364, "navigation": -1.7211419020141017, "network": -2.1041341542702074, "timeout": -1.5540878173509354 }, "totals": { "assertion": 323, "env-config": 694, "flaky-by-retry": 68, "locator-not-found": 368, "navigation": 731, "network": 555, "timeout": 959 }, "version": 3, "vocabSize": 910 };
10862
+
10863
+ // src/analysis/NaiveBayesClassifier.ts
10864
+ init_esm_shims();
10865
+
10866
+ // src/analysis/tokenize.ts
10867
+ init_esm_shims();
10868
+ function tokenize(text) {
10869
+ return text.toLowerCase().replace(/https?:\/\/\S+/gi, " URL ").replace(/[^a-zA-Z0-9\s]/g, " ").replace(/\b\d{3,}[a-z]*\b/g, " NUM ").split(/\s+/).filter((t) => t.length > 1);
10870
+ }
10871
+
10872
+ // src/analysis/NaiveBayesClassifier.ts
10873
+ function classify(model, text) {
10874
+ return classifyTokens(model, tokenize(text));
10875
+ }
10876
+ function classifyTokens(model, tokens) {
10877
+ const vocabTokens = tokens.filter(
10878
+ (tok) => tok.length > 0 && model.labels.some((l) => model.logLikelihoods[l]?.[tok] !== void 0)
10879
+ );
10880
+ if (vocabTokens.length === 0) {
10881
+ return { label: "unknown", margin: 0 };
10882
+ }
10883
+ const scores = {};
10884
+ for (const label of model.labels) {
10885
+ let s = model.priors[label];
10886
+ const oov = Math.log(model.alpha / (model.totals[label] + model.alpha * model.vocabSize));
10887
+ const ll = model.logLikelihoods[label];
10888
+ for (const tok of vocabTokens) {
10889
+ s += ll[tok] ?? oov;
10890
+ }
10891
+ scores[label] = s;
10892
+ }
10893
+ const ranked = Object.entries(scores).sort((a, b) => b[1] - a[1]);
10894
+ const topLog = ranked[0][1];
10895
+ const secondLog = ranked[1]?.[1] ?? topLog;
10896
+ const margin = (topLog - secondLog) / vocabTokens.length;
10897
+ return { label: ranked[0][0], margin };
10898
+ }
10899
+ function isValidNaiveBayesModel(m) {
10900
+ const x = m;
10901
+ return !!x && Array.isArray(x.labels) && x.labels.length > 0 && typeof x.version === "number" && !!x.priors && !!x.totals && !!x.logLikelihoods && typeof x.vocabSize === "number" && typeof x.alpha === "number";
10902
+ }
10854
10903
 
10855
10904
  // src/analysis/ModelStore.ts
10856
10905
  var MODEL_SIG_DOMAIN = "reportforge-model-sig:v1\n";
@@ -10875,10 +10924,7 @@ function verifyModelSignature(modelJson, signatureB64url) {
10875
10924
  return false;
10876
10925
  }
10877
10926
  }
10878
- function schemaValid(m) {
10879
- const x = m;
10880
- return !!x && Array.isArray(x.labels) && x.labels.length > 0 && typeof x.version === "number" && !!x.priors && !!x.totals && !!x.logLikelihoods && typeof x.vocabSize === "number" && typeof x.alpha === "number";
10881
- }
10927
+ var schemaValid = isValidNaiveBayesModel;
10882
10928
  function readCache2() {
10883
10929
  try {
10884
10930
  const raw = fs3.readFileSync(cacheFile(), "utf8");
@@ -11195,42 +11241,61 @@ function maybePrintUpdateNotice(licenseInfo, currentVersion) {
11195
11241
  // src/analysis/index.ts
11196
11242
  init_esm_shims();
11197
11243
 
11198
- // src/analysis/FailureClusterer.ts
11244
+ // src/analysis/LocalModelStore.ts
11199
11245
  init_esm_shims();
11246
+ import fs4 from "fs";
11247
+ import os5 from "os";
11248
+ import path5 from "path";
11249
+ var testDeps2 = null;
11250
+ function defaultLocalModelPath() {
11251
+ return testDeps2?.file ?? path5.join(os5.homedir(), ".reportforge", "model-local.json");
11252
+ }
11253
+ function loadLocalModel(overridePath) {
11254
+ const file = overridePath ?? defaultLocalModelPath();
11255
+ const explicit = overridePath !== void 0;
11256
+ const reject = (why) => {
11257
+ const msg = `local model at ${file} not used: ${why}`;
11258
+ if (explicit) logger.warn(msg);
11259
+ else logger.debug(msg);
11260
+ return null;
11261
+ };
11262
+ let parsed;
11263
+ try {
11264
+ parsed = JSON.parse(fs4.readFileSync(file, "utf8"));
11265
+ } catch (e) {
11266
+ return explicit ? reject(`unreadable (${e.message})`) : null;
11267
+ }
11268
+ if (parsed.formatVersion !== 1) return reject(`unsupported formatVersion ${String(parsed.formatVersion)}`);
11269
+ if (!isValidNaiveBayesModel(parsed.model)) return reject("embedded model failed schema validation");
11270
+ const meta = parsed.meta;
11271
+ if (!meta || typeof meta.gatePassed !== "boolean") return reject("missing meta");
11272
+ if (!meta.gatePassed) return reject("its evaluation gate did not pass - run train-model after labeling more feedback");
11273
+ if (typeof meta.acceptThreshold !== "number") return reject("gate passed but no calibrated threshold (corrupt meta)");
11274
+ return {
11275
+ model: parsed.model,
11276
+ acceptThreshold: meta.acceptThreshold,
11277
+ strongThreshold: typeof meta.strongThreshold === "number" ? meta.strongThreshold : null,
11278
+ meta
11279
+ };
11280
+ }
11200
11281
 
11201
- // src/analysis/NaiveBayesClassifier.ts
11282
+ // src/analysis/FailureClusterer.ts
11202
11283
  init_esm_shims();
11203
11284
 
11204
- // src/analysis/tokenize.ts
11285
+ // src/analysis/redact.ts
11205
11286
  init_esm_shims();
11206
- function tokenize(text) {
11207
- return text.toLowerCase().replace(/https?:\/\/\S+/gi, " URL ").replace(/[^a-zA-Z0-9\s]/g, " ").replace(/\b\d{3,}[a-z]*\b/g, " NUM ").split(/\s+/).filter((t) => t.length > 1);
11287
+ var URI_RE = /[a-z][\w+.-]*:\/\/\S+/gi;
11288
+ var EMAIL_RE = /\b[\w.+-]+@[\w.-]+\.\w+\b/g;
11289
+ var SECRET_RE = /\b(?=[A-Za-z0-9_+/=-]*[0-9])(?=[A-Za-z0-9_+/=-]*[A-Za-z])[A-Za-z0-9_+/=-]{16,}\b/g;
11290
+ var IP_RE = /\b\d{1,3}(?:\.\d{1,3}){3}\b/g;
11291
+ var WIN_PATH_RE = /[A-Za-z]:\\[^\s'"]+/g;
11292
+ var UNIX_PATH_RE = /(?:\/[\w.-]+){2,}/g;
11293
+ function redactForStorage(raw) {
11294
+ const redacted = raw.replace(URI_RE, " URL ").replace(EMAIL_RE, " EMAIL ").replace(SECRET_RE, " SECRET ").replace(IP_RE, " IP ").replace(WIN_PATH_RE, " PATH ").replace(UNIX_PATH_RE, " PATH ");
11295
+ return tokenize(redacted).join(" ");
11208
11296
  }
11209
-
11210
- // src/analysis/NaiveBayesClassifier.ts
11211
- function classify(model, text) {
11212
- const tokens = tokenize(text);
11213
- const vocabTokens = tokens.filter(
11214
- (tok) => model.labels.some((l) => model.logLikelihoods[l]?.[tok] !== void 0)
11215
- );
11216
- if (vocabTokens.length === 0) {
11217
- return { label: "unknown", margin: 0 };
11218
- }
11219
- const scores = {};
11220
- for (const label of model.labels) {
11221
- let s = model.priors[label];
11222
- const oov = Math.log(model.alpha / (model.totals[label] + model.alpha * model.vocabSize));
11223
- const ll = model.logLikelihoods[label];
11224
- for (const tok of vocabTokens) {
11225
- s += ll[tok] ?? oov;
11226
- }
11227
- scores[label] = s;
11228
- }
11229
- const ranked = Object.entries(scores).sort((a, b) => b[1] - a[1]);
11230
- const topLog = ranked[0][1];
11231
- const secondLog = ranked[1]?.[1] ?? topLog;
11232
- const margin = (topLog - secondLog) / vocabTokens.length;
11233
- return { label: ranked[0][0], margin };
11297
+ function localInferenceTokens(message) {
11298
+ return redactForStorage(message).split(" ").filter(Boolean);
11234
11299
  }
11235
11300
 
11236
11301
  // src/analysis/constants.ts
@@ -11259,7 +11324,7 @@ function errorHeader(message) {
11259
11324
  return beforeCallLog.split("\n").filter((line) => !/^\s*[-+]?\s*(?:Expected|Received)\b/i.test(line)).join("\n");
11260
11325
  }
11261
11326
  function isAssertionTimeout(message) {
11262
- return /Expect "[^"]+" with timeout/.test(message) && /resolved to [1-9]\d* element/.test(message);
11327
+ return /(?:Expect "[^"]+"|expect\.\w+) with timeout/.test(message) && /resolved to [1-9]\d* element/.test(message);
11263
11328
  }
11264
11329
  function isNetwork(message) {
11265
11330
  return /net::ERR_(CONNECTION|NAME_NOT_RESOLVED|INTERNET_DISCONNECTED|SSL|TIMED_OUT|ADDRESS|NETWORK_CHANGED|EMPTY_RESPONSE)|\bECONN(?:REFUSED|RESET)\b|\bENOTFOUND\b|\bEAI_AGAIN\b|getaddrinfo|socket hang up|fetch failed/.test(errorHeader(message));
@@ -11296,26 +11361,37 @@ function topFrame(stack) {
11296
11361
  function representativeMessage(message) {
11297
11362
  return clampWithEllipsis(message.split("\n")[0], MAX_MESSAGE_CHARS);
11298
11363
  }
11299
- function classifyOne(f, model) {
11364
+ function classifyOne(f, chain) {
11300
11365
  const frame = topFrame(f.error.stack);
11301
11366
  if (f.retryHistory.some((r) => r.status === "passed")) {
11302
- return { category: "flaky-by-retry", margin: OVERRIDE_MARGIN, failure: f, frame };
11367
+ return { category: "flaky-by-retry", margin: OVERRIDE_MARGIN, strength: "strong", source: "retry", failure: f, frame };
11303
11368
  }
11304
11369
  for (const [match, category] of MESSAGE_RULES) {
11305
- if (match(f.error.message)) return { category, margin: OVERRIDE_MARGIN, failure: f, frame };
11370
+ if (match(f.error.message)) {
11371
+ return { category, margin: OVERRIDE_MARGIN, strength: "strong", source: "rule", failure: f, frame };
11372
+ }
11373
+ }
11374
+ if (chain.local) {
11375
+ const { model, acceptThreshold, strongThreshold } = chain.local;
11376
+ const r = classifyTokens(model, localInferenceTokens(f.error.message));
11377
+ if (r.label !== "unknown" && r.margin >= acceptThreshold) {
11378
+ const strength = strongThreshold !== null && r.margin >= strongThreshold ? "strong" : "moderate";
11379
+ return { category: r.label, margin: r.margin, strength, source: "local", failure: f, frame };
11380
+ }
11306
11381
  }
11307
- const { label, margin } = classify(model, classifyInput(f));
11308
- return { category: label, margin, failure: f, frame };
11382
+ const { label, margin } = classify(chain.base, classifyInput(f));
11383
+ return { category: label, margin, strength: strengthOf(margin), source: "base", failure: f, frame };
11309
11384
  }
11310
- function classifyAll(failures, model) {
11311
- return failures.map((f) => classifyOne(f, model));
11385
+ function classifyAll(failures, chain) {
11386
+ return failures.map((f) => classifyOne(f, chain));
11312
11387
  }
11313
11388
  function perTestClassifications(classified) {
11314
11389
  return classified.map((c) => ({
11315
11390
  testId: c.failure.testId,
11316
11391
  category: c.category,
11317
11392
  message: representativeMessage(c.failure.error.message),
11318
- strength: strengthOf(c.margin)
11393
+ strength: c.strength
11394
+ // resolved at classification time, per producing source
11319
11395
  }));
11320
11396
  }
11321
11397
  function clusterClassified(classified) {
@@ -11326,13 +11402,16 @@ function clusterClassified(classified) {
11326
11402
  if (bucket) bucket.push(c);
11327
11403
  else groups.set(key, [c]);
11328
11404
  }
11405
+ const rank = Object.fromEntries(
11406
+ STRENGTH_LEVELS.map((level, i) => [level, i])
11407
+ );
11329
11408
  const clusters = [];
11330
11409
  for (const members of groups.values()) {
11331
- const margin = Math.max(...members.map((m) => m.margin));
11410
+ const strongest = members.reduce((a, b) => rank[b.strength] > rank[a.strength] ? b : a);
11332
11411
  clusters.push({
11333
11412
  category: members[0].category,
11334
- strength: strengthOf(margin),
11335
- margin,
11413
+ strength: strongest.strength,
11414
+ margin: Math.max(...members.map((m) => m.margin)),
11336
11415
  count: members.length,
11337
11416
  tests: members.slice(0, MAX_TESTS_PER_CLUSTER).map((m) => m.failure.testTitle),
11338
11417
  testsTotal: members.length,
@@ -11408,82 +11487,133 @@ function buildBriefSentence(stats, analysis, trend) {
11408
11487
 
11409
11488
  // src/analysis/UnclassifiedCollector.ts
11410
11489
  init_esm_shims();
11411
- import fs4 from "fs";
11412
- import os5 from "os";
11413
- import path5 from "path";
11490
+ import fs6 from "fs";
11491
+ import os7 from "os";
11492
+ import path7 from "path";
11414
11493
 
11415
11494
  // src/analysis/feedback-csv.ts
11416
11495
  init_esm_shims();
11417
- var FEEDBACK_HEADER = "category,margin,text";
11496
+ var FEEDBACK_HEADER = "category,margin,label,text";
11497
+ var LEGACY_FEEDBACK_HEADER = "category,margin,text";
11418
11498
  function parseFeedbackRows(content) {
11419
- return content.trim().split("\n").slice(1).filter(Boolean).map((line) => {
11499
+ const lines = content.trim().split("\n").filter(Boolean);
11500
+ if (lines.length === 0) return [];
11501
+ const header = lines[0].trim();
11502
+ const isV2 = header === FEEDBACK_HEADER;
11503
+ if (!isV2 && header !== LEGACY_FEEDBACK_HEADER) return [];
11504
+ const minParts = isV2 ? 4 : 3;
11505
+ const rows = [];
11506
+ for (const line of lines.slice(1)) {
11420
11507
  const parts = line.split(",");
11421
- return { category: parts[0], margin: parts[1], text: parts.slice(2).join(","), raw: line };
11422
- });
11508
+ if (parts.length < minParts) continue;
11509
+ const row = isV2 ? { category: parts[0], margin: parts[1], label: parts[2], text: parts.slice(3).join(",") } : { category: parts[0], margin: parts[1], label: "", text: parts.slice(2).join(",") };
11510
+ if (row.text.trim().length === 0) continue;
11511
+ rows.push(row);
11512
+ }
11513
+ return rows;
11514
+ }
11515
+ function serializeFeedbackRow(r) {
11516
+ const label = r.label.replace(/[,\r\n]/g, "").trim();
11517
+ return `${r.category},${r.margin},${label},${r.text}`;
11423
11518
  }
11424
11519
  function feedbackIdentity(category, text) {
11425
11520
  return `${category} ${text}`;
11426
11521
  }
11427
11522
 
11523
+ // src/analysis/FeedbackStore.ts
11524
+ init_esm_shims();
11525
+ import fs5 from "fs";
11526
+ import os6 from "os";
11527
+ import path6 from "path";
11528
+ var MARKER_FILENAME = "project.json";
11529
+ function writeProjectMarker(projectDir, marker) {
11530
+ try {
11531
+ atomicWrite(path6.join(projectDir, MARKER_FILENAME), JSON.stringify(marker));
11532
+ } catch {
11533
+ }
11534
+ }
11535
+ function rewriteFeedbackFile(file, rows) {
11536
+ const body = rows.map(serializeFeedbackRow).join("\n");
11537
+ atomicWrite(file, `${FEEDBACK_HEADER}
11538
+ ${body}${body ? "\n" : ""}`);
11539
+ }
11540
+ function atomicWrite(file, content) {
11541
+ fs5.mkdirSync(path6.dirname(file), { recursive: true });
11542
+ const tmp = `${file}.${process.pid}.tmp`;
11543
+ fs5.writeFileSync(tmp, content, "utf8");
11544
+ fs5.renameSync(tmp, file);
11545
+ }
11546
+
11428
11547
  // src/analysis/UnclassifiedCollector.ts
11429
11548
  var MAX_ROWS = 500;
11430
11549
  var FILENAME = "unclassified.csv";
11431
- var URI_RE = /[a-z][\w+.-]*:\/\/\S+/gi;
11432
- var EMAIL_RE = /\b[\w.+-]+@[\w.-]+\.\w+\b/g;
11433
- var SECRET_RE = /\b(?=[A-Za-z0-9_+/=-]*[0-9])(?=[A-Za-z0-9_+/=-]*[A-Za-z])[A-Za-z0-9_+/=-]{16,}\b/g;
11434
- var IP_RE = /\b\d{1,3}(?:\.\d{1,3}){3}\b/g;
11435
- var WIN_PATH_RE = /[A-Za-z]:\\[^\s'"]+/g;
11436
- var UNIX_PATH_RE = /(?:\/[\w.-]+){2,}/g;
11437
- function redactForStorage(raw) {
11438
- const redacted = raw.replace(URI_RE, " URL ").replace(EMAIL_RE, " EMAIL ").replace(SECRET_RE, " SECRET ").replace(IP_RE, " IP ").replace(WIN_PATH_RE, " PATH ").replace(UNIX_PATH_RE, " PATH ");
11439
- return tokenize(redacted).join(" ");
11440
- }
11441
- function shouldCollect(c) {
11442
- return c.category === "unknown" || c.margin <= STRENGTH.collectMaxMargin;
11550
+ function shouldCollect(c, scope) {
11551
+ if (c.source !== "base") return false;
11552
+ if (c.category === "unknown" || c.margin <= STRENGTH.collectMaxMargin) return true;
11553
+ return scope === "all";
11443
11554
  }
11444
11555
  function tildeify(p) {
11445
- const home = os5.homedir();
11556
+ const home = os7.homedir();
11446
11557
  return p.startsWith(home) ? `~${p.slice(home.length)}` : p;
11447
11558
  }
11448
- function collectUnclassified(classified, projectDir) {
11449
- const rows = classified.filter(shouldCollect).map((c) => ({ text: redactForStorage(c.failure.error.message), category: c.category, margin: c.margin })).filter((r) => r.text.length > 0);
11559
+ function collectUnclassified(classified, projectDir, opts = {}) {
11560
+ const scope = opts.scope ?? "blind-spots";
11561
+ const rows = classified.filter((c) => shouldCollect(c, scope)).map((c) => ({ text: redactForStorage(c.failure.error.message), category: c.category, margin: c.margin })).filter((r) => r.text.length > 0);
11450
11562
  if (rows.length === 0) return;
11451
- const file = path5.join(projectDir, FILENAME);
11452
- const firstTime = !fs4.existsSync(file);
11563
+ const file = path7.join(projectDir, FILENAME);
11564
+ const firstTime = !fs6.existsSync(file);
11453
11565
  const byIdentity = /* @__PURE__ */ new Map();
11454
11566
  if (!firstTime) {
11455
- for (const r of parseFeedbackRows(fs4.readFileSync(file, "utf8"))) {
11456
- byIdentity.set(feedbackIdentity(r.category, r.text), r.raw);
11567
+ for (const r of parseFeedbackRows(fs6.readFileSync(file, "utf8"))) {
11568
+ byIdentity.set(feedbackIdentity(r.category, r.text), r);
11457
11569
  }
11458
11570
  }
11459
- let added = false;
11460
11571
  for (const r of rows) {
11461
11572
  const id = feedbackIdentity(r.category, r.text);
11573
+ const label = byIdentity.get(id)?.label ?? "";
11462
11574
  byIdentity.delete(id);
11463
- byIdentity.set(id, `${r.category},${r.margin},${r.text}`);
11464
- added = true;
11465
- }
11466
- if (!added) return;
11467
- const all = [...byIdentity.values()].slice(-MAX_ROWS);
11468
- fs4.mkdirSync(projectDir, { recursive: true });
11469
- fs4.writeFileSync(file, `${FEEDBACK_HEADER}
11470
- ${all.join("\n")}
11471
- `, "utf8");
11575
+ byIdentity.set(id, { category: r.category, margin: String(r.margin), label, text: r.text });
11576
+ }
11577
+ const all = evictOldestUnlabeledFirst([...byIdentity.values()], MAX_ROWS);
11578
+ fs6.mkdirSync(projectDir, { recursive: true });
11579
+ rewriteFeedbackFile(file, all);
11580
+ if (opts.project) {
11581
+ writeProjectMarker(projectDir, { cwd: opts.project.cwd, outputFile: opts.project.outputFile, updatedAt: Date.now() });
11582
+ }
11472
11583
  if (firstTime) {
11473
11584
  logger.info(
11474
11585
  `Unrecognized failures collected locally at ${tildeify(file)} to improve offline classification. Local only - never sent anywhere. Disable: failureAnalysis.collectUnclassified=false`
11475
11586
  );
11476
11587
  }
11477
11588
  }
11589
+ function evictOldestUnlabeledFirst(rows, max) {
11590
+ const excess = rows.length - max;
11591
+ if (excess <= 0) return rows;
11592
+ let unlabeledToDrop = Math.min(excess, rows.filter((r) => r.label === "").length);
11593
+ let labeledToDrop = excess - unlabeledToDrop;
11594
+ const out = [];
11595
+ for (const r of rows) {
11596
+ if (r.label === "" && unlabeledToDrop > 0) {
11597
+ unlabeledToDrop--;
11598
+ continue;
11599
+ }
11600
+ if (r.label !== "" && labeledToDrop > 0) {
11601
+ labeledToDrop--;
11602
+ continue;
11603
+ }
11604
+ out.push(r);
11605
+ }
11606
+ return out;
11607
+ }
11478
11608
 
11479
11609
  // src/utils/paths.ts
11480
11610
  init_esm_shims();
11481
- import os6 from "os";
11482
- import path6 from "path";
11611
+ import os8 from "os";
11612
+ import path8 from "path";
11483
11613
  import crypto from "crypto";
11484
11614
  function resolveProjectDir(options, cwd) {
11485
11615
  const projectKey = crypto.createHash("sha256").update(cwd + (options.outputFile ?? "")).digest("hex").slice(0, 8);
11486
- return path6.join(os6.homedir(), ".reportforge", projectKey);
11616
+ return path8.join(os8.homedir(), ".reportforge", projectKey);
11487
11617
  }
11488
11618
 
11489
11619
  // src/analysis/index.ts
@@ -11518,16 +11648,36 @@ function runFailureAnalysis(reportData, options, cwd) {
11518
11648
  if (reportData.stats.failed === 0 || !fa.enabled) return;
11519
11649
  const cap = fa.maxFailuresToAnalyse;
11520
11650
  const analysed = reportData.failures.slice(0, cap);
11521
- const model = loadModel(fa.autoUpdateModel);
11522
- const classified = classifyAll(analysed, model);
11651
+ const base = loadModel(fa.autoUpdateModel);
11652
+ const local = fa.localModel ? loadLocalModel(fa.localModelPath) ?? void 0 : void 0;
11653
+ if (local) {
11654
+ logger.debug(
11655
+ `local model active (trained ${local.meta.trainedAt}, ${local.meta.labeledCount} labeled rows, accept margin >= ${local.acceptThreshold})`
11656
+ );
11657
+ if (local.meta.baseVersionAtEval !== base.version) {
11658
+ logger.debug(
11659
+ `local model was gate-checked against base v${local.meta.baseVersionAtEval} but base v${base.version} is active - re-run train-model to re-validate against the current base`
11660
+ );
11661
+ }
11662
+ }
11663
+ const classified = classifyAll(analysed, { base, local });
11664
+ logger.debug(`failure analysis: ${classified.length} classified - ${sourceTally(classified)}`);
11523
11665
  reportData.classifications = perTestClassifications(classified);
11524
11666
  if (templatesConsumeAnalysis(options)) {
11525
11667
  reportData.analysis = analyseClassified(classified, reportData.failures.length, fa);
11526
11668
  }
11527
11669
  if (fa.collectUnclassified) {
11528
- collectUnclassified(classified, resolveProjectDir(options, cwd));
11670
+ collectUnclassified(classified, resolveProjectDir(options, cwd), {
11671
+ scope: fa.collectScope,
11672
+ project: { cwd, outputFile: options.outputFile }
11673
+ });
11529
11674
  }
11530
11675
  }
11676
+ function sourceTally(classified) {
11677
+ const counts = /* @__PURE__ */ new Map();
11678
+ for (const c of classified) counts.set(c.source, (counts.get(c.source) ?? 0) + 1);
11679
+ return ["rule", "retry", "local", "base"].filter((s) => counts.has(s)).map((s) => `${counts.get(s)} ${s}`).join(" / ");
11680
+ }
11531
11681
 
11532
11682
  // src/collector/DataCollector.ts
11533
11683
  init_esm_shims();
@@ -11803,8 +11953,8 @@ function buildSuiteResults(projects, limit) {
11803
11953
  const top = projects.flatMap((p) => p.suites);
11804
11954
  if (top.length <= 1 && top[0] && top[0].suites.length > 0) {
11805
11955
  const file = top[0];
11806
- const fs14 = statsFromTests(file.tests);
11807
- const rootRow = file.tests.length > 0 ? [{ label: file.title, passed: fs14.passed, failed: fs14.failed, timedOut: fs14.timedOut, skipped: fs14.skipped }] : [];
11956
+ const fs16 = statsFromTests(file.tests);
11957
+ const rootRow = file.tests.length > 0 ? [{ label: file.title, passed: fs16.passed, failed: fs16.failed, timedOut: fs16.timedOut, skipped: fs16.skipped }] : [];
11808
11958
  return capRows([...rootRow, ...file.suites.map(toRow)], limit);
11809
11959
  }
11810
11960
  return capRows(top.map(toRow), limit);
@@ -12450,14 +12600,14 @@ var ShardMerger = class {
12450
12600
 
12451
12601
  // src/pdf/PdfGenerator.ts
12452
12602
  init_esm_shims();
12453
- import fs12 from "fs";
12454
- import path12 from "path";
12603
+ import fs14 from "fs";
12604
+ import path14 from "path";
12455
12605
 
12456
12606
  // src/templates/engine.ts
12457
12607
  init_esm_shims();
12458
12608
  var import_handlebars = __toESM(require_lib());
12459
- import fs5 from "fs";
12460
- import path7 from "path";
12609
+ import fs7 from "fs";
12610
+ import path9 from "path";
12461
12611
 
12462
12612
  // src/utils/duration.ts
12463
12613
  init_esm_shims();
@@ -12516,9 +12666,9 @@ var TemplateEngine = class {
12516
12666
  this.customTemplateCache = /* @__PURE__ */ new Map();
12517
12667
  this.styleCache = /* @__PURE__ */ new Map();
12518
12668
  this.handlebars = import_handlebars.default.create();
12519
- this.templatesDir = path7.resolve(__dirname, "templates");
12520
- if (!fs5.existsSync(this.templatesDir)) {
12521
- this.templatesDir = path7.resolve(__dirname, "../templates");
12669
+ this.templatesDir = path9.resolve(__dirname, "templates");
12670
+ if (!fs7.existsSync(this.templatesDir)) {
12671
+ this.templatesDir = path9.resolve(__dirname, "../templates");
12522
12672
  }
12523
12673
  this.registerHelpers();
12524
12674
  this.registerPartials();
@@ -12535,21 +12685,21 @@ var TemplateEngine = class {
12535
12685
  this.chartjsInline = inline;
12536
12686
  }
12537
12687
  render(data, template, userSections, slowTestThreshold) {
12538
- const layoutPath = path7.join(this.templatesDir, "layouts", `${template}.hbs`);
12539
- if (!fs5.existsSync(layoutPath)) {
12688
+ const layoutPath = path9.join(this.templatesDir, "layouts", `${template}.hbs`);
12689
+ if (!fs7.existsSync(layoutPath)) {
12540
12690
  throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
12541
12691
  }
12542
- const layoutSource = fs5.readFileSync(layoutPath, "utf8");
12692
+ const layoutSource = fs7.readFileSync(layoutPath, "utf8");
12543
12693
  const compiledLayout = this.handlebars.compile(layoutSource);
12544
12694
  const ctx = this.buildContext(data, template, userSections, slowTestThreshold);
12545
12695
  return compiledLayout(ctx);
12546
12696
  }
12547
12697
  renderFromPath(data, filePath, slowTestThreshold) {
12548
12698
  if (!this.customTemplateCache.has(filePath)) {
12549
- if (!fs5.existsSync(filePath)) {
12699
+ if (!fs7.existsSync(filePath)) {
12550
12700
  throw new Error(`[reportforge] Custom template not found: ${filePath}`);
12551
12701
  }
12552
- const source = fs5.readFileSync(filePath, "utf8");
12702
+ const source = fs7.readFileSync(filePath, "utf8");
12553
12703
  this.customTemplateCache.set(filePath, this.handlebars.compile(source));
12554
12704
  }
12555
12705
  const compiledFn = this.customTemplateCache.get(filePath);
@@ -12681,18 +12831,18 @@ var TemplateEngine = class {
12681
12831
  readStyle(filename) {
12682
12832
  const cached = this.styleCache.get(filename);
12683
12833
  if (cached !== void 0) return cached;
12684
- const stylePath = path7.join(this.templatesDir, "styles", filename);
12685
- const css = fs5.existsSync(stylePath) ? fs5.readFileSync(stylePath, "utf8") : "";
12834
+ const stylePath = path9.join(this.templatesDir, "styles", filename);
12835
+ const css = fs7.existsSync(stylePath) ? fs7.readFileSync(stylePath, "utf8") : "";
12686
12836
  this.styleCache.set(filename, css);
12687
12837
  return css;
12688
12838
  }
12689
12839
  registerPartials() {
12690
- const partialsDir = path7.join(this.templatesDir, "partials");
12691
- if (!fs5.existsSync(partialsDir)) return;
12692
- for (const file of fs5.readdirSync(partialsDir)) {
12840
+ const partialsDir = path9.join(this.templatesDir, "partials");
12841
+ if (!fs7.existsSync(partialsDir)) return;
12842
+ for (const file of fs7.readdirSync(partialsDir)) {
12693
12843
  if (!file.endsWith(".hbs")) continue;
12694
- const name = path7.basename(file, ".hbs");
12695
- const src = fs5.readFileSync(path7.join(partialsDir, file), "utf8");
12844
+ const name = path9.basename(file, ".hbs");
12845
+ const src = fs7.readFileSync(path9.join(partialsDir, file), "utf8");
12696
12846
  this.handlebars.registerPartial(name, src);
12697
12847
  }
12698
12848
  }
@@ -12797,7 +12947,7 @@ var TemplateEngine = class {
12797
12947
 
12798
12948
  // src/screenshots/ScreenshotEmbedder.ts
12799
12949
  init_esm_shims();
12800
- import fs6 from "fs";
12950
+ import fs8 from "fs";
12801
12951
  import sharp from "sharp";
12802
12952
  var ScreenshotEmbedder = class {
12803
12953
  async embedAll(failures, opts) {
@@ -12806,7 +12956,7 @@ var ScreenshotEmbedder = class {
12806
12956
  async embed(failure, opts) {
12807
12957
  if (!failure.screenshotPath && !failure.screenshotBuffer) return;
12808
12958
  try {
12809
- const raw = failure.screenshotBuffer ?? await fs6.promises.readFile(failure.screenshotPath);
12959
+ const raw = failure.screenshotBuffer ?? await fs8.promises.readFile(failure.screenshotPath);
12810
12960
  const { buffer, mime } = opts.reencode ? await this.recompress(raw, opts) : { buffer: raw, mime: this.detectMimeType(raw) };
12811
12961
  failure.screenshotBase64 = `data:${mime};base64,${buffer.toString("base64")}`;
12812
12962
  } catch (e) {
@@ -12818,7 +12968,7 @@ var ScreenshotEmbedder = class {
12818
12968
  }
12819
12969
  async embedLogoFile(logoPath) {
12820
12970
  try {
12821
- const buffer = await fs6.promises.readFile(logoPath);
12971
+ const buffer = await fs8.promises.readFile(logoPath);
12822
12972
  const ext = logoPath.split(".").pop()?.toLowerCase();
12823
12973
  let mime = "image/png";
12824
12974
  if (ext === "jpg" || ext === "jpeg") mime = "image/jpeg";
@@ -12863,7 +13013,7 @@ var ScreenshotEmbedder = class {
12863
13013
  // src/pdf/BrowserManager.ts
12864
13014
  init_esm_shims();
12865
13015
  import { execSync as execSync2 } from "child_process";
12866
- import fs7 from "fs";
13016
+ import fs9 from "fs";
12867
13017
  var LAUNCH_ARGS = [
12868
13018
  "--no-sandbox",
12869
13019
  "--disable-setuid-sandbox",
@@ -12895,13 +13045,13 @@ var BrowserManager = class {
12895
13045
  }
12896
13046
  }
12897
13047
  resolveChromePath(explicit, puppeteer) {
12898
- if (explicit && fs7.existsSync(explicit)) return explicit;
13048
+ if (explicit && fs9.existsSync(explicit)) return explicit;
12899
13049
  const envPath = process.env.PUPPETEER_EXECUTABLE_PATH;
12900
- if (envPath && fs7.existsSync(envPath)) return envPath;
13050
+ if (envPath && fs9.existsSync(envPath)) return envPath;
12901
13051
  try {
12902
13052
  const chromeFinder = require_lib2();
12903
13053
  const found = chromeFinder();
12904
- if (found && fs7.existsSync(found)) return found;
13054
+ if (found && fs9.existsSync(found)) return found;
12905
13055
  } catch (err) {
12906
13056
  logger.debug("chrome discovery: chrome-finder failed", { error: err.message });
12907
13057
  }
@@ -12913,20 +13063,20 @@ var BrowserManager = class {
12913
13063
  "/snap/bin/chromium"
12914
13064
  ];
12915
13065
  for (const p of linuxPaths) {
12916
- if (fs7.existsSync(p)) return p;
13066
+ if (fs9.existsSync(p)) return p;
12917
13067
  }
12918
13068
  try {
12919
13069
  const found = execSync2("which google-chrome chromium chromium-browser 2>/dev/null", {
12920
13070
  stdio: "pipe"
12921
13071
  }).toString().trim().split("\n")[0];
12922
- if (found && fs7.existsSync(found)) return found;
13072
+ if (found && fs9.existsSync(found)) return found;
12923
13073
  } catch {
12924
13074
  logger.debug("chrome discovery: which lookup found nothing");
12925
13075
  }
12926
13076
  if (puppeteer.executablePath) {
12927
13077
  try {
12928
13078
  const bundled = puppeteer.executablePath();
12929
- if (bundled && fs7.existsSync(bundled)) return bundled;
13079
+ if (bundled && fs9.existsSync(bundled)) return bundled;
12930
13080
  } catch (err) {
12931
13081
  logger.debug("chrome discovery: no puppeteer bundled executable", { error: err.message });
12932
13082
  }
@@ -12940,22 +13090,22 @@ var BrowserManager = class {
12940
13090
 
12941
13091
  // src/pdf/HtmlWriter.ts
12942
13092
  init_esm_shims();
12943
- import fs8 from "fs";
12944
- import os7 from "os";
12945
- import path8 from "path";
13093
+ import fs10 from "fs";
13094
+ import os9 from "os";
13095
+ import path10 from "path";
12946
13096
  import crypto2 from "crypto";
12947
13097
  var HtmlWriter = class {
12948
13098
  async write(html) {
12949
- const tmpDir = os7.tmpdir();
13099
+ const tmpDir = os9.tmpdir();
12950
13100
  const filename = `rf-report-${crypto2.randomBytes(8).toString("hex")}.html`;
12951
- this.tempPath = path8.join(tmpDir, filename);
12952
- await fs8.promises.writeFile(this.tempPath, html, "utf8");
13101
+ this.tempPath = path10.join(tmpDir, filename);
13102
+ await fs10.promises.writeFile(this.tempPath, html, "utf8");
12953
13103
  return this.tempPath;
12954
13104
  }
12955
13105
  async cleanup() {
12956
13106
  if (this.tempPath) {
12957
13107
  const tempPath = this.tempPath;
12958
- await fs8.promises.unlink(tempPath).catch(
13108
+ await fs10.promises.unlink(tempPath).catch(
12959
13109
  (err) => logger.debug("temp HTML cleanup failed (ignored)", { path: tempPath, error: err.message })
12960
13110
  );
12961
13111
  this.tempPath = void 0;
@@ -12990,9 +13140,9 @@ var ChartRenderer = class {
12990
13140
  // src/pdf/PdfEncryptor.ts
12991
13141
  init_esm_shims();
12992
13142
  import { execFileSync } from "child_process";
12993
- import fs9 from "fs";
12994
- import path9 from "path";
12995
- import os8 from "os";
13143
+ import fs11 from "fs";
13144
+ import path11 from "path";
13145
+ import os10 from "os";
12996
13146
  import crypto3 from "crypto";
12997
13147
  var PdfEncryptor = class {
12998
13148
  async encrypt(pdfPath, password) {
@@ -13003,19 +13153,19 @@ var PdfEncryptor = class {
13003
13153
  );
13004
13154
  return;
13005
13155
  }
13006
- const tmpPath = path9.join(os8.tmpdir(), `rf-encrypted-${Date.now()}.pdf`);
13007
- const argFile = path9.join(os8.tmpdir(), `rf-qpdf-args-${crypto3.randomBytes(8).toString("hex")}`);
13156
+ const tmpPath = path11.join(os10.tmpdir(), `rf-encrypted-${Date.now()}.pdf`);
13157
+ const argFile = path11.join(os10.tmpdir(), `rf-qpdf-args-${crypto3.randomBytes(8).toString("hex")}`);
13008
13158
  try {
13009
13159
  const args = ["--encrypt", password, password, "256", "--", pdfPath, tmpPath];
13010
- fs9.writeFileSync(argFile, args.join("\n"), { mode: 384 });
13160
+ fs11.writeFileSync(argFile, args.join("\n"), { mode: 384 });
13011
13161
  execFileSync("qpdf", [`@${argFile}`], { stdio: "pipe" });
13012
- fs9.renameSync(tmpPath, pdfPath);
13162
+ fs11.renameSync(tmpPath, pdfPath);
13013
13163
  logger.info(`PDF encrypted with password.`);
13014
13164
  } catch (e) {
13015
13165
  throw new Error(`qpdf encryption failed: ${e.message}`);
13016
13166
  } finally {
13017
- if (fs9.existsSync(tmpPath)) fs9.unlinkSync(tmpPath);
13018
- fs9.rmSync(argFile, { force: true });
13167
+ if (fs11.existsSync(tmpPath)) fs11.unlinkSync(tmpPath);
13168
+ fs11.rmSync(argFile, { force: true });
13019
13169
  }
13020
13170
  }
13021
13171
  isQpdfAvailable() {
@@ -13031,8 +13181,8 @@ var PdfEncryptor = class {
13031
13181
 
13032
13182
  // src/filename/FilenameResolver.ts
13033
13183
  init_esm_shims();
13034
- import path10 from "path";
13035
- import fs10 from "fs";
13184
+ import path12 from "path";
13185
+ import fs12 from "fs";
13036
13186
  var MAX_BRANCH_LENGTH = 50;
13037
13187
  var FilenameResolver = class {
13038
13188
  /**
@@ -13049,8 +13199,8 @@ var FilenameResolver = class {
13049
13199
  const branch = this.sanitiseBranch(ctx.branch);
13050
13200
  const status = ctx.status;
13051
13201
  const resolved = template.replace(/\{date\}/g, date).replace(/\{branch\}/g, branch).replace(/\{status\}/g, status);
13052
- const absolute = path10.isAbsolute(resolved) ? resolved : path10.resolve(process.cwd(), resolved);
13053
- fs10.mkdirSync(path10.dirname(absolute), { recursive: true });
13202
+ const absolute = path12.isAbsolute(resolved) ? resolved : path12.resolve(process.cwd(), resolved);
13203
+ fs12.mkdirSync(path12.dirname(absolute), { recursive: true });
13054
13204
  return absolute;
13055
13205
  }
13056
13206
  /**
@@ -13062,7 +13212,7 @@ var FilenameResolver = class {
13062
13212
  * // → '/out/2026-report-executive.pdf'
13063
13213
  */
13064
13214
  injectTemplateSuffix(outputPath, suffix) {
13065
- const ext = path10.extname(outputPath);
13215
+ const ext = path12.extname(outputPath);
13066
13216
  const base = outputPath.slice(0, outputPath.length - ext.length);
13067
13217
  return `${base}-${suffix}${ext}`;
13068
13218
  }
@@ -13120,8 +13270,8 @@ var PRESETS = {
13120
13270
 
13121
13271
  // src/pdf/FailurePaginator.ts
13122
13272
  init_esm_shims();
13123
- import fs11 from "fs";
13124
- import path11 from "path";
13273
+ import fs13 from "fs";
13274
+ import path13 from "path";
13125
13275
  var FailurePaginator = class {
13126
13276
  async paginate(failures, maxInline, pdfOutputPath) {
13127
13277
  if (failures.length <= maxInline) {
@@ -13131,13 +13281,13 @@ var FailurePaginator = class {
13131
13281
  const overflow = failures.slice(maxInline);
13132
13282
  const sidecarPath = this.sidecarPathFor(pdfOutputPath);
13133
13283
  try {
13134
- await fs11.promises.writeFile(
13284
+ await fs13.promises.writeFile(
13135
13285
  sidecarPath,
13136
13286
  JSON.stringify(this.serialize(overflow), null, 2),
13137
13287
  "utf8"
13138
13288
  );
13139
13289
  logger.info(
13140
- `Emitted ${overflow.length} overflow failures \u2192 ${path11.basename(sidecarPath)}`
13290
+ `Emitted ${overflow.length} overflow failures \u2192 ${path13.basename(sidecarPath)}`
13141
13291
  );
13142
13292
  } catch (e) {
13143
13293
  logger.warn(`Could not write failure sidecar: ${e.message}`);
@@ -13146,9 +13296,9 @@ var FailurePaginator = class {
13146
13296
  return { inline, overflowCount: overflow.length, sidecarPath };
13147
13297
  }
13148
13298
  sidecarPathFor(pdfPath) {
13149
- const dir = path11.dirname(pdfPath);
13150
- const base = path11.basename(pdfPath, path11.extname(pdfPath));
13151
- return path11.join(dir, `${base}-failures.json`);
13299
+ const dir = path13.dirname(pdfPath);
13300
+ const base = path13.basename(pdfPath, path13.extname(pdfPath));
13301
+ return path13.join(dir, `${base}-failures.json`);
13152
13302
  }
13153
13303
  /**
13154
13304
  * Drops the inlined image bytes — a 150-entry overflow would otherwise
@@ -13227,7 +13377,7 @@ var PdfGenerator = class {
13227
13377
  const sources = this.resolveTemplateSources(options);
13228
13378
  const isMulti = sources.length > 1;
13229
13379
  for (const source of sources) {
13230
- if (source.kind === "custom" && !fs12.existsSync(source.absolutePath)) {
13380
+ if (source.kind === "custom" && !fs14.existsSync(source.absolutePath)) {
13231
13381
  throw new Error(
13232
13382
  `[reportforge] Custom template not found: ${source.absolutePath}`
13233
13383
  );
@@ -13264,7 +13414,7 @@ var PdfGenerator = class {
13264
13414
  await this.renderPdf(templateData, templateOptions, source, compression, outputPath, page);
13265
13415
  const capBytes = (options.maxFileSizeMb ?? 0) * 1024 * 1024;
13266
13416
  if (capBytes > 0) {
13267
- const sizeBytes = (await fs12.promises.stat(outputPath)).size;
13417
+ const sizeBytes = (await fs14.promises.stat(outputPath)).size;
13268
13418
  if (sizeBytes > capBytes) {
13269
13419
  const inlinedCount = Math.min(templateData.failures.length, compression.maxInlineFailures);
13270
13420
  const tighter = this.tightenForCap(compression, sizeBytes, capBytes, inlinedCount);
@@ -13272,7 +13422,7 @@ var PdfGenerator = class {
13272
13422
  `PDF size ${fmtMb(sizeBytes)} exceeds cap ${fmtMb(capBytes)} \u2014 re-rendering (jpeg-q=${tighter.quality}, max-w=${tighter.maxWidth}px, inline-failures\u2264${tighter.maxInlineFailures}).`
13273
13423
  );
13274
13424
  await this.renderPdf(templateData, templateOptions, source, tighter, outputPath, page);
13275
- const finalSize = (await fs12.promises.stat(outputPath)).size;
13425
+ const finalSize = (await fs14.promises.stat(outputPath)).size;
13276
13426
  if (finalSize > capBytes) {
13277
13427
  logger.warn(
13278
13428
  `PDF still ${fmtMb(finalSize)} after retune. Consider lowering maxInlineFailures or splitting the report.`
@@ -13285,7 +13435,7 @@ var PdfGenerator = class {
13285
13435
  if (options.pdfPassword) {
13286
13436
  await this.pdfEncryptor.encrypt(outputPath, options.pdfPassword);
13287
13437
  }
13288
- const finalSizeMb = fmtMb((await fs12.promises.stat(outputPath)).size);
13438
+ const finalSizeMb = fmtMb((await fs14.promises.stat(outputPath)).size);
13289
13439
  logger.info(`PDF report generated: ${outputPath} (${finalSizeMb})`);
13290
13440
  outputPaths.push(outputPath);
13291
13441
  }
@@ -13298,17 +13448,17 @@ var PdfGenerator = class {
13298
13448
  if (options.templatePath && options.templatePath.length > 0) {
13299
13449
  const byAbsolutePath = /* @__PURE__ */ new Map();
13300
13450
  for (const p of options.templatePath) {
13301
- const absolutePath = path12.isAbsolute(p) ? p : path12.resolve(process.cwd(), p);
13451
+ const absolutePath = path14.isAbsolute(p) ? p : path14.resolve(process.cwd(), p);
13302
13452
  if (!byAbsolutePath.has(absolutePath)) byAbsolutePath.set(absolutePath, p);
13303
13453
  }
13304
13454
  const labelCounts = /* @__PURE__ */ new Map();
13305
13455
  for (const rawPath of byAbsolutePath.values()) {
13306
- const label = path12.basename(rawPath, ".hbs");
13456
+ const label = path14.basename(rawPath, ".hbs");
13307
13457
  labelCounts.set(label, (labelCounts.get(label) ?? 0) + 1);
13308
13458
  }
13309
13459
  const seenPerLabel = /* @__PURE__ */ new Map();
13310
13460
  return Array.from(byAbsolutePath.entries()).map(([absolutePath, rawPath]) => {
13311
- const baseLabel = path12.basename(rawPath, ".hbs");
13461
+ const baseLabel = path14.basename(rawPath, ".hbs");
13312
13462
  let label = baseLabel;
13313
13463
  if ((labelCounts.get(baseLabel) ?? 0) > 1) {
13314
13464
  const n = (seenPerLabel.get(baseLabel) ?? 0) + 1;
@@ -13368,7 +13518,7 @@ var PdfGenerator = class {
13368
13518
  ...data,
13369
13519
  failures: paginated.inline,
13370
13520
  overflowFailureCount: paginated.overflowCount,
13371
- overflowSidecarName: paginated.sidecarPath ? path12.basename(paginated.sidecarPath) : void 0
13521
+ overflowSidecarName: paginated.sidecarPath ? path14.basename(paginated.sidecarPath) : void 0
13372
13522
  };
13373
13523
  for (const f of renderData.failures) f.screenshotBase64 = void 0;
13374
13524
  if (options.includeScreenshots !== false) {
@@ -13388,7 +13538,7 @@ var PdfGenerator = class {
13388
13538
  await page.goto(fileUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
13389
13539
  const showCharts = source.kind === "builtin" ? resolveSections(source.id, options.sections).charts : true;
13390
13540
  await this.chartRenderer.waitForCharts(page, showCharts);
13391
- logger.info(`Generating PDF \u2192 ${path12.relative(process.cwd(), outputPath)}`);
13541
+ logger.info(`Generating PDF \u2192 ${path14.relative(process.cwd(), outputPath)}`);
13392
13542
  await page.pdf({
13393
13543
  path: outputPath,
13394
13544
  format: "A4",
@@ -13405,19 +13555,19 @@ function fmtMb(bytes) {
13405
13555
  }
13406
13556
 
13407
13557
  // src/reporter.ts
13408
- import path14 from "path";
13558
+ import path16 from "path";
13409
13559
 
13410
13560
  // src/history/HistoryManager.ts
13411
13561
  init_esm_shims();
13412
- import fs13 from "fs";
13413
- import path13 from "path";
13562
+ import fs15 from "fs";
13563
+ import path15 from "path";
13414
13564
  var HistoryManager = class {
13415
13565
  constructor(filePath) {
13416
13566
  this.filePath = filePath;
13417
13567
  }
13418
13568
  read() {
13419
13569
  try {
13420
- const raw = fs13.readFileSync(this.filePath, "utf8");
13570
+ const raw = fs15.readFileSync(this.filePath, "utf8");
13421
13571
  const parsed = JSON.parse(raw);
13422
13572
  if (parsed.version !== 1) {
13423
13573
  logger.warn(`history.version-mismatch: path=${this.filePath} version=${String(parsed.version)}`);
@@ -13431,12 +13581,12 @@ var HistoryManager = class {
13431
13581
  }
13432
13582
  append(entry, maxSize) {
13433
13583
  try {
13434
- fs13.mkdirSync(path13.dirname(this.filePath), { recursive: true });
13584
+ fs15.mkdirSync(path15.dirname(this.filePath), { recursive: true });
13435
13585
  const next = {
13436
13586
  version: 1,
13437
13587
  entries: [entry, ...this.read()].slice(0, maxSize)
13438
13588
  };
13439
- fs13.writeFileSync(this.filePath, JSON.stringify(next, null, 2), { mode: 420 });
13589
+ fs15.writeFileSync(this.filePath, JSON.stringify(next, null, 2), { mode: 420 });
13440
13590
  return next.entries;
13441
13591
  } catch (err) {
13442
13592
  logger.warn(`history.write-failed: path=${this.filePath} error=${err.message}`);
@@ -14195,6 +14345,7 @@ function chunkToString2(chunk) {
14195
14345
 
14196
14346
  // src/reporter.ts
14197
14347
  var DEFAULT_SERVER_URL2 = "https://reportforge.org";
14348
+ var LICENSE_STALE_MARGIN_MS = 5 * 60 * 1e3;
14198
14349
  var PdfReporter = class {
14199
14350
  constructor(rawOptions = {}) {
14200
14351
  this.cwd = process.cwd();
@@ -14205,7 +14356,7 @@ var PdfReporter = class {
14205
14356
  this.options = parseOptions(rawOptions);
14206
14357
  setLogLevel(this.options.logLevel);
14207
14358
  this.dataCollector = new DataCollector(this.options.capture);
14208
- this.version = true ? "0.19.1" : "0.x";
14359
+ this.version = true ? "0.20.1" : "0.x";
14209
14360
  logger.info(`@reportforge/playwright-pdf v${this.version} initialised`);
14210
14361
  this.licenseClient = new LicenseClient({
14211
14362
  licenseKey: this.options.licenseKey,
@@ -14276,7 +14427,7 @@ var PdfReporter = class {
14276
14427
  }
14277
14428
  }
14278
14429
  async onEnd(result) {
14279
- const licenseInfo = await this.license();
14430
+ const licenseInfo = await this.freshLicense();
14280
14431
  if (!licenseInfo) return;
14281
14432
  const collected = this._collectData(result);
14282
14433
  if (!collected) {
@@ -14395,6 +14546,31 @@ var PdfReporter = class {
14395
14546
  license() {
14396
14547
  return this.licensePromise ?? (this.licensePromise = this.resolveLicense());
14397
14548
  }
14549
+ /**
14550
+ * onEnd entry point for licensing: the memoized resolution can be as old as
14551
+ * the whole run (it is shared with the live stream from onBegin), and a JWT
14552
+ * issued near the subscription's period end can expire MID-RUN while the
14553
+ * subscription itself renews and stays active — the exact case where the
14554
+ * admin dashboard shows "active" but generateAll's expiry gate would throw.
14555
+ * When the token is expired or about to be, re-resolve once: with < 24h TTL
14556
+ * the client always takes the network path, and its token_expired recovery
14557
+ * (clear cache → fresh activation) picks up the renewed period. A refresh
14558
+ * failure downgrades to the normal warn-and-skip, never a hard ERROR.
14559
+ */
14560
+ async freshLicense() {
14561
+ const info = await this.license();
14562
+ if (!info) return null;
14563
+ if (info.expiry.getTime() - Date.now() > LICENSE_STALE_MARGIN_MS) return info;
14564
+ logger.info("License token expired or is about to expire \u2014 refreshing before PDF generation...");
14565
+ this.licensePromise = this.resolveLicense();
14566
+ const refreshed = await this.licensePromise;
14567
+ if (!refreshed) {
14568
+ logger.warn(
14569
+ "License could not be refreshed after expiring mid-run \u2014 PDF generation is skipped. If your subscription is active, the next run will recover automatically."
14570
+ );
14571
+ }
14572
+ return refreshed;
14573
+ }
14398
14574
  async resolveLicense() {
14399
14575
  try {
14400
14576
  return await this.licenseClient.resolve(
@@ -14479,7 +14655,7 @@ var PdfReporter = class {
14479
14655
  }
14480
14656
  resolveProjectName() {
14481
14657
  try {
14482
- const pkgPath = path14.resolve(process.cwd(), "package.json");
14658
+ const pkgPath = path16.resolve(process.cwd(), "package.json");
14483
14659
  const pkg = __require(pkgPath);
14484
14660
  return pkg.name ?? "Playwright Tests";
14485
14661
  } catch {
@@ -14529,9 +14705,9 @@ function deriveVerdict(stats) {
14529
14705
  }
14530
14706
  function resolveHistoryPath(options, cwd) {
14531
14707
  if (options.historyFile) {
14532
- return path14.isAbsolute(options.historyFile) ? options.historyFile : path14.resolve(cwd, options.historyFile);
14708
+ return path16.isAbsolute(options.historyFile) ? options.historyFile : path16.resolve(cwd, options.historyFile);
14533
14709
  }
14534
- return path14.join(resolveProjectDir(options, cwd), "history.json");
14710
+ return path16.join(resolveProjectDir(options, cwd), "history.json");
14535
14711
  }
14536
14712
  function flattenSuiteNodes(suites) {
14537
14713
  return suites.flatMap((s) => [s, ...flattenSuiteNodes(s.suites)]);