@vorec/cli 0.11.0 → 1.0.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.
package/README.md CHANGED
@@ -49,9 +49,8 @@ Create a `vorec.json` file describing the actions to record:
49
49
  | Command | What it does |
50
50
  |---------|-------------|
51
51
  | `vorec init` | Save your API key |
52
- | `vorec run <manifest>` | Record and upload |
53
- | `vorec run <manifest> --auto` | Record, upload, and generate narration |
54
- | `vorec run <manifest> --auto --skip-record` | Resume an existing project |
52
+ | `vorec run <manifest>` | Record, upload, and generate narrated tutorial |
53
+ | `vorec run <manifest> --skip-record --video <file>` | Use existing video instead of recording |
55
54
  | `vorec upload <video>` | Upload a video file directly |
56
55
  | `vorec status` | Check project status |
57
56
 
@@ -1,5 +1,4 @@
1
1
  interface RunOptions {
2
- auto: boolean;
3
2
  skipRecord: boolean;
4
3
  video: string;
5
4
  trackedActions: string;
@@ -3,27 +3,12 @@ import ora from 'ora';
3
3
  import chalk from 'chalk';
4
4
  import { loadManifest } from '../manifest.js';
5
5
  import { apiCall, uploadVideo } from '../api.js';
6
- import { saveProjectState, loadProjectState } from '../config.js';
6
+ import { saveProjectState } from '../config.js';
7
7
  export async function runCommand(manifestPath, opts) {
8
8
  const manifest = loadManifest(manifestPath);
9
9
  console.log(chalk.bold(`Vorec: ${manifest.title}`));
10
10
  console.log(`Actions: ${manifest.actions.length}, URL: ${manifest.url}\n`);
11
- // Check if we're resuming an existing project (--skip-record with saved state)
12
- const savedState = loadProjectState();
13
- const resuming = opts.skipRecord && savedState?.projectId && savedState?.status === 'analyzing';
14
- if (resuming) {
15
- // Resume: skip recording + upload, go straight to analysis
16
- console.log(`Resuming project: ${savedState.projectId}`);
17
- if (opts.auto) {
18
- await runAnalysis(savedState.projectId, manifest);
19
- }
20
- else {
21
- const status = await apiCall('get-status', { projectId: savedState.projectId });
22
- console.log(`\n${chalk.bold('Editor:')} ${status.editor_url}`);
23
- }
24
- return;
25
- }
26
- // Fresh run: record → upload → (optionally analyze)
11
+ // Record upload generate
27
12
  let videoPath = opts.video;
28
13
  let trackedActions = [];
29
14
  let videoDuration = 0;
@@ -107,57 +92,50 @@ export async function runCommand(manifestPath, opts) {
107
92
  status: 'analyzing',
108
93
  });
109
94
  spinner.succeed(`Project created: ${createResult.projectId}`);
110
- if (!opts.auto) {
111
- const status = await apiCall('get-status', { projectId: createResult.projectId });
112
- console.log(`\nVideo uploaded. Run with --auto to continue processing.`);
113
- console.log(`${chalk.bold('Editor:')} ${status.editor_url}`);
114
- return;
115
- }
116
- // Auto mode: continue with analysis
117
- await runAnalysis(createResult.projectId, manifest);
118
- }
119
- async function runAnalysis(projectId, manifest) {
120
- // Analyze video
121
- const descSpinner = ora('Analyzing video...').start();
122
- try {
123
- const descResult = await apiCall('describe-video', {
124
- projectId,
125
- videoContext: manifest.videoContext,
126
- });
127
- descSpinner.succeed(`Video analyzed (${descResult.description?.length || 0} chars)`);
128
- }
129
- catch (err) {
130
- descSpinner.fail(`Analysis failed: ${err.message}`);
131
- process.exit(1);
132
- }
133
- // Generate narration
134
- const narrSpinner = ora('Writing narration...').start();
95
+ // Trigger analysis (runs in background on server)
96
+ const analysisSpinner = ora('Generating narrated tutorial...').start();
135
97
  try {
136
- const narrResult = await apiCall('generate-narration', {
137
- projectId,
98
+ await apiCall('generate-video', {
99
+ projectId: createResult.projectId,
138
100
  language: manifest.language,
139
101
  narrationStyle: manifest.narrationStyle,
102
+ videoContext: manifest.videoContext,
140
103
  customPrompt: manifest.customPrompt,
141
104
  includeIntro: false,
142
105
  });
143
- narrSpinner.succeed(`${narrResult.segments_created} narration segments`);
144
- if (narrResult.segments) {
145
- for (const seg of narrResult.segments) {
146
- console.log(chalk.dim(` [${seg.sort_order}] ${seg.timestamp_seconds.toFixed(1)}s — ${seg.action_name}`));
147
- }
148
- }
149
106
  }
150
107
  catch (err) {
151
- narrSpinner.fail(`Narration failed: ${err.message}`);
108
+ analysisSpinner.fail(`Failed to start analysis: ${err.message}`);
152
109
  process.exit(1);
153
110
  }
154
- // Done
155
- const finalStatus = await apiCall('get-status', { projectId });
156
- console.log(`\n${chalk.bold.green('Done!')} ${finalStatus.segments?.length || 0} segments ready`);
111
+ // Poll until done
112
+ let attempts = 0;
113
+ while (attempts < 120) {
114
+ await new Promise(r => setTimeout(r, 5000));
115
+ const status = await apiCall('get-status', { projectId: createResult.projectId });
116
+ const segCount = status.segments?.length || 0;
117
+ if (status.status === 'editing' || status.status === 'complete') {
118
+ analysisSpinner.succeed(`Done! ${segCount} narration segments`);
119
+ if (status.segments) {
120
+ for (const seg of status.segments) {
121
+ console.log(chalk.dim(` [${seg.sort_order}] ${Number(seg.timestamp_seconds).toFixed(1)}s — ${seg.action_name}`));
122
+ }
123
+ }
124
+ console.log(`\n${chalk.bold('Editor:')} ${status.editor_url}`);
125
+ console.log(chalk.dim('Open the editor to preview narration and generate audio.'));
126
+ saveProjectState({ projectId: createResult.projectId, status: 'complete' });
127
+ return;
128
+ }
129
+ if (status.status === 'draft' || status.status === 'error') {
130
+ analysisSpinner.fail(`Analysis ended with status: ${status.status}`);
131
+ process.exit(1);
132
+ }
133
+ analysisSpinner.text = `Generating narrated tutorial... (${status.status})`;
134
+ attempts++;
135
+ }
136
+ analysisSpinner.fail('Timed out waiting for analysis');
137
+ const finalStatus = await apiCall('get-status', { projectId: createResult.projectId });
157
138
  console.log(`${chalk.bold('Editor:')} ${finalStatus.editor_url}`);
158
- console.log(chalk.dim('Open the editor to preview narration and generate audio.'));
159
- // Clear state so next run creates a fresh project
160
- saveProjectState({ projectId, status: 'complete' });
161
139
  }
162
140
  async function recordAndTrack(manifest) {
163
141
  let pw;
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { statusCommand } from './commands/status.js';
7
7
  const program = new Command()
8
8
  .name('vorec')
9
9
  .description('Turn screen recordings into narrated tutorials')
10
- .version('0.11.0');
10
+ .version('1.0.1');
11
11
  program
12
12
  .command('init')
13
13
  .description('Save your Vorec API key')
@@ -27,9 +27,8 @@ program
27
27
  .action(uploadCommand);
28
28
  program
29
29
  .command('run <manifest>')
30
- .description('Full pipeline: record → upload narrate audio')
31
- .option('--auto', 'Wait for processing and generate audio', false)
32
- .option('--skip-record', 'Skip Playwright recording (use --video)', false)
30
+ .description('Record screen, upload, and generate narrated tutorial')
31
+ .option('--skip-record', 'Skip recording, use --video instead', false)
33
32
  .option('--video <path>', 'Use existing video file instead of recording')
34
33
  .option('--tracked-actions <path>', 'JSON file with tracked actions (for --skip-record)')
35
34
  .action(runCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vorec/cli",
3
- "version": "0.11.0",
3
+ "version": "1.0.1",
4
4
  "description": "Turn screen recordings into narrated tutorials — CLI for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {