claude-presentation-master 3.9.0 → 4.1.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/README.md CHANGED
@@ -20,25 +20,38 @@
20
20
 
21
21
  ---
22
22
 
23
- ## What's New in v3.0.2
24
-
25
- - **🖼️ Automatic Background Images** Every slide now has a contextual background image from Unsplash (free, no API key)
26
- - **Smart Image Matching** — Images are selected based on slide type and content keywords
27
- - **Cinematic Dark Overlay** — 40% opacity images with gradient overlay for guaranteed text readability
28
- - **Playwright Visual QA** Screenshot verification of every slide to ensure visual quality
29
- - **QA Image Verification** Visual QA now validates that background images are present
30
-
31
- ### Previous in v3.0.1
32
-
33
- - **Knowledge-Driven Orchestration** — All decisions route through RuVector knowledge base (6,300+ lines of expert methodology)
34
- - **VisionQA Engine** — Optional Claude multimodal visual analysis for slide rendering validation
35
- - **NanoBanana Pro Integration** — AI image generation using Google Gemini (optional, with GOOGLE_AI_API_KEY)
36
- - **Multi-Agent Consensus Validation** — Expert agents (Duarte, Reynolds, Minto, Tufte, Gallo, Anderson) provide weighted assessments
37
- - **Semantic Completeness Validator** — Ensures presentation covers all key topics from source content
38
- - **7 Specialized Presentation Types** — TED Keynote, Sales Pitch, Consulting Deck, Investment Banking, Investor Pitch, Technical Presentation, All Hands
39
- - **Investment Banking Charts** — Football field, waterfall, sources & uses tables, comparable companies analysis
40
- - **Professional Typography** Google Fonts for each presentation type
41
- - **100% Zero Cost by Default** — No API keys required, optional AI features when keys available
23
+ ## What's New in v4.0.0 — True Knowledge-Driven Architecture
24
+
25
+ **The Knowledge Base now DRIVES everything at runtime no more hardcoded specs.**
26
+
27
+ ### Breaking Changes
28
+ - `PresentationEngineV2` now requires Knowledge Base YAML at runtime
29
+ - All design specs loaded from KB, not constants in code
30
+
31
+ ### New Features
32
+ - **📚 Runtime KB Loading** — The 6,300+ line YAML knowledge base is parsed at runtime, not duplicated in code
33
+ - **🎯 H3 Action Title Extraction** — Markdown H3 headings become slide titles (McKinsey "so what" principle)
34
+ - **📊 Tables Preserved Correctly** — Tables stay as tables, never mangled into metric cards
35
+ - **🚫 No Orphan Slides** — Minimum 3 bullets per slide, balanced distribution
36
+ - **✅ 95+ Quality Threshold** — Engine fails if quality score below 95/100
37
+
38
+ ### Knowledge Base Integration
39
+ - Word limits from `presentation_types.{type}.validation_rules.words_per_slide`
40
+ - Bullet limits from `presentation_types.{type}.validation_rules.bullets_per_slide`
41
+ - Theme from `presentation_types.{type}.color_palette`
42
+ - Experts from `presentation_types.{type}.primary_experts`
43
+ - Scoring weights from `presentation_types.{type}.scoring_weights`
44
+
45
+ ### 7 Specialized Presentation Types
46
+ | Type | Theme | Words/Slide | Key Experts |
47
+ |------|-------|-------------|-------------|
48
+ | `ted_keynote` | Dark | 1-15 | Duarte, Reynolds, Anderson |
49
+ | `sales_pitch` | Modern | 10-30 | Cialdini, Heath |
50
+ | `consulting_deck` | McKinsey | 40-80 | Minto, McKinsey, BCG |
51
+ | `investment_banking` | McKinsey | 60-120 | Wall Street Prep |
52
+ | `investor_pitch` | Startup | 5-30 | Sequoia, YC |
53
+ | `technical_presentation` | Dark | 40-100 | Tufte, C4 Model |
54
+ | `all_hands` | Minimal | 15-40 | Internal Comms |
42
55
 
43
56
  ---
44
57
 
package/bin/cli.js CHANGED
@@ -20,7 +20,7 @@ const args = process.argv.slice(2);
20
20
 
21
21
  // Help text
22
22
  const helpText = `
23
- Claude Presentation Master v2.1.0
23
+ Claude Presentation Master v4.1.0
24
24
  Generate world-class presentations using expert methodologies
25
25
 
26
26
  100% FREE • Zero API Keys • Runs Locally
@@ -85,7 +85,7 @@ For more information: https://github.com/Stuinfla/claude-presentation-master
85
85
  `;
86
86
 
87
87
  // Version
88
- const version = '2.1.0';
88
+ const version = '4.1.0';
89
89
 
90
90
  // Parse arguments
