dashcam 1.0.1-beta.9 → 1.1.0-beta.3

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.
@@ -0,0 +1,287 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for analyzing short recording issues
5
+ *
6
+ * This tests whether very short recordings produce valid multi-frame videos
7
+ * with properly finalized WebM container metadata.
8
+ *
9
+ * Known issue: If ffmpeg/VP9 encoder is killed too quickly, the WebM container
10
+ * metadata (especially duration) may be incomplete, causing playback issues.
11
+ *
12
+ * Usage:
13
+ * node test-short-recording.js # Run recording tests
14
+ * node test-short-recording.js analyze <file> # Analyze existing video
15
+ * node test-short-recording.js fix <input> <output> # Fix broken video container
16
+ *
17
+ * Platform notes:
18
+ * - macOS: Uses AVFoundation for screen capture
19
+ * - Linux: Uses X11grab for screen capture
20
+ * - Windows: Uses gdigrab for screen capture
21
+ */
22
+
23
+ import { startRecording, stopRecording, fixVideoContainer } from './lib/recorder.js';
24
+ import { execa } from 'execa';
25
+ import { getFfprobePath } from './lib/binaries.js';
26
+ import fs from 'fs';
27
+ import path from 'path';
28
+ import os from 'os';
29
+
30
+ async function analyzeVideo(videoPath) {
31
+ const ffprobePath = await getFfprobePath();
32
+
33
+ console.log(`\nšŸ“Š Analyzing video: ${videoPath}`);
34
+ console.log('─'.repeat(80));
35
+
36
+ // Check if file exists
37
+ if (!fs.existsSync(videoPath)) {
38
+ console.error(`āŒ Video file does not exist: ${videoPath}`);
39
+ return null;
40
+ }
41
+
42
+ const stats = fs.statSync(videoPath);
43
+ console.log(`šŸ“ File size: ${(stats.size / 1024).toFixed(2)} KB`);
44
+
45
+ try {
46
+ // Get basic format info
47
+ const formatResult = await execa(ffprobePath, [
48
+ '-v', 'error',
49
+ '-show_entries', 'format=duration,size,bit_rate',
50
+ '-of', 'json',
51
+ videoPath
52
+ ]);
53
+
54
+ const formatData = JSON.parse(formatResult.stdout);
55
+ console.log(`ā±ļø Duration: ${formatData.format.duration || 'unknown'}s`);
56
+ console.log(`šŸ“Š Bit rate: ${formatData.format.bit_rate || 'unknown'} bits/s`);
57
+
58
+ // Get stream info
59
+ const streamResult = await execa(ffprobePath, [
60
+ '-v', 'error',
61
+ '-show_entries', 'stream=codec_name,width,height,r_frame_rate,duration',
62
+ '-of', 'json',
63
+ videoPath
64
+ ]);
65
+
66
+ const streamData = JSON.parse(streamResult.stdout);
67
+ const videoStream = streamData.streams.find(s => s.codec_name);
68
+
69
+ if (videoStream) {
70
+ console.log(`šŸŽ„ Codec: ${videoStream.codec_name}`);
71
+ console.log(`šŸ“ Resolution: ${videoStream.width}x${videoStream.height}`);
72
+ console.log(`šŸŽžļø Frame rate: ${videoStream.r_frame_rate}`);
73
+ }
74
+
75
+ // Count actual frames
76
+ const frameResult = await execa(ffprobePath, [
77
+ '-v', 'error',
78
+ '-count_frames',
79
+ '-select_streams', 'v:0',
80
+ '-show_entries', 'stream=nb_read_frames',
81
+ '-of', 'default=nokey=1:noprint_wrappers=1',
82
+ videoPath
83
+ ], { reject: false });
84
+
85
+ const frameCount = parseInt(frameResult.stdout.trim());
86
+ console.log(`šŸ–¼ļø Frame count: ${frameCount || 'unknown'}`);
87
+
88
+ if (frameResult.stderr) {
89
+ console.log(`āš ļø FFprobe warnings: ${frameResult.stderr.trim()}`);
90
+ }
91
+
92
+ // Check if duration is available in container
93
+ const hasDuration = formatData.format.duration && !isNaN(parseFloat(formatData.format.duration));
94
+
95
+ // Determine if this is a single-frame video issue
96
+ const isSingleFrame = frameCount === 1;
97
+ const hasEncodingIssues = frameResult.stderr.includes('File ended prematurely');
98
+ const hasMissingMetadata = !hasDuration;
99
+
100
+ console.log('\nšŸ“‹ Analysis Result:');
101
+ console.log(` Single frame: ${isSingleFrame ? 'āŒ YES (BUG!)' : 'āœ… NO'}`);
102
+ console.log(` Encoding issues: ${hasEncodingIssues ? 'āš ļø YES' : 'āœ… NO'}`);
103
+ console.log(` Missing metadata: ${hasMissingMetadata ? 'āš ļø YES (container incomplete)' : 'āœ… NO'}`);
104
+ console.log(` Platform: ${os.platform()}`);
105
+
106
+ return {
107
+ exists: true,
108
+ size: stats.size,
109
+ duration: parseFloat(formatData.format.duration),
110
+ frameCount,
111
+ codec: videoStream?.codec_name,
112
+ resolution: videoStream ? `${videoStream.width}x${videoStream.height}` : 'unknown',
113
+ isSingleFrame,
114
+ hasEncodingIssues,
115
+ hasMissingMetadata,
116
+ platform: os.platform()
117
+ };
118
+
119
+ } catch (error) {
120
+ console.error(`āŒ Error analyzing video: ${error.message}`);
121
+ return null;
122
+ }
123
+ }
124
+
125
+ async function testShortRecording(duration = 3000) {
126
+ console.log(`\nšŸŽ¬ Testing ${duration}ms recording...`);
127
+ console.log('═'.repeat(80));
128
+
129
+ try {
130
+ // Start recording
131
+ console.log('ā–¶ļø Starting recording...');
132
+ const { outputPath, startTime } = await startRecording({
133
+ fps: 30,
134
+ includeAudio: false
135
+ });
136
+
137
+ console.log(`āœ… Recording started at: ${outputPath}`);
138
+
139
+ // Wait for specified duration
140
+ console.log(`ā³ Recording for ${duration}ms...`);
141
+ await new Promise(resolve => setTimeout(resolve, duration));
142
+
143
+ // Stop recording
144
+ console.log('ā¹ļø Stopping recording...');
145
+ const result = await stopRecording();
146
+
147
+ console.log(`āœ… Recording stopped`);
148
+ console.log(` Duration: ${result.duration}ms`);
149
+ console.log(` File: ${result.outputPath}`);
150
+
151
+ // Analyze the output
152
+ await analyzeVideo(result.outputPath);
153
+
154
+ return result;
155
+
156
+ } catch (error) {
157
+ console.error(`āŒ Test failed: ${error.message}`);
158
+ console.error(error.stack);
159
+ throw error;
160
+ }
161
+ }
162
+
163
+ async function testExistingVideo(videoPath) {
164
+ console.log('\nšŸ” Testing existing video...');
165
+ console.log('═'.repeat(80));
166
+
167
+ return await analyzeVideo(videoPath);
168
+ }
169
+
170
+ // Main test runner
171
+ async function main() {
172
+ const args = process.argv.slice(2);
173
+
174
+ console.log('\n🧪 Short Recording Test Suite');
175
+ console.log('═'.repeat(80));
176
+ console.log(`Platform: ${os.platform()}`);
177
+ console.log(`Architecture: ${os.arch()}`);
178
+ console.log(`Node version: ${process.version}`);
179
+
180
+ if (args[0] === 'analyze' && args[1]) {
181
+ // Analyze existing video
182
+ const videoPath = path.resolve(args[1]);
183
+ const result = await testExistingVideo(videoPath);
184
+
185
+ if (result?.isSingleFrame) {
186
+ console.log('\nāŒ SINGLE-FRAME VIDEO DETECTED!');
187
+ process.exit(1);
188
+ } else if (result?.hasMissingMetadata) {
189
+ console.log('\nāš ļø WARNING: Video container metadata is incomplete!');
190
+ console.log(' This can cause playback issues in some players.');
191
+ console.log(' The video has frames but duration is not in the container.');
192
+ console.log('\nšŸ’” Try fixing it with:');
193
+ console.log(` node test-short-recording.js fix ${args[1]} ${args[1].replace(/\.(webm|mp4)$/, '-fixed.$1')}`);
194
+ process.exit(1);
195
+ }
196
+ } else if (args[0] === 'fix' && args[1] && args[2]) {
197
+ // Fix existing broken video
198
+ const inputPath = path.resolve(args[1]);
199
+ const outputPath = path.resolve(args[2]);
200
+
201
+ console.log('\nšŸ”§ Fixing video container...');
202
+ console.log('═'.repeat(80));
203
+ console.log(`Input: ${inputPath}`);
204
+ console.log(`Output: ${outputPath}`);
205
+
206
+ if (!fs.existsSync(inputPath)) {
207
+ console.error(`āŒ Input file does not exist: ${inputPath}`);
208
+ process.exit(1);
209
+ }
210
+
211
+ // Analyze before
212
+ console.log('\nšŸ“Š BEFORE:');
213
+ const beforeResult = await analyzeVideo(inputPath);
214
+
215
+ // Fix the video
216
+ const fixSuccess = await fixVideoContainer(inputPath, outputPath);
217
+
218
+ if (!fixSuccess) {
219
+ console.error('\nāŒ Failed to fix video!');
220
+ process.exit(1);
221
+ }
222
+
223
+ // Analyze after
224
+ console.log('\nšŸ“Š AFTER:');
225
+ const afterResult = await analyzeVideo(outputPath);
226
+
227
+ console.log('\nāœ… Video fixed successfully!');
228
+ console.log(` Before: ${beforeResult?.hasMissingMetadata ? 'Missing metadata āš ļø' : 'Has metadata āœ…'}`);
229
+ console.log(` After: ${afterResult?.hasMissingMetadata ? 'Missing metadata āš ļø' : 'Has metadata āœ…'}`);
230
+
231
+ if (afterResult?.hasMissingMetadata) {
232
+ console.log('\nāš ļø Warning: Metadata still missing after fix. The source file may be corrupted.');
233
+ process.exit(1);
234
+ }
235
+ } else {
236
+ // Run recording tests with different durations
237
+ const testDurations = [1000, 2000, 3000, 5000];
238
+ const results = [];
239
+
240
+ for (const duration of testDurations) {
241
+ try {
242
+ const result = await testShortRecording(duration);
243
+ results.push({ duration, success: true, result });
244
+
245
+ // Clean up
246
+ try {
247
+ fs.unlinkSync(result.outputPath);
248
+ if (result.gifPath && fs.existsSync(result.gifPath)) {
249
+ fs.unlinkSync(result.gifPath);
250
+ }
251
+ if (result.snapshotPath && fs.existsSync(result.snapshotPath)) {
252
+ fs.unlinkSync(result.snapshotPath);
253
+ }
254
+ } catch (cleanupError) {
255
+ console.warn(`āš ļø Cleanup warning: ${cleanupError.message}`);
256
+ }
257
+ } catch (error) {
258
+ results.push({ duration, success: false, error: error.message });
259
+ }
260
+
261
+ // Wait between tests
262
+ await new Promise(resolve => setTimeout(resolve, 2000));
263
+ }
264
+
265
+ // Summary
266
+ console.log('\n\nšŸ“Š TEST SUMMARY');
267
+ console.log('═'.repeat(80));
268
+
269
+ for (const result of results) {
270
+ const status = result.success ? 'āœ…' : 'āŒ';
271
+ console.log(`${status} ${result.duration}ms recording: ${result.success ? 'PASSED' : result.error}`);
272
+ }
273
+
274
+ const allPassed = results.every(r => r.success);
275
+ if (!allPassed) {
276
+ console.log('\nāŒ Some tests failed!');
277
+ process.exit(1);
278
+ } else {
279
+ console.log('\nāœ… All tests passed!');
280
+ }
281
+ }
282
+ }
283
+
284
+ main().catch(error => {
285
+ console.error('Fatal error:', error);
286
+ process.exit(1);
287
+ });
package/test_workflow.sh CHANGED
@@ -30,29 +30,30 @@ if [ ! -f "$TEMP_FILE" ]; then
30
30
  fi
31
31
  echo "āœ… File tracking configured"
32
32
 
33
- # 4. Start dashcam recording in background
33
+ # 4. Start dashcam recording in background with timeout to auto-stop
34
34
  echo ""
35
- echo "4. Starting dashcam recording in background..."
36
- # Start recording and redirect output to a log file so we can still monitor it
35
+ echo "4. Starting dashcam recording..."
36
+ # Start recording in background and set up auto-stop after test duration
37
37
  ./bin/dashcam.js record --title "Sync Test Recording" --description "Testing video/log synchronization with timestamped events" > /tmp/dashcam-recording.log 2>&1 &
38
38
  RECORD_PID=$!
39
39
 
40
40
  # Wait for recording to initialize and log tracker to start
41
41
  echo "Waiting for recording to initialize (PID: $RECORD_PID)..."
42
- sleep 1
42
+ sleep 2
43
43
 
44
44
  # Write first event after log tracker is fully ready
45
45
  RECORDING_START=$(date +%s)
46
46
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
47
47
  echo "šŸ”“ EVENT 1: Recording START at $(date '+%H:%M:%S')"
48
48
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
49
- echo "[EVENT 1] Recording started at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_START" >> "$TEMP_FILE"
49
+ echo "[EVENT 1] šŸ”“ Recording started with emoji at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_START" >> "$TEMP_FILE"
50
50
 
51
51
  # Verify recording is actually running
52
52
  if ps -p $RECORD_PID > /dev/null; then
53
53
  echo "āœ… Recording started successfully"
54
54
  else
55
55
  echo "āŒ Recording process died, check /tmp/dashcam-recording.log"
56
+ cat /tmp/dashcam-recording.log
56
57
  exit 1
57
58
  fi
58
59
 
@@ -71,25 +72,25 @@ sleep 3
71
72
  # Event 2 - after 3 seconds
72
73
  echo ""
73
74
  echo "🟔 EVENT 2: 3 seconds mark at $(date '+%H:%M:%S')"
74
- echo "[EVENT 2] 3 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
75
+ echo "[EVENT 2] 🟔 3 seconds elapsed with emoji at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
75
76
  sleep 3
76
77
 
77
78
  # Event 3 - after 6 seconds
78
79
  echo ""
79
80
  echo "🟢 EVENT 3: 6 seconds mark at $(date '+%H:%M:%S')"
80
- echo "[EVENT 3] 6 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
81
+ echo "[EVENT 3] 🟢 6 seconds elapsed with emoji at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
81
82
  sleep 3
82
83
 
83
84
  # Event 4 - after 9 seconds
84
85
  echo ""
85
86
  echo "šŸ”µ EVENT 4: 9 seconds mark at $(date '+%H:%M:%S')"
86
- echo "[EVENT 4] 9 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
87
+ echo "[EVENT 4] šŸ”µ 9 seconds elapsed with emoji at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
87
88
  sleep 3
88
89
 
89
90
  # Event 5 - after 12 seconds
90
91
  echo ""
91
92
  echo "🟣 EVENT 5: 12 seconds mark at $(date '+%H:%M:%S')"
92
- echo "[EVENT 5] 12 seconds elapsed at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
93
+ echo "[EVENT 5] 🟣 12 seconds elapsed with emoji at $(date '+%H:%M:%S')" >> "$TEMP_FILE"
93
94
  sleep 3
94
95
 
95
96
  # Event 6 - before ending
@@ -98,7 +99,7 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
98
99
  echo "⚫ EVENT 6: Recording END at $(date '+%H:%M:%S')"
99
100
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
100
101
  RECORDING_END=$(date +%s)
101
- echo "[EVENT 6] Recording ending at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_END" >> "$TEMP_FILE"
102
+ echo "[EVENT 6] ⚫ Recording ending with emoji at $(date '+%H:%M:%S') - TIMESTAMP: $RECORDING_END" >> "$TEMP_FILE"
102
103
 
103
104
  DURATION=$((RECORDING_END - RECORDING_START))
104
105
  echo ""
@@ -109,11 +110,29 @@ echo ""
109
110
  echo "Waiting 2 seconds to ensure all events are captured..."
110
111
  sleep 2
111
112
 
112
- # 6. Stop recording and upload (this will kill the background recording process)
113
+ # 6. Stop recording by sending SIGINT (Ctrl+C) to the recording process
113
114
  echo ""
114
- echo "6. Stopping recording and uploading..."
115
- ./bin/dashcam.js stop
116
- echo "āœ… Recording stopped and uploaded"
115
+ echo "6. Stopping recording (sending SIGINT)..."
116
+ # Check if recording is still active
117
+ if ps -p $RECORD_PID > /dev/null; then
118
+ kill -INT $RECORD_PID
119
+ echo "Sent SIGINT to recording process, waiting for upload to complete..."
120
+
121
+ # Wait for the process to finish (it will stop recording and upload)
122
+ wait $RECORD_PID 2>/dev/null || true
123
+
124
+ echo "āœ… Recording stopped and upload completed"
125
+
126
+ # Show the output from the recording process
127
+ echo ""
128
+ echo "Recording output:"
129
+ cat /tmp/dashcam-recording.log
130
+ else
131
+ echo "āš ļø Recording process already completed"
132
+ echo ""
133
+ echo "Recording output:"
134
+ cat /tmp/dashcam-recording.log
135
+ fi
117
136
 
118
137
  echo ""
