@fruggr/zendesk-mcp-server 3.7.0 → 3.9.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 CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm version](https://img.shields.io/npm/v/@fruggr/zendesk-mcp-server?logo=npm&color=cb3837)](https://www.npmjs.com/package/@fruggr/zendesk-mcp-server)
6
6
  [![License: MIT](https://img.shields.io/npm/l/@fruggr/zendesk-mcp-server?color=blue)](LICENSE)
7
7
  [![Node.js](https://img.shields.io/node/v/@fruggr/zendesk-mcp-server?logo=nodedotjs&logoColor=white&color=339933)](https://nodejs.org)
8
- [![Container base](https://img.shields.io/static/v1?label=container%20base&message=dhi.io%2Fnode%3A24.22.1-alpine3.24&logo=docker&logoColor=white&color=2496ED)](https://github.com/fruggr/zendesk-mcp-server/blob/main/docs/http-deployment.md#container)
8
+ [![Container base](https://img.shields.io/static/v1?label=container%20base&message=dhi.io%2Fnode%3A24.22.2-alpine3.24&logo=docker&logoColor=white&color=2496ED)](https://github.com/fruggr/zendesk-mcp-server/blob/main/docs/http-deployment.md#container)
9
9
 
10
10
  A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
11
11
  puts Zendesk inside your AI assistant, for **both sides of the conversation**.
@@ -14,11 +14,14 @@ puts Zendesk inside your AI assistant, for **both sides of the conversation**.
14
14
  translates articles while keeping the languages in sync; and handles Support
15
15
  tickets end to end, comments, triage and image attachments included.
16
16
 
17
- **For your customers**: it opens the same door the Help Center's "Submit a
18
- request" form does. They pick the kind of request, get walked through the
19
- questions that form actually asks, attach a screenshot, then follow the
20
- ticket — read the replies, answer back, close it when it's resolved. See
21
- [End-user mode](#end-user-mode).
17
+ **For your customers**: the Help Center's "Submit a request" form, in plain
18
+ language: pick the request, answer its questions, follow the replies, close it.
19
+ See [End-user mode](#end-user-mode).
20
+
21
+ **For your Zendesk admins**: teach the assistant how *your* team works, with
22
+ house tone, lexicon, procedures and ready-made workflows, from a dedicated
23
+ back-office, with no redeploy. See
24
+ [Context and customizations](#context-and-customizations).
22
25
 
23
26
  It all happens in plain language, without switching apps.
24
27
 
@@ -49,6 +52,8 @@ then calls the right tools on your behalf.
49
52
  - Draft and maintain knowledge-base articles. You can write a new one, or revise
50
53
  a large one a single section at a time, so the whole HTML body never has to
51
54
  round-trip through the model.
55
+ - Follow your team's playbook. Instructions, prompts and skills written by your
56
+ admins reach every user's assistant, whatever MCP client they use.
52
57
  - Submit and follow a request as a customer, not an agent. Choose between the
53
58
  kinds of request the vendor offers, answer only the questions that form asks,
54
59
  and then track it: what was replied, what you replied, and whether it's done.
@@ -81,11 +86,16 @@ differently.
81
86
  into namespace proxies, or collapse everything into a single unified tool. You
82
87
  can also filter by namespace or down to read-only operations, so each context
83
88
  loads only the surface it needs (see [Tool surface](#tool-surface)).
84
- - Two deployment shapes, same auth story. Run it on your laptop as a stdio MCP
85
- server, or deploy it as a private remote MCP server reached over HTTP, with one
86
- Zendesk session per request and each client carrying its own user's token.
87
- - A lean stack: the official MCP TypeScript SDK (`@modelcontextprotocol/server`) plus `zod`, speaking to
88
- the Zendesk Support and Help Center (Guide) APIs.
89
+ - Your practices ship with the server. Most teams hand-distribute a skill or a
90
+ rules file per AI client. Here admins author instructions, prompts and skills
91
+ once, inside the server, behind a back-office reserved to Zendesk admins, and
92
+ every MCP client receives them. Skills fall back to prompts on clients that
93
+ don't support them yet.
94
+ - Two deployment shapes, same auth story, on a lean stack. Run it on your laptop
95
+ as a stdio MCP server, or deploy it as a private remote MCP server reached over
96
+ HTTP, each client carrying its own user's token; underneath, the official MCP
97
+ TypeScript SDK plus `zod`, speaking to the Zendesk Support and Help Center
98
+ (Guide) APIs.
89
99
 
90
100
  Look elsewhere when:
91
101
 
@@ -316,19 +326,19 @@ A customer can do less than an agent. That's the point, not a gap:
316
326
  won't let the requester solve it, so the tool says so rather than pretending.
317
327
  - **No search across the ticket base**, no user lookups, no views, no macros.
318
328
 
319
- ## Help Center context
329
+ ## Context and customizations
320
330
 
321
- Beyond tools, the server hands the LLM the structure of *your* Help Center: the
322
- active locales, the category → section tree with IDs, the visibility segments
323
- and the permission groups. With those in hand it uses real IDs instead of
324
- guessing or fuzzy-matching names. It all arrives through MCP-native channels,
325
- namely the `instructions` blob sent on `initialize` plus pull-only resources for
326
- the topology and for reading (or pinning) individual articles. The resources are
327
- fetched with the caller's own token, and clients that don't support resources
328
- ignore them silently.
331
+ The assistant gets two kinds of context besides tools:
329
332
 
330
- What's exposed, what the promoted-article pre-listing costs in requests, and how
331
- to turn each piece off: **[docs/help-center-context.md](docs/help-center-context.md)**.
333
+ - **Built in**: the structure of your Help Center (locales, the category →
334
+ section tree with IDs, segments, permission groups), so it uses real IDs
335
+ instead of guessing, fetched with the caller's own token. Details:
336
+ [docs/help-center-context.md](docs/help-center-context.md).
337
+ - **Yours**: instructions, prompts and skills your Zendesk admins write from
338
+ `/mcp/admin`, a second connector on the same server. A guided `setup` prompt
339
+ walks them through it and reminds them what is already built in. Nothing is
340
+ stored in Zendesk, and no workflow is imposed: each team writes its own.
341
+ Details: [docs/customizations.md](docs/customizations.md).
332
342
 
333
343
  ## Configuration
334
344
 
@@ -30,7 +30,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
30
  SOFTWARE.
31
31
  ```
32
32
 
33
- ## @modelcontextprotocol/core@2.3.1
33
+ ## @modelcontextprotocol/core@2.4.0
34
34
 
35
35
  License: Apache-2.0
36
36
 
@@ -253,7 +253,7 @@ CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for
253
253
  the full license text.
254
254
  ```
255
255
 
256
- ## @modelcontextprotocol/node@2.1.1
256
+ ## @modelcontextprotocol/node@2.1.2
257
257
 
258
258
  License: Apache-2.0
259
259
 
@@ -476,7 +476,7 @@ CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for
476
476
  the full license text.
477
477
  ```
478
478
 
479
- ## @modelcontextprotocol/server@2.3.1
479
+ ## @modelcontextprotocol/server@2.4.0
480
480
 
481
481
  License: Apache-2.0
482
482
 
@@ -2035,7 +2035,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2035
2035
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2036
2036
  ```
2037
2037
 
2038
- ## hast-util-to-html@9.0.5
2038
+ ## hast-util-to-html@9.0.6
2039
2039
 
2040
2040
  License: MIT
2041
2041
 
@@ -2480,7 +2480,7 @@ The above copyright notice and this permission notice shall be included in all c
2480
2480
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2481
2481
  ```
2482
2482
 
2483
- ## jose@6.2.13
2483
+ ## jose@6.2.14
2484
2484
 
2485
2485
  License: MIT
2486
2486
 
@@ -48717,7 +48717,7 @@ function stringifyEntities(value, options) {
48717
48717
  return core(value, Object.assign({ format: formatSmart }, options));
48718
48718
  }
48719
48719
  //#endregion
48720
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/comment.js
48720
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/comment.js
48721
48721
  /**
48722
48722
  * @import {Comment, Parents} from 'hast'
48723
48723
  * @import {State} from '../index.js'
@@ -48731,7 +48731,7 @@ const commentEntitySubset = ["<", ">"];
48731
48731
  * @param {Comment} node
48732
48732
  * Node to handle.
48733
48733
  * @param {number | undefined} _1
48734
- * Index of `node` in `parent.
48734
+ * Index of `node` in `parent`.
48735
48735
  * @param {Parents | undefined} _2
48736
48736
  * Parent of `node`.
48737
48737
  * @param {State} state
@@ -48742,14 +48742,19 @@ const commentEntitySubset = ["<", ">"];
48742
48742
  function comment$3(node, _1, _2, state) {
48743
48743
  return state.settings.bogusComments ? "<?" + stringifyEntities(node.value, Object.assign({}, state.settings.characterReferences, { subset: bogusCommentEntitySubset })) + ">" : "<!--" + node.value.replace(htmlCommentRegex, encode) + "-->";
48744
48744
  /**
48745
+ * Encode a dangerous character.
48746
+ *
48745
48747
  * @param {string} $0
48748
+ * Character.
48749
+ * @returns {string}
48750
+ * Encoded character.
48746
48751
  */
48747
48752
  function encode($0) {
48748
48753
  return stringifyEntities($0, Object.assign({}, state.settings.characterReferences, { subset: commentEntitySubset }));
48749
48754
  }
48750
48755
  }
48751
48756
  //#endregion
48752
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/doctype.js
48757
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/doctype.js
48753
48758
  /**
48754
48759
  * @import {Doctype, Parents} from 'hast'
48755
48760
  * @import {State} from '../index.js'
@@ -48760,7 +48765,7 @@ function comment$3(node, _1, _2, state) {
48760
48765
  * @param {Doctype} _1
48761
48766
  * Node to handle.
48762
48767
  * @param {number | undefined} _2
48763
- * Index of `node` in `parent.
48768
+ * Index of `node` in `parent`.
48764
48769
  * @param {Parents | undefined} _3
48765
48770
  * Parent of `node`.
48766
48771
  * @param {State} state
@@ -48903,7 +48908,7 @@ function empty$1(value) {
48903
48908
  return value.replace(re, "") === "";
48904
48909
  }
48905
48910
  //#endregion
48906
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/omission/util/siblings.js
48911
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/omission/util/siblings.js
48907
48912
  /**
48908
48913
  * @import {Parents, RootContent} from 'hast'
48909
48914
  */
@@ -48915,6 +48920,9 @@ const emptyChildren$1 = [];
48915
48920
  * Factory to check siblings in a direction.
48916
48921
  *
48917
48922
  * @param {number} increment
48923
+ * Direction.
48924
+ * @returns {typeof sibling}
48925
+ * Check.
48918
48926
  */
48919
48927
  function siblings(increment) {
48920
48928
  return sibling;
@@ -48944,7 +48952,7 @@ function siblings(increment) {
48944
48952
  }
48945
48953
  }
48946
48954
  //#endregion
48947
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/omission/omission.js
48955
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/omission/omission.js
48948
48956
  /**
48949
48957
  * @import {Element, Parents} from 'hast'
48950
48958
  */
@@ -48959,7 +48967,6 @@ function siblings(increment) {
48959
48967
  * Parent of element.
48960
48968
  * @returns {boolean}
48961
48969
  * Whether to omit a tag.
48962
- *
48963
48970
  */
48964
48971
  const own$10 = {}.hasOwnProperty;
48965
48972
  /**
@@ -48983,7 +48990,7 @@ function omission(handlers) {
48983
48990
  }
48984
48991
  }
48985
48992
  //#endregion
48986
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/omission/closing.js
48993
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/omission/closing.js
48987
48994
  /**
48988
48995
  * @import {Element, Parents} from 'hast'
48989
48996
  */
@@ -49070,7 +49077,7 @@ function body$1(_, index, parent) {
49070
49077
  */
49071
49078
  function p$2(_, index, parent) {
49072
49079
  const next = siblingAfter(parent, index);
49073
- return next ? next.type === "element" && (next.tagName === "address" || next.tagName === "article" || next.tagName === "aside" || next.tagName === "blockquote" || next.tagName === "details" || next.tagName === "div" || next.tagName === "dl" || next.tagName === "fieldset" || next.tagName === "figcaption" || next.tagName === "figure" || next.tagName === "footer" || next.tagName === "form" || next.tagName === "h1" || next.tagName === "h2" || next.tagName === "h3" || next.tagName === "h4" || next.tagName === "h5" || next.tagName === "h6" || next.tagName === "header" || next.tagName === "hgroup" || next.tagName === "hr" || next.tagName === "main" || next.tagName === "menu" || next.tagName === "nav" || next.tagName === "ol" || next.tagName === "p" || next.tagName === "pre" || next.tagName === "section" || next.tagName === "table" || next.tagName === "ul") : !parent || !(parent.type === "element" && (parent.tagName === "a" || parent.tagName === "audio" || parent.tagName === "del" || parent.tagName === "ins" || parent.tagName === "map" || parent.tagName === "noscript" || parent.tagName === "video"));
49080
+ return next ? next.type === "element" && (next.tagName === "address" || next.tagName === "article" || next.tagName === "aside" || next.tagName === "blockquote" || next.tagName === "details" || next.tagName === "div" || next.tagName === "dl" || next.tagName === "fieldset" || next.tagName === "figcaption" || next.tagName === "figure" || next.tagName === "footer" || next.tagName === "form" || next.tagName === "h1" || next.tagName === "h2" || next.tagName === "h3" || next.tagName === "h4" || next.tagName === "h5" || next.tagName === "h6" || next.tagName === "header" || next.tagName === "hgroup" || next.tagName === "hr" || next.tagName === "main" || next.tagName === "menu" || next.tagName === "nav" || next.tagName === "ol" || next.tagName === "p" || next.tagName === "pre" || next.tagName === "section" || next.tagName === "table" || next.tagName === "ul") : !parent || !(parent.type === "element" && (parent.tagName === "a" || parent.tagName === "audio" || parent.tagName === "del" || parent.tagName === "ins" || parent.tagName === "map" || parent.tagName === "noscript" || parent.tagName === "video" || parent.tagName.includes("-")));
49074
49081
  }
49075
49082
  /**
49076
49083
  * Whether to omit `</li>`.
@@ -49248,7 +49255,7 @@ function cells(_, index, parent) {
49248
49255
  return !next || next.type === "element" && (next.tagName === "td" || next.tagName === "th");
49249
49256
  }
49250
49257
  //#endregion
49251
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/omission/opening.js
49258
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/omission/opening.js
49252
49259
  /**
49253
49260
  * @import {Element, Parents} from 'hast'
49254
49261
  */
@@ -49318,8 +49325,8 @@ function body(node) {
49318
49325
  */
49319
49326
  function colgroup(node, index, parent) {
49320
49327
  const previous = siblingBefore(parent, index);
49321
- const head = siblingAfter(node, -1, true);
49322
49328
  if (parent && previous && previous.type === "element" && previous.tagName === "colgroup" && closing(previous, parent.children.indexOf(previous), parent)) return false;
49329
+ const head = siblingAfter(node, -1, true);
49323
49330
  return Boolean(head && head.type === "element" && head.tagName === "col");
49324
49331
  }
49325
49332
  /**
@@ -49336,12 +49343,12 @@ function colgroup(node, index, parent) {
49336
49343
  */
49337
49344
  function tbody(node, index, parent) {
49338
49345
  const previous = siblingBefore(parent, index);
49339
- const head = siblingAfter(node, -1);
49340
49346
  if (parent && previous && previous.type === "element" && (previous.tagName === "thead" || previous.tagName === "tbody") && closing(previous, parent.children.indexOf(previous), parent)) return false;
49347
+ const head = siblingAfter(node, -1);
49341
49348
  return Boolean(head && head.type === "element" && head.tagName === "tr");
49342
49349
  }
49343
49350
  //#endregion
49344
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/element.js
49351
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/element.js
49345
49352
  /**
49346
49353
  * @import {Element, Parents, Properties} from 'hast'
49347
49354
  * @import {State} from '../index.js'
@@ -49362,12 +49369,22 @@ const constants = {
49362
49369
  double: [["\"&".split(""), "\"&'`".split("")], ["\0\"&".split(""), "\0\"&'`".split("")]]
49363
49370
  };
49364
49371
  /**
49372
+ * SVG elements whose content is HTML.
49373
+ *
49374
+ * @type {ReadonlySet<string>}
49375
+ */
49376
+ const htmlIntegrationPoints = /* @__PURE__ */ new Set([
49377
+ "desc",
49378
+ "foreignObject",
49379
+ "title"
49380
+ ]);
49381
+ /**
49365
49382
  * Serialize an element node.
49366
49383
  *
49367
49384
  * @param {Element} node
49368
49385
  * Node to handle.
49369
49386
  * @param {number | undefined} index
49370
- * Index of `node` in `parent.
49387
+ * Index of `node` in `parent`.
49371
49388
  * @param {Parents | undefined} parent
49372
49389
  * Parent of `node`.
49373
49390
  * @param {State} state
@@ -49376,22 +49393,21 @@ const constants = {
49376
49393
  * Serialized node.
49377
49394
  */
49378
49395
  function element$4(node, index, parent, state) {
49379
- const schema = state.schema;
49396
+ const { schema } = state;
49380
49397
  const omit = schema.space === "svg" ? false : state.settings.omitOptionalTags;
49381
49398
  let selfClosing = schema.space === "svg" ? state.settings.closeEmptyElements : state.settings.voids.includes(node.tagName.toLowerCase());
49382
49399
  /** @type {Array<string>} */
49383
49400
  const parts = [];
49384
- /** @type {string} */
49385
- let last;
49386
49401
  if (schema.space === "html" && node.tagName === "svg") state.schema = svg;
49387
49402
  const attributes = serializeAttributes(state, node.properties);
49403
+ if (state.schema.space === "svg" && htmlIntegrationPoints.has(node.tagName)) state.schema = html$4;
49388
49404
  const content = state.all(schema.space === "html" && node.tagName === "template" ? node.content : node);
49389
49405
  state.schema = schema;
49390
49406
  if (content) selfClosing = false;
49391
49407
  if (attributes || !omit || !opening(node, index, parent)) {
49392
49408
  parts.push("<", node.tagName, attributes ? " " + attributes : "");
49393
49409
  if (selfClosing && (schema.space === "svg" || state.settings.closeSelfClosing)) {
49394
- last = attributes.charAt(attributes.length - 1);
49410
+ const last = attributes.charAt(attributes.length - 1);
49395
49411
  if (!state.settings.tightSelfClosing || last === "/" || last && last !== "\"" && last !== "'") parts.push(" ");
49396
49412
  parts.push("/");
49397
49413
  }
@@ -49402,9 +49418,14 @@ function element$4(node, index, parent, state) {
49402
49418
  return parts.join("");
49403
49419
  }
49404
49420
  /**
49421
+ * Serialize all attributes.
49422
+ *
49405
49423
  * @param {State} state
49424
+ * Info passed around about the current state.
49406
49425
  * @param {Properties | null | undefined} properties
49426
+ * Properties.
49407
49427
  * @returns {string}
49428
+ * Serialized attributes.
49408
49429
  */
49409
49430
  function serializeAttributes(state, properties) {
49410
49431
  /** @type {Array<string>} */
@@ -49425,18 +49446,21 @@ function serializeAttributes(state, properties) {
49425
49446
  return values.join("");
49426
49447
  }
49427
49448
  /**
49449
+ * Serialize an attribute.
49450
+ *
49428
49451
  * @param {State} state
49452
+ * Info passed around about the current state.
49429
49453
  * @param {string} key
49454
+ * Property name.
49430
49455
  * @param {Properties[keyof Properties]} value
49456
+ * Property value.
49431
49457
  * @returns {string}
49458
+ * Serialized attribute.
49432
49459
  */
49433
49460
  function serializeAttribute(state, key, value) {
49434
49461
  const info = find(state.schema, key);
49435
49462
  const x = state.settings.allowParseErrors && state.schema.space === "html" ? 0 : 1;
49436
49463
  const y = state.settings.allowDangerousCharacters ? 0 : 1;
49437
- let quote = state.quote;
49438
- /** @type {string | undefined} */
49439
- let result;
49440
49464
  if (info.overloadedBoolean && (value === info.attribute || value === "")) value = true;
49441
49465
  else if ((info.boolean || info.overloadedBoolean) && (typeof value !== "string" || value === info.attribute || value === "")) value = Boolean(value);
49442
49466
  if (value === null || value === void 0 || value === false || typeof value === "number" && Number.isNaN(value)) return "";
@@ -49444,11 +49468,14 @@ function serializeAttribute(state, key, value) {
49444
49468
  if (value === true) return name;
49445
49469
  value = Array.isArray(value) ? (info.commaSeparated ? stringify$1 : stringify)(value, { padLeft: !state.settings.tightCommaSeparatedLists }) : String(value);
49446
49470
  if (state.settings.collapseEmptyAttributes && !value) return name;
49471
+ /** @type {string | undefined} */
49472
+ let result;
49447
49473
  if (state.settings.preferUnquoted) result = stringifyEntities(value, Object.assign({}, state.settings.characterReferences, {
49448
49474
  attribute: true,
49449
49475
  subset: constants.unquoted[x][y]
49450
49476
  }));
49451
49477
  if (result !== value) {
49478
+ let { quote } = state;
49452
49479
  if (state.settings.quoteSmart && ccount(value, quote) > ccount(value, state.alternative)) quote = state.alternative;
49453
49480
  result = quote + stringifyEntities(value, Object.assign({}, state.settings.characterReferences, {
49454
49481
  subset: (quote === "'" ? constants.single : constants.double)[x][y],
@@ -49458,7 +49485,7 @@ function serializeAttribute(state, key, value) {
49458
49485
  return name + (result ? "=" + result : result);
49459
49486
  }
49460
49487
  //#endregion
49461
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/text.js
49488
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/text.js
49462
49489
  /**
49463
49490
  * @import {Parents, Text} from 'hast'
49464
49491
  * @import {Raw} from 'mdast-util-to-hast'
@@ -49471,7 +49498,7 @@ const textEntitySubset = ["<", "&"];
49471
49498
  * @param {Raw | Text} node
49472
49499
  * Node to handle.
49473
49500
  * @param {number | undefined} _
49474
- * Index of `node` in `parent.
49501
+ * Index of `node` in `parent`.
49475
49502
  * @param {Parents | undefined} parent
49476
49503
  * Parent of `node`.
49477
49504
  * @param {State} state
@@ -49483,7 +49510,7 @@ function text$8(node, _, parent, state) {
49483
49510
  return parent && parent.type === "element" && (parent.tagName === "script" || parent.tagName === "style") ? node.value : stringifyEntities(node.value, Object.assign({}, state.settings.characterReferences, { subset: textEntitySubset }));
49484
49511
  }
49485
49512
  //#endregion
49486
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/raw.js
49513
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/raw.js
49487
49514
  /**
49488
49515
  * @import {Parents} from 'hast'
49489
49516
  * @import {Raw} from 'mdast-util-to-hast'
@@ -49495,7 +49522,7 @@ function text$8(node, _, parent, state) {
49495
49522
  * @param {Raw} node
49496
49523
  * Node to handle.
49497
49524
  * @param {number | undefined} index
49498
- * Index of `node` in `parent.
49525
+ * Index of `node` in `parent`.
49499
49526
  * @param {Parents | undefined} parent
49500
49527
  * Parent of `node`.
49501
49528
  * @param {State} state
@@ -49507,7 +49534,7 @@ function raw$1(node, index, parent, state) {
49507
49534
  return state.settings.allowDangerousHtml ? node.value : text$8(node, index, parent, state);
49508
49535
  }
49509
49536
  //#endregion
49510
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/root.js
49537
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/root.js
49511
49538
  /**
49512
49539
  * @import {Parents, Root} from 'hast'
49513
49540
  * @import {State} from '../index.js'
@@ -49518,7 +49545,7 @@ function raw$1(node, index, parent, state) {
49518
49545
  * @param {Root} node
49519
49546
  * Node to handle.
49520
49547
  * @param {number | undefined} _1
49521
- * Index of `node` in `parent.
49548
+ * Index of `node` in `parent`.
49522
49549
  * @param {Parents | undefined} _2
49523
49550
  * Parent of `node`.
49524
49551
  * @param {State} state
@@ -49530,7 +49557,7 @@ function root$5(node, _1, _2, state) {
49530
49557
  return state.all(node);
49531
49558
  }
49532
49559
  //#endregion
49533
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/handle/index.js
49560
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/handle/index.js
49534
49561
  /**
49535
49562
  * @import {Nodes, Parents} from 'hast'
49536
49563
  * @import {State} from '../index.js'
@@ -49565,7 +49592,7 @@ function invalid$1(node) {
49565
49592
  * Fail when a node with an unknown type is found in the tree.
49566
49593
  *
49567
49594
  * @param {unknown} node_
49568
- * Unknown node.
49595
+ * Unknown node.
49569
49596
  * @returns {never}
49570
49597
  * Never.
49571
49598
  */
@@ -49573,7 +49600,7 @@ function unknown$2(node_) {
49573
49600
  throw new Error("Cannot compile unknown node `" + node_.type + "`");
49574
49601
  }
49575
49602
  //#endregion
49576
- //#region node_modules/.pnpm/hast-util-to-html@9.0.5/node_modules/hast-util-to-html/lib/index.js
49603
+ //#region node_modules/.pnpm/hast-util-to-html@9.0.6/node_modules/hast-util-to-html/lib/index.js
49577
49604
  /**
49578
49605
  * @import {Nodes, Parents, RootContent} from 'hast'
49579
49606
  * @import {Schema} from 'property-information'
@@ -49604,7 +49631,7 @@ function unknown$2(node_) {
49604
49631
  * > 👉 **Note**: intentionally creates parse errors in markup (how parse
49605
49632
  * > errors are handled is well defined, so this works but isn’t pretty).
49606
49633
  * @property {boolean | null | undefined} [bogusComments=false]
49607
- * Use “bogus comments” instead of comments to save byes: `<?charlie>`
49634
+ * Use “bogus comments” instead of comments to save bytes: `<?charlie>`
49608
49635
  * instead of `<!--charlie-->` (default: `false`).
49609
49636
  *
49610
49637
  * > 👉 **Note**: intentionally creates parse errors in markup (how parse
@@ -49655,13 +49682,16 @@ function unknown$2(node_) {
49655
49682
  * @property {Space | null | undefined} [space='html']
49656
49683
  * When an `<svg>` element is found in the HTML space, this package already
49657
49684
  * automatically switches to and from the SVG space when entering and exiting
49658
- * it (default: `'html'`).
49685
+ * it, and goes to HTML inside `desc`, `foreignObject`, and `title`
49686
+ * (default: `'html'`).
49659
49687
  *
49660
49688
  * > 👉 **Note**: hast is not XML.
49661
49689
  * > It supports SVG as embedded in HTML.
49662
49690
  * > It does not support the features available in XML.
49663
49691
  * > Passing SVG might break but fragments of modern SVG should be fine.
49664
49692
  * > Use [`xast`][xast] if you need to support SVG as XML.
49693
+ *
49694
+ * [xast]: https://github.com/syntax-tree/xast
49665
49695
  * @property {boolean | null | undefined} [tightAttributes=false]
49666
49696
  * Join attributes together, without whitespace, if possible: get
49667
49697
  * `class="a b"title="c d"` instead of `class="a b" title="c d"` to save
@@ -49741,8 +49771,8 @@ const emptyChildren = [];
49741
49771
  function toHtml(tree, options) {
49742
49772
  const options_ = options || emptyOptions$7;
49743
49773
  const quote = options_.quote || "\"";
49744
- const alternative = quote === "\"" ? "'" : "\"";
49745
49774
  if (quote !== "\"" && quote !== "'") throw new Error("Invalid quote `" + quote + "`, expected `'` or `\"`");
49775
+ const alternative = quote === "\"" ? "'" : "\"";
49746
49776
  return {
49747
49777
  one: one$4,
49748
49778
  all: all$7,
@@ -49781,7 +49811,7 @@ function toHtml(tree, options) {
49781
49811
  * @param {Nodes} node
49782
49812
  * Node to handle.
49783
49813
  * @param {number | undefined} index
49784
- * Index of `node` in `parent.
49814
+ * Index of `node` in `parent`.
49785
49815
  * @param {Parents | undefined} parent
49786
49816
  * Parent of `node`.
49787
49817
  * @returns {string}
@@ -49798,6 +49828,7 @@ function one$4(node, index, parent) {
49798
49828
  * @param {Parents | undefined} parent
49799
49829
  * Parent whose children to serialize.
49800
49830
  * @returns {string}
49831
+ * Serialized children.
49801
49832
  */
49802
49833
  function all$7(parent) {
49803
49834
  /** @type {Array<string>} */