mycontext-cli 4.2.18 → 4.2.20

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.
Files changed (45) hide show
  1. package/README.md +471 -71
  2. package/dist/agents/implementations/DemoRecorderAgent.d.ts.map +1 -1
  3. package/dist/agents/implementations/DemoRecorderAgent.js +297 -120
  4. package/dist/agents/implementations/DemoRecorderAgent.js.map +1 -1
  5. package/dist/agents/implementations/VisionNavigatorAgent.d.ts.map +1 -1
  6. package/dist/agents/implementations/VisionNavigatorAgent.js +9 -0
  7. package/dist/agents/implementations/VisionNavigatorAgent.js.map +1 -1
  8. package/dist/cli.js +6 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/demo.d.ts +14 -0
  11. package/dist/commands/demo.d.ts.map +1 -0
  12. package/dist/commands/demo.js +165 -0
  13. package/dist/commands/demo.js.map +1 -0
  14. package/dist/commands/generate-components-manifest.d.ts +2 -0
  15. package/dist/commands/generate-components-manifest.d.ts.map +1 -1
  16. package/dist/commands/generate-components-manifest.js +75 -53
  17. package/dist/commands/generate-components-manifest.js.map +1 -1
  18. package/dist/commands/generate-screens-list.d.ts +2 -0
  19. package/dist/commands/generate-screens-list.d.ts.map +1 -1
  20. package/dist/commands/generate-screens-list.js +36 -0
  21. package/dist/commands/generate-screens-list.js.map +1 -1
  22. package/dist/commands/generate.d.ts.map +1 -1
  23. package/dist/commands/generate.js +7 -3
  24. package/dist/commands/generate.js.map +1 -1
  25. package/dist/commands/render.d.ts +14 -0
  26. package/dist/commands/render.d.ts.map +1 -0
  27. package/dist/commands/render.js +730 -0
  28. package/dist/commands/render.js.map +1 -0
  29. package/dist/core/ai/AICore.d.ts +4 -0
  30. package/dist/core/ai/AICore.d.ts.map +1 -1
  31. package/dist/core/ai/AICore.js +12 -1
  32. package/dist/core/ai/AICore.js.map +1 -1
  33. package/dist/mcp/vision-test-runner.d.ts +5 -0
  34. package/dist/mcp/vision-test-runner.d.ts.map +1 -1
  35. package/dist/mcp/vision-test-runner.js +40 -1
  36. package/dist/mcp/vision-test-runner.js.map +1 -1
  37. package/dist/templates/sample-authority-blueprint.json +79 -0
  38. package/dist/types/blueprint-types.d.ts +82 -0
  39. package/dist/types/blueprint-types.d.ts.map +1 -0
  40. package/dist/types/blueprint-types.js +9 -0
  41. package/dist/types/blueprint-types.js.map +1 -0
  42. package/dist/utils/geminiClient.d.ts.map +1 -1
  43. package/dist/utils/geminiClient.js +3 -0
  44. package/dist/utils/geminiClient.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,730 @@
