mcp-scraper 0.50.0 → 0.51.0
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 +11 -3
- package/dist/bin/api-server.cjs +268 -39
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +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-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 +112 -30
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/chunk-73MUQSWC.js +7 -0
- package/dist/chunk-73MUQSWC.js.map +1 -0
- package/dist/{chunk-44LNKZTE.js → chunk-O63VVCCE.js} +113 -31
- package/dist/chunk-O63VVCCE.js.map +1 -0
- package/dist/editorial-reading-room/assets/app.js +62 -0
- package/dist/editorial-reading-room/assets/index.html +8 -0
- package/dist/editorial-reading-room/assets/styles.css +39 -0
- package/dist/{server-3ND2EXYO.js → server-IGIIEHXY.js} +157 -10
- package/dist/{server-3ND2EXYO.js.map → server-IGIIEHXY.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-44LNKZTE.js.map +0 -1
- package/dist/chunk-C7NN57WH.js +0 -7
- package/dist/chunk-C7NN57WH.js.map +0 -1
package/dist/bin/api-server.cjs
CHANGED
|
@@ -17518,7 +17518,8 @@ ${t.topQuestions.map((q) => `- ${q}`).join("\n")}` : ""
|
|
|
17518
17518
|
${q.threadUrl}` : ""}`).join("\n");
|
|
17519
17519
|
const full = [
|
|
17520
17520
|
`# Reddit Trending: "${d.topic || input.topic}"${subreddit ? ` in r/${subreddit}` : ""}`,
|
|
17521
|
-
`**${totals.threads} threads \xB7 ${totals.upvotes} upvotes \xB7 ${totals.comments} comments** \xB7 last ${d.window === "7d" ? "week" : "month"} \xB7 ${d.threadsScraped ?? 0} of ${d.candidatesFound ?? threads.length} discovered scraped${d.partial ? " (partial
|
|
17521
|
+
`**${totals.threads} threads \xB7 ${totals.upvotes} upvotes \xB7 ${totals.comments} comments** \xB7 last ${d.window === "7d" ? "week" : "month"} \xB7 ${d.threadsScraped ?? 0} of ${d.candidatesFound ?? threads.length} discovered scraped${d.partial ? " (partial)" : ""}`,
|
|
17522
|
+
d.degradedResult ? `**Discovery degraded:** ${(d.degradationReasons ?? []).join(", ") || "no usable discovery surface"}${d.retryRecommended ? " \xB7 retry recommended" : ""}${d.billingRefunded ? " \xB7 discovery charge refunded" : ""}` : d.discoverySource === "reddit_search_fallback" ? "**Discovery fallback:** direct Reddit search was used after the primary SERP returned no usable threads." : "",
|
|
17522
17523
|
`
|
|
17523
17524
|
## Ranked threads
|
|
17524
17525
|
${threadBlocks || "_No threads found._"}`,
|
|
@@ -17550,7 +17551,13 @@ ${questionList || "_No questions extracted._"}`,
|
|
|
17550
17551
|
threadsScraped: Number(d.threadsScraped ?? 0),
|
|
17551
17552
|
candidatesFound: Number(d.candidatesFound ?? threads.length),
|
|
17552
17553
|
partial: Boolean(d.partial),
|
|
17553
|
-
searchQuery: d.searchQuery ?? ""
|
|
17554
|
+
searchQuery: d.searchQuery ?? "",
|
|
17555
|
+
discoverySource: d.discoverySource ?? "google_serp",
|
|
17556
|
+
resultQuality: d.resultQuality ?? "complete",
|
|
17557
|
+
degradedResult: Boolean(d.degradedResult),
|
|
17558
|
+
degradationReasons: d.degradationReasons ?? [],
|
|
17559
|
+
retryRecommended: Boolean(d.retryRecommended),
|
|
17560
|
+
billingRefunded: Boolean(d.billingRefunded)
|
|
17554
17561
|
}
|
|
17555
17562
|
};
|
|
17556
17563
|
}
|
|
@@ -33212,6 +33219,15 @@ var init_instagram_routes = __esm({
|
|
|
33212
33219
|
});
|
|
33213
33220
|
|
|
33214
33221
|
// src/api/reddit-trending.ts
|
|
33222
|
+
function buildRedditSearchUrl(topic, subreddit, window2 = "month") {
|
|
33223
|
+
const base = subreddit ? `https://old.reddit.com/r/${encodeURIComponent(subreddit)}/search` : "https://old.reddit.com/search";
|
|
33224
|
+
const params = new URLSearchParams();
|
|
33225
|
+
params.set("q", topic);
|
|
33226
|
+
params.set("sort", "top");
|
|
33227
|
+
params.set("t", window2);
|
|
33228
|
+
if (subreddit) params.set("restrict_sr", "on");
|
|
33229
|
+
return `${base}?${params.toString()}`;
|
|
33230
|
+
}
|
|
33215
33231
|
function buildSerpQuery(topic, subreddit) {
|
|
33216
33232
|
const scope = subreddit ? `site:reddit.com/r/${subreddit}` : "site:reddit.com";
|
|
33217
33233
|
return `${scope} ${topic}`.trim();
|
|
@@ -33274,6 +33290,32 @@ function canonicalThreadUrl(href) {
|
|
|
33274
33290
|
function engagementScore(score, commentCount) {
|
|
33275
33291
|
return score + 2 * commentCount;
|
|
33276
33292
|
}
|
|
33293
|
+
function normalizeSearchRows(rows) {
|
|
33294
|
+
if (!Array.isArray(rows)) return [];
|
|
33295
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33296
|
+
const out = [];
|
|
33297
|
+
for (const raw of rows) {
|
|
33298
|
+
if (!raw || typeof raw !== "object") continue;
|
|
33299
|
+
const r = raw;
|
|
33300
|
+
const url = canonicalThreadUrl(r.url);
|
|
33301
|
+
const title = typeof r.title === "string" ? r.title.trim() : "";
|
|
33302
|
+
if (!url || !title || seen.has(url)) continue;
|
|
33303
|
+
seen.add(url);
|
|
33304
|
+
const score = parseCountText(r.scoreText);
|
|
33305
|
+
const commentCount = parseCountText(r.commentsText);
|
|
33306
|
+
out.push({
|
|
33307
|
+
title,
|
|
33308
|
+
url,
|
|
33309
|
+
subreddit: typeof r.subreddit === "string" ? r.subreddit.trim() : "",
|
|
33310
|
+
score,
|
|
33311
|
+
commentCount,
|
|
33312
|
+
engagementScore: engagementScore(score, commentCount),
|
|
33313
|
+
ageText: typeof r.ageText === "string" ? r.ageText.trim() : "",
|
|
33314
|
+
topQuestions: []
|
|
33315
|
+
});
|
|
33316
|
+
}
|
|
33317
|
+
return out;
|
|
33318
|
+
}
|
|
33277
33319
|
function normalizeQuestionKey(s) {
|
|
33278
33320
|
return s.toLowerCase().replace(/[?.!\s]+$/g, "").replace(/\s+/g, " ").trim();
|
|
33279
33321
|
}
|
|
@@ -33324,10 +33366,29 @@ function flattenQuestions(threads) {
|
|
|
33324
33366
|
}
|
|
33325
33367
|
return out;
|
|
33326
33368
|
}
|
|
33327
|
-
var INTERROGATIVE_STARTERS;
|
|
33369
|
+
var PARSE_REDDIT_SEARCH, INTERROGATIVE_STARTERS;
|
|
33328
33370
|
var init_reddit_trending = __esm({
|
|
33329
33371
|
"src/api/reddit-trending.ts"() {
|
|
33330
33372
|
"use strict";
|
|
33373
|
+
PARSE_REDDIT_SEARCH = `(() => {
|
|
33374
|
+
const txt = el => ((el && el.innerText) || '').trim();
|
|
33375
|
+
const bodyText = (document.body && document.body.innerText) || '';
|
|
33376
|
+
const blocked = /whoa there|blocked by network|you've been blocked|network (policy|security)|log in to your reddit account/i.test(bodyText);
|
|
33377
|
+
const listing = document.querySelector('.search-result-listing');
|
|
33378
|
+
const rows = [];
|
|
33379
|
+
document.querySelectorAll('.search-result.search-result-link').forEach(r => {
|
|
33380
|
+
const titleEl = r.querySelector('header.search-result-header a.search-title');
|
|
33381
|
+
rows.push({
|
|
33382
|
+
title: txt(titleEl),
|
|
33383
|
+
url: (titleEl && titleEl.getAttribute('href')) || '',
|
|
33384
|
+
subreddit: txt(r.querySelector('a.search-subreddit-link')),
|
|
33385
|
+
scoreText: txt(r.querySelector('.search-score')),
|
|
33386
|
+
commentsText: txt(r.querySelector('a.search-comments')),
|
|
33387
|
+
ageText: txt(r.querySelector('.search-time time')),
|
|
33388
|
+
});
|
|
33389
|
+
});
|
|
33390
|
+
return { blocked: blocked, listingFound: Boolean(listing), rowCount: rows.length, rows: rows };
|
|
33391
|
+
})()`;
|
|
33331
33392
|
INTERROGATIVE_STARTERS = /* @__PURE__ */ new Set([
|
|
33332
33393
|
"what",
|
|
33333
33394
|
"whats",
|
|
@@ -35525,8 +35586,8 @@ async function residentialProxyId(attemptIndex) {
|
|
|
35525
35586
|
return void 0;
|
|
35526
35587
|
}
|
|
35527
35588
|
}
|
|
35528
|
-
async function scrapeOldRedditWithRetries(url, script, accept) {
|
|
35529
|
-
for (let attempt = 0; attempt <
|
|
35589
|
+
async function scrapeOldRedditWithRetries(url, script, accept, maxAttempts = 4) {
|
|
35590
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
35530
35591
|
const backupAttempt = attempt === 3;
|
|
35531
35592
|
if (backupAttempt && !backupProxyAvailable()) break;
|
|
35532
35593
|
const proxyId = backupAttempt ? await createBackupProxyIdSafe(browserServiceApiKey(), attempt) : await residentialProxyId(attempt);
|
|
@@ -35695,6 +35756,9 @@ var init_reddit_routes = __esm({
|
|
|
35695
35756
|
if (!ok) return c.json(insufficientBalanceResponse(balance_mc, MC_COSTS.reddit_thread), 402);
|
|
35696
35757
|
discoveryDebited = true;
|
|
35697
35758
|
let candidates = [];
|
|
35759
|
+
let discoverySource = "google_serp";
|
|
35760
|
+
let primaryDiscoveryDegraded = false;
|
|
35761
|
+
let primaryDegradationReasons = [];
|
|
35698
35762
|
try {
|
|
35699
35763
|
const serp = await harvest({
|
|
35700
35764
|
query: serpQuery,
|
|
@@ -35708,14 +35772,59 @@ var init_reddit_routes = __esm({
|
|
|
35708
35772
|
softDeadlineMs
|
|
35709
35773
|
});
|
|
35710
35774
|
candidates = extractRedditThreadUrls(serp.organicResults, body.maxThreads);
|
|
35775
|
+
primaryDiscoveryDegraded = serp.diagnostics?.degradedResult === true;
|
|
35776
|
+
primaryDegradationReasons = Array.isArray(serp.diagnostics?.degradationReasons) ? serp.diagnostics.degradationReasons.filter((reason) => typeof reason === "string") : [];
|
|
35711
35777
|
} catch {
|
|
35712
35778
|
candidates = [];
|
|
35779
|
+
primaryDiscoveryDegraded = true;
|
|
35780
|
+
primaryDegradationReasons = ["primary_serp_failed"];
|
|
35781
|
+
}
|
|
35782
|
+
if (candidates.length === 0) {
|
|
35783
|
+
const fallback = await scrapeOldRedditWithRetries(
|
|
35784
|
+
buildRedditSearchUrl(body.topic, subreddit, body.window),
|
|
35785
|
+
PARSE_REDDIT_SEARCH,
|
|
35786
|
+
(data) => !data.blocked && data.listingFound,
|
|
35787
|
+
2
|
|
35788
|
+
);
|
|
35789
|
+
if (fallback) {
|
|
35790
|
+
candidates = normalizeSearchRows(fallback.data.rows).slice(0, body.maxThreads).map((thread) => ({ title: thread.title, url: thread.url, subreddit: thread.subreddit.replace(/^r\//i, "") }));
|
|
35791
|
+
discoverySource = "reddit_search_fallback";
|
|
35792
|
+
} else {
|
|
35793
|
+
discoverySource = "none";
|
|
35794
|
+
}
|
|
35713
35795
|
}
|
|
35714
35796
|
if (candidates.length === 0) {
|
|
35715
35797
|
await creditMc(user.id, MC_COSTS.reddit_thread, LedgerOperation.REDDIT_THREAD_REFUND, "no reddit threads discovered");
|
|
35716
35798
|
discoveryRefunded = true;
|
|
35717
|
-
|
|
35718
|
-
|
|
35799
|
+
const degradedResult = discoverySource === "none";
|
|
35800
|
+
const degradationReasons = degradedResult ? [.../* @__PURE__ */ new Set([...primaryDegradationReasons, "reddit_fallback_empty_or_blocked"])] : [];
|
|
35801
|
+
const result2 = {
|
|
35802
|
+
topic: body.topic,
|
|
35803
|
+
subreddit: subreddit ?? null,
|
|
35804
|
+
window: body.window === "week" ? "7d" : "30d",
|
|
35805
|
+
totals: trendingTotals([]),
|
|
35806
|
+
rankedThreads: [],
|
|
35807
|
+
questions: [],
|
|
35808
|
+
threadsScraped: 0,
|
|
35809
|
+
candidatesFound: 0,
|
|
35810
|
+
partial: false,
|
|
35811
|
+
searchQuery: serpQuery,
|
|
35812
|
+
discoverySource,
|
|
35813
|
+
resultQuality: degradedResult ? "degraded" : "complete",
|
|
35814
|
+
degradedResult,
|
|
35815
|
+
degradationReasons,
|
|
35816
|
+
retryRecommended: degradedResult,
|
|
35817
|
+
billingRefunded: true
|
|
35818
|
+
};
|
|
35819
|
+
await logRequestEvent({
|
|
35820
|
+
userId: user.id,
|
|
35821
|
+
source: "reddit_trending",
|
|
35822
|
+
status: "done",
|
|
35823
|
+
query: body.topic,
|
|
35824
|
+
resultCount: 0,
|
|
35825
|
+
result: result2
|
|
35826
|
+
});
|
|
35827
|
+
return c.json(result2);
|
|
35719
35828
|
}
|
|
35720
35829
|
let ranked;
|
|
35721
35830
|
if (!body.includeComments) {
|
|
@@ -35791,7 +35900,13 @@ var init_reddit_routes = __esm({
|
|
|
35791
35900
|
threadsScraped: body.includeComments ? ranked.length : 0,
|
|
35792
35901
|
candidatesFound: candidates.length,
|
|
35793
35902
|
partial: body.includeComments && ranked.length < candidates.length,
|
|
35794
|
-
searchQuery: serpQuery
|
|
35903
|
+
searchQuery: serpQuery,
|
|
35904
|
+
discoverySource,
|
|
35905
|
+
resultQuality: primaryDiscoveryDegraded ? "partial" : "complete",
|
|
35906
|
+
degradedResult: false,
|
|
35907
|
+
degradationReasons: primaryDiscoveryDegraded ? primaryDegradationReasons : [],
|
|
35908
|
+
retryRecommended: false,
|
|
35909
|
+
billingRefunded: false
|
|
35795
35910
|
};
|
|
35796
35911
|
await logRequestEvent({ userId: user.id, source: "reddit_trending", status: "done", query: body.topic, resultCount: ranked.length, result });
|
|
35797
35912
|
return c.json(result);
|
|
@@ -41480,7 +41595,7 @@ var PACKAGE_VERSION;
|
|
|
41480
41595
|
var init_version = __esm({
|
|
41481
41596
|
"src/version.ts"() {
|
|
41482
41597
|
"use strict";
|
|
41483
|
-
PACKAGE_VERSION = "0.
|
|
41598
|
+
PACKAGE_VERSION = "0.51.0";
|
|
41484
41599
|
}
|
|
41485
41600
|
});
|
|
41486
41601
|
|
|
@@ -41629,7 +41744,10 @@ seam is noted so you can chain them.
|
|
|
41629
41744
|
handles Reddit's bot wall itself (no login needed). Find threads first with \`search_serp\` or \`reddit_trending\`.
|
|
41630
41745
|
- DISCOVER what a niche is talking about (topic, no known thread) -> **reddit_trending** (takes a topic, optional
|
|
41631
41746
|
subreddit; returns the last 30 days' top threads ranked by engagement plus the questions people asked \u2014
|
|
41632
|
-
feed winning \`rankedThreads[].url\` values into \`reddit_thread\` for the full comment tree).
|
|
41747
|
+
feed winning \`rankedThreads[].url\` values into \`reddit_thread\` for the full comment tree). It uses bounded
|
|
41748
|
+
direct Reddit discovery when the primary SERP is empty. Before interpreting an empty result, inspect
|
|
41749
|
+
\`resultQuality\`, \`discoverySource\`, \`degradationReasons\`, \`retryRecommended\`, and \`billingRefunded\`;
|
|
41750
|
+
a degraded empty result is not evidence that the topic has no Reddit discussion.
|
|
41633
41751
|
|
|
41634
41752
|
## Other sites & logins (browser agent)
|
|
41635
41753
|
For an arbitrary site or a logged-in dashboard with no dedicated tool, use the browser_* agent. **First
|
|
@@ -41679,6 +41797,12 @@ Multi-step orchestrations \u2014 prefer these over hand-chaining primitives when
|
|
|
41679
41797
|
versioning reusable website templates; use the saved-template tools above for those jobs.
|
|
41680
41798
|
- The creation tool is a renderer, not a research or writing model. Preserve source truth in each
|
|
41681
41799
|
\`sourceLabel\`; do not hand it raw source material and expect it to invent the editorial architecture.
|
|
41800
|
+
- One edition may contain up to 100 articles. Images may appear as structured article/card heroes or as
|
|
41801
|
+
Markdown body images. Use \`site.ogImage\` for the collection social preview and \`article.ogImage\` for an
|
|
41802
|
+
article override; otherwise the article hero, then collection image, is reused. Every image requires useful
|
|
41803
|
+
alt text. Preserve caption, credit, source URL, and rights context when known; a reachable URL does not prove
|
|
41804
|
+
reuse rights. Static artifacts include collection OG tags and update article tags in-browser, while crawler-
|
|
41805
|
+
perfect per-article unfurls require the publishing host to serve article-specific metadata.
|
|
41682
41806
|
- ${savesReportsLocally ? "This local stdio server writes one self-contained HTML file and returns its localPath so the user can open it." : "This hosted server creates a private seven-day HTML artifact and returns a signed download URL; use renew_editorial_reading_room_download after the URL expires."}
|
|
41683
41807
|
|
|
41684
41808
|
## Local Sourcebook listings
|
|
@@ -41770,6 +41894,17 @@ deliberate edits and migrations. Use
|
|
|
41770
41894
|
they'll filter/sort by exact value. **memory-search** is meaning-based over full content (embeds, slower);
|
|
41771
41895
|
**memory-list** filters one vault by kind/tags (fast, exact).
|
|
41772
41896
|
|
|
41897
|
+
Choose the read surface by completeness, not convenience. **list-vaults** is the account inventory and
|
|
41898
|
+
reports each vault's note count. **memory-list** returns the complete metadata inventory for one vault but
|
|
41899
|
+
no note bodies, plus a sorted complete folder inventory derived from those paths; use it to identify every
|
|
41900
|
+
stable \`vault + path\` address. **list-memory-tags** returns the
|
|
41901
|
+
complete account-wide canonical tag inventory, including aliases, usage counts, and per-vault distribution.
|
|
41902
|
+
**memory-search** returns ranked
|
|
41903
|
+
content chunks, not an exhaustive inventory or complete documents: deduplicate hits by vault/path and call
|
|
41904
|
+
**memory-get** for every note whose full meaning matters. When the user explicitly needs every full note for
|
|
41905
|
+
backup, migration, or corpus-wide audit, use **memory-export** one vault at a time; do not pull the entire
|
|
41906
|
+
corpus merely to edit one note.
|
|
41907
|
+
|
|
41773
41908
|
For People, Deals, Projects, Tasks, and Communications, use the returned contract rather than guessing:
|
|
41774
41909
|
People only holds a real person or organization hub. Its contact card uses \`phone\`, \`text_phone\`, and
|
|
41775
41910
|
\`email\` for Call/Text/Email; \`memories\` for durable person context; and linked Deals, Projects,
|
|
@@ -41828,19 +41963,35 @@ Tags are live vocabulary, not improvised labels: **list-memory-tags** shows what
|
|
|
41828
41963
|
reusable, and has no exact, alias, or near-equivalent. Use **memory-backlinks**,
|
|
41829
41964
|
**memory-graph-universe**, and **memory-graph-path** to trace the linked universe across vaults.
|
|
41830
41965
|
|
|
41831
|
-
**Always inspect the complete tag inventory and related notes first.**
|
|
41966
|
+
**Always inspect the complete tag inventory and related notes first.** When the user wants to find, recall,
|
|
41967
|
+
understand, or connect something and does not already provide an exact vault/path, start with hybrid Smart
|
|
41968
|
+
RAG through **memory-search**. The exceptions are exhaustive inventory (**memory-list**), title-only lookup
|
|
41969
|
+
(**memory-suggest**), an exact known note (**memory-get**), and an explicit full-vault export (**memory-export**).
|
|
41970
|
+
For hybrid retrieval,
|
|
41832
41971
|
form 3 focused queries (2\u20134 when useful), fuse exact tag/metadata/vault/date and semantic matches into 50
|
|
41833
41972
|
candidates, expand the top 8 seeds by one link/backlink hop with at most 5 neighbors each, then Jina-rerank
|
|
41834
41973
|
the combined pool to the best 30. Graph neighbors are candidates, never automatic links; add only links
|
|
41835
|
-
supported by the note contents.
|
|
41974
|
+
supported by the note contents. A search hit is a discovery excerpt, not the note: call **memory-get** and read
|
|
41975
|
+
the complete note before relying on it for an answer, summary, edit, relationship, or durable write. Read the
|
|
41976
|
+
strong candidates, not every low-ranked hit.
|
|
41836
41977
|
|
|
41837
41978
|
Scrape deposits are raw evidence and therefore go to **Library** through **library-ingest**, with the full
|
|
41838
41979
|
Library template and source metadata. If the source contains durable applicable guidance, create a separate
|
|
41839
41980
|
Knowledge companion through prepare-memory-write + memory-capture and link it to the Library source with
|
|
41840
41981
|
derived_from; do not replace the raw source with the guide.
|
|
41841
41982
|
|
|
41842
|
-
For an update, call **memory-get** first and pass
|
|
41843
|
-
|
|
41983
|
+
For an update, identify the existing note by its stable \`vault + path\`, call **memory-get** first, and pass
|
|
41984
|
+
its revision as \`baseRevision\`. **memory-put replaces the entire content body; it is not a text patch.**
|
|
41985
|
+
Merge the requested change into the full body returned by memory-get, then send that complete merged body.
|
|
41986
|
+
Its supplied \`props\` patch existing metadata, so omit unchanged props and use an empty array only when the
|
|
41987
|
+
user deliberately wants to clear a link list. Preserve the existing title, source, capture time, surrounding
|
|
41988
|
+
content, links, template sections, and unsupported uncertainty unless the request deliberately changes them.
|
|
41989
|
+
A title change does not create a new note identity; keep the path unless the user explicitly asks to move it.
|
|
41990
|
+
Never convert an edit into a new path just because search returned a similar title. If \`baseRevision\`
|
|
41991
|
+
conflicts, reconcile the returned current body with the requested change and retry against the new revision;
|
|
41992
|
+
do not resend the stale full body unchanged. Treat Agent Inbox, optimizer rollups, channel messages, and other
|
|
41993
|
+
system-managed notes through their purpose-built tools when available rather than rewriting their backing
|
|
41994
|
+
notes with memory-put.
|
|
41844
41995
|
If a legacy backend does not return props, do not overwrite an existing linked note through that surface;
|
|
41845
41996
|
report that link preservation cannot be proved. After the write, read it back and search a distinctive
|
|
41846
41997
|
phrase to verify persistence and indexing.
|
|
@@ -42676,7 +42827,7 @@ var init_contracts = __esm({
|
|
|
42676
42827
|
});
|
|
42677
42828
|
|
|
42678
42829
|
// src/mcp/mcp-tool-schemas.ts
|
|
42679
|
-
var import_zod42, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
42830
|
+
var import_zod42, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
42680
42831
|
var init_mcp_tool_schemas = __esm({
|
|
42681
42832
|
"src/mcp/mcp-tool-schemas.ts"() {
|
|
42682
42833
|
"use strict";
|
|
@@ -43257,7 +43408,22 @@ var init_mcp_tool_schemas = __esm({
|
|
|
43257
43408
|
issueLabel: import_zod42.z.string().trim().min(1).max(100).default("Current edition").describe("Issue, date, or collection label in the home-page issue line."),
|
|
43258
43409
|
eyebrow: import_zod42.z.string().trim().min(1).max(120).default("A guided collection").describe("Short editorial eyebrow above the home-page headline."),
|
|
43259
43410
|
heroTitle: import_zod42.z.string().trim().min(1).max(180).describe("Outcome-led home-page headline for the whole reading room."),
|
|
43260
|
-
startLabel: import_zod42.z.string().trim().min(1).max(60).default("Start reading").describe("Label for the primary start-reading button.")
|
|
43411
|
+
startLabel: import_zod42.z.string().trim().min(1).max(60).default("Start reading").describe("Label for the primary start-reading button."),
|
|
43412
|
+
ogImage: import_zod42.z.object({
|
|
43413
|
+
url: import_zod42.z.string().url().refine((value) => /^https?:\/\//i.test(value), "Image URL must use HTTP or HTTPS.").describe("Public HTTP(S) image URL used for the reading-room home page social preview."),
|
|
43414
|
+
alt: import_zod42.z.string().trim().min(1).max(500).describe("Accessible description and og:image:alt text."),
|
|
43415
|
+
width: import_zod42.z.number().int().positive().optional().describe("Optional intrinsic width in pixels."),
|
|
43416
|
+
height: import_zod42.z.number().int().positive().optional().describe("Optional intrinsic height in pixels.")
|
|
43417
|
+
}).strict().optional().describe("Optional collection-level Open Graph image. Individual articles may override it.")
|
|
43418
|
+
}).strict();
|
|
43419
|
+
EditorialReadingRoomImageSchema = import_zod42.z.object({
|
|
43420
|
+
url: import_zod42.z.string().url().refine((value) => /^https?:\/\//i.test(value), "Image URL must use HTTP or HTTPS.").describe("Public HTTP(S) image URL."),
|
|
43421
|
+
alt: import_zod42.z.string().trim().min(1).max(500).describe("Required accessible description of the image."),
|
|
43422
|
+
caption: import_zod42.z.string().trim().max(1e3).optional().describe("Optional visible caption."),
|
|
43423
|
+
credit: import_zod42.z.string().trim().max(500).optional().describe("Optional visible creator, publisher, or rights credit."),
|
|
43424
|
+
sourceUrl: import_zod42.z.string().url().refine((value) => /^https?:\/\//i.test(value), "Source URL must use HTTP or HTTPS.").optional().describe("Optional public HTTP(S) source page for provenance or rights context."),
|
|
43425
|
+
width: import_zod42.z.number().int().positive().optional().describe("Optional intrinsic width in pixels."),
|
|
43426
|
+
height: import_zod42.z.number().int().positive().optional().describe("Optional intrinsic height in pixels.")
|
|
43261
43427
|
}).strict();
|
|
43262
43428
|
EditorialReadingRoomArticleSchema = import_zod42.z.object({
|
|
43263
43429
|
slug: import_zod42.z.string().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(80).describe("Unique kebab-case article identifier."),
|
|
@@ -43270,7 +43436,9 @@ var init_mcp_tool_schemas = __esm({
|
|
|
43270
43436
|
sourceLabel: import_zod42.z.string().trim().min(1).max(500).describe("Visible provenance label naming the material this article was derived from. Do not invent a source."),
|
|
43271
43437
|
revision: import_zod42.z.string().trim().min(1).max(80).optional().describe("Optional revision identifier or version label."),
|
|
43272
43438
|
updatedAt: import_zod42.z.string().trim().min(1).max(80).optional().describe("Optional human-readable source update date."),
|
|
43273
|
-
|
|
43439
|
+
image: EditorialReadingRoomImageSchema.optional().describe("Optional article image shown on cards and above the article body. Markdown images remain supported inside the body."),
|
|
43440
|
+
ogImage: EditorialReadingRoomImageSchema.optional().describe("Optional article-specific social preview image. Defaults to article.image, then site.ogImage."),
|
|
43441
|
+
markdown: import_zod42.z.string().min(1).max(1e5).describe("Complete article body in Markdown. Standard Markdown images are allowed with descriptive alt text. Use H2/H3 headings for jump links, short paragraphs, concrete examples, and tables only where they improve comparison.")
|
|
43274
43442
|
}).strict();
|
|
43275
43443
|
EditorialReadingRoomGuideInputSchema = {
|
|
43276
43444
|
focus: import_zod42.z.enum(["workflow", "content_contract", "example"]).default("workflow").describe("Which part of the reusable editorial-reading-room guide to return. Start with workflow; fetch the content contract or compact example only when needed.")
|
|
@@ -43283,7 +43451,7 @@ var init_mcp_tool_schemas = __esm({
|
|
|
43283
43451
|
CreateEditorialReadingRoomInputSchema = {
|
|
43284
43452
|
site: EditorialReadingRoomSiteSchema,
|
|
43285
43453
|
deck: import_zod42.z.string().trim().min(1).max(1e3).describe("Two or three sentences that explain the collection\u2019s value and scope without generic marketing language."),
|
|
43286
|
-
articles: import_zod42.z.array(EditorialReadingRoomArticleSchema).min(1).max(
|
|
43454
|
+
articles: import_zod42.z.array(EditorialReadingRoomArticleSchema).min(1).max(100).describe("One to one hundred fully authored articles, with no more than 2,000,000 Markdown bytes combined. Articles may include structured card/hero images, article-specific Open Graph images, and Markdown body images. Read all in-scope source material before composing them; preserve distinctions, uncertainty, image provenance, and rights context instead of flattening the corpus."),
|
|
43287
43455
|
filename: import_zod42.z.string().trim().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/).max(120).optional().describe("Optional download filename. The server always normalizes it to a safe .html filename.")
|
|
43288
43456
|
};
|
|
43289
43457
|
EditorialReadingRoomArtifactSchema = import_zod42.z.object({
|
|
@@ -44110,7 +44278,13 @@ var init_mcp_tool_schemas = __esm({
|
|
|
44110
44278
|
threadsScraped: import_zod42.z.number().int().min(0),
|
|
44111
44279
|
candidatesFound: import_zod42.z.number().int().min(0),
|
|
44112
44280
|
partial: import_zod42.z.boolean(),
|
|
44113
|
-
searchQuery: import_zod42.z.string()
|
|
44281
|
+
searchQuery: import_zod42.z.string(),
|
|
44282
|
+
discoverySource: import_zod42.z.enum(["google_serp", "reddit_search_fallback", "none"]),
|
|
44283
|
+
resultQuality: import_zod42.z.enum(["complete", "partial", "degraded"]),
|
|
44284
|
+
degradedResult: import_zod42.z.boolean(),
|
|
44285
|
+
degradationReasons: import_zod42.z.array(import_zod42.z.string()),
|
|
44286
|
+
retryRecommended: import_zod42.z.boolean(),
|
|
44287
|
+
billingRefunded: import_zod42.z.boolean()
|
|
44114
44288
|
};
|
|
44115
44289
|
FacebookPageIntelOutputSchema = {
|
|
44116
44290
|
advertiserName: NullableString,
|
|
@@ -45293,10 +45467,11 @@ var init_guide = __esm({
|
|
|
45293
45467
|
2. Read every in-scope source before designing the page. Build a source inventory with purpose, authority, overlap, and provenance.
|
|
45294
45468
|
3. Architect the corpus into a small editorial edition. Prefer one article per real question, decision, lesson, or reusable pattern. Merge duplicate material; preserve meaningful distinctions and uncertainty.
|
|
45295
45469
|
4. Write the collection-level promise: a specific hero title and deck that explain what the reader will understand or be able to do.
|
|
45296
|
-
5. Author complete articles in Markdown. Use H2/H3 headings as a useful table of contents, short paragraphs, concrete examples, and tables only when they materially improve comparison.
|
|
45297
|
-
6.
|
|
45298
|
-
7.
|
|
45299
|
-
8.
|
|
45470
|
+
5. Author complete articles in Markdown. Use H2/H3 headings as a useful table of contents, short paragraphs, concrete examples, and tables only when they materially improve comparison. Markdown images are supported inside the body.
|
|
45471
|
+
6. Choose images only when they help the reader identify, understand, compare, or remember the material. Use article.image for the card/article hero, article.ogImage for a distinct social preview, and site.ogImage for the collection default. Every image needs descriptive alt text; preserve caption, credit, source URL, and rights context when known. Never invent attribution or imply usage rights.
|
|
45472
|
+
7. Preserve provenance in sourceLabel. Never invent a source, fact, result, quote, or certainty that the source material does not support.
|
|
45473
|
+
8. Call create_editorial_reading_room with the finished site metadata, deck, and ordered articles. Do not ask the renderer to discover, research, or write the content for you.
|
|
45474
|
+
9. Inspect the returned page at both mobile and desktop sizes. Verify navigation, jump links, article order, images, alt text, typography, overflow, source labels, social metadata, and that the page opens without a build step.
|
|
45300
45475
|
|
|
45301
45476
|
The renderer owns the reusable New York Times-inspired reading surface, responsive hamburger navigation, search, article jump links, progress, text-size controls, evening mode, and portable single-file HTML delivery.`;
|
|
45302
45477
|
CONTENT_CONTRACT = `Editorial reading-room content contract
|
|
@@ -45309,13 +45484,16 @@ The renderer owns the reusable New York Times-inspired reading surface, responsi
|
|
|
45309
45484
|
- site.eyebrow: collection framing, not a duplicate headline.
|
|
45310
45485
|
- site.heroTitle: specific outcome or understanding promised by the collection.
|
|
45311
45486
|
- site.startLabel: concise reading CTA.
|
|
45487
|
+
- site.ogImage: optional collection-level Open Graph image with required alt text.
|
|
45312
45488
|
- deck: two or three concrete sentences covering value and scope.
|
|
45313
|
-
- articles: 1-
|
|
45489
|
+
- articles: 1-100 complete editorial pieces, each with a unique slug and order.
|
|
45314
45490
|
- article.category: a repeated grouping label when multiple pieces belong together.
|
|
45315
45491
|
- article.kicker: short framing line.
|
|
45316
45492
|
- article.title: the question, decision, lesson, or reusable pattern.
|
|
45317
45493
|
- article.summary: what the reader will understand.
|
|
45318
45494
|
- article.sourceLabel: visible, truthful provenance.
|
|
45495
|
+
- article.image: optional card/article hero image with alt text and optional caption, credit, source URL, and dimensions.
|
|
45496
|
+
- article.ogImage: optional article-specific social image; otherwise article.image, then site.ogImage is used.
|
|
45319
45497
|
- article.markdown: full body with useful H2/H3 headings.
|
|
45320
45498
|
|
|
45321
45499
|
Quality gates:
|
|
@@ -45324,6 +45502,7 @@ Quality gates:
|
|
|
45324
45502
|
- Do not use placeholder copy.
|
|
45325
45503
|
- Keep headings descriptive enough to work as jump links.
|
|
45326
45504
|
- Prefer a coherent reading sequence over source-file order.
|
|
45505
|
+
- Use only public HTTP(S) image URLs. Preserve provenance and rights context; an available URL is not proof of reuse rights.
|
|
45327
45506
|
- If the corpus is too thin for multiple articles, create one strong article instead of padding the edition.`;
|
|
45328
45507
|
EXAMPLE = `Compact example:
|
|
45329
45508
|
|
|
@@ -45337,7 +45516,11 @@ Quality gates:
|
|
|
45337
45516
|
"issueLabel": "Pattern library",
|
|
45338
45517
|
"eyebrow": "A practical field guide",
|
|
45339
45518
|
"heroTitle": "Make every saved note easier to find and reuse",
|
|
45340
|
-
"startLabel": "Begin with the pattern"
|
|
45519
|
+
"startLabel": "Begin with the pattern",
|
|
45520
|
+
"ogImage": {
|
|
45521
|
+
"url": "https://example.com/reading-room-social.jpg",
|
|
45522
|
+
"alt": "Connected notes arranged as a navigable editorial collection"
|
|
45523
|
+
}
|
|
45341
45524
|
},
|
|
45342
45525
|
"deck": "A concise guide to placing new material in the right vault, connecting it to natural neighbors, and preserving source evidence without turning memory into a generic notes bucket.",
|
|
45343
45526
|
"articles": [{
|
|
@@ -45349,6 +45532,12 @@ Quality gates:
|
|
|
45349
45532
|
"summary": "A useful note is not only stored; it is classified, connected, and made retrievable.",
|
|
45350
45533
|
"sourceType": "Workflow synthesis",
|
|
45351
45534
|
"sourceLabel": "Derived from the MCP Memory capture contract supplied by the user.",
|
|
45535
|
+
"image": {
|
|
45536
|
+
"url": "https://example.com/graph-operation.jpg",
|
|
45537
|
+
"alt": "A source note connected to related project and knowledge notes",
|
|
45538
|
+
"caption": "Useful captures become connected retrieval objects.",
|
|
45539
|
+
"sourceUrl": "https://example.com/source"
|
|
45540
|
+
},
|
|
45352
45541
|
"markdown": "## Start with the destination\\n\\nChoose the vault whose job matches the material...\\n\\n## Connect natural neighbors\\n\\nLink only relationships supported by the notes..."
|
|
45353
45542
|
}]
|
|
45354
45543
|
}`;
|
|
@@ -46240,7 +46429,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
46240
46429
|
}, async (input) => formatRedditThread(await executor.redditThread(input), input));
|
|
46241
46430
|
server.registerTool("reddit_trending", {
|
|
46242
46431
|
title: "Reddit Trending",
|
|
46243
|
-
description: "Discover
|
|
46432
|
+
description: "Discover top Reddit conversations from the last week or month. It tries Google site:reddit.com discovery, falls back to a bounded direct Reddit search when that SERP is empty or unavailable, then optionally scrapes threads for real upvotes, comments, questions, and engagement ranking. Inspect resultQuality, discoverySource, degradationReasons, retryRecommended, and billingRefunded before treating an empty result as a genuine lack of discussion. Set includeComments:false for a cheap discovery-only sweep; use reddit_thread for one known URL.",
|
|
46244
46433
|
inputSchema: RedditTrendingInputSchema,
|
|
46245
46434
|
outputSchema: recordOutputSchema("reddit_trending", RedditTrendingOutputSchema),
|
|
46246
46435
|
annotations: liveWebToolAnnotations("Reddit Trending")
|
|
@@ -46479,7 +46668,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
46479
46668
|
}, async (input) => executor.commonsPreparePublication(input));
|
|
46480
46669
|
server.registerTool("commons_validate_publication", {
|
|
46481
46670
|
title: "Validate Transparent Commons Publication",
|
|
46482
|
-
description: "Validate a publication name claim or a complete source-grounded editorial edition without writing.
|
|
46671
|
+
description: "Validate a publication name claim or a complete source-grounded editorial edition without writing. Publish validation accepts up to 100 articles plus structured article/card images, Markdown body images, and collection/article Open Graph images under the editorial reading-room contract. Use operation claim before commons_claim_publication and operation publish before commons_publish_editorial; ownership and revision conflicts are checked.",
|
|
46483
46672
|
inputSchema: CommonsValidatePublicationInputSchema,
|
|
46484
46673
|
outputSchema: recordOutputSchema("commons_validate_publication", CommonsGenericOutputSchema),
|
|
46485
46674
|
annotations: { title: "Validate Transparent Commons Publication", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
@@ -46493,7 +46682,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
46493
46682
|
}, async (input) => executor.commonsClaimPublication(input));
|
|
46494
46683
|
server.registerTool("commons_publish_editorial", {
|
|
46495
46684
|
title: "Publish Transparent Commons Editorial Edition",
|
|
46496
|
-
description: "Publish
|
|
46685
|
+
description: "Publish up to 100 fully authored editorial pieces, including optional article/card images, Markdown body images, and collection/article Open Graph images, to the caller-owned Transparent Commons subdomain. The calling AI must research and author the source-grounded edition first; image URLs need alt text and preserved provenance/rights context. The tool validates, renders, persists, and returns permanent root, archive, and edition URLs. Existing editions require current baseRevision. Requires idempotencyKey; this is not the neutral wiki write tool.",
|
|
46497
46686
|
inputSchema: CommonsPublishEditorialInputSchema,
|
|
46498
46687
|
outputSchema: recordOutputSchema("commons_publish_editorial", CommonsGenericOutputSchema),
|
|
46499
46688
|
annotations: { title: "Publish Transparent Commons Editorial Edition", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
@@ -46630,7 +46819,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
46630
46819
|
}, async (input) => formatWorkflowArtifactRead(await executor.workflowArtifactRead(input), input));
|
|
46631
46820
|
server.registerTool("editorial_reading_room_guide", {
|
|
46632
46821
|
title: "Editorial Reading Room Guide",
|
|
46633
|
-
description: 'Read the reusable composition contract before creating an editorial reading room. It
|
|
46822
|
+
description: 'Read the reusable composition contract before creating an editorial reading room. It covers corpus inventory, source truth, coherent architecture, up to 100 articles, purposeful images, image provenance, collection/article Open Graph images, and finished-page verification. Start with focus "workflow"; fetch "content_contract" or "example" only when needed. This does not research, write, or create a page.',
|
|
46634
46823
|
inputSchema: EditorialReadingRoomGuideInputSchema,
|
|
46635
46824
|
outputSchema: recordOutputSchema("editorial_reading_room_guide", EditorialReadingRoomGuideOutputSchema),
|
|
46636
46825
|
annotations: localPlanningToolAnnotations("Editorial Reading Room Guide")
|
|
@@ -46646,7 +46835,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
46646
46835
|
}));
|
|
46647
46836
|
server.registerTool("create_editorial_reading_room", {
|
|
46648
46837
|
title: "Create Editorial Reading Room",
|
|
46649
|
-
description: `
|
|
46838
|
+
description: `Render up to 100 fully authored, source-grounded articles into one polished mobile-first editorial report with contents, search, navigation, jump links, progress, text sizing, evening mode, provenance, structured article/card images, Markdown body images, and collection/article Open Graph metadata. Public HTTP(S) image URLs require alt text; preserve caption, credit, source, and rights context when known. The static artifact carries collection OG tags and updates article tags in-browser; a publishing host must serve article-specific metadata for crawler-perfect per-article unfurls. This renderer does not research or invent copy. For reusable website templates use list_artifact_templates instead. ${fileBehavior("Local stdio clients save one self-contained HTML file under the MCP Scraper output directory and return localPath.", "Hosted/app clients receive an owner-scoped private HTML artifact retained for seven days with a renewable signed download URL.")}`,
|
|
46650
46839
|
inputSchema: CreateEditorialReadingRoomInputSchema,
|
|
46651
46840
|
outputSchema: recordOutputSchema("create_editorial_reading_room", CreateEditorialReadingRoomOutputSchema),
|
|
46652
46841
|
annotations: {
|
|
@@ -50354,7 +50543,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50354
50543
|
ExportSchema = {
|
|
50355
50544
|
id: "memory-export",
|
|
50356
50545
|
upstreamName: "exportTool",
|
|
50357
|
-
description: "Export every note in
|
|
50546
|
+
description: "Export every full note in one vault for an explicitly requested backup, migration, or corpus-wide audit \u2014 path, title, content, kind, last-updated, and count. This can be large and is not the normal way to find or edit one note: use memory-list for complete metadata inventory, memory-search for ranked recall, and memory-get for exact content. Defaults to the active or first entitled vault. Requires export scope; the export is logged to provenance.",
|
|
50358
50547
|
input: {
|
|
50359
50548
|
vault: import_zod47.z.string().optional().describe(
|
|
50360
50549
|
"Vault to export. Optional; defaults to the session active vault, then the first vault the caller is entitled to."
|
|
@@ -50406,7 +50595,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50406
50595
|
GetSchema = {
|
|
50407
50596
|
id: "memory-get",
|
|
50408
50597
|
upstreamName: "getTool",
|
|
50409
|
-
description: "Read
|
|
50598
|
+
description: "Read one complete note by exact vault+path, or by accepted shareId. After memory-search identifies a strong candidate, use this before relying on it for an answer, summary, edit, link, or durable write: search results are excerpts, not complete notes. Owned notes include stored Obsidian props so edits preserve links and template metadata. Returns the revision required as baseRevision on later edits/deletes. Requires read scope.",
|
|
50410
50599
|
input: {
|
|
50411
50600
|
vault: import_zod47.z.string().optional().describe(
|
|
50412
50601
|
"Vault to read from. Optional; defaults to the session active vault, then the first vault the caller is entitled to. Ignored when shareId is given."
|
|
@@ -50443,7 +50632,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50443
50632
|
ListSchema = {
|
|
50444
50633
|
id: "memory-list",
|
|
50445
50634
|
upstreamName: "listTool",
|
|
50446
|
-
description: "
|
|
50635
|
+
description: "Return every note in one vault as a complete metadata inventory \u2014 stable path, title, kind, tags, and last-updated \u2014 plus a sorted list of every unique folder and nested folder represented by those paths. It contains no bodies. Use memory-get for exact full content, memory-search for ranked semantic recall, or memory-export only when explicitly asked for every full note. Defaults to the active or first entitled vault; also returns entitled vaults. Requires read scope.",
|
|
50447
50636
|
input: {
|
|
50448
50637
|
vault: import_zod47.z.string().optional().describe(
|
|
50449
50638
|
"Vault to list. Optional; defaults to the session active vault, then the first vault the caller is entitled to."
|
|
@@ -50463,6 +50652,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50463
50652
|
updatedAt: import_zod47.z.string().describe("ISO-8601 timestamp of the note last update.")
|
|
50464
50653
|
})
|
|
50465
50654
|
).optional().describe("The notes in the vault (metadata only, no content). Present when ok is true."),
|
|
50655
|
+
folders: import_zod47.z.array(import_zod47.z.string()).optional().describe("Sorted complete folder inventory derived from note paths, including represented nested parent folders. Present when ok is true."),
|
|
50466
50656
|
vaults: import_zod47.z.array(import_zod47.z.string()).optional().describe("All vaults the caller is entitled to, for choosing a different vault to list."),
|
|
50467
50657
|
error: import_zod47.z.string().optional().describe("Human-readable failure reason when ok is false.")
|
|
50468
50658
|
},
|
|
@@ -50497,7 +50687,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50497
50687
|
PutSchema = {
|
|
50498
50688
|
id: "memory-put",
|
|
50499
50689
|
upstreamName: "putTool",
|
|
50500
|
-
description: "Create or deliberately edit one note at a path
|
|
50690
|
+
description: "Create or deliberately edit one note at a stable vault+path. On an existing note, first call memory-get, merge the requested change into its full body, and pass that complete body plus baseRevision: content is replace-all, while supplied props patch the stored props. A conflict returns the current body for reconciliation; never retry the stale full body unchanged. Use purpose-built tools instead of rewriting system-managed Agent Inbox, optimizer, or channel backing notes. For normal new People, Organizations, Deals, Projects, Tasks, or Communication records, use prepare-memory-write then memory-capture. For row-shaped datasets use table tools. Ordinary vaults are indexed and shareable; store real secrets only in a secure vault. Requires write scope.",
|
|
50501
50691
|
input: {
|
|
50502
50692
|
vault: import_zod47.z.string().optional().describe(
|
|
50503
50693
|
"Vault to write to. Optional; defaults to the session active vault, then the first vault the caller is entitled to. On a default-provisioned account, pick the vault whose job matches the content (see the server instructions for the full 16-vault guide) rather than defaulting blindly \u2014 e.g. a lesson learned goes in Knowledge, the raw source it came from goes in Library, a broken feature goes in Issues, a named real-world initiative goes in Projects. Do not use this low-level tool to create ordinary People, Organizations, Deals, Projects, Tasks, or Communication records: first use prepare-memory-write then memory-capture so relationships and approval state are validated."
|
|
@@ -50505,9 +50695,9 @@ var init_memory_tool_schemas = __esm({
|
|
|
50505
50695
|
path: import_zod47.z.string().optional().describe("Vault-relative note path to create or overwrite, e.g. projects/q3-plan. Writing an existing path replaces it. Required unless shareId is given."),
|
|
50506
50696
|
shareId: import_zod47.z.string().optional().describe("Edit a note someone individually shared with you and you accepted (accept-share), by its shareId, instead of vault+path. Requires the share to grant edit permission, and baseRevision is mandatory (get the current revision first) since you are editing alongside the owner and possibly others."),
|
|
50507
50697
|
title: import_zod47.z.string().optional().describe("Optional human-readable title; defaults are derived from the path when omitted."),
|
|
50508
|
-
content: import_zod47.z.string().min(1).describe("The
|
|
50698
|
+
content: import_zod47.z.string().min(1).describe("The complete note body to store and index. On edit this replaces the prior body, so merge the requested change into the full memory-get content before calling; never pass only the changed fragment."),
|
|
50509
50699
|
props: putTool_notePropsSchema.optional().describe("Obsidian note primitives plus vault-specific template fields. On edits, supplied fields patch the stored props instead of replacing the whole object; pass an empty array to deliberately clear a link list. Type/domain/folder also steer routing when no vault is given."),
|
|
50510
|
-
baseRevision: import_zod47.z.number().optional().describe("Revision the edit is based on (from
|
|
50700
|
+
baseRevision: import_zod47.z.number().optional().describe("Revision the edit is based on (from memory-get/put). Always supply it when an AI edits an existing note; a mismatch rejects the write and returns current content for reconciliation. Omit only for an intentional new note or explicit last-write-wins migration."),
|
|
50511
50701
|
tagDescriptions: import_zod47.z.record(import_zod47.z.string(), import_zod47.z.string()).optional().describe("One-line meaning for any tag in props.tags that is new to the account, keyed by tag. Tags resolve against the account's existing vocabulary; new tags require a one-line description.")
|
|
50512
50702
|
},
|
|
50513
50703
|
output: {
|
|
@@ -50541,7 +50731,7 @@ var init_memory_tool_schemas = __esm({
|
|
|
50541
50731
|
SearchSchema = {
|
|
50542
50732
|
id: "memory-search",
|
|
50543
50733
|
upstreamName: "searchTool",
|
|
50544
|
-
description: "Default
|
|
50734
|
+
description: "Default first tool whenever the user wants to find, recall, understand, or connect Memory content without an exact vault+path. Hybrid Smart RAG combines 2-4 semantic query variants with exact vault/tag/date/kind/type/metadata matches, expands one bounded graph hop, then reranks. Results are ranked excerpts, never an exhaustive inventory or complete notes: deduplicate by vault/path and call memory-get on strong candidates before answering, summarizing, editing, linking, or writing. Use memory-list for every note, memory-suggest for title-only lookup, and memory-export only for explicit full-vault dumps. Before tagging or writing, also inspect list-memory-tags.",
|
|
50545
50735
|
input: {
|
|
50546
50736
|
vault: import_zod47.z.string().optional().describe("Exact logical vault handle to search. Omit to search every entitled vault."),
|
|
50547
50737
|
query: import_zod47.z.string().min(1).describe("A focused semantic reformulation of the request."),
|
|
@@ -51718,6 +51908,24 @@ var init_memory_mcp_server = __esm({
|
|
|
51718
51908
|
});
|
|
51719
51909
|
|
|
51720
51910
|
// src/mcp/memory-mcp-tool-executor.ts
|
|
51911
|
+
function folderInventory(result) {
|
|
51912
|
+
if (!Array.isArray(result.notes)) return [];
|
|
51913
|
+
const folders = /* @__PURE__ */ new Set();
|
|
51914
|
+
for (const note of result.notes) {
|
|
51915
|
+
if (!note || typeof note !== "object" || Array.isArray(note)) continue;
|
|
51916
|
+
const path6 = note.path;
|
|
51917
|
+
if (typeof path6 !== "string") continue;
|
|
51918
|
+
const segments = path6.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
51919
|
+
for (let depth = 1; depth < segments.length; depth += 1) {
|
|
51920
|
+
folders.add(segments.slice(0, depth).join("/"));
|
|
51921
|
+
}
|
|
51922
|
+
}
|
|
51923
|
+
return [...folders].sort((a, b) => a.localeCompare(b));
|
|
51924
|
+
}
|
|
51925
|
+
function enrichMemoryResult(toolName, result) {
|
|
51926
|
+
if (toolName !== "listTool" || result.ok !== true) return result;
|
|
51927
|
+
return { ...result, folders: folderInventory(result) };
|
|
51928
|
+
}
|
|
51721
51929
|
var MemoryMcpToolExecutor;
|
|
51722
51930
|
var init_memory_mcp_tool_executor = __esm({
|
|
51723
51931
|
"src/mcp/memory-mcp-tool-executor.ts"() {
|
|
@@ -51744,7 +51952,10 @@ var init_memory_mcp_tool_executor = __esm({
|
|
|
51744
51952
|
const message = data?.error ?? `memory ${toolName} failed (HTTP ${res.status})`;
|
|
51745
51953
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
51746
51954
|
}
|
|
51747
|
-
const result =
|
|
51955
|
+
const result = enrichMemoryResult(
|
|
51956
|
+
toolName,
|
|
51957
|
+
data ?? { ok: false, error: `memory ${toolName} returned no result` }
|
|
51958
|
+
);
|
|
51748
51959
|
return {
|
|
51749
51960
|
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
51750
51961
|
structuredContent: result,
|
|
@@ -59339,6 +59550,24 @@ function safeFilename3(requested, slug2) {
|
|
|
59339
59550
|
function escapedJsonForHtml(value) {
|
|
59340
59551
|
return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
59341
59552
|
}
|
|
59553
|
+
function socialMeta(input) {
|
|
59554
|
+
const image = input.site.ogImage;
|
|
59555
|
+
const tags = [
|
|
59556
|
+
'<meta property="og:type" content="website">',
|
|
59557
|
+
`<meta property="og:title" content="${escapeHtml6(input.site.title)}">`,
|
|
59558
|
+
`<meta property="og:description" content="${escapeHtml6(input.deck || input.site.heroTitle)}">`,
|
|
59559
|
+
'<meta name="twitter:card" content="summary_large_image">',
|
|
59560
|
+
`<meta name="twitter:title" content="${escapeHtml6(input.site.title)}">`,
|
|
59561
|
+
`<meta name="twitter:description" content="${escapeHtml6(input.deck || input.site.heroTitle)}">`,
|
|
59562
|
+
`<meta property="og:image" content="${image ? escapeHtml6(image.url) : ""}">`,
|
|
59563
|
+
`<meta property="og:image:alt" content="${image ? escapeHtml6(image.alt) : ""}">`,
|
|
59564
|
+
`<meta property="og:image:width" content="${image?.width ?? ""}">`,
|
|
59565
|
+
`<meta property="og:image:height" content="${image?.height ?? ""}">`,
|
|
59566
|
+
`<meta name="twitter:image" content="${image ? escapeHtml6(image.url) : ""}">`,
|
|
59567
|
+
`<meta name="twitter:image:alt" content="${image ? escapeHtml6(image.alt) : ""}">`
|
|
59568
|
+
];
|
|
59569
|
+
return tags.join("\n ");
|
|
59570
|
+
}
|
|
59342
59571
|
function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
59343
59572
|
const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
|
|
59344
59573
|
if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
|
|
@@ -59371,7 +59600,7 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
59371
59600
|
const generatedAt = now.toISOString();
|
|
59372
59601
|
const data = { ...input, generatedAt, articles };
|
|
59373
59602
|
const template = readAsset("index.html");
|
|
59374
|
-
const html = template.replace("<title>Editorial Reading Room</title>", `<title>${escapeHtml6(input.site.title)}</title>`).replace('content="A mobile-first editorial reading room."', `content="${escapeHtml6(input.deck || input.site.heroTitle)}"`).replace("/*__READING_ROOM_STYLES__*/", readAsset("styles.css")).replace("/*__READING_ROOM_DATA__*/", escapedJsonForHtml(data)).replace("/*__READING_ROOM_SCRIPT__*/", readAsset("app.js"));
|
|
59603
|
+
const html = template.replace("<title>Editorial Reading Room</title>", `<title>${escapeHtml6(input.site.title)}</title>`).replace('content="A mobile-first editorial reading room."', `content="${escapeHtml6(input.deck || input.site.heroTitle)}"`).replace("<!--__READING_ROOM_SOCIAL_META__-->", socialMeta(input)).replace("/*__READING_ROOM_STYLES__*/", readAsset("styles.css")).replace("/*__READING_ROOM_DATA__*/", escapedJsonForHtml(data)).replace("/*__READING_ROOM_SCRIPT__*/", readAsset("app.js"));
|
|
59375
59604
|
const bytes = Buffer.byteLength(html);
|
|
59376
59605
|
return {
|
|
59377
59606
|
html,
|