91
91
  function parseArgs(args) {
package/dist/index.d.mts CHANGED
@@ -692,10 +692,27 @@ interface MetricData {
692
692
  label: string;
693
693
  trend?: 'up' | 'down' | 'neutral';
694
694
  }
695
+ interface ModeConfig {
696
+ maxBulletsPerSlide: number;
697
+ maxWordsPerSlide: number;
698
+ minBulletsToKeep: number;
699
+ }
695
700
  declare class SlideGeneratorV2 {
696
701
  private config;
697
702
  private presentationType;
703
+ /**
704
+ * Create a slide generator with default configs.
705
+ * For KB-driven configs, use createSlideGeneratorV2WithConfig() instead.
706
+ */
698
707
  constructor(presentationType?: PresentationType);
708
+ /**
709
+ * Override config with KB-loaded values at runtime.
710
+ */
711
+ setConfig(config: ModeConfig): void;
712
+ /**
713
+ * Get current config (useful for debugging).
714
+ */
715
+ getConfig(): ModeConfig;
699
716
  /**
700
717
  * Generate slides from markdown content.
701
718
  * Simple, correct, no garbage.
@@ -904,17 +921,15 @@ declare function createRendererV2(presentationType?: PresentationType, themeOver
904
921
  *
905
922
  * This engine orchestrates the ENTIRE presentation creation flow:
906
923
  * 1. Analyze content to detect presentation type
907
- * 2. Load design specs from Knowledge Base
924
+ * 2. Load design specs from Knowledge Base (YAML)
908
925
  * 3. Generate slides following expert methodologies
909
926
  * 4. Enhance with images (optional, needs API key)
910
927
  * 5. Review ruthlessly (must score 95/100+)
911
928
  * 6. Output ONLY if quality passes
912
929
  *
913
- * The Knowledge Base drives EVERYTHING:
914
- * - Presentation type detection
915
- * - Design specs (colors, fonts, spacing)
916
- * - Slide structure and word limits
917
- * - Quality criteria and scoring
930
+ * CRITICAL: The Knowledge Base drives EVERYTHING.
931
+ * The KnowledgeGateway reads from presentation-knowledge.yaml at runtime.
932
+ * NO hardcoded fallbacks - if KB is missing data, we fail loudly.
918
933
  */
919
934
 
920
935
  interface DesignSpecs {
@@ -923,18 +938,30 @@ interface DesignSpecs {
923
938
  max: number;
924
939
  ideal: number;
925
940
  };
926
- whitespace: string;
941
+ whitespace: {
942
+ min: number;
943
+ max?: number;
944
+ ideal: number;
945
+ };
927
946
  bulletPoints: {
928
947
  max: number;
929
948
  };
930
949
  fonts: {
931
- title: number;
932
- body: number;
933
- minimum: number;
950
+ title: string;
951
+ body: string;
952
+ maxFonts: number;
934
953
  };
935
954
  theme: ThemeStyle;
936
955
  structure: string;
937
956
  experts: string[];
957
+ actionTitlesRequired: boolean;
958
+ sourcesRequired: boolean;
959
+ scoringWeights: {
960
+ visual_quality: number;
961
+ content_quality: number;
962
+ expert_compliance: number;
963
+ accessibility: number;
964
+ };
938
965
  }
939
966
  interface SlideReview {
940
967
  slideIndex: number;
@@ -977,11 +1004,15 @@ interface EngineResult {
977
1004
  }
978
1005
  declare class PresentationEngineV2 {
979
1006
  private options;
1007
+ private kb;
980
1008
  constructor(options?: EngineOptions);
981
1009
  private log;
982
1010
  /**
983
1011
  * Generate a world-class presentation from markdown content.
984
1012
  * Follows knowledge base specs and demands 95+ quality score.
1013
+ *
1014
+ * CRITICAL: All specs come from the Knowledge Base YAML at runtime.
1015
+ * No hardcoded fallbacks - if KB is missing data, we fail loudly.
985
1016
  */
986
1017
  generate(markdown: string, title?: string): Promise<EngineResult>;
987
1018
  /**
@@ -1207,6 +1238,8 @@ declare class SlideQualityReviewer {
1207
1238
  private whitespaceRules;
1208
1239
  private bulletLimit;
1209
1240
  private glanceTestSeconds;
1241
+ private assessmentWeights;
1242
+ private _loggedWeights;
1210
1243
  private hasCialdini;
1211
1244
  private hasGestalt;
1212
1245
  private hasTufteDataInk;
@@ -1753,7 +1786,7 @@ declare function runCodeQualityCheck(srcDir: string): Promise<boolean>;
1753
1786
  * ALL decisions come from the Knowledge Base. NO hardcoded fallbacks.
1754
1787
  */
1755
1788
 
1756
- declare const VERSION = "2.0.0";
1789
+ declare const VERSION = "4.1.0";
1757
1790
  interface GenerateOptions {
1758
1791
  /** Input content (Markdown, text, etc.) */
1759
1792
  content: string;
package/dist/index.d.ts CHANGED
@@ -692,10 +692,27 @@ interface MetricData {
692
692
  label: string;
693
693
  trend?: 'up' | 'down' | 'neutral';
694
694
  }
695
+ interface ModeConfig {
696
+ maxBulletsPerSlide: number;
697
+ maxWordsPerSlide: number;
698
+ minBulletsToKeep: number;
699
+ }
695
700
  declare class SlideGeneratorV2 {
696
701
  private config;
697
702
  private presentationType;
703
+ /**
704
+ * Create a slide generator with default configs.
705
+ * For KB-driven configs, use createSlideGeneratorV2WithConfig() instead.
706
+ */
698
707
  constructor(presentationType?: PresentationType);
708
+ /**
709
+ * Override config with KB-loaded values at runtime.
710
+ */
711
+ setConfig(config: ModeConfig): void;
712
+ /**
713
+ * Get current config (useful for debugging).
714
+ */
715
+ getConfig(): ModeConfig;
699
716
  /**
700
717
  * Generate slides from markdown content.
701
718
  * Simple, correct, no garbage.
@@ -904,17 +921,15 @@ declare function createRendererV2(presentationType?: PresentationType, themeOver
904
921
  *
905
922
  * This engine orchestrates the ENTIRE presentation creation flow:
906
923
  * 1. Analyze content to detect presentation type
907
- * 2. Load design specs from Knowledge Base
924
+ * 2. Load design specs from Knowledge Base (YAML)
908
925
  * 3. Generate slides following expert methodologies
909
926
  * 4. Enhance with images (optional, needs API key)
910
927
  * 5. Review ruthlessly (must score 95/100+)
911
928
  * 6. Output ONLY if quality passes
912
929
  *
913
- * The Knowledge Base drives EVERYTHING:
914
- * - Presentation type detection
915
- * - Design specs (colors, fonts, spacing)
916
- * - Slide structure and word limits
917
- * - Quality criteria and scoring
930
+ * CRITICAL: The Knowledge Base drives EVERYTHING.
931
+ * The KnowledgeGateway reads from presentation-knowledge.yaml at runtime.
932
+ * NO hardcoded fallbacks - if KB is missing data, we fail loudly.
918
933
  */
919
934
 
920
935
  interface DesignSpecs {
@@ -923,18 +938,30 @@ interface DesignSpecs {
923
938
  max: number;
924
939
  ideal: number;
925
940
  };
926
- whitespace: string;
941
+ whitespace: {
942
+ min: number;
943
+ max?: number;
944
+ ideal: number;
945
+ };
927
946
  bulletPoints: {
928
947
  max: number;
929
948
  };
930
949
  fonts: {
931
- title: number;
932
- body: number;
933
- minimum: number;
950
+ title: string;
951
+ body: string;
952
+ maxFonts: number;
934
953
  };
935
954
  theme: ThemeStyle;
936
955
  structure: string;
937
956
  experts: string[];
957
+ actionTitlesRequired: boolean;
958
+ sourcesRequired: boolean;
959
+ scoringWeights: {
960
+ visual_quality: number;
961
+ content_quality: number;
962
+ expert_compliance: number;
963
+ accessibility: number;
964
+ };
938
965
  }
939
966
  interface SlideReview {
940
967
  slideIndex: number;
@@ -977,11 +1004,15 @@ interface EngineResult {
977
1004
  }
978
1005
  declare class PresentationEngineV2 {
979
1006
  private options;
1007
+ private kb;
980
1008
  constructor(options?: EngineOptions);
981
1009
  private log;
982
1010
  /**
983
1011
  * Generate a world-class presentation from markdown content.
984
1012
  * Follows knowledge base specs and demands 95+ quality score.
1013
+ *
1014
+ * CRITICAL: All specs come from the Knowledge Base YAML at runtime.
1015
+ * No hardcoded fallbacks - if KB is missing data, we fail loudly.
985
1016
  */
986
1017
  generate(markdown: string, title?: string): Promise<EngineResult>;
987
1018
  /**
@@ -1207,6 +1238,8 @@ declare class SlideQualityReviewer {
1207
1238
  private whitespaceRules;
1208
1239
  private bulletLimit;
1209
1240
  private glanceTestSeconds;
1241
+ private assessmentWeights;
1242
+ private _loggedWeights;
1210
1243
  private hasCialdini;
1211
1244
  private hasGestalt;
1212
1245
  private hasTufteDataInk;
@@ -1753,7 +1786,7 @@ declare function runCodeQualityCheck(srcDir: string): Promise<boolean>;
1753
1786
  * ALL decisions come from the Knowledge Base. NO hardcoded fallbacks.
1754
1787
  */
1755
1788
 
1756
- declare const VERSION = "2.0.0";
1789
+ declare const VERSION = "4.1.0";
1757
1790
  interface GenerateOptions {
1758
1791
  /** Input content (Markdown, text, etc.) */
1759
1792
  content: string;
package/dist/index.js CHANGED
@@ -93756,21 +93756,52 @@ async function initSlideGenerator() {
93756
93756
 
93757
93757
  // src/core/SlideGeneratorV2.ts
93758
93758
  var import_marked = require("marked");
93759
- var MODE_CONFIGS = {
93760
- // Consulting decks: 40-80 words per slide is NORMAL
93759
+ var DEFAULT_CONFIGS = {
93760
+ // Consulting decks: 40-80 words per slide is NORMAL (from KB)
93761
93761
  consulting_deck: {
93762
93762
  maxBulletsPerSlide: 7,
93763
- maxWordsPerSlide: 100,
93764
- // Not 20!
93763
+ maxWordsPerSlide: 80,
93764
+ // KB: words_per_slide.max
93765
+ minBulletsToKeep: 3
93766
+ },
93767
+ investment_banking: {
93768
+ maxBulletsPerSlide: 8,
93769
+ maxWordsPerSlide: 120,
93770
+ // KB: words_per_slide.max
93765
93771
  minBulletsToKeep: 3
93766
93772
  },
93767
- // Keynotes: fewer words, more impact
93768
- keynote: {
93773
+ // Keynotes: fewer words, more impact (from KB)
93774
+ ted_keynote: {
93769
93775
  maxBulletsPerSlide: 4,
93776
+ maxWordsPerSlide: 15,
93777
+ // KB: words_per_slide.max
93778
+ minBulletsToKeep: 2
93779
+ },
93780
+ sales_pitch: {
93781
+ maxBulletsPerSlide: 5,
93770
93782
  maxWordsPerSlide: 30,
93783
+ // KB: words_per_slide.max
93784
+ minBulletsToKeep: 2
93785
+ },
93786
+ investor_pitch: {
93787
+ maxBulletsPerSlide: 5,
93788
+ maxWordsPerSlide: 50,
93789
+ // KB: words_per_slide.max
93790
+ minBulletsToKeep: 2
93791
+ },
93792
+ technical_presentation: {
93793
+ maxBulletsPerSlide: 6,
93794
+ maxWordsPerSlide: 100,
93795
+ // KB: words_per_slide.max
93796
+ minBulletsToKeep: 3
93797
+ },
93798
+ all_hands: {
93799
+ maxBulletsPerSlide: 5,
93800
+ maxWordsPerSlide: 40,
93801
+ // KB: words_per_slide.max
93771
93802
  minBulletsToKeep: 2
93772
93803
  },
93773
- // Default: consulting style
93804
+ // Default: fallback
93774
93805
  default: {
93775
93806
  maxBulletsPerSlide: 6,
93776
93807
  maxWordsPerSlide: 80,
@@ -93780,9 +93811,25 @@ var MODE_CONFIGS = {
93780
93811
  var SlideGeneratorV2 = class {
93781
93812
  config;
93782
93813
  presentationType;
93814
+ /**
93815
+ * Create a slide generator with default configs.
93816
+ * For KB-driven configs, use createSlideGeneratorV2WithConfig() instead.
93817
+ */
93783
93818
  constructor(presentationType = "consulting_deck") {
93784
93819
  this.presentationType = presentationType;
93785
- this.config = MODE_CONFIGS[presentationType] || MODE_CONFIGS.default;
93820
+ this.config = DEFAULT_CONFIGS[presentationType] || DEFAULT_CONFIGS.default;
93821
+ }
93822
+ /**
93823
+ * Override config with KB-loaded values at runtime.
93824
+ */
93825
+ setConfig(config2) {
93826
+ this.config = config2;
93827
+ }
93828
+ /**
93829
+ * Get current config (useful for debugging).
93830
+ */
93831
+ getConfig() {
93832
+ return this.config;
93786
93833
  }
93787
93834
  /**
93788
93835
  * Generate slides from markdown content.
@@ -95505,133 +95552,69 @@ function createRendererV2(presentationType = "consulting_deck", themeOverride) {
95505
95552
 
95506
95553
  // src/core/PresentationEngineV2.ts
95507
95554
  var import_fs9 = require("fs");
95508
- var KNOWLEDGE_BASE = {
95509
- // TED/Keynote - Minimal words, maximum impact
95510
- ted_keynote: {
95511
- wordsPerSlide: { min: 6, max: 25, ideal: 10 },
95512
- whitespace: "40%+",
95513
- bulletPoints: { max: 3 },
95514
- fonts: { title: 72, body: 42, minimum: 36 },
95515
- theme: "dark",
95516
- structure: "Sparkline (What Is / What Could Be)",
95517
- experts: ["Nancy Duarte", "Garr Reynolds", "Carmine Gallo", "Chris Anderson"]
95518
- },
95519
- // Sales Pitch - Persuasive, emotional, clear CTA
95520
- sales_pitch: {
95521
- wordsPerSlide: { min: 10, max: 35, ideal: 20 },
95522
- whitespace: "35%+",
95523
- bulletPoints: { max: 4 },
95524
- fonts: { title: 56, body: 32, minimum: 28 },
95525
- theme: "dark",
95526
- structure: "SPIN (Situation, Problem, Implication, Need-Payoff)",
95527
- experts: ["Cialdini", "Challenger Sale", "Oren Klaff"]
95528
- },
95529
- // Consulting Deck - Data-driven, McKinsey style
95530
- consulting_deck: {
95531
- wordsPerSlide: { min: 40, max: 80, ideal: 60 },
95532
- whitespace: "25-30%",
95533
- bulletPoints: { max: 7 },
95534
- fonts: { title: 44, body: 22, minimum: 18 },
95535
- theme: "mckinsey",
95536
- structure: "Pyramid Principle (MECE, SCR)",
95537
- experts: ["Barbara Minto", "McKinsey", "BCG", "Bain"]
95538
- },
95539
- // Investment Banking - Dense, financial, formal
95540
- investment_banking: {
95541
- wordsPerSlide: { min: 60, max: 120, ideal: 90 },
95542
- whitespace: "20-25%",
95543
- bulletPoints: { max: 8 },
95544
- fonts: { title: 28, body: 12, minimum: 10 },
95545
- theme: "mckinsey",
95546
- structure: "Situation-Complication-Hypothesis",
95547
- experts: ["Wall Street Prep", "Analyst Academy"]
95548
- },
95549
- // Investor Pitch - Concise, startup-friendly
95550
- investor_pitch: {
95551
- wordsPerSlide: { min: 5, max: 30, ideal: 15 },
95552
- whitespace: "35%+",
95553
- bulletPoints: { max: 4 },
95554
- fonts: { title: 48, body: 28, minimum: 24 },
95555
- theme: "startup",
95556
- structure: "Problem \u2192 Solution \u2192 Market \u2192 Traction \u2192 Team \u2192 Ask",
95557
- experts: ["Sequoia", "Y Combinator", "DocSend"]
95558
- },
95559
- // Technical Presentation - Clear diagrams, code-friendly
95560
- technical_presentation: {
95561
- wordsPerSlide: { min: 40, max: 100, ideal: 75 },
95562
- whitespace: "25%+",
95563
- bulletPoints: { max: 6 },
95564
- fonts: { title: 44, body: 20, minimum: 14 },
95565
- theme: "dark",
95566
- structure: "TL;DR \u2192 Problem \u2192 Architecture \u2192 Tradeoffs \u2192 Next Steps",
95567
- experts: ["Edward Tufte", "C4 Model", "Google Design Docs"]
95568
- },
95569
- // All Hands - Accessible, clear, motivational
95570
- all_hands: {
95571
- wordsPerSlide: { min: 15, max: 40, ideal: 25 },
95572
- whitespace: "30%+",
95573
- bulletPoints: { max: 5 },
95574
- fonts: { title: 52, body: 28, minimum: 24 },
95575
- theme: "minimal",
95576
- structure: "Updates \u2192 Wins \u2192 Challenges \u2192 What's Next",
95577
- experts: ["Internal Communications Best Practices"]
95578
- }
95555
+ var PALETTE_TO_THEME = {
95556
+ dark_executive: "dark",
95557
+ modern_business: "startup",
95558
+ consulting_classic: "mckinsey",
95559
+ executive_professional: "mckinsey",
95560
+ strategy_growth: "minimal"
95579
95561
  };
95580
- var QUALITY_CRITERIA = {
95581
- ted_keynote: {
95582
- glanceTestSeconds: 3,
95583
- minScore: 95,
95584
- wordLimitStrict: true,
95585
- requireActionTitles: false,
95586
- requireDataSources: false
95587
- },
95588
- sales_pitch: {
95589
- glanceTestSeconds: 3,
95590
- minScore: 95,
95591
- wordLimitStrict: true,
95592
- requireActionTitles: true,
95593
- requireDataSources: false
95594
- },
95595
- consulting_deck: {
95596
- glanceTestSeconds: 5,
95597
- minScore: 95,
95598
- wordLimitStrict: false,
95599
- // Consulting allows denser slides
95600
- requireActionTitles: true,
95601
- // Titles should state the "so what"
95602
- requireDataSources: true
95603
- },
95604
- investment_banking: {
95605
- glanceTestSeconds: 10,
95606
- minScore: 95,
95607
- wordLimitStrict: false,
95608
- requireActionTitles: true,
95609
- requireDataSources: true
95610
- },
95611
- investor_pitch: {
95612
- glanceTestSeconds: 3,
95613
- minScore: 95,
95614
- wordLimitStrict: true,
95615
- requireActionTitles: true,
95616
- requireDataSources: true
95617
- },
95618
- technical_presentation: {
95619
- glanceTestSeconds: 5,
95620
- minScore: 95,
95621
- wordLimitStrict: false,
95622
- requireActionTitles: false,
95623
- requireDataSources: true
95624
- },
95625
- all_hands: {
95626
- glanceTestSeconds: 3,
95627
- minScore: 95,
95628
- wordLimitStrict: true,
95629
- requireActionTitles: false,
95630
- requireDataSources: false
95562
+ async function loadDesignSpecsFromKB(kb, type) {
95563
+ const typeConfig = kb.queryRequired(`presentation_types.${type}`);
95564
+ const validationRules = typeConfig.value.validation_rules;
95565
+ const wordsPerSlide = validationRules.words_per_slide;
95566
+ const whitespace = validationRules.whitespace;
95567
+ const bulletsPerSlide = validationRules.bullets_per_slide;
95568
+ const typography = typeConfig.value.typography;
95569
+ const primaryExperts = typeConfig.value.primary_experts;
95570
+ const colorPalette = typeConfig.value.color_palette || "consulting_classic";
95571
+ const theme = PALETTE_TO_THEME[colorPalette] || "mckinsey";
95572
+ const scoringWeights = typeConfig.value.scoring_weights;
95573
+ let structure = "General presentation structure";
95574
+ if (primaryExperts.some((e) => e.includes("Minto") || e.includes("McKinsey"))) {
95575
+ structure = "Pyramid Principle (MECE, SCR)";
95576
+ } else if (primaryExperts.some((e) => e.includes("Duarte"))) {
95577
+ structure = "Sparkline (What Is / What Could Be)";
95578
+ } else if (primaryExperts.some((e) => e.includes("Cialdini"))) {
95579
+ structure = "Persuasion-driven (SPIN, Challenger)";
95631
95580
  }
95632
- };
95581
+ return {
95582
+ wordsPerSlide,
95583
+ whitespace,
95584
+ bulletPoints: { max: bulletsPerSlide?.max || 5 },
95585
+ fonts: {
95586
+ title: typography?.titles || "44px, Bold",
95587
+ body: typography?.body || "22px",
95588
+ maxFonts: typography?.max_fonts || 2
95589
+ },
95590
+ theme,
95591
+ structure,
95592
+ experts: primaryExperts,
95593
+ actionTitlesRequired: validationRules.action_titles_required || false,
95594
+ sourcesRequired: validationRules.sources_required || false,
95595
+ scoringWeights: scoringWeights || {
95596
+ visual_quality: 30,
95597
+ content_quality: 30,
95598
+ expert_compliance: 30,
95599
+ accessibility: 10
95600
+ }
95601
+ };
95602
+ }
95603
+ function getQualityCriteria(specs, type) {
95604
+ const isKeynote = type === "ted_keynote" || type === "sales_pitch";
95605
+ const isConsulting = type === "consulting_deck" || type === "investment_banking";
95606
+ return {
95607
+ glanceTestSeconds: isKeynote ? 3 : isConsulting ? 5 : 3,
95608
+ minScore: 95,
95609
+ wordLimitStrict: isKeynote,
95610
+ // Keynotes have strict word limits
95611
+ requireActionTitles: specs.actionTitlesRequired,
95612
+ requireDataSources: specs.sourcesRequired
95613
+ };
95614
+ }
95633
95615
  var PresentationEngineV2 = class {
95634
95616
  options;
95617
+ kb = null;
95635
95618
  constructor(options = {}) {
95636
95619
  this.options = {
95637
95620
  presentationType: options.presentationType || "consulting_deck",
@@ -95650,19 +95633,26 @@ var PresentationEngineV2 = class {
95650
95633
  /**
95651
95634
  * Generate a world-class presentation from markdown content.
95652
95635
  * Follows knowledge base specs and demands 95+ quality score.
95636
+ *
95637
+ * CRITICAL: All specs come from the Knowledge Base YAML at runtime.
95638
+ * No hardcoded fallbacks - if KB is missing data, we fail loudly.
95653
95639
  */
95654
95640
  async generate(markdown, title) {
95655
95641
  const warnings = [];
95642
+ this.log("Step 0: Loading Knowledge Base...");
95643
+ this.kb = await initKB();
95644
+ this.log(` KB v${this.kb.getVersion()} loaded`);
95656
95645
  this.log("Step 1: Detecting presentation type...");
95657
95646
  const detectedType = this.detectPresentationType(markdown);
95658
95647
  const presentationType = this.options.presentationType || detectedType;
95659
95648
  this.log(` Using type: ${presentationType} (detected: ${detectedType})`);
95660
95649
  this.log("Step 2: Loading design specs from Knowledge Base...");
95661
- const designSpecs = KNOWLEDGE_BASE[presentationType];
95662
- const qualityCriteria = QUALITY_CRITERIA[presentationType];
95650
+ const designSpecs = await loadDesignSpecsFromKB(this.kb, presentationType);
95651
+ const qualityCriteria = getQualityCriteria(designSpecs, presentationType);
95663
95652
  this.log(` Theme: ${designSpecs.theme}`);
95664
95653
  this.log(` Structure: ${designSpecs.structure}`);
95665
95654
  this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
95655
+ this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
95666
95656
  this.log("Step 3: Generating slides...");
95667
95657
  const generator = createSlideGeneratorV2(presentationType);
95668
95658
  let slides = generator.generate(markdown, title);
@@ -95990,7 +95980,6 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
95990
95980
  * Assess the flow and narrative structure of the deck.
95991
95981
  */
95992
95982
  assessFlow(slides, type) {
95993
- const specs = KNOWLEDGE_BASE[type];
95994
95983
  let score = 100;
95995
95984
  const types = slides.map((s) => s.type);
95996
95985
  if (types[0] !== "title") score -= 10;
@@ -96072,7 +96061,7 @@ Output: ${htmlPath}`);
96072
96061
  }
96073
96062
 
96074
96063
  // src/qa/SlideQualityReviewer.ts
96075
- var ASSESSMENT_WEIGHTS = {
96064
+ var DEFAULT_ASSESSMENT_WEIGHTS = {
96076
96065
  visualImpact: 0.25,
96077
96066
  contentClarity: 0.2,
96078
96067
  layoutBalance: 0.15,
@@ -96081,6 +96070,29 @@ var ASSESSMENT_WEIGHTS = {
96081
96070
  colorHarmony: 0.1,
96082
96071
  audienceAppropriate: 0.05
96083
96072
  };
96073
+ function computeWeightsFromKB(kbWeights) {
96074
+ const totalKB = kbWeights.visual_quality + kbWeights.content_quality + kbWeights.expert_compliance + kbWeights.accessibility;
96075
+ const vq = kbWeights.visual_quality / totalKB;
96076
+ const cq = kbWeights.content_quality / totalKB;
96077
+ const ec = kbWeights.expert_compliance / totalKB;
96078
+ const ac = kbWeights.accessibility / totalKB;
96079
+ return {
96080
+ visualImpact: vq * 0.6,
96081
+ // 60% of visual_quality
96082
+ colorHarmony: vq * 0.4,
96083
+ // 40% of visual_quality
96084
+ contentClarity: cq * 0.8,
96085
+ // 80% of content_quality
96086
+ audienceAppropriate: cq * 0.2,
96087
+ // 20% of content_quality
96088
+ layoutBalance: ec * 0.5,
96089
+ // 50% of expert_compliance
96090
+ typographyHierarchy: ec * 0.5,
96091
+ // 50% of expert_compliance
96092
+ whitespaceUsage: ac
96093
+ // 100% of accessibility
96094
+ };
96095
+ }
96084
96096
  var SlideQualityReviewer = class {
96085
96097
  kb;
96086
96098
  initialized = false;
@@ -96089,6 +96101,9 @@ var SlideQualityReviewer = class {
96089
96101
  whitespaceRules;
96090
96102
  bulletLimit;
96091
96103
  glanceTestSeconds;
96104
+ // KB-loaded scoring weights (computed from KB per presentation type)
96105
+ assessmentWeights = DEFAULT_ASSESSMENT_WEIGHTS;
96106
+ _loggedWeights = null;
96092
96107
  // Expert rules from KB
96093
96108
  hasCialdini = false;
96094
96109
  hasGestalt = false;
@@ -96119,7 +96134,7 @@ var SlideQualityReviewer = class {
96119
96134
  };
96120
96135
  let totalScore = 0;
96121
96136
  for (const [key, assessment] of Object.entries(assessments)) {
96122
- const weight = ASSESSMENT_WEIGHTS[key];
96137
+ const weight = this.assessmentWeights[key];
96123
96138
  totalScore += assessment.score * weight;
96124
96139
  }
96125
96140
  const score = Math.round(totalScore);
@@ -96174,6 +96189,18 @@ var SlideQualityReviewer = class {
96174
96189
  this.wordLimits = wordLimitsResult.value;
96175
96190
  const whitespaceResult = this.kb.getWhitespaceRules(type);
96176
96191
  this.whitespaceRules = whitespaceResult.value;
96192
+ try {
96193
+ const weightsResult = this.kb.getScoringWeights(type);
96194
+ const kbWeights = weightsResult.value;
96195
+ this.assessmentWeights = computeWeightsFromKB(kbWeights);
96196
+ if (!this._loggedWeights?.has(type)) {
96197
+ console.log(`[QA] Loaded scoring weights for ${type}: visual=${kbWeights.visual_quality}%, content=${kbWeights.content_quality}%, expert=${kbWeights.expert_compliance}%, accessibility=${kbWeights.accessibility}%`);
96198
+ if (!this._loggedWeights) this._loggedWeights = /* @__PURE__ */ new Set();
96199
+ this._loggedWeights.add(type);
96200
+ }
96201
+ } catch {
96202
+ this.assessmentWeights = DEFAULT_ASSESSMENT_WEIGHTS;
96203
+ }
96177
96204
  try {
96178
96205
  const glanceResult = this.kb.getGlanceTest();
96179
96206
  this.glanceTestSeconds = 3;
@@ -99467,7 +99494,7 @@ if (typeof process !== "undefined" && process.argv[1]?.includes("CodeQualityVali
99467
99494
  }
99468
99495
 
99469
99496
  // src/index.ts
99470
- var VERSION = "2.0.0";
99497
+ var VERSION = "4.1.0";
99471
99498
  async function generate(options) {
99472
99499
  const {
99473
99500
  content,
package/dist/index.mjs CHANGED
@@ -2040,21 +2040,52 @@ async function initSlideGenerator() {
2040
2040
 
2041
2041
  // src/core/SlideGeneratorV2.ts
2042
2042
  import { marked } from "marked";
2043
- var MODE_CONFIGS = {
2044
- // Consulting decks: 40-80 words per slide is NORMAL
2043
+ var DEFAULT_CONFIGS = {
2044
+ // Consulting decks: 40-80 words per slide is NORMAL (from KB)
2045
2045
  consulting_deck: {
2046
2046
  maxBulletsPerSlide: 7,
2047
- maxWordsPerSlide: 100,
2048
- // Not 20!
2047
+ maxWordsPerSlide: 80,
2048
+ // KB: words_per_slide.max
2049
+ minBulletsToKeep: 3
2050
+ },
2051
+ investment_banking: {
2052
+ maxBulletsPerSlide: 8,
2053
+ maxWordsPerSlide: 120,
2054
+ // KB: words_per_slide.max
2049
2055
  minBulletsToKeep: 3
2050
2056
  },
2051
- // Keynotes: fewer words, more impact
2052
- keynote: {
2057
+ // Keynotes: fewer words, more impact (from KB)
2058
+ ted_keynote: {
2053
2059
  maxBulletsPerSlide: 4,
2060
+ maxWordsPerSlide: 15,
2061
+ // KB: words_per_slide.max
2062
+ minBulletsToKeep: 2
2063
+ },
2064
+ sales_pitch: {
2065
+ maxBulletsPerSlide: 5,
2054
2066
  maxWordsPerSlide: 30,
2067
+ // KB: words_per_slide.max
2068
+ minBulletsToKeep: 2
2069
+ },
2070
+ investor_pitch: {
2071
+ maxBulletsPerSlide: 5,
2072
+ maxWordsPerSlide: 50,
2073
+ // KB: words_per_slide.max
2074
+ minBulletsToKeep: 2
2075
+ },
2076
+ technical_presentation: {
2077
+ maxBulletsPerSlide: 6,
2078
+ maxWordsPerSlide: 100,
2079
+ // KB: words_per_slide.max
2080
+ minBulletsToKeep: 3
2081
+ },
2082
+ all_hands: {
2083
+ maxBulletsPerSlide: 5,
2084
+ maxWordsPerSlide: 40,
2085
+ // KB: words_per_slide.max
2055
2086
  minBulletsToKeep: 2
2056
2087
  },
2057
- // Default: consulting style
2088
+ // Default: fallback
2058
2089
  default: {
2059
2090
  maxBulletsPerSlide: 6,
2060
2091
  maxWordsPerSlide: 80,
@@ -2064,9 +2095,25 @@ var MODE_CONFIGS = {
2064
2095
  var SlideGeneratorV2 = class {
2065
2096
  config;
2066
2097
  presentationType;
2098
+ /**
2099
+ * Create a slide generator with default configs.
2100
+ * For KB-driven configs, use createSlideGeneratorV2WithConfig() instead.
2101
+ */
2067
2102
  constructor(presentationType = "consulting_deck") {
2068
2103
  this.presentationType = presentationType;
2069
- this.config = MODE_CONFIGS[presentationType] || MODE_CONFIGS.default;
2104
+ this.config = DEFAULT_CONFIGS[presentationType] || DEFAULT_CONFIGS.default;
2105
+ }
2106
+ /**
2107
+ * Override config with KB-loaded values at runtime.
2108
+ */
2109
+ setConfig(config) {
2110
+ this.config = config;
2111
+ }
2112
+ /**
2113
+ * Get current config (useful for debugging).
2114
+ */
2115
+ getConfig() {
2116
+ return this.config;
2070
2117
  }
2071
2118
  /**
2072
2119
  * Generate slides from markdown content.
@@ -3789,133 +3836,69 @@ function createRendererV2(presentationType = "consulting_deck", themeOverride) {
3789
3836
 
3790
3837
  // src/core/PresentationEngineV2.ts
3791
3838
  import { writeFileSync as writeFileSync2 } from "fs";
3792
- var KNOWLEDGE_BASE = {
3793
- // TED/Keynote - Minimal words, maximum impact
3794
- ted_keynote: {
3795
- wordsPerSlide: { min: 6, max: 25, ideal: 10 },
3796
- whitespace: "40%+",
3797
- bulletPoints: { max: 3 },
3798
- fonts: { title: 72, body: 42, minimum: 36 },
3799
- theme: "dark",
3800
- structure: "Sparkline (What Is / What Could Be)",
3801
- experts: ["Nancy Duarte", "Garr Reynolds", "Carmine Gallo", "Chris Anderson"]
3802
- },
3803
- // Sales Pitch - Persuasive, emotional, clear CTA
3804
- sales_pitch: {
3805
- wordsPerSlide: { min: 10, max: 35, ideal: 20 },
3806
- whitespace: "35%+",
3807
- bulletPoints: { max: 4 },
3808
- fonts: { title: 56, body: 32, minimum: 28 },
3809
- theme: "dark",
3810
- structure: "SPIN (Situation, Problem, Implication, Need-Payoff)",
3811
- experts: ["Cialdini", "Challenger Sale", "Oren Klaff"]
3812
- },
3813
- // Consulting Deck - Data-driven, McKinsey style
3814
- consulting_deck: {
3815
- wordsPerSlide: { min: 40, max: 80, ideal: 60 },
3816
- whitespace: "25-30%",
3817
- bulletPoints: { max: 7 },
3818
- fonts: { title: 44, body: 22, minimum: 18 },
3819
- theme: "mckinsey",
3820
- structure: "Pyramid Principle (MECE, SCR)",
3821
- experts: ["Barbara Minto", "McKinsey", "BCG", "Bain"]
3822
- },
3823
- // Investment Banking - Dense, financial, formal
3824
- investment_banking: {
3825
- wordsPerSlide: { min: 60, max: 120, ideal: 90 },
3826
- whitespace: "20-25%",
3827
- bulletPoints: { max: 8 },
3828
- fonts: { title: 28, body: 12, minimum: 10 },
3829
- theme: "mckinsey",
3830
- structure: "Situation-Complication-Hypothesis",
3831
- experts: ["Wall Street Prep", "Analyst Academy"]
3832
- },
3833
- // Investor Pitch - Concise, startup-friendly
3834
- investor_pitch: {
3835
- wordsPerSlide: { min: 5, max: 30, ideal: 15 },
3836
- whitespace: "35%+",
3837
- bulletPoints: { max: 4 },
3838
- fonts: { title: 48, body: 28, minimum: 24 },
3839
- theme: "startup",
3840
- structure: "Problem \u2192 Solution \u2192 Market \u2192 Traction \u2192 Team \u2192 Ask",
3841
- experts: ["Sequoia", "Y Combinator", "DocSend"]
3842
- },
3843
- // Technical Presentation - Clear diagrams, code-friendly
3844
- technical_presentation: {
3845
- wordsPerSlide: { min: 40, max: 100, ideal: 75 },
3846
- whitespace: "25%+",
3847
- bulletPoints: { max: 6 },
3848
- fonts: { title: 44, body: 20, minimum: 14 },
3849
- theme: "dark",
3850
- structure: "TL;DR \u2192 Problem \u2192 Architecture \u2192 Tradeoffs \u2192 Next Steps",
3851
- experts: ["Edward Tufte", "C4 Model", "Google Design Docs"]
3852
- },
3853
- // All Hands - Accessible, clear, motivational
3854
- all_hands: {
3855
- wordsPerSlide: { min: 15, max: 40, ideal: 25 },
3856
- whitespace: "30%+",
3857
- bulletPoints: { max: 5 },
3858
- fonts: { title: 52, body: 28, minimum: 24 },
3859
- theme: "minimal",
3860
- structure: "Updates \u2192 Wins \u2192 Challenges \u2192 What's Next",
3861
- experts: ["Internal Communications Best Practices"]
3862
- }
3839
+ var PALETTE_TO_THEME = {
3840
+ dark_executive: "dark",
3841
+ modern_business: "startup",
3842
+ consulting_classic: "mckinsey",
3843
+ executive_professional: "mckinsey",
3844
+ strategy_growth: "minimal"
3863
3845
  };
3864
- var QUALITY_CRITERIA = {
3865
- ted_keynote: {
3866
- glanceTestSeconds: 3,
3867
- minScore: 95,
3868
- wordLimitStrict: true,
3869
- requireActionTitles: false,
3870
- requireDataSources: false
3871
- },
3872
- sales_pitch: {
3873
- glanceTestSeconds: 3,
3874
- minScore: 95,
3875
- wordLimitStrict: true,
3876
- requireActionTitles: true,
3877
- requireDataSources: false
3878
- },
3879
- consulting_deck: {
3880
- glanceTestSeconds: 5,
3881
- minScore: 95,
3882
- wordLimitStrict: false,
3883
- // Consulting allows denser slides
3884
- requireActionTitles: true,
3885
- // Titles should state the "so what"
3886
- requireDataSources: true
3887
- },
3888
- investment_banking: {
3889
- glanceTestSeconds: 10,
3890
- minScore: 95,
3891
- wordLimitStrict: false,
3892
- requireActionTitles: true,
3893
- requireDataSources: true
3894
- },
3895
- investor_pitch: {
3896
- glanceTestSeconds: 3,
3897
- minScore: 95,
3898
- wordLimitStrict: true,
3899
- requireActionTitles: true,
3900
- requireDataSources: true
3901
- },
3902
- technical_presentation: {
3903
- glanceTestSeconds: 5,
3904
- minScore: 95,
3905
- wordLimitStrict: false,
3906
- requireActionTitles: false,
3907
- requireDataSources: true
3908
- },
3909
- all_hands: {
3910
- glanceTestSeconds: 3,
3911
- minScore: 95,
3912
- wordLimitStrict: true,
3913
- requireActionTitles: false,
3914
- requireDataSources: false
3846
+ async function loadDesignSpecsFromKB(kb, type) {
3847
+ const typeConfig = kb.queryRequired(`presentation_types.${type}`);
3848
+ const validationRules = typeConfig.value.validation_rules;
3849
+ const wordsPerSlide = validationRules.words_per_slide;
3850
+ const whitespace = validationRules.whitespace;
3851
+ const bulletsPerSlide = validationRules.bullets_per_slide;
3852
+ const typography = typeConfig.value.typography;
3853
+ const primaryExperts = typeConfig.value.primary_experts;
3854
+ const colorPalette = typeConfig.value.color_palette || "consulting_classic";
3855
+ const theme = PALETTE_TO_THEME[colorPalette] || "mckinsey";
3856
+ const scoringWeights = typeConfig.value.scoring_weights;
3857
+ let structure = "General presentation structure";
3858
+ if (primaryExperts.some((e) => e.includes("Minto") || e.includes("McKinsey"))) {
3859
+ structure = "Pyramid Principle (MECE, SCR)";
3860
+ } else if (primaryExperts.some((e) => e.includes("Duarte"))) {
3861
+ structure = "Sparkline (What Is / What Could Be)";
3862
+ } else if (primaryExperts.some((e) => e.includes("Cialdini"))) {
3863
+ structure = "Persuasion-driven (SPIN, Challenger)";
3915
3864
  }
3916
- };
3865
+ return {
3866
+ wordsPerSlide,
3867
+ whitespace,
3868
+ bulletPoints: { max: bulletsPerSlide?.max || 5 },
3869
+ fonts: {
3870
+ title: typography?.titles || "44px, Bold",
3871
+ body: typography?.body || "22px",
3872
+ maxFonts: typography?.max_fonts || 2
3873
+ },
3874
+ theme,
3875
+ structure,
3876
+ experts: primaryExperts,
3877
+ actionTitlesRequired: validationRules.action_titles_required || false,
3878
+ sourcesRequired: validationRules.sources_required || false,
3879
+ scoringWeights: scoringWeights || {
3880
+ visual_quality: 30,
3881
+ content_quality: 30,
3882
+ expert_compliance: 30,
3883
+ accessibility: 10
3884
+ }
3885
+ };
3886
+ }
3887
+ function getQualityCriteria(specs, type) {
3888
+ const isKeynote = type === "ted_keynote" || type === "sales_pitch";
3889
+ const isConsulting = type === "consulting_deck" || type === "investment_banking";
3890
+ return {
3891
+ glanceTestSeconds: isKeynote ? 3 : isConsulting ? 5 : 3,
3892
+ minScore: 95,
3893
+ wordLimitStrict: isKeynote,
3894
+ // Keynotes have strict word limits
3895
+ requireActionTitles: specs.actionTitlesRequired,
3896
+ requireDataSources: specs.sourcesRequired
3897
+ };
3898
+ }
3917
3899
  var PresentationEngineV2 = class {
3918
3900
  options;
3901
+ kb = null;
3919
3902
  constructor(options = {}) {
3920
3903
  this.options = {
3921
3904
  presentationType: options.presentationType || "consulting_deck",
@@ -3934,19 +3917,26 @@ var PresentationEngineV2 = class {
3934
3917
  /**
3935
3918
  * Generate a world-class presentation from markdown content.
3936
3919
  * Follows knowledge base specs and demands 95+ quality score.
3920
+ *
3921
+ * CRITICAL: All specs come from the Knowledge Base YAML at runtime.
3922
+ * No hardcoded fallbacks - if KB is missing data, we fail loudly.
3937
3923
  */
3938
3924
  async generate(markdown, title) {
3939
3925
  const warnings = [];
3926
+ this.log("Step 0: Loading Knowledge Base...");
3927
+ this.kb = await initKB();
3928
+ this.log(` KB v${this.kb.getVersion()} loaded`);
3940
3929
  this.log("Step 1: Detecting presentation type...");
3941
3930
  const detectedType = this.detectPresentationType(markdown);
3942
3931
  const presentationType = this.options.presentationType || detectedType;
3943
3932
  this.log(` Using type: ${presentationType} (detected: ${detectedType})`);
3944
3933
  this.log("Step 2: Loading design specs from Knowledge Base...");
3945
- const designSpecs = KNOWLEDGE_BASE[presentationType];
3946
- const qualityCriteria = QUALITY_CRITERIA[presentationType];
3934
+ const designSpecs = await loadDesignSpecsFromKB(this.kb, presentationType);
3935
+ const qualityCriteria = getQualityCriteria(designSpecs, presentationType);
3947
3936
  this.log(` Theme: ${designSpecs.theme}`);
3948
3937
  this.log(` Structure: ${designSpecs.structure}`);
3949
3938
  this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
3939
+ this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
3950
3940
  this.log("Step 3: Generating slides...");
3951
3941
  const generator = createSlideGeneratorV2(presentationType);
3952
3942
  let slides = generator.generate(markdown, title);
@@ -4274,7 +4264,6 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
4274
4264
  * Assess the flow and narrative structure of the deck.
4275
4265
  */
4276
4266
  assessFlow(slides, type) {
4277
- const specs = KNOWLEDGE_BASE[type];
4278
4267
  let score = 100;
4279
4268
  const types = slides.map((s) => s.type);
4280
4269
  if (types[0] !== "title") score -= 10;
@@ -4356,7 +4345,7 @@ Output: ${htmlPath}`);
4356
4345
  }
4357
4346
 
4358
4347
  // src/qa/SlideQualityReviewer.ts
4359
- var ASSESSMENT_WEIGHTS = {
4348
+ var DEFAULT_ASSESSMENT_WEIGHTS = {
4360
4349
  visualImpact: 0.25,
4361
4350
  contentClarity: 0.2,
4362
4351
  layoutBalance: 0.15,
@@ -4365,6 +4354,29 @@ var ASSESSMENT_WEIGHTS = {
4365
4354
  colorHarmony: 0.1,
4366
4355
  audienceAppropriate: 0.05
4367
4356
  };
4357
+ function computeWeightsFromKB(kbWeights) {
4358
+ const totalKB = kbWeights.visual_quality + kbWeights.content_quality + kbWeights.expert_compliance + kbWeights.accessibility;
4359
+ const vq = kbWeights.visual_quality / totalKB;
4360
+ const cq = kbWeights.content_quality / totalKB;
4361
+ const ec = kbWeights.expert_compliance / totalKB;
4362
+ const ac = kbWeights.accessibility / totalKB;
4363
+ return {
4364
+ visualImpact: vq * 0.6,
4365
+ // 60% of visual_quality
4366
+ colorHarmony: vq * 0.4,
4367
+ // 40% of visual_quality
4368
+ contentClarity: cq * 0.8,
4369
+ // 80% of content_quality
4370
+ audienceAppropriate: cq * 0.2,
4371
+ // 20% of content_quality
4372
+ layoutBalance: ec * 0.5,
4373
+ // 50% of expert_compliance
4374
+ typographyHierarchy: ec * 0.5,
4375
+ // 50% of expert_compliance
4376
+ whitespaceUsage: ac
4377
+ // 100% of accessibility
4378
+ };
4379
+ }
4368
4380
  var SlideQualityReviewer = class {
4369
4381
  kb;
4370
4382
  initialized = false;
@@ -4373,6 +4385,9 @@ var SlideQualityReviewer = class {
4373
4385
  whitespaceRules;
4374
4386
  bulletLimit;
4375
4387
  glanceTestSeconds;
4388
+ // KB-loaded scoring weights (computed from KB per presentation type)
4389
+ assessmentWeights = DEFAULT_ASSESSMENT_WEIGHTS;
4390
+ _loggedWeights = null;
4376
4391
  // Expert rules from KB
4377
4392
  hasCialdini = false;
4378
4393
  hasGestalt = false;
@@ -4403,7 +4418,7 @@ var SlideQualityReviewer = class {
4403
4418
  };
4404
4419
  let totalScore = 0;
4405
4420
  for (const [key, assessment] of Object.entries(assessments)) {
4406
- const weight = ASSESSMENT_WEIGHTS[key];
4421
+ const weight = this.assessmentWeights[key];
4407
4422
  totalScore += assessment.score * weight;
4408
4423
  }
4409
4424
  const score = Math.round(totalScore);
@@ -4458,6 +4473,18 @@ var SlideQualityReviewer = class {
4458
4473
  this.wordLimits = wordLimitsResult.value;
4459
4474
  const whitespaceResult = this.kb.getWhitespaceRules(type);
4460
4475
  this.whitespaceRules = whitespaceResult.value;
4476
+ try {
4477
+ const weightsResult = this.kb.getScoringWeights(type);
4478
+ const kbWeights = weightsResult.value;
4479
+ this.assessmentWeights = computeWeightsFromKB(kbWeights);
4480
+ if (!this._loggedWeights?.has(type)) {
4481
+ console.log(`[QA] Loaded scoring weights for ${type}: visual=${kbWeights.visual_quality}%, content=${kbWeights.content_quality}%, expert=${kbWeights.expert_compliance}%, accessibility=${kbWeights.accessibility}%`);
4482
+ if (!this._loggedWeights) this._loggedWeights = /* @__PURE__ */ new Set();
4483
+ this._loggedWeights.add(type);
4484
+ }
4485
+ } catch {
4486
+ this.assessmentWeights = DEFAULT_ASSESSMENT_WEIGHTS;
4487
+ }
4461
4488
  try {
4462
4489
  const glanceResult = this.kb.getGlanceTest();
4463
4490
  this.glanceTestSeconds = 3;
@@ -7751,7 +7778,7 @@ if (typeof process !== "undefined" && process.argv[1]?.includes("CodeQualityVali
7751
7778
  }
7752
7779
 
7753
7780
  // src/index.ts
7754
- var VERSION = "2.0.0";
7781
+ var VERSION = "4.1.0";
7755
7782
  async function generate(options) {
7756
7783
  const {
7757
7784
  content,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-presentation-master",
3
- "version": "3.9.0",
3
+ "version": "4.1.0",
4
4
  "description": "Generate world-class presentations using expert methodologies from Duarte, Reynolds, Gallo, and Anderson. Enforces rigorous quality standards through real visual validation.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",