bazaar.it 0.1.0 → 0.2.1

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 (57) hide show
  1. package/README.md +485 -3
  2. package/bin/baz.js +6 -1
  3. package/dist/commands/auth.d.ts +2 -0
  4. package/dist/commands/auth.js +109 -0
  5. package/dist/commands/capabilities.d.ts +2 -0
  6. package/dist/commands/capabilities.js +44 -0
  7. package/dist/commands/context.d.ts +13 -0
  8. package/dist/commands/context.js +498 -0
  9. package/dist/commands/export.d.ts +2 -0
  10. package/dist/commands/export.js +360 -0
  11. package/dist/commands/logs.d.ts +2 -0
  12. package/dist/commands/logs.js +180 -0
  13. package/dist/commands/loop.d.ts +2 -0
  14. package/dist/commands/loop.js +538 -0
  15. package/dist/commands/mcp.d.ts +2 -0
  16. package/dist/commands/mcp.js +143 -0
  17. package/dist/commands/media.d.ts +2 -0
  18. package/dist/commands/media.js +362 -0
  19. package/dist/commands/project.d.ts +2 -0
  20. package/dist/commands/project.js +786 -0
  21. package/dist/commands/prompt.d.ts +2 -0
  22. package/dist/commands/prompt.js +540 -0
  23. package/dist/commands/recipe.d.ts +15 -0
  24. package/dist/commands/recipe.js +607 -0
  25. package/dist/commands/review.d.ts +17 -0
  26. package/dist/commands/review.js +345 -0
  27. package/dist/commands/scenes.d.ts +2 -0
  28. package/dist/commands/scenes.js +481 -0
  29. package/dist/commands/share.d.ts +2 -0
  30. package/dist/commands/share.js +226 -0
  31. package/dist/commands/state.d.ts +2 -0
  32. package/dist/commands/state.js +171 -0
  33. package/dist/commands/status.d.ts +2 -0
  34. package/dist/commands/status.js +219 -0
  35. package/dist/commands/template.d.ts +2 -0
  36. package/dist/commands/template.js +123 -0
  37. package/dist/commands/verify.d.ts +2 -0
  38. package/dist/commands/verify.js +150 -0
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.js +124 -0
  41. package/dist/lib/api.d.ts +188 -0
  42. package/dist/lib/api.js +719 -0
  43. package/dist/lib/banner.d.ts +12 -0
  44. package/dist/lib/banner.js +69 -0
  45. package/dist/lib/config.d.ts +33 -0
  46. package/dist/lib/config.js +99 -0
  47. package/dist/lib/output.d.ts +52 -0
  48. package/dist/lib/output.js +162 -0
  49. package/dist/lib/project-state.d.ts +52 -0
  50. package/dist/lib/project-state.js +178 -0
  51. package/dist/lib/sse.d.ts +168 -0
  52. package/dist/lib/sse.js +227 -0
  53. package/dist/lib/version.d.ts +1 -0
  54. package/dist/lib/version.js +3 -0
  55. package/dist/repl.d.ts +4 -0
  56. package/dist/repl.js +764 -0
  57. package/package.json +32 -5
