claude-presentation-master 1.0.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/bin/cli.js ADDED
@@ -0,0 +1,445 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Claude Presentation Master CLI
5
+ *
6
+ * Generate world-class presentations from the command line.
7
+ *
8
+ * Usage:
9
+ * cpm generate input.md -o output/ --mode keynote --format html,pptx
10
+ * cpm validate presentation.html --mode business
11
+ * cpm --help
12
+ */
13
+
14
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
15
+ import { resolve, dirname, basename, extname } from 'path';
16
+ import { fileURLToPath } from 'url';
17
+
18
+ // Parse command line arguments
19
+ const args = process.argv.slice(2);
20
+
21
+ // Help text
22
+ const helpText = `
23
+ Claude Presentation Master v1.0.0
24
+ Generate world-class presentations using expert methodologies
25
+
26
+ USAGE:
27
+ cpm <command> [options]
28
+ claude-presentation-master <command> [options]
29
+
30
+ COMMANDS:
31
+ generate <input> Generate presentation from input file
32
+ validate <file> Validate an existing HTML presentation
33
+ info Show package information
34
+
35
+ OPTIONS:
36
+ -o, --output <dir> Output directory (default: ./output)
37
+ -m, --mode <mode> Presentation mode: keynote or business (default: keynote)
38
+ -f, --format <fmt> Output formats: html, pptx, or both (default: html)
39
+ -t, --theme <name> Theme: default, light-corporate, modern-tech, minimal, warm, creative
40
+ --title <title> Presentation title (default: filename)
41
+ --author <name> Author name
42
+ --threshold <num> QA score threshold 0-100 (default: 95)
43
+ --skip-qa Skip QA validation (NOT recommended)
44
+ -h, --help Show this help message
45
+ -v, --version Show version number
46
+
47
+ EXAMPLES:
48
+ # Generate keynote presentation as HTML
49
+ cpm generate presentation.md -m keynote
50
+
51
+ # Generate business presentation as both HTML and PPTX
52
+ cpm generate deck.md -m business -f html,pptx -o ./slides
53
+
54
+ # Validate an existing presentation
55
+ cpm validate output/presentation.html -m keynote
56
+
57
+ # Generate with custom theme
58
+ cpm generate content.md --theme modern-tech --title "Product Launch"
59
+
60
+ SUPPORTED INPUT FORMATS:
61
+ - Markdown (.md)
62
+ - JSON (.json)
63
+ - YAML (.yaml, .yml)
64
+ - Plain text (.txt)
65
+
66
+ For more information, visit: https://github.com/isovision/claude-presentation-master
67
+ `;
68
+
69
+ // Version
70
+ const version = '1.0.0';
71
+
72
+ // Parse arguments
73
+ function parseArgs(args) {
74
+ const options = {
75
+ command: null,
76
+ input: null,
77
+ output: './output',
78
+ mode: 'keynote',
79
+ format: ['html'],
80
+ theme: 'default',
81
+ title: null,
82
+ author: null,
83
+ threshold: 95,
84
+ skipQA: false,
85
+ help: false,
86
+ version: false
87
+ };
88
+
89
+ let i = 0;
90
+ while (i < args.length) {
91
+ const arg = args[i];
92
+
93
+ switch (arg) {
94
+ case '-h':
95
+ case '--help':
96
+ options.help = true;
97
+ break;
98
+
99
+ case '-v':
100
+ case '--version':
101
+ options.version = true;
102
+ break;
103
+
104
+ case '-o':
105
+ case '--output':
106
+ options.output = args[++i];
107
+ break;
108
+
109
+ case '-m':
110
+ case '--mode':
111
+ options.mode = args[++i];
112
+ break;
113
+
114
+ case '-f':
115
+ case '--format':
116
+ options.format = args[++i].split(',').map(f => f.trim());
117
+ break;
118
+
119
+ case '-t':
120
+ case '--theme':
121
+ options.theme = args[++i];
122
+ break;
123
+
124
+ case '--title':
125
+ options.title = args[++i];
126
+ break;
127
+
128
+ case '--author':
129
+ options.author = args[++i];
130
+ break;
131
+
132
+ case '--threshold':
133
+ options.threshold = parseInt(args[++i], 10);
134
+ break;
135
+
136
+ case '--skip-qa':
137
+ options.skipQA = true;
138
+ break;
139
+
140
+ case 'generate':
141
+ case 'validate':
142
+ case 'info':
143
+ options.command = arg;
144
+ break;
145
+
146
+ default:
147
+ if (!arg.startsWith('-') && !options.input) {
148
+ options.input = arg;
149
+ }
150
+ break;
151
+ }
152
+ i++;
153
+ }
154
+
155
+ return options;
156
+ }
157
+
158
+ // Determine content type from file extension
159
+ function getContentType(filename) {
160
+ const ext = extname(filename).toLowerCase();
161
+ switch (ext) {
162
+ case '.md':
163
+ case '.markdown':
164
+ return 'markdown';
165
+ case '.json':
166
+ return 'json';
167
+ case '.yaml':
168
+ case '.yml':
169
+ return 'yaml';
170
+ default:
171
+ return 'text';
172
+ }
173
+ }
174
+
175
+ // Main function
176
+ async function main() {
177
+ const options = parseArgs(args);
178
+
179
+ // Handle help
180
+ if (options.help || args.length === 0) {
181
+ console.log(helpText);
182
+ process.exit(0);
183
+ }
184
+
185
+ // Handle version
186
+ if (options.version) {
187
+ console.log(`Claude Presentation Master v${version}`);
188
+ process.exit(0);
189
+ }
190
+
191
+ // Handle info command
192
+ if (options.command === 'info') {
193
+ console.log(`
194
+ Claude Presentation Master v${version}
195
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
196
+
197
+ Author: Stuart Kerr <stuart@isovision.ai>
198
+ License: MIT
199
+
200
+ Features:
201
+ ✓ Expert methodologies (Duarte, Reynolds, Gallo, Anderson)
202
+ ✓ Two modes: Keynote (6-25 words) & Business (40-80 words)
203
+ ✓ HTML (Reveal.js) + PowerPoint output
204
+ ✓ Real visual QA with Playwright
205
+ ✓ 95/100 minimum score enforcement
206
+ ✓ No API keys required (optional enhancements available)
207
+
208
+ Media Providers (all work without API keys):
209
+ Images: Placeholder, Unsplash Source, Local files
210
+ Charts: Chart.js (HTML), QuickChart (PPTX)
211
+ Diagrams: Mermaid.js
212
+
213
+ Expert Knowledge Base:
214
+ • 6,300+ lines of expert principles
215
+ • 40+ presentation experts
216
+ • SCQA, Sparkline, STAR Moment frameworks
217
+ • Automated framework selection
218
+ `);
219
+ process.exit(0);
220
+ }
221
+
222
+ // Validate command
223
+ if (!options.command) {
224
+ console.error('Error: No command specified. Use "generate" or "validate".');
225
+ console.error('Run "cpm --help" for usage information.');
226
+ process.exit(1);
227
+ }
228
+
229
+ // Validate input
230
+ if (!options.input) {
231
+ console.error(`Error: No input file specified for "${options.command}" command.`);
232
+ process.exit(1);
233
+ }
234
+
235
+ // Resolve input path
236
+ const inputPath = resolve(process.cwd(), options.input);
237
+ if (!existsSync(inputPath)) {
238
+ console.error(`Error: Input file not found: ${inputPath}`);
239
+ process.exit(1);
240
+ }
241
+
242
+ // Dynamic import of the library
243
+ console.log('📦 Loading Claude Presentation Master...');
244
+
245
+ try {
246
+ const { generate, validate } = await import('../dist/index.js');
247
+
248
+ if (options.command === 'generate') {
249
+ await runGenerate(inputPath, options, generate);
250
+ } else if (options.command === 'validate') {
251
+ await runValidate(inputPath, options, validate);
252
+ }
253
+ } catch (error) {
254
+ if (error.code === 'ERR_MODULE_NOT_FOUND') {
255
+ console.error('Error: Package not built. Run "npm run build" first.');
256
+ process.exit(1);
257
+ }
258
+ throw error;
259
+ }
260
+ }
261
+
262
+ // Generate command
263
+ async function runGenerate(inputPath, options, generate) {
264
+ console.log(`
265
+ ╔════════════════════════════════════════════════════════╗
266
+ ║ Claude Presentation Master ║
267
+ ║ Generating World-Class Presentation ║
268
+ ╚════════════════════════════════════════════════════════╝
269
+ `);
270
+
271
+ // Read input file
272
+ console.log(`📄 Reading: ${inputPath}`);
273
+ const content = readFileSync(inputPath, 'utf-8');
274
+
275
+ // Determine title
276
+ const title = options.title || basename(inputPath, extname(inputPath));
277
+
278
+ // Build config
279
+ const config = {
280
+ content,
281
+ contentType: getContentType(inputPath),
282
+ mode: options.mode,
283
+ format: options.format,
284
+ theme: options.theme,
285
+ title,
286
+ author: options.author,
287
+ qaThreshold: options.threshold,
288
+ skipQA: options.skipQA
289
+ };
290
+
291
+ console.log(`
292
+ 📋 Configuration:
293
+ Mode: ${options.mode}
294
+ Format: ${options.format.join(', ')}
295
+ Theme: ${options.theme}
296
+ Title: ${title}
297
+ Threshold: ${options.threshold}/100
298
+ Skip QA: ${options.skipQA ? 'Yes (NOT RECOMMENDED)' : 'No'}
299
+ `);
300
+
301
+ try {
302
+ // Generate presentation
303
+ const result = await generate(config);
304
+
305
+ // Create output directory
306
+ const outputDir = resolve(process.cwd(), options.output);
307
+ if (!existsSync(outputDir)) {
308
+ mkdirSync(outputDir, { recursive: true });
309
+ }
310
+
311
+ // Write outputs
312
+ const baseFilename = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
313
+
314
+ if (result.outputs.html) {
315
+ const htmlPath = resolve(outputDir, `${baseFilename}.html`);
316
+ writeFileSync(htmlPath, result.outputs.html);
317
+ console.log(`✅ HTML saved: ${htmlPath}`);
318
+ }
319
+
320
+ if (result.outputs.pptx) {
321
+ const pptxPath = resolve(outputDir, `${baseFilename}.pptx`);
322
+ writeFileSync(pptxPath, result.outputs.pptx);
323
+ console.log(`✅ PPTX saved: ${pptxPath}`);
324
+ }
325
+
326
+ // Show results
327
+ console.log(`
328
+ ╔════════════════════════════════════════════════════════╗
329
+ ║ QA RESULTS ║
330
+ ╚════════════════════════════════════════════════════════╝
331
+
332
+ 📊 Score: ${result.score}/100 ${result.score >= options.threshold ? '✅ PASSED' : '❌ FAILED'}
333
+
334
+ 📈 Metadata:
335
+ Slides: ${result.metadata.slideCount}
336
+ Words: ${result.metadata.wordCount}
337
+ Avg/Slide: ${result.metadata.avgWordsPerSlide}
338
+ Duration: ~${result.metadata.estimatedDuration} minutes
339
+
340
+ 🎓 Frameworks Applied:
341
+ ${result.metadata.frameworks.map(f => ` • ${f}`).join('\n') || ' (none detected)'}
342
+ `);
343
+
344
+ // Show issues if any
345
+ const errors = result.qaResults.issues.filter(i => i.severity === 'error');
346
+ const warnings = result.qaResults.issues.filter(i => i.severity === 'warning');
347
+
348
+ if (errors.length > 0 || warnings.length > 0) {
349
+ console.log('⚠️ Issues:');
350
+ errors.forEach(e => console.log(` ❌ ${e.message}`));
351
+ warnings.forEach(w => console.log(` ⚠️ ${w.message}`));
352
+ }
353
+
354
+ console.log('\n✨ Generation complete!');
355
+
356
+ } catch (error) {
357
+ if (error.name === 'QAFailureError') {
358
+ console.error(`
359
+ ❌ QA VALIDATION FAILED
360
+
361
+ Score: ${error.score}/100 (threshold: ${error.threshold})
362
+
363
+ Issues that must be fixed:
364
+ ${error.getIssues().slice(0, 10).map(i => ` • ${i}`).join('\n')}
365
+
366
+ The presentation did not meet quality standards.
367
+ Fix the issues above or lower the threshold with --threshold.
368
+ `);
369
+ process.exit(1);
370
+ }
371
+
372
+ if (error.name === 'ValidationError') {
373
+ console.error(`
374
+ ❌ VALIDATION ERROR
375
+
376
+ ${error.errors.map(e => ` • ${e}`).join('\n')}
377
+ `);
378
+ process.exit(1);
379
+ }
380
+
381
+ console.error('Error:', error.message);
382
+ process.exit(1);
383
+ }
384
+ }
385
+
386
+ // Validate command
387
+ async function runValidate(inputPath, options, validate) {
388
+ console.log(`
389
+ ╔════════════════════════════════════════════════════════╗
390
+ ║ Claude Presentation Master ║
391
+ ║ Validating Presentation ║
392
+ ╚════════════════════════════════════════════════════════╝
393
+ `);
394
+
395
+ console.log(`📄 Validating: ${inputPath}`);
396
+ console.log(`📋 Mode: ${options.mode}`);
397
+
398
+ try {
399
+ const content = readFileSync(inputPath, 'utf-8');
400
+
401
+ const result = await validate(content, {
402
+ mode: options.mode,
403
+ threshold: options.threshold,
404
+ strictMode: true
405
+ });
406
+
407
+ console.log(`
408
+ ╔════════════════════════════════════════════════════════╗
409
+ ║ QA RESULTS ║
410
+ ╚════════════════════════════════════════════════════════╝
411
+
412
+ 📊 Score: ${result.score}/100 ${result.passed ? '✅ PASSED' : '❌ FAILED'}
413
+
414
+ Category Breakdown:
415
+ Visual: ${Math.round(result.visual?.whitespacePercentage ?? 0)}% whitespace
416
+ Content: ${result.content?.perSlide?.length ?? 0} slides analyzed
417
+ Accessibility: WCAG ${result.accessibility?.wcagLevel ?? 'N/A'}
418
+ `);
419
+
420
+ const errors = result.issues.filter(i => i.severity === 'error');
421
+ const warnings = result.issues.filter(i => i.severity === 'warning');
422
+
423
+ if (errors.length > 0) {
424
+ console.log('❌ Errors:');
425
+ errors.forEach(e => console.log(` • ${e.message}`));
426
+ }
427
+
428
+ if (warnings.length > 0) {
429
+ console.log('⚠️ Warnings:');
430
+ warnings.forEach(w => console.log(` • ${w.message}`));
431
+ }
432
+
433
+ process.exit(result.passed ? 0 : 1);
434
+
435
+ } catch (error) {
436
+ console.error('Error:', error.message);
437
+ process.exit(1);
438
+ }
439
+ }
440
+
441
+ // Run
442
+ main().catch(error => {
443
+ console.error('Fatal error:', error);
444
+ process.exit(1);
445
+ });