markupr 2.6.3 → 2.6.5
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 +21 -21
- package/dist/cli/index.mjs +104 -39
- package/dist/main/index.mjs +321 -61
- package/dist/mcp/index.mjs +357 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<img src="src/renderer/assets/logo.svg" alt="markupR" width="80" height="80">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">
|
|
5
|
+
<h1 align="center">markupR</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<strong>Record your screen. Say what's wrong. Your AI agent fixes it.</strong>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<p align="center">
|
|
20
20
|
<a href="#quick-start">Quick Start</a> ·
|
|
21
|
-
<a href="#why-
|
|
21
|
+
<a href="#why-markupR">Why markupR</a> ·
|
|
22
22
|
<a href="#mcp-server">MCP Server</a> ·
|
|
23
23
|
<a href="#cli">CLI</a> ·
|
|
24
24
|
<a href="#integrations">Integrations</a> ·
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
<!-- hero-screenshot: Replace with an actual screenshot or GIF of
|
|
30
|
+
<!-- hero-screenshot: Replace with an actual screenshot or GIF of markupR in action -->
|
|
31
31
|
|
|
32
32
|
## The Problem
|
|
33
33
|
|
|
@@ -35,7 +35,7 @@ AI coding agents can't see your screen. When you find a bug, you context-switch
|
|
|
35
35
|
|
|
36
36
|
## The Solution
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
markupR records your screen while you narrate what's wrong. When you stop, it runs an intelligent pipeline that correlates your transcript timestamps with the video to extract the right frames at the right moments -- then stitches everything into structured Markdown your AI agent can act on immediately.
|
|
39
39
|
|
|
40
40
|
- **Record** -- press a hotkey, talk through what you see
|
|
41
41
|
- **Process** -- Whisper transcribes, ffmpeg extracts frames at the exact moments you described
|
|
@@ -65,7 +65,7 @@ Download from [markupr.com](https://markupr.com) or [GitHub Releases](https://gi
|
|
|
65
65
|
|
|
66
66
|
No API keys required. Local Whisper transcription works out of the box.
|
|
67
67
|
|
|
68
|
-
## Why
|
|
68
|
+
## Why markupR?
|
|
69
69
|
|
|
70
70
|
**Local-first.** Whisper runs on your device. Your recordings, transcripts, and screenshots never leave your machine. No cloud dependency, no account required.
|
|
71
71
|
|
|
@@ -99,7 +99,7 @@ Each screenshot is extracted from the exact video frame matching your narration
|
|
|
99
99
|
|
|
100
100
|
## MCP Server
|
|
101
101
|
|
|
102
|
-
Give your AI coding agent eyes and ears. Add
|
|
102
|
+
Give your AI coding agent eyes and ears. Add markupR as an MCP server and it can capture screenshots, record your screen with voice, and receive structured reports -- all mid-conversation.
|
|
103
103
|
|
|
104
104
|
### Setup
|
|
105
105
|
|
|
@@ -108,7 +108,7 @@ Give your AI coding agent eyes and ears. Add markupr as an MCP server and it can
|
|
|
108
108
|
```json
|
|
109
109
|
{
|
|
110
110
|
"mcpServers": {
|
|
111
|
-
"
|
|
111
|
+
"markupR": {
|
|
112
112
|
"command": "npx",
|
|
113
113
|
"args": ["-y", "markupr-mcp"]
|
|
114
114
|
}
|
|
@@ -159,32 +159,32 @@ npm install -g markupr
|
|
|
159
159
|
|
|
160
160
|
### Commands
|
|
161
161
|
|
|
162
|
-
**`
|
|
162
|
+
**`markupR analyze <video>`** -- Process a screen recording into structured Markdown.
|
|
163
163
|
|
|
164
164
|
```bash
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
markupR analyze ./bug-demo.mov
|
|
166
|
+
markupR analyze ./recording.mov --output ./reports
|
|
167
|
+
markupR analyze ./recording.mov --template github-issue
|
|
168
|
+
markupR analyze ./recording.mov --no-frames # transcript only
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
**`
|
|
171
|
+
**`markupR watch [directory]`** -- Watch for new recordings and auto-process them.
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
|
-
|
|
174
|
+
markupR watch ~/Desktop --output ./reports
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
**`
|
|
177
|
+
**`markupR push github <report>`** -- Create GitHub issues from a feedback report.
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
markupR push github ./report.md --repo myorg/myapp
|
|
181
|
+
markupR push github ./report.md --repo myorg/myapp --dry-run
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
**`
|
|
184
|
+
**`markupR push linear <report>`** -- Create Linear issues from a feedback report.
|
|
185
185
|
|
|
186
186
|
```bash
|
|
187
|
-
|
|
187
|
+
markupR push linear ./report.md --team ENG
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
### Output Templates
|
|
@@ -200,7 +200,7 @@ markupr push linear ./report.md --team ENG
|
|
|
200
200
|
|
|
201
201
|
### GitHub Action
|
|
202
202
|
|
|
203
|
-
Run
|
|
203
|
+
Run markupR in CI to get visual feedback on pull requests:
|
|
204
204
|
|
|
205
205
|
```yaml
|
|
206
206
|
- uses: eddiesanjuan/markupr-action@v1
|
|
@@ -244,7 +244,7 @@ For architecture details, see [CLAUDE.md](CLAUDE.md).
|
|
|
244
244
|
|
|
245
245
|
```bash
|
|
246
246
|
git clone https://github.com/eddiesanjuan/markupr.git
|
|
247
|
-
cd
|
|
247
|
+
cd markupR
|
|
248
248
|
npm install
|
|
249
249
|
npm run dev
|
|
250
250
|
```
|
package/dist/cli/index.mjs
CHANGED
|
@@ -111,7 +111,7 @@ var init_LinearIssueCreator = __esm({
|
|
|
111
111
|
this.token = token;
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
|
-
* Push a
|
|
114
|
+
* Push a markupR report to Linear, creating one issue per feedback item.
|
|
115
115
|
*/
|
|
116
116
|
async pushReport(reportPath, options) {
|
|
117
117
|
const markdown = await readFile3(reportPath, "utf-8");
|
|
@@ -275,7 +275,7 @@ var init_LinearIssueCreator = __esm({
|
|
|
275
275
|
* Build markdown description for a Linear issue from a feedback item.
|
|
276
276
|
*/
|
|
277
277
|
buildIssueDescription(item) {
|
|
278
|
-
let desc = `##
|
|
278
|
+
let desc = `## markupR Feedback: ${item.id}
|
|
279
279
|
|
|
280
280
|
`;
|
|
281
281
|
desc += `**Severity:** ${item.severity}
|
|
@@ -310,7 +310,7 @@ ${item.suggestedAction}
|
|
|
310
310
|
}
|
|
311
311
|
desc += `
|
|
312
312
|
---
|
|
313
|
-
*Created by [
|
|
313
|
+
*Created by [markupR](https://markupr.com)*`;
|
|
314
314
|
return desc;
|
|
315
315
|
}
|
|
316
316
|
/**
|
|
@@ -363,9 +363,9 @@ var init_types2 = __esm({
|
|
|
363
363
|
Low: { name: "priority: low", color: "0e8a16", description: "Low priority" }
|
|
364
364
|
};
|
|
365
365
|
MARKUPR_LABEL = {
|
|
366
|
-
name: "
|
|
366
|
+
name: "markupR",
|
|
367
367
|
color: "6f42c1",
|
|
368
|
-
description: "Created from
|
|
368
|
+
description: "Created from markupR feedback session"
|
|
369
369
|
};
|
|
370
370
|
}
|
|
371
371
|
});
|
|
@@ -504,7 +504,7 @@ function formatIssueBody(item, reportPath) {
|
|
|
504
504
|
body += `### Screenshots
|
|
505
505
|
|
|
506
506
|
`;
|
|
507
|
-
body += `_${item.screenshotPaths.length} screenshot(s) captured \u2014 see the
|
|
507
|
+
body += `_${item.screenshotPaths.length} screenshot(s) captured \u2014 see the markupR report for images._
|
|
508
508
|
|
|
509
509
|
`;
|
|
510
510
|
}
|
|
@@ -522,7 +522,7 @@ function formatIssueBody(item, reportPath) {
|
|
|
522
522
|
body += `_Source: \`${reportPath}\`_
|
|
523
523
|
`;
|
|
524
524
|
}
|
|
525
|
-
body += `_Created by [
|
|
525
|
+
body += `_Created by [markupR](https://markupr.com)_
|
|
526
526
|
`;
|
|
527
527
|
return body;
|
|
528
528
|
}
|
|
@@ -562,7 +562,7 @@ async function pushToGitHub(options) {
|
|
|
562
562
|
const markdown = await readFile4(reportPath, "utf-8");
|
|
563
563
|
let items = parseMarkuprReport(markdown);
|
|
564
564
|
if (items.length === 0) {
|
|
565
|
-
throw new Error("No feedback items found in the report. Is this a valid
|
|
565
|
+
throw new Error("No feedback items found in the report. Is this a valid markupR report?");
|
|
566
566
|
}
|
|
567
567
|
if (filterIds && filterIds.length > 0) {
|
|
568
568
|
const filterSet = new Set(filterIds.map((id) => id.toUpperCase()));
|
|
@@ -1120,13 +1120,13 @@ var MarkdownGeneratorImpl = class {
|
|
|
1120
1120
|
const filename = this.generateFilename(projectName, session.startTime);
|
|
1121
1121
|
if (items.length === 0) {
|
|
1122
1122
|
const content2 = `# ${projectName} Feedback Report
|
|
1123
|
-
> Generated by
|
|
1123
|
+
> Generated by markupR on ${timestamp}
|
|
1124
1124
|
> Duration: ${duration}
|
|
1125
1125
|
|
|
1126
1126
|
_No feedback items were captured during this session._
|
|
1127
1127
|
|
|
1128
1128
|
---
|
|
1129
|
-
*Generated by [
|
|
1129
|
+
*Generated by [markupR](https://markupr.com)*
|
|
1130
1130
|
${REPORT_SUPPORT_LINE}
|
|
1131
1131
|
`;
|
|
1132
1132
|
return {
|
|
@@ -1147,7 +1147,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1147
1147
|
const highImpactCount = (severityCounts.Critical || 0) + (severityCounts.High || 0);
|
|
1148
1148
|
const platform2 = session.metadata?.os || process?.platform || "Unknown";
|
|
1149
1149
|
let content = `# ${projectName} Feedback Report
|
|
1150
|
-
> Generated by
|
|
1150
|
+
> Generated by markupR on ${timestamp}
|
|
1151
1151
|
> Duration: ${duration} | Items: ${items.length} | Screenshots: ${screenshotCount}
|
|
1152
1152
|
|
|
1153
1153
|
## Session Overview
|
|
@@ -1244,7 +1244,7 @@ _No screenshot captured for this item._
|
|
|
1244
1244
|
`;
|
|
1245
1245
|
content += `
|
|
1246
1246
|
---
|
|
1247
|
-
*Generated by [
|
|
1247
|
+
*Generated by [markupR](https://markupr.com)*
|
|
1248
1248
|
${REPORT_SUPPORT_LINE}
|
|
1249
1249
|
`;
|
|
1250
1250
|
return {
|
|
@@ -1277,7 +1277,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1277
1277
|
const sessionDuration = transcriptSegments.length > 0 ? this.formatDuration(
|
|
1278
1278
|
(transcriptSegments[transcriptSegments.length - 1].endTime - transcriptSegments[0].startTime) * 1e3
|
|
1279
1279
|
) : "0:00";
|
|
1280
|
-
let md = `#
|
|
1280
|
+
let md = `# markupR Session \u2014 ${sessionTimestamp}
|
|
1281
1281
|
`;
|
|
1282
1282
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
1283
1283
|
|
|
@@ -1308,11 +1308,17 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1308
1308
|
md += `
|
|
1309
1309
|
|
|
1310
1310
|
`;
|
|
1311
|
+
const contextLine = this.formatCaptureContextLine(frame.captureContext);
|
|
1312
|
+
if (contextLine) {
|
|
1313
|
+
md += `> ${contextLine}
|
|
1314
|
+
|
|
1315
|
+
`;
|
|
1316
|
+
}
|
|
1311
1317
|
}
|
|
1312
1318
|
}
|
|
1313
1319
|
}
|
|
1314
1320
|
md += `---
|
|
1315
|
-
*Generated by [
|
|
1321
|
+
*Generated by [markupR](https://markupr.com)*
|
|
1316
1322
|
${REPORT_SUPPORT_LINE}
|
|
1317
1323
|
`;
|
|
1318
1324
|
return md;
|
|
@@ -1359,6 +1365,16 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1359
1365
|
}
|
|
1360
1366
|
return path.relative(sessionDir, framePath);
|
|
1361
1367
|
}
|
|
1368
|
+
formatCaptureContextLine(context) {
|
|
1369
|
+
if (!context) {
|
|
1370
|
+
return void 0;
|
|
1371
|
+
}
|
|
1372
|
+
const cursor = context.cursor ? `Cursor: ${Math.round(context.cursor.x)}, ${Math.round(context.cursor.y)}` : void 0;
|
|
1373
|
+
const app = context.activeWindow?.appName || context.activeWindow?.sourceName;
|
|
1374
|
+
const focus = context.focusedElement?.textPreview || context.focusedElement?.label || context.focusedElement?.role;
|
|
1375
|
+
const parts = [cursor, app ? `App: ${app}` : void 0, focus ? `Focus: ${focus}` : void 0].filter((part) => Boolean(part));
|
|
1376
|
+
return parts.length ? parts.join(" | ") : void 0;
|
|
1377
|
+
}
|
|
1362
1378
|
/**
|
|
1363
1379
|
* Format a timestamp in seconds to M:SS format for post-process output.
|
|
1364
1380
|
* Examples: 0 -> "0:00", 15.3 -> "0:15", 125 -> "2:05"
|
|
@@ -2307,7 +2323,7 @@ var markdownTemplate = {
|
|
|
2307
2323
|
const { transcriptSegments, extractedFrames } = result;
|
|
2308
2324
|
const sessionTimestamp = formatDate(new Date(timestamp ?? Date.now()));
|
|
2309
2325
|
const sessionDuration = computeSessionDuration(transcriptSegments);
|
|
2310
|
-
let md = `#
|
|
2326
|
+
let md = `# markupR Session \u2014 ${sessionTimestamp}
|
|
2311
2327
|
`;
|
|
2312
2328
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
2313
2329
|
|
|
@@ -2338,11 +2354,20 @@ var markdownTemplate = {
|
|
|
2338
2354
|
md += `
|
|
2339
2355
|
|
|
2340
2356
|
`;
|
|
2357
|
+
const cursor = frame.captureContext?.cursor ? `Cursor: ${Math.round(frame.captureContext.cursor.x)}, ${Math.round(frame.captureContext.cursor.y)}` : void 0;
|
|
2358
|
+
const app = frame.captureContext?.activeWindow?.appName || frame.captureContext?.activeWindow?.sourceName;
|
|
2359
|
+
const focus = frame.captureContext?.focusedElement?.textPreview || frame.captureContext?.focusedElement?.label || frame.captureContext?.focusedElement?.role;
|
|
2360
|
+
const contextLine = [cursor, app ? `App: ${app}` : void 0, focus ? `Focus: ${focus}` : void 0].filter(Boolean).join(" | ");
|
|
2361
|
+
if (contextLine) {
|
|
2362
|
+
md += `> ${contextLine}
|
|
2363
|
+
|
|
2364
|
+
`;
|
|
2365
|
+
}
|
|
2341
2366
|
}
|
|
2342
2367
|
}
|
|
2343
2368
|
}
|
|
2344
2369
|
md += `---
|
|
2345
|
-
*Generated by [
|
|
2370
|
+
*Generated by [markupR](https://markupr.com)*
|
|
2346
2371
|
${REPORT_SUPPORT_LINE2}
|
|
2347
2372
|
`;
|
|
2348
2373
|
return { content: md, fileExtension: ".md" };
|
|
@@ -2360,7 +2385,7 @@ var jsonTemplate = {
|
|
|
2360
2385
|
const segmentFrameMap = mapFramesToSegments(transcriptSegments, extractedFrames);
|
|
2361
2386
|
const output = {
|
|
2362
2387
|
version: "1.0",
|
|
2363
|
-
generator: "
|
|
2388
|
+
generator: "markupR",
|
|
2364
2389
|
timestamp: new Date(timestamp ?? Date.now()).toISOString(),
|
|
2365
2390
|
summary: {
|
|
2366
2391
|
segments: transcriptSegments.length,
|
|
@@ -2377,7 +2402,8 @@ var jsonTemplate = {
|
|
|
2377
2402
|
frames: frames.map((f) => ({
|
|
2378
2403
|
path: computeRelativeFramePath(f.path, sessionDir),
|
|
2379
2404
|
timestamp: f.timestamp,
|
|
2380
|
-
reason: f.reason
|
|
2405
|
+
reason: f.reason,
|
|
2406
|
+
captureContext: f.captureContext
|
|
2381
2407
|
}))
|
|
2382
2408
|
};
|
|
2383
2409
|
})
|
|
@@ -2402,7 +2428,7 @@ var githubIssueTemplate = {
|
|
|
2402
2428
|
let md = `## Feedback Report
|
|
2403
2429
|
|
|
2404
2430
|
`;
|
|
2405
|
-
md += `> Captured by [
|
|
2431
|
+
md += `> Captured by [markupR](https://markupr.com) on ${sessionTimestamp}
|
|
2406
2432
|
`;
|
|
2407
2433
|
md += `> ${transcriptSegments.length} segments | ${extractedFrames.length} frames | Duration: ${duration}
|
|
2408
2434
|
|
|
@@ -2452,7 +2478,7 @@ var githubIssueTemplate = {
|
|
|
2452
2478
|
`;
|
|
2453
2479
|
}
|
|
2454
2480
|
md += `---
|
|
2455
|
-
_Generated by [
|
|
2481
|
+
_Generated by [markupR](https://markupr.com)_
|
|
2456
2482
|
`;
|
|
2457
2483
|
return { content: md, fileExtension: ".md" };
|
|
2458
2484
|
}
|
|
@@ -2512,7 +2538,7 @@ var linearTemplate = {
|
|
|
2512
2538
|
}
|
|
2513
2539
|
}
|
|
2514
2540
|
md += `---
|
|
2515
|
-
_Captured by [
|
|
2541
|
+
_Captured by [markupR](https://markupr.com)_
|
|
2516
2542
|
`;
|
|
2517
2543
|
return { content: md, fileExtension: ".md" };
|
|
2518
2544
|
}
|
|
@@ -2586,7 +2612,7 @@ ${segment.text}
|
|
|
2586
2612
|
}
|
|
2587
2613
|
}
|
|
2588
2614
|
content += `----
|
|
2589
|
-
_Generated by [
|
|
2615
|
+
_Generated by [markupR|https://markupr.com]_
|
|
2590
2616
|
`;
|
|
2591
2617
|
return { content, fileExtension: ".jira" };
|
|
2592
2618
|
}
|
|
@@ -2668,8 +2694,15 @@ var CLIPipeline = class _CLIPipeline {
|
|
|
2668
2694
|
const result = {
|
|
2669
2695
|
transcriptSegments: segments,
|
|
2670
2696
|
extractedFrames,
|
|
2671
|
-
reportPath: this.options.outputDir
|
|
2697
|
+
reportPath: this.options.outputDir,
|
|
2698
|
+
captureContexts: this.normalizeCaptureContexts(this.options.captureContexts || [])
|
|
2672
2699
|
};
|
|
2700
|
+
if (result.captureContexts && result.captureContexts.length > 0 && result.extractedFrames.length > 0) {
|
|
2701
|
+
result.extractedFrames = this.attachCaptureContextsToFrames(
|
|
2702
|
+
result.extractedFrames,
|
|
2703
|
+
result.captureContexts
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2673
2706
|
let reportContent;
|
|
2674
2707
|
let reportExtension = ".md";
|
|
2675
2708
|
const templateName = this.options.template;
|
|
@@ -2755,6 +2788,38 @@ var CLIPipeline = class _CLIPipeline {
|
|
|
2755
2788
|
this.activeProcesses.add(child);
|
|
2756
2789
|
});
|
|
2757
2790
|
}
|
|
2791
|
+
normalizeCaptureContexts(contexts) {
|
|
2792
|
+
return contexts.filter((context) => Number.isFinite(context.recordedAt)).slice().sort((a, b) => a.recordedAt - b.recordedAt);
|
|
2793
|
+
}
|
|
2794
|
+
attachCaptureContextsToFrames(frames, contexts) {
|
|
2795
|
+
const earliestContext = contexts[0]?.recordedAt;
|
|
2796
|
+
if (!Number.isFinite(earliestContext)) {
|
|
2797
|
+
return frames;
|
|
2798
|
+
}
|
|
2799
|
+
const maxDistanceMs = 5e3;
|
|
2800
|
+
return frames.map((frame) => {
|
|
2801
|
+
const frameAtMs = Number(earliestContext) + Math.round(frame.timestamp * 1e3);
|
|
2802
|
+
let bestMatch;
|
|
2803
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
2804
|
+
for (const context of contexts) {
|
|
2805
|
+
const distance = Math.abs(frameAtMs - context.recordedAt);
|
|
2806
|
+
if (distance < bestDistance) {
|
|
2807
|
+
bestDistance = distance;
|
|
2808
|
+
bestMatch = context;
|
|
2809
|
+
}
|
|
2810
|
+
if (context.recordedAt > frameAtMs && distance > bestDistance) {
|
|
2811
|
+
break;
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
if (!bestMatch || bestDistance > maxDistanceMs) {
|
|
2815
|
+
return frame;
|
|
2816
|
+
}
|
|
2817
|
+
return {
|
|
2818
|
+
...frame,
|
|
2819
|
+
captureContext: bestMatch
|
|
2820
|
+
};
|
|
2821
|
+
});
|
|
2822
|
+
}
|
|
2758
2823
|
/**
|
|
2759
2824
|
* Validate the video file is a real, non-empty file with a video stream.
|
|
2760
2825
|
*/
|
|
@@ -3304,7 +3369,7 @@ async function checkNodeVersion() {
|
|
|
3304
3369
|
name: "Node.js",
|
|
3305
3370
|
status: "warn",
|
|
3306
3371
|
message: `Unknown version: ${version}`,
|
|
3307
|
-
hint: "
|
|
3372
|
+
hint: "markupR requires Node.js >= 18.0.0"
|
|
3308
3373
|
};
|
|
3309
3374
|
}
|
|
3310
3375
|
const [major] = parsed;
|
|
@@ -3319,7 +3384,7 @@ async function checkNodeVersion() {
|
|
|
3319
3384
|
name: "Node.js",
|
|
3320
3385
|
status: "fail",
|
|
3321
3386
|
message: `${version} is too old`,
|
|
3322
|
-
hint: "
|
|
3387
|
+
hint: "markupR requires Node.js >= 18.0.0. Upgrade at https://nodejs.org"
|
|
3323
3388
|
};
|
|
3324
3389
|
}
|
|
3325
3390
|
async function checkFfmpeg() {
|
|
@@ -3368,7 +3433,7 @@ async function checkWhisperModel() {
|
|
|
3368
3433
|
status: "warn",
|
|
3369
3434
|
message: "No models directory found",
|
|
3370
3435
|
hint: `Models directory: ${modelsDir}
|
|
3371
|
-
Download a model via the
|
|
3436
|
+
Download a model via the markupR desktop app, or manually place a ggml-*.bin file there`
|
|
3372
3437
|
};
|
|
3373
3438
|
}
|
|
3374
3439
|
const model = findWhisperModel(modelsDir);
|
|
@@ -3378,7 +3443,7 @@ Download a model via the markupr desktop app, or manually place a ggml-*.bin fil
|
|
|
3378
3443
|
status: "warn",
|
|
3379
3444
|
message: "No model files found",
|
|
3380
3445
|
hint: `Models directory: ${modelsDir}
|
|
3381
|
-
Download a model via the
|
|
3446
|
+
Download a model via the markupR desktop app, or manually place a ggml-*.bin file there`
|
|
3382
3447
|
};
|
|
3383
3448
|
}
|
|
3384
3449
|
return {
|
|
@@ -3444,7 +3509,7 @@ async function checkDiskSpace() {
|
|
|
3444
3509
|
name: "Disk space",
|
|
3445
3510
|
status: "warn",
|
|
3446
3511
|
message: `${availableGB.toFixed(1)} GB available (low)`,
|
|
3447
|
-
hint: "
|
|
3512
|
+
hint: "markupR recordings and output need disk space. Free up some space if you plan to record long sessions"
|
|
3448
3513
|
};
|
|
3449
3514
|
}
|
|
3450
3515
|
return {
|
|
@@ -3558,7 +3623,7 @@ async function runInit(options) {
|
|
|
3558
3623
|
}
|
|
3559
3624
|
|
|
3560
3625
|
// src/cli/index.ts
|
|
3561
|
-
var VERSION = true ? "2.6.
|
|
3626
|
+
var VERSION = true ? "2.6.5" : "0.0.0-dev";
|
|
3562
3627
|
var SYMBOLS = {
|
|
3563
3628
|
check: "\u2714",
|
|
3564
3629
|
// checkmark
|
|
@@ -3577,7 +3642,7 @@ var SYMBOLS = {
|
|
|
3577
3642
|
};
|
|
3578
3643
|
function banner() {
|
|
3579
3644
|
console.log();
|
|
3580
|
-
console.log(`
|
|
3645
|
+
console.log(` markupR v${VERSION} ${SYMBOLS.bullet} CLI Mode`);
|
|
3581
3646
|
console.log(` ${SYMBOLS.line.repeat(40)}`);
|
|
3582
3647
|
console.log();
|
|
3583
3648
|
}
|
|
@@ -3762,7 +3827,7 @@ program.command("watch").description("Watch a directory for new recordings and a
|
|
|
3762
3827
|
process.exit(EXIT_SYSTEM_ERROR);
|
|
3763
3828
|
}
|
|
3764
3829
|
});
|
|
3765
|
-
program.command("doctor").description("Check your environment for
|
|
3830
|
+
program.command("doctor").description("Check your environment for markupR dependencies and configuration").action(async () => {
|
|
3766
3831
|
banner();
|
|
3767
3832
|
step("Checking environment...");
|
|
3768
3833
|
console.log();
|
|
@@ -3786,16 +3851,16 @@ program.command("doctor").description("Check your environment for markupr depend
|
|
|
3786
3851
|
console.log(` ${result.passed} passed, ${result.warned} warnings, ${result.failed} failed`);
|
|
3787
3852
|
console.log();
|
|
3788
3853
|
if (result.failed > 0) {
|
|
3789
|
-
fail("Some required checks failed. Fix them to use
|
|
3854
|
+
fail("Some required checks failed. Fix them to use markupR.");
|
|
3790
3855
|
process.exit(EXIT_USER_ERROR);
|
|
3791
3856
|
} else if (result.warned > 0) {
|
|
3792
|
-
success("
|
|
3857
|
+
success("markupR is ready (some optional features are not configured).");
|
|
3793
3858
|
} else {
|
|
3794
|
-
success("
|
|
3859
|
+
success("markupR is fully configured and ready to go!");
|
|
3795
3860
|
}
|
|
3796
3861
|
console.log();
|
|
3797
3862
|
});
|
|
3798
|
-
program.command("init").description("Create a .markupr.json
|
|
3863
|
+
program.command("init").description("Create a markupR project config file (.markupr.json) in the current project").option("--output <dir>", "Output directory for feedback sessions", "./markupr-output").option("--no-gitignore", "Skip updating .gitignore").option("--force", "Overwrite existing config file", false).action(async (options) => {
|
|
3799
3864
|
banner();
|
|
3800
3865
|
const result = await runInit({
|
|
3801
3866
|
directory: process.cwd(),
|
|
@@ -3811,17 +3876,17 @@ program.command("init").description("Create a .markupr.json config file in the c
|
|
|
3811
3876
|
}
|
|
3812
3877
|
success(`Created ${result.configPath}`);
|
|
3813
3878
|
if (result.gitignoreUpdated) {
|
|
3814
|
-
success("Updated .gitignore with
|
|
3879
|
+
success("Updated .gitignore with markupR output directory");
|
|
3815
3880
|
}
|
|
3816
3881
|
console.log();
|
|
3817
3882
|
step("Next steps:");
|
|
3818
3883
|
console.log(" 1. Run `markupr doctor` to verify your environment");
|
|
3819
|
-
console.log(" 2. Record a session with the
|
|
3884
|
+
console.log(" 2. Record a session with the markupR desktop app or screen recorder");
|
|
3820
3885
|
console.log(" 3. Run `markupr analyze <video-file>` to generate a feedback report");
|
|
3821
3886
|
console.log();
|
|
3822
3887
|
});
|
|
3823
3888
|
var pushCmd = program.command("push").description("Push feedback to external services");
|
|
3824
|
-
pushCmd.command("linear").description("Create Linear issues from a
|
|
3889
|
+
pushCmd.command("linear").description("Create Linear issues from a markupR feedback report").argument("<report>", "Path to the markupR markdown report").requiredOption("--team <key>", "Linear team key (e.g., ENG, DES)").option("--token <token>", "Linear API key (prefer LINEAR_API_KEY env var)").option("--project <name>", "Linear project name to assign issues to").option("--dry-run", "Show what would be created without creating anything", false).action(async (report, options) => {
|
|
3825
3890
|
banner();
|
|
3826
3891
|
const reportPath = resolve3(report);
|
|
3827
3892
|
if (!existsSync7(reportPath)) {
|
|
@@ -3892,7 +3957,7 @@ pushCmd.command("linear").description("Create Linear issues from a markupr feedb
|
|
|
3892
3957
|
process.exit(EXIT_USER_ERROR);
|
|
3893
3958
|
}
|
|
3894
3959
|
});
|
|
3895
|
-
pushCmd.command("github").description("Create GitHub issues from a
|
|
3960
|
+
pushCmd.command("github").description("Create GitHub issues from a markupR feedback report").argument("<report>", "Path to the markupR markdown report").requiredOption("--repo <owner/repo>", "Target GitHub repository (e.g., myorg/myapp)").option("--token <token>", "GitHub token (prefer GITHUB_TOKEN env var or gh auth login)").option("--items <ids...>", "Specific FB-XXX item IDs to push (default: all)").option("--dry-run", "Show what would be created without creating anything", false).action(async (report, options) => {
|
|
3896
3961
|
banner();
|
|
3897
3962
|
const reportPath = resolve3(report);
|
|
3898
3963
|
if (!existsSync7(reportPath)) {
|