@@ -0,0 +1,538 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { readFileSync, existsSync } from 'fs';
5
+ import { loadConfig, hasAuth, getProjectId } from '../lib/config.js';
6
+ import { streamGeneration, uploadImage, fetchUrlContent, ApiError, apiRequest } from '../lib/api.js';
7
+ import { success, error, output } from '../lib/output.js';
8
+ function collect(value, previous) {
9
+ return previous.concat([value]);
10
+ }
11
+ function formatElapsed(ms) {
12
+ if (ms < 1000)
13
+ return `${ms}ms`;
14
+ const seconds = Math.floor(ms / 1000);
15
+ if (seconds < 60)
16
+ return `${seconds}s`;
17
+ const minutes = Math.floor(seconds / 60);
18
+ const remainingSecs = seconds % 60;
19
+ return `${minutes}m ${remainingSecs}s`;
20
+ }
21
+ function normalizeRequirements(input) {
22
+ if (!input)
23
+ return [];
24
+ return input.split(',').map(r => r.trim()).filter(Boolean);
25
+ }
26
+ function getStartFrame(scene) {
27
+ return scene.start ?? scene.props?.start ?? 0;
28
+ }
29
+ function buildRequirementsCheck(requirements, data) {
30
+ const haystackParts = [];
31
+ for (const scene of data.scenes) {
32
+ if (scene.name)
33
+ haystackParts.push(scene.name);
34
+ }
35
+ if (data.recipe) {
36
+ haystackParts.push(data.recipe.title || '');
37
+ data.recipe.scenes?.forEach(s => haystackParts.push(s.prompt || '', s.name || ''));
38
+ data.recipe.voiceovers?.forEach(v => haystackParts.push(v.text || ''));
39
+ }
40
+ const haystack = haystackParts.join('\n').toLowerCase();
41
+ const missing = [];
42
+ const satisfied = [];
43
+ for (const req of requirements) {
44
+ if (haystack.includes(req.toLowerCase())) {
45
+ satisfied.push(req);
46
+ }
47
+ else {
48
+ missing.push(req);
49
+ }
50
+ }
51
+ return { satisfied, missing, total: requirements.length };
52
+ }
53
+ function parseBudgetMs(input) {
54
+ if (!input)
55
+ return undefined;
56
+ const value = input.trim().toLowerCase();
57
+ const match = value.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/);
58
+ if (!match)
59
+ return undefined;
60
+ const amount = parseFloat(match[1] ?? '0');
61
+ const unit = match[2] || 's';
62
+ if (!Number.isFinite(amount) || amount <= 0)
63
+ return undefined;
64
+ switch (unit) {
65
+ case 'ms':
66
+ return amount;
67
+ case 'm':
68
+ return amount * 60_000;
69
+ case 'h':
70
+ return amount * 3_600_000;
71
+ case 's':
72
+ default:
73
+ return amount * 1_000;
74
+ }
75
+ }
76
+ export const loopCommand = new Command('loop')
77
+ .description('Iterate prompt → review in a basic OODA loop')
78
+ .argument('<text>', 'The prompt text (or use --file)')
79
+ .option('--mode <mode>', 'Generation mode: agent (default), agent-max, multi-scene', 'agent')
80
+ .option('--max', 'Shorthand for --mode agent-max')
81
+ .option('--max-iterations <n>', 'Maximum iterations (default: 3)', '3')
82
+ .option('--budget <time>', 'Total time budget (e.g., 45s, 2m, 1h)')
83
+ .option('--stop-on-fail', 'Stop the loop on generation failure')
84
+ .option('--requirements <list>', 'Requirements to verify against (comma-separated)')
85
+ .option('--file <path>', 'Read prompt from file')
86
+ .option('--image <path>', 'Attach an image file (can be used multiple times)', collect, [])
87
+ .option('--url <url>', 'Attach a URL for the agent to analyze (can be used multiple times)', collect, [])
88
+ .option('--no-stream', 'Disable streaming output')
89
+ .option('--stream-json', 'Output events as newline-delimited JSON')
90
+ .option('--plan', 'Create a recipe/plan without executing (handshake protocol)')
91
+ .action(async (text, options, cmd) => {
92
+ const globalOpts = cmd.optsWithGlobals();
93
+ const agentModeEnv = process.env.BAZ_AGENT === '1';
94
+ const jsonOutput = globalOpts.json || agentModeEnv;
95
+ const streamJson = options.streamJson === true || agentModeEnv;
96
+ const config = loadConfig({
97
+ configPath: globalOpts.config,
98
+ apiUrl: globalOpts.apiUrl,
99
+ projectId: globalOpts.projectId,
100
+ });
101
+ if (!hasAuth(config)) {
102
+ if (streamJson || jsonOutput) {
103
+ console.log(JSON.stringify({
104
+ type: 'error',
105
+ code: 'AUTH_MISSING',
106
+ message: 'Not authenticated',
107
+ category: 'auth',
108
+ retryable: false,
109
+ continue: false,
110
+ }));
111
+ }
112
+ else {
113
+ error('Not authenticated', 'Run: baz auth login <api-key>');
114
+ }
115
+ process.exit(13);
116
+ }
117
+ let projectId;
118
+ try {
119
+ projectId = getProjectId(config, globalOpts.projectId);
120
+ }
121
+ catch (err) {
122
+ if (streamJson || jsonOutput) {
123
+ console.log(JSON.stringify({
124
+ type: 'error',
125
+ code: 'VALIDATION',
126
+ message: err.message,
127
+ category: 'validation',
128
+ retryable: false,
129
+ continue: false,
130
+ }));
131
+ }
132
+ else {
133
+ error(err.message);
134
+ }
135
+ process.exit(64);
136
+ }
137
+ // Get prompt text
138
+ let promptText = text;
139
+ if (options.file) {
140
+ try {
141
+ promptText = readFileSync(options.file, 'utf-8').trim();
142
+ }
143
+ catch {
144
+ error(`Failed to read file: ${options.file}`);
145
+ process.exit(1);
146
+ }
147
+ }
148
+ if (!promptText) {
149
+ error('No prompt provided');
150
+ process.exit(1);
151
+ }
152
+ const mode = options.max ? 'agent-max' : options.mode;
153
+ const requirements = normalizeRequirements(options.requirements);
154
+ const budgetMs = parseBudgetMs(options.budget);
155
+ const stopOnFail = options.stopOnFail === true;
156
+ let maxIterations = parseInt(options.maxIterations, 10);
157
+ if (!Number.isFinite(maxIterations) || maxIterations < 1)
158
+ maxIterations = 1;
159
+ if (options.plan)
160
+ maxIterations = 1;
161
+ if (budgetMs !== undefined && budgetMs <= 0) {
162
+ error('Budget must be a positive duration (e.g., 30s, 2m)');
163
+ process.exit(64);
164
+ }
165
+ // Handle image uploads
166
+ const imageUrls = [];
167
+ if (options.image && options.image.length > 0) {
168
+ const uploadSpinner = ora('Uploading images...').start();
169
+ try {
170
+ for (const imagePath of options.image) {
171
+ if (!existsSync(imagePath)) {
172
+ uploadSpinner.fail();
173
+ error(`Image file not found: ${imagePath}`);
174
+ process.exit(1);
175
+ }
176
+ const imageBuffer = readFileSync(imagePath);
177
+ const url = await uploadImage(config, { projectId, buffer: imageBuffer, filename: imagePath });
178
+ imageUrls.push(url);
179
+ }
180
+ uploadSpinner.succeed(`Uploaded ${imageUrls.length} image${imageUrls.length > 1 ? 's' : ''}`);
181
+ }
182
+ catch (err) {
183
+ uploadSpinner.fail();
184
+ const errMsg = err instanceof ApiError
185
+ ? `${err.message}${err.suggestion ? ` — ${err.suggestion}` : ''}`
186
+ : err.message;
187
+ error(`Failed to upload images: ${errMsg}`);
188
+ process.exit(1);
189
+ }
190
+ }
191
+ // Handle URL attachments
192
+ const urlContents = [];
193
+ if (options.url && options.url.length > 0) {
194
+ const urlSpinner = ora('Fetching URLs...').start();
195
+ try {
196
+ for (const url of options.url) {
197
+ const result = await fetchUrlContent(url);
198
+ urlContents.push({
199
+ url,
200
+ title: result.title,
201
+ content: result.content.slice(0, 10000),
202
+ });
203
+ }
204
+ urlSpinner.succeed(`Fetched ${urlContents.length} URL${urlContents.length > 1 ? 's' : ''}`);
205
+ }
206
+ catch (err) {
207
+ urlSpinner.fail();
208
+ const errMsg = err instanceof ApiError
209
+ ? `${err.message}${err.details ? ` — ${err.details}` : ''}`
210
+ : err.message;
211
+ error(`Failed to fetch URL: ${errMsg}`);
212
+ process.exit(1);
213
+ }
214
+ if (urlContents.length > 0) {
215
+ const urlContext = urlContents.map(u => `--- Content from ${u.url}${u.title ? ` (${u.title})` : ''} ---\n${u.content}`).join('\n\n');
216
+ promptText = `${urlContext}\n\n---\n\nUser request: ${promptText}`;
217
+ }
218
+ }
219
+ const toolNames = {
220
+ add_scene: '🎬 Creating scene',
221
+ edit_scene: '✏️ Editing scene',
222
+ delete_scene: '🗑️ Deleting scene',
223
+ addScene: '🎬 Creating scene',
224
+ editScene: '✏️ Editing scene',
225
+ deleteScene: '🗑️ Deleting scene',
226
+ trimScene: '⏱️ Adjusting timing',
227
+ generateImage: '🖼️ Generating image',
228
+ generateVideo: '🎥 Generating video',
229
+ generateVoiceover: '🎙️ Generating voiceover',
230
+ generateMusic: '🎵 Generating music',
231
+ fetch_url: '🌐 Fetching URL',
232
+ take_screenshot: '📸 Taking screenshot',
233
+ removeBackground: '✂️ Removing background',
234
+ summarize: '📝 Summarizing content',
235
+ str_replace_based_edit_tool: '✏️ Editing code',
236
+ browse_composition: '👀 Analyzing composition',
237
+ create_video_plan: '📋 Planning video',
238
+ create_recipe: '🧪 Creating recipe',
239
+ workflow: '🔄 Running workflow',
240
+ execute_workflow: '⚡ Executing workflow',
241
+ addAudio: '🔊 Adding audio',
242
+ embedAudio: '🎧 Embedding audio',
243
+ generateVeo3: '🎬 Generating Veo video',
244
+ nanoBanana: '🍌 Running Nano Banana',
245
+ NanoBananaService: '🍌 Nano Banana generation',
246
+ seedance: '💃 Generating Seedance video',
247
+ };
248
+ const basePrompt = promptText;
249
+ let currentPrompt = basePrompt;
250
+ const results = [];
251
+ const loopStart = Date.now();
252
+ const emit = (payload) => {
253
+ if (streamJson) {
254
+ console.log(JSON.stringify(payload));
255
+ }
256
+ };
257
+ emit({
258
+ type: 'loop_start',
259
+ mode,
260
+ projectId,
261
+ maxIterations,
262
+ budgetMs: budgetMs ?? null,
263
+ requirements,
264
+ planOnly: options.plan === true,
265
+ });
266
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
267
+ const iterStart = Date.now();
268
+ const elapsedTotal = Date.now() - loopStart;
269
+ if (budgetMs !== undefined && elapsedTotal > budgetMs) {
270
+ emit({
271
+ type: 'loop_budget_exceeded',
272
+ iteration,
273
+ budgetMs,
274
+ elapsedMs: elapsedTotal,
275
+ continue: false,
276
+ });
277
+ break;
278
+ }
279
+ emit({
280
+ type: 'loop_iteration_start',
281
+ iteration,
282
+ maxIterations,
283
+ mode,
284
+ projectId,
285
+ requirements,
286
+ planOnly: options.plan === true,
287
+ });
288
+ emit({
289
+ type: 'ooda_act',
290
+ iteration,
291
+ prompt: currentPrompt,
292
+ });
293
+ if (!streamJson && !jsonOutput) {
294
+ console.log(chalk.cyan(`\nIteration ${iteration}/${maxIterations}`));
295
+ }
296
+ let stepCount = 0;
297
+ let lastPhase = '';
298
+ let currentSpinner = null;
299
+ const startTime = Date.now();
300
+ const spinner = options.stream !== false ? null : ora('Processing...').start();
301
+ let result = null;
302
+ try {
303
+ result = await streamGeneration(config, {
304
+ projectId,
305
+ prompt: currentPrompt,
306
+ mode,
307
+ imageUrls: imageUrls.length > 0 ? imageUrls : undefined,
308
+ includeRaw: streamJson,
309
+ planOnly: options.plan,
310
+ requirements: options.requirements,
311
+ onEvent: options.stream !== false ? (event) => {
312
+ if (streamJson) {
313
+ console.log(JSON.stringify({ ...event, iteration }));
314
+ return;
315
+ }
316
+ if (jsonOutput) {
317
+ return;
318
+ }
319
+ const currentPhase = event.type;
320
+ if (currentPhase !== lastPhase && currentPhase !== 'text') {
321
+ if (['tool_use', 'code_gen', 'compile'].includes(currentPhase)) {
322
+ stepCount++;
323
+ }
324
+ lastPhase = currentPhase;
325
+ }
326
+ const elapsed = formatElapsed(Date.now() - startTime);
327
+ const stepPrefix = chalk.dim(`[${elapsed}]`);
328
+ switch (event.type) {
329
+ case 'thinking':
330
+ if (currentSpinner)
331
+ currentSpinner.stop();
332
+ currentSpinner = ora(`${stepPrefix} ${chalk.blue('🧠 Thinking...')}`).start();
333
+ break;
334
+ case 'tool_use':
335
+ if (currentSpinner)
336
+ currentSpinner.succeed();
337
+ currentSpinner = ora(`${stepPrefix} ${chalk.yellow(toolNames[event.tool || ''] || `🔧 ${event.tool}`)}`).start();
338
+ break;
339
+ case 'code_gen':
340
+ if (currentSpinner)
341
+ currentSpinner.succeed();
342
+ currentSpinner = ora(`${stepPrefix} ${chalk.magenta('💻 Generating code...')}`).start();
343
+ break;
344
+ case 'compile':
345
+ if (currentSpinner)
346
+ currentSpinner.succeed();
347
+ currentSpinner = ora(`${stepPrefix} ${chalk.cyan('⚙️ Compiling...')}`).start();
348
+ break;
349
+ case 'scene_created':
350
+ if (currentSpinner)
351
+ currentSpinner.succeed();
352
+ currentSpinner = null;
353
+ break;
354
+ case 'scene_updated':
355
+ if (currentSpinner)
356
+ currentSpinner.succeed();
357
+ currentSpinner = null;
358
+ break;
359
+ case 'error':
360
+ if (currentSpinner)
361
+ currentSpinner.fail();
362
+ currentSpinner = null;
363
+ break;
364
+ case 'complete':
365
+ if (currentSpinner)
366
+ currentSpinner.succeed();
367
+ currentSpinner = null;
368
+ break;
369
+ }
370
+ } : undefined,
371
+ });
372
+ }
373
+ catch (err) {
374
+ if (currentSpinner)
375
+ currentSpinner.fail();
376
+ if (spinner)
377
+ spinner.stop();
378
+ const message = err instanceof Error ? err.message : String(err);
379
+ if (streamJson || jsonOutput) {
380
+ console.log(JSON.stringify({
381
+ type: 'error',
382
+ message,
383
+ iteration,
384
+ category: 'fatal',
385
+ retryable: false,
386
+ continue: false,
387
+ }));
388
+ }
389
+ else {
390
+ error(message);
391
+ }
392
+ break;
393
+ }
394
+ if (!result) {
395
+ break;
396
+ }
397
+ if (currentSpinner)
398
+ currentSpinner.stop();
399
+ if (spinner)
400
+ spinner.stop();
401
+ const totalElapsed = formatElapsed(Date.now() - startTime);
402
+ const elapsedMs = Date.now() - startTime;
403
+ // Observe: fetch summary state
404
+ const project = await apiRequest(config, 'project.getFullProject', {
405
+ id: projectId,
406
+ include: ['scenes'],
407
+ includeSceneCode: false,
408
+ });
409
+ const recipeResult = await apiRequest(config, 'recipe.getByProject', {
410
+ projectId,
411
+ });
412
+ const scenes = project.scenes || [];
413
+ const totalFrames = scenes.reduce((max, s) => {
414
+ const start = getStartFrame(s);
415
+ return Math.max(max, start + (s.duration || 0));
416
+ }, 0);
417
+ const totalDuration = totalFrames / 30;
418
+ const requirementsCheck = requirements.length > 0
419
+ ? buildRequirementsCheck(requirements, { scenes, recipe: recipeResult?.recipe })
420
+ : { satisfied: [], missing: [], total: 0 };
421
+ const reviewSummary = {
422
+ iteration,
423
+ success: result.success,
424
+ elapsed: totalElapsed,
425
+ elapsedMs,
426
+ steps: stepCount,
427
+ scenesCreated: result.scenesCreated,
428
+ scenesUpdated: result.scenesUpdated,
429
+ errors: result.errors,
430
+ project: {
431
+ sceneCount: scenes.length,
432
+ totalDuration,
433
+ },
434
+ recipe: recipeResult?.recipe ? {
435
+ title: recipeResult.recipe.title,
436
+ sceneCount: recipeResult.recipe.scenes.length,
437
+ voiceoverCount: recipeResult.recipe.voiceovers.length,
438
+ } : null,
439
+ requirements: requirementsCheck,
440
+ };
441
+ results.push(reviewSummary);
442
+ emit({
443
+ type: 'ooda_observe',
444
+ iteration,
445
+ scenes: scenes.length,
446
+ duration: totalDuration,
447
+ });
448
+ emit({
449
+ type: 'ooda_orient',
450
+ iteration,
451
+ requirements: requirementsCheck,
452
+ });
453
+ emit({
454
+ type: 'loop_review',
455
+ ...reviewSummary,
456
+ });
457
+ if (!jsonOutput && !streamJson) {
458
+ if (result.success) {
459
+ success(`Iteration ${iteration} complete (${totalElapsed})`);
460
+ }
461
+ else {
462
+ error(`Iteration ${iteration} failed`);
463
+ }
464
+ console.log(chalk.gray(`Scenes: ${scenes.length} | Duration: ${totalDuration.toFixed(1)}s`));
465
+ if (requirements.length > 0) {
466
+ const missing = requirementsCheck.missing;
467
+ if (missing.length === 0) {
468
+ console.log(chalk.green('Requirements satisfied'));
469
+ }
470
+ else {
471
+ console.log(chalk.yellow(`Missing requirements: ${missing.join(', ')}`));
472
+ }
473
+ }
474
+ }
475
+ const satisfied = requirements.length === 0 || requirementsCheck.missing.length === 0;
476
+ const shouldStopOnFail = stopOnFail && !result.success;
477
+ if (shouldStopOnFail) {
478
+ emit({
479
+ type: 'ooda_decide',
480
+ iteration,
481
+ decision: 'stop',
482
+ reason: 'generation_failed',
483
+ });
484
+ break;
485
+ }
486
+ const elapsedAfter = Date.now() - loopStart;
487
+ if (budgetMs !== undefined && elapsedAfter > budgetMs) {
488
+ emit({
489
+ type: 'ooda_decide',
490
+ iteration,
491
+ decision: 'stop',
492
+ reason: 'budget_exceeded',
493
+ elapsedMs: elapsedAfter,
494
+ budgetMs,
495
+ });
496
+ break;
497
+ }
498
+ if (satisfied || iteration === maxIterations) {
499
+ emit({
500
+ type: 'ooda_decide',
501
+ iteration,
502
+ decision: 'stop',
503
+ reason: satisfied ? 'requirements_satisfied' : 'max_iterations',
504
+ });
505
+ break;
506
+ }
507
+ // Decide: re-run with a fix instruction
508
+ const missing = requirementsCheck.missing.join(', ');
509
+ const failureNote = !result.success && !stopOnFail
510
+ ? `The previous attempt failed with errors: ${(result.errors || []).join('; ')}.\n`
511
+ : '';
512
+ currentPrompt = `${basePrompt}\n\n${failureNote}The previous attempt did not satisfy these requirements: ${missing}.\nPlease update the scenes to satisfy them.`;
513
+ const iterElapsed = formatElapsed(Date.now() - iterStart);
514
+ emit({
515
+ type: 'ooda_decide',
516
+ iteration,
517
+ decision: 'continue',
518
+ reason: 'requirements_missing',
519
+ nextPrompt: currentPrompt,
520
+ elapsed: iterElapsed,
521
+ });
522
+ }
523
+ if (jsonOutput && !streamJson) {
524
+ output({
525
+ type: 'loop_summary',
526
+ projectId,
527
+ mode,
528
+ iterations: results.length,
529
+ results,
530
+ }, { json: true, compact: globalOpts.compact || agentModeEnv });
531
+ }
532
+ emit({
533
+ type: 'loop_complete',
534
+ iterations: results.length,
535
+ projectId,
536
+ mode,
537
+ });
538
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const mcpCommand: Command;
@@ -0,0 +1,143 @@
1
+ import { Command } from 'commander';
2
+ import { output } from '../lib/output.js';
3
+ import { CLI_VERSION } from '../lib/version.js';
4
+ function getMcpManifest() {
5
+ const tools = [
6
+ {
7
+ name: 'baz_prompt',
8
+ description: 'Generate or edit video scenes from a natural language prompt.',
9
+ command: 'baz prompt "<text>" --project-id <id> --stream-json',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ projectId: { type: 'string' },
14
+ prompt: { type: 'string' },
15
+ mode: { type: 'string', enum: ['agent', 'agent-max', 'multi-scene'] },
16
+ streamJson: { type: 'boolean', default: true },
17
+ },
18
+ required: ['projectId', 'prompt'],
19
+ },
20
+ },
21
+ {
22
+ name: 'baz_state',
23
+ description: 'Get project state snapshot for agent context.',
24
+ command: 'baz state --project-id <id> --json',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ projectId: { type: 'string' },
29
+ includeCode: { type: 'boolean', default: false },
30
+ includeMessages: { type: 'boolean', default: false },
31
+ },
32
+ required: ['projectId'],
33
+ },
34
+ },
35
+ {
36
+ name: 'baz_verify',
37
+ description: 'Verify the current project against criteria.',
38
+ command: 'baz verify --project-id <id> --criteria "<c1,c2>" --json',
39
+ inputSchema: {
40
+ type: 'object',
41
+ properties: {
42
+ projectId: { type: 'string' },
43
+ criteria: { type: 'array', items: { type: 'string' } },
44
+ sceneId: { type: 'string' },
45
+ },
46
+ required: ['projectId', 'criteria'],
47
+ },
48
+ },
49
+ {
50
+ name: 'baz_project_validate',
51
+ description: 'Run structural validation on project timeline.',
52
+ command: 'baz project validate --project-id <id> --json',
53
+ inputSchema: {
54
+ type: 'object',
55
+ properties: {
56
+ projectId: { type: 'string' },
57
+ },
58
+ required: ['projectId'],
59
+ },
60
+ },
61
+ {
62
+ name: 'baz_export_start',
63
+ description: 'Start a video export.',
64
+ command: 'baz export start --project-id <id> --json',
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {
68
+ projectId: { type: 'string' },
69
+ quality: { type: 'string', enum: ['1080p', '720p'] },
70
+ wait: { type: 'boolean', default: false },
71
+ },
72
+ required: ['projectId'],
73
+ },
74
+ },
75
+ {
76
+ name: 'baz_scenes_code',
77
+ description: 'Read TSX source code for a scene. Use before set-code to get current code.',
78
+ command: 'baz scenes code <scene-id> --project-id <id> --json',
79
+ inputSchema: {
80
+ type: 'object',
81
+ properties: {
82
+ projectId: { type: 'string' },
83
+ sceneId: { type: 'string' },
84
+ all: { type: 'boolean', default: false },
85
+ },
86
+ required: ['projectId'],
87
+ },
88
+ },
89
+ {
90
+ name: 'baz_scenes_set_code',
91
+ description: 'Replace scene TSX code directly. Read code first with baz_scenes_code, edit locally, then write back. No LLM in the middle — deterministic.',
92
+ command: 'baz scenes set-code <scene-id> --file <path> --project-id <id> --json',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ projectId: { type: 'string' },
97
+ sceneId: { type: 'string' },
98
+ file: { type: 'string', description: 'Path to file containing new TSX code' },
99
+ code: { type: 'string', description: 'Inline TSX code (alternative to file)' },
100
+ overwriteDuration: { type: 'boolean', default: false },
101
+ },
102
+ required: ['projectId', 'sceneId'],
103
+ },
104
+ },
105
+ ];
106
+ return {
107
+ protocol: 'mcp-manifest',
108
+ version: '1.0',
109
+ server: {
110
+ name: 'baz-cli',
111
+ cliVersion: CLI_VERSION,
112
+ transport: 'stdio-via-cli',
113
+ },
114
+ tools,
115
+ };
116
+ }
117
+ export const mcpCommand = new Command('mcp')
118
+ .description('Expose MCP-style tool manifest for agent integrations')
119
+ .action((options, cmd) => {
120
+ const globalOpts = cmd.optsWithGlobals();
121
+ output(getMcpManifest(), { json: true, compact: globalOpts.compact });
122
+ });
123
+ mcpCommand
124
+ .command('schema')
125
+ .description('Print MCP-style manifest schema')
126
+ .action((options, cmd) => {
127
+ const globalOpts = cmd.optsWithGlobals();
128
+ output(getMcpManifest(), { json: true, compact: globalOpts.compact });
129
+ });
130
+ mcpCommand
131
+ .command('tools')
132
+ .description('List MCP tool names')
133
+ .action((options, cmd) => {
134
+ const globalOpts = cmd.optsWithGlobals();
135
+ const manifest = getMcpManifest();
136
+ if (globalOpts.json) {
137
+ output(manifest.tools.map((tool) => tool.name), { json: true, compact: globalOpts.compact });
138
+ return;
139
+ }
140
+ for (const tool of manifest.tools) {
141
+ console.log(`${tool.name} - ${tool.description}`);
142
+ }
143
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const mediaCommand: Command;