claude-presentation-master 4.1.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
  });
@@ -94205,69 +94208,112 @@ function createSlideGeneratorV2(type = "consulting_deck") {
94205
94208
 
94206
94209
  // src/output/RendererV2.ts
94207
94210
  var import_fs8 = require("fs");
94208
- var THEMES = {
94209
- mckinsey: {
94210
- style: "mckinsey",
94211
- primaryColor: "#003366",
94212
- // McKinsey blue
94213
- accentColor: "#0066cc",
94214
- description: "White background, professional hierarchy - for consulting/analysis decks"
94211
+ var FALLBACK_PALETTES = {
94212
+ consulting_classic: {
94213
+ background: "#FAFAF9",
94214
+ primary: "#0F172A",
94215
+ secondary: "#475569",
94216
+ accent: "#0369A1",
94217
+ text: "#18181B",
94218
+ name: "Consulting Classic"
94215
94219
  },
94216
- dark: {
94217
- style: "dark",
94218
- primaryColor: "#1a1a2e",
94219
- accentColor: "#4a9eff",
94220
- description: "Dark dramatic theme - for keynotes and tech presentations"
94220
+ dark_executive: {
94221
+ background: "#18181B",
94222
+ primary: "#FAFAFA",
94223
+ secondary: "#A1A1AA",
94224
+ accent: "#F59E0B",
94225
+ text: "#F4F4F5",
94226
+ name: "Dark Executive"
94221
94227
  },
94222
- minimal: {
94223
- style: "minimal",
94224
- primaryColor: "#333333",
94225
- accentColor: "#0066cc",
94226
- description: "Clean minimal white - for training and documentation"
94228
+ modern_business: {
94229
+ background: "#F8FAFC",
94230
+ primary: "#1E293B",
94231
+ secondary: "#64748B",
94232
+ accent: "#0891B2",
94233
+ text: "#0F172A",
94234
+ name: "Modern Business"
94227
94235
  },
94228
- corporate: {
94229
- style: "mckinsey",
94230
- // Uses McKinsey CSS but with different branding potential
94231
- primaryColor: "#1a365d",
94232
- accentColor: "#3182ce",
94233
- description: "Professional corporate - for executive presentations"
94236
+ executive_professional: {
94237
+ background: "#F5F5F4",
94238
+ primary: "#1E3A5F",
94239
+ secondary: "#64748B",
94240
+ accent: "#D97706",
94241
+ text: "#1F2937",
94242
+ name: "Executive Professional"
94234
94243
  },
94235
- startup: {
94236
- style: "dark",
94237
- primaryColor: "#0d1117",
94238
- accentColor: "#58a6ff",
94239
- description: "Modern dark - for pitch decks and product demos"
94244
+ strategy_growth: {
94245
+ background: "#FAF9F7",
94246
+ primary: "#292524",
94247
+ secondary: "#78716C",
94248
+ accent: "#059669",
94249
+ text: "#1C1917",
94250
+ name: "Strategy Growth"
94240
94251
  }
94241
94252
  };
94242
- var PRESENTATION_TYPE_TO_THEME = {
94243
- // Keynotes Dark dramatic style (TED talks, big stage)
94244
- ted_keynote: "dark",
94245
- // Sales → Dark dramatic style (persuasion, impact)
94246
- sales_pitch: "dark",
94247
- // Consulting/Analysis decks → McKinsey white style (data-heavy, professional)
94248
- consulting_deck: "mckinsey",
94249
- // Investment Banking → McKinsey style (financial, dense data)
94250
- investment_banking: "mckinsey",
94251
- // Investor Pitch → Startup dark style (modern, VC audiences)
94252
- investor_pitch: "startup",
94253
- // Technical → Dark style (engineering audiences like dark mode)
94254
- technical_presentation: "dark",
94255
- // All Hands → Minimal clean style (readable, accessible)
94256
- all_hands: "minimal"
94257
- };
94253
+ function getPaletteStyle(paletteName) {
94254
+ return paletteName === "dark_executive" ? "dark" : "light";
94255
+ }
94258
94256
  var RendererV2 = class {
94259
94257
  theme;
94260
94258
  presentationType;
94259
+ kb;
94261
94260
  /**
94262
- * Create renderer with theme based on presentation type.
94263
- * @param presentationType - The type of deck being created (determines theme)
94264
- * @param themeOverride - Optional explicit theme override
94261
+ * Create renderer with theme loaded from Knowledge Base.
94262
+ * @param presentationType - The type of deck being created (determines palette)
94263
+ * @param kb - Knowledge Base gateway (optional, will use global if not provided)
94265
94264
  */
94266
- constructor(presentationType = "consulting_deck", themeOverride) {
94265
+ constructor(presentationType = "consulting_deck", kb) {
94267
94266
  this.presentationType = presentationType;
94268
- const themeStyle = themeOverride || PRESENTATION_TYPE_TO_THEME[presentationType] || "mckinsey";
94269
- this.theme = THEMES[themeStyle] || THEMES.mckinsey;
94270
- console.log(`[RendererV2] Using "${this.theme.style}" theme for "${presentationType}" deck`);
94267
+ this.kb = kb || getKB();
94268
+ this.theme = this.loadThemeFromKB(presentationType);
94269
+ console.log(`[RendererV2] Using "${this.theme.paletteName}" palette (${this.theme.style} style) for "${presentationType}" deck`);
94270
+ }
94271
+ /**
94272
+ * Load theme configuration from Knowledge Base.
94273
+ * Falls back to hardcoded values only if KB fails.
94274
+ */
94275
+ loadThemeFromKB(type) {
94276
+ try {
94277
+ const paletteName = this.kb.queryOptional(`presentation_types.${type}.color_palette`).value || this.getDefaultPaletteName(type);
94278
+ const kbPalette = this.kb.queryOptional(`color_palettes.${paletteName}`).value;
94279
+ if (kbPalette) {
94280
+ console.log(`[RendererV2] Loaded "${paletteName}" palette from KB: bg=${kbPalette.background}, accent=${kbPalette.accent}`);
94281
+ return {
94282
+ style: getPaletteStyle(paletteName),
94283
+ palette: kbPalette,
94284
+ paletteName
94285
+ };
94286
+ }
94287
+ const fallback = FALLBACK_PALETTES[paletteName] ?? FALLBACK_PALETTES.consulting_classic;
94288
+ console.log(`[RendererV2] Using fallback "${paletteName}" palette`);
94289
+ return {
94290
+ style: getPaletteStyle(paletteName),
94291
+ palette: fallback,
94292
+ paletteName
94293
+ };
94294
+ } catch {
94295
+ const defaultPalette = FALLBACK_PALETTES.consulting_classic;
94296
+ return {
94297
+ style: "light",
94298
+ palette: defaultPalette,
94299
+ paletteName: "consulting_classic"
94300
+ };
94301
+ }
94302
+ }
94303
+ /**
94304
+ * Default palette mapping per presentation type (used if KB doesn't specify).
94305
+ */
94306
+ getDefaultPaletteName(type) {
94307
+ const defaults = {
94308
+ ted_keynote: "dark_executive",
94309
+ sales_pitch: "modern_business",
94310
+ consulting_deck: "consulting_classic",
94311
+ investment_banking: "executive_professional",
94312
+ investor_pitch: "modern_business",
94313
+ technical_presentation: "dark_executive",
94314
+ all_hands: "strategy_growth"
94315
+ };
94316
+ return defaults[type] || "consulting_classic";
94271
94317
  }
94272
94318
  /**
94273
94319
  * Render slides to complete HTML document.
@@ -94357,15 +94403,15 @@ ${slidesHtml}
94357
94403
  const content = this.renderSlideContent(slide);
94358
94404
  return `<div class="slide slide-${slide.type}">${content}</div>`;
94359
94405
  }).join("\n");
94360
- if (this.theme.style === "mckinsey") {
94361
- return this.getMcKinseyPrintHTML(title, slidesHtml);
94406
+ if (this.theme.style === "light") {
94407
+ return this.getLightPrintHTML(title, slidesHtml);
94362
94408
  }
94363
94409
  return this.getDarkPrintHTML(title, slidesHtml);
94364
94410
  }
94365
94411
  /**
94366
- * McKinsey-style print HTML (white background, professional).
94412
+ * Light theme print HTML (professional, white background).
94367
94413
  */
94368
- getMcKinseyPrintHTML(title, slidesHtml) {
94414
+ getLightPrintHTML(title, slidesHtml) {
94369
94415
  return `<!DOCTYPE html>
94370
94416
  <html lang="en">
94371
94417
  <head>
@@ -95021,34 +95067,60 @@ ${content}
95021
95067
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
95022
95068
  }
95023
95069
  /**
95024
- * Professional CSS - McKinsey/BCG consulting style.
95070
+ * Generate CSS with colors from Knowledge Base.
95025
95071
  */
95026
95072
  getCSS() {
95027
- if (this.theme.style === "mckinsey") {
95028
- return this.getMcKinseyCSS();
95073
+ if (this.theme.style === "light") {
95074
+ return this.getLightThemeCSS();
95029
95075
  }
95030
- return this.getDarkCSS();
95076
+ return this.getDarkThemeCSS();
95031
95077
  }
95032
95078
  /**
95033
- * McKinsey/BCG Consulting Style - WHITE background, professional hierarchy.
95079
+ * Generate CSS variables from KB palette.
95034
95080
  */
95035
- getMcKinseyCSS() {
95081
+ getCSSVariables() {
95082
+ const p = this.theme.palette;
95083
+ const isLight = this.theme.style === "light";
95084
+ const bgSecondary = isLight ? this.lightenColor(p.background, -5) : this.lightenColor(p.background, 10);
95085
+ const bgAccent = isLight ? this.lightenColor(p.background, -10) : this.lightenColor(p.background, 15);
95086
+ const textMuted = isLight ? this.lightenColor(p.text, 40) : this.lightenColor(p.text, -30);
95036
95087
  return `
95037
- /* McKinsey Consulting Theme - Clean White, Strong Hierarchy */
95088
+ /* ${this.theme.paletteName} Theme - Loaded from Knowledge Base */
95038
95089
  :root {
95039
- --bg-primary: #ffffff;
95040
- --bg-secondary: #f8f9fa;
95041
- --bg-accent: #e9ecef;
95042
- --text-primary: #1a1a1a;
95043
- --text-secondary: #333333;
95044
- --text-muted: #666666;
95045
- --mckinsey-blue: #003366;
95046
- --accent-blue: #0066cc;
95090
+ --kb-palette: "${this.theme.paletteName}";
95091
+ --bg-primary: ${p.background};
95092
+ --bg-secondary: ${bgSecondary};
95093
+ --bg-accent: ${bgAccent};
95094
+ --text-primary: ${p.text};
95095
+ --text-secondary: ${p.secondary};
95096
+ --text-muted: ${textMuted};
95097
+ --color-primary: ${p.primary};
95098
+ --color-accent: ${p.accent};
95099
+ --accent-blue: ${p.accent};
95047
95100
  --accent-green: #28a745;
95048
95101
  --accent-red: #dc3545;
95049
- --border-color: #dee2e6;
95050
- --header-bar: #003366;
95051
- }
95102
+ --border-color: ${isLight ? "#dee2e6" : "rgba(255,255,255,0.1)"};
95103
+ --header-bar: ${p.primary};
95104
+ --mckinsey-blue: ${p.accent};
95105
+ }`;
95106
+ }
95107
+ /**
95108
+ * Lighten or darken a hex color.
95109
+ */
95110
+ lightenColor(hex, percent) {
95111
+ const num = parseInt(hex.replace("#", ""), 16);
95112
+ const amt = Math.round(2.55 * percent);
95113
+ const R = Math.max(0, Math.min(255, (num >> 16) + amt));
95114
+ const G = Math.max(0, Math.min(255, (num >> 8 & 255) + amt));
95115
+ const B = Math.max(0, Math.min(255, (num & 255) + amt));
95116
+ return `#${(16777216 + R * 65536 + G * 256 + B).toString(16).slice(1)}`;
95117
+ }
95118
+ /**
95119
+ * Light theme CSS (consulting style) with KB palette colors.
95120
+ */
95121
+ getLightThemeCSS() {
95122
+ return `
95123
+ ${this.getCSSVariables()}
95052
95124
 
95053
95125
  .reveal {
95054
95126
  font-family: 'Georgia', 'Times New Roman', serif;
@@ -95319,23 +95391,11 @@ ${content}
95319
95391
  `;
95320
95392
  }
95321
95393
  /**
95322
- * Dark theme CSS (legacy).
95394
+ * Dark theme CSS with KB palette colors.
95323
95395
  */
95324
- getDarkCSS() {
95396
+ getDarkThemeCSS() {
95325
95397
  return `
95326
- /* Professional Dark Theme - No Random Images */
95327
- :root {
95328
- --bg-primary: #1a1a2e;
95329
- --bg-secondary: #16213e;
95330
- --bg-accent: #0f3460;
95331
- --text-primary: #ffffff;
95332
- --text-secondary: rgba(255, 255, 255, 0.85);
95333
- --text-muted: rgba(255, 255, 255, 0.6);
95334
- --accent-blue: #4a9eff;
95335
- --accent-green: #00d4aa;
95336
- --accent-orange: #ff9f43;
95337
- --border-color: rgba(255, 255, 255, 0.1);
95338
- }
95398
+ ${this.getCSSVariables()}
95339
95399
 
95340
95400
  .reveal {
95341
95401
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
@@ -95546,18 +95606,625 @@ ${content}
95546
95606
  `;
95547
95607
  }
95548
95608
  };
95549
- function createRendererV2(presentationType = "consulting_deck", themeOverride) {
95550
- return new RendererV2(presentationType, themeOverride);
95609
+ function createRendererV2(presentationType = "consulting_deck", kb) {
95610
+ return new RendererV2(presentationType, kb);
95551
95611
  }
95552
95612
 
95553
- // src/core/PresentationEngineV2.ts
95613
+ // src/qa/VisualQAEngine.ts
95554
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");
95555
96222
  var PALETTE_TO_THEME = {
95556
96223
  dark_executive: "dark",
95557
- modern_business: "startup",
95558
- consulting_classic: "mckinsey",
95559
- executive_professional: "mckinsey",
95560
- strategy_growth: "minimal"
96224
+ modern_business: "light",
96225
+ consulting_classic: "light",
96226
+ executive_professional: "light",
96227
+ strategy_growth: "light"
95561
96228
  };
95562
96229
  async function loadDesignSpecsFromKB(kb, type) {
95563
96230
  const typeConfig = kb.queryRequired(`presentation_types.${type}`);
@@ -95568,7 +96235,7 @@ async function loadDesignSpecsFromKB(kb, type) {
95568
96235
  const typography = typeConfig.value.typography;
95569
96236
  const primaryExperts = typeConfig.value.primary_experts;
95570
96237
  const colorPalette = typeConfig.value.color_palette || "consulting_classic";
95571
- const theme = PALETTE_TO_THEME[colorPalette] || "mckinsey";
96238
+ const theme = PALETTE_TO_THEME[colorPalette] || "light";
95572
96239
  const scoringWeights = typeConfig.value.scoring_weights;
95573
96240
  let structure = "General presentation structure";
95574
96241
  if (primaryExperts.some((e) => e.includes("Minto") || e.includes("McKinsey"))) {
@@ -95612,6 +96279,80 @@ function getQualityCriteria(specs, type) {
95612
96279
  requireDataSources: specs.sourcesRequired
95613
96280
  };
95614
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
+ }
95615
96356
  var PresentationEngineV2 = class {
95616
96357
  options;
95617
96358
  kb = null;
@@ -95622,7 +96363,10 @@ var PresentationEngineV2 = class {
95622
96363
  imageApiKey: options.imageApiKey || process.env.GEMINI_API_KEY || process.env.OPENAI_API_KEY || "",
95623
96364
  minScore: options.minScore ?? 95,
95624
96365
  verbose: options.verbose ?? false,
95625
- 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
95626
96370
  };
95627
96371
  }
95628
96372
  log(message) {
@@ -95654,8 +96398,21 @@ var PresentationEngineV2 = class {
95654
96398
  this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
95655
96399
  this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
95656
96400
  this.log("Step 3: Generating slides...");
95657
- const generator = createSlideGeneratorV2(presentationType);
95658
- 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
+ }
95659
96416
  this.log(` Generated ${slides.length} slides`);
95660
96417
  if (!this.options.imageApiKey) {
95661
96418
  const shouldUseImages = this.shouldRecommendImages(slides, presentationType);
@@ -95705,12 +96462,31 @@ Summary: ${review.summary}`
95705
96462
  );
95706
96463
  }
95707
96464
  this.log("Step 7: Rendering output...");
95708
- const renderer = createRendererV2(presentationType, this.options.themeOverride);
96465
+ const renderer = createRendererV2(presentationType, this.kb);
95709
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
+ }
95710
96486
  this.log(`
95711
96487
  SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95712
96488
  this.log(`Flow: ${review.flow}`);
95713
- return {
96489
+ const result = {
95714
96490
  slides,
95715
96491
  html,
95716
96492
  presentationType,
@@ -95718,6 +96494,10 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95718
96494
  review,
95719
96495
  warnings
95720
96496
  };
96497
+ if (visualQA) {
96498
+ result.visualQA = visualQA;
96499
+ }
96500
+ return result;
95721
96501
  }
95722
96502
  /**
95723
96503
  * Detect presentation type from content analysis.
@@ -95812,7 +96592,7 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95812
96592
  const issues = [];
95813
96593
  const suggestions = [];
95814
96594
  let score = 100;
95815
- if (slide.type === "title" || slide.type === "thank_you") {
96595
+ if (slide.type === "title" || slide.type === "thank_you" || slide.type === "section") {
95816
96596
  return {
95817
96597
  slideIndex: index,
95818
96598
  title: slide.title,
@@ -95870,7 +96650,7 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95870
96650
  score -= 10;
95871
96651
  }
95872
96652
  }
95873
- 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;
95874
96654
  if (!hasContent) {
95875
96655
  issues.push("Slide has no content");
95876
96656
  score -= 30;
@@ -96053,7 +96833,7 @@ async function generatePresentation(markdown, options) {
96053
96833
  const result = await engine.generate(markdown, options?.title);
96054
96834
  if (options?.outputPath) {
96055
96835
  const htmlPath = options.outputPath.replace(/\.[^.]+$/, "") + ".html";
96056
- (0, import_fs9.writeFileSync)(htmlPath, result.html);
96836
+ (0, import_fs10.writeFileSync)(htmlPath, result.html);
96057
96837
  console.log(`
96058
96838
  Output: ${htmlPath}`);
96059
96839
  }
@@ -96797,12 +97577,12 @@ var SlideQualityReviewer = class {
96797
97577
  };
96798
97578
  }
96799
97579
  };
96800
- var instance5 = null;
97580
+ var instance6 = null;
96801
97581
  function getSlideQualityReviewer() {
96802
- if (!instance5) {
96803
- instance5 = new SlideQualityReviewer();
97582
+ if (!instance6) {
97583
+ instance6 = new SlideQualityReviewer();
96804
97584
  }
96805
- return instance5;
97585
+ return instance6;
96806
97586
  }
96807
97587
  async function initSlideQualityReviewer() {
96808
97588
  const reviewer = getSlideQualityReviewer();
@@ -97332,12 +98112,12 @@ var DeckQualityReviewer = class {
97332
98112
  return Math.max(0, 100 - deduction);
97333
98113
  }
97334
98114
  };
97335
- var instance6 = null;
98115
+ var instance7 = null;
97336
98116
  function getDeckQualityReviewer() {
97337
- if (!instance6) {
97338
- instance6 = new DeckQualityReviewer();
98117
+ if (!instance7) {
98118
+ instance7 = new DeckQualityReviewer();
97339
98119
  }
97340
- return instance6;
98120
+ return instance7;
97341
98121
  }
97342
98122
  async function initDeckQualityReviewer() {
97343
98123
  const reviewer = getDeckQualityReviewer();
@@ -97642,12 +98422,12 @@ var Remediator = class {
97642
98422
  return text.split(/\s+/).filter((w) => w.length > 0).length;
97643
98423
  }
97644
98424
  };
97645
- var instance7 = null;
98425
+ var instance8 = null;
97646
98426
  function getRemediator() {
97647
- if (!instance7) {
97648
- instance7 = new Remediator();
98427
+ if (!instance8) {
98428
+ instance8 = new Remediator();
97649
98429
  }
97650
- return instance7;
98430
+ return instance8;
97651
98431
  }
97652
98432
  async function initRemediator() {
97653
98433
  const remediator = getRemediator();
@@ -98619,12 +99399,12 @@ ${content}
98619
99399
  return html;
98620
99400
  }
98621
99401
  };
98622
- var instance8 = null;
99402
+ var instance9 = null;
98623
99403
  function getRenderer() {
98624
- if (!instance8) {
98625
- instance8 = new Renderer();
99404
+ if (!instance9) {
99405
+ instance9 = new Renderer();
98626
99406
  }
98627
- return instance8;
99407
+ return instance9;
98628
99408
  }
98629
99409
  async function initRenderer() {
98630
99410
  const renderer = getRenderer();
@@ -98852,7 +99632,7 @@ function getNanoBananaPrompt(style, concept, presentationType) {
98852
99632
  }
98853
99633
 
98854
99634
  // src/image/ImageMatcher.ts
98855
- var import_fs10 = require("fs");
99635
+ var import_fs11 = require("fs");
98856
99636
  function analyzeImage(imagePath) {
98857
99637
  const parts = imagePath.split("/");
98858
99638
  const filename = parts[parts.length - 1] || "unknown";
@@ -99083,7 +99863,7 @@ async function analyzeImageWithVision(imagePath) {
99083
99863
  return basicInfo;
99084
99864
  }
99085
99865
  try {
99086
- const imageBuffer = (0, import_fs10.readFileSync)(imagePath);
99866
+ const imageBuffer = (0, import_fs11.readFileSync)(imagePath);
99087
99867
  const base64Image = imageBuffer.toString("base64");
99088
99868
  const mimeType = getMimeType(basicInfo.extension);
99089
99869
  const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
@@ -99494,7 +100274,7 @@ if (typeof process !== "undefined" && process.argv[1]?.includes("CodeQualityVali
99494
100274
  }
99495
100275
 
99496
100276
  // src/index.ts
99497
- var VERSION = "4.1.0";
100277
+ var VERSION = "4.2.0";
99498
100278
  async function generate(options) {
99499
100279
  const {
99500
100280
  content,
@@ -99682,6 +100462,7 @@ function countWords(slide) {
99682
100462
  SlideQualityReviewer,
99683
100463
  VERSION,
99684
100464
  VisualDesignSystem,
100465
+ VisualQAEngine,
99685
100466
  createNanoBananaProvider,
99686
100467
  createPresentationEngineV2,
99687
100468
  createRendererV2,
@@ -99697,6 +100478,7 @@ function countWords(slide) {
99697
100478
  getSlideGenerator,
99698
100479
  getSlideQualityReviewer,
99699
100480
  getVisualDesignSystem,
100481
+ getVisualQAEngine,
99700
100482
  initContentAnalyzer,
99701
100483
  initDeckQualityReviewer,
99702
100484
  initKB,
@@ -99705,6 +100487,7 @@ function countWords(slide) {
99705
100487
  initSlideGenerator,
99706
100488
  initSlideQualityReviewer,
99707
100489
  initVisualDesignSystem,
100490
+ initVisualQAEngine,
99708
100491
  runCodeQualityCheck,
99709
100492
  validateCodeQuality
99710
100493
  });