@appsoftwareltd/etherpk-mcp 0.9.6 → 0.10.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/dist/main.js +244 -60
- package/dist/main.js.map +1 -1
- package/dist/map-picture-page.js +73 -72
- package/package.json +5 -5
package/dist/main.js
CHANGED
|
@@ -717,7 +717,7 @@ function looksLikeAgentSetupCode(value) {
|
|
|
717
717
|
}
|
|
718
718
|
var package_default = {
|
|
719
719
|
name: "@appsoftwareltd/etherpk-mcp",
|
|
720
|
-
version: "0.
|
|
720
|
+
version: "0.10.0",
|
|
721
721
|
license: "Elastic-2.0",
|
|
722
722
|
description: "EtherPK Headless Client: an MCP server over a synced knowledge graph, run beside the agent on the user's own machine.",
|
|
723
723
|
type: "module",
|
|
@@ -4162,9 +4162,49 @@ function parseBlocks(markdown) {
|
|
|
4162
4162
|
return roots;
|
|
4163
4163
|
}
|
|
4164
4164
|
//#endregion
|
|
4165
|
+
//#region ../client/src/lib/document/extension-fence.ts
|
|
4166
|
+
/**
|
|
4167
|
+
* [[Extension Fence]]s (ADR 0138): a fence whose info word is `<extension id>.<name>` holds an
|
|
4168
|
+
* extension's data, such as a drawing's elements. Every reader of a document decides from the info
|
|
4169
|
+
* word alone, with no extension running, so the editor, the index, Semantic Search, the publisher
|
|
4170
|
+
* and the Headless Client always agree: the body is never read as writing, never searched, and never
|
|
4171
|
+
* published as code.
|
|
4172
|
+
*
|
|
4173
|
+
* Framework-free, so the index worker, the publisher and the Headless Client read it as the editor
|
|
4174
|
+
* does.
|
|
4175
|
+
*/
|
|
4176
|
+
/** An extension's id or a name under it: lowercase letters, digits and hyphens, from a letter. */
|
|
4177
|
+
var NAME = "[a-z][a-z0-9-]*";
|
|
4178
|
+
var EXTENSION_FENCE_INFO = new RegExp(`^${NAME}\\.${NAME}$`);
|
|
4179
|
+
/** Whether an info word names an Extension Fence: an extension's id, a dot and a name. */
|
|
4180
|
+
function isExtensionFenceInfo(info) {
|
|
4181
|
+
return EXTENSION_FENCE_INFO.test(info);
|
|
4182
|
+
}
|
|
4183
|
+
/** The extension an Extension Fence's info word names: the part before the dot. */
|
|
4184
|
+
function extensionOfFence(info) {
|
|
4185
|
+
return info.slice(0, info.indexOf("."));
|
|
4186
|
+
}
|
|
4187
|
+
/** Each complete, outermost Extension Fence in `lines`, by its opener's and closer's 0-based lines. */
|
|
4188
|
+
function extensionFences(lines) {
|
|
4189
|
+
const out = [];
|
|
4190
|
+
const { sorted, parent } = fencedBlockTree(fencedBlocks(lines));
|
|
4191
|
+
sorted.forEach((block, i) => {
|
|
4192
|
+
if (parent[i] !== -1) return;
|
|
4193
|
+
const info = fenceLineInfo(lines[block.start])?.info ?? "";
|
|
4194
|
+
if (isExtensionFenceInfo(info)) out.push({
|
|
4195
|
+
start: block.start,
|
|
4196
|
+
end: block.end,
|
|
4197
|
+
info
|
|
4198
|
+
});
|
|
4199
|
+
});
|
|
4200
|
+
return out;
|
|
4201
|
+
}
|
|
4202
|
+
//#endregion
|
|
4165
4203
|
//#region ../client/src/lib/document/map-text.ts
|
|
4166
4204
|
var NUMBER = String.raw`[+-]?(?:\d+(?:\.\d*)?|\.\d+)`;
|
|
4167
4205
|
var POINT = new RegExp(String.raw`^\s*(${NUMBER})\s*,\s*(${NUMBER})\s*$`);
|
|
4206
|
+
/** How many of the last `@`s on a line may end its name (`readMapLine`). */
|
|
4207
|
+
var MAX_NAME_ENDS = 16;
|
|
4168
4208
|
function readPoint(text) {
|
|
4169
4209
|
const match = POINT.exec(text);
|
|
4170
4210
|
if (!match) return null;
|
|
@@ -4214,7 +4254,8 @@ function readLocation(text, name) {
|
|
|
4214
4254
|
function readMapLine(text) {
|
|
4215
4255
|
const trimmed = text.trim();
|
|
4216
4256
|
if (trimmed === "") return null;
|
|
4217
|
-
|
|
4257
|
+
let tries = 0;
|
|
4258
|
+
for (let at = trimmed.lastIndexOf("@"); at >= 0 && tries < MAX_NAME_ENDS; at = at === 0 ? -1 : trimmed.lastIndexOf("@", at - 1), tries++) {
|
|
4218
4259
|
const line = readLocation(trimmed.slice(at + 1), trimmed.slice(0, at).trim());
|
|
4219
4260
|
if (line) return line;
|
|
4220
4261
|
}
|
|
@@ -4528,30 +4569,57 @@ function deriveDoc(text) {
|
|
|
4528
4569
|
const candidateTasks = blocks.filter((b) => b.kind === "task");
|
|
4529
4570
|
const fenced = candidateTasks.length === 0 ? () => false : fencedLines(text);
|
|
4530
4571
|
const taskBlocks = candidateTasks.filter((b) => !fenced(b.startLine));
|
|
4572
|
+
const tasks = taskBlocks.map((b) => {
|
|
4573
|
+
const tags = parseTaskTags(b.label);
|
|
4574
|
+
return {
|
|
4575
|
+
blockLocalId: b.localId,
|
|
4576
|
+
done: b.done ?? false,
|
|
4577
|
+
text: b.label,
|
|
4578
|
+
line: b.startLine,
|
|
4579
|
+
priority: tags.priority,
|
|
4580
|
+
waiting: tags.waiting,
|
|
4581
|
+
doing: tags.doing,
|
|
4582
|
+
cancelled: tags.cancelled,
|
|
4583
|
+
due: tags.due,
|
|
4584
|
+
completion: tags.completion,
|
|
4585
|
+
scheduled: tags.scheduled
|
|
4586
|
+
};
|
|
4587
|
+
});
|
|
4588
|
+
const maps = deriveMaps(text, blocks, links, lineToBlock);
|
|
4531
4589
|
return {
|
|
4532
4590
|
blocks,
|
|
4533
4591
|
links,
|
|
4534
|
-
tasks
|
|
4535
|
-
const tags = parseTaskTags(b.label);
|
|
4536
|
-
return {
|
|
4537
|
-
blockLocalId: b.localId,
|
|
4538
|
-
done: b.done ?? false,
|
|
4539
|
-
text: b.label,
|
|
4540
|
-
line: b.startLine,
|
|
4541
|
-
priority: tags.priority,
|
|
4542
|
-
waiting: tags.waiting,
|
|
4543
|
-
doing: tags.doing,
|
|
4544
|
-
cancelled: tags.cancelled,
|
|
4545
|
-
due: tags.due,
|
|
4546
|
-
completion: tags.completion,
|
|
4547
|
-
scheduled: tags.scheduled
|
|
4548
|
-
};
|
|
4549
|
-
}),
|
|
4592
|
+
tasks,
|
|
4550
4593
|
taskConcepts: deriveTaskConcepts(blocks, links, taskBlocks),
|
|
4551
|
-
...
|
|
4594
|
+
...maps,
|
|
4595
|
+
searchText: withoutExtensionFences(text, blocks, lineToBlock, maps.searchText)
|
|
4552
4596
|
};
|
|
4553
4597
|
}
|
|
4554
4598
|
/**
|
|
4599
|
+
* What search and Semantic Search read for each block holding an [[Extension Fence]] (ADR 0138):
|
|
4600
|
+
* the block's text with the fence's lines left out, so an extension's data (a drawing's elements)
|
|
4601
|
+
* never fills either index. Added to what `deriveMaps` gave, block by block.
|
|
4602
|
+
*/
|
|
4603
|
+
function withoutExtensionFences(text, blocks, lineToBlock, searchText) {
|
|
4604
|
+
if (!/```[a-z][a-z0-9-]*\.[a-z]/.test(text)) return searchText;
|
|
4605
|
+
const fences = extensionFences(text.split("\n"));
|
|
4606
|
+
if (fences.length === 0) return searchText;
|
|
4607
|
+
const hidden = /* @__PURE__ */ new Map();
|
|
4608
|
+
for (const fence of fences) {
|
|
4609
|
+
const id = lineToBlock.get(fence.start);
|
|
4610
|
+
if (id === void 0) continue;
|
|
4611
|
+
const lines = hidden.get(id) ?? /* @__PURE__ */ new Set();
|
|
4612
|
+
for (let line = fence.start; line <= fence.end; line++) lines.add(line);
|
|
4613
|
+
hidden.set(id, lines);
|
|
4614
|
+
}
|
|
4615
|
+
for (const [id, lines] of hidden) {
|
|
4616
|
+
const block = blocks[id];
|
|
4617
|
+
const read = (searchText.get(id) ?? block.text).split("\n").map((line, n) => lines.has(block.startLine + n) ? "" : line);
|
|
4618
|
+
searchText.set(id, read.join("\n"));
|
|
4619
|
+
}
|
|
4620
|
+
return searchText;
|
|
4621
|
+
}
|
|
4622
|
+
/**
|
|
4555
4623
|
* The [[Place]]s and [[Route]]s a document's [[Map Block]]s hold (ADR 0118), the [[Block
|
|
4556
4624
|
* Concept]]s of the blocks they sit in, and what text search reads for those blocks instead of
|
|
4557
4625
|
* their coordinates.
|
|
@@ -12651,6 +12719,13 @@ function wikilinkRule(md, resolve) {
|
|
|
12651
12719
|
* grammars for code), so they are pre-rendered by the orchestrator and handed in as lookups;
|
|
12652
12720
|
* the renderer itself is synchronous and pure over its inputs.
|
|
12653
12721
|
*/
|
|
12722
|
+
/** A fence an extension published, as HTML the publisher writes: the extension never writes markup into a site. */
|
|
12723
|
+
function fenceOutputHtml(output) {
|
|
12724
|
+
if (output.kind === "picture") return `<figure class="diagram diagram-extension"><img src="${escapeHtml$3(output.src)}" alt="${escapeHtml$3(output.alt)}" width="${output.width}" height="${output.height}" loading="lazy"></figure>\n`;
|
|
12725
|
+
const size = (image) => image.width && image.height ? ` width="${Math.round(image.width)}" height="${Math.round(image.height)}"` : "";
|
|
12726
|
+
const image = output.image ? `<img src="${escapeHtml$3(output.image.src)}" alt="${escapeHtml$3(output.image.alt)}"${size(output.image)} loading="lazy">` : "";
|
|
12727
|
+
return `<figure class="diagram diagram-link"><a href="${escapeHtml$3(output.href)}">${image}</a><figcaption><a href="${escapeHtml$3(output.href)}">${escapeHtml$3(output.text)}</a></figcaption></figure>\n`;
|
|
12728
|
+
}
|
|
12654
12729
|
/** The names on a Map Block, one line for the search index and the excerpt; never its coordinates. */
|
|
12655
12730
|
function mapNames(source) {
|
|
12656
12731
|
return readMapBody(source.split("\n")).items.map((item) => item.name).filter((name) => name !== "").join(", ");
|
|
@@ -12698,7 +12773,7 @@ function plainText(tokens) {
|
|
|
12698
12773
|
if (info === "map") {
|
|
12699
12774
|
const names = mapNames(token.content);
|
|
12700
12775
|
if (names !== "") lines.push(names);
|
|
12701
|
-
} else if (info !== "mermaid" && info !== "math") lines.push(token.content.trim());
|
|
12776
|
+
} else if (info !== "mermaid" && info !== "math" && !isExtensionFenceInfo(info)) lines.push(token.content.trim());
|
|
12702
12777
|
}
|
|
12703
12778
|
return lines.join("\n");
|
|
12704
12779
|
}
|
|
@@ -12777,6 +12852,9 @@ function createDocumentRenderer(options) {
|
|
|
12777
12852
|
if (!picture) return "";
|
|
12778
12853
|
return `<figure class="map"><img src="${escapeHtml$3(picture.src)}" alt="${escapeHtml$3(picture.alt)}" width="${picture.width}" height="${picture.height}" loading="lazy"></figure>\n`;
|
|
12779
12854
|
}
|
|
12855
|
+
const output = options.fenceOutput?.(lang, code);
|
|
12856
|
+
if (output) return fenceOutputHtml(output);
|
|
12857
|
+
if (output === null || isExtensionFenceInfo(lang)) return "";
|
|
12780
12858
|
const highlighted = options.highlighted?.(lang, code);
|
|
12781
12859
|
return `<pre><code${lang === "" ? "" : ` class="language-${escapeHtml$3(lang)}"`}>${highlighted ?? escapeHtml$3(code)}</code></pre>\n`;
|
|
12782
12860
|
};
|
|
@@ -13229,6 +13307,80 @@ async function mapPictureName(source) {
|
|
|
13229
13307
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${MAP_PICTURE_VERSION}\n${source}`));
|
|
13230
13308
|
return [...new Uint8Array(digest)].slice(0, 8).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
13231
13309
|
}
|
|
13310
|
+
/** A fence's body as lines, as an extension's widget reads it: markdown-it's content ends with a line break. */
|
|
13311
|
+
function bodyLines(code) {
|
|
13312
|
+
const lines = code.split("\n");
|
|
13313
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
13314
|
+
return lines;
|
|
13315
|
+
}
|
|
13316
|
+
var PICTURE_EXTENSIONS = {
|
|
13317
|
+
"image/svg+xml": "svg",
|
|
13318
|
+
"image/png": "png",
|
|
13319
|
+
"image/webp": "webp"
|
|
13320
|
+
};
|
|
13321
|
+
/** An `https` address as written, or null for any other. */
|
|
13322
|
+
function httpsAddress(value) {
|
|
13323
|
+
if (typeof value !== "string") return null;
|
|
13324
|
+
try {
|
|
13325
|
+
return new URL(value).protocol === "https:" ? value : null;
|
|
13326
|
+
} catch {
|
|
13327
|
+
return null;
|
|
13328
|
+
}
|
|
13329
|
+
}
|
|
13330
|
+
/**
|
|
13331
|
+
* What an extension's `publish` answered for a fence, checked, its picture kept for the site under
|
|
13332
|
+
* a name taken from its bytes: a picture, a link (`https` only, as is any picture in it), null when
|
|
13333
|
+
* it is left out, or undefined when it could not be made, after which an ordinary fence is published
|
|
13334
|
+
* as code and an Extension Fence left out, with a warning either way.
|
|
13335
|
+
*/
|
|
13336
|
+
async function publishedFence(asked, info, concept, pictures, warnings) {
|
|
13337
|
+
try {
|
|
13338
|
+
const out = await asked;
|
|
13339
|
+
if (out === null) return null;
|
|
13340
|
+
if (out.kind === "picture") {
|
|
13341
|
+
const extension = PICTURE_EXTENSIONS[out.type];
|
|
13342
|
+
if (!(out.bytes instanceof Uint8Array) || !extension) throw new Error("its picture is not an SVG, PNG or WebP file");
|
|
13343
|
+
const digest = await crypto.subtle.digest("SHA-256", out.bytes);
|
|
13344
|
+
const path = `pictures/${[...new Uint8Array(digest)].slice(0, 8).map((byte) => byte.toString(16).padStart(2, "0")).join("")}.${extension}`;
|
|
13345
|
+
pictures.set(path, out.bytes);
|
|
13346
|
+
return {
|
|
13347
|
+
kind: "picture",
|
|
13348
|
+
src: path,
|
|
13349
|
+
alt: String(out.alt ?? ""),
|
|
13350
|
+
width: Math.round(out.width),
|
|
13351
|
+
height: Math.round(out.height)
|
|
13352
|
+
};
|
|
13353
|
+
}
|
|
13354
|
+
if (out.kind === "link") {
|
|
13355
|
+
const href = httpsAddress(out.href);
|
|
13356
|
+
if (!href) throw new Error("its link is not an https address");
|
|
13357
|
+
const src = httpsAddress(out.image?.src);
|
|
13358
|
+
const image = src && out.image ? {
|
|
13359
|
+
src,
|
|
13360
|
+
alt: String(out.image.alt ?? ""),
|
|
13361
|
+
width: out.image.width,
|
|
13362
|
+
height: out.image.height
|
|
13363
|
+
} : void 0;
|
|
13364
|
+
return {
|
|
13365
|
+
kind: "link",
|
|
13366
|
+
href,
|
|
13367
|
+
text: String(out.text ?? href),
|
|
13368
|
+
...image ? { image } : {}
|
|
13369
|
+
};
|
|
13370
|
+
}
|
|
13371
|
+
throw new Error("it answered with something that is neither a picture nor a link");
|
|
13372
|
+
} catch (error) {
|
|
13373
|
+
const why = error instanceof Error ? error.message : String(error);
|
|
13374
|
+
const extensionFence = isExtensionFenceInfo(info);
|
|
13375
|
+
warnings.push({
|
|
13376
|
+
level: "warning",
|
|
13377
|
+
code: "extension-fence-failed",
|
|
13378
|
+
message: `A \`${info}\` block in "${concept}" could not be published: ${why}. ${extensionFence ? "It is left out." : "It is published as its text."}`,
|
|
13379
|
+
concept
|
|
13380
|
+
});
|
|
13381
|
+
return extensionFence ? null : void 0;
|
|
13382
|
+
}
|
|
13383
|
+
}
|
|
13232
13384
|
function assetHrefOf(name) {
|
|
13233
13385
|
return `assets/${encodeURIComponent(name)}`;
|
|
13234
13386
|
}
|
|
@@ -13407,6 +13559,10 @@ async function publishPublication(source, publication, env, options = {}) {
|
|
|
13407
13559
|
}
|
|
13408
13560
|
const mermaidSvg = /* @__PURE__ */ new Map();
|
|
13409
13561
|
const mapPictures = /* @__PURE__ */ new Map();
|
|
13562
|
+
/** What each fence an extension publishes becomes, by its info word and body; null when it is left out. */
|
|
13563
|
+
const fenceOutputs = /* @__PURE__ */ new Map();
|
|
13564
|
+
/** The pictures extensions made of fences, by their path in the site. */
|
|
13565
|
+
const fencePictures = /* @__PURE__ */ new Map();
|
|
13410
13566
|
const highlighted = /* @__PURE__ */ new Map();
|
|
13411
13567
|
const highlight = env.highlightCode ?? highlightCode;
|
|
13412
13568
|
const probe = createDocumentRenderer({
|
|
@@ -13417,51 +13573,77 @@ async function publishPublication(source, publication, env, options = {}) {
|
|
|
13417
13573
|
doc: d,
|
|
13418
13574
|
body: bodyOf$1(d)
|
|
13419
13575
|
}));
|
|
13420
|
-
for (const { doc, body } of bodies) for (const fence of probe.fences(body))
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13576
|
+
for (const { doc, body } of bodies) for (const fence of probe.fences(body)) {
|
|
13577
|
+
const fenceKey = `${fence.lang}\n${fence.code}`;
|
|
13578
|
+
const extensionFence = isExtensionFenceInfo(fence.lang);
|
|
13579
|
+
const asked = fence.lang === "" || fenceOutputs.has(fenceKey) ? void 0 : env.publishFence?.({
|
|
13580
|
+
info: fence.lang,
|
|
13581
|
+
body: bodyLines(fence.code),
|
|
13582
|
+
document: doc.concept
|
|
13583
|
+
});
|
|
13584
|
+
if (asked) {
|
|
13585
|
+
const output = await publishedFence(asked, fence.lang, doc.concept, fencePictures, warnings);
|
|
13586
|
+
if (output !== void 0) {
|
|
13587
|
+
fenceOutputs.set(fenceKey, output);
|
|
13588
|
+
continue;
|
|
13589
|
+
}
|
|
13590
|
+
} else if (fenceOutputs.has(fenceKey)) continue;
|
|
13591
|
+
if (extensionFence) {
|
|
13592
|
+
fenceOutputs.set(fenceKey, null);
|
|
13425
13593
|
warnings.push({
|
|
13426
13594
|
level: "warning",
|
|
13427
|
-
code: "
|
|
13428
|
-
message: `
|
|
13429
|
-
concept: doc.concept
|
|
13430
|
-
});
|
|
13431
|
-
}
|
|
13432
|
-
} else if (fence.lang === "map") {
|
|
13433
|
-
if (mapPictures.has(fence.code) || errors.some((e) => e.code === "map-not-drawn" && e.concept === doc.concept)) continue;
|
|
13434
|
-
if (!env.renderMap) {
|
|
13435
|
-
errors.push({
|
|
13436
|
-
level: "error",
|
|
13437
|
-
code: "map-not-drawn",
|
|
13438
|
-
message: `"${doc.concept}" holds a map, which this publisher can't draw. Publish the site from EtherPK in a browser, where maps are drawn.`,
|
|
13595
|
+
code: "extension-fence-left-out",
|
|
13596
|
+
message: `"${doc.concept}" holds content from the ${extensionOfFence(fence.lang)} extension, which this publisher can't draw, so it is left out. Publish from EtherPK in a browser, with that extension on, to include it.`,
|
|
13439
13597
|
concept: doc.concept
|
|
13440
13598
|
});
|
|
13441
13599
|
continue;
|
|
13442
13600
|
}
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
|
|
13450
|
-
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13601
|
+
if (fence.lang === "mermaid") {
|
|
13602
|
+
if (!env.renderMermaid || mermaidSvg.has(fence.code)) continue;
|
|
13603
|
+
try {
|
|
13604
|
+
mermaidSvg.set(fence.code, await env.renderMermaid(fence.code));
|
|
13605
|
+
} catch (error) {
|
|
13606
|
+
warnings.push({
|
|
13607
|
+
level: "warning",
|
|
13608
|
+
code: "mermaid-render-failed",
|
|
13609
|
+
message: `A diagram in "${doc.concept}" could not be rendered: ${error instanceof Error ? error.message : String(error)}. It is left as its source for a script to draw.`,
|
|
13610
|
+
concept: doc.concept
|
|
13611
|
+
});
|
|
13612
|
+
}
|
|
13613
|
+
} else if (fence.lang === "map") {
|
|
13614
|
+
if (mapPictures.has(fence.code) || errors.some((e) => e.code === "map-not-drawn" && e.concept === doc.concept)) continue;
|
|
13615
|
+
if (!env.renderMap) {
|
|
13616
|
+
errors.push({
|
|
13617
|
+
level: "error",
|
|
13618
|
+
code: "map-not-drawn",
|
|
13619
|
+
message: `"${doc.concept}" holds a map, which this publisher can't draw. Publish the site from EtherPK in a browser, where maps are drawn.`,
|
|
13620
|
+
concept: doc.concept
|
|
13621
|
+
});
|
|
13622
|
+
continue;
|
|
13623
|
+
}
|
|
13624
|
+
try {
|
|
13625
|
+
const picture = await env.renderMap(fence.code);
|
|
13626
|
+
const path = `maps/${await mapPictureName(fence.code)}.${picture.type === "image/webp" ? "webp" : "png"}`;
|
|
13627
|
+
mapPictures.set(fence.code, {
|
|
13628
|
+
...picture,
|
|
13629
|
+
path,
|
|
13630
|
+
alt: mapAltText(fence.code.split("\n"))
|
|
13631
|
+
});
|
|
13632
|
+
} catch (error) {
|
|
13633
|
+
const why = error instanceof Error ? error.message : String(error);
|
|
13634
|
+
errors.push({
|
|
13635
|
+
level: "error",
|
|
13636
|
+
code: "map-not-drawn",
|
|
13637
|
+
message: `The map in "${doc.concept}" could not be drawn: ${why}. Nothing was published, so try again once it can be.`,
|
|
13638
|
+
concept: doc.concept
|
|
13639
|
+
});
|
|
13640
|
+
}
|
|
13641
|
+
} else if (fence.lang !== "" && fence.lang !== "math" && fence.lang !== "etherpk-cipher") {
|
|
13642
|
+
const key = `${fence.lang}\n${fence.code}`;
|
|
13643
|
+
if (highlighted.has(key)) continue;
|
|
13644
|
+
const html = await highlight(fence.lang, fence.code);
|
|
13645
|
+
if (html !== null) highlighted.set(key, html);
|
|
13459
13646
|
}
|
|
13460
|
-
} else if (fence.lang !== "" && fence.lang !== "math" && fence.lang !== "etherpk-cipher") {
|
|
13461
|
-
const key = `${fence.lang}\n${fence.code}`;
|
|
13462
|
-
if (highlighted.has(key)) continue;
|
|
13463
|
-
const html = await highlight(fence.lang, fence.code);
|
|
13464
|
-
if (html !== null) highlighted.set(key, html);
|
|
13465
13647
|
}
|
|
13466
13648
|
if (errors.length > 0) return {
|
|
13467
13649
|
bundle,
|
|
@@ -13493,7 +13675,8 @@ async function publishPublication(source, publication, env, options = {}) {
|
|
|
13493
13675
|
width: picture.width,
|
|
13494
13676
|
height: picture.height
|
|
13495
13677
|
};
|
|
13496
|
-
}
|
|
13678
|
+
},
|
|
13679
|
+
fenceOutput: (lang, code) => fenceOutputs.get(`${lang}\n${code}`)
|
|
13497
13680
|
});
|
|
13498
13681
|
const pages = [];
|
|
13499
13682
|
let done = 0;
|
|
@@ -13752,6 +13935,7 @@ async function publishPublication(source, publication, env, options = {}) {
|
|
|
13752
13935
|
report.assets.copied.push(name);
|
|
13753
13936
|
}
|
|
13754
13937
|
for (const picture of mapPictures.values()) bundle.set(picture.path, picture.bytes);
|
|
13938
|
+
for (const [path, bytes] of fencePictures) bundle.set(path, bytes);
|
|
13755
13939
|
for (const [path, text] of theme.files) if (path.startsWith("assets/")) bundle.set(`theme/${path.slice(7)}`, text);
|
|
13756
13940
|
if (customCss !== "") bundle.set("theme/custom.css", customCss.endsWith("\n") ? customCss : `${customCss}\n`);
|
|
13757
13941
|
if (hasMath) {
|
|
@@ -18498,7 +18682,7 @@ function createMcpServer(source, info) {
|
|
|
18498
18682
|
}, async (args) => run((graph) => rename$1(graph, args)));
|
|
18499
18683
|
server.registerTool("set_aliases", {
|
|
18500
18684
|
title: "Set aliases",
|
|
18501
|
-
description: "Replace a document's aliases: other names it answers to in [[wikilinks]],
|
|
18685
|
+
description: "Replace a document's aliases: other names it answers to in [[wikilinks]], Search and on a published site. The list you pass is the complete list, and it is shown in the document's frontmatter, in a block added if there is none. A name that is already another document's title or alias is refused with error \"name_taken\".",
|
|
18502
18686
|
inputSchema: {
|
|
18503
18687
|
concept,
|
|
18504
18688
|
aliases: z.array(z.string()).describe("Every alias the document should have - an empty list removes them all.")
|