mcp-scraper 0.3.11 → 0.3.12
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 +2 -2
- package/dist/bin/api-server.cjs +86 -22
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/browser-agent-stdio-server.cjs +198 -27
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-server.js +3 -2
- package/dist/bin/browser-agent-stdio-server.js.map +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +254 -56
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +4 -3
- package/dist/bin/mcp-scraper-combined-stdio-server.js.map +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +38 -11
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/bin/paa-harvest.cjs +21 -1
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/chunk-3YGKXXUG.js +133 -0
- package/dist/chunk-3YGKXXUG.js.map +1 -0
- package/dist/{chunk-UWSG3C5J.js → chunk-4OPKIDON.js} +22 -2
- package/dist/chunk-4OPKIDON.js.map +1 -0
- package/dist/{chunk-VMH7SRWY.js → chunk-7R7VBQRV.js} +39 -12
- package/dist/chunk-7R7VBQRV.js.map +1 -0
- package/dist/{chunk-L27GJQV7.js → chunk-BW3DGFNQ.js} +28 -5
- package/dist/chunk-BW3DGFNQ.js.map +1 -0
- package/dist/chunk-FB5ZJGFN.js +7 -0
- package/dist/chunk-FB5ZJGFN.js.map +1 -0
- package/dist/index.cjs +21 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-3SA5Q4OF.js → server-CUPDJLWM.js} +42 -151
- package/dist/server-CUPDJLWM.js.map +1 -0
- package/dist/{worker-56IXWOQU.js → worker-FG7ZWEGA.js} +2 -2
- package/docs/mcp-tool-craft-lint.generated.md +1 -1
- package/docs/mcp-tool-manifest.generated.json +1 -1
- package/package.json +1 -1
- package/dist/chunk-L27GJQV7.js.map +0 -1
- package/dist/chunk-RRE7WVHQ.js +0 -7
- package/dist/chunk-RRE7WVHQ.js.map +0 -1
- package/dist/chunk-UWSG3C5J.js.map +0 -1
- package/dist/chunk-VMH7SRWY.js.map +0 -1
- package/dist/server-3SA5Q4OF.js.map +0 -1
- /package/dist/{worker-56IXWOQU.js.map → worker-FG7ZWEGA.js.map} +0 -0
package/dist/bin/api-server.js
CHANGED
|
@@ -17,8 +17,8 @@ loadDotEnv();
|
|
|
17
17
|
async function main() {
|
|
18
18
|
const [{ serve }, { app }, { startWorker }, { migrate }] = await Promise.all([
|
|
19
19
|
import("@hono/node-server"),
|
|
20
|
-
import("../server-
|
|
21
|
-
import("../worker-
|
|
20
|
+
import("../server-CUPDJLWM.js"),
|
|
21
|
+
import("../worker-FG7ZWEGA.js"),
|
|
22
22
|
import("../db-BE4JVB3V.js")
|
|
23
23
|
]);
|
|
24
24
|
const PORT = parseInt(process.env.PORT ?? "3001");
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
3
25
|
|
|
4
26
|
// bin/browser-agent-stdio-server.ts
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
27
|
+
var import_node_fs3 = require("fs");
|
|
28
|
+
var import_node_os4 = require("os");
|
|
29
|
+
var import_node_path4 = require("path");
|
|
8
30
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
9
31
|
|
|
10
32
|
// src/mcp/browser-agent-mcp-server.ts
|
|
11
33
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
var
|
|
34
|
+
var import_node_fs2 = require("fs");
|
|
35
|
+
var import_node_os3 = require("os");
|
|
36
|
+
var import_node_path3 = require("path");
|
|
15
37
|
|
|
16
38
|
// src/lib/browser-service-env.ts
|
|
17
39
|
function browserServiceProfileName() {
|
|
@@ -26,8 +48,137 @@ function browserServiceProfileSaveChanges() {
|
|
|
26
48
|
return void 0;
|
|
27
49
|
}
|
|
28
50
|
|
|
51
|
+
// src/services/fanout/export.ts
|
|
52
|
+
var import_node_fs = require("fs");
|
|
53
|
+
var import_node_os = require("os");
|
|
54
|
+
var import_node_path = require("path");
|
|
55
|
+
var import_papaparse = __toESM(require("papaparse"), 1);
|
|
56
|
+
function outputBaseDir() {
|
|
57
|
+
return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0, import_node_path.join)((0, import_node_os.homedir)(), "Downloads", "mcp-scraper");
|
|
58
|
+
}
|
|
59
|
+
function safe(value) {
|
|
60
|
+
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "capture";
|
|
61
|
+
}
|
|
62
|
+
function writeTable(path, rows, delimiter) {
|
|
63
|
+
(0, import_node_fs.writeFileSync)(path, import_papaparse.default.unparse(rows.length ? rows : [{}], { delimiter }));
|
|
64
|
+
}
|
|
65
|
+
function exportFanout(enriched) {
|
|
66
|
+
const stamp = safe(enriched.capturedAt.replace(/[:.]/g, "-"));
|
|
67
|
+
const outputDir = outputBaseDir();
|
|
68
|
+
const relativeDir = (0, import_node_path.join)("fanout", `${stamp}-${safe(enriched.platform)}`);
|
|
69
|
+
const dir = (0, import_node_path.join)(outputDir, relativeDir);
|
|
70
|
+
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
71
|
+
const queryRows = enriched.queries.map((q, i) => ({ index: i + 1, query: q }));
|
|
72
|
+
const citationRows = enriched.aggregates.citationOrder.map((c) => {
|
|
73
|
+
const src = enriched.citedUrls.find((s) => s.url === c.url);
|
|
74
|
+
return { rank: c.rank, domain: c.domain, url: c.url, timesCited: c.timesCited, siteType: src?.siteType ?? "", title: src?.title ?? "" };
|
|
75
|
+
});
|
|
76
|
+
const sourceRows = enriched.browsedUrls.map((s) => ({ domain: s.domain, url: s.url, cited: s.cited, timesCited: s.timesCited, siteType: s.siteType, title: s.title, round: s.round ?? "" }));
|
|
77
|
+
const browsedOnlyRows = enriched.browsedOnly.map((s) => ({ domain: s.domain, url: s.url, cited: s.cited, timesCited: s.timesCited, siteType: s.siteType, title: s.title, round: s.round ?? "" }));
|
|
78
|
+
const snippetRows = enriched.snippets.map((s) => ({ domain: s.domain, url: s.url, title: s.title, text: s.text }));
|
|
79
|
+
const domainRows = enriched.aggregates.topSites.map((d) => ({ domain: d.domain, count: d.count, cited: d.cited, timesCited: d.timesCited, siteType: d.siteType }));
|
|
80
|
+
const relativePaths = {
|
|
81
|
+
relativeTo: "MCP_SCRAPER_OUTPUT_DIR or ~/Downloads/mcp-scraper",
|
|
82
|
+
dir: relativeDir,
|
|
83
|
+
json: (0, import_node_path.join)(relativeDir, "fanout.json"),
|
|
84
|
+
queriesCsv: (0, import_node_path.join)(relativeDir, "queries.csv"),
|
|
85
|
+
queriesTsv: (0, import_node_path.join)(relativeDir, "queries.tsv"),
|
|
86
|
+
citationsCsv: (0, import_node_path.join)(relativeDir, "citations.csv"),
|
|
87
|
+
sourcesCsv: (0, import_node_path.join)(relativeDir, "sources.csv"),
|
|
88
|
+
browsedOnlyCsv: (0, import_node_path.join)(relativeDir, "browsed-only.csv"),
|
|
89
|
+
snippetsCsv: (0, import_node_path.join)(relativeDir, "snippets.csv"),
|
|
90
|
+
domainsCsv: (0, import_node_path.join)(relativeDir, "domains.csv"),
|
|
91
|
+
report: (0, import_node_path.join)(relativeDir, "report.html")
|
|
92
|
+
};
|
|
93
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(outputDir, relativePaths.json), JSON.stringify(enriched, null, 2));
|
|
94
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.queriesCsv), queryRows, ",");
|
|
95
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.queriesTsv), queryRows, " ");
|
|
96
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.citationsCsv), citationRows, ",");
|
|
97
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.sourcesCsv), sourceRows, ",");
|
|
98
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.browsedOnlyCsv), browsedOnlyRows, ",");
|
|
99
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.snippetsCsv), snippetRows, ",");
|
|
100
|
+
writeTable((0, import_node_path.join)(outputDir, relativePaths.domainsCsv), domainRows, ",");
|
|
101
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(outputDir, relativePaths.report), renderReportHtml(enriched));
|
|
102
|
+
return relativePaths;
|
|
103
|
+
}
|
|
104
|
+
function esc(s) {
|
|
105
|
+
return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
106
|
+
}
|
|
107
|
+
function renderReportHtml(enriched) {
|
|
108
|
+
const data = JSON.stringify(enriched).replace(/</g, "\\u003c");
|
|
109
|
+
return `<!doctype html>
|
|
110
|
+
<html lang="en">
|
|
111
|
+
<head>
|
|
112
|
+
<meta charset="utf-8" />
|
|
113
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
114
|
+
<title>AI Search Fan-Out \u2014 ${esc(enriched.platform)}</title>
|
|
115
|
+
<style>
|
|
116
|
+
:root{--bg:#0b0d12;--panel:#151922;--line:#252b38;--ink:#e8ecf3;--mut:#8b95a7;--acc:#5b9dff;--cite:#39d98a;--browse:#5a6677}
|
|
117
|
+
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}
|
|
118
|
+
.wrap{max-width:980px;margin:0 auto;padding:28px 20px 80px}
|
|
119
|
+
h1{font-size:20px;margin:0 0 2px}.sub{color:var(--mut);margin:0 0 20px;font-size:13px}
|
|
120
|
+
.stat{font-size:30px;font-weight:700}.stat small{font-size:13px;font-weight:400;color:var(--mut)}
|
|
121
|
+
.cards{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:18px 0}
|
|
122
|
+
.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px 14px}
|
|
123
|
+
.card b{font-size:22px;display:block}.card span{color:var(--mut);font-size:12px}
|
|
124
|
+
.bars{margin:8px 0 22px}.bar{display:flex;align-items:center;gap:8px;margin:4px 0}
|
|
125
|
+
.bar .lab{width:150px;color:var(--mut);font-size:12px;text-align:right}.bar .track{flex:1;background:#10141c;border-radius:5px;overflow:hidden}
|
|
126
|
+
.bar .fill{background:var(--acc);height:16px}.bar .n{width:34px;font-size:12px;color:var(--mut)}
|
|
127
|
+
.tabs{display:flex;gap:8px;margin:22px 0 12px}.tab{background:var(--panel);border:1px solid var(--line);color:var(--ink);padding:7px 14px;border-radius:8px;cursor:pointer}
|
|
128
|
+
.tab.on{background:var(--acc);border-color:var(--acc);color:#04101f;font-weight:600}
|
|
129
|
+
.chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
|
|
130
|
+
.chip{background:var(--panel);border:1px solid var(--line);color:var(--mut);padding:4px 10px;border-radius:20px;cursor:pointer;font-size:12px}
|
|
131
|
+
.chip.on{border-color:var(--acc);color:var(--ink)}.chip b{color:var(--ink)}
|
|
132
|
+
.row{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin:6px 0;display:flex;gap:10px;align-items:flex-start}
|
|
133
|
+
.row .idx{color:var(--mut);min-width:22px}.row .main{flex:1}
|
|
134
|
+
.tag{font-size:11px;padding:2px 7px;border-radius:6px;border:1px solid var(--line);color:var(--mut);margin-right:5px}
|
|
135
|
+
.dom{font-weight:600}.url{color:var(--mut);font-size:12px;word-break:break-all}
|
|
136
|
+
.pill{font-size:11px;padding:2px 7px;border-radius:6px}.pill.cite{background:rgba(57,217,138,.15);color:var(--cite)}.pill.brow{background:rgba(90,102,119,.2);color:#aeb8c8}
|
|
137
|
+
.copy{background:none;border:1px solid var(--line);color:var(--mut);border-radius:6px;cursor:pointer;font-size:11px;padding:2px 8px}
|
|
138
|
+
.hide{display:none}
|
|
139
|
+
</style>
|
|
140
|
+
</head>
|
|
141
|
+
<body><div class="wrap">
|
|
142
|
+
<h1>AI Search Fan-Out</h1>
|
|
143
|
+
<p class="sub" id="sub"></p>
|
|
144
|
+
<div class="stat" id="stat"></div>
|
|
145
|
+
<div class="cards" id="cards"></div>
|
|
146
|
+
<div id="charts"></div>
|
|
147
|
+
<div class="tabs"><button class="tab on" data-tab="q">Queries</button><button class="tab" data-tab="u">URLs</button></div>
|
|
148
|
+
<div class="chips" id="chips"></div>
|
|
149
|
+
<div id="list"></div>
|
|
150
|
+
</div>
|
|
151
|
+
<script>
|
|
152
|
+
const D=${data};
|
|
153
|
+
const el=(t,c,h)=>{const e=document.createElement(t);if(c)e.className=c;if(h!=null)e.innerHTML=h;return e};
|
|
154
|
+
document.getElementById('sub').textContent=D.platform+' \xB7 '+(D.meta.model||'model n/a')+' \xB7 '+D.meta.rounds+' search round(s) \xB7 prompt: '+(D.prompt||'');
|
|
155
|
+
document.getElementById('stat').innerHTML='Total Fan-Out: '+D.counts.subQueries+' <small>sub-queries \xB7 '+D.counts.browsed+' URLs researched \xB7 '+D.counts.cited+' cited</small>';
|
|
156
|
+
const cards=[['Sub-queries',D.counts.subQueries],['Researched',D.counts.browsed],['Cited',D.counts.cited],['Browsed-only',D.counts.browsedOnly]];
|
|
157
|
+
const cc=document.getElementById('cards');cards.forEach(([k,v])=>{const c=el('div','card');c.appendChild(el('b',null,v));c.appendChild(el('span',null,k));cc.appendChild(c)});
|
|
158
|
+
function barChart(title,obj){const max=Math.max(1,...Object.values(obj));const box=el('div','bars');box.appendChild(el('div',null,'<b>'+title+'</b>'));Object.entries(obj).forEach(([k,v])=>{const r=el('div','bar');r.appendChild(el('div','lab',k));const t=el('div','track');const f=el('div','fill');f.style.width=(v/max*100)+'%';t.appendChild(f);r.appendChild(t);r.appendChild(el('div','n',v));box.appendChild(r)});return box}
|
|
159
|
+
const charts=document.getElementById('charts');
|
|
160
|
+
charts.appendChild(barChart('URL Categories',D.aggregates.byCategory));
|
|
161
|
+
let tab='q',filter=null;
|
|
162
|
+
const chips=document.getElementById('chips'),list=document.getElementById('list');
|
|
163
|
+
function render(){
|
|
164
|
+
chips.innerHTML='';list.innerHTML='';
|
|
165
|
+
if(tab==='q'){
|
|
166
|
+
D.queries.forEach((q,i)=>{const r=el('div','row');r.appendChild(el('div','idx',i+1));const m=el('div','main');m.appendChild(el('div',null,esc(q)));r.appendChild(m);const b=el('button','copy','copy');b.onclick=()=>navigator.clipboard.writeText(q);r.appendChild(b);list.appendChild(r)});
|
|
167
|
+
} else {
|
|
168
|
+
const counts={};D.browsedUrls.forEach(s=>{counts[s.siteType]=(counts[s.siteType]||0)+1});
|
|
169
|
+
Object.entries(counts).forEach(([k,v])=>{const c=el('button','chip'+(filter===k?' on':''),k+' <b>'+v+'</b>');c.onclick=()=>{filter=filter===k?null:k;render()};chips.appendChild(c)});
|
|
170
|
+
D.browsedUrls.forEach(s=>{if(filter&&s.siteType!==filter)return;const r=el('div','row');const m=el('div','main');m.appendChild(el('div',null,'<span class="dom">'+esc(s.domain)+'</span> <span class="pill '+(s.cited?'cite':'brow')+'">'+(s.cited?'cited '+s.timesCited+'\xD7':'browsed')+'</span> <span class="tag">'+s.siteType+'</span>'));m.appendChild(el('div','url',esc(s.url)));r.appendChild(m);list.appendChild(r)});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
174
|
+
document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.remove('on'));t.classList.add('on');tab=t.dataset.tab;filter=null;render()});
|
|
175
|
+
render();
|
|
176
|
+
</script>
|
|
177
|
+
</body></html>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
29
180
|
// src/version.ts
|
|
30
|
-
var PACKAGE_VERSION = "0.3.
|
|
181
|
+
var PACKAGE_VERSION = "0.3.12";
|
|
31
182
|
|
|
32
183
|
// src/mcp/browser-agent-tool-schemas.ts
|
|
33
184
|
var import_zod = require("zod");
|
|
@@ -369,8 +520,8 @@ var BrowserListSessionsOutputSchema = {
|
|
|
369
520
|
// src/mcp/replay-annotator.ts
|
|
370
521
|
var import_node_child_process = require("child_process");
|
|
371
522
|
var import_promises = require("fs/promises");
|
|
372
|
-
var
|
|
373
|
-
var
|
|
523
|
+
var import_node_os2 = require("os");
|
|
524
|
+
var import_node_path2 = require("path");
|
|
374
525
|
var import_node_util = require("util");
|
|
375
526
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
376
527
|
function finiteNumber(value) {
|
|
@@ -380,11 +531,11 @@ function clamp(value, min, max) {
|
|
|
380
531
|
return Math.min(max, Math.max(min, value));
|
|
381
532
|
}
|
|
382
533
|
function formatAssTime(seconds) {
|
|
383
|
-
const
|
|
384
|
-
const hours = Math.floor(
|
|
385
|
-
const minutes = Math.floor(
|
|
386
|
-
const wholeSeconds = Math.floor(
|
|
387
|
-
const centiseconds = Math.floor((
|
|
534
|
+
const safe2 = Math.max(0, seconds);
|
|
535
|
+
const hours = Math.floor(safe2 / 3600);
|
|
536
|
+
const minutes = Math.floor(safe2 % 3600 / 60);
|
|
537
|
+
const wholeSeconds = Math.floor(safe2 % 60);
|
|
538
|
+
const centiseconds = Math.floor((safe2 - Math.floor(safe2)) * 100);
|
|
388
539
|
return `${hours}:${String(minutes).padStart(2, "0")}:${String(wholeSeconds).padStart(2, "0")}.${String(centiseconds).padStart(2, "0")}`;
|
|
389
540
|
}
|
|
390
541
|
function cssHexToAssColor(color) {
|
|
@@ -593,8 +744,8 @@ function ffmpegFilterPath(path) {
|
|
|
593
744
|
async function annotateReplayVideo(inputFilePath, outputFilePath, options) {
|
|
594
745
|
if (!options.annotations.length) throw new Error("annotations must include at least one item");
|
|
595
746
|
const size = await videoSize(inputFilePath);
|
|
596
|
-
const tmp = await (0, import_promises.mkdtemp)((0,
|
|
597
|
-
const assPath = (0,
|
|
747
|
+
const tmp = await (0, import_promises.mkdtemp)((0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "mcp-scraper-ass-"));
|
|
748
|
+
const assPath = (0, import_node_path2.join)(tmp, "annotations.ass");
|
|
598
749
|
try {
|
|
599
750
|
await (0, import_promises.writeFile)(assPath, buildAssSubtitle(options, size), "utf8");
|
|
600
751
|
await execFileAsync("ffmpeg", [
|
|
@@ -662,8 +813,8 @@ function actionResult(tool, sessionId, ok, data, nextRecommendedTool = "browser_
|
|
|
662
813
|
nextRecommendedTool
|
|
663
814
|
});
|
|
664
815
|
}
|
|
665
|
-
function
|
|
666
|
-
return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0,
|
|
816
|
+
function outputBaseDir2() {
|
|
817
|
+
return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0, import_node_path3.join)((0, import_node_os3.homedir)(), "Downloads", "mcp-scraper");
|
|
667
818
|
}
|
|
668
819
|
function safeFilePart(value) {
|
|
669
820
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 120) || "replay";
|
|
@@ -672,7 +823,7 @@ function replayFilePath(sessionId, replayId, filename) {
|
|
|
672
823
|
const requested = filename?.trim();
|
|
673
824
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
674
825
|
const name = requested ? safeFilePart(requested).replace(/\.mp4$/i, "") : `${stamp}-${safeFilePart(sessionId)}-${safeFilePart(replayId)}`;
|
|
675
|
-
return (0,
|
|
826
|
+
return (0, import_node_path3.join)(outputBaseDir2(), "browser-replays", `${name}.mp4`);
|
|
676
827
|
}
|
|
677
828
|
function slugPart(value) {
|
|
678
829
|
const trimmed = value?.trim().toLowerCase();
|
|
@@ -685,6 +836,11 @@ function savedProfileNameFromEmail(email, domain) {
|
|
|
685
836
|
const domainPart = slugPart(domain);
|
|
686
837
|
return `${value}${domainPart ? `-${domainPart}` : ""}`.slice(0, 80) || null;
|
|
687
838
|
}
|
|
839
|
+
function isEnrichedFanout(value) {
|
|
840
|
+
if (!value || typeof value !== "object") return false;
|
|
841
|
+
const candidate = value;
|
|
842
|
+
return typeof candidate.platform === "string" && typeof candidate.capturedAt === "string" && typeof candidate.prompt === "string" && Array.isArray(candidate.queries) && Array.isArray(candidate.browsedUrls) && Array.isArray(candidate.citedUrls) && Array.isArray(candidate.browsedOnly) && Array.isArray(candidate.snippets) && !!candidate.counts && !!candidate.aggregates;
|
|
843
|
+
}
|
|
688
844
|
function annotatedReplayFilePath(sessionId, replayId, filename) {
|
|
689
845
|
const requested = filename?.trim();
|
|
690
846
|
if (requested) return replayFilePath(sessionId, replayId, requested);
|
|
@@ -747,8 +903,8 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
747
903
|
}
|
|
748
904
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
749
905
|
const filePath = replayFilePath(sessionId, replayId, filename);
|
|
750
|
-
(0,
|
|
751
|
-
(0,
|
|
906
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path3.join)(outputBaseDir2(), "browser-replays"), { recursive: true });
|
|
907
|
+
(0, import_node_fs2.writeFileSync)(filePath, bytes);
|
|
752
908
|
return {
|
|
753
909
|
ok: true,
|
|
754
910
|
data: {
|
|
@@ -1207,7 +1363,7 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
1207
1363
|
try {
|
|
1208
1364
|
const sourcePath = String(downloaded.data.file_path);
|
|
1209
1365
|
const outputPath = annotatedReplayFilePath(input.session_id, input.replay_id, input.filename);
|
|
1210
|
-
(0,
|
|
1366
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path3.join)(outputBaseDir2(), "browser-replays"), { recursive: true });
|
|
1211
1367
|
const result = await annotateReplayVideo(sourcePath, outputPath, {
|
|
1212
1368
|
annotations: input.annotations,
|
|
1213
1369
|
sourceWidth: input.source_width,
|
|
@@ -1286,7 +1442,7 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
1286
1442
|
annotations: annotations("Capture AI Search Fan-Out")
|
|
1287
1443
|
},
|
|
1288
1444
|
async (input) => {
|
|
1289
|
-
const emit = (result,
|
|
1445
|
+
const emit = (result, exports3) => structuredResult({
|
|
1290
1446
|
ok: true,
|
|
1291
1447
|
tool: "browser_capture_fanout",
|
|
1292
1448
|
session_id: input.session_id,
|
|
@@ -1302,7 +1458,7 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
1302
1458
|
counts: result.counts,
|
|
1303
1459
|
aggregates: result.aggregates,
|
|
1304
1460
|
first_party_domain: result.firstPartyDomain,
|
|
1305
|
-
exports:
|
|
1461
|
+
exports: exports3 ?? null,
|
|
1306
1462
|
...result.debug ? { debug: result.debug } : {}
|
|
1307
1463
|
});
|
|
1308
1464
|
const res = await req("POST", `/agent/sessions/${input.session_id}/capture-fanout`, {
|
|
@@ -1314,7 +1470,22 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
1314
1470
|
});
|
|
1315
1471
|
if (!res.ok) return errorResult("browser_capture_fanout", res.data, input.session_id);
|
|
1316
1472
|
const hosted = res.data?.result ?? res.data;
|
|
1317
|
-
|
|
1473
|
+
let exports2 = res.data?.exports ?? null;
|
|
1474
|
+
if (input.export && !exports2 && isEnrichedFanout(hosted)) {
|
|
1475
|
+
try {
|
|
1476
|
+
exports2 = exportFanout(hosted);
|
|
1477
|
+
} catch (err) {
|
|
1478
|
+
return errorResult(
|
|
1479
|
+
"browser_capture_fanout",
|
|
1480
|
+
{
|
|
1481
|
+
error: `Fan-out captured but local export failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1482
|
+
result: hosted
|
|
1483
|
+
},
|
|
1484
|
+
input.session_id
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return emit(hosted, exports2);
|
|
1318
1489
|
}
|
|
1319
1490
|
);
|
|
1320
1491
|
}
|
|
@@ -1322,10 +1493,10 @@ function registerBrowserAgentMcpTools(server2, opts) {
|
|
|
1322
1493
|
// bin/browser-agent-stdio-server.ts
|
|
1323
1494
|
function readApiKeyFile() {
|
|
1324
1495
|
const explicitPath = process.env.MCP_SCRAPER_KEY_PATH?.trim();
|
|
1325
|
-
const paths = [explicitPath, (0,
|
|
1496
|
+
const paths = [explicitPath, (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".mcp-scraper-key")].filter(Boolean);
|
|
1326
1497
|
for (const path of paths) {
|
|
1327
1498
|
try {
|
|
1328
|
-
const value = (0,
|
|
1499
|
+
const value = (0, import_node_fs3.readFileSync)(path, "utf8").trim();
|
|
1329
1500
|
if (value) return value;
|
|
1330
1501
|
} catch {
|
|
1331
1502
|
}
|