@xnetjs/plugins 1.0.0 → 2.0.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/index.js CHANGED
@@ -1978,25 +1978,37 @@ async function resolveMentionProviders(providers, trigger, query, options = {})
1978
1978
  }
1979
1979
 
1980
1980
  // src/editor-schema-safety.ts
1981
- function isSchemaDefiningExtension(ext) {
1982
- return ext?.type === "node" || ext?.type === "mark";
1981
+ function collectSpecNames(contribution) {
1982
+ return [
1983
+ ...Object.keys(contribution.blockSpecs ?? {}).map((name) => ({ kind: "block", name })),
1984
+ ...Object.keys(contribution.inlineContentSpecs ?? {}).map((name) => ({
1985
+ kind: "inlineContent",
1986
+ name
1987
+ })),
1988
+ ...Object.keys(contribution.styleSpecs ?? {}).map((name) => ({ kind: "style", name }))
1989
+ ];
1990
+ }
1991
+ function isSchemaDefiningContribution(contribution) {
1992
+ return collectSpecNames(contribution).length > 0;
1983
1993
  }
1984
- function findEditorSchemaRisks(contributions) {
1994
+ function findEditorSchemaRisks(contributions, bundledSpecNames = []) {
1995
+ const bundled = new Set(bundledSpecNames);
1985
1996
  const risks = [];
1986
1997
  for (const c of contributions) {
1987
- const ext = c.extension;
1988
- if (isSchemaDefiningExtension(ext)) {
1989
- risks.push({ id: c.id, kind: ext.type ?? "unknown", name: ext.name ?? "unknown" });
1998
+ for (const spec of collectSpecNames(c)) {
1999
+ if (!bundled.has(spec.name)) {
2000
+ risks.push({ id: c.id, kind: spec.kind, name: spec.name });
2001
+ }
1990
2002
  }
1991
2003
  }
1992
2004
  return risks;
1993
2005
  }
1994
- function warnOnEditorSchemaRisks(pluginId, contributions) {
1995
- const risks = findEditorSchemaRisks(contributions);
2006
+ function warnOnEditorSchemaRisks(pluginId, contributions, bundledSpecNames = []) {
2007
+ const risks = findEditorSchemaRisks(contributions, bundledSpecNames);
1996
2008
  if (risks.length > 0 && process.env.NODE_ENV !== "production") {
1997
2009
  for (const r of risks) {
1998
2010
  console.warn(
1999
- `[plugins] '${pluginId}' editor contribution '${r.id}' adds a schema ${r.kind} ('${r.name}'). Schema-defining extensions must be present for ALL collaborators or Yjs will silently drop content across version skew. Prefer behavior-only extensions, or ship schema nodes in the bundled core.`
2011
+ `[plugins] '${pluginId}' editor contribution '${r.id}' adds a schema ${r.kind} spec ('${r.name}') that is not statically bundled. Schema-defining specs must be present for ALL collaborators or Yjs will silently drop content across version skew. Ship schema specs in the bundled core and contribute only the UI affordance (slash menu items).`
2000
2012
  );
2001
2013
  }
2002
2014
  }
@@ -6291,7 +6303,7 @@ var applyPageMarkdownTool = {
6291
6303
  definition: {
6292
6304
  name: "xnet_apply_page_markdown",
6293
6305
  title: "Apply page Markdown plan",
6294
- description: "Apply a validated page Markdown mutation plan through the configured TipTap/Yjs document adapter, with a node-property fallback.",
6306
+ description: "Apply a validated page Markdown mutation plan through the configured BlockNote/Yjs document adapter, with a node-property fallback.",
6295
6307
  risk: "high",
6296
6308
  requiredScopes: ["page.read", "page.write"],
6297
6309
  inputSchema: {
@@ -9007,6 +9019,514 @@ function quoteYaml(value) {
9007
9019
  return JSON.stringify(value);
9008
9020
  }
9009
9021
 
9022
+ // src/ai-surface/page-fragment.ts
9023
+ import * as Y from "yjs";
9024
+ var XNET_PAGE_FRAGMENT_FIELD = "content-v4";
9025
+ var XNET_PAGE_LEGACY_FRAGMENT_FIELD = "content";
9026
+ function isRecord5(value) {
9027
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9028
+ }
9029
+ function attrString(attrs, ...keys) {
9030
+ for (const key of keys) {
9031
+ const value = attrs[key];
9032
+ if (value !== void 0 && value !== null && value !== "") return String(value);
9033
+ }
9034
+ return "";
9035
+ }
9036
+ function markWrap(text3, attributes) {
9037
+ if (!attributes || text3 === "") return text3;
9038
+ let out = text3;
9039
+ if (attributes.code) out = `\`${out}\``;
9040
+ if (attributes.bold) out = `**${out}**`;
9041
+ if (attributes.italic) out = `*${out}*`;
9042
+ const link = attributes.link;
9043
+ const href = isRecord5(link) ? link.href : link;
9044
+ if (typeof href === "string" && href) out = `[${out}](${href})`;
9045
+ return out;
9046
+ }
9047
+ function textToMarkdown(node) {
9048
+ let out = "";
9049
+ const delta = node.toDelta();
9050
+ for (const op of delta) {
9051
+ if (typeof op.insert === "string") {
9052
+ out += markWrap(op.insert, op.attributes);
9053
+ } else if (isRecord5(op.insert)) {
9054
+ out += embeddedAtomToMarkdown(op.insert);
9055
+ }
9056
+ }
9057
+ return out;
9058
+ }
9059
+ function embeddedAtomToMarkdown(embed) {
9060
+ const type = typeof embed.type === "string" ? embed.type : "";
9061
+ const attrs = isRecord5(embed.attrs) ? embed.attrs : embed;
9062
+ return atomToMarkdown(type, attrs) ?? "";
9063
+ }
9064
+ function atomToMarkdown(name, attrs) {
9065
+ switch (name) {
9066
+ case "mention":
9067
+ case "personMention":
9068
+ case "taskMention":
9069
+ return `@${attrString(attrs, "label", "id")}`;
9070
+ case "hashtag":
9071
+ return `#${attrString(attrs, "name")}`;
9072
+ case "wikilink":
9073
+ return `[[${attrString(attrs, "title", "href")}]]`;
9074
+ case "inlineMath":
9075
+ return `$${attrString(attrs, "latex")}$`;
9076
+ case "smartReference":
9077
+ case "databaseReference":
9078
+ return attrString(attrs, "title", "url", "databaseId");
9079
+ case "emoji": {
9080
+ const emoji = attrString(attrs, "name");
9081
+ return emoji ? `:${emoji}:` : "";
9082
+ }
9083
+ default:
9084
+ return null;
9085
+ }
9086
+ }
9087
+ function inlineToMarkdown(element) {
9088
+ let out = "";
9089
+ for (let i = 0; i < element.length; i++) {
9090
+ const child = element.get(i);
9091
+ if (child instanceof Y.XmlText) {
9092
+ out += textToMarkdown(child);
9093
+ } else if (child instanceof Y.XmlElement) {
9094
+ const atom = atomToMarkdown(child.nodeName, child.getAttributes());
9095
+ out += atom ?? inlineToMarkdown(child);
9096
+ }
9097
+ }
9098
+ return out;
9099
+ }
9100
+ var LIST_ITEM_TYPES = /* @__PURE__ */ new Set(["bulletListItem", "numberedListItem", "checkListItem"]);
9101
+ function elementChildren(element) {
9102
+ const children = [];
9103
+ for (let i = 0; i < element.length; i++) {
9104
+ const child = element.get(i);
9105
+ if (child instanceof Y.XmlElement) children.push(child);
9106
+ }
9107
+ return children;
9108
+ }
9109
+ function joinChunks(chunks) {
9110
+ let out = "";
9111
+ chunks.forEach((chunk, index) => {
9112
+ if (index > 0) {
9113
+ const previous = chunks[index - 1];
9114
+ out += previous.kind === "list" && chunk.kind === "list" ? "\n" : "\n\n";
9115
+ }
9116
+ out += chunk.text;
9117
+ });
9118
+ return out;
9119
+ }
9120
+ function indentLines(text3, indent) {
9121
+ return text3.split("\n").map((line) => line ? indent + line : line).join("\n");
9122
+ }
9123
+ function tableToMarkdown(table) {
9124
+ const rows = [];
9125
+ const visit = (element) => {
9126
+ for (const child of elementChildren(element)) {
9127
+ if (child.nodeName === "tableRow") {
9128
+ const cells = [];
9129
+ for (const cell of elementChildren(child)) {
9130
+ if (cell.nodeName === "tableCell" || cell.nodeName === "tableHeader") {
9131
+ cells.push(inlineToMarkdown(cell).replace(/\n/g, " ").trim());
9132
+ }
9133
+ }
9134
+ rows.push(cells);
9135
+ } else {
9136
+ visit(child);
9137
+ }
9138
+ }
9139
+ };
9140
+ visit(table);
9141
+ if (rows.length === 0) return "";
9142
+ const lines = [`| ${rows[0].join(" | ")} |`, `| ${rows[0].map(() => "---").join(" | ")} |`];
9143
+ for (const row of rows.slice(1)) lines.push(`| ${row.join(" | ")} |`);
9144
+ return lines.join("\n");
9145
+ }
9146
+ function blockContentToMarkdown(content, orderedIndex) {
9147
+ const attrs = content.getAttributes();
9148
+ switch (content.nodeName) {
9149
+ case "paragraph":
9150
+ return inlineToMarkdown(content);
9151
+ case "heading": {
9152
+ const level = Math.min(Math.max(Number(attrs.level ?? 1) || 1, 1), 6);
9153
+ return `${"#".repeat(level)} ${inlineToMarkdown(content)}`;
9154
+ }
9155
+ case "bulletListItem":
9156
+ return `- ${inlineToMarkdown(content)}`;
9157
+ case "numberedListItem":
9158
+ return `${orderedIndex}. ${inlineToMarkdown(content)}`;
9159
+ case "checkListItem": {
9160
+ const checked = attrs.checked === true || attrs.checked === "true";
9161
+ return `- [${checked ? "x" : " "}] ${inlineToMarkdown(content)}`;
9162
+ }
9163
+ case "codeBlock": {
9164
+ const language = typeof attrs.language === "string" ? attrs.language : "";
9165
+ return `\`\`\`${language}
9166
+ ${inlineToMarkdown(content)}
9167
+ \`\`\``;
9168
+ }
9169
+ case "quote":
9170
+ return inlineToMarkdown(content).split("\n").map((line) => `> ${line}`).join("\n");
9171
+ case "callout": {
9172
+ const kind = attrString(attrs, "kind") || "info";
9173
+ return `> [!${kind}] ${inlineToMarkdown(content)}`;
9174
+ }
9175
+ case "table":
9176
+ return tableToMarkdown(content);
9177
+ case "mermaid":
9178
+ return `\`\`\`mermaid
9179
+ ${attrString(attrs, "code") || inlineToMarkdown(content)}
9180
+ \`\`\``;
9181
+ case "embed":
9182
+ case "richLink":
9183
+ return attrString(attrs, "url");
9184
+ case "pageEmbed":
9185
+ return `[[${attrString(attrs, "title", "nodeId")}]]`;
9186
+ case "image":
9187
+ return `![${attrString(attrs, "alt")}](${attrString(attrs, "src", "cid")})`;
9188
+ case "divider":
9189
+ case "horizontalRule":
9190
+ return "---";
9191
+ default:
9192
+ return inlineToMarkdown(content);
9193
+ }
9194
+ }
9195
+ function blockGroupToChunks(group) {
9196
+ const chunks = [];
9197
+ let orderedIndex = 0;
9198
+ for (const container of elementChildren(group)) {
9199
+ if (container.nodeName !== "blockContainer") {
9200
+ chunks.push(...blockGroupToChunks(container));
9201
+ continue;
9202
+ }
9203
+ const children = elementChildren(container);
9204
+ const content = children.find((child) => child.nodeName !== "blockGroup") ?? null;
9205
+ const childGroup = children.find((child) => child.nodeName === "blockGroup") ?? null;
9206
+ const type = content?.nodeName ?? "";
9207
+ orderedIndex = type === "numberedListItem" ? orderedIndex + 1 : 0;
9208
+ const kind = LIST_ITEM_TYPES.has(type) ? "list" : "block";
9209
+ let text3 = content ? blockContentToMarkdown(content, orderedIndex) : "";
9210
+ if (childGroup) {
9211
+ const nested = joinChunks(blockGroupToChunks(childGroup));
9212
+ if (nested) {
9213
+ const separator = kind === "list" ? "\n" : "\n\n";
9214
+ text3 = text3 ? `${text3}${separator}${indentLines(nested, " ")}` : indentLines(nested, " ");
9215
+ }
9216
+ }
9217
+ if (text3.trim()) chunks.push({ text: text3, kind });
9218
+ }
9219
+ return chunks;
9220
+ }
9221
+ function blockNoteFragmentToMarkdown(fragment) {
9222
+ return joinChunks(blockGroupToChunks(fragment));
9223
+ }
9224
+ function legacyBlockToLines(element, lines) {
9225
+ const attrs = element.getAttributes();
9226
+ switch (element.nodeName) {
9227
+ case "paragraph": {
9228
+ const text3 = inlineToMarkdown(element);
9229
+ if (text3.trim()) lines.push(text3);
9230
+ break;
9231
+ }
9232
+ case "heading": {
9233
+ const level = Math.min(Math.max(Number(attrs.level ?? 1) || 1, 1), 6);
9234
+ lines.push(`${"#".repeat(level)} ${inlineToMarkdown(element)}`);
9235
+ break;
9236
+ }
9237
+ case "codeBlock": {
9238
+ const language = typeof attrs.language === "string" ? attrs.language : "";
9239
+ lines.push(`\`\`\`${language}
9240
+ ${inlineToMarkdown(element)}
9241
+ \`\`\``);
9242
+ break;
9243
+ }
9244
+ case "blockquote":
9245
+ case "callout": {
9246
+ const inner = [];
9247
+ legacyChildrenToLines(element, inner);
9248
+ lines.push(inner.map((line) => indentLines(line, "> ").replace(/^> $/gm, ">")).join("\n>\n"));
9249
+ break;
9250
+ }
9251
+ case "bulletList":
9252
+ legacyListToLines(element, false, lines);
9253
+ break;
9254
+ case "orderedList":
9255
+ legacyListToLines(element, true, lines);
9256
+ break;
9257
+ case "taskList":
9258
+ legacyTaskListToLines(element, lines);
9259
+ break;
9260
+ case "horizontalRule":
9261
+ lines.push("---");
9262
+ break;
9263
+ case "image":
9264
+ lines.push(`![${attrString(attrs, "alt")}](${attrString(attrs, "src", "cid")})`);
9265
+ break;
9266
+ case "embed":
9267
+ case "richLink":
9268
+ lines.push(attrString(attrs, "url"));
9269
+ break;
9270
+ case "pageEmbed":
9271
+ lines.push(`[[${attrString(attrs, "title", "nodeId")}]]`);
9272
+ break;
9273
+ case "mermaid":
9274
+ lines.push(`\`\`\`mermaid
9275
+ ${attrString(attrs, "code") || inlineToMarkdown(element)}
9276
+ \`\`\``);
9277
+ break;
9278
+ default:
9279
+ if (element.length > 0 && elementChildren(element).length > 0) {
9280
+ legacyChildrenToLines(element, lines);
9281
+ } else {
9282
+ const text3 = inlineToMarkdown(element);
9283
+ if (text3.trim()) lines.push(text3);
9284
+ }
9285
+ }
9286
+ }
9287
+ function legacyListToLines(element, ordered, lines) {
9288
+ const items = [];
9289
+ let index = 1;
9290
+ for (const child of elementChildren(element)) {
9291
+ if (child.nodeName !== "listItem") continue;
9292
+ const inner = [];
9293
+ legacyChildrenToLines(child, inner);
9294
+ const marker = ordered ? `${index}.` : "-";
9295
+ items.push(`${marker} ${indentLines(inner.join("\n"), " ").trimStart()}`);
9296
+ index += 1;
9297
+ }
9298
+ if (items.length > 0) lines.push(items.join("\n"));
9299
+ }
9300
+ function legacyTaskListToLines(element, lines) {
9301
+ const items = [];
9302
+ for (const child of elementChildren(element)) {
9303
+ if (child.nodeName !== "taskItem") continue;
9304
+ const checkedAttr = child.getAttribute("checked");
9305
+ const checked = checkedAttr === true || checkedAttr === "true";
9306
+ const inner = [];
9307
+ legacyChildrenToLines(child, inner);
9308
+ items.push(`- [${checked ? "x" : " "}] ${indentLines(inner.join("\n"), " ").trimStart()}`);
9309
+ }
9310
+ if (items.length > 0) lines.push(items.join("\n"));
9311
+ }
9312
+ function legacyChildrenToLines(element, lines) {
9313
+ for (let i = 0; i < element.length; i++) {
9314
+ const child = element.get(i);
9315
+ if (child instanceof Y.XmlElement) {
9316
+ legacyBlockToLines(child, lines);
9317
+ } else if (child instanceof Y.XmlText) {
9318
+ const text3 = textToMarkdown(child);
9319
+ if (text3.trim()) lines.push(text3);
9320
+ }
9321
+ }
9322
+ }
9323
+ function legacyFragmentToMarkdown(fragment) {
9324
+ const lines = [];
9325
+ legacyChildrenToLines(fragment, lines);
9326
+ return lines.join("\n\n");
9327
+ }
9328
+ function xnetPageFragmentToMarkdown(doc, options = {}) {
9329
+ const fragment = doc.getXmlFragment(options.field ?? XNET_PAGE_FRAGMENT_FIELD);
9330
+ if (fragment.length > 0) return blockNoteFragmentToMarkdown(fragment);
9331
+ const legacy = doc.getXmlFragment(options.legacyField ?? XNET_PAGE_LEGACY_FRAGMENT_FIELD);
9332
+ if (legacy.length > 0) return legacyFragmentToMarkdown(legacy);
9333
+ return "";
9334
+ }
9335
+ var HEADING_PATTERN = /^(#{1,6})\s+(.*)$/;
9336
+ var FENCE_PATTERN = /^```([A-Za-z0-9_-]*)\s*$/;
9337
+ var LIST_ITEM_PATTERN = /^(\s*)(?:([-*+])|(\d+)[.)])\s+(.*)$/;
9338
+ var CHECK_PATTERN = /^\[([ xX])\]\s+(.*)$/;
9339
+ var CALLOUT_PATTERN = /^\[!([a-z][a-z0-9-]*)\]\s?(.*)$/i;
9340
+ function parseMarkdownBlocks(markdown) {
9341
+ const lines = markdown.replace(/\r\n/g, "\n").split("\n");
9342
+ const blocks = [];
9343
+ let listStack = [];
9344
+ let index = 0;
9345
+ const pushTop = (block) => {
9346
+ blocks.push(block);
9347
+ listStack = [];
9348
+ };
9349
+ while (index < lines.length) {
9350
+ const line = lines[index];
9351
+ if (!line.trim()) {
9352
+ index += 1;
9353
+ listStack = [];
9354
+ continue;
9355
+ }
9356
+ const fence = FENCE_PATTERN.exec(line.trim());
9357
+ if (fence) {
9358
+ const code = [];
9359
+ index += 1;
9360
+ while (index < lines.length && !/^```\s*$/.test(lines[index].trim())) {
9361
+ code.push(lines[index]);
9362
+ index += 1;
9363
+ }
9364
+ index += 1;
9365
+ pushTop({
9366
+ type: "codeBlock",
9367
+ props: fence[1] ? { language: fence[1] } : {},
9368
+ text: code.join("\n"),
9369
+ children: []
9370
+ });
9371
+ continue;
9372
+ }
9373
+ const heading = HEADING_PATTERN.exec(line);
9374
+ if (heading) {
9375
+ pushTop({
9376
+ type: "heading",
9377
+ props: { level: heading[1].length },
9378
+ text: heading[2],
9379
+ children: []
9380
+ });
9381
+ index += 1;
9382
+ continue;
9383
+ }
9384
+ const listItem = LIST_ITEM_PATTERN.exec(line);
9385
+ if (listItem) {
9386
+ const indent = Math.floor(listItem[1].replace(/\t/g, " ").length / 2);
9387
+ const rest = listItem[4];
9388
+ const check = listItem[2] ? CHECK_PATTERN.exec(rest) : null;
9389
+ const block = check ? {
9390
+ type: "checkListItem",
9391
+ props: { checked: check[1] !== " " },
9392
+ text: check[2],
9393
+ children: []
9394
+ } : {
9395
+ type: listItem[3] ? "numberedListItem" : "bulletListItem",
9396
+ props: {},
9397
+ text: rest,
9398
+ children: []
9399
+ };
9400
+ while (listStack.length > 0 && listStack[listStack.length - 1].indent >= indent) {
9401
+ listStack.pop();
9402
+ }
9403
+ const parent = listStack[listStack.length - 1];
9404
+ if (parent) {
9405
+ parent.block.children.push(block);
9406
+ } else {
9407
+ blocks.push(block);
9408
+ }
9409
+ listStack.push({ indent, block });
9410
+ index += 1;
9411
+ continue;
9412
+ }
9413
+ if (line.startsWith(">")) {
9414
+ const quoted = [];
9415
+ while (index < lines.length && lines[index].startsWith(">")) {
9416
+ quoted.push(lines[index].replace(/^>\s?/, ""));
9417
+ index += 1;
9418
+ }
9419
+ const callout = CALLOUT_PATTERN.exec(quoted[0] ?? "");
9420
+ if (callout) {
9421
+ pushTop({
9422
+ type: "callout",
9423
+ props: { kind: callout[1].toLowerCase() },
9424
+ text: [callout[2], ...quoted.slice(1)].filter((part) => part !== "").join("\n"),
9425
+ children: []
9426
+ });
9427
+ } else {
9428
+ pushTop({ type: "quote", props: {}, text: quoted.join("\n"), children: [] });
9429
+ }
9430
+ continue;
9431
+ }
9432
+ const paragraph = [line];
9433
+ index += 1;
9434
+ while (index < lines.length) {
9435
+ const next = lines[index];
9436
+ if (!next.trim() || HEADING_PATTERN.test(next) || FENCE_PATTERN.test(next.trim()) || LIST_ITEM_PATTERN.test(next) || next.startsWith(">")) {
9437
+ break;
9438
+ }
9439
+ paragraph.push(next);
9440
+ index += 1;
9441
+ }
9442
+ pushTop({ type: "paragraph", props: {}, text: paragraph.join("\n"), children: [] });
9443
+ }
9444
+ return blocks;
9445
+ }
9446
+ var blockIdCounter = 0;
9447
+ function defaultBlockId() {
9448
+ const cryptoApi = globalThis.crypto;
9449
+ if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
9450
+ blockIdCounter += 1;
9451
+ return `ai-block-${Date.now().toString(36)}-${blockIdCounter}`;
9452
+ }
9453
+ function setAttr(element, name, value) {
9454
+ element.setAttribute(name, value);
9455
+ }
9456
+ var WIKILINK_SPLIT = /(\[\[[^\]\n]+\]\])/;
9457
+ function inlineNodesForText(text3) {
9458
+ const nodes = [];
9459
+ for (const part of text3.split(WIKILINK_SPLIT)) {
9460
+ if (!part) continue;
9461
+ const wikilink = /^\[\[([^\]\n]+)\]\]$/.exec(part);
9462
+ if (wikilink) {
9463
+ const atom = new Y.XmlElement("wikilink");
9464
+ setAttr(atom, "title", wikilink[1]);
9465
+ setAttr(atom, "href", "");
9466
+ nodes.push(atom);
9467
+ } else {
9468
+ nodes.push(new Y.XmlText(part));
9469
+ }
9470
+ }
9471
+ return nodes;
9472
+ }
9473
+ function blockToYElement(block, generateBlockId) {
9474
+ const container = new Y.XmlElement("blockContainer");
9475
+ setAttr(container, "id", generateBlockId());
9476
+ const content = new Y.XmlElement(block.type);
9477
+ for (const [key, value] of Object.entries(block.props)) setAttr(content, key, value);
9478
+ if (block.type === "codeBlock") {
9479
+ if (block.text) content.insert(0, [new Y.XmlText(block.text)]);
9480
+ } else if (block.text) {
9481
+ content.insert(0, inlineNodesForText(block.text));
9482
+ }
9483
+ container.insert(0, [content]);
9484
+ if (block.children.length > 0) {
9485
+ const group = new Y.XmlElement("blockGroup");
9486
+ group.insert(
9487
+ 0,
9488
+ block.children.map((child) => blockToYElement(child, generateBlockId))
9489
+ );
9490
+ container.insert(1, [group]);
9491
+ }
9492
+ return container;
9493
+ }
9494
+ function replaceXNetPageFragmentWithMarkdown(doc, markdown, options = {}) {
9495
+ const fragment = doc.getXmlFragment(options.field ?? XNET_PAGE_FRAGMENT_FIELD);
9496
+ const generateBlockId = options.generateBlockId ?? defaultBlockId;
9497
+ const blocks = parseMarkdownBlocks(markdown);
9498
+ doc.transact(() => {
9499
+ if (fragment.length > 0) fragment.delete(0, fragment.length);
9500
+ if (blocks.length === 0) return;
9501
+ const group = new Y.XmlElement("blockGroup");
9502
+ fragment.insert(0, [group]);
9503
+ group.insert(
9504
+ 0,
9505
+ blocks.map((block) => blockToYElement(block, generateBlockId))
9506
+ );
9507
+ });
9508
+ }
9509
+ function createBlockNotePageMarkdownAdapter(options) {
9510
+ const field = options.field ?? XNET_PAGE_FRAGMENT_FIELD;
9511
+ return {
9512
+ applyMarkdown: async ({ pageId, bodyMarkdown }) => {
9513
+ const doc = await options.resolveDoc(pageId);
9514
+ if (!doc) {
9515
+ throw new Error(`No document available for page ${pageId}`);
9516
+ }
9517
+ replaceXNetPageFragmentWithMarkdown(doc, bodyMarkdown, {
9518
+ field,
9519
+ ...options.generateBlockId ? { generateBlockId: options.generateBlockId } : {}
9520
+ });
9521
+ return { mode: "blocknote-yjs", yjsField: field };
9522
+ },
9523
+ readMarkdown: async (pageId) => {
9524
+ const doc = await options.resolveDoc(pageId);
9525
+ return doc ? xnetPageFragmentToMarkdown(doc, { field }) : null;
9526
+ }
9527
+ };
9528
+ }
9529
+
9010
9530
  // src/sandbox/ast-validator.ts
9011
9531
  import * as acorn from "acorn";
9012
9532
  var FORBIDDEN_GLOBALS = /* @__PURE__ */ new Set([
@@ -10128,12 +10648,12 @@ var createCapabilities = (overrides = {}) => ({
10128
10648
  ...overrides
10129
10649
  });
10130
10650
  var normalizeBaseUrl = (baseUrl) => baseUrl.replace(/\/+$/, "");
10131
- var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
10651
+ var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
10132
10652
  var parseToolArguments = (value) => {
10133
10653
  if (!value) return {};
10134
10654
  try {
10135
10655
  const parsed = JSON.parse(value);
10136
- return isRecord5(parsed) ? parsed : { value: parsed };
10656
+ return isRecord6(parsed) ? parsed : { value: parsed };
10137
10657
  } catch {
10138
10658
  return { raw: value };
10139
10659
  }
@@ -12434,6 +12954,8 @@ export {
12434
12954
  WebLLMProvider,
12435
12955
  WebhookEmitter,
12436
12956
  XNET_MARKDOWN_DIRECTIVE_SPECS,
12957
+ XNET_PAGE_FRAGMENT_FIELD,
12958
+ XNET_PAGE_LEGACY_FRAGMENT_FIELD,
12437
12959
  agentToolToExtraTool,
12438
12960
  agentToolsAsExtraTools,
12439
12961
  aggregateRatings,
@@ -12443,6 +12965,7 @@ export {
12443
12965
  assertSystemAudio,
12444
12966
  assistTurnProvenance,
12445
12967
  attachAiPlanValidation,
12968
+ blockNoteFragmentToMarkdown,
12446
12969
  buildAirtableConnector,
12447
12970
  buildDiscordAction,
12448
12971
  buildEmailAction,
@@ -12470,6 +12993,7 @@ export {
12470
12993
  createAiOperation,
12471
12994
  createAiSurfaceService,
12472
12995
  createAiValidationResult,
12996
+ createBlockNotePageMarkdownAdapter,
12473
12997
  createCanvasErpPrototypeRiskSummary,
12474
12998
  createCanvasErpPrototypeScenario,
12475
12999
  createCanvasPluginFixtureCards,
@@ -12537,7 +13061,7 @@ export {
12537
13061
  isOllamaAvailable,
12538
13062
  isPaidPricing,
12539
13063
  isPresetWorkspaceId,
12540
- isSchemaDefiningExtension,
13064
+ isSchemaDefiningContribution,
12541
13065
  isSchemaReadAllowed,
12542
13066
  isSchemaWriteAllowed,
12543
13067
  isScriptNode,
@@ -12545,6 +13069,7 @@ export {
12545
13069
  isSystemAudioAllowed,
12546
13070
  ladderTierForTrust,
12547
13071
  leaveWithEverything,
13072
+ legacyFragmentToMarkdown,
12548
13073
  listOllamaModels,
12549
13074
  matchSchemaIri,
12550
13075
  moveSlot,
@@ -12570,6 +13095,7 @@ export {
12570
13095
  renderMarkdownLineDiff,
12571
13096
  renderMarkdownReviewDiff,
12572
13097
  renderSelectionPrompt,
13098
+ replaceXNetPageFragmentWithMarkdown,
12573
13099
  requiresCapabilityReprompt,
12574
13100
  resolveImporters,
12575
13101
  resolveInstallOrder,
@@ -12601,5 +13127,6 @@ export {
12601
13127
  verifyProvenance,
12602
13128
  warnOnEditorSchemaRisks,
12603
13129
  wrapCliConnector,
12604
- writeModeFor
13130
+ writeModeFor,
13131
+ xnetPageFragmentToMarkdown
12605
13132
  };