bazaar.it 0.1.0 → 0.2.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.
Files changed (57) hide show
  1. package/README.md +489 -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 +529 -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 +186 -0
  42. package/dist/lib/api.js +717 -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 +39 -5
@@ -0,0 +1,360 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { loadConfig, hasAuth, getProjectId } from '../lib/config.js';
5
+ import { apiRequest, ApiError } from '../lib/api.js';
6
+ import { success, error, output } from '../lib/output.js';
7
+ function exitExportAuthError(globalOpts) {
8
+ if (globalOpts.json) {
9
+ output({
10
+ type: 'error',
11
+ code: 'AUTH_MISSING',
12
+ message: 'Not authenticated',
13
+ category: 'auth',
14
+ retryable: false,
15
+ transient: false,
16
+ exitCode: 13,
17
+ suggestion: 'Run: baz auth login <api-key>',
18
+ continue: false,
19
+ }, { json: true, compact: globalOpts.compact });
20
+ }
21
+ else {
22
+ error('Not authenticated', 'Run: baz auth login <api-key>');
23
+ }
24
+ process.exit(13);
25
+ }
26
+ export const exportCommand = new Command('export')
27
+ .description('Export video from active project');
28
+ /**
29
+ * baz export start
30
+ * Supports --wait for blocking operation (agent-friendly)
31
+ */
32
+ exportCommand
33
+ .command('start')
34
+ .description('Start a video export/render')
35
+ .option('--quality <quality>', 'Video quality: low, medium, high', 'high')
36
+ .option('--format <format>', 'Output format: mp4, webm, gif', 'mp4')
37
+ .option('--wait', 'Block until export completes (agent-friendly)')
38
+ .option('--timeout <seconds>', 'Fail if export takes longer than this (requires --wait)', '600')
39
+ .action(async (options, cmd) => {
40
+ const globalOpts = cmd.optsWithGlobals();
41
+ const config = loadConfig({
42
+ configPath: globalOpts.config,
43
+ apiUrl: globalOpts.apiUrl,
44
+ projectId: globalOpts.projectId,
45
+ });
46
+ if (!hasAuth(config)) {
47
+ exitExportAuthError(globalOpts);
48
+ }
49
+ let projectId;
50
+ try {
51
+ projectId = getProjectId(config, globalOpts.projectId);
52
+ }
53
+ catch (err) {
54
+ if (globalOpts.json) {
55
+ output({
56
+ type: 'error',
57
+ code: 'VALIDATION',
58
+ message: err.message,
59
+ category: 'validation',
60
+ retryable: false,
61
+ transient: false,
62
+ exitCode: 64,
63
+ continue: false,
64
+ }, { json: true, compact: globalOpts.compact });
65
+ }
66
+ else {
67
+ error(err.message);
68
+ }
69
+ process.exit(64); // Input error exit code
70
+ }
71
+ const spinner = ora('Starting export...').start();
72
+ const startTime = Date.now();
73
+ const timeoutMs = parseInt(options.timeout, 10) * 1000;
74
+ try {
75
+ const result = await apiRequest(config, 'render.startRender', {
76
+ projectId,
77
+ quality: options.quality,
78
+ format: options.format,
79
+ });
80
+ const renderId = result.renderId || result.id;
81
+ // If --wait flag, block until complete
82
+ if (options.wait) {
83
+ spinner.text = 'Rendering...';
84
+ const checkStatus = async () => {
85
+ return await apiRequest(config, 'render.getRenderStatus', { renderId });
86
+ };
87
+ let status = await checkStatus();
88
+ let lastProgress = 0;
89
+ while (status.status === 'pending' || status.status === 'rendering' || status.status === 'in_progress') {
90
+ // Check timeout
91
+ const elapsed = Date.now() - startTime;
92
+ if (elapsed > timeoutMs) {
93
+ spinner.fail();
94
+ if (globalOpts.json) {
95
+ console.log(JSON.stringify({
96
+ type: 'error',
97
+ code: 'TIMEOUT',
98
+ errorType: 'TIMEOUT',
99
+ message: `Export timed out after ${options.timeout} seconds`,
100
+ category: 'transient',
101
+ retryable: true,
102
+ transient: true,
103
+ continue: false,
104
+ }));
105
+ }
106
+ else {
107
+ error(`Export timed out after ${options.timeout} seconds`);
108
+ }
109
+ process.exit(10); // Transient error - can retry
110
+ }
111
+ const progress = status.progress || 0;
112
+ if (progress !== lastProgress) {
113
+ lastProgress = progress;
114
+ // Emit progress event for agents
115
+ if (globalOpts.json) {
116
+ console.log(JSON.stringify({
117
+ type: 'progress',
118
+ exportId: renderId,
119
+ progress,
120
+ eta_seconds: Math.ceil((timeoutMs - (Date.now() - startTime)) / 1000),
121
+ continue: true,
122
+ }));
123
+ }
124
+ }
125
+ spinner.text = `Rendering... ${progress}%`;
126
+ await new Promise(r => setTimeout(r, 3000));
127
+ status = await checkStatus();
128
+ }
129
+ spinner.stop();
130
+ if (status.status === 'completed' || status.status === 'done') {
131
+ const finalResult = {
132
+ type: 'export_completed',
133
+ success: true,
134
+ exportId: renderId,
135
+ url: status.url || status.outputUrl,
136
+ status: 'completed',
137
+ continue: false,
138
+ };
139
+ if (globalOpts.json) {
140
+ output(finalResult, { json: true });
141
+ }
142
+ else {
143
+ success('Export complete!');
144
+ if (status.url || status.outputUrl) {
145
+ console.log(` Download: ${chalk.cyan(status.url || status.outputUrl)}`);
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ // Export failed
151
+ if (globalOpts.json) {
152
+ console.log(JSON.stringify({
153
+ type: 'error',
154
+ code: 'EXPORT_FAILED',
155
+ errorType: 'EXPORT_FAILED',
156
+ message: status.error || 'Export failed',
157
+ category: 'fatal',
158
+ retryable: false,
159
+ transient: false,
160
+ continue: false,
161
+ }));
162
+ }
163
+ else {
164
+ error(`Export failed: ${status.error || status.status}`);
165
+ }
166
+ process.exit(1);
167
+ }
168
+ }
169
+ else {
170
+ // Non-blocking mode (original behavior)
171
+ spinner.stop();
172
+ if (globalOpts.json) {
173
+ output({
174
+ type: 'export_started',
175
+ exportId: renderId,
176
+ status: 'pending',
177
+ continue: true, // Agent should poll for completion
178
+ }, { json: true });
179
+ return;
180
+ }
181
+ success(`Export started!`);
182
+ console.log(` Render ID: ${chalk.cyan(renderId)}`);
183
+ console.log();
184
+ console.log(chalk.gray(`Check status: baz export status ${renderId}`));
185
+ console.log(chalk.gray(`Or use: baz export start --wait`));
186
+ }
187
+ }
188
+ catch (err) {
189
+ spinner.stop();
190
+ if (err instanceof ApiError) {
191
+ if (globalOpts.json) {
192
+ output({ ...err.toJSON(), continue: false }, { json: true, compact: globalOpts.compact });
193
+ }
194
+ else {
195
+ error(err.message, err.suggestion);
196
+ }
197
+ process.exit(err.exitCode);
198
+ }
199
+ if (globalOpts.json) {
200
+ output({
201
+ type: 'error',
202
+ code: 'UNKNOWN',
203
+ message: err.message,
204
+ category: 'fatal',
205
+ retryable: false,
206
+ transient: false,
207
+ exitCode: 1,
208
+ continue: false,
209
+ }, { json: true, compact: globalOpts.compact });
210
+ }
211
+ else {
212
+ error(err.message);
213
+ }
214
+ process.exit(1);
215
+ }
216
+ });
217
+ /**
218
+ * baz export status <renderId>
219
+ */
220
+ exportCommand
221
+ .command('status <renderId>')
222
+ .description('Check export status')
223
+ .option('--wait', 'Wait for completion')
224
+ .action(async (renderId, options, cmd) => {
225
+ const globalOpts = cmd.optsWithGlobals();
226
+ const config = loadConfig({
227
+ configPath: globalOpts.config,
228
+ apiUrl: globalOpts.apiUrl,
229
+ });
230
+ if (!hasAuth(config)) {
231
+ exitExportAuthError(globalOpts);
232
+ }
233
+ const checkStatus = async () => {
234
+ const result = await apiRequest(config, 'render.getRenderStatus', {
235
+ renderId,
236
+ });
237
+ return result;
238
+ };
239
+ if (options.wait) {
240
+ const spinner = ora('Waiting for export to complete...').start();
241
+ try {
242
+ let status = await checkStatus();
243
+ while (status.status === 'pending' || status.status === 'rendering' || status.status === 'in_progress') {
244
+ const progress = status.progress || 0;
245
+ spinner.text = `Rendering... ${progress}%`;
246
+ await new Promise(r => setTimeout(r, 3000));
247
+ status = await checkStatus();
248
+ }
249
+ spinner.stop();
250
+ if (globalOpts.json) {
251
+ output(status, { json: true });
252
+ return;
253
+ }
254
+ if (status.status === 'completed' || status.status === 'done') {
255
+ success('Export complete!');
256
+ if (status.url || status.outputUrl) {
257
+ console.log(` Download: ${chalk.cyan(status.url || status.outputUrl)}`);
258
+ }
259
+ }
260
+ else {
261
+ error(`Export failed: ${status.error || status.status}`);
262
+ process.exit(1);
263
+ }
264
+ }
265
+ catch (err) {
266
+ spinner.stop();
267
+ error(err.message);
268
+ process.exit(1);
269
+ }
270
+ }
271
+ else {
272
+ const spinner = ora('Checking status...').start();
273
+ try {
274
+ const status = await checkStatus();
275
+ spinner.stop();
276
+ if (globalOpts.json) {
277
+ output(status, { json: true });
278
+ return;
279
+ }
280
+ const statusColor = status.status === 'completed' || status.status === 'done' ? chalk.green :
281
+ status.status === 'failed' || status.status === 'error' ? chalk.red :
282
+ chalk.yellow;
283
+ console.log(`Status: ${statusColor(status.status)}`);
284
+ if (status.progress !== undefined) {
285
+ console.log(`Progress: ${status.progress}%`);
286
+ }
287
+ if (status.url || status.outputUrl) {
288
+ console.log(`Download: ${chalk.cyan(status.url || status.outputUrl)}`);
289
+ }
290
+ if (status.error) {
291
+ console.log(`Error: ${chalk.red(status.error)}`);
292
+ }
293
+ }
294
+ catch (err) {
295
+ spinner.stop();
296
+ error(err.message);
297
+ process.exit(1);
298
+ }
299
+ }
300
+ });
301
+ /**
302
+ * baz export list
303
+ */
304
+ exportCommand
305
+ .command('list')
306
+ .description('List recent exports')
307
+ .option('--limit <n>', 'Number of exports to show', '10')
308
+ .action(async (options, cmd) => {
309
+ const globalOpts = cmd.optsWithGlobals();
310
+ const config = loadConfig({
311
+ configPath: globalOpts.config,
312
+ apiUrl: globalOpts.apiUrl,
313
+ projectId: globalOpts.projectId,
314
+ });
315
+ if (!hasAuth(config)) {
316
+ exitExportAuthError(globalOpts);
317
+ }
318
+ let projectId;
319
+ try {
320
+ projectId = getProjectId(config, globalOpts.projectId);
321
+ }
322
+ catch (err) {
323
+ error(err.message);
324
+ process.exit(1);
325
+ }
326
+ const spinner = ora('Fetching exports...').start();
327
+ try {
328
+ const result = await apiRequest(config, 'render.listRenders', {
329
+ projectId,
330
+ limit: parseInt(options.limit, 10),
331
+ });
332
+ spinner.stop();
333
+ if (globalOpts.json) {
334
+ output(result, { json: true });
335
+ return;
336
+ }
337
+ const renders = Array.isArray(result) ? result : result.renders || [];
338
+ if (renders.length === 0) {
339
+ console.log(chalk.gray('No exports yet.'));
340
+ console.log(chalk.gray('Start one with: baz export start'));
341
+ return;
342
+ }
343
+ console.log(`Recent Exports (${renders.length}):`);
344
+ console.log();
345
+ for (const render of renders) {
346
+ const statusColor = render.status === 'completed' || render.status === 'done' ? chalk.green :
347
+ render.status === 'failed' || render.status === 'error' ? chalk.red :
348
+ chalk.yellow;
349
+ console.log(` ${chalk.gray(render.id?.slice(0, 8) || 'unknown')} ${statusColor(render.status)} ${render.createdAt || ''}`);
350
+ if (render.url || render.outputUrl) {
351
+ console.log(` ${chalk.cyan(render.url || render.outputUrl)}`);
352
+ }
353
+ }
354
+ }
355
+ catch (err) {
356
+ spinner.stop();
357
+ error(err.message);
358
+ process.exit(1);
359
+ }
360
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const logsCommand: Command;
@@ -0,0 +1,180 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { loadConfig, hasAuth, getProjectId } from '../lib/config.js';
5
+ import { apiRequest, ApiError, ErrorCodes } from '../lib/api.js';
6
+ import { error, output } from '../lib/output.js';
7
+ /**
8
+ * Format timestamp for display
9
+ */
10
+ function formatTime(isoString) {
11
+ const date = new Date(isoString);
12
+ return date.toLocaleTimeString('en-US', {
13
+ hour: '2-digit',
14
+ minute: '2-digit',
15
+ second: '2-digit',
16
+ hour12: false,
17
+ });
18
+ }
19
+ /**
20
+ * Color log level
21
+ */
22
+ function colorLevel(level) {
23
+ if (!level)
24
+ return chalk.gray('info');
25
+ switch (level.toLowerCase()) {
26
+ case 'error':
27
+ return chalk.red('error');
28
+ case 'warn':
29
+ case 'warning':
30
+ return chalk.yellow('warn');
31
+ case 'info':
32
+ return chalk.blue('info');
33
+ case 'debug':
34
+ return chalk.gray('debug');
35
+ default:
36
+ return chalk.gray(level);
37
+ }
38
+ }
39
+ /**
40
+ * Truncate message for display
41
+ */
42
+ function truncateMessage(msg, maxLen = 100) {
43
+ if (msg.length <= maxLen)
44
+ return msg;
45
+ return msg.slice(0, maxLen - 3) + '...';
46
+ }
47
+ export const logsCommand = new Command('logs')
48
+ .description('Query recent project/runtime logs')
49
+ .option('--errors', 'Show only errors')
50
+ .option('--search <text>', 'Search for text in log messages')
51
+ .option('--path <path>', 'Filter by API path (e.g., /api/generate-stream)')
52
+ .option('--since <time>', 'Time range: 5m, 1h, 24h, 7d (default: 1h)', '1h')
53
+ .option('--limit <n>', 'Maximum number of logs to show (default: 50)', '50')
54
+ .option('--project', 'Filter logs by current project ID')
55
+ .action(async (options, cmd) => {
56
+ const globalOpts = cmd.optsWithGlobals();
57
+ const config = loadConfig({
58
+ configPath: globalOpts.config,
59
+ apiUrl: globalOpts.apiUrl,
60
+ projectId: globalOpts.projectId,
61
+ });
62
+ if (!hasAuth(config)) {
63
+ if (globalOpts.json) {
64
+ output({
65
+ type: 'error',
66
+ code: 'AUTH_MISSING',
67
+ message: 'Not authenticated',
68
+ category: 'auth',
69
+ retryable: false,
70
+ transient: false,
71
+ exitCode: 13,
72
+ suggestion: 'Run: baz auth login <api-key>',
73
+ }, { json: true, compact: globalOpts.compact });
74
+ }
75
+ else {
76
+ error('Not authenticated', 'Run: baz auth login <api-key>');
77
+ }
78
+ process.exit(13);
79
+ }
80
+ // Build query parameters
81
+ const params = {
82
+ since: options.since,
83
+ limit: options.limit,
84
+ };
85
+ if (options.errors) {
86
+ params.errorsOnly = 'true';
87
+ }
88
+ if (options.search) {
89
+ params.search = options.search;
90
+ }
91
+ if (options.path) {
92
+ params.path = options.path;
93
+ }
94
+ // Get project ID if filtering by project
95
+ if (options.project) {
96
+ try {
97
+ params.projectId = getProjectId(config, globalOpts.projectId);
98
+ }
99
+ catch (err) {
100
+ if (globalOpts.json) {
101
+ output({
102
+ type: 'error',
103
+ code: 'VALIDATION',
104
+ message: err.message,
105
+ category: 'validation',
106
+ retryable: false,
107
+ transient: false,
108
+ exitCode: 64,
109
+ }, { json: true, compact: globalOpts.compact });
110
+ }
111
+ else {
112
+ error(err.message);
113
+ }
114
+ process.exit(64);
115
+ }
116
+ }
117
+ const spinner = globalOpts.json ? null : ora('Querying logs...').start();
118
+ try {
119
+ const result = await apiRequest(config, 'logs.query', params);
120
+ spinner?.stop();
121
+ if (globalOpts.json) {
122
+ output(result, { json: true, compact: globalOpts.compact });
123
+ return;
124
+ }
125
+ if (!result.logs || result.logs.length === 0) {
126
+ console.log(chalk.gray('No logs found matching your criteria.'));
127
+ console.log(chalk.dim(`\nTry adjusting your filters or time range (--since ${options.since})`));
128
+ return;
129
+ }
130
+ // Display logs
131
+ console.log(chalk.cyan(`Found ${result.logs.length} logs:`));
132
+ console.log();
133
+ for (const log of result.logs) {
134
+ const time = formatTime(log._time);
135
+ const level = colorLevel(log.level);
136
+ const path = log['request.path'] ? chalk.dim(` [${log['request.path']}]`) : '';
137
+ const duration = log['report.durationMs'] ? chalk.dim(` ${log['report.durationMs']}ms`) : '';
138
+ const message = log.message ? truncateMessage(log.message, 80) : '';
139
+ console.log(`${chalk.gray(time)} ${level}${path}${duration} ${message}`);
140
+ }
141
+ if (result.total > result.logs.length) {
142
+ console.log();
143
+ console.log(chalk.dim(`Showing ${result.logs.length} of ${result.total} logs. Use --limit to see more.`));
144
+ }
145
+ }
146
+ catch (err) {
147
+ spinner?.fail('Failed to query logs');
148
+ if (err instanceof ApiError) {
149
+ if (err.code === ErrorCodes.NOT_FOUND) {
150
+ console.log(chalk.gray('No logs found for your filters.'));
151
+ return;
152
+ }
153
+ if (globalOpts.json) {
154
+ output(err.toJSON(), { json: true, compact: globalOpts.compact });
155
+ }
156
+ else {
157
+ error(err.message, err.suggestion);
158
+ }
159
+ }
160
+ else {
161
+ if (globalOpts.json) {
162
+ output({
163
+ type: 'error',
164
+ code: 'UNKNOWN',
165
+ message: err.message,
166
+ category: 'fatal',
167
+ retryable: false,
168
+ transient: false,
169
+ exitCode: 1,
170
+ }, { json: true, compact: globalOpts.compact });
171
+ }
172
+ else {
173
+ error(err.message);
174
+ }
175
+ }
176
+ process.exit(1);
177
+ }
178
+ });
179
+ // Note: Shortcut subcommands like `baz logs errors` removed to avoid
180
+ // recursive parsing issues. Use `baz logs --errors` instead.
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const loopCommand: Command;