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/LICENSE +21 -0
- package/README.md +763 -0
- package/assets/presentation-engine.css +3057 -0
- package/assets/presentation-knowledge.yaml +6312 -0
- package/bin/cli.js +445 -0
- package/dist/index.d.mts +1209 -0
- package/dist/index.d.ts +1209 -0
- package/dist/index.js +4204 -0
- package/dist/index.mjs +4142 -0
- package/package.json +99 -0
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
|
+
});
|