markupr 2.6.3 → 2.6.4
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 +37 -37
- package/dist/main/index.mjs +47 -47
- package/dist/mcp/index.mjs +33 -33
- 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
|
|
|
@@ -1312,7 +1312,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1312
1312
|
}
|
|
1313
1313
|
}
|
|
1314
1314
|
md += `---
|
|
1315
|
-
*Generated by [
|
|
1315
|
+
*Generated by [markupR](https://markupr.com)*
|
|
1316
1316
|
${REPORT_SUPPORT_LINE}
|
|
1317
1317
|
`;
|
|
1318
1318
|
return md;
|
|
@@ -2307,7 +2307,7 @@ var markdownTemplate = {
|
|
|
2307
2307
|
const { transcriptSegments, extractedFrames } = result;
|
|
2308
2308
|
const sessionTimestamp = formatDate(new Date(timestamp ?? Date.now()));
|
|
2309
2309
|
const sessionDuration = computeSessionDuration(transcriptSegments);
|
|
2310
|
-
let md = `#
|
|
2310
|
+
let md = `# markupR Session \u2014 ${sessionTimestamp}
|
|
2311
2311
|
`;
|
|
2312
2312
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
2313
2313
|
|
|
@@ -2342,7 +2342,7 @@ var markdownTemplate = {
|
|
|
2342
2342
|
}
|
|
2343
2343
|
}
|
|
2344
2344
|
md += `---
|
|
2345
|
-
*Generated by [
|
|
2345
|
+
*Generated by [markupR](https://markupr.com)*
|
|
2346
2346
|
${REPORT_SUPPORT_LINE2}
|
|
2347
2347
|
`;
|
|
2348
2348
|
return { content: md, fileExtension: ".md" };
|
|
@@ -2360,7 +2360,7 @@ var jsonTemplate = {
|
|
|
2360
2360
|
const segmentFrameMap = mapFramesToSegments(transcriptSegments, extractedFrames);
|
|
2361
2361
|
const output = {
|
|
2362
2362
|
version: "1.0",
|
|
2363
|
-
generator: "
|
|
2363
|
+
generator: "markupR",
|
|
2364
2364
|
timestamp: new Date(timestamp ?? Date.now()).toISOString(),
|
|
2365
2365
|
summary: {
|
|
2366
2366
|
segments: transcriptSegments.length,
|
|
@@ -2402,7 +2402,7 @@ var githubIssueTemplate = {
|
|
|
2402
2402
|
let md = `## Feedback Report
|
|
2403
2403
|
|
|
2404
2404
|
`;
|
|
2405
|
-
md += `> Captured by [
|
|
2405
|
+
md += `> Captured by [markupR](https://markupr.com) on ${sessionTimestamp}
|
|
2406
2406
|
`;
|
|
2407
2407
|
md += `> ${transcriptSegments.length} segments | ${extractedFrames.length} frames | Duration: ${duration}
|
|
2408
2408
|
|
|
@@ -2452,7 +2452,7 @@ var githubIssueTemplate = {
|
|
|
2452
2452
|
`;
|
|
2453
2453
|
}
|
|
2454
2454
|
md += `---
|
|
2455
|
-
_Generated by [
|
|
2455
|
+
_Generated by [markupR](https://markupr.com)_
|
|
2456
2456
|
`;
|
|
2457
2457
|
return { content: md, fileExtension: ".md" };
|
|
2458
2458
|
}
|
|
@@ -2512,7 +2512,7 @@ var linearTemplate = {
|
|
|
2512
2512
|
}
|
|
2513
2513
|
}
|
|
2514
2514
|
md += `---
|
|
2515
|
-
_Captured by [
|
|
2515
|
+
_Captured by [markupR](https://markupr.com)_
|
|
2516
2516
|
`;
|
|
2517
2517
|
return { content: md, fileExtension: ".md" };
|
|
2518
2518
|
}
|
|
@@ -2586,7 +2586,7 @@ ${segment.text}
|
|
|
2586
2586
|
}
|
|
2587
2587
|
}
|
|
2588
2588
|
content += `----
|
|
2589
|
-
_Generated by [
|
|
2589
|
+
_Generated by [markupR|https://markupr.com]_
|
|
2590
2590
|
`;
|
|
2591
2591
|
return { content, fileExtension: ".jira" };
|
|
2592
2592
|
}
|
|
@@ -3304,7 +3304,7 @@ async function checkNodeVersion() {
|
|
|
3304
3304
|
name: "Node.js",
|
|
3305
3305
|
status: "warn",
|
|
3306
3306
|
message: `Unknown version: ${version}`,
|
|
3307
|
-
hint: "
|
|
3307
|
+
hint: "markupR requires Node.js >= 18.0.0"
|
|
3308
3308
|
};
|
|
3309
3309
|
}
|
|
3310
3310
|
const [major] = parsed;
|
|
@@ -3319,7 +3319,7 @@ async function checkNodeVersion() {
|
|
|
3319
3319
|
name: "Node.js",
|
|
3320
3320
|
status: "fail",
|
|
3321
3321
|
message: `${version} is too old`,
|
|
3322
|
-
hint: "
|
|
3322
|
+
hint: "markupR requires Node.js >= 18.0.0. Upgrade at https://nodejs.org"
|
|
3323
3323
|
};
|
|
3324
3324
|
}
|
|
3325
3325
|
async function checkFfmpeg() {
|
|
@@ -3368,7 +3368,7 @@ async function checkWhisperModel() {
|
|
|
3368
3368
|
status: "warn",
|
|
3369
3369
|
message: "No models directory found",
|
|
3370
3370
|
hint: `Models directory: ${modelsDir}
|
|
3371
|
-
Download a model via the
|
|
3371
|
+
Download a model via the markupR desktop app, or manually place a ggml-*.bin file there`
|
|
3372
3372
|
};
|
|
3373
3373
|
}
|
|
3374
3374
|
const model = findWhisperModel(modelsDir);
|
|
@@ -3378,7 +3378,7 @@ Download a model via the markupr desktop app, or manually place a ggml-*.bin fil
|
|
|
3378
3378
|
status: "warn",
|
|
3379
3379
|
message: "No model files found",
|
|
3380
3380
|
hint: `Models directory: ${modelsDir}
|
|
3381
|
-
Download a model via the
|
|
3381
|
+
Download a model via the markupR desktop app, or manually place a ggml-*.bin file there`
|
|
3382
3382
|
};
|
|
3383
3383
|
}
|
|
3384
3384
|
return {
|
|
@@ -3444,7 +3444,7 @@ async function checkDiskSpace() {
|
|
|
3444
3444
|
name: "Disk space",
|
|
3445
3445
|
status: "warn",
|
|
3446
3446
|
message: `${availableGB.toFixed(1)} GB available (low)`,
|
|
3447
|
-
hint: "
|
|
3447
|
+
hint: "markupR recordings and output need disk space. Free up some space if you plan to record long sessions"
|
|
3448
3448
|
};
|
|
3449
3449
|
}
|
|
3450
3450
|
return {
|
|
@@ -3558,7 +3558,7 @@ async function runInit(options) {
|
|
|
3558
3558
|
}
|
|
3559
3559
|
|
|
3560
3560
|
// src/cli/index.ts
|
|
3561
|
-
var VERSION = true ? "2.6.
|
|
3561
|
+
var VERSION = true ? "2.6.4" : "0.0.0-dev";
|
|
3562
3562
|
var SYMBOLS = {
|
|
3563
3563
|
check: "\u2714",
|
|
3564
3564
|
// checkmark
|
|
@@ -3577,7 +3577,7 @@ var SYMBOLS = {
|
|
|
3577
3577
|
};
|
|
3578
3578
|
function banner() {
|
|
3579
3579
|
console.log();
|
|
3580
|
-
console.log(`
|
|
3580
|
+
console.log(` markupR v${VERSION} ${SYMBOLS.bullet} CLI Mode`);
|
|
3581
3581
|
console.log(` ${SYMBOLS.line.repeat(40)}`);
|
|
3582
3582
|
console.log();
|
|
3583
3583
|
}
|
|
@@ -3762,7 +3762,7 @@ program.command("watch").description("Watch a directory for new recordings and a
|
|
|
3762
3762
|
process.exit(EXIT_SYSTEM_ERROR);
|
|
3763
3763
|
}
|
|
3764
3764
|
});
|
|
3765
|
-
program.command("doctor").description("Check your environment for
|
|
3765
|
+
program.command("doctor").description("Check your environment for markupR dependencies and configuration").action(async () => {
|
|
3766
3766
|
banner();
|
|
3767
3767
|
step("Checking environment...");
|
|
3768
3768
|
console.log();
|
|
@@ -3786,16 +3786,16 @@ program.command("doctor").description("Check your environment for markupr depend
|
|
|
3786
3786
|
console.log(` ${result.passed} passed, ${result.warned} warnings, ${result.failed} failed`);
|
|
3787
3787
|
console.log();
|
|
3788
3788
|
if (result.failed > 0) {
|
|
3789
|
-
fail("Some required checks failed. Fix them to use
|
|
3789
|
+
fail("Some required checks failed. Fix them to use markupR.");
|
|
3790
3790
|
process.exit(EXIT_USER_ERROR);
|
|
3791
3791
|
} else if (result.warned > 0) {
|
|
3792
|
-
success("
|
|
3792
|
+
success("markupR is ready (some optional features are not configured).");
|
|
3793
3793
|
} else {
|
|
3794
|
-
success("
|
|
3794
|
+
success("markupR is fully configured and ready to go!");
|
|
3795
3795
|
}
|
|
3796
3796
|
console.log();
|
|
3797
3797
|
});
|
|
3798
|
-
program.command("init").description("Create a .markupr.json
|
|
3798
|
+
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
3799
|
banner();
|
|
3800
3800
|
const result = await runInit({
|
|
3801
3801
|
directory: process.cwd(),
|
|
@@ -3811,17 +3811,17 @@ program.command("init").description("Create a .markupr.json config file in the c
|
|
|
3811
3811
|
}
|
|
3812
3812
|
success(`Created ${result.configPath}`);
|
|
3813
3813
|
if (result.gitignoreUpdated) {
|
|
3814
|
-
success("Updated .gitignore with
|
|
3814
|
+
success("Updated .gitignore with markupR output directory");
|
|
3815
3815
|
}
|
|
3816
3816
|
console.log();
|
|
3817
3817
|
step("Next steps:");
|
|
3818
3818
|
console.log(" 1. Run `markupr doctor` to verify your environment");
|
|
3819
|
-
console.log(" 2. Record a session with the
|
|
3819
|
+
console.log(" 2. Record a session with the markupR desktop app or screen recorder");
|
|
3820
3820
|
console.log(" 3. Run `markupr analyze <video-file>` to generate a feedback report");
|
|
3821
3821
|
console.log();
|
|
3822
3822
|
});
|
|
3823
3823
|
var pushCmd = program.command("push").description("Push feedback to external services");
|
|
3824
|
-
pushCmd.command("linear").description("Create Linear issues from a
|
|
3824
|
+
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
3825
|
banner();
|
|
3826
3826
|
const reportPath = resolve3(report);
|
|
3827
3827
|
if (!existsSync7(reportPath)) {
|
|
@@ -3892,7 +3892,7 @@ pushCmd.command("linear").description("Create Linear issues from a markupr feedb
|
|
|
3892
3892
|
process.exit(EXIT_USER_ERROR);
|
|
3893
3893
|
}
|
|
3894
3894
|
});
|
|
3895
|
-
pushCmd.command("github").description("Create GitHub issues from a
|
|
3895
|
+
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
3896
|
banner();
|
|
3897
3897
|
const reportPath = resolve3(report);
|
|
3898
3898
|
if (!existsSync7(reportPath)) {
|
package/dist/main/index.mjs
CHANGED
|
@@ -580,7 +580,7 @@ const HOTKEYS = [
|
|
|
580
580
|
{
|
|
581
581
|
id: "quit",
|
|
582
582
|
label: "Quit",
|
|
583
|
-
description: "Quit
|
|
583
|
+
description: "Quit markupR",
|
|
584
584
|
macAccelerator: "Command+Q",
|
|
585
585
|
winLinuxAccelerator: "Alt+F4"
|
|
586
586
|
}
|
|
@@ -725,7 +725,7 @@ class ErrorHandler {
|
|
|
725
725
|
const messages = {
|
|
726
726
|
microphone: {
|
|
727
727
|
title: "Microphone Access Required",
|
|
728
|
-
message: "
|
|
728
|
+
message: "markupR needs microphone access to capture your voice feedback.",
|
|
729
729
|
detail: `Click "Open Settings" to grant microphone permission in ${settingsName}.
|
|
730
730
|
|
|
731
731
|
After enabling, you may need to restart the app.`,
|
|
@@ -734,7 +734,7 @@ After enabling, you may need to restart the app.`,
|
|
|
734
734
|
},
|
|
735
735
|
screen: {
|
|
736
736
|
title: "Screen Recording Required",
|
|
737
|
-
message: "
|
|
737
|
+
message: "markupR needs screen recording permission to capture screenshots.",
|
|
738
738
|
detail: `Click "Open Settings" to grant screen recording permission in ${settingsName}.
|
|
739
739
|
|
|
740
740
|
You will need to restart the app after enabling.`,
|
|
@@ -790,7 +790,7 @@ You will need to restart the app after enabling.`,
|
|
|
790
790
|
type: "warning",
|
|
791
791
|
title: "API Key Required",
|
|
792
792
|
message: "Your OpenAI API key is missing or invalid.",
|
|
793
|
-
detail: "
|
|
793
|
+
detail: "markupR uses OpenAI for post-session narration transcription. Please enter a valid API key in Settings.\n\nCreate a key at platform.openai.com/api-keys",
|
|
794
794
|
buttons: ["Open Settings", "OK"],
|
|
795
795
|
defaultId: 0
|
|
796
796
|
}).then(({ response }) => {
|
|
@@ -992,7 +992,7 @@ Please restart the app to continue.`,
|
|
|
992
992
|
this.emitToRenderer(IPC_CHANNELS.NOTIFICATION, { title, message });
|
|
993
993
|
if (Notification.isSupported()) {
|
|
994
994
|
new Notification({
|
|
995
|
-
title: `
|
|
995
|
+
title: `markupR: ${title}`,
|
|
996
996
|
body: message,
|
|
997
997
|
silent: true
|
|
998
998
|
}).show();
|
|
@@ -2179,7 +2179,7 @@ class SettingsManager {
|
|
|
2179
2179
|
}
|
|
2180
2180
|
setFallbackApiKey(service, key) {
|
|
2181
2181
|
if (!this.canUseEncryptedFallback()) {
|
|
2182
|
-
throw new Error("Secure storage is unavailable. API keys cannot be saved until the app is fully initialized. Try restarting
|
|
2182
|
+
throw new Error("Secure storage is unavailable. API keys cannot be saved until the app is fully initialized. Try restarting markupR.");
|
|
2183
2183
|
}
|
|
2184
2184
|
const encrypted = safeStorage.encryptString(key).toString("base64");
|
|
2185
2185
|
this.secureStore.set(service, encrypted);
|
|
@@ -2306,7 +2306,7 @@ class SettingsManager {
|
|
|
2306
2306
|
console.log(`[SettingsManager] Stored API key for ${service} via plaintext fallback`);
|
|
2307
2307
|
} catch (insecureError) {
|
|
2308
2308
|
throw new Error(
|
|
2309
|
-
`Unable to store API key for ${service}. All storage methods failed. Try restarting
|
|
2309
|
+
`Unable to store API key for ${service}. All storage methods failed. Try restarting markupR or check filesystem permissions. (${insecureError instanceof Error ? insecureError.message : String(insecureError)})`
|
|
2310
2310
|
);
|
|
2311
2311
|
}
|
|
2312
2312
|
}
|
|
@@ -4345,11 +4345,11 @@ const sessionController = new SessionController();
|
|
|
4345
4345
|
function buildStateTooltips() {
|
|
4346
4346
|
const toggleKey = formatHotkeyForDisplay("toggleRecording");
|
|
4347
4347
|
return {
|
|
4348
|
-
idle: `
|
|
4349
|
-
recording: `
|
|
4350
|
-
processing: "
|
|
4351
|
-
complete: "
|
|
4352
|
-
error: "
|
|
4348
|
+
idle: `markupR - Ready (${toggleKey})`,
|
|
4349
|
+
recording: `markupR - Recording... (${toggleKey} to stop)`,
|
|
4350
|
+
processing: "markupR - Processing...",
|
|
4351
|
+
complete: "markupR - Feedback captured!",
|
|
4352
|
+
error: "markupR - Error (click for details)"
|
|
4353
4353
|
};
|
|
4354
4354
|
}
|
|
4355
4355
|
const DONATE_URL = "https://ko-fi.com/eddiesanjuan";
|
|
@@ -4529,12 +4529,12 @@ class TrayManagerImpl {
|
|
|
4529
4529
|
},
|
|
4530
4530
|
{ type: "separator" },
|
|
4531
4531
|
{
|
|
4532
|
-
label: "About
|
|
4532
|
+
label: "About markupR",
|
|
4533
4533
|
role: "about"
|
|
4534
4534
|
},
|
|
4535
4535
|
{ type: "separator" },
|
|
4536
4536
|
{
|
|
4537
|
-
label: "Quit
|
|
4537
|
+
label: "Quit markupR",
|
|
4538
4538
|
accelerator: "CmdOrCtrl+Q",
|
|
4539
4539
|
click: () => {
|
|
4540
4540
|
app.quit();
|
|
@@ -4764,13 +4764,13 @@ class ClipboardServiceImpl {
|
|
|
4764
4764
|
this.lastNotificationTime = now;
|
|
4765
4765
|
if (success) {
|
|
4766
4766
|
this.showNotification(
|
|
4767
|
-
title || "
|
|
4767
|
+
title || "markupR",
|
|
4768
4768
|
"Summary copied to clipboard!",
|
|
4769
4769
|
"Paste into your AI coding assistant."
|
|
4770
4770
|
);
|
|
4771
4771
|
} else {
|
|
4772
4772
|
this.showNotification(
|
|
4773
|
-
"
|
|
4773
|
+
"markupR",
|
|
4774
4774
|
"Failed to copy",
|
|
4775
4775
|
"Please try again or copy manually."
|
|
4776
4776
|
);
|
|
@@ -5253,13 +5253,13 @@ class MarkdownGeneratorImpl {
|
|
|
5253
5253
|
const filename = this.generateFilename(projectName, session.startTime);
|
|
5254
5254
|
if (items.length === 0) {
|
|
5255
5255
|
const content2 = `# ${projectName} Feedback Report
|
|
5256
|
-
> Generated by
|
|
5256
|
+
> Generated by markupR on ${timestamp}
|
|
5257
5257
|
> Duration: ${duration}
|
|
5258
5258
|
|
|
5259
5259
|
_No feedback items were captured during this session._
|
|
5260
5260
|
|
|
5261
5261
|
---
|
|
5262
|
-
*Generated by [
|
|
5262
|
+
*Generated by [markupR](https://markupr.com)*
|
|
5263
5263
|
${REPORT_SUPPORT_LINE}
|
|
5264
5264
|
`;
|
|
5265
5265
|
return {
|
|
@@ -5280,7 +5280,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
5280
5280
|
const highImpactCount = (severityCounts.Critical || 0) + (severityCounts.High || 0);
|
|
5281
5281
|
const platform = session.metadata?.os || process?.platform || "Unknown";
|
|
5282
5282
|
let content = `# ${projectName} Feedback Report
|
|
5283
|
-
> Generated by
|
|
5283
|
+
> Generated by markupR on ${timestamp}
|
|
5284
5284
|
> Duration: ${duration} | Items: ${items.length} | Screenshots: ${screenshotCount}
|
|
5285
5285
|
|
|
5286
5286
|
## Session Overview
|
|
@@ -5377,7 +5377,7 @@ _No screenshot captured for this item._
|
|
|
5377
5377
|
`;
|
|
5378
5378
|
content += `
|
|
5379
5379
|
---
|
|
5380
|
-
*Generated by [
|
|
5380
|
+
*Generated by [markupR](https://markupr.com)*
|
|
5381
5381
|
${REPORT_SUPPORT_LINE}
|
|
5382
5382
|
`;
|
|
5383
5383
|
return {
|
|
@@ -5410,7 +5410,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
5410
5410
|
const sessionDuration = transcriptSegments.length > 0 ? this.formatDuration(
|
|
5411
5411
|
(transcriptSegments[transcriptSegments.length - 1].endTime - transcriptSegments[0].startTime) * 1e3
|
|
5412
5412
|
) : "0:00";
|
|
5413
|
-
let md = `#
|
|
5413
|
+
let md = `# markupR Session — ${sessionTimestamp}
|
|
5414
5414
|
`;
|
|
5415
5415
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
5416
5416
|
|
|
@@ -5445,7 +5445,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
5445
5445
|
}
|
|
5446
5446
|
}
|
|
5447
5447
|
md += `---
|
|
5448
|
-
*Generated by [
|
|
5448
|
+
*Generated by [markupR](https://markupr.com)*
|
|
5449
5449
|
${REPORT_SUPPORT_LINE}
|
|
5450
5450
|
`;
|
|
5451
5451
|
return md;
|
|
@@ -6421,7 +6421,7 @@ function evenlySpaced(items, count) {
|
|
|
6421
6421
|
}
|
|
6422
6422
|
return result;
|
|
6423
6423
|
}
|
|
6424
|
-
const SYSTEM_PROMPT = `You are
|
|
6424
|
+
const SYSTEM_PROMPT = `You are markupR's AI analysis engine. You receive a developer's voice-narrated feedback session: a transcript of everything they said while reviewing software, paired with screenshots captured at natural pause points.
|
|
6425
6425
|
|
|
6426
6426
|
Your job is to transform this raw narration into a structured, actionable feedback document.
|
|
6427
6427
|
|
|
@@ -6821,7 +6821,7 @@ class StructuredMarkdownBuilder {
|
|
|
6821
6821
|
}
|
|
6822
6822
|
buildFooter(options) {
|
|
6823
6823
|
const model = options.modelId ? ` with ${options.modelId}` : " with AI analysis";
|
|
6824
|
-
return `*Generated by [
|
|
6824
|
+
return `*Generated by [markupR](https://markupr.com)${model}*
|
|
6825
6825
|
*If this report saved you time, support development: [Ko-fi](https://ko-fi.com/eddiesanjuan)*
|
|
6826
6826
|
`;
|
|
6827
6827
|
}
|
|
@@ -9015,7 +9015,7 @@ class MenuManager {
|
|
|
9015
9015
|
},
|
|
9016
9016
|
{ type: "separator" },
|
|
9017
9017
|
{
|
|
9018
|
-
label: "
|
|
9018
|
+
label: "markupR Documentation",
|
|
9019
9019
|
click: () => shell.openExternal("https://github.com/eddiesanjuan/markupr#readme")
|
|
9020
9020
|
},
|
|
9021
9021
|
{
|
|
@@ -9259,7 +9259,7 @@ class WindowsTaskbar {
|
|
|
9259
9259
|
{
|
|
9260
9260
|
type: "task",
|
|
9261
9261
|
title: "Open Settings",
|
|
9262
|
-
description: "Configure
|
|
9262
|
+
description: "Configure markupR settings",
|
|
9263
9263
|
program: process.execPath,
|
|
9264
9264
|
args: "--settings",
|
|
9265
9265
|
iconPath: process.execPath,
|
|
@@ -9910,7 +9910,7 @@ class TaskbarIntegration {
|
|
|
9910
9910
|
{
|
|
9911
9911
|
type: "task",
|
|
9912
9912
|
title: "Open Settings",
|
|
9913
|
-
description: "Configure
|
|
9913
|
+
description: "Configure markupR settings",
|
|
9914
9914
|
program: process.execPath,
|
|
9915
9915
|
args: "--settings",
|
|
9916
9916
|
iconPath: process.execPath,
|
|
@@ -10139,7 +10139,7 @@ class TaskbarIntegration {
|
|
|
10139
10139
|
notifyRecordingStarted() {
|
|
10140
10140
|
this.showNotification({
|
|
10141
10141
|
title: "Recording Started",
|
|
10142
|
-
body: "
|
|
10142
|
+
body: "markupR is now capturing your feedback",
|
|
10143
10143
|
silent: true,
|
|
10144
10144
|
urgency: "low"
|
|
10145
10145
|
});
|
|
@@ -10205,19 +10205,19 @@ new TaskbarIntegration();
|
|
|
10205
10205
|
const PERMISSION_DESCRIPTIONS = {
|
|
10206
10206
|
microphone: {
|
|
10207
10207
|
title: "Microphone Access",
|
|
10208
|
-
description: "
|
|
10208
|
+
description: "markupR needs microphone access to capture your voice feedback and transcribe it in real-time.",
|
|
10209
10209
|
required: true,
|
|
10210
10210
|
systemPrefsPane: "Privacy_Microphone"
|
|
10211
10211
|
},
|
|
10212
10212
|
screen: {
|
|
10213
10213
|
title: "Screen Recording",
|
|
10214
|
-
description: "
|
|
10214
|
+
description: "markupR needs screen recording permission to capture screenshots when you pause speaking.",
|
|
10215
10215
|
required: true,
|
|
10216
10216
|
systemPrefsPane: "Privacy_ScreenCapture"
|
|
10217
10217
|
},
|
|
10218
10218
|
accessibility: {
|
|
10219
10219
|
title: "Accessibility",
|
|
10220
|
-
description: "
|
|
10220
|
+
description: "markupR uses accessibility features for global hotkeys. This is optional but recommended.",
|
|
10221
10221
|
required: false,
|
|
10222
10222
|
systemPrefsPane: "Privacy_Accessibility"
|
|
10223
10223
|
}
|
|
@@ -10421,9 +10421,9 @@ class PermissionManager {
|
|
|
10421
10421
|
|
|
10422
10422
|
To enable this permission:
|
|
10423
10423
|
1. Click "${settingsLabel}"
|
|
10424
|
-
2. Find
|
|
10424
|
+
2. Find markupR in the list
|
|
10425
10425
|
3. Toggle it ON
|
|
10426
|
-
4. You may need to restart
|
|
10426
|
+
4. You may need to restart markupR`
|
|
10427
10427
|
};
|
|
10428
10428
|
const { response } = this.mainWindow ? await dialog.showMessageBox(this.mainWindow, options) : await dialog.showMessageBox(options);
|
|
10429
10429
|
if (response === 0) {
|
|
@@ -10444,8 +10444,8 @@ To enable this permission:
|
|
|
10444
10444
|
defaultId: 0,
|
|
10445
10445
|
cancelId: 2,
|
|
10446
10446
|
title: "Permissions Needed",
|
|
10447
|
-
message: "
|
|
10448
|
-
detail: `To work properly,
|
|
10447
|
+
message: "markupR needs your permission",
|
|
10448
|
+
detail: `To work properly, markupR needs access to:
|
|
10449
10449
|
${missingDescriptions}
|
|
10450
10450
|
|
|
10451
10451
|
Would you like to set up permissions now?`
|
|
@@ -10902,8 +10902,8 @@ function registerSettingsHandlers(ctx, actions) {
|
|
|
10902
10902
|
}
|
|
10903
10903
|
const mainWindow2 = getMainWindow();
|
|
10904
10904
|
const options = {
|
|
10905
|
-
title: "Export
|
|
10906
|
-
defaultPath: join(app.getPath("documents"), "
|
|
10905
|
+
title: "Export markupR Settings",
|
|
10906
|
+
defaultPath: join(app.getPath("documents"), "markupR-settings.json"),
|
|
10907
10907
|
filters: [{ name: "JSON", extensions: ["json"] }]
|
|
10908
10908
|
};
|
|
10909
10909
|
const result = mainWindow2 ? await dialog.showSaveDialog(mainWindow2, options) : await dialog.showSaveDialog(options);
|
|
@@ -10921,7 +10921,7 @@ function registerSettingsHandlers(ctx, actions) {
|
|
|
10921
10921
|
}
|
|
10922
10922
|
const mainWindow2 = getMainWindow();
|
|
10923
10923
|
const options = {
|
|
10924
|
-
title: "Import
|
|
10924
|
+
title: "Import markupR Settings",
|
|
10925
10925
|
properties: ["openFile"],
|
|
10926
10926
|
filters: [{ name: "JSON", extensions: ["json"] }]
|
|
10927
10927
|
};
|
|
@@ -11956,7 +11956,7 @@ async function writeProcessingTrace(sessionDir, trace) {
|
|
|
11956
11956
|
if (process.platform === "darwin") {
|
|
11957
11957
|
app.dock.hide();
|
|
11958
11958
|
}
|
|
11959
|
-
app.setName("
|
|
11959
|
+
app.setName("markupR");
|
|
11960
11960
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
11961
11961
|
const __dirname$1 = dirname(__filename$1);
|
|
11962
11962
|
function wrapConsoleMethod(method) {
|
|
@@ -12096,7 +12096,7 @@ async function loadRendererIntoWindow(window, label) {
|
|
|
12096
12096
|
`data:text/html;charset=utf-8,${encodeURIComponent(`
|
|
12097
12097
|
<html>
|
|
12098
12098
|
<body style="margin:0;padding:20px;background:#121212;color:#f5f5f5;font-family:-apple-system,system-ui,sans-serif;">
|
|
12099
|
-
<h2 style="margin:0 0 12px 0;">
|
|
12099
|
+
<h2 style="margin:0 0 12px 0;">markupR failed to load</h2>
|
|
12100
12100
|
<p style="margin:0 0 8px 0;">Dev renderer did not become reachable at ${DEV_RENDERER_URL}.</p>
|
|
12101
12101
|
<p style="margin:0;color:#b3b3b3;">${finalMessage}</p>
|
|
12102
12102
|
</body>
|
|
@@ -12194,7 +12194,7 @@ function handleSessionStateChange(state, session) {
|
|
|
12194
12194
|
console.log(`[Main] Session state changed: ${state}`);
|
|
12195
12195
|
trayManager.setState(mapToTrayState(state));
|
|
12196
12196
|
if (state === "recording" && sessionController.isSessionPaused()) {
|
|
12197
|
-
trayManager.setTooltip(`
|
|
12197
|
+
trayManager.setTooltip(`markupR - Paused (${formatHotkeyForDisplay("pauseResume")} to resume)`);
|
|
12198
12198
|
}
|
|
12199
12199
|
const keepVisibleOnBlur = state === "starting" || state === "recording" || state === "stopping" || state === "processing";
|
|
12200
12200
|
popover?.setKeepVisibleOnBlur(keepVisibleOnBlur);
|
|
@@ -12238,7 +12238,7 @@ function handleFeedbackItem(item) {
|
|
|
12238
12238
|
function handleSessionError(error) {
|
|
12239
12239
|
console.error("[Main] Session error:", error);
|
|
12240
12240
|
trayManager.setState("error");
|
|
12241
|
-
trayManager.setTooltip(`
|
|
12241
|
+
trayManager.setTooltip(`markupR - Error: ${error.message}`);
|
|
12242
12242
|
safeSendToRenderer(IPC_CHANNELS.SESSION_ERROR, {
|
|
12243
12243
|
message: error.message
|
|
12244
12244
|
});
|
|
@@ -12393,7 +12393,7 @@ function pauseSession() {
|
|
|
12393
12393
|
if (!paused) {
|
|
12394
12394
|
return { success: false, error: "Session is already paused." };
|
|
12395
12395
|
}
|
|
12396
|
-
trayManager.setTooltip(`
|
|
12396
|
+
trayManager.setTooltip(`markupR - Paused (${formatHotkeyForDisplay("pauseResume")} to resume)`);
|
|
12397
12397
|
return { success: true };
|
|
12398
12398
|
}
|
|
12399
12399
|
function resumeSession() {
|
|
@@ -12404,7 +12404,7 @@ function resumeSession() {
|
|
|
12404
12404
|
if (!resumed) {
|
|
12405
12405
|
return { success: false, error: "Session is not paused." };
|
|
12406
12406
|
}
|
|
12407
|
-
trayManager.setTooltip(`
|
|
12407
|
+
trayManager.setTooltip(`markupR - Recording... (${formatHotkeyForDisplay("toggleRecording")} to stop)`);
|
|
12408
12408
|
return { success: true };
|
|
12409
12409
|
}
|
|
12410
12410
|
async function resolveDefaultCaptureSource() {
|
|
@@ -12414,7 +12414,7 @@ async function resolveDefaultCaptureSource() {
|
|
|
12414
12414
|
});
|
|
12415
12415
|
if (!sources.length) {
|
|
12416
12416
|
const settingsHint = process.platform === "darwin" ? "System Settings > Privacy & Security > Screen Recording" : process.platform === "win32" ? "Windows Settings > Privacy > Screen capture" : "your system settings";
|
|
12417
|
-
throw new Error(`No screen capture source is available. Check that
|
|
12417
|
+
throw new Error(`No screen capture source is available. Check that markupR has screen recording permission in ${settingsHint}.`);
|
|
12418
12418
|
}
|
|
12419
12419
|
const primaryDisplayId = String(screen.getPrimaryDisplay().id);
|
|
12420
12420
|
const preferredSource = sources.find((source) => source.display_id === primaryDisplayId);
|
|
@@ -13076,7 +13076,7 @@ app.whenReady().then(async () => {
|
|
|
13076
13076
|
showWindow();
|
|
13077
13077
|
}
|
|
13078
13078
|
});
|
|
13079
|
-
console.log("[Main]
|
|
13079
|
+
console.log("[Main] markupR initialization complete");
|
|
13080
13080
|
});
|
|
13081
13081
|
app.on("window-all-closed", () => {
|
|
13082
13082
|
if (process.platform !== "darwin") {
|
|
@@ -13128,7 +13128,7 @@ process.on("uncaughtException", (error) => {
|
|
|
13128
13128
|
}
|
|
13129
13129
|
console.error("[Main] Uncaught exception:", error);
|
|
13130
13130
|
try {
|
|
13131
|
-
showErrorNotification("
|
|
13131
|
+
showErrorNotification("markupR Error", error.message);
|
|
13132
13132
|
} catch {
|
|
13133
13133
|
}
|
|
13134
13134
|
});
|
package/dist/mcp/index.mjs
CHANGED
|
@@ -24,7 +24,7 @@ import { resolve } from "path";
|
|
|
24
24
|
|
|
25
25
|
// src/mcp/utils/Logger.ts
|
|
26
26
|
function log(message) {
|
|
27
|
-
process.stderr.write(`[
|
|
27
|
+
process.stderr.write(`[markupR-mcp] ${message}
|
|
28
28
|
`);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -817,13 +817,13 @@ var MarkdownGeneratorImpl = class {
|
|
|
817
817
|
const filename = this.generateFilename(projectName, session.startTime);
|
|
818
818
|
if (items.length === 0) {
|
|
819
819
|
const content2 = `# ${projectName} Feedback Report
|
|
820
|
-
> Generated by
|
|
820
|
+
> Generated by markupR on ${timestamp}
|
|
821
821
|
> Duration: ${duration}
|
|
822
822
|
|
|
823
823
|
_No feedback items were captured during this session._
|
|
824
824
|
|
|
825
825
|
---
|
|
826
|
-
*Generated by [
|
|
826
|
+
*Generated by [markupR](https://markupr.com)*
|
|
827
827
|
${REPORT_SUPPORT_LINE}
|
|
828
828
|
`;
|
|
829
829
|
return {
|
|
@@ -844,7 +844,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
844
844
|
const highImpactCount = (severityCounts.Critical || 0) + (severityCounts.High || 0);
|
|
845
845
|
const platform = session.metadata?.os || process?.platform || "Unknown";
|
|
846
846
|
let content = `# ${projectName} Feedback Report
|
|
847
|
-
> Generated by
|
|
847
|
+
> Generated by markupR on ${timestamp}
|
|
848
848
|
> Duration: ${duration} | Items: ${items.length} | Screenshots: ${screenshotCount}
|
|
849
849
|
|
|
850
850
|
## Session Overview
|
|
@@ -941,7 +941,7 @@ _No screenshot captured for this item._
|
|
|
941
941
|
`;
|
|
942
942
|
content += `
|
|
943
943
|
---
|
|
944
|
-
*Generated by [
|
|
944
|
+
*Generated by [markupR](https://markupr.com)*
|
|
945
945
|
${REPORT_SUPPORT_LINE}
|
|
946
946
|
`;
|
|
947
947
|
return {
|
|
@@ -974,7 +974,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
974
974
|
const sessionDuration = transcriptSegments.length > 0 ? this.formatDuration(
|
|
975
975
|
(transcriptSegments[transcriptSegments.length - 1].endTime - transcriptSegments[0].startTime) * 1e3
|
|
976
976
|
) : "0:00";
|
|
977
|
-
let md = `#
|
|
977
|
+
let md = `# markupR Session \u2014 ${sessionTimestamp}
|
|
978
978
|
`;
|
|
979
979
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
980
980
|
|
|
@@ -1009,7 +1009,7 @@ ${REPORT_SUPPORT_LINE}
|
|
|
1009
1009
|
}
|
|
1010
1010
|
}
|
|
1011
1011
|
md += `---
|
|
1012
|
-
*Generated by [
|
|
1012
|
+
*Generated by [markupR](https://markupr.com)*
|
|
1013
1013
|
${REPORT_SUPPORT_LINE}
|
|
1014
1014
|
`;
|
|
1015
1015
|
return md;
|
|
@@ -2004,7 +2004,7 @@ var markdownTemplate = {
|
|
|
2004
2004
|
const { transcriptSegments, extractedFrames } = result;
|
|
2005
2005
|
const sessionTimestamp = formatDate(new Date(timestamp ?? Date.now()));
|
|
2006
2006
|
const sessionDuration = computeSessionDuration(transcriptSegments);
|
|
2007
|
-
let md = `#
|
|
2007
|
+
let md = `# markupR Session \u2014 ${sessionTimestamp}
|
|
2008
2008
|
`;
|
|
2009
2009
|
md += `> Segments: ${transcriptSegments.length} | Frames: ${extractedFrames.length} | Duration: ${sessionDuration}
|
|
2010
2010
|
|
|
@@ -2039,7 +2039,7 @@ var markdownTemplate = {
|
|
|
2039
2039
|
}
|
|
2040
2040
|
}
|
|
2041
2041
|
md += `---
|
|
2042
|
-
*Generated by [
|
|
2042
|
+
*Generated by [markupR](https://markupr.com)*
|
|
2043
2043
|
${REPORT_SUPPORT_LINE2}
|
|
2044
2044
|
`;
|
|
2045
2045
|
return { content: md, fileExtension: ".md" };
|
|
@@ -2057,7 +2057,7 @@ var jsonTemplate = {
|
|
|
2057
2057
|
const segmentFrameMap = mapFramesToSegments(transcriptSegments, extractedFrames);
|
|
2058
2058
|
const output = {
|
|
2059
2059
|
version: "1.0",
|
|
2060
|
-
generator: "
|
|
2060
|
+
generator: "markupR",
|
|
2061
2061
|
timestamp: new Date(timestamp ?? Date.now()).toISOString(),
|
|
2062
2062
|
summary: {
|
|
2063
2063
|
segments: transcriptSegments.length,
|
|
@@ -2099,7 +2099,7 @@ var githubIssueTemplate = {
|
|
|
2099
2099
|
let md = `## Feedback Report
|
|
2100
2100
|
|
|
2101
2101
|
`;
|
|
2102
|
-
md += `> Captured by [
|
|
2102
|
+
md += `> Captured by [markupR](https://markupr.com) on ${sessionTimestamp}
|
|
2103
2103
|
`;
|
|
2104
2104
|
md += `> ${transcriptSegments.length} segments | ${extractedFrames.length} frames | Duration: ${duration}
|
|
2105
2105
|
|
|
@@ -2149,7 +2149,7 @@ var githubIssueTemplate = {
|
|
|
2149
2149
|
`;
|
|
2150
2150
|
}
|
|
2151
2151
|
md += `---
|
|
2152
|
-
_Generated by [
|
|
2152
|
+
_Generated by [markupR](https://markupr.com)_
|
|
2153
2153
|
`;
|
|
2154
2154
|
return { content: md, fileExtension: ".md" };
|
|
2155
2155
|
}
|
|
@@ -2209,7 +2209,7 @@ var linearTemplate = {
|
|
|
2209
2209
|
}
|
|
2210
2210
|
}
|
|
2211
2211
|
md += `---
|
|
2212
|
-
_Captured by [
|
|
2212
|
+
_Captured by [markupR](https://markupr.com)_
|
|
2213
2213
|
`;
|
|
2214
2214
|
return { content: md, fileExtension: ".md" };
|
|
2215
2215
|
}
|
|
@@ -2283,7 +2283,7 @@ ${segment.text}
|
|
|
2283
2283
|
}
|
|
2284
2284
|
}
|
|
2285
2285
|
content += `----
|
|
2286
|
-
_Generated by [
|
|
2286
|
+
_Generated by [markupR|https://markupr.com]_
|
|
2287
2287
|
`;
|
|
2288
2288
|
return { content, fileExtension: ".jira" };
|
|
2289
2289
|
}
|
|
@@ -2712,7 +2712,7 @@ var CLIPipelineError = class extends Error {
|
|
|
2712
2712
|
function register2(server) {
|
|
2713
2713
|
server.tool(
|
|
2714
2714
|
"capture_with_voice",
|
|
2715
|
-
"Record screen and voice for a specified duration, then run the full
|
|
2715
|
+
"Record screen and voice for a specified duration, then run the full markupR pipeline to produce a structured feedback report.",
|
|
2716
2716
|
{
|
|
2717
2717
|
duration: z2.number().min(3).max(300).describe("Recording duration in seconds (3-300)"),
|
|
2718
2718
|
outputDir: z2.string().optional().describe("Output directory (default: session directory)"),
|
|
@@ -2779,7 +2779,7 @@ import { stat as stat4 } from "fs/promises";
|
|
|
2779
2779
|
function register3(server) {
|
|
2780
2780
|
server.tool(
|
|
2781
2781
|
"analyze_video",
|
|
2782
|
-
"Process an existing video file through the
|
|
2782
|
+
"Process an existing video file through the markupR pipeline. Generates a structured markdown report with transcript, key moments, and extracted frames.",
|
|
2783
2783
|
{
|
|
2784
2784
|
videoPath: z3.string().describe("Absolute path to the video file"),
|
|
2785
2785
|
audioPath: z3.string().optional().describe("Separate audio file path (if not embedded)"),
|
|
@@ -3024,7 +3024,7 @@ import { z as z6 } from "zod";
|
|
|
3024
3024
|
function register6(server) {
|
|
3025
3025
|
server.tool(
|
|
3026
3026
|
"stop_recording",
|
|
3027
|
-
"Stop an active recording and run the full
|
|
3027
|
+
"Stop an active recording and run the full markupR pipeline on the captured video.",
|
|
3028
3028
|
{
|
|
3029
3029
|
sessionId: z6.string().optional().describe("Session ID (default: current active recording)"),
|
|
3030
3030
|
skipFrames: z6.boolean().optional().default(false).describe("Skip frame extraction"),
|
|
@@ -3128,7 +3128,7 @@ var LinearIssueCreator = class {
|
|
|
3128
3128
|
this.token = token;
|
|
3129
3129
|
}
|
|
3130
3130
|
/**
|
|
3131
|
-
* Push a
|
|
3131
|
+
* Push a markupR report to Linear, creating one issue per feedback item.
|
|
3132
3132
|
*/
|
|
3133
3133
|
async pushReport(reportPath, options) {
|
|
3134
3134
|
const markdown = await readFile4(reportPath, "utf-8");
|
|
@@ -3292,7 +3292,7 @@ var LinearIssueCreator = class {
|
|
|
3292
3292
|
* Build markdown description for a Linear issue from a feedback item.
|
|
3293
3293
|
*/
|
|
3294
3294
|
buildIssueDescription(item) {
|
|
3295
|
-
let desc = `##
|
|
3295
|
+
let desc = `## markupR Feedback: ${item.id}
|
|
3296
3296
|
|
|
3297
3297
|
`;
|
|
3298
3298
|
desc += `**Severity:** ${item.severity}
|
|
@@ -3327,7 +3327,7 @@ ${item.suggestedAction}
|
|
|
3327
3327
|
}
|
|
3328
3328
|
desc += `
|
|
3329
3329
|
---
|
|
3330
|
-
*Created by [
|
|
3330
|
+
*Created by [markupR](https://markupr.com)*`;
|
|
3331
3331
|
return desc;
|
|
3332
3332
|
}
|
|
3333
3333
|
/**
|
|
@@ -3417,9 +3417,9 @@ function extractSuggestedAction(section) {
|
|
|
3417
3417
|
function register7(server) {
|
|
3418
3418
|
server.tool(
|
|
3419
3419
|
"push_to_linear",
|
|
3420
|
-
"Push a
|
|
3420
|
+
"Push a markupR feedback report to Linear. Creates one issue per feedback item with priority mapping, labels, and full context.",
|
|
3421
3421
|
{
|
|
3422
|
-
reportPath: z7.string().describe("Absolute path to the
|
|
3422
|
+
reportPath: z7.string().describe("Absolute path to the markupR markdown report"),
|
|
3423
3423
|
teamKey: z7.string().describe('Linear team key (e.g., "ENG", "DES")'),
|
|
3424
3424
|
token: z7.string().optional().describe("Linear API key (or set LINEAR_API_KEY env var)"),
|
|
3425
3425
|
projectName: z7.string().optional().describe("Linear project name to assign issues to"),
|
|
@@ -3530,9 +3530,9 @@ var SEVERITY_LABELS = {
|
|
|
3530
3530
|
Low: { name: "priority: low", color: "0e8a16", description: "Low priority" }
|
|
3531
3531
|
};
|
|
3532
3532
|
var MARKUPR_LABEL = {
|
|
3533
|
-
name: "
|
|
3533
|
+
name: "markupR",
|
|
3534
3534
|
color: "6f42c1",
|
|
3535
|
-
description: "Created from
|
|
3535
|
+
description: "Created from markupR feedback session"
|
|
3536
3536
|
};
|
|
3537
3537
|
|
|
3538
3538
|
// src/integrations/github/GitHubIssueCreator.ts
|
|
@@ -3658,7 +3658,7 @@ function formatIssueBody(item, reportPath) {
|
|
|
3658
3658
|
body += `### Screenshots
|
|
3659
3659
|
|
|
3660
3660
|
`;
|
|
3661
|
-
body += `_${item.screenshotPaths.length} screenshot(s) captured \u2014 see the
|
|
3661
|
+
body += `_${item.screenshotPaths.length} screenshot(s) captured \u2014 see the markupR report for images._
|
|
3662
3662
|
|
|
3663
3663
|
`;
|
|
3664
3664
|
}
|
|
@@ -3676,7 +3676,7 @@ function formatIssueBody(item, reportPath) {
|
|
|
3676
3676
|
body += `_Source: \`${reportPath}\`_
|
|
3677
3677
|
`;
|
|
3678
3678
|
}
|
|
3679
|
-
body += `_Created by [
|
|
3679
|
+
body += `_Created by [markupR](https://markupr.com)_
|
|
3680
3680
|
`;
|
|
3681
3681
|
return body;
|
|
3682
3682
|
}
|
|
@@ -3796,7 +3796,7 @@ async function pushToGitHub(options) {
|
|
|
3796
3796
|
const markdown = await readFile5(reportPath, "utf-8");
|
|
3797
3797
|
let items = parseMarkuprReport(markdown);
|
|
3798
3798
|
if (items.length === 0) {
|
|
3799
|
-
throw new Error("No feedback items found in the report. Is this a valid
|
|
3799
|
+
throw new Error("No feedback items found in the report. Is this a valid markupR report?");
|
|
3800
3800
|
}
|
|
3801
3801
|
if (filterIds && filterIds.length > 0) {
|
|
3802
3802
|
const filterSet = new Set(filterIds.map((id) => id.toUpperCase()));
|
|
@@ -3866,9 +3866,9 @@ function parseRepoString(repoStr) {
|
|
|
3866
3866
|
function register8(server) {
|
|
3867
3867
|
server.tool(
|
|
3868
3868
|
"push_to_github",
|
|
3869
|
-
"Create GitHub issues from a
|
|
3869
|
+
"Create GitHub issues from a markupR feedback report. Each feedback item becomes a separate issue with labels and structured markdown.",
|
|
3870
3870
|
{
|
|
3871
|
-
reportPath: z8.string().describe("Absolute path to the
|
|
3871
|
+
reportPath: z8.string().describe("Absolute path to the markupR markdown report"),
|
|
3872
3872
|
repo: z8.string().describe('Target GitHub repository in "owner/repo" format'),
|
|
3873
3873
|
token: z8.string().optional().describe("GitHub token (falls back to GITHUB_TOKEN env or gh CLI)"),
|
|
3874
3874
|
items: z8.array(z8.string()).optional().describe("Specific FB-XXX item IDs to push (default: all)"),
|
|
@@ -4222,10 +4222,10 @@ function registerResources(server) {
|
|
|
4222
4222
|
}
|
|
4223
4223
|
|
|
4224
4224
|
// src/mcp/server.ts
|
|
4225
|
-
var VERSION = true ? "2.6.
|
|
4225
|
+
var VERSION = true ? "2.6.4" : "0.0.0-dev";
|
|
4226
4226
|
function createServer() {
|
|
4227
4227
|
const server = new McpServer2({
|
|
4228
|
-
name: "
|
|
4228
|
+
name: "markupR",
|
|
4229
4229
|
version: VERSION
|
|
4230
4230
|
});
|
|
4231
4231
|
register(server);
|
|
@@ -4242,8 +4242,8 @@ function createServer() {
|
|
|
4242
4242
|
}
|
|
4243
4243
|
|
|
4244
4244
|
// src/mcp/index.ts
|
|
4245
|
-
var VERSION2 = true ? "2.6.
|
|
4246
|
-
log(`
|
|
4245
|
+
var VERSION2 = true ? "2.6.4" : "0.0.0-dev";
|
|
4246
|
+
log(`markupR MCP server v${VERSION2} starting...`);
|
|
4247
4247
|
process.on("uncaughtException", (error) => {
|
|
4248
4248
|
log(`Uncaught exception: ${error instanceof Error ? error.message : String(error)}`);
|
|
4249
4249
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markupr",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.4",
|
|
4
4
|
"description": "Record your screen, narrate feedback, get structured Markdown with screenshots. Desktop app, CLI, and MCP server for AI coding agents like Claude Code, Cursor, and Windsurf.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main/index.mjs",
|