119
138
  echo "🧹 Cleaning up..."
@@ -122,11 +141,6 @@ echo ""
122
141
  echo "šŸŽ‰ Test workflow completed successfully!"
123
142
  echo "======================================"
124
143
 
125
- # Show final status
126
- echo ""
127
- echo "šŸ“Š Final Status:"
128
- ./bin/dashcam.js status
129
-
130
144
  echo ""
131
145
  echo "╔════════════════════════════════════════════════════════════════╗"
132
146
  echo "ā•‘ SYNC VERIFICATION GUIDE ā•‘"
@@ -140,12 +154,12 @@ echo "3. Verify these events appear at the correct times:"
140
154
  echo ""
141
155
  echo " Time | Terminal Display | Log Entry"
142
156
  echo " -------|---------------------------|---------------------------"
143
- echo " 0:00 | šŸ”“ EVENT 1 | [EVENT 1] Recording started"
144
- echo " 0:03 | 🟔 EVENT 2 | [EVENT 2] 3 seconds elapsed"
145
- echo " 0:06 | 🟢 EVENT 3 | [EVENT 3] 6 seconds elapsed"
146
- echo " 0:09 | šŸ”µ EVENT 4 | [EVENT 4] 9 seconds elapsed"
147
- echo " 0:12 | 🟣 EVENT 5 | [EVENT 5] 12 seconds elapsed"
148
- echo " 0:15 | ⚫ EVENT 6 | [EVENT 6] Recording ending"
157
+ echo " 0:00 | šŸ”“ EVENT 1 | [EVENT 1] šŸ”“ Recording started"
158
+ echo " 0:03 | 🟔 EVENT 2 | [EVENT 2] 🟔 3 seconds elapsed"
159
+ echo " 0:06 | 🟢 EVENT 3 | [EVENT 3] 🟢 6 seconds elapsed"
160
+ echo " 0:09 | šŸ”µ EVENT 4 | [EVENT 4] šŸ”µ 9 seconds elapsed"
161
+ echo " 0:12 | 🟣 EVENT 5 | [EVENT 5] 🟣 12 seconds elapsed"
162
+ echo " 0:15 | ⚫ EVENT 6 | [EVENT 6] ⚫ Recording ending"
149
163
  echo ""
150
164
  echo "4. The log timestamps should match the video timeline exactly"
151
165
  echo "5. Each colored event marker should appear in the video"
