## Phase 8: Enterprise Extractor Improvements ✅ - 14 security extractors (TLS, JWT, SQL injection, XSS, etc.) - 10 framework-specific extractors (Spring, Django, Rails, etc.) - Config file security detection (YAML, TOML) ## Phase 9: Autonomous Extractor Generation ✅ - Shadow mode executor with TP/FP tracking - Graduation pipeline with confidence thresholds - Auto-rollback on regression detection - Cross-project pattern syncing ## UAT Suite Complete (14 scripts, 90 tests) - test-core-detection.sh (6 tests) - test-declarative-extractors.sh (5 tests) - test-domain-frameworks.sh (5 tests) - test-domain-unreal.sh (3 tests) - test-llm-extraction.sh (6 tests) - test-eval-harness.sh (5 tests) - test-cross-language.sh (3 tests) - test-precommit-performance.sh (4 tests) - test-output-formats.sh (8 tests) - test-drift-detection.sh (6 tests) - test-exit-codes.sh (12 tests) + 3 more scripts ## Other Changes - Updated roadmap to mark Phase 8-9 complete - Added .gitignore entries for build artifacts - Updated pre-commit: 800 line limit, exclude tests/data/cmd Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
/**
|
|
* Pitch Video Render Script
|
|
*
|
|
* Programmatic rendering of pitch videos via Remotion API.
|
|
* Usage: pnpm render:pitch:api [script.json] [output.mp4]
|
|
*/
|
|
|
|
import { bundle } from '@remotion/bundler';
|
|
import { renderMedia, selectComposition } from '@remotion/renderer';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { stemedbPitchScript } from './data/stemedb-pitch';
|
|
import { calculateTotalDuration } from './types/pitch-script';
|
|
import type { PitchScript } from './types/pitch-script';
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
const scriptPath = args[0];
|
|
const outputPath = args[1] || 'out/stemedb-pitch.mp4';
|
|
|
|
// Load script from file or use default
|
|
let script: PitchScript;
|
|
if (scriptPath && fs.existsSync(scriptPath)) {
|
|
console.log(`Loading script from ${scriptPath}`);
|
|
script = JSON.parse(fs.readFileSync(scriptPath, 'utf-8'));
|
|
} else {
|
|
console.log('Using default StemeDB pitch script');
|
|
script = stemedbPitchScript;
|
|
}
|
|
|
|
// Calculate total duration
|
|
const totalDuration = calculateTotalDuration(script.blocks);
|
|
console.log(`Total duration: ${(totalDuration / 1000).toFixed(1)}s (${script.blocks.length} blocks)`);
|
|
|
|
// Bundle the Remotion project
|
|
console.log('Bundling...');
|
|
const bundleLocation = await bundle({
|
|
entryPoint: path.resolve(__dirname, './index.ts'),
|
|
webpackOverride: (config) => config,
|
|
});
|
|
|
|
// Select the composition
|
|
const composition = await selectComposition({
|
|
serveUrl: bundleLocation,
|
|
id: 'PitchVideo',
|
|
inputProps: { script },
|
|
});
|
|
|
|
// Ensure output directory exists
|
|
const outputDir = path.dirname(outputPath);
|
|
if (!fs.existsSync(outputDir)) {
|
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
}
|
|
|
|
// Render the video
|
|
console.log(`Rendering to ${outputPath}...`);
|
|
await renderMedia({
|
|
composition,
|
|
serveUrl: bundleLocation,
|
|
codec: 'h264',
|
|
outputLocation: outputPath,
|
|
inputProps: { script },
|
|
onProgress: ({ progress }) => {
|
|
const percent = Math.round(progress * 100);
|
|
process.stdout.write(`\rProgress: ${percent}%`);
|
|
},
|
|
});
|
|
|
|
console.log('\nDone!');
|
|
console.log(`Output: ${path.resolve(outputPath)}`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|