claude-presentation-master 4.2.0 → 4.3.0

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.js CHANGED
@@ -243,9 +243,9 @@ function isFunction(value) {
243
243
  return typeof value === "function";
244
244
  }
245
245
  function createErrorClass(createImpl) {
246
- var _super = function(instance9) {
247
- Error.call(instance9);
248
- instance9.stack = new Error().stack;
246
+ var _super = function(instance10) {
247
+ Error.call(instance10);
248
+ instance10.stack = new Error().stack;
249
249
  };
250
250
  var ctorFunc = createImpl(_super);
251
251
  ctorFunc.prototype = Object.create(Error.prototype);
@@ -55351,7 +55351,7 @@ var require_util2 = __commonJS({
55351
55351
  return path13;
55352
55352
  }
55353
55353
  exports2.normalize = normalize2;
55354
- function join6(aRoot, aPath) {
55354
+ function join7(aRoot, aPath) {
55355
55355
  if (aRoot === "") {
55356
55356
  aRoot = ".";
55357
55357
  }
@@ -55383,7 +55383,7 @@ var require_util2 = __commonJS({
55383
55383
  }
55384
55384
  return joined;
55385
55385
  }
55386
- exports2.join = join6;
55386
+ exports2.join = join7;
55387
55387
  exports2.isAbsolute = function(aPath) {
55388
55388
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
55389
55389
  };
@@ -55556,7 +55556,7 @@ var require_util2 = __commonJS({
55556
55556
  parsed.path = parsed.path.substring(0, index + 1);
55557
55557
  }
55558
55558
  }
55559
- sourceURL = join6(urlGenerate(parsed), sourceURL);
55559
+ sourceURL = join7(urlGenerate(parsed), sourceURL);
55560
55560
  }
55561
55561
  return normalize2(sourceURL);
55562
55562
  }
@@ -57367,7 +57367,7 @@ var require_escodegen = __commonJS({
57367
57367
  function noEmptySpace() {
57368
57368
  return space ? space : " ";
57369
57369
  }
57370
- function join6(left2, right2) {
57370
+ function join7(left2, right2) {
57371
57371
  var leftSource, rightSource, leftCharCode, rightCharCode;
57372
57372
  leftSource = toSourceNodeWhenNeeded(left2).toString();
57373
57373
  if (leftSource.length === 0) {
@@ -57698,8 +57698,8 @@ var require_escodegen = __commonJS({
57698
57698
  } else {
57699
57699
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
57700
57700
  }
57701
- result = join6(result, operator);
57702
- result = [join6(
57701
+ result = join7(result, operator);
57702
+ result = [join7(
57703
57703
  result,
57704
57704
  that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
57705
57705
  ), ")"];
@@ -57842,11 +57842,11 @@ var require_escodegen = __commonJS({
57842
57842
  var result, fragment;
57843
57843
  result = ["class"];
57844
57844
  if (stmt.id) {
57845
- result = join6(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
57845
+ result = join7(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
57846
57846
  }
57847
57847
  if (stmt.superClass) {
57848
- fragment = join6("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
57849
- result = join6(result, fragment);
57848
+ fragment = join7("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
57849
+ result = join7(result, fragment);
57850
57850
  }
57851
57851
  result.push(space);
57852
57852
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -57859,9 +57859,9 @@ var require_escodegen = __commonJS({
57859
57859
  return escapeDirective(stmt.directive) + this.semicolon(flags);
57860
57860
  },
57861
57861
  DoWhileStatement: function(stmt, flags) {
57862
- var result = join6("do", this.maybeBlock(stmt.body, S_TFFF));
57862
+ var result = join7("do", this.maybeBlock(stmt.body, S_TFFF));
57863
57863
  result = this.maybeBlockSuffix(stmt.body, result);
57864
- return join6(result, [
57864
+ return join7(result, [
57865
57865
  "while" + space + "(",
57866
57866
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
57867
57867
  ")" + this.semicolon(flags)
@@ -57897,11 +57897,11 @@ var require_escodegen = __commonJS({
57897
57897
  ExportDefaultDeclaration: function(stmt, flags) {
57898
57898
  var result = ["export"], bodyFlags;
57899
57899
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
57900
- result = join6(result, "default");
57900
+ result = join7(result, "default");
57901
57901
  if (isStatement(stmt.declaration)) {
57902
- result = join6(result, this.generateStatement(stmt.declaration, bodyFlags));
57902
+ result = join7(result, this.generateStatement(stmt.declaration, bodyFlags));
57903
57903
  } else {
57904
- result = join6(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
57904
+ result = join7(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
57905
57905
  }
57906
57906
  return result;
57907
57907
  },
@@ -57909,15 +57909,15 @@ var require_escodegen = __commonJS({
57909
57909
  var result = ["export"], bodyFlags, that = this;
57910
57910
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
57911
57911
  if (stmt.declaration) {
57912
- return join6(result, this.generateStatement(stmt.declaration, bodyFlags));
57912
+ return join7(result, this.generateStatement(stmt.declaration, bodyFlags));
57913
57913
  }
57914
57914
  if (stmt.specifiers) {
57915
57915
  if (stmt.specifiers.length === 0) {
57916
- result = join6(result, "{" + space + "}");
57916
+ result = join7(result, "{" + space + "}");
57917
57917
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
57918
- result = join6(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
57918
+ result = join7(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
57919
57919
  } else {
57920
- result = join6(result, "{");
57920
+ result = join7(result, "{");
57921
57921
  withIndent(function(indent2) {
57922
57922
  var i, iz;
57923
57923
  result.push(newline);
@@ -57935,7 +57935,7 @@ var require_escodegen = __commonJS({
57935
57935
  result.push(base + "}");
57936
57936
  }
57937
57937
  if (stmt.source) {
57938
- result = join6(result, [
57938
+ result = join7(result, [
57939
57939
  "from" + space,
57940
57940
  // ModuleSpecifier
57941
57941
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -58023,7 +58023,7 @@ var require_escodegen = __commonJS({
58023
58023
  ];
58024
58024
  cursor = 0;
58025
58025
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
58026
- result = join6(result, [
58026
+ result = join7(result, [
58027
58027
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
58028
58028
  ]);
58029
58029
  ++cursor;
@@ -58033,7 +58033,7 @@ var require_escodegen = __commonJS({
58033
58033
  result.push(",");
58034
58034
  }
58035
58035
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
58036
- result = join6(result, [
58036
+ result = join7(result, [
58037
58037
  space,
58038
58038
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
58039
58039
  ]);
@@ -58062,7 +58062,7 @@ var require_escodegen = __commonJS({
58062
58062
  }
58063
58063
  }
58064
58064
  }
58065
- result = join6(result, [
58065
+ result = join7(result, [
58066
58066
  "from" + space,
58067
58067
  // ModuleSpecifier
58068
58068
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -58116,7 +58116,7 @@ var require_escodegen = __commonJS({
58116
58116
  return result;
58117
58117
  },
58118
58118
  ThrowStatement: function(stmt, flags) {
58119
- return [join6(
58119
+ return [join7(
58120
58120
  "throw",
58121
58121
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
58122
58122
  ), this.semicolon(flags)];
@@ -58127,7 +58127,7 @@ var require_escodegen = __commonJS({
58127
58127
  result = this.maybeBlockSuffix(stmt.block, result);
58128
58128
  if (stmt.handlers) {
58129
58129
  for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
58130
- result = join6(result, this.generateStatement(stmt.handlers[i], S_TFFF));
58130
+ result = join7(result, this.generateStatement(stmt.handlers[i], S_TFFF));
58131
58131
  if (stmt.finalizer || i + 1 !== iz) {
58132
58132
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
58133
58133
  }
@@ -58135,7 +58135,7 @@ var require_escodegen = __commonJS({
58135
58135
  } else {
58136
58136
  guardedHandlers = stmt.guardedHandlers || [];
58137
58137
  for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
58138
- result = join6(result, this.generateStatement(guardedHandlers[i], S_TFFF));
58138
+ result = join7(result, this.generateStatement(guardedHandlers[i], S_TFFF));
58139
58139
  if (stmt.finalizer || i + 1 !== iz) {
58140
58140
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
58141
58141
  }
@@ -58143,13 +58143,13 @@ var require_escodegen = __commonJS({
58143
58143
  if (stmt.handler) {
58144
58144
  if (Array.isArray(stmt.handler)) {
58145
58145
  for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
58146
- result = join6(result, this.generateStatement(stmt.handler[i], S_TFFF));
58146
+ result = join7(result, this.generateStatement(stmt.handler[i], S_TFFF));
58147
58147
  if (stmt.finalizer || i + 1 !== iz) {
58148
58148
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
58149
58149
  }
58150
58150
  }
58151
58151
  } else {
58152
- result = join6(result, this.generateStatement(stmt.handler, S_TFFF));
58152
+ result = join7(result, this.generateStatement(stmt.handler, S_TFFF));
58153
58153
  if (stmt.finalizer) {
58154
58154
  result = this.maybeBlockSuffix(stmt.handler.body, result);
58155
58155
  }
@@ -58157,7 +58157,7 @@ var require_escodegen = __commonJS({
58157
58157
  }
58158
58158
  }
58159
58159
  if (stmt.finalizer) {
58160
- result = join6(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
58160
+ result = join7(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
58161
58161
  }
58162
58162
  return result;
58163
58163
  },
@@ -58191,7 +58191,7 @@ var require_escodegen = __commonJS({
58191
58191
  withIndent(function() {
58192
58192
  if (stmt.test) {
58193
58193
  result = [
58194
- join6("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
58194
+ join7("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
58195
58195
  ":"
58196
58196
  ];
58197
58197
  } else {
@@ -58239,9 +58239,9 @@ var require_escodegen = __commonJS({
58239
58239
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
58240
58240
  result = this.maybeBlockSuffix(stmt.consequent, result);
58241
58241
  if (stmt.alternate.type === Syntax.IfStatement) {
58242
- result = join6(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
58242
+ result = join7(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
58243
58243
  } else {
58244
- result = join6(result, join6("else", this.maybeBlock(stmt.alternate, bodyFlags)));
58244
+ result = join7(result, join7("else", this.maybeBlock(stmt.alternate, bodyFlags)));
58245
58245
  }
58246
58246
  } else {
58247
58247
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -58342,7 +58342,7 @@ var require_escodegen = __commonJS({
58342
58342
  },
58343
58343
  ReturnStatement: function(stmt, flags) {
58344
58344
  if (stmt.argument) {
58345
- return [join6(
58345
+ return [join7(
58346
58346
  "return",
58347
58347
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
58348
58348
  ), this.semicolon(flags)];
@@ -58431,14 +58431,14 @@ var require_escodegen = __commonJS({
58431
58431
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
58432
58432
  result = [fragment, noEmptySpace(), expr.operator];
58433
58433
  } else {
58434
- result = join6(fragment, expr.operator);
58434
+ result = join7(fragment, expr.operator);
58435
58435
  }
58436
58436
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
58437
58437
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
58438
58438
  result.push(noEmptySpace());
58439
58439
  result.push(fragment);
58440
58440
  } else {
58441
- result = join6(result, fragment);
58441
+ result = join7(result, fragment);
58442
58442
  }
58443
58443
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
58444
58444
  return ["(", result, ")"];
@@ -58478,7 +58478,7 @@ var require_escodegen = __commonJS({
58478
58478
  var result, length, i, iz, itemFlags;
58479
58479
  length = expr["arguments"].length;
58480
58480
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
58481
- result = join6(
58481
+ result = join7(
58482
58482
  "new",
58483
58483
  this.generateExpression(expr.callee, Precedence.New, itemFlags)
58484
58484
  );
@@ -58528,11 +58528,11 @@ var require_escodegen = __commonJS({
58528
58528
  var result, fragment, rightCharCode, leftSource, leftCharCode;
58529
58529
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
58530
58530
  if (space === "") {
58531
- result = join6(expr.operator, fragment);
58531
+ result = join7(expr.operator, fragment);
58532
58532
  } else {
58533
58533
  result = [expr.operator];
58534
58534
  if (expr.operator.length > 2) {
58535
- result = join6(result, fragment);
58535
+ result = join7(result, fragment);
58536
58536
  } else {
58537
58537
  leftSource = toSourceNodeWhenNeeded(result).toString();
58538
58538
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -58555,7 +58555,7 @@ var require_escodegen = __commonJS({
58555
58555
  result = "yield";
58556
58556
  }
58557
58557
  if (expr.argument) {
58558
- result = join6(
58558
+ result = join7(
58559
58559
  result,
58560
58560
  this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
58561
58561
  );
@@ -58563,7 +58563,7 @@ var require_escodegen = __commonJS({
58563
58563
  return parenthesize(result, Precedence.Yield, precedence);
58564
58564
  },
58565
58565
  AwaitExpression: function(expr, precedence, flags) {
58566
- var result = join6(
58566
+ var result = join7(
58567
58567
  expr.all ? "await*" : "await",
58568
58568
  this.generateExpression(expr.argument, Precedence.Await, E_TTT)
58569
58569
  );
@@ -58646,11 +58646,11 @@ var require_escodegen = __commonJS({
58646
58646
  var result, fragment;
58647
58647
  result = ["class"];
58648
58648
  if (expr.id) {
58649
- result = join6(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
58649
+ result = join7(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
58650
58650
  }
58651
58651
  if (expr.superClass) {
58652
- fragment = join6("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
58653
- result = join6(result, fragment);
58652
+ fragment = join7("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
58653
+ result = join7(result, fragment);
58654
58654
  }
58655
58655
  result.push(space);
58656
58656
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -58665,7 +58665,7 @@ var require_escodegen = __commonJS({
58665
58665
  }
58666
58666
  if (expr.kind === "get" || expr.kind === "set") {
58667
58667
  fragment = [
58668
- join6(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
58668
+ join7(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
58669
58669
  this.generateFunctionBody(expr.value)
58670
58670
  ];
58671
58671
  } else {
@@ -58675,7 +58675,7 @@ var require_escodegen = __commonJS({
58675
58675
  this.generateFunctionBody(expr.value)
58676
58676
  ];
58677
58677
  }
58678
- return join6(result, fragment);
58678
+ return join7(result, fragment);
58679
58679
  },
58680
58680
  Property: function(expr, precedence, flags) {
58681
58681
  if (expr.kind === "get" || expr.kind === "set") {
@@ -58870,7 +58870,7 @@ var require_escodegen = __commonJS({
58870
58870
  for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
58871
58871
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
58872
58872
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
58873
- result = join6(result, fragment);
58873
+ result = join7(result, fragment);
58874
58874
  } else {
58875
58875
  result.push(fragment);
58876
58876
  }
@@ -58878,13 +58878,13 @@ var require_escodegen = __commonJS({
58878
58878
  });
58879
58879
  }
58880
58880
  if (expr.filter) {
58881
- result = join6(result, "if" + space);
58881
+ result = join7(result, "if" + space);
58882
58882
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
58883
- result = join6(result, ["(", fragment, ")"]);
58883
+ result = join7(result, ["(", fragment, ")"]);
58884
58884
  }
58885
58885
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
58886
58886
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
58887
- result = join6(result, fragment);
58887
+ result = join7(result, fragment);
58888
58888
  }
58889
58889
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
58890
58890
  return result;
@@ -58900,8 +58900,8 @@ var require_escodegen = __commonJS({
58900
58900
  } else {
58901
58901
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
58902
58902
  }
58903
- fragment = join6(fragment, expr.of ? "of" : "in");
58904
- fragment = join6(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
58903
+ fragment = join7(fragment, expr.of ? "of" : "in");
58904
+ fragment = join7(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
58905
58905
  return ["for" + space + "(", fragment, ")"];
58906
58906
  },
58907
58907
  SpreadElement: function(expr, precedence, flags) {
@@ -72706,9 +72706,9 @@ var require_dist9 = __commonJS({
72706
72706
  var singleton = void 0;
72707
72707
  var singletonPromise = void 0;
72708
72708
  async function getQuickJS() {
72709
- singletonPromise ?? (singletonPromise = (0, variants_1.newQuickJSWASMModule)().then((instance9) => {
72710
- singleton = instance9;
72711
- return instance9;
72709
+ singletonPromise ?? (singletonPromise = (0, variants_1.newQuickJSWASMModule)().then((instance10) => {
72710
+ singleton = instance10;
72711
+ return instance10;
72712
72712
  }));
72713
72713
  return await singletonPromise;
72714
72714
  }
@@ -84924,9 +84924,9 @@ async function getConnectionTransport(options) {
84924
84924
  throw new Error("Could not detect required browser platform");
84925
84925
  }
84926
84926
  const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel2 } = await Promise.resolve().then(() => (init_LaunchOptions(), LaunchOptions_exports));
84927
- const { join: join6 } = await import("path");
84927
+ const { join: join7 } = await import("path");
84928
84928
  const userDataDir = resolveDefaultUserDataDir3(Browser4.CHROME, platform, convertPuppeteerChannelToBrowsersChannel2(options.channel));
84929
- const portPath = join6(userDataDir, "DevToolsActivePort");
84929
+ const portPath = join7(userDataDir, "DevToolsActivePort");
84930
84930
  try {
84931
84931
  const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
84932
84932
  const [rawPort, rawPath] = fileContent.split("\n").map((line) => {
@@ -90544,7 +90544,7 @@ var require_env_paths = __commonJS({
90544
90544
  var path13 = require("path");
90545
90545
  var os9 = require("os");
90546
90546
  var homedir2 = os9.homedir();
90547
- var tmpdir2 = os9.tmpdir();
90547
+ var tmpdir3 = os9.tmpdir();
90548
90548
  var { env: env2 } = process;
90549
90549
  var macos = (name) => {
90550
90550
  const library = path13.join(homedir2, "Library");
@@ -90553,7 +90553,7 @@ var require_env_paths = __commonJS({
90553
90553
  config: path13.join(library, "Preferences", name),
90554
90554
  cache: path13.join(library, "Caches", name),
90555
90555
  log: path13.join(library, "Logs", name),
90556
- temp: path13.join(tmpdir2, name)
90556
+ temp: path13.join(tmpdir3, name)
90557
90557
  };
90558
90558
  };
90559
90559
  var windows = (name) => {
@@ -90565,7 +90565,7 @@ var require_env_paths = __commonJS({
90565
90565
  config: path13.join(appData, name, "Config"),
90566
90566
  cache: path13.join(localAppData, name, "Cache"),
90567
90567
  log: path13.join(localAppData, name, "Log"),
90568
- temp: path13.join(tmpdir2, name)
90568
+ temp: path13.join(tmpdir3, name)
90569
90569
  };
90570
90570
  };
90571
90571
  var linux = (name) => {
@@ -90576,7 +90576,7 @@ var require_env_paths = __commonJS({
90576
90576
  cache: path13.join(env2.XDG_CACHE_HOME || path13.join(homedir2, ".cache"), name),
90577
90577
  // https://wiki.debian.org/XDGBaseDirectorySpecification#state
90578
90578
  log: path13.join(env2.XDG_STATE_HOME || path13.join(homedir2, ".local", "state"), name),
90579
- temp: path13.join(tmpdir2, username, name)
90579
+ temp: path13.join(tmpdir3, username, name)
90580
90580
  };
90581
90581
  };
90582
90582
  var envPaths = (name, options) => {
@@ -91688,6 +91688,7 @@ __export(index_exports, {
91688
91688
  SlideQualityReviewer: () => SlideQualityReviewer,
91689
91689
  VERSION: () => VERSION,
91690
91690
  VisualDesignSystem: () => VisualDesignSystem,
91691
+ VisualQAEngine: () => VisualQAEngine,
91691
91692
  createNanoBananaProvider: () => createNanoBananaProvider,
91692
91693
  createPresentationEngineV2: () => createPresentationEngineV2,
91693
91694
  createRendererV2: () => createRendererV2,
@@ -91703,6 +91704,7 @@ __export(index_exports, {
91703
91704
  getSlideGenerator: () => getSlideGenerator,
91704
91705
  getSlideQualityReviewer: () => getSlideQualityReviewer,
91705
91706
  getVisualDesignSystem: () => getVisualDesignSystem,
91707
+ getVisualQAEngine: () => getVisualQAEngine,
91706
91708
  initContentAnalyzer: () => initContentAnalyzer,
91707
91709
  initDeckQualityReviewer: () => initDeckQualityReviewer,
91708
91710
  initKB: () => initKB,
@@ -91711,6 +91713,7 @@ __export(index_exports, {
91711
91713
  initSlideGenerator: () => initSlideGenerator,
91712
91714
  initSlideQualityReviewer: () => initSlideQualityReviewer,
91713
91715
  initVisualDesignSystem: () => initVisualDesignSystem,
91716
+ initVisualQAEngine: () => initVisualQAEngine,
91714
91717
  runCodeQualityCheck: () => runCodeQualityCheck,
91715
91718
  validateCodeQuality: () => validateCodeQuality
91716
91719
  });
@@ -95098,6 +95101,7 @@ ${content}
95098
95101
  --accent-red: #dc3545;
95099
95102
  --border-color: ${isLight ? "#dee2e6" : "rgba(255,255,255,0.1)"};
95100
95103
  --header-bar: ${p.primary};
95104
+ --mckinsey-blue: ${p.accent};
95101
95105
  }`;
95102
95106
  }
95103
95107
  /**
@@ -95606,8 +95610,615 @@ function createRendererV2(presentationType = "consulting_deck", kb) {
95606
95610
  return new RendererV2(presentationType, kb);
95607
95611
  }
95608
95612
 
95609
- // src/core/PresentationEngineV2.ts
95613
+ // src/qa/VisualQAEngine.ts
95610
95614
  var import_fs9 = require("fs");
95615
+ var import_path6 = require("path");
95616
+ var import_os = require("os");
95617
+ var VisualQAEngine = class {
95618
+ kb;
95619
+ browser = null;
95620
+ initialized = false;
95621
+ // KB-loaded thresholds
95622
+ minWhitespace = 0.35;
95623
+ minContrast = 4.5;
95624
+ // WCAG AA
95625
+ maxWordsPerSlide = 50;
95626
+ targetScore = 95;
95627
+ constructor() {
95628
+ this.kb = getKB();
95629
+ }
95630
+ /**
95631
+ * Initialize Playwright browser.
95632
+ */
95633
+ async initialize() {
95634
+ if (this.initialized) return;
95635
+ const playwright = await import("playwright");
95636
+ this.browser = await playwright.chromium.launch({
95637
+ headless: true,
95638
+ args: ["--no-sandbox", "--disable-setuid-sandbox"]
95639
+ });
95640
+ await this.loadKBThresholds();
95641
+ this.initialized = true;
95642
+ console.log("[VisualQA] Initialized with Playwright");
95643
+ }
95644
+ /**
95645
+ * Load quality thresholds from Knowledge Base.
95646
+ */
95647
+ async loadKBThresholds() {
95648
+ try {
95649
+ const whitespaceResult = this.kb.queryOptional("design_system.whitespace_rules");
95650
+ if (whitespaceResult.value?.min) {
95651
+ this.minWhitespace = whitespaceResult.value.min;
95652
+ }
95653
+ } catch {
95654
+ }
95655
+ }
95656
+ /**
95657
+ * Capture screenshots of all slides in a presentation.
95658
+ */
95659
+ async captureSlides(html) {
95660
+ await this.initialize();
95661
+ if (!this.browser) throw new Error("Browser not initialized");
95662
+ const tempDir = (0, import_fs9.mkdtempSync)((0, import_path6.join)((0, import_os.tmpdir)(), "visual-qa-"));
95663
+ const tempFile = (0, import_path6.join)(tempDir, "presentation.html");
95664
+ const modifiedHtml = html.replace(
95665
+ /hash:\s*true/g,
95666
+ "hash: false"
95667
+ );
95668
+ (0, import_fs9.writeFileSync)(tempFile, modifiedHtml);
95669
+ const page = await this.browser.newPage();
95670
+ await page.setViewportSize({ width: 1920, height: 1080 });
95671
+ await page.goto(`file://${tempFile}`, { waitUntil: "networkidle" });
95672
+ await page.waitForTimeout(1500);
95673
+ const slideCount = await page.evaluate(() => {
95674
+ const reveal = window.Reveal;
95675
+ if (reveal) {
95676
+ return reveal.getTotalSlides();
95677
+ }
95678
+ return document.querySelectorAll(".slides > section").length;
95679
+ });
95680
+ console.log(`[VisualQA] Capturing ${slideCount} slides...`);
95681
+ const screenshots = [];
95682
+ for (let i = 0; i < slideCount; i++) {
95683
+ await page.evaluate((index) => {
95684
+ const reveal = window.Reveal;
95685
+ if (reveal) {
95686
+ reveal.slide(index, 0, 0);
95687
+ }
95688
+ }, i);
95689
+ await page.waitForTimeout(400);
95690
+ const screenshot = await page.screenshot({
95691
+ type: "png",
95692
+ fullPage: false
95693
+ });
95694
+ screenshots.push(screenshot);
95695
+ console.log(`[VisualQA] Captured slide ${i + 1}/${slideCount}`);
95696
+ }
95697
+ await page.close();
95698
+ try {
95699
+ (0, import_fs9.unlinkSync)(tempFile);
95700
+ } catch {
95701
+ }
95702
+ return screenshots;
95703
+ }
95704
+ /**
95705
+ * Analyze a single slide screenshot.
95706
+ */
95707
+ async analyzeSlide(screenshot, slideIndex, slideTitle, presentationType) {
95708
+ const issues = [];
95709
+ let score = 100;
95710
+ const typeThresholds = this.getTypeThresholds(presentationType);
95711
+ const whitespacePercentage = await this.measureWhitespace(screenshot);
95712
+ if (whitespacePercentage < typeThresholds.minWhitespace) {
95713
+ const penalty = Math.round((typeThresholds.minWhitespace - whitespacePercentage) * 100);
95714
+ score -= penalty;
95715
+ issues.push({
95716
+ severity: penalty > 15 ? "critical" : "major",
95717
+ category: "whitespace",
95718
+ issue: `Whitespace is ${(whitespacePercentage * 100).toFixed(1)}% (need ${typeThresholds.minWhitespace * 100}%+)`,
95719
+ measurement: whitespacePercentage,
95720
+ threshold: typeThresholds.minWhitespace,
95721
+ fix: "Reduce content or increase margins"
95722
+ });
95723
+ }
95724
+ const colorContrast = await this.measureContrast(screenshot);
95725
+ if (colorContrast < this.minContrast) {
95726
+ score -= 20;
95727
+ issues.push({
95728
+ severity: "critical",
95729
+ category: "contrast",
95730
+ issue: `Contrast ratio is ${colorContrast.toFixed(1)}:1 (WCAG AA requires 4.5:1)`,
95731
+ measurement: colorContrast,
95732
+ threshold: this.minContrast,
95733
+ fix: "Increase contrast between text and background"
95734
+ });
95735
+ }
95736
+ const textDensity = await this.measureTextDensity(screenshot);
95737
+ const maxDensity = typeThresholds.maxWordsPerSlide / 100;
95738
+ if (textDensity > maxDensity) {
95739
+ score -= 15;
95740
+ issues.push({
95741
+ severity: "major",
95742
+ category: "density",
95743
+ issue: `Text is too dense for ${presentationType}`,
95744
+ measurement: textDensity,
95745
+ threshold: maxDensity,
95746
+ fix: "Split content across multiple slides"
95747
+ });
95748
+ }
95749
+ const visualBalance = await this.measureBalance(screenshot);
95750
+ const balanceThreshold = ["ted_keynote", "sales_pitch"].includes(presentationType) ? 20 : 60;
95751
+ if (visualBalance < balanceThreshold) {
95752
+ score -= 10;
95753
+ issues.push({
95754
+ severity: "minor",
95755
+ category: "balance",
95756
+ issue: `Visual balance score is ${visualBalance}/100`,
95757
+ measurement: visualBalance,
95758
+ threshold: balanceThreshold,
95759
+ fix: "Redistribute content for better visual balance"
95760
+ });
95761
+ }
95762
+ const hierarchyClear = await this.checkHierarchy(screenshot);
95763
+ if (!hierarchyClear) {
95764
+ score -= 10;
95765
+ issues.push({
95766
+ severity: "major",
95767
+ category: "hierarchy",
95768
+ issue: "No clear visual hierarchy detected",
95769
+ fix: "Add distinct title styling or increase heading size"
95770
+ });
95771
+ }
95772
+ const glanceTestPassed = textDensity < 0.3 && hierarchyClear;
95773
+ if (!glanceTestPassed && presentationType !== "investment_banking") {
95774
+ score -= 10;
95775
+ issues.push({
95776
+ severity: "major",
95777
+ category: "density",
95778
+ issue: "Fails 3-second glance test",
95779
+ fix: "Simplify to one clear message per slide"
95780
+ });
95781
+ }
95782
+ const minBalanceForPro = ["ted_keynote", "sales_pitch"].includes(presentationType) ? 20 : 50;
95783
+ const professionalLook = whitespacePercentage >= typeThresholds.minWhitespace * 0.9 && colorContrast >= this.minContrast * 0.9 && visualBalance >= minBalanceForPro;
95784
+ if (!professionalLook) {
95785
+ score -= 5;
95786
+ issues.push({
95787
+ severity: "minor",
95788
+ category: "professional",
95789
+ issue: "Slide lacks professional polish",
95790
+ fix: "Review spacing, colors, and alignment"
95791
+ });
95792
+ }
95793
+ return {
95794
+ slideIndex,
95795
+ title: slideTitle,
95796
+ screenshot,
95797
+ whitespacePercentage,
95798
+ textDensity,
95799
+ colorContrast,
95800
+ visualBalance,
95801
+ glanceTestPassed,
95802
+ hierarchyClear,
95803
+ professionalLook,
95804
+ score: Math.max(0, Math.min(100, score)),
95805
+ issues,
95806
+ passed: score >= this.targetScore
95807
+ };
95808
+ }
95809
+ /**
95810
+ * Analyze entire deck visually.
95811
+ */
95812
+ async analyzeDeck(html, slides, presentationType) {
95813
+ console.log(`[VisualQA] Starting visual analysis of ${slides.length} slides...`);
95814
+ const screenshots = await this.captureSlides(html);
95815
+ const slideAnalyses = [];
95816
+ for (let i = 0; i < screenshots.length; i++) {
95817
+ const slide = slides[i];
95818
+ const analysis = await this.analyzeSlide(
95819
+ screenshots[i],
95820
+ i,
95821
+ slide?.title || `Slide ${i + 1}`,
95822
+ presentationType
95823
+ );
95824
+ slideAnalyses.push(analysis);
95825
+ console.log(`[VisualQA] Slide ${i + 1}: ${analysis.score}/100 ${analysis.passed ? "\u2713" : "\u2717"}`);
95826
+ }
95827
+ const consistency = this.calculateConsistency(slideAnalyses);
95828
+ const deckIssues = [];
95829
+ const failingSlides = slideAnalyses.filter((s) => !s.passed);
95830
+ if (failingSlides.length > 0) {
95831
+ deckIssues.push(`${failingSlides.length} slides below quality threshold`);
95832
+ }
95833
+ if (consistency < 80) {
95834
+ deckIssues.push(`Visual inconsistency across slides (${consistency}/100)`);
95835
+ }
95836
+ const avgScore = slideAnalyses.reduce((sum, s) => sum + s.score, 0) / slideAnalyses.length;
95837
+ const consistencyBonus = consistency >= 90 ? 2 : consistency >= 80 ? 0 : -3;
95838
+ const overallScore = Math.round(Math.min(100, Math.max(0, avgScore + consistencyBonus)));
95839
+ const passed = overallScore >= this.targetScore && failingSlides.length === 0;
95840
+ const summary = passed ? `\u2705 Visual QA PASSED: ${overallScore}/100 with ${consistency}% consistency` : `\u274C Visual QA FAILED: ${overallScore}/100, ${failingSlides.length} slides need work`;
95841
+ console.log(`[VisualQA] ${summary}`);
95842
+ return {
95843
+ slides: slideAnalyses,
95844
+ overallScore,
95845
+ passed,
95846
+ consistency,
95847
+ deckIssues,
95848
+ summary
95849
+ };
95850
+ }
95851
+ /**
95852
+ * Generate remediation feedback for failing slides.
95853
+ */
95854
+ generateRemediationFeedback(analysis) {
95855
+ const feedback = [];
95856
+ for (const slide of analysis.slides) {
95857
+ if (!slide.passed) {
95858
+ const fixes = [];
95859
+ const problems = [];
95860
+ for (const issue of slide.issues) {
95861
+ problems.push(issue.issue);
95862
+ fixes.push(issue.fix);
95863
+ }
95864
+ feedback.push({
95865
+ slideIndex: slide.slideIndex,
95866
+ currentScore: slide.score,
95867
+ targetScore: this.targetScore,
95868
+ specificFixes: fixes,
95869
+ visualProblems: problems
95870
+ });
95871
+ }
95872
+ }
95873
+ return feedback;
95874
+ }
95875
+ /**
95876
+ * Run the full QA loop until passing or max iterations.
95877
+ */
95878
+ async runQALoop(generateFn, remediateFn, presentationType, maxIterations = 3) {
95879
+ console.log(`[VisualQA] Starting QA loop (max ${maxIterations} iterations)...`);
95880
+ let iteration = 0;
95881
+ let currentAnalysis = null;
95882
+ let initialScore = 0;
95883
+ const improvements = [];
95884
+ while (iteration < maxIterations) {
95885
+ iteration++;
95886
+ console.log(`
95887
+ [VisualQA] === Iteration ${iteration} ===`);
95888
+ const { html, slides } = await generateFn();
95889
+ currentAnalysis = await this.analyzeDeck(html, slides, presentationType);
95890
+ if (iteration === 1) {
95891
+ initialScore = currentAnalysis.overallScore;
95892
+ }
95893
+ if (currentAnalysis.passed) {
95894
+ console.log(`[VisualQA] \u2705 PASSED on iteration ${iteration}!`);
95895
+ break;
95896
+ }
95897
+ const feedback = this.generateRemediationFeedback(currentAnalysis);
95898
+ console.log(`[VisualQA] ${feedback.length} slides need remediation`);
95899
+ for (const fb of feedback) {
95900
+ console.log(` Slide ${fb.slideIndex + 1}: ${fb.currentScore}\u2192${fb.targetScore}`);
95901
+ for (const fix of fb.specificFixes.slice(0, 2)) {
95902
+ console.log(` - ${fix}`);
95903
+ }
95904
+ }
95905
+ improvements.push(`Iteration ${iteration}: ${currentAnalysis.overallScore}/100`);
95906
+ if (iteration < maxIterations) {
95907
+ await remediateFn(feedback);
95908
+ }
95909
+ }
95910
+ if (!currentAnalysis) {
95911
+ throw new Error("No analysis performed");
95912
+ }
95913
+ return {
95914
+ finalScore: currentAnalysis.overallScore,
95915
+ passed: currentAnalysis.passed,
95916
+ iterations: iteration,
95917
+ initialScore,
95918
+ improvements,
95919
+ finalAnalysis: currentAnalysis
95920
+ };
95921
+ }
95922
+ /**
95923
+ * Close browser and cleanup.
95924
+ */
95925
+ async cleanup() {
95926
+ if (this.browser) {
95927
+ await this.browser.close();
95928
+ this.browser = null;
95929
+ this.initialized = false;
95930
+ }
95931
+ }
95932
+ // =============================================================================
95933
+ // PIXEL ANALYSIS METHODS
95934
+ // =============================================================================
95935
+ /**
95936
+ * Measure whitespace percentage from screenshot.
95937
+ * Uses actual pixel analysis.
95938
+ */
95939
+ async measureWhitespace(screenshot) {
95940
+ try {
95941
+ const sharp = await import("sharp");
95942
+ const image = sharp.default(screenshot);
95943
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
95944
+ const totalPixels = info.width * info.height;
95945
+ let backgroundPixels = 0;
95946
+ const bgColor = this.detectBackgroundColor(data, info.width, info.height, info.channels);
95947
+ for (let i = 0; i < data.length; i += info.channels) {
95948
+ const r = data[i];
95949
+ const g = data[i + 1];
95950
+ const b = data[i + 2];
95951
+ if (this.isSimilarColor(r, g, b, bgColor.r, bgColor.g, bgColor.b, 30)) {
95952
+ backgroundPixels++;
95953
+ }
95954
+ }
95955
+ return backgroundPixels / totalPixels;
95956
+ } catch {
95957
+ return 0.4;
95958
+ }
95959
+ }
95960
+ /**
95961
+ * Measure color contrast ratio.
95962
+ */
95963
+ async measureContrast(screenshot) {
95964
+ try {
95965
+ const sharp = await import("sharp");
95966
+ const image = sharp.default(screenshot);
95967
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
95968
+ const bgColor = this.detectBackgroundColor(data, info.width, info.height, info.channels);
95969
+ const textColor = this.detectTextColor(data, info.width, info.height, info.channels, bgColor);
95970
+ const bgLuminance = this.relativeLuminance(bgColor.r, bgColor.g, bgColor.b);
95971
+ const textLuminance = this.relativeLuminance(textColor.r, textColor.g, textColor.b);
95972
+ const lighter = Math.max(bgLuminance, textLuminance);
95973
+ const darker = Math.min(bgLuminance, textLuminance);
95974
+ return (lighter + 0.05) / (darker + 0.05);
95975
+ } catch {
95976
+ return 7;
95977
+ }
95978
+ }
95979
+ /**
95980
+ * Measure text density (approximation based on non-background pixels).
95981
+ */
95982
+ async measureTextDensity(screenshot) {
95983
+ try {
95984
+ const sharp = await import("sharp");
95985
+ const image = sharp.default(screenshot);
95986
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
95987
+ const bgColor = this.detectBackgroundColor(data, info.width, info.height, info.channels);
95988
+ let contentPixels = 0;
95989
+ const totalPixels = info.width * info.height;
95990
+ for (let i = 0; i < data.length; i += info.channels) {
95991
+ const r = data[i];
95992
+ const g = data[i + 1];
95993
+ const b = data[i + 2];
95994
+ if (!this.isSimilarColor(r, g, b, bgColor.r, bgColor.g, bgColor.b, 30)) {
95995
+ contentPixels++;
95996
+ }
95997
+ }
95998
+ return contentPixels / totalPixels;
95999
+ } catch {
96000
+ return 0.2;
96001
+ }
96002
+ }
96003
+ /**
96004
+ * Measure visual balance (how evenly distributed is the content).
96005
+ * Uses a 3x3 grid to properly detect centered layouts (common in keynotes).
96006
+ */
96007
+ async measureBalance(screenshot) {
96008
+ try {
96009
+ const sharp = await import("sharp");
96010
+ const image = sharp.default(screenshot);
96011
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
96012
+ const bgColor = this.detectBackgroundColor(data, info.width, info.height, info.channels);
96013
+ const grid = [0, 0, 0, 0, 0, 0, 0, 0, 0];
96014
+ const thirdW = Math.floor(info.width / 3);
96015
+ const thirdH = Math.floor(info.height / 3);
96016
+ for (let y = 0; y < info.height; y++) {
96017
+ for (let x = 0; x < info.width; x++) {
96018
+ const i = (y * info.width + x) * info.channels;
96019
+ const r = data[i];
96020
+ const g = data[i + 1];
96021
+ const b = data[i + 2];
96022
+ if (!this.isSimilarColor(r, g, b, bgColor.r, bgColor.g, bgColor.b, 30)) {
96023
+ const col = x < thirdW ? 0 : x < thirdW * 2 ? 1 : 2;
96024
+ const row = y < thirdH ? 0 : y < thirdH * 2 ? 1 : 2;
96025
+ const cellIndex = row * 3 + col;
96026
+ grid[cellIndex] = (grid[cellIndex] ?? 0) + 1;
96027
+ }
96028
+ }
96029
+ }
96030
+ const total = grid.reduce((a, b) => a + b, 0);
96031
+ if (total === 0) return 100;
96032
+ const centerColumn = (grid[1] ?? 0) + (grid[4] ?? 0) + (grid[7] ?? 0);
96033
+ const leftColumn = (grid[0] ?? 0) + (grid[3] ?? 0) + (grid[6] ?? 0);
96034
+ const rightColumn = (grid[2] ?? 0) + (grid[5] ?? 0) + (grid[8] ?? 0);
96035
+ const centerRatio = centerColumn / total;
96036
+ if (centerRatio > 0.6) {
96037
+ const sideBalance = leftColumn > 0 && rightColumn > 0 ? Math.min(leftColumn, rightColumn) / Math.max(leftColumn, rightColumn) : 1;
96038
+ return Math.round(70 + sideBalance * 30);
96039
+ }
96040
+ const leftTotal = leftColumn + (grid[1] ?? 0) / 2 + (grid[4] ?? 0) / 2 + (grid[7] ?? 0) / 2;
96041
+ const rightTotal = rightColumn + (grid[1] ?? 0) / 2 + (grid[4] ?? 0) / 2 + (grid[7] ?? 0) / 2;
96042
+ const topRow = (grid[0] ?? 0) + (grid[1] ?? 0) + (grid[2] ?? 0);
96043
+ const bottomRow = (grid[6] ?? 0) + (grid[7] ?? 0) + (grid[8] ?? 0);
96044
+ const hBalance = leftTotal > 0 && rightTotal > 0 ? Math.min(leftTotal, rightTotal) / Math.max(leftTotal, rightTotal) : 0.5;
96045
+ const vBalance = topRow > 0 && bottomRow > 0 ? Math.min(topRow, bottomRow) / Math.max(topRow, bottomRow) : 0.5;
96046
+ const score = (hBalance * 0.6 + vBalance * 0.4) * 100;
96047
+ return Math.max(0, Math.min(100, Math.round(score)));
96048
+ } catch {
96049
+ return 75;
96050
+ }
96051
+ }
96052
+ /**
96053
+ * Check if there's clear visual hierarchy.
96054
+ */
96055
+ async checkHierarchy(screenshot) {
96056
+ try {
96057
+ const sharp = await import("sharp");
96058
+ const image = sharp.default(screenshot);
96059
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
96060
+ const bgColor = this.detectBackgroundColor(data, info.width, info.height, info.channels);
96061
+ const topRegionHeight = Math.floor(info.height * 0.2);
96062
+ let topContentPixels = 0;
96063
+ let bottomContentPixels = 0;
96064
+ for (let y = 0; y < info.height; y++) {
96065
+ for (let x = 0; x < info.width; x++) {
96066
+ const i = (y * info.width + x) * info.channels;
96067
+ const r = data[i];
96068
+ const g = data[i + 1];
96069
+ const b = data[i + 2];
96070
+ if (!this.isSimilarColor(r, g, b, bgColor.r, bgColor.g, bgColor.b, 30)) {
96071
+ if (y < topRegionHeight) {
96072
+ topContentPixels++;
96073
+ } else {
96074
+ bottomContentPixels++;
96075
+ }
96076
+ }
96077
+ }
96078
+ }
96079
+ const topDensity = topContentPixels / (info.width * topRegionHeight);
96080
+ const bottomDensity = bottomContentPixels / (info.width * (info.height - topRegionHeight));
96081
+ return topDensity > 0.01 && topDensity < 0.3;
96082
+ } catch {
96083
+ return true;
96084
+ }
96085
+ }
96086
+ // =============================================================================
96087
+ // HELPER METHODS
96088
+ // =============================================================================
96089
+ getTypeThresholds(type) {
96090
+ const thresholds = {
96091
+ ted_keynote: { minWhitespace: 0.6, maxWordsPerSlide: 15 },
96092
+ sales_pitch: { minWhitespace: 0.5, maxWordsPerSlide: 30 },
96093
+ investor_pitch: { minWhitespace: 0.5, maxWordsPerSlide: 35 },
96094
+ consulting_deck: { minWhitespace: 0.35, maxWordsPerSlide: 70 },
96095
+ investment_banking: { minWhitespace: 0.3, maxWordsPerSlide: 100 },
96096
+ technical_presentation: { minWhitespace: 0.45, maxWordsPerSlide: 45 },
96097
+ all_hands: { minWhitespace: 0.4, maxWordsPerSlide: 50 }
96098
+ };
96099
+ return thresholds[type] || { minWhitespace: 0.4, maxWordsPerSlide: 50 };
96100
+ }
96101
+ detectBackgroundColor(data, width, height, channels) {
96102
+ const colorBuckets = /* @__PURE__ */ new Map();
96103
+ for (let y = 0; y < height; y += 4) {
96104
+ for (let x = 0; x < width; x += 4) {
96105
+ const i = (y * width + x) * channels;
96106
+ const r = data[i];
96107
+ const g = data[i + 1];
96108
+ const b = data[i + 2];
96109
+ const key = `${Math.floor(r / 16)},${Math.floor(g / 16)},${Math.floor(b / 16)}`;
96110
+ const existing = colorBuckets.get(key);
96111
+ if (existing) {
96112
+ existing.count++;
96113
+ } else {
96114
+ colorBuckets.set(key, { r, g, b, count: 1 });
96115
+ }
96116
+ }
96117
+ }
96118
+ let maxCount = 0;
96119
+ let dominantColor = { r: 240, g: 240, b: 240 };
96120
+ for (const color of colorBuckets.values()) {
96121
+ if (color.count > maxCount) {
96122
+ maxCount = color.count;
96123
+ dominantColor = { r: color.r, g: color.g, b: color.b };
96124
+ }
96125
+ }
96126
+ return dominantColor;
96127
+ }
96128
+ detectTextColor(data, width, height, channels, bgColor) {
96129
+ const bgLuminance = this.relativeLuminance(bgColor.r, bgColor.g, bgColor.b);
96130
+ const isDarkBg = bgLuminance < 0.5;
96131
+ const luminanceBuckets = /* @__PURE__ */ new Map();
96132
+ const startY = Math.floor(height * 0.05);
96133
+ const endY = Math.floor(height * 0.95);
96134
+ const startX = Math.floor(width * 0.05);
96135
+ const endX = Math.floor(width * 0.95);
96136
+ for (let y = startY; y < endY; y += 2) {
96137
+ for (let x = startX; x < endX; x += 2) {
96138
+ const i = (y * width + x) * channels;
96139
+ const r = data[i];
96140
+ const g = data[i + 1];
96141
+ const b = data[i + 2];
96142
+ if (this.isSimilarColor(r, g, b, bgColor.r, bgColor.g, bgColor.b, 25)) {
96143
+ continue;
96144
+ }
96145
+ const lum = this.relativeLuminance(r, g, b);
96146
+ const bucket = Math.floor(lum * 10);
96147
+ const existing = luminanceBuckets.get(bucket);
96148
+ if (existing) {
96149
+ const total = existing.count + 1;
96150
+ existing.r = Math.round((existing.r * existing.count + r) / total);
96151
+ existing.g = Math.round((existing.g * existing.count + g) / total);
96152
+ existing.b = Math.round((existing.b * existing.count + b) / total);
96153
+ existing.count = total;
96154
+ } else {
96155
+ luminanceBuckets.set(bucket, { r, g, b, count: 1 });
96156
+ }
96157
+ }
96158
+ }
96159
+ const totalPixels = Array.from(luminanceBuckets.values()).reduce((sum, b) => sum + b.count, 0);
96160
+ const minCount = Math.max(50, totalPixels * 5e-3);
96161
+ let textColor = isDarkBg ? { r: 255, g: 255, b: 255 } : { r: 0, g: 0, b: 0 };
96162
+ if (isDarkBg) {
96163
+ for (let bucket = 10; bucket >= 0; bucket--) {
96164
+ const colors = luminanceBuckets.get(bucket);
96165
+ if (colors && colors.count >= minCount) {
96166
+ textColor = { r: colors.r, g: colors.g, b: colors.b };
96167
+ break;
96168
+ }
96169
+ }
96170
+ } else {
96171
+ for (let bucket = 0; bucket <= 10; bucket++) {
96172
+ const colors = luminanceBuckets.get(bucket);
96173
+ if (colors && colors.count >= minCount) {
96174
+ textColor = { r: colors.r, g: colors.g, b: colors.b };
96175
+ break;
96176
+ }
96177
+ }
96178
+ }
96179
+ return textColor;
96180
+ }
96181
+ isSimilarColor(r1, g1, b1, r2, g2, b2, threshold) {
96182
+ return Math.abs(r1 - r2) < threshold && Math.abs(g1 - g2) < threshold && Math.abs(b1 - b2) < threshold;
96183
+ }
96184
+ relativeLuminance(r, g, b) {
96185
+ const sRGB = [r, g, b].map((c) => {
96186
+ c = c / 255;
96187
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
96188
+ });
96189
+ return 0.2126 * sRGB[0] + 0.7152 * sRGB[1] + 0.0722 * sRGB[2];
96190
+ }
96191
+ calculateConsistency(slides) {
96192
+ if (slides.length < 2) return 100;
96193
+ const whitespaces = slides.map((s) => s.whitespacePercentage);
96194
+ const densities = slides.map((s) => s.textDensity);
96195
+ const wsVariance = this.variance(whitespaces);
96196
+ const densityVariance = this.variance(densities);
96197
+ const maxVariance = 0.1;
96198
+ const wsScore = Math.max(0, 100 - wsVariance / maxVariance * 50);
96199
+ const densityScore = Math.max(0, 100 - densityVariance / maxVariance * 50);
96200
+ return Math.round((wsScore + densityScore) / 2);
96201
+ }
96202
+ variance(values) {
96203
+ const mean = values.reduce((a, b) => a + b, 0) / values.length;
96204
+ return values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / values.length;
96205
+ }
96206
+ };
96207
+ var instance5 = null;
96208
+ function getVisualQAEngine() {
96209
+ if (!instance5) {
96210
+ instance5 = new VisualQAEngine();
96211
+ }
96212
+ return instance5;
96213
+ }
96214
+ async function initVisualQAEngine() {
96215
+ const engine = getVisualQAEngine();
96216
+ await engine.initialize();
96217
+ return engine;
96218
+ }
96219
+
96220
+ // src/core/PresentationEngineV2.ts
96221
+ var import_fs10 = require("fs");
95611
96222
  var PALETTE_TO_THEME = {
95612
96223
  dark_executive: "dark",
95613
96224
  modern_business: "light",
@@ -95668,6 +96279,80 @@ function getQualityCriteria(specs, type) {
95668
96279
  requireDataSources: specs.sourcesRequired
95669
96280
  };
95670
96281
  }
96282
+ function convertV1SlideToV2(slide) {
96283
+ const data = slide.data;
96284
+ const typeMap = {
96285
+ title: "title",
96286
+ title_impact: "title",
96287
+ agenda: "bullets",
96288
+ section_divider: "section",
96289
+ thank_you: "thank_you",
96290
+ single_statement: "statement",
96291
+ big_idea: "statement",
96292
+ big_number: "metrics",
96293
+ quote: "statement",
96294
+ star_moment: "statement",
96295
+ call_to_action: "call_to_action",
96296
+ three_points: "bullets",
96297
+ bullet_points: "bullets",
96298
+ two_column: "bullets",
96299
+ comparison: "bullets",
96300
+ metrics_grid: "metrics",
96301
+ data_insight: "metrics",
96302
+ problem_statement: "statement",
96303
+ solution_overview: "bullets",
96304
+ recommendation: "bullets",
96305
+ next_steps: "bullets"
96306
+ };
96307
+ const v2Type = typeMap[slide.type] || "bullets";
96308
+ const content = {};
96309
+ if (data.bullets && data.bullets.length > 0) {
96310
+ content.bullets = data.bullets;
96311
+ }
96312
+ if (data.metrics && data.metrics.length > 0) {
96313
+ content.metrics = data.metrics.map((m) => {
96314
+ const metric = {
96315
+ value: String(m.value),
96316
+ label: m.label
96317
+ };
96318
+ if (m.trend) {
96319
+ metric.trend = m.trend;
96320
+ }
96321
+ return metric;
96322
+ });
96323
+ }
96324
+ if (v2Type === "statement") {
96325
+ const statement = data.keyMessage || data.quote || data.body || "";
96326
+ if (statement) {
96327
+ content.statement = statement;
96328
+ }
96329
+ if (data.attribution) {
96330
+ content.subtext = data.attribution;
96331
+ }
96332
+ }
96333
+ if (data.body && v2Type !== "statement") {
96334
+ content.body = data.body;
96335
+ }
96336
+ if (data.source) {
96337
+ content.source = data.source;
96338
+ }
96339
+ if (data.subtitle) {
96340
+ content.subtext = data.subtitle;
96341
+ }
96342
+ const v2Slide = {
96343
+ index: slide.index,
96344
+ type: v2Type,
96345
+ title: data.title || "",
96346
+ content
96347
+ };
96348
+ if (slide.notes) {
96349
+ v2Slide.notes = slide.notes;
96350
+ }
96351
+ return v2Slide;
96352
+ }
96353
+ function convertV1SlidesToV2(slides) {
96354
+ return slides.map(convertV1SlideToV2);
96355
+ }
95671
96356
  var PresentationEngineV2 = class {
95672
96357
  options;
95673
96358
  kb = null;
@@ -95678,7 +96363,10 @@ var PresentationEngineV2 = class {
95678
96363
  imageApiKey: options.imageApiKey || process.env.GEMINI_API_KEY || process.env.OPENAI_API_KEY || "",
95679
96364
  minScore: options.minScore ?? 95,
95680
96365
  verbose: options.verbose ?? false,
95681
- maxRemediationAttempts: options.maxRemediationAttempts ?? 3
96366
+ maxRemediationAttempts: options.maxRemediationAttempts ?? 3,
96367
+ runVisualQA: options.runVisualQA ?? false,
96368
+ useRichPipeline: options.useRichPipeline ?? true
96369
+ // Default to V1's rich pipeline
95682
96370
  };
95683
96371
  }
95684
96372
  log(message) {
@@ -95710,8 +96398,21 @@ var PresentationEngineV2 = class {
95710
96398
  this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
95711
96399
  this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
95712
96400
  this.log("Step 3: Generating slides...");
95713
- const generator = createSlideGeneratorV2(presentationType);
95714
- let slides = generator.generate(markdown, title);
96401
+ let slides;
96402
+ if (this.options.useRichPipeline) {
96403
+ this.log(" Using V1 rich pipeline...");
96404
+ const contentAnalyzer = await initContentAnalyzer();
96405
+ const slideGenerator = await initSlideGenerator();
96406
+ const analysis = await contentAnalyzer.analyze(markdown, "markdown");
96407
+ this.log(` Content analysis: ${analysis.sections.length} sections, ${analysis.dataPoints.length} data points`);
96408
+ const v1Slides = await slideGenerator.generate(analysis, presentationType);
96409
+ this.log(` V1 generated ${v1Slides.length} slides`);
96410
+ slides = convertV1SlidesToV2(v1Slides);
96411
+ } else {
96412
+ this.log(" Using V2 minimalist pipeline...");
96413
+ const generator = createSlideGeneratorV2(presentationType);
96414
+ slides = generator.generate(markdown, title);
96415
+ }
95715
96416
  this.log(` Generated ${slides.length} slides`);
95716
96417
  if (!this.options.imageApiKey) {
95717
96418
  const shouldUseImages = this.shouldRecommendImages(slides, presentationType);
@@ -95763,10 +96464,29 @@ Summary: ${review.summary}`
95763
96464
  this.log("Step 7: Rendering output...");
95764
96465
  const renderer = createRendererV2(presentationType, this.kb);
95765
96466
  const html = renderer.render(slides, title || "Presentation");
96467
+ let visualQA;
96468
+ if (this.options.runVisualQA) {
96469
+ this.log("Step 8: Running Visual QA analysis...");
96470
+ try {
96471
+ const visualQAEngine = await initVisualQAEngine();
96472
+ visualQA = await visualQAEngine.analyzeDeck(html, slides, presentationType);
96473
+ await visualQAEngine.cleanup();
96474
+ if (!visualQA.passed) {
96475
+ warnings.push(`Visual QA detected issues: ${visualQA.summary}`);
96476
+ this.log(`Visual QA: ${visualQA.overallScore}/100 - ${visualQA.deckIssues.length} issues found`);
96477
+ } else {
96478
+ this.log(`Visual QA PASSED: ${visualQA.overallScore}/100`);
96479
+ }
96480
+ } catch (error) {
96481
+ const errMsg = error instanceof Error ? error.message : "Unknown error";
96482
+ warnings.push(`Visual QA failed: ${errMsg}`);
96483
+ this.log(`Visual QA error: ${errMsg}`);
96484
+ }
96485
+ }
95766
96486
  this.log(`
95767
96487
  SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95768
96488
  this.log(`Flow: ${review.flow}`);
95769
- return {
96489
+ const result = {
95770
96490
  slides,
95771
96491
  html,
95772
96492
  presentationType,
@@ -95774,6 +96494,10 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95774
96494
  review,
95775
96495
  warnings
95776
96496
  };
96497
+ if (visualQA) {
96498
+ result.visualQA = visualQA;
96499
+ }
96500
+ return result;
95777
96501
  }
95778
96502
  /**
95779
96503
  * Detect presentation type from content analysis.
@@ -95868,7 +96592,7 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95868
96592
  const issues = [];
95869
96593
  const suggestions = [];
95870
96594
  let score = 100;
95871
- if (slide.type === "title" || slide.type === "thank_you") {
96595
+ if (slide.type === "title" || slide.type === "thank_you" || slide.type === "section") {
95872
96596
  return {
95873
96597
  slideIndex: index,
95874
96598
  title: slide.title,
@@ -95926,7 +96650,7 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95926
96650
  score -= 10;
95927
96651
  }
95928
96652
  }
95929
- const hasContent = slide.content.bullets && slide.content.bullets.length > 0 || slide.content.table || slide.content.statement || slide.content.body;
96653
+ const hasContent = slide.content.bullets && slide.content.bullets.length > 0 || slide.content.table || slide.content.metrics && slide.content.metrics.length > 0 || slide.content.statement || slide.content.body;
95930
96654
  if (!hasContent) {
95931
96655
  issues.push("Slide has no content");
95932
96656
  score -= 30;
@@ -96109,7 +96833,7 @@ async function generatePresentation(markdown, options) {
96109
96833
  const result = await engine.generate(markdown, options?.title);
96110
96834
  if (options?.outputPath) {
96111
96835
  const htmlPath = options.outputPath.replace(/\.[^.]+$/, "") + ".html";
96112
- (0, import_fs9.writeFileSync)(htmlPath, result.html);
96836
+ (0, import_fs10.writeFileSync)(htmlPath, result.html);
96113
96837
  console.log(`
96114
96838
  Output: ${htmlPath}`);
96115
96839
  }
@@ -96853,12 +97577,12 @@ var SlideQualityReviewer = class {
96853
97577
  };
96854
97578
  }
96855
97579
  };
96856
- var instance5 = null;
97580
+ var instance6 = null;
96857
97581
  function getSlideQualityReviewer() {
96858
- if (!instance5) {
96859
- instance5 = new SlideQualityReviewer();
97582
+ if (!instance6) {
97583
+ instance6 = new SlideQualityReviewer();
96860
97584
  }
96861
- return instance5;
97585
+ return instance6;
96862
97586
  }
96863
97587
  async function initSlideQualityReviewer() {
96864
97588
  const reviewer = getSlideQualityReviewer();
@@ -97388,12 +98112,12 @@ var DeckQualityReviewer = class {
97388
98112
  return Math.max(0, 100 - deduction);
97389
98113
  }
97390
98114
  };
97391
- var instance6 = null;
98115
+ var instance7 = null;
97392
98116
  function getDeckQualityReviewer() {
97393
- if (!instance6) {
97394
- instance6 = new DeckQualityReviewer();
98117
+ if (!instance7) {
98118
+ instance7 = new DeckQualityReviewer();
97395
98119
  }
97396
- return instance6;
98120
+ return instance7;
97397
98121
  }
97398
98122
  async function initDeckQualityReviewer() {
97399
98123
  const reviewer = getDeckQualityReviewer();
@@ -97698,12 +98422,12 @@ var Remediator = class {
97698
98422
  return text.split(/\s+/).filter((w) => w.length > 0).length;
97699
98423
  }
97700
98424
  };
97701
- var instance7 = null;
98425
+ var instance8 = null;
97702
98426
  function getRemediator() {
97703
- if (!instance7) {
97704
- instance7 = new Remediator();
98427
+ if (!instance8) {
98428
+ instance8 = new Remediator();
97705
98429
  }
97706
- return instance7;
98430
+ return instance8;
97707
98431
  }
97708
98432
  async function initRemediator() {
97709
98433
  const remediator = getRemediator();
@@ -98675,12 +99399,12 @@ ${content}
98675
99399
  return html;
98676
99400
  }
98677
99401
  };
98678
- var instance8 = null;
99402
+ var instance9 = null;
98679
99403
  function getRenderer() {
98680
- if (!instance8) {
98681
- instance8 = new Renderer();
99404
+ if (!instance9) {
99405
+ instance9 = new Renderer();
98682
99406
  }
98683
- return instance8;
99407
+ return instance9;
98684
99408
  }
98685
99409
  async function initRenderer() {
98686
99410
  const renderer = getRenderer();
@@ -98908,7 +99632,7 @@ function getNanoBananaPrompt(style, concept, presentationType) {
98908
99632
  }
98909
99633
 
98910
99634
  // src/image/ImageMatcher.ts
98911
- var import_fs10 = require("fs");
99635
+ var import_fs11 = require("fs");
98912
99636
  function analyzeImage(imagePath) {
98913
99637
  const parts = imagePath.split("/");
98914
99638
  const filename = parts[parts.length - 1] || "unknown";
@@ -99139,7 +99863,7 @@ async function analyzeImageWithVision(imagePath) {
99139
99863
  return basicInfo;
99140
99864
  }
99141
99865
  try {
99142
- const imageBuffer = (0, import_fs10.readFileSync)(imagePath);
99866
+ const imageBuffer = (0, import_fs11.readFileSync)(imagePath);
99143
99867
  const base64Image = imageBuffer.toString("base64");
99144
99868
  const mimeType = getMimeType(basicInfo.extension);
99145
99869
  const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
@@ -99738,6 +100462,7 @@ function countWords(slide) {
99738
100462
  SlideQualityReviewer,
99739
100463
  VERSION,
99740
100464
  VisualDesignSystem,
100465
+ VisualQAEngine,
99741
100466
  createNanoBananaProvider,
99742
100467
  createPresentationEngineV2,
99743
100468
  createRendererV2,
@@ -99753,6 +100478,7 @@ function countWords(slide) {
99753
100478
  getSlideGenerator,
99754
100479
  getSlideQualityReviewer,
99755
100480
  getVisualDesignSystem,
100481
+ getVisualQAEngine,
99756
100482
  initContentAnalyzer,
99757
100483
  initDeckQualityReviewer,
99758
100484
  initKB,
@@ -99761,6 +100487,7 @@ function countWords(slide) {
99761
100487
  initSlideGenerator,
99762
100488
  initSlideQualityReviewer,
99763
100489
  initVisualDesignSystem,
100490
+ initVisualQAEngine,
99764
100491
  runCodeQualityCheck,
99765
100492
  validateCodeQuality
99766
100493
  });