@@ -1,177 +0,0 @@
1
- # Backward Compatibility Summary
2
-
3
- This document confirms that `dashcam-cli-minimal` now supports all commands and arguments documented in the README.md.
4
-
5
- ## āœ… Implemented Commands
6
-
7
- ### `auth <api-key>`
8
- Authenticate the dashcam desktop using a team's apiKey.
9
- ```bash
10
- dashcam auth <api-key>
11
- ```
12
-
13
- ### `create [options]`
14
- Create a clip from current recording and output the resulting url or markdown. This stops the current recording and uploads it.
15
- ```bash
16
- # Start instant replay in background
17
- dashcam start
18
-
19
- # Later, create a clip from the recording
20
- dashcam create
21
- dashcam create -t "My New Title"
22
- dashcam create --md
23
- dashcam create -k wef8we72h23012j
24
- dashcam create -d "Description text"
25
- cat README.md | dashcam create
26
- ```
27
-
28
- Options:
29
- - `-t, --title <string>` - Title of the replay
30
- - `-d, --description [text]` - Replay markdown body (supports piped input)
31
- - `--md` - Returns rich markdown image link
32
- - `-k, --project <project>` - Project ID to publish to
33
-
34
- **Note:** `create` stops the current recording and creates a clip. It's similar to `stop` but focused on outputting URLs/markdown for integration with other tools.
35
-
36
- ### `record [options]`
37
- Start a recording terminal to be included in your dashcam video recording.
38
- ```bash
39
- dashcam record
40
- ```
41
-
42
- Options:
43
- - `-t, --title <title>` - Title for the recording
44
- - `-d, --description <description>` - Description for the recording
45
- - `-p, --project <project>` - Project ID to upload to
46
- - `-a, --audio` - Include audio
47
- - `-f, --fps <fps>` - Frames per second
48
-
49
- ### `pipe`
50
- Pipe command output to dashcam to be included in recorded video.
51
- ```bash
52
- ping 1.1.1.1 | dashcam pipe
53
- cat /var/log/system.log | dashcam pipe
54
- ```
55
-
56
- ### `track [options]`
57
- Add a logs config to Dashcam.
58
-
59
- **New Syntax (matches README):**
60
- ```bash
61
- dashcam track --name=social --type=web --pattern="*facebook.com*" --pattern="*twitter.com*"
62
- dashcam track --name=app-logs --type=application --pattern="/var/log/*.log"
63
- ```
64
-
65
- **Old Syntax (still supported):**
66
- ```bash
67
- dashcam track --web "*facebook.com*"
68
- dashcam track --app "/var/log/app.log"
69
- ```
70
-
71
- Options:
72
- - `--name <name>` - Name for the tracking configuration (required with new syntax)
73
- - `--type <type>` - Type: "application" or "web" (required with new syntax)
74
- - `--pattern <pattern>` - Pattern to track (can use multiple times)
75
- - `--web <pattern>` - Web URL pattern (deprecated, use --type=web --pattern)
76
- - `--app <pattern>` - Application file pattern (deprecated, use --type=application --pattern)
77
-
78
- ### `start`
79
- Start instant replay recording on dashcam.
80
- ```bash
81
- dashcam start
82
- ```
83
-
84
- ### `stop`
85
- Stop the current recording and upload.
86
- ```bash
87
- dashcam stop
88
- ```
89
-
90
- ### `status`
91
- Show current recording status.
92
- ```bash
93
- dashcam status
94
- ```
95
-
96
- ## Examples from README
97
-
98
- All examples from the README should now work:
99
-
100
- ### Basic usage
101
- ```bash
102
- # Create a replay
103
- dashcam create
104
- # Returns: https://dashcam.io/replay/123?share=xyz
105
-
106
- # With markdown output
107
- dashcam create --md
108
-
109
- # With title
110
- dashcam create -t "My New Title"
111
-
112
- # With project
113
- dashcam create -k wef8we72h23012j
114
-
115
- # Attach last 20 CLI commands
116
- history -20 | dashcam create
117
-
118
- # Attach a logfile
119
- cat /var/log/system.log | dashcam create
120
- ```
121
-
122
- ### Tracking logs
123
- ```bash
124
- # Track web URLs
125
- dashcam track --name=social --type=web --pattern="*facebook.com*" --pattern="*twitter.com*"
126
-
127
- # Track application files
128
- dashcam track --name=app-logs --type=application --pattern="/var/log/*.log"
129
- ```
130
-
131
- ### Recording
132
- ```bash
133
- # Start recording
134
- dashcam record
135
-
136
- # Pipe output into recording
137
- ping 1.1.1.1 | dashcam pipe
138
-
139
- # Stop recording
140
- dashcam stop
141
- ```
142
-
143
- ### GitHub CLI integration
144
- ```bash
145
- # Create GitHub issue with replay
146
- gh issue create -w -t "Title" -b "`dashcam create --md`"
147
-
148
- # With system logs
149
- gh issue create -w -t "Title" -b "`cat /var/log/system.log | dashcam create --md`"
150
-
151
- # Create PR with replay
152
- gh pr create -w -t "Title" -b "`dashcam create --md`"
153
-
154
- # Append to commit
155
- git commit -am "`dashcam create`"
156
- ```
157
-
158
- ## Key Changes for Backward Compatibility
159
-
160
- 1. **Added `create` command** - Stops current recording and creates a clip with URL/markdown output
161
- 2. **Added `pipe` command** - Allows piping command output into recordings
162
- 3. **Added `start` command** - Simple way to start instant replay recording in background
163
- 4. **Updated `track` command** - Now supports both old syntax (--web, --app) and new syntax (--name, --type, --pattern)
164
- 5. **Updated descriptions** - Match README text exactly
165
- 6. **Updated `auth` parameter** - Changed from `<apiKey>` to `<api-key>` to match README
166
- 7. **Added `-k` alias** - For `--project` option in `create` command
167
- 8. **Shared implementation** - `create`, `record`, and `start` share common code to avoid duplication
168
-
169
- ## Migration Notes
170
-
171
- - **`start`** - Starts instant replay recording in background (like desktop app's always-on recording)
172
- - **`create`** - Stops the current recording and outputs URL/markdown (perfect for CI/CD, git hooks, GitHub CLI)
173
- - **`record`** - Full-featured recording command with all options (terminal recording mode)
174
- - **`stop`** - Similar to `create` but focused on stopping and uploading vs URL output
175
- - Old `track` syntax still works for backward compatibility but new syntax is preferred
176
- - All piped input examples from README are supported
177
- - Can run just `dashcam` with options (defaults to `create` command)