1
+ "use strict";
2
+ /**
3
+ * Render Command
4
+ *
5
+ * CLI command to ingest Authority Engine Production Blueprints and produce
6
+ * final media artifacts through the MyContext rendering pipeline.
7
+ *
8
+ * Usage:
9
+ * mycontext render <blueprint.json> — Render from a blueprint file
10
+ * mycontext render --demo — Run with built-in sample blueprint
11
+ * mycontext render --demo --voiceover — Include AI voiceover generation
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ var __importDefault = (this && this.__importDefault) || function (mod) {
47
+ return (mod && mod.__esModule) ? mod : { "default": mod };
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.registerRenderCommand = registerRenderCommand;
51
+ const chalk_1 = __importDefault(require("chalk"));
52
+ const path = __importStar(require("path"));
53
+ const fs = __importStar(require("fs-extra"));
54
+ const uuid_1 = require("uuid");
55
+ const AICore_1 = require("../core/ai/AICore");
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+ // Blueprint → Pipeline Adapter
58
+ // ─────────────────────────────────────────────────────────────────────────────
59
+ /**
60
+ * Convert Authority Engine scenes into MyContext VisionTestSteps
61
+ * This bridges the Authority Engine schema to the existing demo pipeline.
62
+ */
63
+ function blueprintToSteps(blueprint) {
64
+ return blueprint.scenes.map((scene, index) => ({
65
+ // TestStep base fields
66
+ id: `scene-${scene.sceneNumber}`,
67
+ order: index,
68
+ action: scene.title,
69
+ intent: scene.script,
70
+ screenshot: undefined,
71
+ success: true,
72
+ timestamp: new Date().toISOString(),
73
+ duration: scene.duration * 1000, // ms
74
+ selector: undefined,
75
+ // VisionTestStep extensions
76
+ visionDecision: {
77
+ action: "complete",
78
+ confidence: 100,
79
+ reasoning: `Scene ${scene.sceneNumber}: ${scene.plotPillar || "narrative scene"}`,
80
+ visualContext: scene.visualPrompt,
81
+ intent: scene.storyBeat || "narration",
82
+ alignsWithPrimeObjective: true,
83
+ gravityScore: 100,
84
+ },
85
+ visualAnalysis: {
86
+ componentsDetected: ["scene-frame"],
87
+ interactiveElements: [],
88
+ textContent: [scene.script],
89
+ colorPalette: [],
90
+ layoutStructure: `${blueprint.outputFormat.aspectRatio} vertical video — ${scene.transition || "cut"} transition`,
91
+ },
92
+ }));
93
+ }
94
+ /**
95
+ * Build a rich HTML storyboard from blueprint visual prompts
96
+ */
97
+ function buildBlueprintStoryboardHTML(blueprint) {
98
+ const scenesHTML = blueprint.scenes
99
+ .map((scene, index) => {
100
+ // Beat-based color coding
101
+ const beatColors = {
102
+ hook: "#ff4444",
103
+ build: "#ff8c00",
104
+ payoff: "#00c853",
105
+ transition: "#2979ff",
106
+ };
107
+ const beatColor = beatColors[scene.storyBeat || "build"] || "#666";
108
+ return `
109
+ <div class="scene" data-scene="${index}" ${index === 0 ? 'style="display:flex"' : ""}>
110
+ <div class="scene-visual">
111
+ <div class="visual-prompt-card">
112
+ <div class="scene-badge" style="background:${beatColor}">
113
+ ${(scene.storyBeat || "scene").toUpperCase()}
114
+ </div>
115
+ <h3>Scene ${scene.sceneNumber}: ${scene.title}</h3>
116
+ <p class="visual-prompt">${scene.visualPrompt}</p>
117
+ ${scene.bRollNotes ? `<p class="broll"><strong>B-Roll:</strong> ${scene.bRollNotes}</p>` : ""}
118
+ <div class="scene-meta">
119
+ <span class="duration">⏱ ${scene.duration}s</span>
120
+ <span class="transition">→ ${scene.transition || "cut"}</span>
121
+ ${scene.plotPillar ? `<span class="pillar">🎯 ${scene.plotPillar}</span>` : ""}
122
+ </div>
123
+ </div>
124
+ </div>
125
+ <div class="scene-script">
126
+ <div class="script-card">
127
+ <h4>🎙️ Script</h4>
128
+ <blockquote>${scene.script}</blockquote>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ `;
133
+ })
134
+ .join("");
135
+ return `<!DOCTYPE html>
136
+ <html lang="en">
137
+ <head>
138
+ <meta charset="UTF-8">
139
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
140
+ <title>${blueprint.title} — MyContext Storyboard</title>
141
+ <style>
142
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
143
+ * { box-sizing: border-box; margin: 0; padding: 0; }
144
+ body {
145
+ font-family: 'Inter', -apple-system, sans-serif;
146
+ background: #0a0a0a;
147
+ color: #e0e0e0;
148
+ min-height: 100vh;
149
+ }
150
+ .container { max-width: 1100px; margin: 0 auto; padding: 40px 20px; }
151
+
152
+ /* Header */
153
+ .header {
154
+ text-align: center;
155
+ padding: 60px 30px;
156
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
157
+ border-radius: 16px;
158
+ margin-bottom: 30px;
159
+ border: 1px solid rgba(255,255,255,0.05);
160
+ }
161
+ .header h1 {
162
+ font-size: 32px;
163
+ font-weight: 700;
164
+ background: linear-gradient(135deg, #00d2ff, #7b2ff7);
165
+ -webkit-background-clip: text;
166
+ -webkit-text-fill-color: transparent;
167
+ margin-bottom: 12px;
168
+ }
169
+ .header .subtitle { color: #888; font-size: 16px; line-height: 1.6; max-width: 600px; margin: 0 auto; }
170
+ .header .meta {
171
+ display: flex;
172
+ justify-content: center;
173
+ gap: 24px;
174
+ margin-top: 20px;
175
+ font-size: 13px;
176
+ color: #666;
177
+ }
178
+ .header .meta span { display: flex; align-items: center; gap: 6px; }
179
+
180
+ /* Narrative Strip */
181
+ .narrative {
182
+ display: grid;
183
+ grid-template-columns: repeat(3, 1fr);
184
+ gap: 16px;
185
+ margin-bottom: 30px;
186
+ }
187
+ .narrative-card {
188
+ background: #111;
189
+ border: 1px solid #222;
190
+ border-radius: 12px;
191
+ padding: 20px;
192
+ }
193
+ .narrative-card h4 { color: #888; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; }
194
+ .narrative-card p { font-size: 14px; line-height: 1.5; }
195
+ .narrative-card.mission p { color: #00d2ff; }
196
+ .narrative-card.villain p { color: #ff4444; }
197
+ .narrative-card.identity p { color: #00c853; }
198
+
199
+ /* Controls */
200
+ .controls {
201
+ background: #111;
202
+ border: 1px solid #222;
203
+ border-radius: 12px;
204
+ padding: 16px 24px;
205
+ display: flex;
206
+ align-items: center;
207
+ gap: 12px;
208
+ margin-bottom: 24px;
209
+ }
210
+ button {
211
+ padding: 10px 20px;
212
+ border: none;
213
+ border-radius: 8px;
214
+ background: linear-gradient(135deg, #7b2ff7, #00d2ff);
215
+ color: white;
216
+ cursor: pointer;
217
+ font-size: 14px;
218
+ font-weight: 600;
219
+ transition: opacity 0.2s;
220
+ }
221
+ button:hover { opacity: 0.85; }
222
+ button:disabled { opacity: 0.3; cursor: not-allowed; }
223
+ .step-indicator { margin-left: auto; color: #666; font-size: 14px; }
224
+ .voice-badge {
225
+ background: #1a1a2e;
226
+ color: #7b2ff7;
227
+ padding: 6px 12px;
228
+ border-radius: 6px;
229
+ font-size: 12px;
230
+ font-weight: 600;
231
+ text-transform: uppercase;
232
+ letter-spacing: 0.5px;
233
+ }
234
+
235
+ /* Scene */
236
+ .scene { display: none; gap: 24px; }
237
+ .scene-visual, .scene-script { flex: 1; }
238
+ .visual-prompt-card, .script-card {
239
+ background: #111;
240
+ border: 1px solid #222;
241
+ border-radius: 12px;
242
+ padding: 24px;
243
+ height: 100%;
244
+ }
245
+ .scene-badge {
246
+ display: inline-block;
247
+ padding: 4px 10px;
248
+ border-radius: 4px;
249
+ font-size: 11px;
250
+ font-weight: 700;
251
+ color: white;
252
+ letter-spacing: 1px;
253
+ margin-bottom: 12px;
254
+ }
255
+ .visual-prompt-card h3 { font-size: 20px; margin-bottom: 16px; color: #fff; }
256
+ .visual-prompt { color: #aaa; line-height: 1.7; font-size: 14px; }
257
+ .broll { color: #666; margin-top: 12px; font-size: 13px; font-style: italic; }
258
+ .scene-meta {
259
+ display: flex;
260
+ gap: 16px;
261
+ margin-top: 20px;
262
+ padding-top: 16px;
263
+ border-top: 1px solid #222;
264
+ font-size: 13px;
265
+ color: #666;
266
+ }
267
+ .script-card h4 { color: #888; margin-bottom: 16px; font-size: 14px; }
268
+ .script-card blockquote {
269
+ font-size: 18px;
270
+ line-height: 1.8;
271
+ color: #ddd;
272
+ border-left: 3px solid #7b2ff7;
273
+ padding-left: 20px;
274
+ font-style: italic;
275
+ }
276
+
277
+ /* Footer */
278
+ .footer {
279
+ text-align: center;
280
+ padding: 40px;
281
+ color: #444;
282
+ font-size: 12px;
283
+ }
284
+ .footer a { color: #7b2ff7; text-decoration: none; }
285
+ </style>
286
+ </head>
287
+ <body>
288
+ <div class="container">
289
+ <div class="header">
290
+ <h1>${blueprint.title}</h1>
291
+ <p class="subtitle">${blueprint.description}</p>
292
+ <div class="meta">
293
+ <span>📐 ${blueprint.outputFormat.aspectRatio}</span>
294
+ <span>🎬 ${blueprint.scenes.length} scenes</span>
295
+ <span>⏱ ${blueprint.totalDuration}s</span>
296
+ <span>🎙️ ${blueprint.voiceTone.style} tone</span>
297
+ </div>
298
+ </div>
299
+
300
+ <div class="narrative">
301
+ <div class="narrative-card mission">
302
+ <h4>🎯 Mission</h4>
303
+ <p>${blueprint.narrative.mission}</p>
304
+ </div>
305
+ <div class="narrative-card villain">
306
+ <h4>👿 Villain</h4>
307
+ <p>${blueprint.narrative.villain}</p>
308
+ </div>
309
+ <div class="narrative-card identity">
310
+ <h4>🦋 Identity Shift</h4>
311
+ <p>${blueprint.narrative.identityShift}</p>
312
+ </div>
313
+ </div>
314
+
315
+ <div class="controls">
316
+ <button id="prevBtn">← Prev</button>
317
+ <button id="nextBtn">Next →</button>
318
+ <span class="voice-badge">🎙️ ${blueprint.voiceTone.style} · ${blueprint.voiceTone.pace || "moderate"}</span>
319
+ <div class="step-indicator">
320
+ Scene <span id="currentScene">1</span> / <span id="totalScenes">${blueprint.scenes.length}</span>
321
+ </div>
322
+ </div>
323
+
324
+ <div class="scenes">
325
+ ${scenesHTML}
326
+ </div>
327
+
328
+ <div class="footer">
329
+ Rendered by <a href="https://github.com/farajabien/mycontext-cli">MyContext</a> · Authority Engine Integration
330
+ </div>
331
+ </div>
332
+
333
+ <script>
334
+ let current = 0;
335
+ const total = ${blueprint.scenes.length};
336
+
337
+ const prevBtn = document.getElementById('prevBtn');
338
+ const nextBtn = document.getElementById('nextBtn');
339
+ const currentSpan = document.getElementById('currentScene');
340
+
341
+ function show(i) {
342
+ document.querySelectorAll('.scene').forEach(s => s.style.display = 'none');
343
+ const el = document.querySelector('[data-scene="' + i + '"]');
344
+ if (el) el.style.display = 'flex';
345
+ current = i;
346
+ currentSpan.textContent = i + 1;
347
+ prevBtn.disabled = i === 0;
348
+ nextBtn.disabled = i === total - 1;
349
+ }
350
+
351
+ prevBtn.addEventListener('click', () => { if (current > 0) show(current - 1); });
352
+ nextBtn.addEventListener('click', () => { if (current < total - 1) show(current + 1); });
353
+ document.addEventListener('keydown', (e) => {
354
+ if (e.key === 'ArrowLeft' && current > 0) show(current - 1);
355
+ if (e.key === 'ArrowRight' && current < total - 1) show(current + 1);
356
+ });
357
+
358
+ show(0);
359
+ </script>
360
+ </body>
361
+ </html>`;
362
+ }
363
+ // ─────────────────────────────────────────────────────────────────────────────
364
+ // Render Pipeline
365
+ // ─────────────────────────────────────────────────────────────────────────────
366
+ /**
367
+ * Execute the full render pipeline for an Authority Engine blueprint
368
+ */
369
+ async function executeRender(blueprint, options, projectPath) {
370
+ const startTime = Date.now();
371
+ const renderDir = options.outputDir ||
372
+ path.join(projectPath, ".mycontext", "renders", `${blueprint.id}-${Date.now()}`);
373
+ await fs.ensureDir(renderDir);
374
+ console.log(chalk_1.default.bold.magenta(`\n${"═".repeat(70)}`));
375
+ console.log(chalk_1.default.bold.magenta(`🎬 MYCONTEXT RENDER ENGINE`));
376
+ console.log(chalk_1.default.bold.magenta(`${"═".repeat(70)}\n`));
377
+ console.log(chalk_1.default.white(`Blueprint: ${blueprint.title}`));
378
+ console.log(chalk_1.default.gray(`Scenes: ${blueprint.scenes.length}`));
379
+ console.log(chalk_1.default.gray(`Duration: ${blueprint.totalDuration}s`));
380
+ console.log(chalk_1.default.gray(`Voice: ${blueprint.voiceTone.style} (${blueprint.voiceTone.pace || "moderate"})`));
381
+ console.log(chalk_1.default.gray(`Format: ${blueprint.outputFormat.aspectRatio} @ ${blueprint.outputFormat.resolution}`));
382
+ console.log(chalk_1.default.gray(`Output: ${renderDir}\n`));
383
+ // ── Narrative Context ──────────────────────────────────────────────────
384
+ console.log(chalk_1.default.bold.cyan(`\n━━━ NARRATIVE CONTEXT ━━━`));
385
+ console.log(chalk_1.default.white(` 🎯 Mission: ${blueprint.narrative.mission}`));
386
+ console.log(chalk_1.default.red(` 👿 Villain: ${blueprint.narrative.villain}`));
387
+ console.log(chalk_1.default.green(` 🦋 Shift: ${blueprint.narrative.identityShift}\n`));
388
+ // Convert blueprint to steps
389
+ const steps = blueprintToSteps(blueprint);
390
+ // ── PHASE 1: Storyboard HTML ───────────────────────────────────────────
391
+ console.log(chalk_1.default.bold.cyan(`\n━━━ PHASE 1: STORYBOARD GENERATION ━━━`));
392
+ const storyboardPath = path.join(renderDir, "storyboard.html");
393
+ const storyboardHTML = buildBlueprintStoryboardHTML(blueprint);
394
+ await fs.writeFile(storyboardPath, storyboardHTML, "utf-8");
395
+ console.log(chalk_1.default.green(` ✓ Interactive storyboard → ${storyboardPath}`));
396
+ // ── PHASE 2: Voiceover Script ──────────────────────────────────────────
397
+ console.log(chalk_1.default.bold.cyan(`\n━━━ PHASE 2: VOICEOVER SCRIPT ━━━`));
398
+ const voScriptPath = path.join(renderDir, "voiceover-script.json");
399
+ // Build segments directly from blueprint (no vision extraction needed)
400
+ const segments = blueprint.scenes.map((scene, i) => {
401
+ const wordCount = scene.script.split(/\s+/).length;
402
+ const estimatedDuration = Math.max((wordCount / 150) * 60, scene.duration);
403
+ return {
404
+ id: (0, uuid_1.v4)(),
405
+ timestamp: blueprint.scenes.slice(0, i).reduce((sum, s) => sum + s.duration, 0),
406
+ duration: estimatedDuration,
407
+ narration: scene.script,
408
+ action: scene.title,
409
+ metadata: {
410
+ step: scene.sceneNumber,
411
+ uiState: scene.visualPrompt.substring(0, 80) + "...",
412
+ textOnScreen: [scene.title, scene.plotPillar || ""].filter(Boolean),
413
+ },
414
+ };
415
+ });
416
+ const totalDuration = segments.reduce((sum, s) => sum + s.duration, 0);
417
+ const fullScriptMd = buildVOScriptMarkdown(blueprint, segments);
418
+ const voScript = {
419
+ title: blueprint.title,
420
+ totalDuration,
421
+ segments,
422
+ fullScript: fullScriptMd,
423
+ };
424
+ await fs.writeFile(voScriptPath, JSON.stringify(voScript, null, 2), "utf-8");
425
+ console.log(chalk_1.default.green(` ✓ VO Script JSON → ${voScriptPath}`));
426
+ const voScriptMdPath = path.join(renderDir, "voiceover-script.md");
427
+ await fs.writeFile(voScriptMdPath, fullScriptMd, "utf-8");
428
+ console.log(chalk_1.default.green(` ✓ VO Script Markdown → ${voScriptMdPath}`));
429
+ segments.forEach((seg, i) => {
430
+ console.log(chalk_1.default.gray(` [${formatTimestamp(seg.timestamp)}] Scene ${i + 1}: "${seg.narration.substring(0, 50)}..."`));
431
+ });
432
+ // ── PHASE 3: AI Voice Enhancement (optional) ──────────────────────────
433
+ let audioSegments = [];
434
+ if (options.voiceover) {
435
+ console.log(chalk_1.default.bold.cyan(`\n━━━ PHASE 3: AI VOICEOVER ━━━`));
436
+ try {
437
+ // Initialize AICore if not already
438
+ try {
439
+ AICore_1.AICore.getInstance();
440
+ }
441
+ catch {
442
+ AICore_1.AICore.getInstance({
443
+ workingDirectory: projectPath,
444
+ fallbackEnabled: true,
445
+ });
446
+ }
447
+ const aiCore = AICore_1.AICore.getInstance();
448
+ // Use Gemini to enhance the script with professional narration
449
+ for (let i = 0; i < segments.length; i++) {
450
+ const scene = blueprint.scenes[i];
451
+ const seg = segments[i];
452
+ console.log(chalk_1.default.cyan(` 🎙️ Enhancing Scene ${i + 1}: ${scene.title}`));
453
+ const enhancePrompt = `You are a professional voiceover script editor.
454
+
455
+ Voice Tone: ${blueprint.voiceTone.style}, pace: ${blueprint.voiceTone.pace || "moderate"}
456
+ ${blueprint.voiceTone.emphasis?.length ? `Emphasis words: ${blueprint.voiceTone.emphasis.join(", ")}` : ""}
457
+
458
+ Story Beat: ${scene.storyBeat || "narration"}
459
+ Plot Pillar: ${scene.plotPillar || "general"}
460
+
461
+ Original Script:
462
+ "${scene.script}"
463
+
464
+ Polish this script for AI voiceover delivery. Keep the exact meaning but optimize for:
465
+ 1. Natural speech rhythm and breathing points (marked with ...)
466
+ 2. ${blueprint.voiceTone.style} tone throughout
467
+ 3. Emphasis on key phrases
468
+ 4. Clean pronunciation-friendly phrasing
469
+
470
+ Return ONLY the polished script text, nothing else.`;
471
+ try {
472
+ const enhanced = await aiCore.generateText(enhancePrompt, {
473
+ temperature: 0.6,
474
+ maxTokens: 500,
475
+ });
476
+ seg.narration = enhanced.trim();
477
+ console.log(chalk_1.default.gray(` ✓ Enhanced: "${seg.narration.substring(0, 60)}..."`));
478
+ }
479
+ catch (err) {
480
+ console.log(chalk_1.default.yellow(` ⚠ Enhancement failed, using original: ${err.message?.substring(0, 50)}`));
481
+ }
482
+ }
483
+ // Save enhanced script
484
+ const enhancedScript = {
485
+ ...voScript,
486
+ segments,
487
+ fullScript: buildVOScriptMarkdown(blueprint, segments),
488
+ };
489
+ await fs.writeFile(voScriptPath, JSON.stringify(enhancedScript, null, 2), "utf-8");
490
+ await fs.writeFile(voScriptMdPath, enhancedScript.fullScript, "utf-8");
491
+ console.log(chalk_1.default.green(`\n ✓ Enhanced scripts saved`));
492
+ }
493
+ catch (err) {
494
+ console.log(chalk_1.default.yellow(`\n ⚠ AI voiceover enhancement failed: ${err.message}`));
495
+ console.log(chalk_1.default.gray(` Falling back to original scripts`));
496
+ }
497
+ }
498
+ // ── PHASE 4: Markdown Production Script ────────────────────────────────
499
+ console.log(chalk_1.default.bold.cyan(`\n━━━ PHASE ${options.voiceover ? "4" : "3"}: PRODUCTION SCRIPT ━━━`));
500
+ const prodScriptPath = path.join(renderDir, "production-script.md");
501
+ const prodScript = buildProductionScript(blueprint);
502
+ await fs.writeFile(prodScriptPath, prodScript, "utf-8");
503
+ console.log(chalk_1.default.green(` ✓ Production Script → ${prodScriptPath}`));
504
+ // ── Summary ────────────────────────────────────────────────────────────
505
+ const endTime = Date.now();
506
+ const wordsSpoken = segments.reduce((sum, s) => sum + s.narration.split(/\s+/).length, 0);
507
+ const renderOutput = {
508
+ blueprintId: blueprint.id,
509
+ renderedAt: new Date().toISOString(),
510
+ outputDir: renderDir,
511
+ artifacts: {
512
+ voiceoverScript: voScriptPath,
513
+ voiceoverMarkdown: voScriptMdPath,
514
+ storyboardHtml: storyboardPath,
515
+ audioSegments: audioSegments.length > 0 ? audioSegments : undefined,
516
+ },
517
+ stats: {
518
+ totalScenes: blueprint.scenes.length,
519
+ totalDuration: blueprint.totalDuration,
520
+ wordsSpoken,
521
+ generationTime: endTime - startTime,
522
+ },
523
+ };
524
+ // Save render manifest
525
+ const manifestPath = path.join(renderDir, "render-manifest.json");
526
+ await fs.writeFile(manifestPath, JSON.stringify(renderOutput, null, 2), "utf-8");
527
+ console.log(chalk_1.default.bold.magenta(`\n${"═".repeat(70)}`));
528
+ console.log(chalk_1.default.bold.green(`✅ RENDER COMPLETE`));
529
+ console.log(chalk_1.default.bold.magenta(`${"═".repeat(70)}\n`));
530
+ console.log(chalk_1.default.white(` 📐 Scenes: ${renderOutput.stats.totalScenes}`));
531
+ console.log(chalk_1.default.white(` ⏱ Duration: ${renderOutput.stats.totalDuration}s`));
532
+ console.log(chalk_1.default.white(` 📝 Words: ${renderOutput.stats.wordsSpoken}`));
533
+ console.log(chalk_1.default.white(` ⚡ Generated in: ${(renderOutput.stats.generationTime / 1000).toFixed(1)}s`));
534
+ console.log(chalk_1.default.gray(`\n 📂 Output: ${renderDir}`));
535
+ console.log(chalk_1.default.gray(` ├── storyboard.html`));
536
+ console.log(chalk_1.default.gray(` ├── voiceover-script.json`));
537
+ console.log(chalk_1.default.gray(` ├── voiceover-script.md`));
538
+ console.log(chalk_1.default.gray(` ├── production-script.md`));
539
+ console.log(chalk_1.default.gray(` └── render-manifest.json\n`));
540
+ return renderOutput;
541
+ }
542
+ // ─────────────────────────────────────────────────────────────────────────────
543
+ // Helper: Build Markdown Scripts
544
+ // ─────────────────────────────────────────────────────────────────────────────
545
+ function buildVOScriptMarkdown(blueprint, segments) {
546
+ const lines = [
547
+ `# ${blueprint.title} — Voice-Over Script`,
548
+ "",
549
+ blueprint.description,
550
+ "",
551
+ `**Voice Tone**: ${blueprint.voiceTone.style} · ${blueprint.voiceTone.pace || "moderate"}`,
552
+ `**Duration**: ${formatDuration(segments.reduce((sum, s) => sum + s.duration, 0))}`,
553
+ `**Segments**: ${segments.length}`,
554
+ `**Format**: ${blueprint.outputFormat.aspectRatio} @ ${blueprint.outputFormat.resolution}`,
555
+ "",
556
+ "---",
557
+ "",
558
+ "## Narration",
559
+ "",
560
+ ];
561
+ segments.forEach((segment, index) => {
562
+ const scene = blueprint.scenes[index];
563
+ lines.push(`### [${formatTimestamp(segment.timestamp)}] Scene ${index + 1}: ${segment.action}`);
564
+ lines.push("");
565
+ if (scene?.storyBeat)
566
+ lines.push(`> **Beat**: ${scene.storyBeat.toUpperCase()} · **Pillar**: ${scene.plotPillar || "—"}`);
567
+ lines.push("");
568
+ lines.push(`**Duration**: ${segment.duration.toFixed(1)}s`);
569
+ lines.push("");
570
+ lines.push(`> ${segment.narration}`);
571
+ lines.push("");
572
+ if (scene?.visualPrompt) {
573
+ lines.push(`*Visual: ${scene.visualPrompt.substring(0, 120)}...*`);
574
+ lines.push("");
575
+ }
576
+ lines.push("---");
577
+ lines.push("");
578
+ });
579
+ return lines.join("\n");
580
+ }
581
+ function buildProductionScript(blueprint) {
582
+ const lines = [
583
+ `# ${blueprint.title}`,
584
+ `## Production Script`,
585
+ "",
586
+ `**Source**: ${blueprint.source}`,
587
+ `**Created**: ${blueprint.createdAt}`,
588
+ `**Format**: ${blueprint.outputFormat.aspectRatio} · ${blueprint.outputFormat.resolution}`,
589
+ `**Total Duration**: ${blueprint.totalDuration}s`,
590
+ "",
591
+ "---",
592
+ "",
593
+ "## Narrative Framework",
594
+ "",
595
+ `| Element | Content |`,
596
+ `|---------|---------|`,
597
+ `| 🎯 Mission | ${blueprint.narrative.mission} |`,
598
+ `| 👿 Villain | ${blueprint.narrative.villain} |`,
599
+ `| 🦋 Identity Shift | ${blueprint.narrative.identityShift} |`,
600
+ "",
601
+ "---",
602
+ "",
603
+ "## Scene Breakdown",
604
+ "",
605
+ ];
606
+ blueprint.scenes.forEach((scene) => {
607
+ lines.push(`### Scene ${scene.sceneNumber}: ${scene.title}`);
608
+ lines.push("");
609
+ lines.push(`| Property | Value |`);
610
+ lines.push(`|----------|-------|`);
611
+ lines.push(`| ⏱ Duration | ${scene.duration}s |`);
612
+ lines.push(`| 🎯 Plot Pillar | ${scene.plotPillar || "—"} |`);
613
+ lines.push(`| 🎭 Story Beat | ${scene.storyBeat || "—"} |`);
614
+ lines.push(`| → Transition | ${scene.transition || "cut"} |`);
615
+ lines.push("");
616
+ lines.push("**🎙️ Script:**");
617
+ lines.push(`> ${scene.script}`);
618
+ lines.push("");
619
+ lines.push("**🎨 Visual Direction:**");
620
+ lines.push(`> ${scene.visualPrompt}`);
621
+ lines.push("");
622
+ if (scene.bRollNotes) {
623
+ lines.push(`**📹 B-Roll:** ${scene.bRollNotes}`);
624
+ lines.push("");
625
+ }
626
+ lines.push("---");
627
+ lines.push("");
628
+ });
629
+ if (blueprint.storyBeats) {
630
+ lines.push("## Story Architecture");
631
+ lines.push("");
632
+ lines.push(`**Beats**: ${blueprint.storyBeats.join(" → ")}`);
633
+ lines.push("");
634
+ if (blueprint.plotPillars) {
635
+ lines.push(`**Pillars**: ${blueprint.plotPillars.join(" → ")}`);
636
+ lines.push("");
637
+ }
638
+ }
639
+ lines.push("---");
640
+ lines.push(`*Rendered by MyContext · Authority Engine Integration*`);
641
+ return lines.join("\n");
642
+ }
643
+ // ─────────────────────────────────────────────────────────────────────────────
644
+ // Utility
645
+ // ─────────────────────────────────────────────────────────────────────────────
646
+ function formatTimestamp(seconds) {
647
+ const mins = Math.floor(seconds / 60);
648
+ const secs = Math.floor(seconds % 60);
649
+ return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
650
+ }
651
+ function formatDuration(seconds) {
652
+ const mins = Math.floor(seconds / 60);
653
+ const secs = Math.floor(seconds % 60);
654
+ return mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
655
+ }
656
+ // ─────────────────────────────────────────────────────────────────────────────
657
+ // CLI Command Registration
658
+ // ─────────────────────────────────────────────────────────────────────────────
659
+ function registerRenderCommand(program) {
660
+ program
661
+ .command("render")
662
+ .description("Render an Authority Engine Production Blueprint into media artifacts")
663
+ .argument("[blueprint]", "Path to blueprint JSON file")
664
+ .option("--demo", "Use built-in sample blueprint for demo")
665
+ .option("--voiceover", "Enhance scripts with AI voiceover processing")
666
+ .option("--audio", "Generate audio files using TTS (requires voiceover)")
667
+ .option("--output <dir>", "Custom output directory")
668
+ .action(async (blueprintPath, options) => {
669
+ const projectPath = process.cwd();
670
+ let blueprint;
671
+ if (options.demo) {
672
+ // Load built-in sample blueprint
673
+ console.log(chalk_1.default.blue("\n📦 Loading built-in Authority Engine sample blueprint...\n"));
674
+ // Try loading from the templates directory (works in both dev and built modes)
675
+ const candidates = [
676
+ path.join(__dirname, "..", "templates", "sample-authority-blueprint.json"),
677
+ path.join(__dirname, "templates", "sample-authority-blueprint.json"),
678
+ path.join(projectPath, "apps", "cli", "src", "templates", "sample-authority-blueprint.json"),
679
+ ];
680
+ let loaded = false;
681
+ for (const candidate of candidates) {
682
+ if (await fs.pathExists(candidate)) {
683
+ blueprint = await fs.readJson(candidate);
684
+ loaded = true;
685
+ break;
686
+ }
687
+ }
688
+ if (!loaded) {
689
+ console.error(chalk_1.default.red("❌ Could not find sample blueprint. Try specifying a blueprint file path."));
690
+ process.exit(1);
691
+ }
692
+ blueprint = blueprint;
693
+ }
694
+ else if (blueprintPath) {
695
+ // Load from specified file
696
+ const resolvedPath = path.resolve(projectPath, blueprintPath);
697
+ if (!(await fs.pathExists(resolvedPath))) {
698
+ console.error(chalk_1.default.red(`❌ Blueprint file not found: ${resolvedPath}`));
699
+ process.exit(1);
700
+ }
701
+ try {
702
+ blueprint = await fs.readJson(resolvedPath);
703
+ }
704
+ catch (err) {
705
+ console.error(chalk_1.default.red(`❌ Invalid blueprint JSON: ${err.message}`));
706
+ process.exit(1);
707
+ }
708
+ }
709
+ else {
710
+ console.error(chalk_1.default.red("❌ Please specify a blueprint file or use --demo"));
711
+ console.log(chalk_1.default.gray("\n Usage:"));
712
+ console.log(chalk_1.default.gray(" mycontext render <blueprint.json> Render from a file"));
713
+ console.log(chalk_1.default.gray(" mycontext render --demo Run with sample blueprint"));
714
+ console.log(chalk_1.default.gray(" mycontext render --demo --voiceover Include AI voiceover\n"));
715
+ process.exit(1);
716
+ }
717
+ // Validate blueprint has required fields
718
+ if (!blueprint.scenes || blueprint.scenes.length === 0) {
719
+ console.error(chalk_1.default.red("❌ Blueprint must contain at least one scene"));
720
+ process.exit(1);
721
+ }
722
+ // Execute render
723
+ await executeRender(blueprint, {
724
+ voiceover: options.voiceover,
725
+ audio: options.audio,
726
+ outputDir: options.output,
727
+ }, projectPath);
728
+ });
729
+ }
730
+ //# sourceMappingURL=render.js.map