@nearform/fling 0.10.1 → 0.11.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.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/dist/cli.js +2122 -549
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -181,33 +181,33 @@ function sharedVia(site) {
181
181
  var describeSharedSite = (site) => `- ${site.name}: ${site.url} (shared by ${site.owner}, through ${sharedVia(site)}${site.reviewUrl ? `; review: ${site.reviewUrl}` : ""})`;
182
182
 
183
183
  // ../../node_modules/.pnpm/@cfworker+json-schema@4.1.4/node_modules/@cfworker/json-schema/dist/esm/deep-compare-strict.js
184
- function deepCompareStrict(a, b) {
185
- const typeofa = typeof a;
184
+ function deepCompareStrict(a3, b) {
185
+ const typeofa = typeof a3;
186
186
  if (typeofa !== typeof b) {
187
187
  return false;
188
188
  }
189
- const aIsArray = Array.isArray(a);
189
+ const aIsArray = Array.isArray(a3);
190
190
  const bIsArray = Array.isArray(b);
191
191
  if (aIsArray !== bIsArray) {
192
192
  return false;
193
193
  }
194
194
  if (aIsArray) {
195
- const length = a.length;
195
+ const length = a3.length;
196
196
  if (length !== b.length) {
197
197
  return false;
198
198
  }
199
199
  for (let i = 0; i < length; i++) {
200
- if (!deepCompareStrict(a[i], b[i])) {
200
+ if (!deepCompareStrict(a3[i], b[i])) {
201
201
  return false;
202
202
  }
203
203
  }
204
204
  return true;
205
205
  }
206
206
  if (typeofa === "object") {
207
- if (!a || !b) {
208
- return a === b;
207
+ if (!a3 || !b) {
208
+ return a3 === b;
209
209
  }
210
- const aKeys = Object.keys(a);
210
+ const aKeys = Object.keys(a3);
211
211
  const bKeys = Object.keys(b);
212
212
  const length = aKeys.length;
213
213
  if (length !== bKeys.length) {
@@ -217,13 +217,13 @@ function deepCompareStrict(a, b) {
217
217
  if (!Object.prototype.hasOwnProperty.call(b, k)) {
218
218
  return false;
219
219
  }
220
- if (!deepCompareStrict(a[k], b[k])) {
220
+ if (!deepCompareStrict(a3[k], b[k])) {
221
221
  return false;
222
222
  }
223
223
  }
224
224
  return true;
225
225
  }
226
- return a === b;
226
+ return a3 === b;
227
227
  }
228
228
 
229
229
  // ../../node_modules/.pnpm/@cfworker+json-schema@4.1.4/node_modules/@cfworker/json-schema/dist/esm/pointer.js
@@ -1084,10 +1084,10 @@ Known schemas:
1084
1084
  const keywordLocation = `${schemaLocation}/contains`;
1085
1085
  const errorsLength = errors.length;
1086
1086
  let contained = 0;
1087
- for (let j = 0; j < length; j++) {
1088
- const result = validate(instance[j], $contains, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${j}`, keywordLocation);
1087
+ for (let j2 = 0; j2 < length; j2++) {
1088
+ const result = validate(instance[j2], $contains, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${j2}`, keywordLocation);
1089
1089
  if (result.valid) {
1090
- evaluated[j] = true;
1090
+ evaluated[j2] = true;
1091
1091
  contained++;
1092
1092
  } else {
1093
1093
  errors.push(...result.errors);
@@ -1139,23 +1139,23 @@ Known schemas:
1139
1139
  }
1140
1140
  }
1141
1141
  if ($uniqueItems) {
1142
- for (let j = 0; j < length; j++) {
1143
- const a = instance[j];
1144
- const ao = typeof a === "object" && a !== null;
1142
+ for (let j2 = 0; j2 < length; j2++) {
1143
+ const a3 = instance[j2];
1144
+ const ao = typeof a3 === "object" && a3 !== null;
1145
1145
  for (let k = 0; k < length; k++) {
1146
- if (j === k) {
1146
+ if (j2 === k) {
1147
1147
  continue;
1148
1148
  }
1149
1149
  const b = instance[k];
1150
1150
  const bo = typeof b === "object" && b !== null;
1151
- if (a === b || ao && bo && deepCompareStrict(a, b)) {
1151
+ if (a3 === b || ao && bo && deepCompareStrict(a3, b)) {
1152
1152
  errors.push({
1153
1153
  instanceLocation,
1154
1154
  keyword: "uniqueItems",
1155
1155
  keywordLocation: `${schemaLocation}/uniqueItems`,
1156
- error: `Duplicate items at indexes ${j} and ${k}.`
1156
+ error: `Duplicate items at indexes ${j2} and ${k}.`
1157
1157
  });
1158
- j = Number.MAX_SAFE_INTEGER;
1158
+ j2 = Number.MAX_SAFE_INTEGER;
1159
1159
  k = Number.MAX_SAFE_INTEGER;
1160
1160
  }
1161
1161
  }
@@ -1315,9 +1315,11 @@ function markdownHomePages(files) {
1315
1315
 
1316
1316
  // ../../packages/shared/src/comments.ts
1317
1317
  var COMMENT_MAX_CHARS = 4e3;
1318
+ var COMMENTS_PER_SITE_MAX = 1e3;
1318
1319
  var COMMENT_PATH_MAX = 1024;
1319
1320
  var FORM_ID_MAX = 40;
1320
1321
  var RESPONSE_DATA_MAX_BYTES = 16 * 1024;
1322
+ var RESPONSES_PER_SITE_MAX = 1e4;
1321
1323
  var CommentAuthorSchema = z3.discriminatedUnion("kind", [
1322
1324
  z3.object({ kind: z3.literal("user"), email: z3.string() }),
1323
1325
  z3.object({ kind: z3.literal("guest"), name: z3.string() })
@@ -1425,11 +1427,11 @@ function normalizeCommentPath(input) {
1425
1427
  var RAW_QUERY = "?raw=1";
1426
1428
  function commentThreads(comments) {
1427
1429
  const threads = /* @__PURE__ */ new Map();
1428
- for (const c of comments) {
1429
- if (c.parentId === null) threads.set(c.id, { comment: c, replies: [] });
1430
+ for (const c2 of comments) {
1431
+ if (c2.parentId === null) threads.set(c2.id, { comment: c2, replies: [] });
1430
1432
  }
1431
- for (const c of comments) {
1432
- if (c.parentId !== null) threads.get(c.parentId)?.replies.push(c);
1433
+ for (const c2 of comments) {
1434
+ if (c2.parentId !== null) threads.get(c2.parentId)?.replies.push(c2);
1433
1435
  }
1434
1436
  return [...threads.values()];
1435
1437
  }
@@ -1604,15 +1606,15 @@ var FormsConfigSchema = z4.object({
1604
1606
  }
1605
1607
  });
1606
1608
  var DATA_KEYWORDS = /* @__PURE__ */ new Set(["const", "enum", "default", "examples"]);
1607
- function walkSchema(node, at, visit) {
1609
+ function walkSchema(node, at2, visit) {
1608
1610
  if (Array.isArray(node)) {
1609
- for (const [i, item] of node.entries()) walkSchema(item, `${at}/${i}`, visit);
1611
+ for (const [i, item] of node.entries()) walkSchema(item, `${at2}/${i}`, visit);
1610
1612
  return;
1611
1613
  }
1612
1614
  if (node === null || typeof node !== "object") return;
1613
1615
  for (const [key, value] of Object.entries(node)) {
1614
- visit(key, value, at);
1615
- if (!DATA_KEYWORDS.has(key)) walkSchema(value, `${at}/${key}`, visit);
1616
+ visit(key, value, at2);
1617
+ if (!DATA_KEYWORDS.has(key)) walkSchema(value, `${at2}/${key}`, visit);
1616
1618
  }
1617
1619
  }
1618
1620
  function resolveLocalRef(root, ref) {
@@ -1620,8 +1622,8 @@ function resolveLocalRef(root, ref) {
1620
1622
  if (fragment === "") return root;
1621
1623
  if (!fragment.startsWith("/")) {
1622
1624
  let found;
1623
- walkSchema(root, "#", (key, value, at) => {
1624
- if (key === "$anchor" && value === fragment && found === void 0) found = at;
1625
+ walkSchema(root, "#", (key, value, at2) => {
1626
+ if (key === "$anchor" && value === fragment && found === void 0) found = at2;
1625
1627
  });
1626
1628
  return found;
1627
1629
  }
@@ -1651,19 +1653,19 @@ function checkFormSchema(schema) {
1651
1653
  problems.push(`Not a valid JSON Schema: ${e.field ? `${e.field} ` : ""}${e.message}`);
1652
1654
  }
1653
1655
  }
1654
- walkSchema(root, "#", (key, value, at) => {
1656
+ walkSchema(root, "#", (key, value, at2) => {
1655
1657
  if (key === "$ref" && typeof value === "string") {
1656
1658
  if (!value.startsWith("#")) {
1657
- problems.push(`${at}: $ref "${value}" is remote; only local refs ("#/$defs/\u2026") are allowed`);
1659
+ problems.push(`${at2}: $ref "${value}" is remote; only local refs ("#/$defs/\u2026") are allowed`);
1658
1660
  } else if (resolveLocalRef(root, value) === void 0) {
1659
- problems.push(`${at}: $ref "${value}" points at nothing`);
1661
+ problems.push(`${at2}: $ref "${value}" points at nothing`);
1660
1662
  }
1661
1663
  }
1662
1664
  if ((key === "$dynamicRef" || key === "$recursiveRef") && typeof value === "string") {
1663
- problems.push(`${at}: ${key} is not supported; use $ref`);
1665
+ problems.push(`${at2}: ${key} is not supported; use $ref`);
1664
1666
  }
1665
- if (key === "$id" && at !== "#" && typeof value === "string") {
1666
- problems.push(`${at}: $id is only allowed at the root`);
1667
+ if (key === "$id" && at2 !== "#" && typeof value === "string") {
1668
+ problems.push(`${at2}: $id is only allowed at the root`);
1667
1669
  }
1668
1670
  });
1669
1671
  return problems;
@@ -1694,7 +1696,7 @@ function fieldErrors(units) {
1694
1696
  if (WRAPPERS.has(u.keyword) && /subschema|does not match schema|do not match/i.test(u.error)) {
1695
1697
  continue;
1696
1698
  }
1697
- if (choices.some((c) => u.keywordLocation.startsWith(c))) continue;
1699
+ if (choices.some((c2) => u.keywordLocation.startsWith(c2))) continue;
1698
1700
  let field = fieldOf(u.instanceLocation);
1699
1701
  let message = u.error;
1700
1702
  const missing = u.keyword === "required" && /"([^"]+)"/.exec(u.error);
@@ -1727,7 +1729,7 @@ function globRegExp(glob) {
1727
1729
  const cached = globCache.get(glob);
1728
1730
  if (cached) return cached;
1729
1731
  const g = glob.replace(/^\/+/, "");
1730
- let re = "";
1732
+ let re2 = "";
1731
1733
  for (let i = 0; i < g.length; i++) {
1732
1734
  const ch = g[i];
1733
1735
  if (ch === "*") {
@@ -1735,21 +1737,21 @@ function globRegExp(glob) {
1735
1737
  i++;
1736
1738
  if (g[i + 1] === "/") {
1737
1739
  i++;
1738
- re += "(?:.*/)?";
1739
- } else re += ".*";
1740
- } else re += "[^/]*";
1741
- } else if (ch === "?") re += "[^/]";
1742
- else re += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
1740
+ re2 += "(?:.*/)?";
1741
+ } else re2 += ".*";
1742
+ } else re2 += "[^/]*";
1743
+ } else if (ch === "?") re2 += "[^/]";
1744
+ else re2 += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
1743
1745
  }
1744
- const out = new RegExp(`^${re}$`);
1746
+ const out = new RegExp(`^${re2}$`);
1745
1747
  globCache.set(glob, out);
1746
1748
  return out;
1747
1749
  }
1748
1750
  function globMatches(glob, path3) {
1749
1751
  const rel = path3.replace(/^\/+/, "");
1750
- const re = globRegExp(glob);
1752
+ const re2 = globRegExp(glob);
1751
1753
  const names = rel === "" || rel.endsWith("/") ? [rel, rel.replace(/\/$/, ""), `${rel}index.html`] : [rel];
1752
- return names.some((n) => re.test(n));
1754
+ return names.some((n) => re2.test(n));
1753
1755
  }
1754
1756
  function formAppliesTo(form, path3) {
1755
1757
  const globs = form.paths ?? [];
@@ -1805,7 +1807,7 @@ function formsSummaryLines(summary) {
1805
1807
  const own = f.visibility === "own" ? ", each reviewer sees only their own" : "";
1806
1808
  return `${summary.title} \xB7 ${f.title} (${f.id}): ${f.kind === "page" ? "one per reviewer per page" : "a comment type"}${where}${own}`;
1807
1809
  }),
1808
- ...summary.warnings.map((w) => `warning: ${w}`)
1810
+ ...summary.warnings.map((w2) => `warning: ${w2}`)
1809
1811
  ];
1810
1812
  }
1811
1813
  function responseFields(form, data) {
@@ -1874,11 +1876,11 @@ function responsesCsv(rows, forms2 = []) {
1874
1876
  for (const form of forms2) Object.keys(form.schema.properties ?? {}).forEach(add);
1875
1877
  for (const row2 of rows) Object.keys(row2.data).forEach(add);
1876
1878
  const fixed = ["id", "path", "formId", "author", "createdAt", "updatedAt", "versionId"];
1877
- const header = [...fixed, ...columns.map((c) => fixed.includes(c) ? `data.${c}` : c)];
1879
+ const header = [...fixed, ...columns.map((c2) => fixed.includes(c2) ? `data.${c2}` : c2)];
1878
1880
  const lines = [header.map(csvCell).join(",")];
1879
1881
  for (const row2 of rows) {
1880
1882
  lines.push(
1881
- [...fixed.map((k) => csvCell(row2[k])), ...columns.map((c) => csvCell(row2.data[c]))].join(",")
1883
+ [...fixed.map((k) => csvCell(row2[k])), ...columns.map((c2) => csvCell(row2.data[c2]))].join(",")
1882
1884
  );
1883
1885
  }
1884
1886
  return `${lines.join("\r\n")}\r
@@ -1893,8 +1895,8 @@ function progressLines(exported) {
1893
1895
  return exported.progress.map((p) => {
1894
1896
  const form = exported.forms.find((f) => f.id === p.form);
1895
1897
  const done = p.pages.filter((page2) => (p.done[page2]?.length ?? 0) > 0).length;
1896
- const count2 = exported.responses.filter((r) => r.formId === p.form).length;
1897
- const where = form?.kind === "comment" ? `${count2} response${count2 === 1 ? "" : "s"} on ${Object.keys(p.done).length} of ${p.pages.length} pages` : `${done} / ${p.pages.length} page${p.pages.length === 1 ? "" : "s"} answered`;
1898
+ const count3 = exported.responses.filter((r) => r.formId === p.form).length;
1899
+ const where = form?.kind === "comment" ? `${count3} response${count3 === 1 ? "" : "s"} on ${Object.keys(p.done).length} of ${p.pages.length} pages` : `${done} / ${p.pages.length} page${p.pages.length === 1 ? "" : "s"} answered`;
1898
1900
  return `${form?.title ?? p.form} (${p.form}): ${where}, ${p.reviewers.length} reviewer${p.reviewers.length === 1 ? "" : "s"}`;
1899
1901
  });
1900
1902
  }
@@ -1905,6 +1907,7 @@ var MAX_FILE_BYTES = 25 * 1024 * 1024;
1905
1907
  var MAX_FILES = 5e3;
1906
1908
  var MAX_PATH_LENGTH = 1024;
1907
1909
  var MAX_PATH_FOLDER_LENGTH = 100;
1910
+ var MAX_PATHS_PER_SITE = 1e3;
1908
1911
 
1909
1912
  // ../../packages/shared/src/manifest.ts
1910
1913
  import { z as z5 } from "zod";
@@ -2066,7 +2069,7 @@ function scanForSecrets(text2, path3) {
2066
2069
  findings.push({ path: path3, line, rule: rule.id });
2067
2070
  }
2068
2071
  }
2069
- return findings.sort((a, b) => a.line - b.line || a.rule.localeCompare(b.rule));
2072
+ return findings.sort((a3, b) => a3.line - b.line || a3.rule.localeCompare(b.rule));
2070
2073
  }
2071
2074
  var BINARY_EXTENSIONS = new Set(
2072
2075
  "png jpg jpeg gif webp avif ico bmp tif tiff heic psd woff woff2 ttf otf eot mp3 mp4 m4a m4v mov webm ogg oga ogv wav flac aac avi mkv zip gz tgz br zst bz2 xz 7z rar wasm pdf glb gltf-binary bin dat".split(/\s+/).filter(Boolean)
@@ -2537,6 +2540,7 @@ var CLI_PACKAGE = "@nearform/fling";
2537
2540
  var REPO_SLUG = "nearform/fling";
2538
2541
  var DEFAULT_INSTALL_COMMAND = `npm install -g ${CLI_PACKAGE}`;
2539
2542
  var REPO_URL = `https://github.com/${REPO_SLUG}`;
2543
+ var WHY_SITE_NAME = "why-fling";
2540
2544
 
2541
2545
  // ../../packages/shared/src/forms-templates.ts
2542
2546
  var FORM_TEMPLATE_NAMES = ["labels", "rubric", "compare", "issue", "survey"];
@@ -2779,6 +2783,1476 @@ function describeGroup(group) {
2779
2783
  ].join("\n");
2780
2784
  }
2781
2785
 
2786
+ // ../../packages/shared/src/guide.ts
2787
+ import { z as z11 } from "zod";
2788
+ var GUIDE_PARTS = [
2789
+ { id: "start", label: "Start" },
2790
+ { id: "publish", label: "Publish" },
2791
+ { id: "share", label: "Share" },
2792
+ { id: "team-sites", label: "Team sites" },
2793
+ { id: "feedback", label: "Feedback" },
2794
+ { id: "admin", label: "Admin" },
2795
+ { id: "run", label: "Run your own Fling" }
2796
+ ];
2797
+ var PART_IDS = GUIDE_PARTS.map((p) => p.id);
2798
+ var GUIDE_ROUTE = "/guide";
2799
+ var GuideFrontmatterSchema = z11.object({
2800
+ title: z11.string().min(1),
2801
+ part: z11.enum(PART_IDS),
2802
+ /** its place within the part */
2803
+ order: z11.number().int(),
2804
+ /** one line: the nav's tooltip and what search matches besides the text */
2805
+ summary: z11.string().min(1),
2806
+ /** capabilities the page needs; it is hidden on an instance without any of them */
2807
+ requires: z11.array(z11.string().min(1)).default([]),
2808
+ /** `admin`: shown to the instance's admins only */
2809
+ audience: z11.enum(["everyone", "admin"]).default("everyone"),
2810
+ /** repository globs of the code the page describes (coarse: a directory, not a list of files) */
2811
+ sources: z11.array(z11.string().min(1)).min(1),
2812
+ /** the commit at which the page was last checked against its sources */
2813
+ verified: z11.string().regex(/^[0-9a-f]{7,40}$/, "a commit sha")
2814
+ });
2815
+ var instanceGuideUrl = (instance) => instance?.appOrigin && instance.capabilities?.guide === true ? `${instance.appOrigin}${GUIDE_ROUTE}` : void 0;
2816
+
2817
+ // ../../node_modules/.pnpm/marked@18.1.3/node_modules/marked/lib/marked.esm.js
2818
+ function H() {
2819
+ return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
2820
+ }
2821
+ var S = H();
2822
+ function se(a3) {
2823
+ S = a3;
2824
+ }
2825
+ var B = { exec: () => null };
2826
+ function D(a3) {
2827
+ let e = [];
2828
+ return (t) => {
2829
+ let n = Math.max(0, Math.min(3, t - 1)), s = e[n];
2830
+ return s || (s = a3(n), e[n] = s), s;
2831
+ };
2832
+ }
2833
+ function c(a3, e = "") {
2834
+ let t = typeof a3 == "string" ? a3 : a3.source, n = { replace: (s, r) => {
2835
+ let o = typeof r == "string" ? r : r.source;
2836
+ return o = o.replace(T.caret, "$1"), t = t.replace(s, o), n;
2837
+ }, getRegex: () => new RegExp(t, e) };
2838
+ return n;
2839
+ }
2840
+ var Te = ((a3 = "") => {
2841
+ try {
2842
+ return !!new RegExp("(?<=1)(?<!1)" + a3);
2843
+ } catch {
2844
+ return false;
2845
+ }
2846
+ })();
2847
+ var T = { codeRemoveIndent: /^(?: {0,3}\t| {1,4})/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, endingSpaceTabChar: /[ \t]$/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, leadingSpaceTab: /^[ \t]+/, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+)[ \t]*)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, blockquoteMarkerWhitespace: /^( {0,3}>)([ \t]+)/gm, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\][ \t]+\S/, listReplaceTask: /^\[[ xX]\][ \t]+/, listTaskCheckbox: /\[[ xX]\]/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, numericCharacterReference: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));/, numericCharacterReferenceOrAmpersand: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (a3) => new RegExp(`^( {0,3}${a3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: D((a3) => new RegExp(`^ {0,${a3}}((?:-[ ]*){3,}|(?:_[ ]*){3,}|(?:\\*[ ]*){3,})(?:\\n+|$)`)), fencesBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:\`\`\`|~~~)`)), headingBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}#{1,6}(?:\\s|$)`)), pedanticHeadingBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}#`)), htmlBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:</?(?:${K})(?: +|$|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)`, "i")), blockquoteBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}>`)) };
2848
+ var ve = /^(?:[ \t]*(?:\n|$))+/;
2849
+ var Ze = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
2850
+ var He = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}(?:(?=`)\1`*|(?=~)\1~*) *(?=\n|$)|$)/;
2851
+ var W = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
2852
+ var je = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
2853
+ var oe = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
2854
+ var Oe = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |fences|blockquote|heading|hr|html|table))+?)\n {0,3}(=+|-+)[ \t]*(?:\n+|$)/;
2855
+ var we = c(Oe).replace(/bull/g, oe).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
2856
+ var Ge = c(Oe).replace(/bull/g, oe).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
2857
+ var ae = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
2858
+ var Ne = /^[^\n]+/;
2859
+ var le = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\\n]|\n(?![ \t]*\n))+/;
2860
+ var Fe = c(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", le).replace("title", /(?:"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\\n]|\n(?!\n))*'|\((?:\\[\s\S]|[^()\\])*\))/).getRegex();
2861
+ var Qe = c(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, oe).getRegex();
2862
+ var K = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
2863
+ var ue = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
2864
+ var Ue = c("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?:[ \\t]+|\\n|/?>|$)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!(?:script|pre|style|textarea)(?![a-z0-9-]))([a-z][a-z0-9-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</[a-z][a-z0-9-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", ue).replace("tag", K).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
2865
+ var Pe = (a3) => c(ae).replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", a3).replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex();
2866
+ var We = Pe(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
2867
+ var Ke = Pe(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
2868
+ var Xe = c(/^( {0,3}> ?(?:(?![ \t]*(?:\n|$))(paragraph)|[^\n]*)(?:\n|$))+/).replace("paragraph", Ke).getRegex();
2869
+ var pe = { blockquote: Xe, code: Ze, def: Fe, fences: He, heading: je, hr: W, html: Ue, lheading: we, list: Qe, newline: ve, paragraph: We, table: B, text: Ne };
2870
+ var xe = c("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex();
2871
+ var Ve = { ...pe, lheading: Ge, table: xe, paragraph: c(ae).replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", xe).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex() };
2872
+ var Je = { ...pe, html: c(`^ *(?:comment(?: *\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1>(?: *\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?>(?: *\\n{2,}|\\s*$))`).replace("comment", ue).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: B, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: c(ae).replace("hr", W).replace("heading", ` *#{1,6} *[^
2873
+ ]`).replace("lheading", we).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
2874
+ var Ye = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
2875
+ var et = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
2876
+ var Se = /^( {2,}|\\)\n(?!\s*$)[ \t]*/;
2877
+ var tt = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
2878
+ var $ = /[\p{P}\p{S}]/u;
2879
+ var j = /[\s\p{P}\p{S}]/u;
2880
+ var X = /[^\s\p{P}\p{S}]/u;
2881
+ var nt = c(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, j).getRegex();
2882
+ var rt = /[\p{Pi}\p{Ps}"']/u;
2883
+ var ye = /(?!~)[\p{P}\p{S}]/u;
2884
+ var st = /(?!~)[\s\p{P}\p{S}]/u;
2885
+ var it = /(?:[^\s\p{P}\p{S}]|~)/u;
2886
+ var ot = c(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", Te ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
2887
+ var _e = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
2888
+ var at = c(_e, "u").replace(/punct/g, $).getRegex();
2889
+ var lt = c(_e, "u").replace(/punct/g, ye).getRegex();
2890
+ var ut = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
2891
+ var pt = c(ut, "u").replace(/openQuote/g, rt).replace(/punct/g, $).getRegex();
2892
+ var $e = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
2893
+ var ct = c($e, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
2894
+ var ht = c($e, "gu").replace(/notPunctSpace/g, it).replace(/punctSpace/g, st).replace(/punct/g, ye).getRegex();
2895
+ var dt = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)";
2896
+ var gt = c(dt, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
2897
+ var kt = c("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
2898
+ var ft = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)";
2899
+ var mt = c(ft, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
2900
+ var xt = c(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, $).getRegex();
2901
+ var bt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)";
2902
+ var Rt = c(bt, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
2903
+ var Tt = c(/\\(punct)/, "gu").replace(/punct/g, $).getRegex();
2904
+ var Ot = c(/(`+)(?:[^`]|[^`][\s\S]*?[^`])\1(?!`)|`+|\\(punct)/, "gu").replace(/punct/g, $).getRegex();
2905
+ var wt = c(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
2906
+ var Pt = c(ue).replace("(?:-->|$)", "-->").getRegex();
2907
+ var St = c("^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", Pt).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
2908
+ var Le = /\[(?:\\[\s\S]|[^\[\]\\])*\]/;
2909
+ var re = c(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace("brackets", Le).getRegex();
2910
+ var yt = c(/^!?\[(label)\]\([ \t\n]*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?[ \t\n]*\)/).replace("label", re).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|\((?:\\[\s\S]|[^)\\])*\)/).getRegex();
2911
+ var _t = c(/^!?\[(label)\]\[(ref)\]/).replace("label", re).replace("ref", le).getRegex();
2912
+ var $t = c(/^!?\[(ref)\](?:\[\])?/).replace("ref", le).getRegex();
2913
+ var be = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/;
2914
+ var Lt = c(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace("brackets", Le).getRegex();
2915
+ var Ct = c("reflink|nolink(?!\\()", "g").replace("reflink", c(/^!?\[(label)\]\[(ref)\]/).replace("label", Lt).replace("ref", be).getRegex()).replace("nolink", c(/^!?\[(ref)\](?:\[\])?/).replace("ref", be).getRegex()).getRegex();
2916
+ var Re = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
2917
+ var It = /[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/;
2918
+ var At = c(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g, It).getRegex();
2919
+ var ce = { _backpedal: B, anyPunctuation: Tt, anyPunctuationOutsideCode: Ot, autolink: wt, blockSkip: ot, br: Se, code: et, del: B, delLDelim: B, delRDelim: B, emStrongLDelim: at, emStrongRDelimAst: ct, emStrongRDelimUnd: kt, escape: Ye, link: yt, nolink: $t, punctuation: nt, reflink: _t, reflinkSearch: Ct, tag: St, text: tt, url: B };
2920
+ var Et = { ...ce, emStrongLDelim: pt, emStrongRDelimAst: gt, emStrongRDelimUnd: mt, link: c(/^!?\[(label)\]\((.*?)\)/).replace("label", re).getRegex(), reflink: c(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", re).getRegex() };
2921
+ var ie = { ...ce, emStrongRDelimAst: ht, emStrongLDelim: lt, delLDelim: xt, delRDelim: Rt, url: c(/^emailProtocol|^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("emailProtocol", At).replace("protocol", Re).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: c(/^(?:[^a-zA-Z0-9](?=emailProtocol)|(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|wwwStart|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9](?=emailProtocol)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))))/).replace("protocol", Re).replace(/emailProtocol/g, /(?:mailto|xmpp):/).replace("wwwStart", Te ? "(?<![^\\s*_~(])www\\." : "www\\.").getRegex() };
2922
+ var zt = { ...ie, br: c(Se).replace("{2,}", "*").getRegex(), text: c(ie.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
2923
+ var V = { normal: pe, gfm: Ve, pedantic: Je };
2924
+ var G = { normal: ce, gfm: ie, breaks: zt, pedantic: Et };
2925
+ var Mt = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
2926
+ var Ce = (a3) => Mt[a3];
2927
+ function P(a3, e) {
2928
+ if (e) {
2929
+ if (T.escapeTest.test(a3)) return a3.replace(T.escapeReplace, Ce);
2930
+ } else if (T.escapeTestNoEncode.test(a3)) return a3.replace(T.escapeReplaceNoEncode, Ce);
2931
+ return a3;
2932
+ }
2933
+ function Ie(a3) {
2934
+ return T.numericCharacterReference.test(a3) ? a3.replace(T.numericCharacterReferenceOrAmpersand, (e, t, n) => {
2935
+ if (t === void 0 && n === void 0) return "&amp;";
2936
+ let s = t === void 0 ? Number.parseInt(n, 16) : Number.parseInt(t, 10);
2937
+ return s === 0 || s > 1114111 || s >= 55296 && s <= 57343 ? "\uFFFD" : s === 38 ? "&amp;" : String.fromCodePoint(s);
2938
+ }) : a3;
2939
+ }
2940
+ function he(a3) {
2941
+ try {
2942
+ a3 = encodeURI(a3).replace(T.percentDecode, "%");
2943
+ } catch {
2944
+ return null;
2945
+ }
2946
+ return a3;
2947
+ }
2948
+ function de(a3, e) {
2949
+ let t = a3.replace(T.findPipe, (r, o, i) => {
2950
+ let l = false, p = o;
2951
+ for (; --p >= 0 && i[p] === "\\"; ) l = !l;
2952
+ return l ? "|" : " |";
2953
+ }), n = t.split(T.splitPipe), s = 0;
2954
+ if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e);
2955
+ else for (; n.length < e; ) n.push("");
2956
+ for (; s < n.length; s++) n[s] = n[s].trim().replace(T.slashPipe, "|");
2957
+ return n;
2958
+ }
2959
+ function L(a3, e, t) {
2960
+ let n = a3.length;
2961
+ if (n === 0) return "";
2962
+ let s = 0;
2963
+ for (; s < n; ) {
2964
+ let r = a3.charAt(n - s - 1);
2965
+ if (r === e && !t) s++;
2966
+ else if (r !== e && t) s++;
2967
+ else break;
2968
+ }
2969
+ return a3.slice(0, n - s);
2970
+ }
2971
+ function ge(a3) {
2972
+ let e = a3.split(`
2973
+ `), t = e.length - 1;
2974
+ for (; t >= 0 && T.blankLine.test(e[t]); ) t--;
2975
+ return e.length - t <= 2 ? a3 : e.slice(0, t + 1).join(`
2976
+ `);
2977
+ }
2978
+ function F(a3) {
2979
+ return a3.trim().replace(T.multipleSpaceGlobal, " ").toLowerCase().toUpperCase().toLowerCase();
2980
+ }
2981
+ function ke(a3, e) {
2982
+ if (a3.indexOf(e[0]) === -1 && a3.indexOf(e[1]) === -1) return -1;
2983
+ let t = 0;
2984
+ for (let n = 0; n < a3.length; n++) if (a3[n] === "\\") n++;
2985
+ else if (a3[n] === e[0]) t++;
2986
+ else if (a3[n] === e[1] && (t--, t < 0)) return n;
2987
+ return t > 0 ? -2 : -1;
2988
+ }
2989
+ var N = /* @__PURE__ */ new WeakMap();
2990
+ function fe(a3) {
2991
+ let e = { "*": -1, _: -1 }, t = -1, n = a3.length;
2992
+ for (let s = 0; s < n; s++) {
2993
+ let r = a3[s];
2994
+ if (r !== "*" && r !== "_" && r !== "~") continue;
2995
+ let o = s === 0 ? `
2996
+ ` : a3[s - 1], i = s + 1;
2997
+ for (; i < n && a3[i] === r; ) i++;
2998
+ o !== " " && o !== " " && o !== `
2999
+ ` && o !== "\r" && o !== "\f" && (r === "~" ? t = s : e[r] = s), s = i - 1;
3000
+ }
3001
+ return { maskedSrc: a3, lastPossibleEmStrongCloserIndex: e, lastPossibleDelCloserIndex: t };
3002
+ }
3003
+ function Ae(a3, e) {
3004
+ let t = fe(e), n = N.get(a3);
3005
+ n ? n.push(t) : N.set(a3, [t]);
3006
+ }
3007
+ function Ee(a3) {
3008
+ let e = N.get(a3);
3009
+ e && (e.pop(), e.length === 0 && N.delete(a3));
3010
+ }
3011
+ function ze(a3, e, t) {
3012
+ let n = N.get(a3)?.at(-1);
3013
+ return n && n.maskedSrc === e ? n.lastPossibleEmStrongCloserIndex[t] : fe(e).lastPossibleEmStrongCloserIndex[t];
3014
+ }
3015
+ function Me(a3, e) {
3016
+ let t = N.get(a3)?.at(-1);
3017
+ return t && t.maskedSrc === e ? t.lastPossibleDelCloserIndex : fe(e).lastPossibleDelCloserIndex;
3018
+ }
3019
+ function J(a3, e = 0) {
3020
+ let t = e, n = "";
3021
+ for (let s of a3) if (s === " ") {
3022
+ let r = 4 - t % 4;
3023
+ n += " ".repeat(r), t += r;
3024
+ } else n += s, t++;
3025
+ return n;
3026
+ }
3027
+ function De(a3, e, t, n, s) {
3028
+ let r = e.href, o = e.title || null, i = a3[1].replace(s.other.outputLinkReplace, "$1"), l = a3[0].charAt(0) === "!", p = n.state.inLink, h = n.state.linkEmitted, u = n.state.inRawBlock;
3029
+ n.state.inLink = true, n.state.linkEmitted = false;
3030
+ let d = n.inlineTokens(i), k = n.state.linkEmitted;
3031
+ if (n.state.linkEmitted = h, n.state.inLink = p, !l) {
3032
+ if (k) {
3033
+ n.state.inRawBlock = u;
3034
+ return;
3035
+ }
3036
+ n.state.linkEmitted = true;
3037
+ }
3038
+ return { type: l ? "image" : "link", raw: t, href: r, title: o, text: i, tokens: d };
3039
+ }
3040
+ function Dt(a3, e, t) {
3041
+ let n = a3.match(t.other.indentCodeCompensation);
3042
+ if (n === null) return e;
3043
+ let s = n[1];
3044
+ return e.split(`
3045
+ `).map((r) => {
3046
+ let o = r.match(t.other.beginningSpace);
3047
+ if (o === null) return r;
3048
+ let [i] = o;
3049
+ return r.slice(Math.min(i.length, s.length));
3050
+ }).join(`
3051
+ `);
3052
+ }
3053
+ function Be(a3, e, t, n) {
3054
+ if (!e.includes("<")) return false;
3055
+ for (let s = 0; s < e.length; s++) {
3056
+ if (e[s] === "\\") {
3057
+ s++;
3058
+ continue;
3059
+ }
3060
+ if (e[s] === "`") {
3061
+ let i = n.inline.code.exec(e.slice(s));
3062
+ if (i) {
3063
+ s += i[0].length - 1;
3064
+ continue;
3065
+ }
3066
+ }
3067
+ if (e[s] !== "<") continue;
3068
+ let r = a3.slice(t + s), o = n.inline.tag.exec(r) || n.inline.autolink.exec(r);
3069
+ if (o) {
3070
+ if (o[0].length > e.length - s) return true;
3071
+ s += o[0].length - 1;
3072
+ }
3073
+ }
3074
+ return false;
3075
+ }
3076
+ var _ = class {
3077
+ options;
3078
+ rules;
3079
+ lexer;
3080
+ constructor(e) {
3081
+ this.options = e || S;
3082
+ }
3083
+ space(e) {
3084
+ let t = this.rules.block.newline.exec(e);
3085
+ if (t && t[0].length > 0) return { type: "space", raw: t[0] };
3086
+ }
3087
+ code(e) {
3088
+ let t = this.rules.block.code.exec(e);
3089
+ if (t) {
3090
+ let n = this.options.pedantic ? t[0] : ge(t[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
3091
+ return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
3092
+ }
3093
+ }
3094
+ fences(e) {
3095
+ let t = this.rules.block.fences.exec(e);
3096
+ if (t) {
3097
+ let n = t[0], s = Dt(n, t[3] || "", this.rules);
3098
+ return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: s };
3099
+ }
3100
+ }
3101
+ heading(e) {
3102
+ let t = this.rules.block.heading.exec(e);
3103
+ if (t) {
3104
+ let n = t[2].trim();
3105
+ if (this.rules.other.endingHash.test(n)) {
3106
+ let s = L(n, "#");
3107
+ (this.options.pedantic || !s || this.rules.other.endingSpaceTabChar.test(s)) && (n = s.trim());
3108
+ }
3109
+ return { type: "heading", raw: L(t[0], `
3110
+ `), depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
3111
+ }
3112
+ }
3113
+ hr(e) {
3114
+ let t = this.rules.block.hr.exec(e);
3115
+ if (t) return { type: "hr", raw: L(t[0], `
3116
+ `) };
3117
+ }
3118
+ blockquote(e) {
3119
+ let t = this.rules.block.blockquote.exec(e);
3120
+ if (t) {
3121
+ let n = L(t[0], `
3122
+ `).split(`
3123
+ `), s = "", r = "", o = [];
3124
+ for (; n.length > 0; ) {
3125
+ let i = false, l = [], p;
3126
+ for (p = 0; p < n.length; p++) if (this.rules.other.blockquoteStart.test(n[p])) l.push(n[p]), i = true;
3127
+ else if (!i) l.push(n[p]);
3128
+ else break;
3129
+ n = n.slice(p);
3130
+ let h = l.join(`
3131
+ `), u = h.replace(this.rules.other.blockquoteMarkerWhitespace, (g, b, m) => b + J(m, b.length)).replace(this.rules.other.blockquoteSetextReplace, `
3132
+ $1`).replace(this.rules.other.blockquoteSetextReplace2, "");
3133
+ s = s ? `${s}
3134
+ ${h}` : h, r = r ? `${r}
3135
+ ${u}` : u;
3136
+ let d = this.lexer.state.top;
3137
+ if (this.lexer.state.top = true, this.lexer.blockTokens(u, o, true), this.lexer.state.top = d, n.length === 0) break;
3138
+ let k = o.at(-1);
3139
+ if (k?.type === "code" || k?.type === "heading" || k?.type === "hr" || k?.type === "html" || k?.type === "table") break;
3140
+ if (k?.type === "blockquote") {
3141
+ let g = k, b = n.join(`
3142
+ `), m = g.raw + `
3143
+ ` + b.replace(this.rules.other.blockquoteSetextReplace2, ""), f = this.blockquote(m);
3144
+ o[o.length - 1] = f;
3145
+ let y = m.substring(f.raw.length).replace(/^\n/, ""), R = y ? y.split(`
3146
+ `).length : 0, A = R ? n.slice(0, -R) : n;
3147
+ if (A.length > 0 && (s = `${s}
3148
+ ${A.join(`
3149
+ `)}`), r = r.substring(0, r.length - g.text.length) + f.text, n = n.slice(A.length), n.length > 0 && this.rules.other.blockquoteStart.test(n[0])) continue;
3150
+ break;
3151
+ } else if (k?.type === "list") {
3152
+ let g = k, b = g.raw + `
3153
+ ` + n.join(`
3154
+ `), m = this.list(b);
3155
+ o[o.length - 1] = m;
3156
+ let f = m.raw.length > g.raw.length ? b.slice(g.raw.length + 1, m.raw.length).split(`
3157
+ `).length : 0;
3158
+ if (f > 0) {
3159
+ let y = n.slice(0, f).join(`
3160
+ `);
3161
+ s = `${s}
3162
+ ${y}`, r = `${r}
3163
+ ${y}`;
3164
+ }
3165
+ n = n.slice(f);
3166
+ continue;
3167
+ }
3168
+ }
3169
+ return { type: "blockquote", raw: s, tokens: o, text: r };
3170
+ }
3171
+ }
3172
+ list(e) {
3173
+ let t = this.rules.block.list.exec(e);
3174
+ if (t) {
3175
+ let n = e, s = () => n.length - e.length, r = t[1].trim(), o = r.length > 1, i = { type: "list", raw: "", ordered: o, start: o ? +r.slice(0, -1) : "", loose: false, items: [] };
3176
+ r = o ? `\\d{1,9}\\${r.slice(-1)}` : `\\${r}`, this.options.pedantic && (r = o ? r : "[*+-]");
3177
+ let l = this.rules.other.listItemRegex(r), p = false;
3178
+ for (; e; ) {
3179
+ let u = false, d = "";
3180
+ if (!(t = l.exec(e)) || this.rules.block.hr.test(e)) break;
3181
+ let k = s();
3182
+ e = e.substring(t[0].length);
3183
+ let g = t[2].split(`
3184
+ `, 1)[0], b = t[1].length, m = this.options.pedantic ? J(g, b) : g.replace(this.rules.other.leadingSpaceTab, (v) => J(v, b)), f = e.split(`
3185
+ `, 1)[0], y = !m.trim(), R = 0;
3186
+ if (this.options.pedantic ? (R = 2, d = m.trimStart()) : y ? R = b + 1 : (R = m.search(this.rules.other.nonSpaceChar), R = R > 4 ? 1 : R, d = m.slice(R), R += b), y && this.rules.other.blankLine.test(f) && (e = e.substring(f.length + 1), u = true), !u) {
3187
+ let v = this.rules.other.nextBulletRegex(R), Q = this.rules.other.hrRegex(R), ee = this.rules.other.fencesBeginRegex(R), te = this.options.pedantic ? this.rules.other.pedanticHeadingBeginRegex(R) : this.rules.other.headingBeginRegex(R), M = this.rules.other.htmlBeginRegex(R), ne = this.rules.other.blockquoteBeginRegex(R);
3188
+ for (; e; ) {
3189
+ let U = e.split(`
3190
+ `, 1)[0], Z;
3191
+ if (f = U, this.options.pedantic ? (f = f.replace(this.rules.other.listReplaceNesting, " "), Z = f) : Z = f.replace(this.rules.other.leadingSpaceTab, (me) => J(me)), ee.test(f) || te.test(f) || M.test(f) || ne.test(f) || v.test(f) || Q.test(f)) break;
3192
+ if (Z.search(this.rules.other.nonSpaceChar) >= R || !f.trim()) d += `
3193
+ ` + Z.slice(R);
3194
+ else {
3195
+ if (y || m.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || ee.test(m) || te.test(m) || M.test(m) || Q.test(m)) break;
3196
+ let qe = !this.options.pedantic && /^ {0,3}(?:=+|-+) *$/.test(f) && this.rules.block.lheading.test(`${m}
3197
+ ${f}`) ? ` ${Z.replace(/^ {0,3}/, "")}` : f;
3198
+ d += `
3199
+ ` + qe;
3200
+ }
3201
+ y = !f.trim(), e = e.substring(U.length + 1), m = Z.slice(R);
3202
+ }
3203
+ }
3204
+ let A = n.slice(k, s());
3205
+ i.loose || (p ? i.loose = true : this.rules.other.doubleBlankLine.test(A) && (p = true)), i.items.push({ type: "list_item", raw: A, task: !!this.options.gfm && this.rules.other.listIsTask.test(d), loose: false, text: d, tokens: [] });
3206
+ }
3207
+ let h = i.items.at(-1);
3208
+ if (h) h.raw = h.raw.trimEnd(), h.text = h.text.trimEnd();
3209
+ else return;
3210
+ i.raw = n.slice(0, s()).trimEnd();
3211
+ for (let u of i.items) if (this.lexer.state.top = false, u.tokens = this.lexer.blockTokens(u.text, []), !i.loose) {
3212
+ let d = u.tokens.filter((g) => g.type === "space"), k = d.length > 0 && d.some((g) => this.rules.other.anyLine.test(g.raw));
3213
+ i.loose = k;
3214
+ }
3215
+ for (let u of i.items) {
3216
+ let d = u.tokens[0];
3217
+ if (u.task && (d?.type === "text" || d?.type === "paragraph")) {
3218
+ u.text = u.text.replace(this.rules.other.listReplaceTask, ""), d.raw = d.raw.replace(this.rules.other.listReplaceTask, ""), d.text = d.text.replace(this.rules.other.listReplaceTask, "");
3219
+ for (let g = this.lexer.inlineQueue.length - 1; g >= 0; g--) if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[g].src)) {
3220
+ this.lexer.inlineQueue[g].src = this.lexer.inlineQueue[g].src.replace(this.rules.other.listReplaceTask, "");
3221
+ break;
3222
+ }
3223
+ let k = this.rules.other.listTaskCheckbox.exec(u.raw);
3224
+ if (k) {
3225
+ let g = { type: "checkbox", raw: k[0] + " ", checked: k[0] !== "[ ]" };
3226
+ u.checked = g.checked, i.loose ? u.tokens[0] && ["paragraph", "text"].includes(u.tokens[0].type) && "tokens" in u.tokens[0] && u.tokens[0].tokens ? (u.tokens[0].raw = g.raw + u.tokens[0].raw, u.tokens[0].text = g.raw + u.tokens[0].text, u.tokens[0].tokens.unshift(g)) : u.tokens.unshift({ type: "paragraph", raw: g.raw, text: g.raw, tokens: [g] }) : u.tokens.unshift(g);
3227
+ }
3228
+ } else u.task && (u.task = false);
3229
+ }
3230
+ if (i.loose) for (let u of i.items) {
3231
+ u.loose = true;
3232
+ for (let d of u.tokens) d.type === "text" && (d.type = "paragraph");
3233
+ }
3234
+ return i;
3235
+ }
3236
+ }
3237
+ html(e) {
3238
+ let t = this.rules.block.html.exec(e);
3239
+ if (t) {
3240
+ let n = ge(t[0]);
3241
+ return { type: "html", block: true, raw: n, pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: n };
3242
+ }
3243
+ }
3244
+ def(e) {
3245
+ let t = this.rules.block.def.exec(e);
3246
+ if (t) {
3247
+ if (!this.rules.other.startAngleBracket.test(t[2]) && ke(t[2], "()") !== -1) return;
3248
+ let n = F(t[1]), s = t[2] ? t[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", r = t[3] ? t[3].substring(1, t[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t[3];
3249
+ return { type: "def", tag: n, raw: L(t[0], `
3250
+ `), href: s, title: r };
3251
+ }
3252
+ }
3253
+ table(e) {
3254
+ let t = this.rules.block.table.exec(e);
3255
+ if (!t || !this.rules.other.tableDelimiter.test(t[2])) return;
3256
+ let n = de(t[1]), s = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
3257
+ `) : [], o = { type: "table", raw: L(t[0], `
3258
+ `), header: [], align: [], rows: [] };
3259
+ if (n.length === s.length) {
3260
+ for (let i of s) this.rules.other.tableAlignRight.test(i) ? o.align.push("right") : this.rules.other.tableAlignCenter.test(i) ? o.align.push("center") : this.rules.other.tableAlignLeft.test(i) ? o.align.push("left") : o.align.push(null);
3261
+ for (let i = 0; i < n.length; i++) o.header.push({ text: n[i], tokens: this.lexer.inline(n[i]), header: true, align: o.align[i] });
3262
+ for (let i of r) o.rows.push(de(i, o.header.length).map((l, p) => ({ text: l, tokens: this.lexer.inline(l), header: false, align: o.align[p] })));
3263
+ return o;
3264
+ }
3265
+ }
3266
+ lheading(e) {
3267
+ let t = this.rules.block.lheading.exec(e);
3268
+ if (t) {
3269
+ let n = t[1].trim();
3270
+ return { type: "heading", raw: L(t[0], `
3271
+ `), depth: t[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
3272
+ }
3273
+ }
3274
+ paragraph(e) {
3275
+ let t = this.rules.block.paragraph.exec(e);
3276
+ if (t) {
3277
+ let n = t[1].charAt(t[1].length - 1) === `
3278
+ ` ? t[1].slice(0, -1) : t[1];
3279
+ return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
3280
+ }
3281
+ }
3282
+ text(e) {
3283
+ let t = this.rules.block.text.exec(e);
3284
+ if (t) return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
3285
+ }
3286
+ escape(e) {
3287
+ let t = this.rules.inline.escape.exec(e);
3288
+ if (t) return { type: "escape", raw: t[0], text: t[1] };
3289
+ }
3290
+ tag(e) {
3291
+ let t = this.rules.inline.tag.exec(e);
3292
+ if (t) return !this.lexer.state.inLink && this.rules.other.startATag.test(t[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t[0] };
3293
+ }
3294
+ link(e) {
3295
+ if (this.lexer.state.linkParenPossible === false) return;
3296
+ let t = this.rules.inline.link.exec(e);
3297
+ if (t) {
3298
+ let n = t[0].charAt(0) === "!" ? 2 : 1;
3299
+ if (!this.options.pedantic && Be(e, t[1], n, this.rules)) return;
3300
+ let s = t[2].trim();
3301
+ if (!this.options.pedantic && this.rules.other.startAngleBracket.test(s)) {
3302
+ if (!this.rules.other.endAngleBracket.test(s)) return;
3303
+ let l = L(s.slice(0, -1), "\\");
3304
+ if ((s.length - l.length) % 2 === 0) return;
3305
+ } else {
3306
+ let l = ke(t[2], "()");
3307
+ if (l === -2) return;
3308
+ if (l > -1) {
3309
+ let h = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + l;
3310
+ t[2] = t[2].substring(0, l), t[0] = t[0].substring(0, h).trim(), t[3] = "";
3311
+ }
3312
+ }
3313
+ let r = L(t[0].slice(0, -1), "\\");
3314
+ if ((t[0].length - r.length) % 2 === 0) return;
3315
+ let o = t[2], i = "";
3316
+ if (this.options.pedantic) {
3317
+ let l = this.rules.other.pedanticHrefTitle.exec(o);
3318
+ l && (o = l[1], i = l[3]);
3319
+ } else i = t[3] ? t[3].slice(1, -1) : "";
3320
+ return o = o.trim(), this.rules.other.startAngleBracket.test(o) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(s) ? o = o.slice(1) : o = o.slice(1, -1)), De(t, { href: o && o.replace(this.rules.inline.anyPunctuation, "$1"), title: i && i.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
3321
+ }
3322
+ }
3323
+ reflink(e, t) {
3324
+ let n;
3325
+ if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
3326
+ let s = n[0].charAt(0) === "!" ? 2 : 1;
3327
+ if (!this.options.pedantic && Be(e, n[1], s, this.rules)) return;
3328
+ let r = t[F(n[2] || n[1])];
3329
+ if (!r) {
3330
+ let o = n[0].charAt(0);
3331
+ return { type: "text", raw: o, text: o };
3332
+ }
3333
+ return De(n, r, n[0], this.lexer, this.rules);
3334
+ }
3335
+ }
3336
+ emStrong(e, t, n = "") {
3337
+ let s = this.rules.inline.emStrongLDelim.exec(e);
3338
+ if (!s || !s[1] && !s[2] && !s[3] && !s[4]) return;
3339
+ let r = s[0][0], o = n === r, i = t.length - e.length, l = i;
3340
+ for (; !this.options.pedantic && l > 0 && t[l - 1] === r; ) l--;
3341
+ let p = [...t.slice(Math.max(0, l - 2), l)].at(-1) ?? "", h = p === "*" || p === "_" || !!this.rules.inline.punctuation.exec(p);
3342
+ l < i && (n = p);
3343
+ let u = l < i ? h : !!this.rules.inline.punctuation.exec(n);
3344
+ if (s[4] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
3345
+ let d = s[1] || s[3] || "";
3346
+ if (!d || !n || u) {
3347
+ let k = [...s[0]].length - 1, g, b, m = k, f = 0, y = i - l + k, R = !this.options.pedantic && !!p.trim() && (!!d || r === "*" && !h);
3348
+ if (r !== "*" && r !== "_") return;
3349
+ let A = r === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd, v = ze(this, t, r), Q = t.length - e.length + k;
3350
+ if (v < Q) return;
3351
+ t = t.slice(-1 * e.length + k);
3352
+ let ee = v - Q;
3353
+ for (A.lastIndex = 0; (s = A.exec(t)) !== null && !(s.index > ee); ) {
3354
+ if (g = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !g) continue;
3355
+ if (b = [...g].length, s[3] || s[4]) {
3356
+ m += b;
3357
+ continue;
3358
+ } else if (s[5] || s[6] || R) {
3359
+ if (o && (s[5] || s[6])) break;
3360
+ if (y % 3 && !((y + b) % 3)) {
3361
+ f += b;
3362
+ continue;
3363
+ }
3364
+ }
3365
+ if (m -= b, m > 0) continue;
3366
+ b = Math.min(b, b + m + f);
3367
+ let te = [...s[0]][0].length, M = e.slice(0, k + s.index + te + b);
3368
+ if (Math.min(k, b) % 2) {
3369
+ let U = M.slice(1, -1);
3370
+ return { type: "em", raw: M, text: U, tokens: this.lexer.inlineTokens(U) };
3371
+ }
3372
+ let ne = M.slice(2, -2);
3373
+ return { type: "strong", raw: M, text: ne, tokens: this.lexer.inlineTokens(ne) };
3374
+ }
3375
+ }
3376
+ }
3377
+ codespan(e) {
3378
+ let t = this.rules.inline.code.exec(e);
3379
+ if (t) {
3380
+ let n = t[2].replace(this.rules.other.newLineCharGlobal, " "), s = this.rules.other.nonSpaceChar.test(n), r = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
3381
+ return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
3382
+ }
3383
+ }
3384
+ br(e) {
3385
+ let t = this.rules.inline.br.exec(e);
3386
+ if (t) return { type: "br", raw: t[0] };
3387
+ }
3388
+ del(e, t, n = "") {
3389
+ let s = this.rules.inline.delLDelim.exec(e);
3390
+ if (!s) return;
3391
+ if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
3392
+ let o = [...s[0]].length - 1, i, l, p = o, h = this.rules.inline.delRDelim, u = Me(this, t), d = t.length - e.length + o;
3393
+ if (u < d) return;
3394
+ t = t.slice(-1 * e.length + o);
3395
+ let k = u - d;
3396
+ for (h.lastIndex = 0; (s = h.exec(t)) !== null && !(s.index > k); ) {
3397
+ if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i || (l = [...i].length, l !== o)) continue;
3398
+ if (s[3] || s[4]) {
3399
+ p += l;
3400
+ continue;
3401
+ }
3402
+ if (p -= l, p > 0) continue;
3403
+ l = Math.min(l, l + p);
3404
+ let g = [...s[0]][0].length, b = e.slice(0, o + s.index + g + l), m = b.slice(o, -o);
3405
+ return { type: "del", raw: b, text: m, tokens: this.lexer.inlineTokens(m) };
3406
+ }
3407
+ }
3408
+ }
3409
+ autolink(e) {
3410
+ let t = this.rules.inline.autolink.exec(e);
3411
+ if (t) {
3412
+ let n, s;
3413
+ return t[2] === "@" ? (n = t[1], s = "mailto:" + n) : (n = t[1], s = n), { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
3414
+ }
3415
+ }
3416
+ url(e) {
3417
+ let t;
3418
+ if (t = this.rules.inline.url.exec(e)) {
3419
+ let n, s;
3420
+ if (t[2] === "@") n = t[0], s = "mailto:" + n;
3421
+ else {
3422
+ let r;
3423
+ do
3424
+ r = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
3425
+ while (r !== t[0]);
3426
+ n = t[0], t[1] === "www." ? s = "http://" + t[0] : s = t[0];
3427
+ }
3428
+ return { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
3429
+ }
3430
+ }
3431
+ inlineText(e) {
3432
+ let t = this.rules.inline.text.exec(e);
3433
+ if (t) {
3434
+ let n = this.lexer.state.inRawBlock;
3435
+ return { type: "text", raw: t[0], text: n ? t[0] : Ie(t[0]), escaped: n };
3436
+ }
3437
+ }
3438
+ };
3439
+ var O = class a {
3440
+ tokens;
3441
+ options;
3442
+ state;
3443
+ inlineQueue;
3444
+ tokenizer;
3445
+ constructor(e) {
3446
+ this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e || S, this.options.tokenizer = this.options.tokenizer || new _(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, linkEmitted: false, linkParenPossible: true, top: true };
3447
+ let t = { other: T, block: V.normal, inline: G.normal };
3448
+ this.options.pedantic ? (t.block = V.pedantic, t.inline = G.pedantic) : this.options.gfm && (t.block = V.gfm, this.options.breaks ? t.inline = G.breaks : t.inline = G.gfm), this.tokenizer.rules = t;
3449
+ }
3450
+ static get rules() {
3451
+ return { block: V, inline: G };
3452
+ }
3453
+ static lex(e, t) {
3454
+ return new a(t).lex(e);
3455
+ }
3456
+ static lexInline(e, t) {
3457
+ return new a(t).inlineTokens(e);
3458
+ }
3459
+ lex(e) {
3460
+ e = e.replace(T.carriageReturn, `
3461
+ `), this.blockTokens(e, this.tokens);
3462
+ for (let t = 0; t < this.inlineQueue.length; t++) {
3463
+ let n = this.inlineQueue[t];
3464
+ this.state.inRawBlock = false, this.inlineTokens(n.src, n.tokens);
3465
+ }
3466
+ return this.inlineQueue = [], this.tokens;
3467
+ }
3468
+ blockTokens(e, t = [], n = false) {
3469
+ this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(T.tabCharGlobal, " ").replace(T.spaceLine, ""));
3470
+ let s = 1 / 0;
3471
+ for (; e; ) {
3472
+ if (e.length < s) s = e.length;
3473
+ else {
3474
+ this.infiniteLoopError(e.charCodeAt(0));
3475
+ break;
3476
+ }
3477
+ let r;
3478
+ if (this.options.extensions?.block?.some((i) => (r = i.call({ lexer: this }, e, t)) ? (e = e.substring(r.raw.length), t.push(r), true) : false)) continue;
3479
+ if (r = this.tokenizer.space(e)) {
3480
+ e = e.substring(r.raw.length);
3481
+ let i = t.at(-1);
3482
+ r.raw.length === 1 && i !== void 0 ? i.raw += `
3483
+ ` : t.push(r);
3484
+ continue;
3485
+ }
3486
+ if (r = this.tokenizer.code(e)) {
3487
+ e = e.substring(r.raw.length);
3488
+ let i = t.at(-1);
3489
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
3490
+ `) ? "" : `
3491
+ `) + r.raw, i.text += `
3492
+ ` + r.text, this.inlineQueue.at(-1).src = i.text) : t.push(r);
3493
+ continue;
3494
+ }
3495
+ if (r = this.tokenizer.fences(e)) {
3496
+ e = e.substring(r.raw.length), t.push(r);
3497
+ continue;
3498
+ }
3499
+ if (r = this.tokenizer.heading(e)) {
3500
+ e = e.substring(r.raw.length), t.push(r);
3501
+ continue;
3502
+ }
3503
+ if (r = this.tokenizer.hr(e)) {
3504
+ e = e.substring(r.raw.length), t.push(r);
3505
+ continue;
3506
+ }
3507
+ if (r = this.tokenizer.blockquote(e)) {
3508
+ e = e.substring(r.raw.length), t.push(r);
3509
+ continue;
3510
+ }
3511
+ if (r = this.tokenizer.list(e)) {
3512
+ e = e.substring(r.raw.length), t.push(r);
3513
+ continue;
3514
+ }
3515
+ if (r = this.tokenizer.html(e)) {
3516
+ e = e.substring(r.raw.length), t.push(r);
3517
+ continue;
3518
+ }
3519
+ if (r = this.tokenizer.def(e)) {
3520
+ e = e.substring(r.raw.length);
3521
+ let i = t.at(-1);
3522
+ i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
3523
+ `) ? "" : `
3524
+ `) + r.raw, i.text += `
3525
+ ` + r.raw, this.inlineQueue.at(-1).src = i.text) : (this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }), t.push(r));
3526
+ continue;
3527
+ }
3528
+ if (r = this.tokenizer.table(e)) {
3529
+ e = e.substring(r.raw.length), t.push(r);
3530
+ continue;
3531
+ }
3532
+ if (r = this.tokenizer.lheading(e)) {
3533
+ e = e.substring(r.raw.length), t.push(r);
3534
+ continue;
3535
+ }
3536
+ let o = e;
3537
+ if (this.options.extensions?.startBlock) {
3538
+ let i = 1 / 0, l = e.slice(1), p;
3539
+ this.options.extensions.startBlock.forEach((h) => {
3540
+ p = h.call({ lexer: this }, l), typeof p == "number" && p >= 0 && (i = Math.min(i, p));
3541
+ }), i < 1 / 0 && i >= 0 && (o = e.substring(0, i + 1));
3542
+ }
3543
+ if (this.state.top && (r = this.tokenizer.paragraph(o))) {
3544
+ let i = t.at(-1);
3545
+ n && i?.type === "paragraph" ? (i.raw += (i.raw.endsWith(`
3546
+ `) ? "" : `
3547
+ `) + r.raw, i.text += `
3548
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r), n = o.length !== e.length, e = e.substring(r.raw.length);
3549
+ continue;
3550
+ }
3551
+ if (r = this.tokenizer.text(e)) {
3552
+ e = e.substring(r.raw.length);
3553
+ let i = t.at(-1);
3554
+ i?.type === "text" ? (i.raw += (i.raw.endsWith(`
3555
+ `) ? "" : `
3556
+ `) + r.raw, i.text += `
3557
+ ` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r);
3558
+ continue;
3559
+ }
3560
+ if (e) {
3561
+ this.infiniteLoopError(e.charCodeAt(0));
3562
+ break;
3563
+ }
3564
+ }
3565
+ return this.state.top = true, t;
3566
+ }
3567
+ inline(e, t = []) {
3568
+ return this.inlineQueue.push({ src: e, tokens: t }), t;
3569
+ }
3570
+ linkInText(e) {
3571
+ if (!e.includes("[")) return false;
3572
+ let t = this.tokenizer.rules.inline.link;
3573
+ for (let n of e.matchAll(this.tokenizer.rules.inline.blockSkip)) if (t.test(n[0]) && e.charAt(n.index - 1) !== "!") return true;
3574
+ for (let n of e.matchAll(this.tokenizer.rules.inline.reflinkSearch)) {
3575
+ let s = n[0], r = s.lastIndexOf("[");
3576
+ if (!(s.charAt(0) === "!" || !Object.hasOwn(this.tokens.links, F(s.slice(r + 1, -1)))) && !(r > 1 && this.linkInText(s.slice(1, r - 1)))) return true;
3577
+ }
3578
+ return false;
3579
+ }
3580
+ inlineTokens(e, t = []) {
3581
+ this.tokenizer.lexer = this;
3582
+ let n = this.state.linkParenPossible;
3583
+ this.state.linkParenPossible = n && e.includes(")");
3584
+ try {
3585
+ return this.#e(e, t);
3586
+ } finally {
3587
+ this.state.linkParenPossible = n;
3588
+ }
3589
+ }
3590
+ #e(e, t) {
3591
+ let n = e.includes("*") || e.includes("_") || e.includes("~") || this.options.hooks?.emStrongMask || this.tokenizer.emStrong !== _.prototype.emStrong || this.tokenizer.del !== _.prototype.del ? this.#n(e) : e;
3592
+ Ae(this.tokenizer, n);
3593
+ try {
3594
+ return this.#t(e, n, t);
3595
+ } finally {
3596
+ Ee(this.tokenizer);
3597
+ }
3598
+ }
3599
+ #t(e, t, n) {
3600
+ let s = false, r = "", o = 1 / 0;
3601
+ for (; e; ) {
3602
+ if (e.length < o) o = e.length;
3603
+ else {
3604
+ this.infiniteLoopError(e.charCodeAt(0));
3605
+ break;
3606
+ }
3607
+ s || (r = ""), s = false;
3608
+ let i;
3609
+ if (this.options.extensions?.inline?.some((p) => (i = p.call({ lexer: this }, e, n)) ? (e = e.substring(i.raw.length), n.push(i), true) : false)) continue;
3610
+ if (i = this.tokenizer.escape(e)) {
3611
+ e = e.substring(i.raw.length), n.push(i);
3612
+ continue;
3613
+ }
3614
+ if (i = this.tokenizer.tag(e)) {
3615
+ e = e.substring(i.raw.length), n.push(i);
3616
+ continue;
3617
+ }
3618
+ if (i = this.tokenizer.link(e)) {
3619
+ e = e.substring(i.raw.length), n.push(i);
3620
+ continue;
3621
+ }
3622
+ if (i = this.tokenizer.reflink(e, this.tokens.links)) {
3623
+ e = e.substring(i.raw.length);
3624
+ let p = n.at(-1);
3625
+ i.type === "text" && p?.type === "text" ? (p.raw += i.raw, p.text += i.text) : n.push(i);
3626
+ continue;
3627
+ }
3628
+ if (i = this.tokenizer.emStrong(e, t, r)) {
3629
+ e = e.substring(i.raw.length), n.push(i);
3630
+ continue;
3631
+ }
3632
+ if (i = this.tokenizer.codespan(e)) {
3633
+ e = e.substring(i.raw.length), n.push(i);
3634
+ continue;
3635
+ }
3636
+ if (i = this.tokenizer.br(e)) {
3637
+ e = e.substring(i.raw.length), n.push(i);
3638
+ continue;
3639
+ }
3640
+ if (i = this.tokenizer.del(e, t, r)) {
3641
+ e = e.substring(i.raw.length), n.push(i);
3642
+ continue;
3643
+ }
3644
+ if (i = this.tokenizer.autolink(e)) {
3645
+ e = e.substring(i.raw.length), n.push(i);
3646
+ continue;
3647
+ }
3648
+ if (!this.state.inLink && (i = this.tokenizer.url(e))) {
3649
+ e = e.substring(i.raw.length), n.push(i);
3650
+ continue;
3651
+ }
3652
+ let l = e;
3653
+ if (this.options.extensions?.startInline) {
3654
+ let p = 1 / 0, h = e.slice(1), u;
3655
+ this.options.extensions.startInline.forEach((d) => {
3656
+ u = d.call({ lexer: this }, h), typeof u == "number" && u >= 0 && (p = Math.min(p, u));
3657
+ }), p < 1 / 0 && p >= 0 && (l = e.substring(0, p + 1));
3658
+ }
3659
+ if (i = this.tokenizer.inlineText(l)) {
3660
+ e = e.substring(i.raw.length), i.raw.slice(-1) !== "_" && (r = i.raw.slice(-1)), s = true;
3661
+ let p = n.at(-1);
3662
+ p?.type === "text" ? (p.raw += i.raw, p.text += i.text) : n.push(i);
3663
+ continue;
3664
+ }
3665
+ if (e) {
3666
+ this.infiniteLoopError(e.charCodeAt(0));
3667
+ break;
3668
+ }
3669
+ }
3670
+ return n;
3671
+ }
3672
+ #n(e) {
3673
+ let t = e;
3674
+ if (this.tokens.links && e.includes("[")) {
3675
+ let n = this.tokenizer.rules.inline.reflinkSearch, s = (r) => {
3676
+ let o = r.lastIndexOf("[");
3677
+ if (!Object.hasOwn(this.tokens.links, F(r.slice(o + 1, -1)))) return r;
3678
+ if (o > 1 && r.charAt(0) !== "!") {
3679
+ let i = r.slice(1, o - 1);
3680
+ if (this.linkInText(i)) return "[" + i.replace(n, s) + "][" + "a".repeat(r.length - o - 2) + "]";
3681
+ }
3682
+ return "[" + "a".repeat(r.length - 2) + "]";
3683
+ };
3684
+ t = t.replace(n, s);
3685
+ }
3686
+ return t = t.replace(this.tokenizer.rules.inline.anyPunctuationOutsideCode, (n, s, r) => r ? "+".repeat(n.length) : s ? s + n.slice(s.length, -s.length).replace(/`/g, "+") + s : n), t = t.replace(this.tokenizer.rules.inline.blockSkip, (n, s, r) => {
3687
+ let o = r ? r.length : 0;
3688
+ return n.slice(0, o) + "[" + "a".repeat(n.length - o - 2) + "]";
3689
+ }), t = this.options.hooks?.emStrongMask?.call({ lexer: this }, t) ?? t, t;
3690
+ }
3691
+ infiniteLoopError(e) {
3692
+ let t = "Infinite loop on byte: " + e;
3693
+ if (this.options.silent) console.error(t);
3694
+ else throw new Error(t);
3695
+ }
3696
+ };
3697
+ var C = class {
3698
+ options;
3699
+ parser;
3700
+ constructor(e) {
3701
+ this.options = e || S;
3702
+ }
3703
+ space(e) {
3704
+ return "";
3705
+ }
3706
+ code({ text: e, lang: t, escaped: n }) {
3707
+ let s = (t || "").match(T.notSpaceStart)?.[0], r = e ? e.replace(T.endingNewline, "") + `
3708
+ ` : "";
3709
+ return s ? '<pre><code class="language-' + P(s) + '">' + (n ? r : P(r, true)) + `</code></pre>
3710
+ ` : "<pre><code>" + (n ? r : P(r, true)) + `</code></pre>
3711
+ `;
3712
+ }
3713
+ blockquote({ tokens: e }) {
3714
+ return `<blockquote>
3715
+ ${this.parser.parse(e)}</blockquote>
3716
+ `;
3717
+ }
3718
+ html({ text: e }) {
3719
+ return e;
3720
+ }
3721
+ def(e) {
3722
+ return "";
3723
+ }
3724
+ heading({ tokens: e, depth: t }) {
3725
+ return `<h${t}>${this.parser.parseInline(e)}</h${t}>
3726
+ `;
3727
+ }
3728
+ hr(e) {
3729
+ return `<hr>
3730
+ `;
3731
+ }
3732
+ list(e) {
3733
+ let t = e.ordered, n = e.start, s = "";
3734
+ for (let i = 0; i < e.items.length; i++) {
3735
+ let l = e.items[i];
3736
+ s += this.listitem(l);
3737
+ }
3738
+ let r = t ? "ol" : "ul", o = t && n !== 1 ? ' start="' + n + '"' : "";
3739
+ return "<" + r + o + `>
3740
+ ` + s + "</" + r + `>
3741
+ `;
3742
+ }
3743
+ listitem(e) {
3744
+ return `<li>${this.parser.parse(e.tokens)}</li>
3745
+ `;
3746
+ }
3747
+ checkbox({ checked: e }) {
3748
+ return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
3749
+ }
3750
+ paragraph({ tokens: e }) {
3751
+ return `<p>${this.parser.parseInline(e)}</p>
3752
+ `;
3753
+ }
3754
+ table(e) {
3755
+ let t = "", n = "";
3756
+ for (let r = 0; r < e.header.length; r++) n += this.tablecell(e.header[r]);
3757
+ t += this.tablerow({ text: n });
3758
+ let s = "";
3759
+ for (let r = 0; r < e.rows.length; r++) {
3760
+ let o = e.rows[r];
3761
+ n = "";
3762
+ for (let i = 0; i < o.length; i++) n += this.tablecell(o[i]);
3763
+ s += this.tablerow({ text: n });
3764
+ }
3765
+ return s && (s = `<tbody>${s}</tbody>`), `<table>
3766
+ <thead>
3767
+ ` + t + `</thead>
3768
+ ` + s + `</table>
3769
+ `;
3770
+ }
3771
+ tablerow({ text: e }) {
3772
+ return `<tr>
3773
+ ${e}</tr>
3774
+ `;
3775
+ }
3776
+ tablecell(e) {
3777
+ let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
3778
+ return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
3779
+ `;
3780
+ }
3781
+ strong({ tokens: e }) {
3782
+ return `<strong>${this.parser.parseInline(e)}</strong>`;
3783
+ }
3784
+ em({ tokens: e }) {
3785
+ return `<em>${this.parser.parseInline(e)}</em>`;
3786
+ }
3787
+ codespan({ text: e }) {
3788
+ return `<code>${P(e, true)}</code>`;
3789
+ }
3790
+ br(e) {
3791
+ return "<br>";
3792
+ }
3793
+ del({ tokens: e }) {
3794
+ return `<del>${this.parser.parseInline(e)}</del>`;
3795
+ }
3796
+ link({ href: e, title: t, text: n, tokens: s, autolink: r }) {
3797
+ let o = r ? P(n, true) : this.parser.parseInline(s), i = he(e);
3798
+ if (i === null) return o;
3799
+ e = P(i, r);
3800
+ let l = '<a href="' + e + '"';
3801
+ return t && (l += ' title="' + P(t) + '"'), l += ">" + o + "</a>", l;
3802
+ }
3803
+ image({ href: e, title: t, text: n, tokens: s }) {
3804
+ s && (n = this.parser.parseInline(s, this.parser.textRenderer));
3805
+ let r = he(e);
3806
+ if (r === null) return P(n);
3807
+ e = r;
3808
+ let o = `<img src="${P(e)}" alt="${P(n)}"`;
3809
+ return t && (o += ` title="${P(t)}"`), o += ">", o;
3810
+ }
3811
+ text(e) {
3812
+ return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : "escaped" in e && e.escaped ? e.text : P(e.text);
3813
+ }
3814
+ };
3815
+ var E = class {
3816
+ parser;
3817
+ strong({ text: e, tokens: t }) {
3818
+ return t ? this.parser.parseInline(t, this) : e;
3819
+ }
3820
+ em({ text: e, tokens: t }) {
3821
+ return t ? this.parser.parseInline(t, this) : e;
3822
+ }
3823
+ codespan({ text: e }) {
3824
+ return e;
3825
+ }
3826
+ del({ text: e, tokens: t }) {
3827
+ return t ? this.parser.parseInline(t, this) : e;
3828
+ }
3829
+ html({ text: e }) {
3830
+ return e;
3831
+ }
3832
+ text({ text: e }) {
3833
+ return e;
3834
+ }
3835
+ link({ text: e, tokens: t }) {
3836
+ return t ? this.parser.parseInline(t, this) : e;
3837
+ }
3838
+ image({ text: e, tokens: t }) {
3839
+ return t ? this.parser.parseInline(t, this) : e;
3840
+ }
3841
+ br() {
3842
+ return "";
3843
+ }
3844
+ checkbox({ raw: e }) {
3845
+ return e;
3846
+ }
3847
+ };
3848
+ var w = class a2 {
3849
+ options;
3850
+ renderer;
3851
+ textRenderer;
3852
+ constructor(e) {
3853
+ this.options = e || S, this.options.renderer = this.options.renderer || new C(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new E(), this.textRenderer.parser = this;
3854
+ }
3855
+ static parse(e, t) {
3856
+ return new a2(t).parse(e);
3857
+ }
3858
+ static parseInline(e, t) {
3859
+ return new a2(t).parseInline(e);
3860
+ }
3861
+ parse(e) {
3862
+ this.renderer.parser = this;
3863
+ let t = "";
3864
+ for (let n = 0; n < e.length; n++) {
3865
+ let s = e[n];
3866
+ if (this.options.extensions?.renderers?.[s.type]) {
3867
+ let o = s, i = this.options.extensions.renderers[o.type].call({ parser: this }, o);
3868
+ if (i !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "checkbox", "html", "def", "paragraph", "text"].includes(o.type)) {
3869
+ t += i || "";
3870
+ continue;
3871
+ }
3872
+ }
3873
+ let r = s;
3874
+ switch (r.type) {
3875
+ case "space": {
3876
+ t += this.renderer.space(r);
3877
+ break;
3878
+ }
3879
+ case "hr": {
3880
+ t += this.renderer.hr(r);
3881
+ break;
3882
+ }
3883
+ case "heading": {
3884
+ t += this.renderer.heading(r);
3885
+ break;
3886
+ }
3887
+ case "code": {
3888
+ t += this.renderer.code(r);
3889
+ break;
3890
+ }
3891
+ case "table": {
3892
+ t += this.renderer.table(r);
3893
+ break;
3894
+ }
3895
+ case "blockquote": {
3896
+ t += this.renderer.blockquote(r);
3897
+ break;
3898
+ }
3899
+ case "list": {
3900
+ t += this.renderer.list(r);
3901
+ break;
3902
+ }
3903
+ case "checkbox": {
3904
+ t += this.renderer.checkbox(r);
3905
+ break;
3906
+ }
3907
+ case "html": {
3908
+ t += this.renderer.html(r);
3909
+ break;
3910
+ }
3911
+ case "def": {
3912
+ t += this.renderer.def(r);
3913
+ break;
3914
+ }
3915
+ case "paragraph": {
3916
+ t += this.renderer.paragraph(r);
3917
+ break;
3918
+ }
3919
+ case "text": {
3920
+ t += this.renderer.text(r);
3921
+ break;
3922
+ }
3923
+ default: {
3924
+ let o = 'Token with "' + r.type + '" type was not found.';
3925
+ if (this.options.silent) return console.error(o), "";
3926
+ throw new Error(o);
3927
+ }
3928
+ }
3929
+ }
3930
+ return t;
3931
+ }
3932
+ parseInline(e, t = this.renderer) {
3933
+ this.renderer.parser = this;
3934
+ let n = "";
3935
+ for (let s = 0; s < e.length; s++) {
3936
+ let r = e[s];
3937
+ if (this.options.extensions?.renderers?.[r.type]) {
3938
+ let i = this.options.extensions.renderers[r.type].call({ parser: this }, r);
3939
+ if (i !== false || !["escape", "html", "link", "image", "checkbox", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
3940
+ n += i || "";
3941
+ continue;
3942
+ }
3943
+ }
3944
+ let o = r;
3945
+ switch (o.type) {
3946
+ case "escape": {
3947
+ n += t.text(o);
3948
+ break;
3949
+ }
3950
+ case "html": {
3951
+ n += t.html(o);
3952
+ break;
3953
+ }
3954
+ case "link": {
3955
+ n += t.link(o);
3956
+ break;
3957
+ }
3958
+ case "image": {
3959
+ n += t.image(o);
3960
+ break;
3961
+ }
3962
+ case "checkbox": {
3963
+ n += t.checkbox(o);
3964
+ break;
3965
+ }
3966
+ case "strong": {
3967
+ n += t.strong(o);
3968
+ break;
3969
+ }
3970
+ case "em": {
3971
+ n += t.em(o);
3972
+ break;
3973
+ }
3974
+ case "codespan": {
3975
+ n += t.codespan(o);
3976
+ break;
3977
+ }
3978
+ case "br": {
3979
+ n += t.br(o);
3980
+ break;
3981
+ }
3982
+ case "del": {
3983
+ n += t.del(o);
3984
+ break;
3985
+ }
3986
+ case "text": {
3987
+ n += t.text(o);
3988
+ break;
3989
+ }
3990
+ default: {
3991
+ let i = 'Token with "' + o.type + '" type was not found.';
3992
+ if (this.options.silent) return console.error(i), "";
3993
+ throw new Error(i);
3994
+ }
3995
+ }
3996
+ }
3997
+ return n;
3998
+ }
3999
+ };
4000
+ var I = class {
4001
+ options;
4002
+ block;
4003
+ constructor(e) {
4004
+ this.options = e || S;
4005
+ }
4006
+ static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
4007
+ static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]);
4008
+ preprocess(e) {
4009
+ return e;
4010
+ }
4011
+ postprocess(e) {
4012
+ return e;
4013
+ }
4014
+ processAllTokens(e) {
4015
+ return e;
4016
+ }
4017
+ emStrongMask(e) {
4018
+ return e;
4019
+ }
4020
+ provideLexer(e = this.block) {
4021
+ return e ? O.lex : O.lexInline;
4022
+ }
4023
+ provideParser(e = this.block) {
4024
+ return e ? w.parse : w.parseInline;
4025
+ }
4026
+ };
4027
+ function z12(a3, e) {
4028
+ if (Array.isArray(e)) for (let t = 0; t < e.length; t++) a3.push(e[t]);
4029
+ else a3.push(e);
4030
+ }
4031
+ var Y = class {
4032
+ defaults = H();
4033
+ options = this.setOptions;
4034
+ parse = this.parseMarkdown(true);
4035
+ parseInline = this.parseMarkdown(false);
4036
+ Parser = w;
4037
+ Renderer = C;
4038
+ TextRenderer = E;
4039
+ Lexer = O;
4040
+ Tokenizer = _;
4041
+ Hooks = I;
4042
+ constructor(...e) {
4043
+ this.use(...e);
4044
+ }
4045
+ walkTokens(e, t) {
4046
+ let n = [];
4047
+ for (let s of e) switch (z12(n, t.call(this, s)), s.type) {
4048
+ case "table": {
4049
+ let r = s;
4050
+ for (let o of r.header) z12(n, this.walkTokens(o.tokens, t));
4051
+ for (let o of r.rows) for (let i of o) z12(n, this.walkTokens(i.tokens, t));
4052
+ break;
4053
+ }
4054
+ case "list": {
4055
+ let r = s;
4056
+ z12(n, this.walkTokens(r.items, t));
4057
+ break;
4058
+ }
4059
+ default: {
4060
+ let r = s;
4061
+ this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((o) => {
4062
+ let i = r[o].flat(1 / 0);
4063
+ z12(n, this.walkTokens(i, t));
4064
+ }) : r.tokens && z12(n, this.walkTokens(r.tokens, t));
4065
+ }
4066
+ }
4067
+ return n;
4068
+ }
4069
+ use(...e) {
4070
+ let t = this.defaults.extensions || { renderers: /* @__PURE__ */ Object.create(null), childTokens: /* @__PURE__ */ Object.create(null) };
4071
+ return e.forEach((n) => {
4072
+ let s = { ...n };
4073
+ if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
4074
+ if (!r.name) throw new Error("extension name required");
4075
+ if ("renderer" in r) {
4076
+ let o = t.renderers[r.name];
4077
+ o ? t.renderers[r.name] = function(...i) {
4078
+ let l = r.renderer.apply(this, i);
4079
+ return l === false && (l = o.apply(this, i)), l;
4080
+ } : t.renderers[r.name] = r.renderer;
4081
+ }
4082
+ if ("tokenizer" in r) {
4083
+ if (!r.level || r.level !== "block" && r.level !== "inline") throw new Error("extension level must be 'block' or 'inline'");
4084
+ let o = t[r.level];
4085
+ o ? o.unshift(r.tokenizer) : t[r.level] = [r.tokenizer], r.start && (r.level === "block" ? t.startBlock ? t.startBlock.push(r.start) : t.startBlock = [r.start] : r.level === "inline" && (t.startInline ? t.startInline.push(r.start) : t.startInline = [r.start]));
4086
+ }
4087
+ "childTokens" in r && r.childTokens && (t.childTokens[r.name] = r.childTokens);
4088
+ }), s.extensions = t), n.renderer) {
4089
+ let r = this.defaults.renderer || new C(this.defaults);
4090
+ for (let o in n.renderer) {
4091
+ if (!(o in r)) throw new Error(`renderer '${o}' does not exist`);
4092
+ if (["options", "parser"].includes(o)) continue;
4093
+ let i = o, l = n.renderer[i], p = r[i];
4094
+ r[i] = (...h) => {
4095
+ let u = l.apply(r, h);
4096
+ return u === false && (u = p.apply(r, h)), u === false ? "" : u ?? "";
4097
+ };
4098
+ }
4099
+ s.renderer = r;
4100
+ }
4101
+ if (n.tokenizer) {
4102
+ let r = this.defaults.tokenizer || new _(this.defaults);
4103
+ for (let o in n.tokenizer) {
4104
+ if (!(o in r)) throw new Error(`tokenizer '${o}' does not exist`);
4105
+ if (["options", "rules", "lexer"].includes(o)) continue;
4106
+ let i = o, l = n.tokenizer[i], p = r[i];
4107
+ r[i] = (...h) => {
4108
+ let u = l.apply(r, h);
4109
+ return u === false && (u = p.apply(r, h)), u;
4110
+ };
4111
+ }
4112
+ s.tokenizer = r;
4113
+ }
4114
+ if (n.hooks) {
4115
+ let r = this.defaults.hooks || new I();
4116
+ for (let o in n.hooks) {
4117
+ if (!(o in r)) throw new Error(`hook '${o}' does not exist`);
4118
+ if (["options", "block"].includes(o)) continue;
4119
+ let i = o, l = n.hooks[i], p = r[i];
4120
+ I.passThroughHooks.has(o) ? r[i] = (h) => {
4121
+ if (r.options.async && I.passThroughHooksRespectAsync.has(o)) return (async () => {
4122
+ let d = await l.call(r, h);
4123
+ return p.call(r, d);
4124
+ })();
4125
+ let u = l.call(r, h);
4126
+ return p.call(r, u);
4127
+ } : r[i] = (...h) => {
4128
+ if (r.options.async) return (async () => {
4129
+ let d = await l.apply(r, h);
4130
+ return d === false && (d = await p.apply(r, h)), d;
4131
+ })();
4132
+ let u = l.apply(r, h);
4133
+ return u === false && (u = p.apply(r, h)), u;
4134
+ };
4135
+ }
4136
+ s.hooks = r;
4137
+ }
4138
+ if (n.walkTokens) {
4139
+ let r = this.defaults.walkTokens, o = n.walkTokens;
4140
+ s.walkTokens = function(i) {
4141
+ let l = [];
4142
+ return z12(l, o.call(this, i)), r && z12(l, r.call(this, i)), l;
4143
+ };
4144
+ }
4145
+ this.defaults = { ...this.defaults, ...s };
4146
+ }), this;
4147
+ }
4148
+ setOptions(e) {
4149
+ return this.defaults = { ...this.defaults, ...e }, this;
4150
+ }
4151
+ lexer(e, t) {
4152
+ return O.lex(e, t ?? this.defaults);
4153
+ }
4154
+ parser(e, t) {
4155
+ return w.parse(e, t ?? this.defaults);
4156
+ }
4157
+ parseMarkdown(e) {
4158
+ return (n, s) => {
4159
+ let r = { ...s }, o = { ...this.defaults, ...r }, i = this.onError(!!o.silent, !!o.async);
4160
+ if (this.defaults.async === true && r.async === false) return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
4161
+ if (typeof n > "u" || n === null) return i(new Error("marked(): input parameter is undefined or null"));
4162
+ if (typeof n != "string") return i(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
4163
+ if (o.hooks && (o.hooks.options = o, o.hooks.block = e), o.async) return (async () => {
4164
+ let l = o.hooks ? await o.hooks.preprocess(n) : n, h = await (o.hooks ? await o.hooks.provideLexer(e) : e ? O.lex : O.lexInline)(l, o), u = o.hooks ? await o.hooks.processAllTokens(h) : h;
4165
+ o.walkTokens && await Promise.all(this.walkTokens(u, o.walkTokens));
4166
+ let k = await (o.hooks ? await o.hooks.provideParser(e) : e ? w.parse : w.parseInline)(u, o);
4167
+ return o.hooks ? await o.hooks.postprocess(k) : k;
4168
+ })().catch(i);
4169
+ try {
4170
+ o.hooks && (n = o.hooks.preprocess(n));
4171
+ let p = (o.hooks ? o.hooks.provideLexer(e) : e ? O.lex : O.lexInline)(n, o);
4172
+ o.hooks && (p = o.hooks.processAllTokens(p)), o.walkTokens && this.walkTokens(p, o.walkTokens);
4173
+ let u = (o.hooks ? o.hooks.provideParser(e) : e ? w.parse : w.parseInline)(p, o);
4174
+ return o.hooks && (u = o.hooks.postprocess(u)), u;
4175
+ } catch (l) {
4176
+ return i(l);
4177
+ }
4178
+ };
4179
+ }
4180
+ onError(e, t) {
4181
+ return (n) => {
4182
+ if (n.message += `
4183
+ Please report this to https://github.com/markedjs/marked.`, e) {
4184
+ let s = "<p>An error occurred:</p><pre>" + P(n.message + "", true) + "</pre>";
4185
+ return t ? Promise.resolve(s) : s;
4186
+ }
4187
+ if (t) return Promise.reject(n);
4188
+ throw n;
4189
+ };
4190
+ }
4191
+ };
4192
+ var q = new Y();
4193
+ function x(a3, e) {
4194
+ return q.parse(a3, e);
4195
+ }
4196
+ x.options = x.setOptions = function(a3) {
4197
+ return q.setOptions(a3), x.defaults = q.defaults, se(x.defaults), x;
4198
+ };
4199
+ x.getDefaults = H;
4200
+ x.defaults = S;
4201
+ function Bt(...a3) {
4202
+ return q.use(...a3), x.defaults = q.defaults, se(x.defaults), x;
4203
+ }
4204
+ x.use = Bt;
4205
+ x.walkTokens = function(a3, e) {
4206
+ return q.walkTokens(a3, e);
4207
+ };
4208
+ x.parseInline = q.parseInline;
4209
+ x.Parser = w;
4210
+ x.parser = w.parse;
4211
+ x.Renderer = C;
4212
+ x.TextRenderer = E;
4213
+ x.Lexer = O;
4214
+ x.lexer = O.lex;
4215
+ x.Tokenizer = _;
4216
+ x.Hooks = I;
4217
+ x.parse = x;
4218
+ var _n = x.options;
4219
+ var $n = x.setOptions;
4220
+ var Ln = x.walkTokens;
4221
+ var Cn = x.parseInline;
4222
+ var An = w.parse;
4223
+ var En = O.lex;
4224
+
4225
+ // ../../packages/shared/src/markdown.ts
4226
+ var MAX_RENDERED_MARKDOWN = 200;
4227
+ var MAX_MARKDOWN_BYTES = 2 * 1024 * 1024;
4228
+ var STYLE = `
4229
+ :root{color-scheme:light dark;--fg:light-dark(#1f2328,#e6edf3);--muted:light-dark(#59636e,#9198a1);--bg:light-dark(#fff,#0d1117);--line:light-dark(#d1d9e0,#3d444d);--code:light-dark(#f6f8fa,#151b23);--link:light-dark(#0969da,#4493f8)}
4230
+ *{box-sizing:border-box}
4231
+ body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif}
4232
+ .fling-md-header,main{max-width:64rem;margin:0 auto;padding-inline:clamp(1rem,4vw,2rem)}
4233
+ .fling-md-header{padding-block:.75rem;display:flex;gap:1rem;justify-content:space-between;font-size:.8125rem;color:var(--muted);border-bottom:1px solid var(--line)}
4234
+ .fling-md-header span{overflow-wrap:anywhere}
4235
+ main{padding-block:1.5rem 4rem;overflow-wrap:break-word}
4236
+ a{color:var(--link)}
4237
+ h1,h2,h3,h4,h5,h6{line-height:1.25;margin:1.75em 0 .6em}
4238
+ h1:first-child,h2:first-child{margin-top:0}
4239
+ h1,h2{padding-bottom:.3em;border-bottom:1px solid var(--line)}
4240
+ code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;font-size:.875em}
4241
+ :not(pre)>code{background:var(--code);padding:.15em .35em;border-radius:4px}
4242
+ pre{background:var(--code);padding:1rem;border-radius:6px;overflow:auto;line-height:1.45}
4243
+ blockquote{margin:1em 0;padding:0 1em;color:var(--muted);border-left:.25em solid var(--line)}
4244
+ table{border-collapse:collapse;display:block;max-width:100%;overflow:auto;margin:1em 0}
4245
+ th,td{border:1px solid var(--line);padding:.4em .8em}
4246
+ th{background:var(--code)}
4247
+ img,video{max-width:100%;height:auto}
4248
+ hr{border:0;border-top:1px solid var(--line);margin:2em 0}
4249
+ li.task-list-item{list-style:none}
4250
+ li.task-list-item input{margin:0 .4em 0 -1.4em;vertical-align:middle}
4251
+ `.trim().replace(/\n/g, "");
4252
+
4253
+ // ../../packages/shared/src/mcp-tools.ts
4254
+ import { z as z15 } from "zod";
4255
+
2782
4256
  // ../../packages/shared/src/site-labels.ts
2783
4257
  var SITE_NAME_MAX = 50;
2784
4258
  var SHARE_TOKEN_LENGTH = 20;
@@ -2813,56 +4287,56 @@ function siteUrl(label, sitesDomain, protocol = "https:") {
2813
4287
  }
2814
4288
 
2815
4289
  // ../../packages/shared/src/instance.ts
2816
- import { z as z11 } from "zod";
4290
+ import { z as z13 } from "zod";
2817
4291
  var INSTANCE_METADATA_PATH = "/.well-known/fling";
2818
4292
  var RELEASE_HEADER = "Fling-Release";
2819
4293
  var HEX_COLOR_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
2820
- var color = z11.string().regex(HEX_COLOR_RE);
2821
- var SignInProviderSchema = z11.looseObject({
4294
+ var color = z13.string().regex(HEX_COLOR_RE);
4295
+ var SignInProviderSchema = z13.looseObject({
2822
4296
  /** `google` or `oidc` today; clients pass it back as is. */
2823
- id: z11.string().min(1),
4297
+ id: z13.string().min(1),
2824
4298
  /** "Sign in with <displayName>". */
2825
- displayName: z11.string().min(1),
2826
- issuer: z11.string().optional()
4299
+ displayName: z13.string().min(1),
4300
+ issuer: z13.string().optional()
2827
4301
  });
2828
- var InstanceAuthSchema = z11.looseObject({
2829
- kind: z11.string().min(1),
2830
- displayName: z11.string().min(1),
2831
- issuer: z11.string().optional(),
2832
- providers: z11.array(SignInProviderSchema).optional(),
2833
- emailDomains: z11.array(z11.string()).default([]),
2834
- invitedEmails: z11.boolean().optional()
4302
+ var InstanceAuthSchema = z13.looseObject({
4303
+ kind: z13.string().min(1),
4304
+ displayName: z13.string().min(1),
4305
+ issuer: z13.string().optional(),
4306
+ providers: z13.array(SignInProviderSchema).optional(),
4307
+ emailDomains: z13.array(z13.string()).default([]),
4308
+ invitedEmails: z13.boolean().optional()
2835
4309
  });
2836
- var BrandColorsSchema = z11.looseObject({
4310
+ var BrandColorsSchema = z13.looseObject({
2837
4311
  primary: color.optional(),
2838
4312
  primaryContent: color.optional(),
2839
4313
  accent: color.optional(),
2840
4314
  ink: color.optional(),
2841
4315
  highlight: color.optional()
2842
4316
  });
2843
- var InstanceBrandSchema = z11.looseObject({
4317
+ var InstanceBrandSchema = z13.looseObject({
2844
4318
  /** https: or data: URL of the logo mark shown before the name (light theme). */
2845
- logoUrl: z11.string().optional(),
4319
+ logoUrl: z13.string().optional(),
2846
4320
  /** The same for the dark theme; defaults to `logoUrl`. */
2847
- logoDarkUrl: z11.string().optional(),
2848
- faviconUrl: z11.string().optional(),
4321
+ logoDarkUrl: z13.string().optional(),
4322
+ faviconUrl: z13.string().optional(),
2849
4323
  colors: BrandColorsSchema.default({})
2850
4324
  });
2851
- var InstanceMetadataSchema = z11.looseObject({
2852
- version: z11.number().int().min(1),
4325
+ var InstanceMetadataSchema = z13.looseObject({
4326
+ version: z13.number().int().min(1),
2853
4327
  /** Display name, e.g. "Fling". */
2854
- name: z11.string().min(1),
4328
+ name: z13.string().min(1),
2855
4329
  /** e.g. `https://fling.example.test` (no trailing slash) */
2856
- appOrigin: z11.string().url(),
4330
+ appOrigin: z13.string().url(),
2857
4331
  /** host[:port] sites hang off: a site is `<name>.<sitesDomain>` */
2858
- sitesDomain: z11.string().min(1),
2859
- siteScheme: z11.enum(["http", "https"]),
4332
+ sitesDomain: z13.string().min(1),
4333
+ siteScheme: z13.enum(["http", "https"]),
2860
4334
  auth: InstanceAuthSchema,
2861
4335
  brand: InstanceBrandSchema.default({ colors: {} }),
2862
4336
  /** Feature flags: a client hides what is missing or false. */
2863
- capabilities: z11.record(z11.string(), z11.boolean()).default({}),
4337
+ capabilities: z13.record(z13.string(), z13.boolean()).default({}),
2864
4338
  /** How to install the CLI, e.g. `npm install -g <package>`. */
2865
- installCommand: z11.string().min(1),
4339
+ installCommand: z13.string().min(1),
2866
4340
  /**
2867
4341
  * The access level a new site gets when its first deploy names none (`SITE_DEFAULT_ACCESS`).
2868
4342
  * Missing (older servers) or unknown: `members` (`defaultAccessOf`).
@@ -2872,8 +4346,59 @@ var InstanceMetadataSchema = z11.looseObject({
2872
4346
  * The Fling release the server runs, e.g. `0.7.0` (the root package.json's version, built in).
2873
4347
  * Missing on servers built before releases were stamped.
2874
4348
  */
2875
- release: z11.string().min(1).optional().catch(void 0)
4349
+ release: z13.string().min(1).optional().catch(void 0)
2876
4350
  });
4351
+ var CORE_CAPABILITIES = {
4352
+ /** the remote MCP connector at `/mcp` */
4353
+ remoteMcp: true,
4354
+ shareLinks: true,
4355
+ publicSites: true,
4356
+ archive: true,
4357
+ rollback: true,
4358
+ /** a private site can be limited to listed people (its audience) */
4359
+ audiences: true,
4360
+ /** named lists of people (groups.ts) that any member can use in an audience */
4361
+ groups: true,
4362
+ /** the five access levels (access.ts), `only_me` among them, set with `access` */
4363
+ accessLevels: true,
4364
+ /** a site's owners and publishers, people and groups (site-roles.ts), set with `owners`/`publishers` */
4365
+ siteRoles: true,
4366
+ /** a deploy can publish one top-level folder of a site, as its Path (`DeployRequest.path`) */
4367
+ pathPublish: true,
4368
+ /**
4369
+ * Paths: top-level folders of a site with their own versions, rollback, owners and publishers
4370
+ * (`/api/sites/:name/paths…`, `fling paths`, `fling_paths`); a home page with a Paths block lists
4371
+ * them, as does `/_fling-paths.json`
4372
+ */
4373
+ paths: true,
4374
+ /** Markdown files are served rendered as pages (GitHub-flavoured), their source at `?raw=1` */
4375
+ markdown: true,
4376
+ /**
4377
+ * whoever can see a site signed in may download its files (`GET /api/sites/:name/pull`,
4378
+ * `fling pull`, `fling_read_files`), and a deploy can build on the version pulled, sending only
4379
+ * what changed (`DeployRequest.base`)
4380
+ */
4381
+ pull: true,
4382
+ /**
4383
+ * a live preview of each site's home page on its site page, and a thumbnail of it in the site
4384
+ * lists, taken by its owners' and publishers' browsers (thumbnails.ts)
4385
+ */
4386
+ thumbnails: true,
4387
+ /** the user guide in the web app at `/guide` (guide.ts), readable signed out */
4388
+ guide: true
4389
+ };
4390
+ var CONFIGURED_CAPABILITIES = [
4391
+ "comments",
4392
+ "forms",
4393
+ "live",
4394
+ "notifications",
4395
+ "email",
4396
+ "invites"
4397
+ ];
4398
+ var CAPABILITY_NAMES = [
4399
+ ...Object.keys(CORE_CAPABILITIES),
4400
+ ...CONFIGURED_CAPABILITIES
4401
+ ];
2877
4402
  var defaultAccessOf = (instance) => instance?.defaultAccess ?? LEGACY_DEFAULT_ACCESS;
2878
4403
  function instanceSitesPattern(instance) {
2879
4404
  return `${instance.siteScheme}://<name>.${instance.sitesDomain}`;
@@ -2896,128 +4421,11 @@ function instanceMetadataUrl(serverUrl) {
2896
4421
  return `${serverUrl.replace(/\/+$/, "")}${INSTANCE_METADATA_PATH}`;
2897
4422
  }
2898
4423
 
2899
- // ../../packages/shared/src/kvs.ts
2900
- import { z as z12 } from "zod";
2901
-
2902
- // ../../packages/shared/src/route-keys.ts
2903
- var SITE_PASS_TTL_SECONDS = 5 * 60;
2904
-
2905
- // ../../packages/shared/src/kvs.ts
2906
- var KvsSiteValueSchema = z12.object({
2907
- /** siteId — S3 prefix is `sites/<id>/<v>/` */
2908
- id: z12.string(),
2909
- /** current versionId */
2910
- v: z12.string(),
2911
- vis: z12.enum(["private", "public"]),
2912
- /** serve /index.html for unknown extensionless paths */
2913
- spa: z12.boolean(),
2914
- /** present when the site is restricted (private with an audience): the edge wants a site pass */
2915
- r: z12.literal(1).optional(),
2916
- /** present when the site has live Paths: a request's first folder may be one (`path:` keys) */
2917
- p: z12.literal(1).optional(),
2918
- /**
2919
- * the rendered home page and Paths listing (`sites/<id>/_rendered/<i>.html|json`), served for
2920
- * `/`, `/index.html` and PATHS_JSON_PATH instead of the version's own index.html
2921
- */
2922
- i: z12.string().optional(),
2923
- /** present when the current version's Markdown files have rendered pages (markdown.ts) */
2924
- m: z12.literal(1).optional()
2925
- });
2926
- var KvsPathValueSchema = z12.object({
2927
- id: z12.string(),
2928
- v: z12.string(),
2929
- /** as on a site's value: its current version's Markdown has rendered pages */
2930
- m: z12.literal(1).optional()
2931
- });
2932
-
2933
- // ../../packages/shared/src/listing.ts
2934
- var LISTING_GENERATOR_META = "fling-listing";
2935
- var escapeHtml = (s) => s.replace(
2936
- /[&<>"']/g,
2937
- (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]
2938
- );
2939
- var hrefFor = (path3) => path3.split("/").map(encodeURIComponent).join("/");
2940
- function isHtmlPath(path3) {
2941
- return /\.html?$/i.test(path3);
2942
- }
2943
- function extractHtmlTitle(html) {
2944
- const match = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html.slice(0, 65536));
2945
- const title = match?.[1]?.replace(/<[^>]*>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\s+/g, " ").trim();
2946
- return title ? title : null;
2947
- }
2948
- function renderHtmlListing(siteName2, entries) {
2949
- const pages = entries.filter((e) => isHtmlPath(e.path) && e.path.toLowerCase() !== "index.html").sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
2950
- const groups2 = /* @__PURE__ */ new Map();
2951
- for (const page2 of pages) {
2952
- const slash = page2.path.lastIndexOf("/");
2953
- const folder = slash === -1 ? "" : page2.path.slice(0, slash);
2954
- groups2.set(folder, [...groups2.get(folder) ?? [], page2]);
2955
- }
2956
- const sections = [...groups2.entries()].sort(([a], [b]) => a === "" ? -1 : b === "" ? 1 : a < b ? -1 : 1).map(([folder, items]) => {
2957
- const heading = folder ? `<h2>${escapeHtml(folder)}/</h2>` : "";
2958
- const rows = items.map((item) => {
2959
- const file = item.path.slice(item.path.lastIndexOf("/") + 1);
2960
- const label = item.title ? escapeHtml(item.title) : escapeHtml(file);
2961
- const sub = item.title ? `<span class="file">${escapeHtml(file)}</span>` : "";
2962
- return `<li><a href="${hrefFor(item.path)}">${label}</a>${sub}</li>`;
2963
- }).join("\n");
2964
- return `${heading}<ul>
2965
- ${rows}
2966
- </ul>`;
2967
- }).join("\n");
2968
- const body = pages.length ? sections : '<p class="empty">No HTML pages in this fling.</p>';
2969
- const count2 = `${pages.length} page${pages.length === 1 ? "" : "s"}`;
2970
- return `<!doctype html>
2971
- <html lang="en">
2972
- <head>
2973
- <meta charset="utf-8">
2974
- <meta name="viewport" content="width=device-width, initial-scale=1">
2975
- <meta name="generator" content="${LISTING_GENERATOR_META}">
2976
- <title>${escapeHtml(siteName2)}</title>
2977
- <style>
2978
- :root { color-scheme: light dark; --fg: #000e38; --muted: #5b6480; --bg: #f7f8fb; --card: #fff;
2979
- --line: #e3e6ef; --accent: #166bff; --green: #00e5a4; }
2980
- @media (prefers-color-scheme: dark) { :root { --fg: #eef1f8; --muted: #9aa3bd; --bg: #000e38;
2981
- --card: #0b1a4a; --line: #1d2c5e; --accent: #6ea2ff; } }
2982
- * { box-sizing: border-box; }
2983
- body { margin: 0; font: 16px/1.5 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
2984
- color: var(--fg); background: var(--bg); }
2985
- main { max-width: 760px; margin: 0 auto; padding: 48px 20px 64px; }
2986
- header { border-left: 4px solid var(--green); padding-left: 14px; margin-bottom: 28px; }
2987
- h1 { margin: 0; font-size: 1.6rem; }
2988
- header p, .file, footer { color: var(--muted); font-size: .875rem; }
2989
- header p { margin: 4px 0 0; }
2990
- h2 { font-size: .95rem; margin: 28px 0 8px; color: var(--muted); font-weight: 600; }
2991
- ul { list-style: none; margin: 0; padding: 0; background: var(--card); border: 1px solid var(--line);
2992
- border-radius: 10px; overflow: hidden; }
2993
- li { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; gap: 12px;
2994
- justify-content: space-between; align-items: baseline; flex-wrap: wrap; }
2995
- li:first-child { border-top: 0; }
2996
- a { color: var(--accent); text-decoration: none; font-weight: 500; }
2997
- a:hover { text-decoration: underline; }
2998
- .empty { color: var(--muted); }
2999
- footer { margin-top: 40px; }
3000
- </style>
3001
- </head>
3002
- <body>
3003
- <main>
3004
- <header><h1>${escapeHtml(siteName2)}</h1><p>${count2}</p></header>
3005
- ${body}
3006
- <footer>Flung with Fling</footer>
3007
- </main>
3008
- </body>
3009
- </html>
3010
- `;
3011
- }
3012
-
3013
- // ../../packages/shared/src/mcp-tools.ts
3014
- import { z as z14 } from "zod";
3015
-
3016
4424
  // ../../packages/shared/src/notifications.ts
3017
- import { z as z13 } from "zod";
4425
+ import { z as z14 } from "zod";
3018
4426
  var CHANNEL_IDS = ["email"];
3019
- var ChannelIdSchema = z13.enum(CHANNEL_IDS);
3020
- var DeliverySchema = z13.enum(["on", "off"]);
4427
+ var ChannelIdSchema = z14.enum(CHANNEL_IDS);
4428
+ var DeliverySchema = z14.enum(["on", "off"]);
3021
4429
  var EVENT_KEYS = [
3022
4430
  "site.shared",
3023
4431
  "site.shared_via_group",
@@ -3027,7 +4435,7 @@ var EVENT_KEYS = [
3027
4435
  "comment.created",
3028
4436
  "comment.reply"
3029
4437
  ];
3030
- var EventKeySchema = z13.enum(EVENT_KEYS);
4438
+ var EventKeySchema = z14.enum(EVENT_KEYS);
3031
4439
  var EVENT_CATALOGUE = [
3032
4440
  {
3033
4441
  key: "site.shared",
@@ -3091,95 +4499,96 @@ var EVENT_CATALOGUE = [
3091
4499
  }
3092
4500
  ];
3093
4501
  var BY_KEY = new Map(EVENT_CATALOGUE.map((e) => [e.key, e]));
3094
- var NotificationPreferencesUpdateSchema = z13.object({
3095
- muted: z13.boolean().optional(),
3096
- cells: z13.partialRecord(EventKeySchema, z13.partialRecord(ChannelIdSchema, DeliverySchema.nullable())).optional()
4502
+ var NotificationPreferencesUpdateSchema = z14.object({
4503
+ muted: z14.boolean().optional(),
4504
+ cells: z14.partialRecord(EventKeySchema, z14.partialRecord(ChannelIdSchema, DeliverySchema.nullable())).optional()
3097
4505
  });
3098
- var EventDefinitionSchema = z13.looseObject({
3099
- key: z13.string(),
3100
- title: z13.string(),
3101
- description: z13.string(),
3102
- section: z13.string(),
3103
- defaults: z13.record(z13.string(), DeliverySchema),
3104
- coolDown: z13.boolean(),
3105
- capability: z13.string().optional()
4506
+ var EventDefinitionSchema = z14.looseObject({
4507
+ key: z14.string(),
4508
+ title: z14.string(),
4509
+ description: z14.string(),
4510
+ section: z14.string(),
4511
+ defaults: z14.record(z14.string(), DeliverySchema),
4512
+ coolDown: z14.boolean(),
4513
+ capability: z14.string().optional()
3106
4514
  });
3107
- var NotificationSettingsSchema = z13.looseObject({
3108
- channels: z13.array(z13.string()),
3109
- events: z13.array(EventDefinitionSchema),
3110
- muted: z13.boolean(),
3111
- cells: z13.record(z13.string(), z13.record(z13.string(), DeliverySchema)),
3112
- overrides: z13.record(z13.string(), z13.record(z13.string(), DeliverySchema)).default({})
4515
+ var NotificationSettingsSchema = z14.looseObject({
4516
+ channels: z14.array(z14.string()),
4517
+ events: z14.array(EventDefinitionSchema),
4518
+ muted: z14.boolean(),
4519
+ cells: z14.record(z14.string(), z14.record(z14.string(), DeliverySchema)),
4520
+ overrides: z14.record(z14.string(), z14.record(z14.string(), DeliverySchema)).default({})
3113
4521
  });
3114
- var SentNotificationSchema = z13.looseObject({
3115
- id: z13.string(),
3116
- channel: z13.string(),
4522
+ var SentNotificationSchema = z14.looseObject({
4523
+ id: z14.string(),
4524
+ channel: z14.string(),
3117
4525
  /** the events it told them about (several when folded) */
3118
- eventKeys: z13.array(z13.string()),
3119
- subject: z13.string(),
4526
+ eventKeys: z14.array(z14.string()),
4527
+ subject: z14.string(),
3120
4528
  /** the provider's message id, when it gave one */
3121
- providerId: z13.string().nullable(),
3122
- sentAt: z13.string()
4529
+ providerId: z14.string().nullable(),
4530
+ sentAt: z14.string()
3123
4531
  });
3124
- var SentNotificationListSchema = z13.object({ sent: z13.array(SentNotificationSchema) });
3125
- var MailCountsSchema = z13.object({
3126
- sent: z13.number(),
3127
- retrying: z13.number(),
3128
- givenUp: z13.number(),
3129
- suppressed: z13.number(),
3130
- dropped: z13.number()
4532
+ var SentNotificationListSchema = z14.object({ sent: z14.array(SentNotificationSchema) });
4533
+ var MailCountsSchema = z14.object({
4534
+ sent: z14.number(),
4535
+ retrying: z14.number(),
4536
+ givenUp: z14.number(),
4537
+ suppressed: z14.number(),
4538
+ dropped: z14.number()
3131
4539
  });
3132
- var MailAdminSchema = z13.object({
3133
- config: z13.object({
3134
- driver: z13.string(),
3135
- from: z13.string(),
3136
- fromName: z13.string(),
3137
- replyTo: z13.string().nullable(),
3138
- configurationSet: z13.string().nullable(),
4540
+ var MailAdminSchema = z14.object({
4541
+ config: z14.object({
4542
+ driver: z14.string(),
4543
+ from: z14.string(),
4544
+ fromName: z14.string(),
4545
+ replyTo: z14.string().nullable(),
4546
+ configurationSet: z14.string().nullable(),
3139
4547
  /** outside invitations are on (`INVITES`) */
3140
- invites: z13.boolean()
4548
+ invites: z14.boolean()
3141
4549
  }),
3142
- health: z13.object({
4550
+ health: z14.object({
3143
4551
  /** the first hour counted (UTC, `2026-10-28T14`) */
3144
- since: z13.string(),
4552
+ since: z14.string(),
3145
4553
  /** the hours with any activity, oldest first */
3146
- hours: z13.array(MailCountsSchema.extend({ hour: z13.string() })),
4554
+ hours: z14.array(MailCountsSchema.extend({ hour: z14.string() })),
3147
4555
  totals: MailCountsSchema,
3148
4556
  /** the latest failed sends, newest first */
3149
- failures: z13.array(
3150
- z13.object({
3151
- at: z13.string(),
3152
- batchId: z13.string(),
3153
- eventKeys: z13.array(z13.string()),
3154
- reason: z13.string(),
3155
- detail: z13.string().nullable()
4557
+ failures: z14.array(
4558
+ z14.object({
4559
+ at: z14.string(),
4560
+ batchId: z14.string(),
4561
+ eventKeys: z14.array(z14.string()),
4562
+ reason: z14.string(),
4563
+ detail: z14.string().nullable()
3156
4564
  })
3157
4565
  )
3158
4566
  }),
3159
4567
  /** test emails this admin may still send this hour, of `limit` */
3160
- tests: z13.object({ remaining: z13.number(), limit: z13.number() })
4568
+ tests: z14.object({ remaining: z14.number(), limit: z14.number() })
3161
4569
  });
3162
- var MailTestRequestSchema = z13.object({
3163
- to: z13.string().trim().toLowerCase().min(3).max(254)
4570
+ var MailTestRequestSchema = z14.object({
4571
+ to: z14.string().trim().toLowerCase().min(3).max(254)
3164
4572
  });
3165
- var MailTestResultSchema = z13.discriminatedUnion("ok", [
3166
- z13.object({ ok: z13.literal(true), providerId: z13.string().nullable(), subject: z13.string() }),
3167
- z13.object({
3168
- ok: z13.literal(false),
3169
- reason: z13.string(),
3170
- detail: z13.string().nullable(),
3171
- error: z13.string()
4573
+ var MailTestResultSchema = z14.discriminatedUnion("ok", [
4574
+ z14.object({ ok: z14.literal(true), providerId: z14.string().nullable(), subject: z14.string() }),
4575
+ z14.object({
4576
+ ok: z14.literal(false),
4577
+ reason: z14.string(),
4578
+ detail: z14.string().nullable(),
4579
+ error: z14.string()
3172
4580
  })
3173
4581
  ]);
3174
- var CellChangeSchema = z13.object({
4582
+ var MAIL_TESTS_PER_HOUR = 10;
4583
+ var CellChangeSchema = z14.object({
3175
4584
  event: EventKeySchema,
3176
4585
  channel: ChannelIdSchema,
3177
- value: z13.enum(["on", "off", "default"])
4586
+ value: z14.enum(["on", "off", "default"])
3178
4587
  });
3179
4588
  function preferencesUpdateOf(change) {
3180
4589
  const cells = {};
3181
- for (const c of change.cells ?? []) {
3182
- cells[c.event] = { ...cells[c.event], [c.channel]: c.value === "default" ? null : c.value };
4590
+ for (const c2 of change.cells ?? []) {
4591
+ cells[c2.event] = { ...cells[c2.event], [c2.channel]: c2.value === "default" ? null : c2.value };
3183
4592
  }
3184
4593
  return {
3185
4594
  ...change.muted === void 0 ? {} : { muted: change.muted },
@@ -3225,28 +4634,28 @@ function matchesQuery(row2, query) {
3225
4634
  }
3226
4635
  return true;
3227
4636
  }
3228
- function compareRows(a, b, sort) {
3229
- const x = String(a.folder);
4637
+ function compareRows(a3, b, sort) {
4638
+ const x2 = String(a3.folder);
3230
4639
  const y = String(b.folder);
3231
- const xs = x.match(/\d+|\D+/g) || [];
4640
+ const xs = x2.match(/\d+|\D+/g) || [];
3232
4641
  const ys = y.match(/\d+|\D+/g) || [];
3233
4642
  let byFolder = 0;
3234
4643
  for (let i = 0; i < xs.length && i < ys.length && byFolder === 0; i++) {
3235
4644
  const p = xs[i];
3236
- const q = ys[i];
3237
- if (/^\d/.test(p) && /^\d/.test(q)) {
4645
+ const q2 = ys[i];
4646
+ if (/^\d/.test(p) && /^\d/.test(q2)) {
3238
4647
  const pn = p.replace(/^0+/, "");
3239
- const qn = q.replace(/^0+/, "");
4648
+ const qn = q2.replace(/^0+/, "");
3240
4649
  byFolder = pn.length - qn.length || (pn < qn ? -1 : pn > qn ? 1 : 0);
3241
4650
  } else {
3242
4651
  const pl = p.toLowerCase();
3243
- const ql = q.toLowerCase();
4652
+ const ql = q2.toLowerCase();
3244
4653
  byFolder = pl < ql ? -1 : pl > ql ? 1 : 0;
3245
4654
  }
3246
4655
  }
3247
4656
  if (byFolder === 0) byFolder = xs.length - ys.length;
3248
- if (byFolder === 0) byFolder = x < y ? -1 : x > y ? 1 : 0;
3249
- const byTime = (Date.parse(a.updated) || 0) - (Date.parse(b.updated) || 0);
4657
+ if (byFolder === 0) byFolder = x2 < y ? -1 : x2 > y ? 1 : 0;
4658
+ const byTime = (Date.parse(a3.updated) || 0) - (Date.parse(b.updated) || 0);
3250
4659
  if (sort === "folder") return byFolder;
3251
4660
  if (sort === "folder-desc") return -byFolder;
3252
4661
  if (sort === "oldest") return byTime || byFolder;
@@ -3474,7 +4883,7 @@ var ESCAPES = {
3474
4883
  '"': "&quot;",
3475
4884
  "'": "&#39;"
3476
4885
  };
3477
- var esc = (value) => value.replace(/[&<>"']/g, (c) => ESCAPES[c] ?? c);
4886
+ var esc = (value) => value.replace(/[&<>"']/g, (c2) => ESCAPES[c2] ?? c2);
3478
4887
  var BASE_CSS = `:root{color-scheme:light dark;--bg:#f7f7f8;--fg:#1c1c21;--muted:#5d5d68;--card:#fff;--line:#e2e2e7;--fling-paths-accent:#2f5fc4}
3479
4888
  @media (prefers-color-scheme:dark){:root{--bg:#141417;--fg:#ececf0;--muted:#a0a0ab;--card:#1d1d22;--line:#2e2e35;--fling-paths-accent:#8ab0ff}}
3480
4889
  *{box-sizing:border-box}
@@ -3654,9 +5063,9 @@ function describeReadFiles(name, result) {
3654
5063
  // ../../packages/shared/src/site-sort.ts
3655
5064
  var SITE_SORTS = ["updated", "created", "name"];
3656
5065
  var DEFAULT_SITE_SORT = "updated";
3657
- var byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
5066
+ var byName = (a3, b) => a3.name < b.name ? -1 : a3.name > b.name ? 1 : 0;
3658
5067
  function sortSites(sites, sort = DEFAULT_SITE_SORT) {
3659
- const newest = (key) => (a, b) => Date.parse(b[key]) - Date.parse(a[key]) || byName(a, b);
5068
+ const newest = (key) => (a3, b) => Date.parse(b[key]) - Date.parse(a3[key]) || byName(a3, b);
3660
5069
  const compare = sort === "name" ? byName : newest(sort === "created" ? "createdAt" : "updatedAt");
3661
5070
  return [...sites].sort(compare);
3662
5071
  }
@@ -3684,21 +5093,23 @@ function mcpWording(instance) {
3684
5093
  signIn: `their ${instance.auth.displayName} account`,
3685
5094
  reviewPattern: instance.appOrigin ? reviewUrl(instance.appOrigin, "<name>") : GENERIC_REVIEW,
3686
5095
  defaultAccess: defaultAccessOf(instance),
3687
- invites: instance.capabilities?.invites === true
5096
+ invites: instance.capabilities?.invites === true,
5097
+ ...instanceGuideUrl(instance) ? { guide: instanceGuideUrl(instance) } : {}
3688
5098
  };
3689
5099
  }
3690
- var addressRule = (w) => w.invites ? `Each address must be one that can sign in to ${w.name}, or one from outside it, which is invited as a reviewer (a guest who signs in with an emailed link and sees only what is shared with them; a few a day per person, else \`too_many_invites\`).` : `Each address must be one that can sign in to ${w.name}.`;
3691
- var defaultAccessPhrase = (w) => w.defaultAccess === "members" ? `open to ${w.privateAudience}` : w.defaultAccess === "only_me" ? "visible only to the user" : "given the Fling's default (only the user, unless the Fling is set up otherwise)";
3692
- var ACCESS_NOTE = (w) => "Before publishing a new site, ask the user who should be able to open it, unless they already said, and pass `access`: `only_me` (only the user), `members` (" + w.privateAudience + `), \`groups\` or \`people\` (only the groups in \`groups\`, by slug, and the addresses in \`emails\`; one site may name both), or \`public\` (anyone, no sign-in; only if the user asks). Without \`access\` a new site is ${defaultAccessPhrase(w)}. Re-publishing never changes who can open an existing site: use fling_set_access for that. Share links (fling_share) open a site to anyone who has them.`;
5100
+ var GUIDE_NOTE = (w2) => w2.guide ? `When the user asks how to do something with ${w2.name} (connect an assistant, share a site, team sites, comments), answer, then point them at its guide, ${w2.guide}, which covers every feature by assistant, command line and web app.` : void 0;
5101
+ var addressRule = (w2) => w2.invites ? `Each address must be one that can sign in to ${w2.name}, or one from outside it, which is invited as a reviewer (a guest who signs in with an emailed link and sees only what is shared with them; a few a day per person, else \`too_many_invites\`).` : `Each address must be one that can sign in to ${w2.name}.`;
5102
+ var defaultAccessPhrase = (w2) => w2.defaultAccess === "members" ? `open to ${w2.privateAudience}` : w2.defaultAccess === "only_me" ? "visible only to the user" : "given the Fling's default (only the user, unless the Fling is set up otherwise)";
5103
+ var ACCESS_NOTE = (w2) => "Before publishing a new site, ask the user who should be able to open it, unless they already said, and pass `access`: `only_me` (only the user), `members` (" + w2.privateAudience + `), \`groups\` or \`people\` (only the groups in \`groups\`, by slug, and the addresses in \`emails\`; one site may name both), or \`public\` (anyone, no sign-in; only if the user asks). Without \`access\` a new site is ${defaultAccessPhrase(w2)}. Re-publishing never changes who can open an existing site: use fling_set_access for that. Share links (fling_share) open a site to anyone who has them.`;
3693
5104
  var NAME_REQUIRED = 'Publishing needs a name: if the user did not give one, propose a short descriptive one (e.g. "q3-report") and confirm it with them first (fling_check_name tells you whether it is free). If the name is taken by someone else the call fails with free suggestions \u2014 offer those to the user and retry with the one they pick.';
3694
5105
  var INLINE_ONLY = "If you created the content in this conversation, pass it directly \u2014 never pass file paths from your sandbox (this server cannot read them) and never try to curl/upload from your sandbox.";
3695
5106
  var NEVER_PUBLISHED = "Fling never publishes dotfiles, gitignored files, secret files (keys, certs, credentials) or files that contain secrets (API keys, tokens, private keys, passwords in database URLs); it stops and tells you which file and line. Remove the secret (or leave the file out) and retry \u2014 there is no way to override this.";
3696
5107
  var ENCODING = '`encoding` is "utf8" (default, for text: HTML, CSS, JS, SVG, JSON, Markdown\u2026) or "base64" (binary: images, fonts, PDFs).';
3697
5108
  var LIST_HTML = "If the files have no root index.html but do include HTML pages, the call does not publish: it reports how many HTML pages there are and asks you to check with the user. Ask them whether to generate an index.html listing those pages (retry with `listHtml: true`) or to publish without one (`listHtml: false` \u2014 the site root will 404, the pages still work at their own paths), then retry.";
3698
- var listHtml = z14.boolean().optional().describe(
5109
+ var listHtml = z15.boolean().optional().describe(
3699
5110
  "Only matters when there is no root index.html: true \u2192 generate an index.html linking every HTML page; false \u2192 publish without one (root 404s). Omit until the user has decided"
3700
5111
  );
3701
- var siteName = z14.string().min(1).max(200).describe('Site name, e.g. "q3-report"');
5112
+ var siteName = z15.string().min(1).max(200).describe('Site name, e.g. "q3-report"');
3702
5113
  function describePublishHints(hints) {
3703
5114
  if (!hints?.length) return "";
3704
5115
  return `
@@ -3707,33 +5118,33 @@ Worth doing:
3707
5118
  }
3708
5119
  var PATH_PUBLISH_NOTE = `With \`path\` (one top-level folder, e.g. "PAY-412"), the files are published as that folder's Path: they go to <site>/PAY-412/\u2026 (give their paths relative to the folder, its page being "index.html"), and the rest of the site is untouched. A Path has its own versions, rollback, owners and publishers, and is made on first use (you own it). Use it for one plan, spec, report or week's page on a shared team site; teammates publishing other Paths never collide. fling_paths lists a site's Paths. The site's home page lists them by default when it has no index.html, or as a custom page with a Paths block (fling_paths_template); an index.html without a block lists none: settle which with the user (see fling_paths).`;
3709
5120
  var PULL_NOTE = "To change a site that is already published (fix a typo, update a page, add one), start from what is live, not from scratch: read its files with fling_read_files, then call fling_publish with `base` (the `versionId` it returned) and only the files you changed or added, plus `remove` for files to delete; every other file stays as it is. If someone published the site in between, it fails with base_changed: read the files again and redo the changes, rather than publishing without `base` over theirs.";
3710
- var base = z14.string().min(1).max(100).optional().describe(
5121
+ var base = z15.string().min(1).max(100).optional().describe(
3711
5122
  "The versionId fling_read_files returned: publish only what changed on top of it. `files` then holds only the files you changed or added, and every other file of the site is kept. Fails with base_changed if the site has changed since. Not with `path`"
3712
5123
  );
3713
- var remove = z14.array(z14.string().min(1).max(1024)).max(MAX_FILES).optional().describe("With `base`: the paths of the files to delete from the site");
3714
- var publishPath = z14.string().min(1).max(1024).optional().describe(
5124
+ var remove = z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe("With `base`: the paths of the files to delete from the site");
5125
+ var publishPath = z15.string().min(1).max(1024).optional().describe(
3715
5126
  'Publish as the Path at this top-level folder of the site, e.g. "PAY-412" (served at <site>/PAY-412/); the rest of the site is untouched. File paths are relative to it. Omit to publish the site itself'
3716
5127
  );
3717
- var sitePath = z14.string().min(1).max(1024).describe(
5128
+ var sitePath = z15.string().min(1).max(1024).describe(
3718
5129
  'Site-relative path with forward slashes, e.g. "index.html", "css/app.css", "img/logo.png". The root page must be "index.html". No dotfiles (".env", ".well-known/\u2026")'
3719
5130
  );
3720
- var emails = z14.array(z14.string().min(3).max(254)).max(AUDIENCE_EMAILS_MAX);
3721
- var groupSlugs = z14.array(z14.string().min(1).max(100)).max(AUDIENCE_GROUPS_MAX);
5131
+ var emails = z15.array(z15.string().min(3).max(254)).max(AUDIENCE_EMAILS_MAX);
5132
+ var groupSlugs = z15.array(z15.string().min(1).max(100)).max(AUDIENCE_GROUPS_MAX);
3722
5133
  var roleChange = {
3723
- add: z14.array(z14.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
3724
- remove: z14.array(z14.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
3725
- set: z14.array(z14.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
3726
- addGroups: z14.array(z14.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
3727
- removeGroups: z14.array(z14.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
3728
- setGroups: z14.array(z14.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional()
5134
+ add: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
5135
+ remove: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
5136
+ set: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
5137
+ addGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
5138
+ removeGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
5139
+ setGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional()
3729
5140
  };
3730
- var groupSlug = z14.string().min(1).max(100).describe(`The group's slug, e.g. "design"`);
3731
- var members = z14.array(z14.string().min(3).max(254)).max(GROUP_MEMBERS_MAX);
3732
- var groupName = z14.string().min(1).max(GROUP_NAME_MAX);
3733
- var commentPath = z14.string().max(1024);
3734
- var commentId = z14.string().min(1).max(100);
3735
- var formsConfig = z14.record(z14.string(), z14.unknown());
3736
- var formId = z14.string().min(1).max(40);
5141
+ var groupSlug = z15.string().min(1).max(100).describe(`The group's slug, e.g. "design"`);
5142
+ var members = z15.array(z15.string().min(3).max(254)).max(GROUP_MEMBERS_MAX);
5143
+ var groupName = z15.string().min(1).max(GROUP_NAME_MAX);
5144
+ var commentPath = z15.string().max(1024);
5145
+ var commentId = z15.string().min(1).max(100);
5146
+ var formsConfig = z15.record(z15.string(), z15.unknown());
5147
+ var formId = z15.string().min(1).max(40);
3737
5148
  var TEMPLATES_LIST = FORM_TEMPLATE_NAMES.map(
3738
5149
  (n) => `\`${n}\` (${FORM_TEMPLATE_DESCRIPTIONS[n]})`
3739
5150
  ).join(", ");
@@ -3800,23 +5211,23 @@ function describePathsCheck(check2) {
3800
5211
  return [
3801
5212
  head,
3802
5213
  ...check2.errors.map((e) => `- Error: ${e}`),
3803
- ...check2.warnings.map((w) => `- Warning: ${w}`),
5214
+ ...check2.warnings.map((w2) => `- Warning: ${w2}`),
3804
5215
  ...check2.ok ? ["Publish it as the site's root index.html (without `path`)."] : []
3805
5216
  ].join("\n");
3806
5217
  }
3807
- var pathFolder = z14.string().min(1).max(MAX_PATH_FOLDER_LENGTH + 2);
3808
- var encoding = z14.enum(["utf8", "base64"]).optional().describe('How `content` is encoded: "utf8" (default) for text, "base64" for binary files');
3809
- var spa = z14.boolean().optional().describe(
5218
+ var pathFolder = z15.string().min(1).max(MAX_PATH_FOLDER_LENGTH + 2);
5219
+ var encoding = z15.enum(["utf8", "base64"]).optional().describe('How `content` is encoded: "utf8" (default) for text, "base64" for binary files');
5220
+ var spa = z15.boolean().optional().describe(
3810
5221
  "Single-page app: serve index.html for unknown paths (client-side routing). Omit to keep the current setting"
3811
5222
  );
3812
- function mcpToolsFor(w) {
3813
- const NAME_RULES = `Site names are 1-${SITE_NAME_MAX} chars of lowercase letters, digits and single hyphens, and are one global namespace (first come, first served): the site is served at ${w.sitesPattern}.`;
3814
- const VISIBILITY = ACCESS_NOTE(w);
3815
- const isPublic = z14.boolean().optional().describe(
5223
+ function mcpToolsFor(w2) {
5224
+ const NAME_RULES = `Site names are 1-${SITE_NAME_MAX} chars of lowercase letters, digits and single hyphens, and are one global namespace (first come, first served): the site is served at ${w2.sitesPattern}.`;
5225
+ const VISIBILITY = ACCESS_NOTE(w2);
5226
+ const isPublic = z15.boolean().optional().describe(
3816
5227
  "Prefer `access` (a new site) or fling_set_access (an existing one). true \u2192 anyone can view; false \u2192 private. Omit to keep the current setting"
3817
5228
  );
3818
- const access3 = z14.enum(ACCESS_LEVELS).optional().describe(
3819
- `Who can open a new site: only_me, members (${w.privateAudience}), groups, people or public. Ask the user before the first publish; omit for the default (${defaultAccessPhrase(w)}). Ignored when the site already exists`
5229
+ const access3 = z15.enum(ACCESS_LEVELS).optional().describe(
5230
+ `Who can open a new site: only_me, members (${w2.privateAudience}), groups, people or public. Ask the user before the first publish; omit for the default (${defaultAccessPhrase(w2)}). Ignored when the site already exists`
3820
5231
  );
3821
5232
  const accessEmails = emails.optional().describe('With access "people" (or "groups"): the addresses that may open it');
3822
5233
  const accessGroups = groupSlugs.optional().describe('With access "groups" (or "people"): the groups, by slug, whose members may open it');
@@ -3824,7 +5235,7 @@ function mcpToolsFor(w) {
3824
5235
  whoami: tool({
3825
5236
  name: "fling_whoami",
3826
5237
  title: "Who am I",
3827
- description: `Show the signed-in user that ${w.name} acts as.`,
5238
+ description: `Show the signed-in user that ${w2.name} acts as.`,
3828
5239
  inputSchema: {},
3829
5240
  annotations: { readOnlyHint: true, openWorldHint: false }
3830
5241
  }),
@@ -3833,9 +5244,9 @@ function mcpToolsFor(w) {
3833
5244
  title: "List sites",
3834
5245
  description: "List the user's Fling sites with URL, visibility and share link. With `shared: true`, list instead the restricted sites other people have shared with the user (by address or through a group they're in), with URL, review link and owner.",
3835
5246
  inputSchema: {
3836
- archived: z14.boolean().optional().describe("List archived sites instead of live ones"),
3837
- shared: z14.boolean().optional().describe("List the sites others have shared with the user instead of the user's own"),
3838
- sort: z14.enum(SITE_SORTS).optional().describe(
5247
+ archived: z15.boolean().optional().describe("List archived sites instead of live ones"),
5248
+ shared: z15.boolean().optional().describe("List the sites others have shared with the user instead of the user's own"),
5249
+ sort: z15.enum(SITE_SORTS).optional().describe(
3839
5250
  "Order: updated (last updated, newest first; the default), created (newest first) or name (A\u2013Z)"
3840
5251
  )
3841
5252
  },
@@ -3859,7 +5270,7 @@ function mcpToolsFor(w) {
3859
5270
  description: "List the files in a site's current version (or in `versionId`, from fling_info): path, size and content type, sorted by path. Use it to check what was actually published \u2014 e.g. when the user sees a 404, confirm the page exists at that path and that there is a root index.html (without one the site root 404s).",
3860
5271
  inputSchema: {
3861
5272
  name: siteName,
3862
- versionId: z14.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served"),
5273
+ versionId: z15.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served"),
3863
5274
  path: pathFolder.optional().describe(
3864
5275
  "One of the site's Paths, its folder (e.g. \"PAY-412\"): list that Path's version (ids from fling_info with this `path`) instead; its files are under the folder"
3865
5276
  )
@@ -3872,10 +5283,10 @@ function mcpToolsFor(w) {
3872
5283
  description: `Read the files of a site's current version (or \`versionId\`), with their content inline (text as utf8, anything else base64), to change some of them and publish again. Returns up to ${MCP_READ_MAX_BYTES / 1024 / 1024} MB a call, in path order: when there is more, pass the returned \`cursor\` for the next files, or name the files you need in \`paths\` (fling_files lists them). It returns the \`versionId\` to pass to fling_publish as \`base\`. Anyone who can open the site may read it; publishing needs an owner or publisher. ${PULL_NOTE}`,
3873
5284
  inputSchema: {
3874
5285
  name: siteName,
3875
- paths: z14.array(z14.string().min(1).max(1024)).max(MAX_FILES).optional().describe('Only these files (site paths, e.g. "index.html"); omit for all of them'),
3876
- path: z14.string().min(1).max(1024).optional().describe('The files of this Path of the site, e.g. "PAY-412" (paths relative to it)'),
3877
- cursor: z14.string().max(20).optional().describe("From the previous call, for the next files"),
3878
- versionId: z14.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served")
5286
+ paths: z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe('Only these files (site paths, e.g. "index.html"); omit for all of them'),
5287
+ path: z15.string().min(1).max(1024).optional().describe('The files of this Path of the site, e.g. "PAY-412" (paths relative to it)'),
5288
+ cursor: z15.string().max(20).optional().describe("From the previous call, for the next files"),
5289
+ versionId: z15.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served")
3879
5290
  },
3880
5291
  annotations: { readOnlyHint: true, openWorldHint: false }
3881
5292
  }),
@@ -3883,7 +5294,7 @@ function mcpToolsFor(w) {
3883
5294
  name: "fling_check_name",
3884
5295
  title: "Check a site name",
3885
5296
  description: "Check whether a site name can be used before publishing: `available` (a new site), `yours` (publishing updates the user's existing site), `taken` (someone else's \u2014 free `suggestions` are returned) or `invalid`. " + NAME_RULES,
3886
- inputSchema: { name: z14.string().min(1).max(200).describe("Site name to check") },
5297
+ inputSchema: { name: z15.string().min(1).max(200).describe("Site name to check") },
3887
5298
  annotations: { readOnlyHint: true, openWorldHint: false }
3888
5299
  }),
3889
5300
  publish: tool({
@@ -3892,10 +5303,10 @@ function mcpToolsFor(w) {
3892
5303
  description: `Publish a static site to Fling in one call and get back its URL. Pass every file of the site inline in \`files\` (whole site, up to ${MCP_PUBLISH_MAX_BYTES / 1024 / 1024} MB decoded in total; bigger sites: fling_upload_begin / fling_upload_file / fling_upload_finish). ${INLINE_ONLY} ${ENCODING} Publishing replaces the whole site with exactly these files (it is not a patch: include unchanged files too), unless \`path\` or \`base\` is given; publishing identical content again is a no-op. ${PATH_PUBLISH_NOTE} ${PULL_NOTE} ${NAME_REQUIRED} ${NAME_RULES} ${VISIBILITY} ${LIST_HTML} ${NEVER_PUBLISHED} The result includes \`warnings\`. Share the returned URL with the user; fling_files shows exactly which files the site has. To collect labels, ratings, scores or eval judgements from reviewers, pass \`forms\` (or include ${FORMS_FILE} among the files): see fling_forms_template.`,
3893
5304
  inputSchema: {
3894
5305
  name: siteName,
3895
- files: z14.array(
3896
- z14.object({
5306
+ files: z15.array(
5307
+ z15.object({
3897
5308
  path: sitePath,
3898
- content: z14.string().describe("The file content, encoded as `encoding` says"),
5309
+ content: z15.string().describe("The file content, encoded as `encoding` says"),
3899
5310
  encoding
3900
5311
  })
3901
5312
  ).max(MAX_FILES).describe(
@@ -3938,11 +5349,11 @@ function mcpToolsFor(w) {
3938
5349
  title: "Upload a file (chunked)",
3939
5350
  description: `Add one file to a chunked upload started with fling_upload_begin. Sending the same path again replaces it. A file larger than ${MCP_UPLOAD_CHUNK_MAX_CHARS / 1024 / 1024} MB of content can span calls: send the first part normally, then the following parts in order with \`append: true\` (same path and encoding; send appends one at a time, not in parallel). ${ENCODING} ${NEVER_PUBLISHED}`,
3940
5351
  inputSchema: {
3941
- uploadId: z14.string().min(1).max(100).describe("From fling_upload_begin"),
5352
+ uploadId: z15.string().min(1).max(100).describe("From fling_upload_begin"),
3942
5353
  path: sitePath,
3943
- content: z14.string().max(MCP_UPLOAD_CHUNK_MAX_CHARS).describe("The file content (or the next part of it, with `append`)"),
5354
+ content: z15.string().max(MCP_UPLOAD_CHUNK_MAX_CHARS).describe("The file content (or the next part of it, with `append`)"),
3944
5355
  encoding,
3945
- append: z14.boolean().optional().describe("Append this content to the file sent earlier with the same path")
5356
+ append: z15.boolean().optional().describe("Append this content to the file sent earlier with the same path")
3946
5357
  },
3947
5358
  annotations: { destructiveHint: false, openWorldHint: false }
3948
5359
  }),
@@ -3951,7 +5362,7 @@ function mcpToolsFor(w) {
3951
5362
  title: "Finish a chunked upload",
3952
5363
  description: `Publish everything sent with fling_upload_file as the new version of the site and return its URL. The site becomes exactly the uploaded files (with \`path\`, that Path does; with \`base\`, plus the rest of that version). ${LIST_HTML} The upload stays open, so just call fling_upload_finish again with \`listHtml\`. The result includes \`warnings\`.`,
3953
5364
  inputSchema: {
3954
- uploadId: z14.string().min(1).max(100).describe("From fling_upload_begin"),
5365
+ uploadId: z15.string().min(1).max(100).describe("From fling_upload_begin"),
3955
5366
  listHtml
3956
5367
  },
3957
5368
  annotations: { destructiveHint: false, openWorldHint: true }
@@ -3962,18 +5373,18 @@ function mcpToolsFor(w) {
3962
5373
  description: "Get or create a public share link for a site: anyone with the link can view it without signing in (use it to show a private site to someone who cannot sign in). `refresh` replaces the link (the old one stops working); `revoke` removes it.",
3963
5374
  inputSchema: {
3964
5375
  name: siteName,
3965
- refresh: z14.boolean().optional().describe("Rotate the link"),
3966
- revoke: z14.boolean().optional().describe("Remove the link")
5376
+ refresh: z15.boolean().optional().describe("Rotate the link"),
5377
+ revoke: z15.boolean().optional().describe("Remove the link")
3967
5378
  },
3968
5379
  annotations: { destructiveHint: false, openWorldHint: true }
3969
5380
  }),
3970
5381
  setAccess: tool({
3971
5382
  name: "fling_set_access",
3972
5383
  title: "Set who can open a site",
3973
- description: "Set a site's access level: `only_me` (only the user), `members` (" + w.privateAudience + `), \`groups\` and \`people\` (only the user, the groups in \`groups\` by slug and the addresses in \`emails\`; both levels take both, and replace the whole audience), or \`public\` (anyone can open the site; its review page and comments still need sign-in). Only change it when the user asks. ${addressRule(w)} Share links still open the site to anyone who has them. Someone who loses access is shut out within 5 minutes; people and groups added are told by email when the instance sends it.`,
5384
+ description: "Set a site's access level: `only_me` (only the user), `members` (" + w2.privateAudience + `), \`groups\` and \`people\` (only the user, the groups in \`groups\` by slug and the addresses in \`emails\`; both levels take both, and replace the whole audience), or \`public\` (anyone can open the site; its review page and comments still need sign-in). Only change it when the user asks. ${addressRule(w2)} Share links still open the site to anyone who has them. Someone who loses access is shut out within 5 minutes; people and groups added are told by email when the instance sends it.`,
3974
5385
  inputSchema: {
3975
5386
  name: siteName,
3976
- access: z14.enum(ACCESS_LEVELS).describe("only_me, members, groups, people or public"),
5387
+ access: z15.enum(ACCESS_LEVELS).describe("only_me, members, groups, people or public"),
3977
5388
  emails: emails.optional().describe("For groups or people: the addresses that may open it"),
3978
5389
  groups: groupSlugs.optional().describe("For groups or people: the groups (slugs, fling_groups) whose members may")
3979
5390
  },
@@ -3982,14 +5393,14 @@ function mcpToolsFor(w) {
3982
5393
  setVisibility: tool({
3983
5394
  name: "fling_set_visibility",
3984
5395
  title: "Set visibility",
3985
- description: `Make a site private or public (anyone can open the site; its review page and comments still need sign-in). Making it private gives it back the access it had before (only the user, ${w.privateAudience}, or its audience). fling_set_access sets any level.`,
3986
- inputSchema: { name: siteName, visibility: z14.enum(["private", "public"]) },
5396
+ description: `Make a site private or public (anyone can open the site; its review page and comments still need sign-in). Making it private gives it back the access it had before (only the user, ${w2.privateAudience}, or its audience). fling_set_access sets any level.`,
5397
+ inputSchema: { name: siteName, visibility: z15.enum(["private", "public"]) },
3987
5398
  annotations: { idempotentHint: true, openWorldHint: true }
3988
5399
  }),
3989
5400
  setAudience: tool({
3990
5401
  name: "fling_set_audience",
3991
5402
  title: "Set who can see a private site",
3992
- description: `Limit a private site to listed people and groups (its audience), or open it again to ${w.privateAudience}; fling_set_access does the same for whole levels, including only the user. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups lists them); \`clear\` empties both (then every signed-in member can see it again). The owner always sees the site. ${addressRule(w)} The audience only applies while the site is private (fling_set_visibility); share links still open it to anyone. Removing someone takes up to 5 minutes to shut them out. fling_info shows the audience.`,
5403
+ description: `Limit a private site to listed people and groups (its audience), or open it again to ${w2.privateAudience}; fling_set_access does the same for whole levels, including only the user. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups lists them); \`clear\` empties both (then every signed-in member can see it again). The owner always sees the site. ${addressRule(w2)} The audience only applies while the site is private (fling_set_visibility); share links still open it to anyone. Removing someone takes up to 5 minutes to shut them out. fling_info shows the audience.`,
3993
5404
  inputSchema: {
3994
5405
  name: siteName,
3995
5406
  add: emails.optional().describe("Addresses to let in"),
@@ -3998,14 +5409,14 @@ function mcpToolsFor(w) {
3998
5409
  addGroups: groupSlugs.optional().describe("Groups (slugs) to let in"),
3999
5410
  removeGroups: groupSlugs.optional().describe("Groups (slugs) to take out"),
4000
5411
  setGroups: groupSlugs.optional().describe("Replace the groups with exactly these slugs"),
4001
- clear: z14.boolean().optional().describe("Empty the audience (addresses and groups): every signed-in member sees it")
5412
+ clear: z15.boolean().optional().describe("Empty the audience (addresses and groups): every signed-in member sees it")
4002
5413
  },
4003
5414
  annotations: { idempotentHint: true, openWorldHint: false }
4004
5415
  }),
4005
5416
  setOwners: tool({
4006
5417
  name: "fling_set_owners",
4007
5418
  title: "Set a site's owners",
4008
- description: `Change who owns a site: people and groups who may do everything the user can with it (publish, roll back, change its access and settings, its owners and publishers, archive and delete it). Only owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w.name} may be owners, never guests; a site keeps at least one person (address) as an owner, and has at most ${OWNER_EMAILS_MAX} addresses. Naming a group trusts whoever manages it. fling_info shows the owners and publishers.`,
5419
+ description: `Change who owns a site: people and groups who may do everything the user can with it (publish, roll back, change its access and settings, its owners and publishers, archive and delete it). Only owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w2.name} may be owners, never guests; a site keeps at least one person (address) as an owner, and has at most ${OWNER_EMAILS_MAX} addresses. Naming a group trusts whoever manages it. fling_info shows the owners and publishers.`,
4009
5420
  inputSchema: {
4010
5421
  name: siteName,
4011
5422
  add: roleChange.add.describe("Addresses to make owners"),
@@ -4022,7 +5433,7 @@ function mcpToolsFor(w) {
4022
5433
  setPublishers: tool({
4023
5434
  name: "fling_set_publishers",
4024
5435
  title: "Set a site's publishers",
4025
- description: `Change who publishes a site without owning it: people and groups who may deploy new versions and roll back, but not change its access or settings, add owners or delete it. Only the site's owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w.name} may publish, never guests. Someone who is also an owner stays an owner. fling_info shows the owners and publishers.`,
5436
+ description: `Change who publishes a site without owning it: people and groups who may deploy new versions and roll back, but not change its access or settings, add owners or delete it. Only the site's owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w2.name} may publish, never guests. Someone who is also an owner stays an owner. fling_info shows the owners and publishers.`,
4026
5437
  inputSchema: {
4027
5438
  name: siteName,
4028
5439
  add: roleChange.add.describe("Addresses to make publishers"),
@@ -4039,9 +5450,9 @@ function mcpToolsFor(w) {
4039
5450
  groups: tool({
4040
5451
  name: "fling_groups",
4041
5452
  title: "List groups",
4042
- description: `List the groups on ${w.name}: named lists of people (a team) that any member can use in a site's audience (fling_set_audience \`addGroups\`). Each has a slug, a name, a size and an owner; \`mine\` lists only the user's own. \`members\` lists only the groups of exactly those people: use it before making a group, or to swap a list of addresses in an audience for a group that already holds them.`,
5453
+ description: `List the groups on ${w2.name}: named lists of people (a team) that any member can use in a site's audience (fling_set_audience \`addGroups\`). Each has a slug, a name, a size and an owner; \`mine\` lists only the user's own. \`members\` lists only the groups of exactly those people: use it before making a group, or to swap a list of addresses in an audience for a group that already holds them.`,
4043
5454
  inputSchema: {
4044
- mine: z14.boolean().optional().describe("Only the groups the user owns"),
5455
+ mine: z15.boolean().optional().describe("Only the groups the user owns"),
4045
5456
  members: members.optional().describe("Only the groups whose members are exactly these addresses")
4046
5457
  },
4047
5458
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -4056,7 +5467,7 @@ function mcpToolsFor(w) {
4056
5467
  groupCreate: tool({
4057
5468
  name: "fling_group_create",
4058
5469
  title: "Create a group",
4059
- description: `Create a group the user owns: a named list of people that anyone signed in to ${w.name} can see and use in a site's audience, but only the user can change. The slug is ${GROUP_SLUG_RULES}, unique on ${w.name}; at most ${GROUP_MEMBERS_MAX} members. ${addressRule(w)}`,
5470
+ description: `Create a group the user owns: a named list of people that anyone signed in to ${w2.name} can see and use in a site's audience, but only the user can change. The slug is ${GROUP_SLUG_RULES}, unique on ${w2.name}; at most ${GROUP_MEMBERS_MAX} members. ${addressRule(w2)}`,
4060
5471
  inputSchema: {
4061
5472
  slug: groupSlug,
4062
5473
  name: groupName.describe('Its display name, e.g. "Design team"'),
@@ -4067,7 +5478,7 @@ function mcpToolsFor(w) {
4067
5478
  groupMembers: tool({
4068
5479
  name: "fling_group_members",
4069
5480
  title: "Change who is in a group",
4070
- description: `Add people to a group the user owns, or take them out. Every site whose audience names the group follows: someone taken out is shut out within 5 minutes. ${addressRule(w)}`,
5481
+ description: `Add people to a group the user owns, or take them out. Every site whose audience names the group follows: someone taken out is shut out within 5 minutes. ${addressRule(w2)}`,
4071
5482
  inputSchema: {
4072
5483
  slug: groupSlug,
4073
5484
  add: members.optional().describe("Addresses to add"),
@@ -4088,7 +5499,7 @@ function mcpToolsFor(w) {
4088
5499
  description: "Permanently delete a group the user owns. Sites whose audience names it keep their restriction, and anyone it let in loses access (a site limited to it alone is left to its owner). Cannot be undone \u2014 confirm with the user first and pass `confirm: true`.",
4089
5500
  inputSchema: {
4090
5501
  slug: groupSlug,
4091
- confirm: z14.literal(true).describe("Must be true: the user has confirmed the deletion")
5502
+ confirm: z15.literal(true).describe("Must be true: the user has confirmed the deletion")
4092
5503
  },
4093
5504
  annotations: { destructiveHint: true, openWorldHint: false }
4094
5505
  }),
@@ -4098,7 +5509,7 @@ function mcpToolsFor(w) {
4098
5509
  description: "Archive a site (it stops being served and is hidden from lists, but its name, files and versions are kept) or, with `unarchive`, bring it back. Prefer this over deleting.",
4099
5510
  inputSchema: {
4100
5511
  name: siteName,
4101
- unarchive: z14.boolean().optional().describe("Restore an archived site")
5512
+ unarchive: z15.boolean().optional().describe("Restore an archived site")
4102
5513
  },
4103
5514
  annotations: { idempotentHint: true, openWorldHint: false }
4104
5515
  }),
@@ -4108,28 +5519,28 @@ function mcpToolsFor(w) {
4108
5519
  description: "Permanently delete a site and every version of it, freeing its name. Cannot be undone \u2014 confirm with the user first and pass `confirm: true`. Consider fling_archive instead.",
4109
5520
  inputSchema: {
4110
5521
  name: siteName,
4111
- confirm: z14.literal(true).describe("Must be true: the user has confirmed the deletion")
5522
+ confirm: z15.literal(true).describe("Must be true: the user has confirmed the deletion")
4112
5523
  },
4113
5524
  annotations: { destructiveHint: true, openWorldHint: false }
4114
5525
  }),
4115
5526
  commentsList: tool({
4116
5527
  name: "fling_comments_list",
4117
5528
  title: "List comments",
4118
- description: `List the comments people left on a site while reviewing it (${w.reviewPattern}), as threads: each has the page path it is about, the version the site was serving when it was written, its replies, and whether it is resolved. Anyone signed in to ${w.name} can comment on a site they can open. Resolved threads are left out unless \`includeResolved\`. Use it to act on feedback: fix the site, republish, then resolve the threads with fling_comment_resolve.`,
5529
+ description: `List the comments people left on a site while reviewing it (${w2.reviewPattern}), as threads: each has the page path it is about, the version the site was serving when it was written, its replies, and whether it is resolved. Anyone signed in to ${w2.name} can comment on a site they can open. Resolved threads are left out unless \`includeResolved\`. Use it to act on feedback: fix the site, republish, then resolve the threads with fling_comment_resolve.`,
4119
5530
  inputSchema: {
4120
5531
  name: siteName,
4121
5532
  path: commentPath.optional().describe('Only this page, e.g. "/" or "/docs/"'),
4122
- includeResolved: z14.boolean().optional().describe("Include resolved threads")
5533
+ includeResolved: z15.boolean().optional().describe("Include resolved threads")
4123
5534
  },
4124
5535
  annotations: { readOnlyHint: true, openWorldHint: false }
4125
5536
  }),
4126
5537
  commentAdd: tool({
4127
5538
  name: "fling_comment_add",
4128
5539
  title: "Add a comment",
4129
- description: `Comment on a page of a site (shown on its review page, ${w.reviewPattern}), or reply to a thread (\`replyTo\`: a thread id from fling_comments_list). Comments are signed with the user's name, so only write one the user asked for.`,
5540
+ description: `Comment on a page of a site (shown on its review page, ${w2.reviewPattern}), or reply to a thread (\`replyTo\`: a thread id from fling_comments_list). Comments are signed with the user's name, so only write one the user asked for.`,
4130
5541
  inputSchema: {
4131
5542
  name: siteName,
4132
- body: z14.string().min(1).max(COMMENT_MAX_CHARS).describe("The comment (plain text)"),
5543
+ body: z15.string().min(1).max(COMMENT_MAX_CHARS).describe("The comment (plain text)"),
4133
5544
  path: commentPath.optional().describe('The page it is about (default "/"); ignored for a reply'),
4134
5545
  replyTo: commentId.optional().describe("Reply to this thread instead of starting one")
4135
5546
  },
@@ -4142,7 +5553,7 @@ function mcpToolsFor(w) {
4142
5553
  inputSchema: {
4143
5554
  name: siteName,
4144
5555
  id: commentId.describe("The thread id"),
4145
- reopen: z14.boolean().optional().describe("Reopen a resolved thread")
5556
+ reopen: z15.boolean().optional().describe("Reopen a resolved thread")
4146
5557
  },
4147
5558
  annotations: { idempotentHint: true, openWorldHint: false }
4148
5559
  }),
@@ -4168,8 +5579,8 @@ function mcpToolsFor(w) {
4168
5579
  title: "Start a forms config",
4169
5580
  description: `A starter forms config to adapt, for structured feedback on a site's review page: ${TEMPLATES_LIST}. Ask the user what they want collected first, then change the template's options, wording and \`paths\` to fit, check it with fling_forms_check and publish it as \`forms\`. ${FORMS_FORMAT}`,
4170
5581
  inputSchema: {
4171
- template: z14.enum(FORM_TEMPLATE_NAMES).describe("Which starter"),
4172
- title: z14.string().min(1).max(FORMS_TITLE_MAX).optional().describe(`The config's title, what the review page calls the forms (e.g. "Evals")`)
5582
+ template: z15.enum(FORM_TEMPLATE_NAMES).describe("Which starter"),
5583
+ title: z15.string().min(1).max(FORMS_TITLE_MAX).optional().describe(`The config's title, what the review page calls the forms (e.g. "Evals")`)
4173
5584
  },
4174
5585
  annotations: { readOnlyHint: true, openWorldHint: false }
4175
5586
  }),
@@ -4179,7 +5590,7 @@ function mcpToolsFor(w) {
4179
5590
  description: `Check a forms config before publishing it, as a publish will: the envelope, each schema against JSON Schema 2020-12, the limits and the globs. With \`paths\` (the site's files, e.g. ["index.html", "interviews/1.html"]) it also says which pages each form applies to and warns about globs that match none. Returns \`ok\`, the \`errors\` (each saying where) and a summary. ${FORMS_FORMAT}`,
4180
5591
  inputSchema: {
4181
5592
  forms: formsConfig.describe("The forms config to check"),
4182
- paths: z14.array(z14.string().min(1).max(1024)).max(MAX_FILES).optional().describe(
5593
+ paths: z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe(
4183
5594
  "The site's file paths (or page paths), to see which pages each form applies to"
4184
5595
  )
4185
5596
  },
@@ -4204,25 +5615,25 @@ function mcpToolsFor(w) {
4204
5615
  name: siteName,
4205
5616
  path: commentPath.describe('The page, e.g. "/" or "/interviews/1.html"'),
4206
5617
  formId: formId.describe("The form (its id, from fling_forms)"),
4207
- data: z14.record(z14.string(), z14.unknown()).describe("The answers, keyed by schema property"),
4208
- quote: z14.string().min(1).max(ANCHOR_QUOTE_MAX).optional().describe("A comment-kind form: the text on the page the response is about")
5618
+ data: z15.record(z15.string(), z15.unknown()).describe("The answers, keyed by schema property"),
5619
+ quote: z15.string().min(1).max(ANCHOR_QUOTE_MAX).optional().describe("A comment-kind form: the text on the page the response is about")
4209
5620
  },
4210
5621
  annotations: { destructiveHint: false, openWorldHint: true }
4211
5622
  }),
4212
5623
  notifications: tool({
4213
5624
  name: "fling_notifications",
4214
5625
  title: "Notification settings",
4215
- description: `Show what ${w.name} tells the user about and how: each event (a site shared with them, added to a group, a comment on their site, a reply in their thread\u2026) with its key and, per channel (email), whether it is on or off, marking the ones the user chose themselves; and whether everything is muted. Use it before fling_notifications_set, or when the user asks why they get (or do not get) emails.`,
5626
+ description: `Show what ${w2.name} tells the user about and how: each event (a site shared with them, added to a group, a comment on their site, a reply in their thread\u2026) with its key and, per channel (email), whether it is on or off, marking the ones the user chose themselves; and whether everything is muted. Use it before fling_notifications_set, or when the user asks why they get (or do not get) emails.`,
4216
5627
  inputSchema: {},
4217
5628
  annotations: { readOnlyHint: true, openWorldHint: false }
4218
5629
  }),
4219
5630
  notificationsSet: tool({
4220
5631
  name: "fling_notifications_set",
4221
5632
  title: "Change notification settings",
4222
- description: `Change what ${w.name} tells the user about: \`muted: true\` stops everything (false turns it back on, with their choices kept), and \`cells\` turns single events on or off per channel, or back to the default (\`value: "default"\`). Event keys come from fling_notifications. Only change what the user asked for. Returns the settings after the change.`,
5633
+ description: `Change what ${w2.name} tells the user about: \`muted: true\` stops everything (false turns it back on, with their choices kept), and \`cells\` turns single events on or off per channel, or back to the default (\`value: "default"\`). Event keys come from fling_notifications. Only change what the user asked for. Returns the settings after the change.`,
4223
5634
  inputSchema: {
4224
- muted: z14.boolean().optional().describe("true: send nothing at all; false: unmute"),
4225
- cells: z14.array(CellChangeSchema).max(50).optional().describe(
5635
+ muted: z15.boolean().optional().describe("true: send nothing at all; false: unmute"),
5636
+ cells: z15.array(CellChangeSchema).max(50).optional().describe(
4226
5637
  'Events to change: `{ event, channel, value }`, value "on", "off" or "default"'
4227
5638
  )
4228
5639
  },
@@ -4240,8 +5651,8 @@ function mcpToolsFor(w) {
4240
5651
  title: "Start a Paths home page",
4241
5652
  description: `A starter home page (index.html) for a site with Paths, with its Paths block in place: Fling fills it with the site's live Paths. Templates: ${PATHS_TEMPLATES_LIST}. Use it when the user wants a custom home page listing their Paths rather than the default one. Adapt it freely (wording, layout, styling) while keeping the block, check it with fling_paths_check, then publish it as the site root (without \`path\`). Needs no sign-in. ${PATHS_HOME_CHOICE} ${PATHS_BLOCK_FORMAT}`,
4242
5653
  inputSchema: {
4243
- template: z14.enum(PATHS_TEMPLATE_NAMES).describe("Which starter"),
4244
- title: z14.string().min(1).max(200).optional().describe(`The page's title and heading (e.g. "Payments plans")`)
5654
+ template: z15.enum(PATHS_TEMPLATE_NAMES).describe("Which starter"),
5655
+ title: z15.string().min(1).max(200).optional().describe(`The page's title and heading (e.g. "Payments plans")`)
4245
5656
  },
4246
5657
  annotations: { readOnlyHint: true, openWorldHint: false }
4247
5658
  }),
@@ -4250,7 +5661,7 @@ function mcpToolsFor(w) {
4250
5661
  title: "Check a Paths home page",
4251
5662
  description: `Check a site's home page (index.html) before publishing it, for the Paths block Fling fills with the site's Paths: whether there is one, bare or template, its options, and warnings (unknown options or placeholders, an unclosed template, an item without a link). Returns \`ok\`, \`errors\` and \`warnings\`. Use it on every custom home page for a site with Paths. Needs no sign-in. ${PATHS_HOME_CHOICE} ${PATHS_BLOCK_FORMAT}`,
4252
5663
  inputSchema: {
4253
- html: z14.string().min(1).max(MCP_PUBLISH_MAX_BYTES).describe("The page, as HTML")
5664
+ html: z15.string().min(1).max(MCP_PUBLISH_MAX_BYTES).describe("The page, as HTML")
4254
5665
  },
4255
5666
  annotations: { readOnlyHint: true, openWorldHint: false }
4256
5667
  }),
@@ -4260,7 +5671,7 @@ function mcpToolsFor(w) {
4260
5671
  description: "Point a site at an earlier version (ids from fling_info). Instant; nothing is uploaded. With `path`, roll back only that Path (ids from fling_info with the same `path`); the rest of the site and its other Paths stay as they are.",
4261
5672
  inputSchema: {
4262
5673
  name: siteName,
4263
- versionId: z14.string().min(1).max(100).describe("Version id to serve"),
5674
+ versionId: z15.string().min(1).max(100).describe("Version id to serve"),
4264
5675
  path: pathFolder.optional().describe(
4265
5676
  `One of the site's Paths, its folder (e.g. "PAY-412"): roll back only that Path`
4266
5677
  )
@@ -4270,8 +5681,8 @@ function mcpToolsFor(w) {
4270
5681
  };
4271
5682
  }
4272
5683
  var mcpTools = mcpToolsFor(mcpWording());
4273
- var NOTIFICATIONS_NOTE = (w) => `${w.name} emails people when a site is shared with them, they are made an owner or publisher of one, they are added to a group, or someone comments on their site or replies in their thread. fling_notifications shows what the user hears about; change it with fling_notifications_set only when they ask.`;
4274
- var COMMENTS_NOTE = (w, opts = {}) => `People review sites at ${w.reviewPattern} and leave comments on its pages. Publishing returns this review link (\`reviewUrl\`): it is the one to share when the user wants feedback; reviewers sign in to use it. fling_comments_list shows the comments; after acting on feedback, resolve the threads with fling_comment_resolve. Only post (fling_comment_add) or delete (fling_comment_delete) comments when the user asks.` + (opts.forms ? " To collect labels, ratings, scores or eval judgements, add a form (fling_forms_template) rather than asking reviewers to type codes in comments: their answers are then checked and exported as data." : "");
5684
+ var NOTIFICATIONS_NOTE = (w2) => `${w2.name} emails people when a site is shared with them, they are made an owner or publisher of one, they are added to a group, or someone comments on their site or replies in their thread. fling_notifications shows what the user hears about; change it with fling_notifications_set only when they ask.`;
5685
+ var COMMENTS_NOTE = (w2, opts = {}) => `People review sites at ${w2.reviewPattern} and leave comments on its pages. Publishing returns this review link (\`reviewUrl\`): it is the one to share when the user wants feedback; reviewers sign in to use it. fling_comments_list shows the comments; after acting on feedback, resolve the threads with fling_comment_resolve. Only post (fling_comment_add) or delete (fling_comment_delete) comments when the user asks.` + (opts.forms ? " To collect labels, ratings, scores or eval judgements, add a form (fling_forms_template) rather than asking reviewers to type codes in comments: their answers are then checked and exported as data." : "");
4275
5686
  var shareForFeedback = (reviewPage2, instanceName, forms2 = false) => `Share for feedback: ${reviewPage2} (reviewers sign in to ${instanceName} to see the site${forms2 ? ", comment and answer its forms" : " and comment"}).`;
4276
5687
  var MCP_FILES_LISTED = 200;
4277
5688
  function describeVersionFiles(name, files, opts) {
@@ -4295,13 +5706,13 @@ function describeVersionFiles(name, files, opts) {
4295
5706
  return lines.join("\n");
4296
5707
  }
4297
5708
  function looksLikeCodedLabels(threads) {
4298
- const short = threads.map((t) => t.comment).filter((c) => !c.response && c.body.trim().length <= 40);
5709
+ const short = threads.map((t) => t.comment).filter((c2) => !c2.response && c2.body.trim().length <= 40);
4299
5710
  if (short.length < 5 || short.length * 2 < threads.length) return false;
4300
5711
  const key = (body) => body.trim().toLowerCase().replace(/[\s.!]+$/g, "");
4301
5712
  const counts = /* @__PURE__ */ new Map();
4302
- for (const c of short) counts.set(key(c.body), (counts.get(key(c.body)) ?? 0) + 1);
4303
- const repeated = short.filter((c) => (counts.get(key(c.body)) ?? 0) > 1);
4304
- return repeated.length * 2 >= short.length && new Set(repeated.map((c) => c.path)).size >= 3;
5713
+ for (const c2 of short) counts.set(key(c2.body), (counts.get(key(c2.body)) ?? 0) + 1);
5714
+ const repeated = short.filter((c2) => (counts.get(key(c2.body)) ?? 0) > 1);
5715
+ return repeated.length * 2 >= short.length && new Set(repeated.map((c2) => c2.path)).size >= 3;
4305
5716
  }
4306
5717
  var CODED_LABELS_NOTE = "These comments look like labels typed by hand (short, repeated across pages). For the next round, suggest a form to the user (fling_forms_template, e.g. `labels`): reviewers then pick from readable options, every page gets one answer per reviewer, and fling_responses_list exports them as data.";
4307
5718
  function describeComments(list, opts = {}) {
@@ -4312,10 +5723,10 @@ function describeComments(list, opts = {}) {
4312
5723
  const version = (id) => id === null ? "" : id === list.site.currentVersionId ? ", current version" : `, version ${id}`;
4313
5724
  const head = `${threads.length} ${opts.includeResolved ? "" : "open "}thread${threads.length === 1 ? "" : "s"} on ${name}` + (hidden ? ` (${hidden} resolved not shown)` : "") + (opts.reviewUrl ? `. Review page: ${opts.reviewUrl}` : "");
4314
5725
  const blocks = threads.map(
4315
- ({ comment: c, replies }) => [
4316
- `- [${c.id}] ${c.resolvedAt ? "RESOLVED " : ""}${c.path}${version(c.versionId)} \u2014 ${authorLabel(c.author)}, ${c.updatedAt ?? c.createdAt}` + (c.response ? ` (response to form "${c.response.formId}")` : "") + ":",
4317
- ...c.anchor?.quote ? [` > ${c.anchor.quote.replace(/\n/g, " ")}`] : [],
4318
- ` ${c.body.replace(/\n/g, "\n ")}`,
5726
+ ({ comment: c2, replies }) => [
5727
+ `- [${c2.id}] ${c2.resolvedAt ? "RESOLVED " : ""}${c2.path}${version(c2.versionId)} \u2014 ${authorLabel(c2.author)}, ${c2.updatedAt ?? c2.createdAt}` + (c2.response ? ` (response to form "${c2.response.formId}")` : "") + ":",
5728
+ ...c2.anchor?.quote ? [` > ${c2.anchor.quote.replace(/\n/g, " ")}`] : [],
5729
+ ` ${c2.body.replace(/\n/g, "\n ")}`,
4319
5730
  ...replies.map(
4320
5731
  (r) => ` - [${r.id}] ${authorLabel(r.author)}, ${r.createdAt}: ${r.body.replace(/\n/g, "\n ")}`
4321
5732
  )
@@ -4325,6 +5736,163 @@ function describeComments(list, opts = {}) {
4325
5736
  return [head, ...blocks, ...note].join("\n");
4326
5737
  }
4327
5738
 
5739
+ // ../../packages/shared/src/route-keys.ts
5740
+ var SITE_PASS_TTL_SECONDS = 5 * 60;
5741
+
5742
+ // ../../packages/shared/src/guide-facts.ts
5743
+ var mb = (bytes) => `${bytes / (1024 * 1024)} MB`;
5744
+ var count2 = (n) => n.toLocaleString("en-GB");
5745
+ var PINNED_GUIDE_FACTS = {
5746
+ /** the oldest Node the CLI runs on (apps/cli/package.json `engines.node`) */
5747
+ "node-version": "22",
5748
+ /** how long the audit log keeps an entry (`AUDIT_TTL_DAYS`) */
5749
+ "audit-days": "180 days",
5750
+ /** how long an admin's impersonation lasts (`IMPERSONATION_TTL_SECONDS`) */
5751
+ "impersonation-ttl": "an hour",
5752
+ /** how long an invitation's sign-in link works (`INVITATION_LINK_TTL_SECONDS`) */
5753
+ "invite-link-ttl": "7 days",
5754
+ /** new outside addresses one person may invite a day, unless the instance says otherwise (`INVITES_PER_DAY`) */
5755
+ "invites-per-day": "20",
5756
+ /** how long an address that bounced or complained gets no mail (`SUPPRESSION_MS`) */
5757
+ "suppression-days": "30 days"
5758
+ };
5759
+ var GUIDE_FACTS = {
5760
+ "max-deploy": mb(MAX_DEPLOY_BYTES),
5761
+ "max-file": mb(MAX_FILE_BYTES),
5762
+ "max-files": count2(MAX_FILES),
5763
+ "max-inline": mb(MCP_PUBLISH_MAX_BYTES),
5764
+ "max-paths": count2(MAX_PATHS_PER_SITE),
5765
+ "max-folder": count2(MAX_PATH_FOLDER_LENGTH),
5766
+ "site-name-max": count2(SITE_NAME_MAX),
5767
+ "mail-tests-per-hour": count2(MAIL_TESTS_PER_HOUR),
5768
+ "markdown-max-size": mb(MAX_MARKDOWN_BYTES),
5769
+ "markdown-max-files": count2(MAX_RENDERED_MARKDOWN),
5770
+ "access-revoke-delay": `${SITE_PASS_TTL_SECONDS / 60} minutes`,
5771
+ "audience-emails-max": count2(AUDIENCE_EMAILS_MAX),
5772
+ "audience-groups-max": count2(AUDIENCE_GROUPS_MAX),
5773
+ "group-members-max": count2(GROUP_MEMBERS_MAX),
5774
+ "owner-emails-max": count2(OWNER_EMAILS_MAX),
5775
+ "publisher-emails-max": count2(PUBLISHER_EMAILS_MAX),
5776
+ "comments-max": count2(COMMENTS_PER_SITE_MAX),
5777
+ "comment-max-chars": count2(COMMENT_MAX_CHARS),
5778
+ "forms-max": count2(FORMS_MAX),
5779
+ "responses-max": count2(RESPONSES_PER_SITE_MAX),
5780
+ "cli-package": CLI_PACKAGE,
5781
+ "repo-slug": REPO_SLUG,
5782
+ "repo-url": REPO_URL,
5783
+ "why-site": WHY_SITE_NAME,
5784
+ ...PINNED_GUIDE_FACTS
5785
+ };
5786
+
5787
+ // ../../packages/shared/src/kvs.ts
5788
+ import { z as z16 } from "zod";
5789
+ var KvsSiteValueSchema = z16.object({
5790
+ /** siteId — S3 prefix is `sites/<id>/<v>/` */
5791
+ id: z16.string(),
5792
+ /** current versionId */
5793
+ v: z16.string(),
5794
+ vis: z16.enum(["private", "public"]),
5795
+ /** serve /index.html for unknown extensionless paths */
5796
+ spa: z16.boolean(),
5797
+ /** present when the site is restricted (private with an audience): the edge wants a site pass */
5798
+ r: z16.literal(1).optional(),
5799
+ /** present when the site has live Paths: a request's first folder may be one (`path:` keys) */
5800
+ p: z16.literal(1).optional(),
5801
+ /**
5802
+ * the rendered home page and Paths listing (`sites/<id>/_rendered/<i>.html|json`), served for
5803
+ * `/`, `/index.html` and PATHS_JSON_PATH instead of the version's own index.html
5804
+ */
5805
+ i: z16.string().optional(),
5806
+ /** present when the current version's Markdown files have rendered pages (markdown.ts) */
5807
+ m: z16.literal(1).optional()
5808
+ });
5809
+ var KvsPathValueSchema = z16.object({
5810
+ id: z16.string(),
5811
+ v: z16.string(),
5812
+ /** as on a site's value: its current version's Markdown has rendered pages */
5813
+ m: z16.literal(1).optional()
5814
+ });
5815
+
5816
+ // ../../packages/shared/src/listing.ts
5817
+ var LISTING_GENERATOR_META = "fling-listing";
5818
+ var escapeHtml = (s) => s.replace(
5819
+ /[&<>"']/g,
5820
+ (c2) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c2]
5821
+ );
5822
+ var hrefFor = (path3) => path3.split("/").map(encodeURIComponent).join("/");
5823
+ function isHtmlPath(path3) {
5824
+ return /\.html?$/i.test(path3);
5825
+ }
5826
+ function extractHtmlTitle(html) {
5827
+ const match = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html.slice(0, 65536));
5828
+ const title = match?.[1]?.replace(/<[^>]*>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\s+/g, " ").trim();
5829
+ return title ? title : null;
5830
+ }
5831
+ function renderHtmlListing(siteName2, entries) {
5832
+ const pages = entries.filter((e) => isHtmlPath(e.path) && e.path.toLowerCase() !== "index.html").sort((a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0);
5833
+ const groups2 = /* @__PURE__ */ new Map();
5834
+ for (const page2 of pages) {
5835
+ const slash = page2.path.lastIndexOf("/");
5836
+ const folder = slash === -1 ? "" : page2.path.slice(0, slash);
5837
+ groups2.set(folder, [...groups2.get(folder) ?? [], page2]);
5838
+ }
5839
+ const sections = [...groups2.entries()].sort(([a3], [b]) => a3 === "" ? -1 : b === "" ? 1 : a3 < b ? -1 : 1).map(([folder, items]) => {
5840
+ const heading = folder ? `<h2>${escapeHtml(folder)}/</h2>` : "";
5841
+ const rows = items.map((item) => {
5842
+ const file = item.path.slice(item.path.lastIndexOf("/") + 1);
5843
+ const label = item.title ? escapeHtml(item.title) : escapeHtml(file);
5844
+ const sub = item.title ? `<span class="file">${escapeHtml(file)}</span>` : "";
5845
+ return `<li><a href="${hrefFor(item.path)}">${label}</a>${sub}</li>`;
5846
+ }).join("\n");
5847
+ return `${heading}<ul>
5848
+ ${rows}
5849
+ </ul>`;
5850
+ }).join("\n");
5851
+ const body = pages.length ? sections : '<p class="empty">No HTML pages in this fling.</p>';
5852
+ const count3 = `${pages.length} page${pages.length === 1 ? "" : "s"}`;
5853
+ return `<!doctype html>
5854
+ <html lang="en">
5855
+ <head>
5856
+ <meta charset="utf-8">
5857
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5858
+ <meta name="generator" content="${LISTING_GENERATOR_META}">
5859
+ <title>${escapeHtml(siteName2)}</title>
5860
+ <style>
5861
+ :root { color-scheme: light dark; --fg: #000e38; --muted: #5b6480; --bg: #f7f8fb; --card: #fff;
5862
+ --line: #e3e6ef; --accent: #166bff; --green: #00e5a4; }
5863
+ @media (prefers-color-scheme: dark) { :root { --fg: #eef1f8; --muted: #9aa3bd; --bg: #000e38;
5864
+ --card: #0b1a4a; --line: #1d2c5e; --accent: #6ea2ff; } }
5865
+ * { box-sizing: border-box; }
5866
+ body { margin: 0; font: 16px/1.5 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
5867
+ color: var(--fg); background: var(--bg); }
5868
+ main { max-width: 760px; margin: 0 auto; padding: 48px 20px 64px; }
5869
+ header { border-left: 4px solid var(--green); padding-left: 14px; margin-bottom: 28px; }
5870
+ h1 { margin: 0; font-size: 1.6rem; }
5871
+ header p, .file, footer { color: var(--muted); font-size: .875rem; }
5872
+ header p { margin: 4px 0 0; }
5873
+ h2 { font-size: .95rem; margin: 28px 0 8px; color: var(--muted); font-weight: 600; }
5874
+ ul { list-style: none; margin: 0; padding: 0; background: var(--card); border: 1px solid var(--line);
5875
+ border-radius: 10px; overflow: hidden; }
5876
+ li { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; gap: 12px;
5877
+ justify-content: space-between; align-items: baseline; flex-wrap: wrap; }
5878
+ li:first-child { border-top: 0; }
5879
+ a { color: var(--accent); text-decoration: none; font-weight: 500; }
5880
+ a:hover { text-decoration: underline; }
5881
+ .empty { color: var(--muted); }
5882
+ footer { margin-top: 40px; }
5883
+ </style>
5884
+ </head>
5885
+ <body>
5886
+ <main>
5887
+ <header><h1>${escapeHtml(siteName2)}</h1><p>${count3}</p></header>
5888
+ ${body}
5889
+ <footer>Flung with Fling</footer>
5890
+ </main>
5891
+ </body>
5892
+ </html>
5893
+ `;
5894
+ }
5895
+
4328
5896
  // ../../packages/shared/src/ready.ts
4329
5897
  var READY_TIMEOUT_MS = 15e3;
4330
5898
  var NOT_READY_NOTE = "it can take a few more seconds to appear everywhere; reload if you see a 404";
@@ -4373,109 +5941,109 @@ function readinessWaitDisabled(env) {
4373
5941
  }
4374
5942
 
4375
5943
  // ../../packages/shared/src/review-bridge.ts
4376
- import { z as z15 } from "zod";
4377
- var tag = { fling: z15.literal("review") };
4378
- var path = z15.string().max(COMMENT_PATH_MAX);
4379
- var hash = z15.string().max(COMMENT_PATH_MAX);
4380
- var BridgePinSchema = z15.object({
4381
- id: z15.string(),
4382
- n: z15.number().int().min(1),
5944
+ import { z as z17 } from "zod";
5945
+ var tag = { fling: z17.literal("review") };
5946
+ var path = z17.string().max(COMMENT_PATH_MAX);
5947
+ var hash = z17.string().max(COMMENT_PATH_MAX);
5948
+ var BridgePinSchema = z17.object({
5949
+ id: z17.string(),
5950
+ n: z17.number().int().min(1),
4383
5951
  anchor: CommentAnchorSchema,
4384
- selected: z15.boolean(),
4385
- resolved: z15.boolean()
5952
+ selected: z17.boolean(),
5953
+ resolved: z17.boolean()
4386
5954
  });
4387
- var BridgeCursorSchema = z15.object({
4388
- id: z15.string(),
4389
- name: z15.string().max(100),
4390
- colour: z15.string().max(32),
5955
+ var BridgeCursorSchema = z17.object({
5956
+ id: z17.string(),
5957
+ name: z17.string().max(100),
5958
+ colour: z17.string().max(32),
4391
5959
  anchor: CommentAnchorSchema
4392
5960
  });
4393
- var ShellMessageSchema = z15.discriminatedUnion("type", [
4394
- z15.object({ ...tag, type: z15.literal("ready") }),
5961
+ var ShellMessageSchema = z17.discriminatedUnion("type", [
5962
+ z17.object({ ...tag, type: z17.literal("ready") }),
4395
5963
  /** the frame is on `path` (normalised, see normalizeCommentPath) with fragment `hash` ('' or '#…') */
4396
- z15.object({ ...tag, type: z15.literal("location"), path, hash, title: z15.string().max(300) }),
5964
+ z17.object({ ...tag, type: z17.literal("location"), path, hash, title: z17.string().max(300) }),
4397
5965
  /** a pin placed while placing: a click (a spot) or a drag (a box) */
4398
- z15.object({ ...tag, type: z15.literal("pinPlaced"), anchor: CommentAnchorSchema }),
5966
+ z17.object({ ...tag, type: z17.literal("pinPlaced"), anchor: CommentAnchorSchema }),
4399
5967
  /** the reviewer selected text in the page: an anchor on it, with its quote */
4400
- z15.object({ ...tag, type: z15.literal("textSelected"), anchor: CommentAnchorSchema }),
4401
- z15.object({ ...tag, type: z15.literal("pinCancelled") }),
4402
- z15.object({ ...tag, type: z15.literal("pinClicked"), id: z15.string() }),
5968
+ z17.object({ ...tag, type: z17.literal("textSelected"), anchor: CommentAnchorSchema }),
5969
+ z17.object({ ...tag, type: z17.literal("pinCancelled") }),
5970
+ z17.object({ ...tag, type: z17.literal("pinClicked"), id: z17.string() }),
4403
5971
  /** this reviewer's pointer on the page; null when it left the frame */
4404
- z15.object({ ...tag, type: z15.literal("cursor"), anchor: CommentAnchorSchema.nullable() }),
5972
+ z17.object({ ...tag, type: z17.literal("cursor"), anchor: CommentAnchorSchema.nullable() }),
4405
5973
  /** a link or form to another origin, stopped: the frame stays on the site */
4406
- z15.object({ ...tag, type: z15.literal("blocked"), href: z15.string().max(2048) }),
4407
- z15.object({ ...tag, type: z15.literal("escape") }),
5974
+ z17.object({ ...tag, type: z17.literal("blocked"), href: z17.string().max(2048) }),
5975
+ z17.object({ ...tag, type: z17.literal("escape") }),
4408
5976
  /** preview mode: the thumbnail the page asked for, a PNG of the frame's viewport of `versionId` */
4409
- z15.object({
5977
+ z17.object({
4410
5978
  ...tag,
4411
- type: z15.literal("captured"),
4412
- png: z15.instanceof(Blob),
4413
- versionId: z15.string().max(100)
5979
+ type: z17.literal("captured"),
5980
+ png: z17.instanceof(Blob),
5981
+ versionId: z17.string().max(100)
4414
5982
  }),
4415
5983
  /** preview mode: no thumbnail could be drawn (CAPTURE_STALE: the host serves another version) */
4416
- z15.object({ ...tag, type: z15.literal("captureFailed"), reason: z15.string().max(300) })
5984
+ z17.object({ ...tag, type: z17.literal("captureFailed"), reason: z17.string().max(300) })
4417
5985
  ]);
4418
- var PageMessageSchema = z15.discriminatedUnion("type", [
5986
+ var PageMessageSchema = z17.discriminatedUnion("type", [
4419
5987
  /** load `path` (site-relative, may carry `?query` and `#hash`) in the frame */
4420
- z15.object({ ...tag, type: z15.literal("navigate"), path: z15.string().max(COMMENT_PATH_MAX * 2) }),
4421
- z15.object({ ...tag, type: z15.literal("reload") }),
4422
- z15.object({ ...tag, type: z15.literal("placing"), on: z15.boolean() }),
5988
+ z17.object({ ...tag, type: z17.literal("navigate"), path: z17.string().max(COMMENT_PATH_MAX * 2) }),
5989
+ z17.object({ ...tag, type: z17.literal("reload") }),
5990
+ z17.object({ ...tag, type: z17.literal("placing"), on: z17.boolean() }),
4423
5991
  /** the pins on the frame's current page */
4424
- z15.object({ ...tag, type: z15.literal("pins"), pins: z15.array(BridgePinSchema) }),
5992
+ z17.object({ ...tag, type: z17.literal("pins"), pins: z17.array(BridgePinSchema) }),
4425
5993
  /** scroll the pin into view and draw attention to it */
4426
- z15.object({ ...tag, type: z15.literal("focusPin"), id: z15.string() }),
4427
- z15.object({ ...tag, type: z15.literal("cursors"), cursors: z15.array(BridgeCursorSchema) }),
5994
+ z17.object({ ...tag, type: z17.literal("focusPin"), id: z17.string() }),
5995
+ z17.object({ ...tag, type: z17.literal("cursors"), cursors: z17.array(BridgeCursorSchema) }),
4428
5996
  /**
4429
5997
  * preview mode: once the page has loaded and settled, draw it as a thumbnail (`captured`), only
4430
5998
  * if the sites host serves `versionId` (the site's current version, as the API says)
4431
5999
  */
4432
- z15.object({ ...tag, type: z15.literal("capture"), versionId: z15.string().max(100) })
6000
+ z17.object({ ...tag, type: z17.literal("capture"), versionId: z17.string().max(100) })
4433
6001
  ]);
4434
6002
 
4435
6003
  // ../../packages/shared/src/review-live.ts
4436
- import { z as z16 } from "zod";
6004
+ import { z as z18 } from "zod";
4437
6005
  var LIVE_PICTURE_MAX = 1024;
4438
- var LivePeerSchema = z16.object({
4439
- id: z16.string(),
4440
- name: z16.string().max(100),
4441
- colour: z16.string().max(32),
6006
+ var LivePeerSchema = z18.object({
6007
+ id: z18.string(),
6008
+ name: z18.string().max(100),
6009
+ colour: z18.string().max(32),
4442
6010
  /** their profile picture (https), when sign-in gave one; else clients show initials */
4443
- picture: z16.string().max(LIVE_PICTURE_MAX).optional()
6011
+ picture: z18.string().max(LIVE_PICTURE_MAX).optional()
4444
6012
  });
4445
- var LiveTicketSchema = z16.object({
4446
- url: z16.string(),
4447
- ticket: z16.string(),
6013
+ var LiveTicketSchema = z18.object({
6014
+ url: z18.string(),
6015
+ ticket: z18.string(),
4448
6016
  /** seconds the ticket is good for: connect before then */
4449
- expiresIn: z16.number().int()
6017
+ expiresIn: z18.number().int()
4450
6018
  });
4451
- var path2 = z16.string().max(COMMENT_PATH_MAX);
4452
- var hash2 = z16.string().max(COMMENT_PATH_MAX);
4453
- var LiveClientMessageSchema = z16.discriminatedUnion("type", [
4454
- z16.object({ type: z16.literal("hello") }),
6019
+ var path2 = z18.string().max(COMMENT_PATH_MAX);
6020
+ var hash2 = z18.string().max(COMMENT_PATH_MAX);
6021
+ var LiveClientMessageSchema = z18.discriminatedUnion("type", [
6022
+ z18.object({ type: z18.literal("hello") }),
4455
6023
  /** where this peer's pointer is; `anchor` null when it left the page */
4456
- z16.object({
4457
- type: z16.literal("cursor"),
6024
+ z18.object({
6025
+ type: z18.literal("cursor"),
4458
6026
  path: path2,
4459
6027
  hash: hash2,
4460
6028
  anchor: CommentAnchorSchema.nullable()
4461
6029
  }),
4462
- z16.object({ type: z16.literal("ping") })
6030
+ z18.object({ type: z18.literal("ping") })
4463
6031
  ]);
4464
- var LiveServerMessageSchema = z16.discriminatedUnion("type", [
6032
+ var LiveServerMessageSchema = z18.discriminatedUnion("type", [
4465
6033
  /** the answer to `hello`: who this connection is, and who else is in the room */
4466
- z16.object({ type: z16.literal("welcome"), you: LivePeerSchema, peers: z16.array(LivePeerSchema) }),
4467
- z16.object({ type: z16.literal("join"), peer: LivePeerSchema }),
4468
- z16.object({ type: z16.literal("leave"), peerId: z16.string() }),
4469
- z16.object({
4470
- type: z16.literal("cursor"),
4471
- peerId: z16.string(),
6034
+ z18.object({ type: z18.literal("welcome"), you: LivePeerSchema, peers: z18.array(LivePeerSchema) }),
6035
+ z18.object({ type: z18.literal("join"), peer: LivePeerSchema }),
6036
+ z18.object({ type: z18.literal("leave"), peerId: z18.string() }),
6037
+ z18.object({
6038
+ type: z18.literal("cursor"),
6039
+ peerId: z18.string(),
4472
6040
  path: path2,
4473
6041
  hash: hash2,
4474
6042
  anchor: CommentAnchorSchema.nullable()
4475
6043
  }),
4476
6044
  /** the site's comments changed: refetch them */
4477
- z16.object({ type: z16.literal("comments") }),
4478
- z16.object({ type: z16.literal("pong") })
6045
+ z18.object({ type: z18.literal("comments") }),
6046
+ z18.object({ type: z18.literal("pong") })
4479
6047
  ]);
4480
6048
 
4481
6049
  // src/cli.ts
@@ -4529,7 +6097,7 @@ function exitCodeFor(error) {
4529
6097
  // package.json
4530
6098
  var package_default = {
4531
6099
  name: "@nearform/fling",
4532
- version: "0.10.1",
6100
+ version: "0.11.0",
4533
6101
  license: "MIT",
4534
6102
  description: "Fling a folder of static files at a Fling server and get a link back. CLI + MCP server.",
4535
6103
  type: "module",
@@ -4753,7 +6321,7 @@ function describeCause(cause) {
4753
6321
  import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
4754
6322
  import { homedir } from "node:os";
4755
6323
  import { delimiter, join } from "node:path";
4756
- import { z as z17 } from "zod";
6324
+ import { z as z19 } from "zod";
4757
6325
  var CONFIG_DIR_NAME = ".fling";
4758
6326
  var CONFIG_FILE_NAME = "config.json";
4759
6327
  var ENV = {
@@ -4770,14 +6338,14 @@ var ENV = {
4770
6338
  /** Set by CI systems; the update check stays quiet there too. */
4771
6339
  ci: "CI"
4772
6340
  };
4773
- var serverEntrySchema = z17.object({
6341
+ var serverEntrySchema = z19.object({
4774
6342
  /** What the server said about itself at login. A copy this CLI can't read is just refetched. */
4775
6343
  instance: InstanceMetadataSchema.optional().catch(void 0),
4776
- apiKey: z17.string().min(1).optional().catch(void 0),
4777
- user: z17.object({
4778
- email: z17.string().optional(),
4779
- name: z17.string().optional(),
4780
- userSlug: z17.string().optional()
6344
+ apiKey: z19.string().min(1).optional().catch(void 0),
6345
+ user: z19.object({
6346
+ email: z19.string().optional(),
6347
+ name: z19.string().optional(),
6348
+ userSlug: z19.string().optional()
4781
6349
  }).optional().catch(void 0)
4782
6350
  });
4783
6351
  function systemLocateOptions(env = process.env) {
@@ -5268,9 +6836,9 @@ function colourAt(t) {
5268
6836
  const scaled = Math.min(Math.max(t, 0), 1) * (STOPS.length - 1);
5269
6837
  const i = Math.min(Math.floor(scaled), STOPS.length - 2);
5270
6838
  const f = scaled - i;
5271
- const a = STOPS[i];
6839
+ const a3 = STOPS[i];
5272
6840
  const b = STOPS[i + 1];
5273
- return [0, 1, 2].map((k) => Math.round(a[k] + (b[k] - a[k]) * f));
6841
+ return [0, 1, 2].map((k) => Math.round(a3[k] + (b[k] - a3[k]) * f));
5274
6842
  }
5275
6843
  function gradient(text2, width = text2.length, offset = 0) {
5276
6844
  if (chalk2.level === 0) return text2;
@@ -5435,8 +7003,8 @@ function requireClient(ctx) {
5435
7003
  }
5436
7004
 
5437
7005
  // src/sites.ts
5438
- import { z as z18 } from "zod";
5439
- var ShareResponseSchema2 = z18.looseObject({ shareUrl: z18.string() });
7006
+ import { z as z20 } from "zod";
7007
+ var ShareResponseSchema2 = z20.looseObject({ shareUrl: z20.string() });
5440
7008
  var sitePath2 = (name) => `/api/sites/${encodeURIComponent(name)}`;
5441
7009
  function whoami(client) {
5442
7010
  return client.request("GET", "/api/me", { schema: MeSchema });
@@ -5904,9 +7472,9 @@ function commentsClient(ctx) {
5904
7472
  return requireClient(ctx);
5905
7473
  }
5906
7474
  var reviewPage = (ctx, name, path3) => reviewUrl(ctx.config.instance?.appOrigin ?? ctx.config.serverUrl ?? "", name, path3);
5907
- function describe(c, currentVersionId) {
5908
- const version = c.versionId === null ? "" : c.versionId === currentVersionId ? "" : chalk6.dim(` (on version ${c.versionId})`);
5909
- return `${chalk6.bold(authorLabel(c.author))} ${chalk6.dim(formatDate(c.createdAt))}${version}`;
7475
+ function describe(c2, currentVersionId) {
7476
+ const version = c2.versionId === null ? "" : c2.versionId === currentVersionId ? "" : chalk6.dim(` (on version ${c2.versionId})`);
7477
+ return `${chalk6.bold(authorLabel(c2.author))} ${chalk6.dim(formatDate(c2.createdAt))}${version}`;
5910
7478
  }
5911
7479
  async function runComments(ctx, name, opts) {
5912
7480
  const list = await listComments(commentsClient(ctx), name, { path: opts.path });
@@ -5916,17 +7484,17 @@ async function runComments(ctx, name, opts) {
5916
7484
  ctx.out.data({ ...list, reviewUrl: reviewPage(ctx, name) }, () => {
5917
7485
  const lines = [];
5918
7486
  let lastPath = null;
5919
- for (const { comment: c, replies } of threads.sort(
5920
- (a, b) => a.comment.path.localeCompare(b.comment.path)
7487
+ for (const { comment: c2, replies } of threads.sort(
7488
+ (a3, b) => a3.comment.path.localeCompare(b.comment.path)
5921
7489
  )) {
5922
- if (c.path !== lastPath) {
5923
- lines.push("", chalk6.bold.underline(c.path));
5924
- lastPath = c.path;
5925
- }
5926
- const state = c.resolvedAt ? chalk6.green(" \u2713 resolved") : "";
5927
- lines.push(`${chalk6.dim(c.id)}${state} ${describe(c, list.site.currentVersionId)}`);
5928
- if (c.anchor?.quote) lines.push(chalk6.dim(` > ${c.anchor.quote}`));
5929
- lines.push(...c.body.split("\n").map((l) => ` ${l}`));
7490
+ if (c2.path !== lastPath) {
7491
+ lines.push("", chalk6.bold.underline(c2.path));
7492
+ lastPath = c2.path;
7493
+ }
7494
+ const state = c2.resolvedAt ? chalk6.green(" \u2713 resolved") : "";
7495
+ lines.push(`${chalk6.dim(c2.id)}${state} ${describe(c2, list.site.currentVersionId)}`);
7496
+ if (c2.anchor?.quote) lines.push(chalk6.dim(` > ${c2.anchor.quote}`));
7497
+ lines.push(...c2.body.split("\n").map((l) => ` ${l}`));
5930
7498
  for (const r of replies) {
5931
7499
  lines.push(` ${chalk6.dim("\u21B3")} ${describe(r, list.site.currentVersionId)}`);
5932
7500
  lines.push(...r.body.split("\n").map((l) => ` ${l}`));
@@ -6016,7 +7584,7 @@ async function rootIsIgnored(top, root) {
6016
7584
  const rel = relative(top, root);
6017
7585
  if (!rel || rel.startsWith("..")) return false;
6018
7586
  const segments = rel.split(sep);
6019
- const candidates = segments.map((_, i) => `${segments.slice(0, i + 1).join("/")}/`);
7587
+ const candidates = segments.map((_2, i) => `${segments.slice(0, i + 1).join("/")}/`);
6020
7588
  const out = await git(top, ["check-ignore", "--stdin", "-z"], `${candidates.join("\0")}\0`);
6021
7589
  return out !== null && out.split("\0").some(Boolean);
6022
7590
  }
@@ -6175,7 +7743,7 @@ async function buildManifest(dir) {
6175
7743
  async function walk2(realDir, relDir) {
6176
7744
  await gitIgnore.enterDir(realDir, relDir);
6177
7745
  const entries = await readdir(realDir, { withFileTypes: true });
6178
- entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
7746
+ entries.sort((a3, b) => a3.name < b.name ? -1 : a3.name > b.name ? 1 : 0);
6179
7747
  for (const entry of entries) {
6180
7748
  const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
6181
7749
  if (entry.name.startsWith(".")) {
@@ -6267,7 +7835,7 @@ async function buildManifest(dir) {
6267
7835
  if (findings.length > 0) {
6268
7836
  throw new SecretsFoundError(
6269
7837
  findings.sort(
6270
- (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.line - b.line || a.rule.localeCompare(b.rule)
7838
+ (a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : a3.line - b.line || a3.rule.localeCompare(b.rule)
6271
7839
  )
6272
7840
  );
6273
7841
  }
@@ -6325,13 +7893,13 @@ async function withHtmlListing(local, siteName2) {
6325
7893
  contentType: contentTypeFor("index.html")
6326
7894
  };
6327
7895
  const files = [...local.files.filter((f) => f.path !== "index.html"), index].sort(
6328
- (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0
7896
+ (a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0
6329
7897
  );
6330
7898
  return {
6331
7899
  ...local,
6332
7900
  files,
6333
7901
  totalBytes: files.reduce((n, f) => n + f.size, 0),
6334
- warnings: local.warnings.filter((w) => w !== NO_INDEX_WARNING)
7902
+ warnings: local.warnings.filter((w2) => w2 !== NO_INDEX_WARNING)
6335
7903
  };
6336
7904
  }
6337
7905
  async function loadIgnore(root) {
@@ -6450,7 +8018,7 @@ async function nameTakenError(client, name, body) {
6450
8018
  const raw = body?.error?.suggestions;
6451
8019
  let suggestions = Array.isArray(raw) ? raw.filter((s) => typeof s === "string") : [];
6452
8020
  if (suggestions.length === 0) {
6453
- suggestions = await checkName(client, name).then((c) => c.suggestions).catch(() => []);
8021
+ suggestions = await checkName(client, name).then((c2) => c2.suggestions).catch(() => []);
6454
8022
  }
6455
8023
  return new NameTakenError(name, suggestions);
6456
8024
  }
@@ -6793,7 +8361,7 @@ function zipDotEntry(name) {
6793
8361
  async function extractZip(data, dest, skippedDotfiles = []) {
6794
8362
  const unsafe = [];
6795
8363
  let declared = 0;
6796
- let count2 = 0;
8364
+ let count3 = 0;
6797
8365
  let entries;
6798
8366
  try {
6799
8367
  entries = unzipSync(data, {
@@ -6808,7 +8376,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
6808
8376
  if (dot && !skippedDotfiles.includes(dot)) skippedDotfiles.push(dot);
6809
8377
  return false;
6810
8378
  }
6811
- count2++;
8379
+ count3++;
6812
8380
  declared += file.originalSize;
6813
8381
  if (file.originalSize > MAX_FILE_BYTES)
6814
8382
  throw new CliError(
@@ -6818,7 +8386,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
6818
8386
  throw new CliError(
6819
8387
  `The zip expands to more than ${formatBytes(MAX_DEPLOY_BYTES)}, the limit per deploy`
6820
8388
  );
6821
- if (count2 > MAX_FILES) throw new CliError(`The zip has more than ${MAX_FILES} files`);
8389
+ if (count3 > MAX_FILES) throw new CliError(`The zip has more than ${MAX_FILES} files`);
6822
8390
  return true;
6823
8391
  }
6824
8392
  });
@@ -6855,7 +8423,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
6855
8423
  }
6856
8424
  return written.sort();
6857
8425
  }
6858
- var escapeHtml3 = (s) => s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
8426
+ var escapeHtml3 = (s) => s.replace(/[&<>"']/g, (c2) => `&#${c2.charCodeAt(0)};`);
6859
8427
  function wrapperPage(file) {
6860
8428
  const href = escapeHtml3(encodeURIComponent(file));
6861
8429
  const title = escapeHtml3(file);
@@ -6893,22 +8461,22 @@ function wrapperPage(file) {
6893
8461
  import { createHash as createHash3 } from "node:crypto";
6894
8462
  import { mkdir as mkdir3, readdir as readdir2, readFile as readFile7, rm as rm2, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
6895
8463
  import { dirname as dirname2, join as join6 } from "node:path";
6896
- import { z as z19 } from "zod";
8464
+ import { z as z21 } from "zod";
6897
8465
  var SITE_LINK_FILE = ".fling-site.json";
6898
8466
  var DOWNLOAD_CONCURRENCY = 8;
6899
8467
  var DOWNLOAD_RETRIES = 3;
6900
- var SiteLinkSchema = z19.object({
8468
+ var SiteLinkSchema = z21.object({
6901
8469
  /** the Fling it was pulled from */
6902
- server: z19.string(),
6903
- name: z19.string(),
8470
+ server: z21.string(),
8471
+ name: z21.string(),
6904
8472
  /** the version pulled, or the one the last deploy made */
6905
- versionId: z19.string(),
8473
+ versionId: z21.string(),
6906
8474
  /** a pull of one of the site's Paths (its folder): the folder is that Path */
6907
- path: z19.string().optional(),
8475
+ path: z21.string().optional(),
6908
8476
  /** every file pulled (or deployed), by site path: its SHA-256 */
6909
- files: z19.record(z19.string(), z19.string()),
8477
+ files: z21.record(z21.string(), z21.string()),
6910
8478
  /** the SHA-256 of the fling.forms.json pulled (or deployed); absent when the version had none */
6911
- forms: z19.string().optional()
8479
+ forms: z21.string().optional()
6912
8480
  });
6913
8481
  async function readSiteLink(dir) {
6914
8482
  let raw;
@@ -6951,11 +8519,11 @@ var linkAfter = (link, versionId, local, forms2) => {
6951
8519
  const { forms: _was, ...rest } = link;
6952
8520
  return { ...rest, versionId, files: siteFiles(link, local), ...forms2 ? { forms: forms2 } : {} };
6953
8521
  };
6954
- function describeChanges(c) {
8522
+ function describeChanges(c2) {
6955
8523
  const parts = [
6956
- c.changed.length ? `${c.changed.length} changed` : "",
6957
- c.added.length ? `${c.added.length} added` : "",
6958
- c.removed.length ? `${c.removed.length} removed` : ""
8524
+ c2.changed.length ? `${c2.changed.length} changed` : "",
8525
+ c2.added.length ? `${c2.added.length} added` : "",
8526
+ c2.removed.length ? `${c2.removed.length} removed` : ""
6959
8527
  ].filter(Boolean);
6960
8528
  return parts.length ? parts.join(", ") : "no changes";
6961
8529
  }
@@ -7413,7 +8981,7 @@ var manifest_default = {
7413
8981
  manifest_version: "0.3",
7414
8982
  name: "fling",
7415
8983
  display_name: "Fling",
7416
- version: "0.10.1",
8984
+ version: "0.11.0",
7417
8985
  description: "Publish HTML pages, zips and folders from your computer to Fling and get a link back.",
7418
8986
  long_description: "Fling hosts static sites at https://<name>.<your sites domain> (private to people signed in to your Fling unless you make them public or share a link).\n\nThis extension runs on your computer, so Claude can publish:\n\n- content it created in the conversation (sent inline \u2014 no sandbox uploads),\n- a file you downloaded or Claude Desktop saved, by name: it looks in Downloads, Desktop, Documents/Claude and Claude Desktop's output folders,\n- a single .html file, a .zip of a site, or a folder with index.html.\n\nIt works with every Fling you sign in to: the one you downloaded it from is added on start, Claude can sign in to another with the fling_login tool, and the logins are shared with the fling CLI (`fling login <address>`). When several Flings are set up, Claude settles with you which one a conversation uses and names it on every call.",
7419
8987
  author: {
@@ -7658,23 +9226,23 @@ function parseSemver(input) {
7658
9226
  if (!m) return null;
7659
9227
  return { core: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ? m[4].split(".") : [] };
7660
9228
  }
7661
- function compareSemver(a, b) {
9229
+ function compareSemver(a3, b) {
7662
9230
  for (let i = 0; i < 3; i++) {
7663
- const d = (a.core[i] ?? 0) - (b.core[i] ?? 0);
9231
+ const d = (a3.core[i] ?? 0) - (b.core[i] ?? 0);
7664
9232
  if (d !== 0) return d;
7665
9233
  }
7666
- if (!a.pre.length || !b.pre.length) return b.pre.length - a.pre.length;
7667
- for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {
7668
- const x = a.pre[i];
9234
+ if (!a3.pre.length || !b.pre.length) return b.pre.length - a3.pre.length;
9235
+ for (let i = 0; i < Math.max(a3.pre.length, b.pre.length); i++) {
9236
+ const x2 = a3.pre[i];
7669
9237
  const y = b.pre[i];
7670
- if (x === void 0) return -1;
9238
+ if (x2 === void 0) return -1;
7671
9239
  if (y === void 0) return 1;
7672
- if (x === y) continue;
7673
- const xn = /^\d+$/.test(x);
9240
+ if (x2 === y) continue;
9241
+ const xn = /^\d+$/.test(x2);
7674
9242
  const yn = /^\d+$/.test(y);
7675
- if (xn && yn) return Number(x) - Number(y);
9243
+ if (xn && yn) return Number(x2) - Number(y);
7676
9244
  if (xn !== yn) return xn ? -1 : 1;
7677
- return x < y ? -1 : 1;
9245
+ return x2 < y ? -1 : 1;
7678
9246
  }
7679
9247
  return 0;
7680
9248
  }
@@ -7755,7 +9323,7 @@ async function runChecks(deps) {
7755
9323
  ]);
7756
9324
  return groups2.flat();
7757
9325
  }
7758
- var doctorExitCode = (checks) => checks.some((c) => c.status === "problem") ? 1 : 0;
9326
+ var doctorExitCode = (checks) => checks.some((c2) => c2.status === "problem") ? 1 : 0;
7759
9327
  function systemDoctorDeps(store, fetch2, runClaude2, findClaudeDesktop2) {
7760
9328
  const { env, home, platform } = systemLocateOptions();
7761
9329
  return {
@@ -7780,7 +9348,7 @@ function systemDoctorDeps(store, fetch2, runClaude2, findClaudeDesktop2) {
7780
9348
  }
7781
9349
  var SYMBOL = { ok: "\u2714", warning: "\u25B2", problem: "\u2716" };
7782
9350
  function describeChecks(checks) {
7783
- return checks.map((c) => `${SYMBOL[c.status]} ${c.message}${c.fix ? ` \u2014 fix: ${c.fix}` : ""}`).join("\n");
9351
+ return checks.map((c2) => `${SYMBOL[c2.status]} ${c2.message}${c2.fix ? ` \u2014 fix: ${c2.fix}` : ""}`).join("\n");
7784
9352
  }
7785
9353
  async function cliChecks(d) {
7786
9354
  const checks = [
@@ -7967,7 +9535,7 @@ async function serverChecks(d) {
7967
9535
  return perServer.flat();
7968
9536
  }
7969
9537
  async function oneServer(d, url, label, apiKey) {
7970
- const at = (id, check2) => ({
9538
+ const at2 = (id, check2) => ({
7971
9539
  area: "server",
7972
9540
  id,
7973
9541
  server: url,
@@ -7978,7 +9546,7 @@ async function oneServer(d, url, label, apiKey) {
7978
9546
  instance = await fetchInstance(url, d.fetch);
7979
9547
  } catch (error) {
7980
9548
  return [
7981
- at("server.metadata", {
9549
+ at2("server.metadata", {
7982
9550
  status: "problem",
7983
9551
  message: `${label}: ${error.message}`,
7984
9552
  fix: `Check the address and your connection; if the Fling moved: ${BIN_NAME} login <its new address>`
@@ -7986,15 +9554,15 @@ async function oneServer(d, url, label, apiKey) {
7986
9554
  ];
7987
9555
  }
7988
9556
  const checks = [
7989
- at("server.metadata", { status: "ok", message: `${label}: ${instance.name} answers` })
9557
+ at2("server.metadata", { status: "ok", message: `${label}: ${instance.name} answers` })
7990
9558
  ];
7991
9559
  const newer = newerRelease(instance.release, d.version);
7992
9560
  checks.push(
7993
- newer ? at("server.release", {
9561
+ newer ? at2("server.release", {
7994
9562
  status: "warning",
7995
9563
  message: `${label} runs Fling ${newer}, newer than this CLI (${d.version})`,
7996
9564
  fix: UPDATE_COMMAND
7997
- }) : at("server.release", {
9565
+ }) : at2("server.release", {
7998
9566
  status: "ok",
7999
9567
  message: instance.release ? `${label} runs Fling ${instance.release}` : `${label} does not say which release it runs`
8000
9568
  })
@@ -8002,7 +9570,7 @@ async function oneServer(d, url, label, apiKey) {
8002
9570
  const login = `${BIN_NAME} login ${url}`;
8003
9571
  if (!apiKey) {
8004
9572
  checks.push(
8005
- at("server.signedIn", { status: "problem", message: `${label}: not signed in`, fix: login })
9573
+ at2("server.signedIn", { status: "problem", message: `${label}: not signed in`, fix: login })
8006
9574
  );
8007
9575
  } else {
8008
9576
  try {
@@ -8014,18 +9582,18 @@ async function oneServer(d, url, label, apiKey) {
8014
9582
  });
8015
9583
  const me = await client.request("GET", "/api/me");
8016
9584
  checks.push(
8017
- at("server.signedIn", {
9585
+ at2("server.signedIn", {
8018
9586
  status: "ok",
8019
9587
  message: `${label}: signed in${me?.email ? ` as ${me.email}` : ""}`
8020
9588
  })
8021
9589
  );
8022
9590
  } catch (error) {
8023
9591
  checks.push(
8024
- exitCodeFor(error) === 2 ? at("server.signedIn", {
9592
+ exitCodeFor(error) === 2 ? at2("server.signedIn", {
8025
9593
  status: "problem",
8026
9594
  message: `${label}: the API key is not accepted`,
8027
9595
  fix: login
8028
- }) : at("server.signedIn", {
9596
+ }) : at2("server.signedIn", {
8029
9597
  status: "warning",
8030
9598
  message: `${label}: could not check the sign-in (${error.message})`,
8031
9599
  fix: `${BIN_NAME} whoami --server ${url}`
@@ -8035,7 +9603,7 @@ async function oneServer(d, url, label, apiKey) {
8035
9603
  }
8036
9604
  const on = Object.entries(instance.capabilities).filter(([, v]) => v === true).map(([k]) => k).sort();
8037
9605
  checks.push(
8038
- at("server.capabilities", {
9606
+ at2("server.capabilities", {
8039
9607
  status: "ok",
8040
9608
  message: `${label}: ${on.length ? on.join(", ") : "no optional features"}`
8041
9609
  })
@@ -8118,21 +9686,21 @@ async function claudeDesktopChecks(d) {
8118
9686
  if (!app) return [];
8119
9687
  const dataDir = claudeDesktopDataDir(d.platform, d.env, d.home);
8120
9688
  const ext = dataDir ? await desktopExtensionStatus(dataDir) : null;
8121
- const at = (check2) => ({
9689
+ const at2 = (check2) => ({
8122
9690
  area: "claudeDesktop",
8123
9691
  id: "claudeDesktop.extension",
8124
9692
  ...check2
8125
9693
  });
8126
9694
  if (!ext)
8127
9695
  return [
8128
- at({
9696
+ at2({
8129
9697
  status: "ok",
8130
9698
  message: `Claude Desktop is installed (${app}); the extension could not be looked up`
8131
9699
  })
8132
9700
  ];
8133
9701
  if (!ext.installed)
8134
9702
  return [
8135
- at({
9703
+ at2({
8136
9704
  status: "warning",
8137
9705
  message: "The Fling extension is not installed in Claude Desktop",
8138
9706
  fix: `${BIN_NAME} setup (it opens fling.mcpb in Claude Desktop)`
@@ -8149,11 +9717,11 @@ async function claudeDesktopChecks(d) {
8149
9717
  });
8150
9718
  const behind = ext.version ? newerRelease(d.version, ext.version) : null;
8151
9719
  checks.push(
8152
- behind ? at({
9720
+ behind ? at2({
8153
9721
  status: "warning",
8154
9722
  message: `The Claude Desktop extension is ${ext.version}, older than this CLI (${d.version})`,
8155
9723
  fix: `${BIN_NAME} setup`
8156
- }) : at({
9724
+ }) : at2({
8157
9725
  status: "ok",
8158
9726
  message: `The Claude Desktop extension is installed${ext.version ? ` (${ext.version})` : ""} (${DESKTOP_EXTENSION_ID})`
8159
9727
  })
@@ -8182,13 +9750,13 @@ async function runDoctor(ctx, deps) {
8182
9750
  function render(checks) {
8183
9751
  const lines = [];
8184
9752
  let area;
8185
- for (const c of checks) {
8186
- if (c.area !== area) {
8187
- area = c.area;
8188
- lines.push(`${lines.length ? "\n" : ""}${chalk8.bold(AREAS[c.area])}`);
9753
+ for (const c2 of checks) {
9754
+ if (c2.area !== area) {
9755
+ area = c2.area;
9756
+ lines.push(`${lines.length ? "\n" : ""}${chalk8.bold(AREAS[c2.area])}`);
8189
9757
  }
8190
- const message = c.status === "problem" ? chalk8.red(c.message) : c.message;
8191
- lines.push(`${SYMBOLS[c.status]} ${message}${c.fix ? chalk8.dim(` \u2014 fix: ${c.fix}`) : ""}`);
9758
+ const message = c2.status === "problem" ? chalk8.red(c2.message) : c2.message;
9759
+ lines.push(`${SYMBOLS[c2.status]} ${message}${c2.fix ? chalk8.dim(` \u2014 fix: ${c2.fix}`) : ""}`);
8192
9760
  }
8193
9761
  return lines.join("\n");
8194
9762
  }
@@ -8618,7 +10186,7 @@ async function runPathsCheck(ctx, path3) {
8618
10186
  });
8619
10187
  }
8620
10188
  const check2 = checkPathsIndex(html);
8621
- for (const w of check2.warnings) ctx.log.warn(w);
10189
+ for (const w2 of check2.warnings) ctx.log.warn(w2);
8622
10190
  if (!check2.ok) {
8623
10191
  if (ctx.json) ctx.out.data({ path: file, ...check2 }, () => "");
8624
10192
  throw new CliError(`${shown2(file)} has no Paths block:
@@ -8725,9 +10293,13 @@ async function runSetup(baseCtx, opts, deps = {}) {
8725
10293
  results.claudeCode = await stepClaudeCode(after, run, scope, ask, fancy);
8726
10294
  results.claudeDesktop = await stepClaudeDesktop(after, deps, ask, fancy);
8727
10295
  const failed = Object.values(results).includes("failed");
10296
+ const guide = instanceGuideUrl(
10297
+ login.serverUrl ? (await ctx.store.resolve({ serverUrl: login.serverUrl })).instance : void 0
10298
+ );
8728
10299
  if (fancy)
8729
10300
  outro(
8730
- failed ? chalk14.yellow("Setup finished with problems \u2014 see above, then run `fling setup` again.") : `You're set. Try ${chalk14.bold(`${ctx.binName} deploy ./dist`)}, or ask Claude to \u201Cfling this\u201D.`,
10301
+ failed ? chalk14.yellow("Setup finished with problems \u2014 see above, then run `fling setup` again.") : `You're set. Try ${chalk14.bold(`${ctx.binName} deploy ./dist`)}, or ask Claude to \u201Cfling this\u201D.${guide ? `
10302
+ How everything works: ${chalk14.underline(guide)}` : ""}`,
8731
10303
  { output: process.stderr }
8732
10304
  );
8733
10305
  ctx.out.data(results, () => "");
@@ -9076,7 +10648,7 @@ async function runAccess(ctx, name, opts) {
9076
10648
  const client = requireClient(ctx);
9077
10649
  const site = changesAudience(change) ? await setAudience(client, name, change) : await getAudience(client, name);
9078
10650
  const warnings = audienceWarnings(site);
9079
- for (const w of warnings) ctx.log.warn(w);
10651
+ for (const w2 of warnings) ctx.log.warn(w2);
9080
10652
  ctx.out.data({ ...site, warnings }, () => describeAudience(site, membersOf(ctx)));
9081
10653
  }
9082
10654
  async function runSetLevel(ctx, name, level, opts) {
@@ -9093,7 +10665,7 @@ async function runSetLevel(ctx, name, level, opts) {
9093
10665
  }
9094
10666
  const site = await setAccess(requireClient(ctx), name, level);
9095
10667
  const warnings = audienceWarnings(site);
9096
- for (const w of warnings) ctx.log.warn(w);
10668
+ for (const w2 of warnings) ctx.log.warn(w2);
9097
10669
  ctx.out.data({ ...site, warnings }, () => describeAudience(site, membersOf(ctx)));
9098
10670
  }
9099
10671
  async function runRoles(ctx, which, name, opts) {
@@ -9169,7 +10741,7 @@ import { tmpdir as tmpdir3 } from "node:os";
9169
10741
  import { basename as basename3, dirname as dirname4, join as join13, resolve as resolvePath } from "node:path";
9170
10742
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9171
10743
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9172
- import { z as z20 } from "zod";
10744
+ import { z as z22 } from "zod";
9173
10745
 
9174
10746
  // src/locate.ts
9175
10747
  import { lstat, readdir as readdir3, readFile as readFile12, realpath as realpath4, stat as stat9 } from "node:fs/promises";
@@ -9331,9 +10903,9 @@ function withoutDuplicateSuffix(name) {
9331
10903
  return name.replace(/ \(\d+\)(?=\.[^.]+$|$)/, "");
9332
10904
  }
9333
10905
  function namesMatch(candidate, wanted) {
9334
- const a = candidate.toLowerCase();
10906
+ const a3 = candidate.toLowerCase();
9335
10907
  const b = wanted.toLowerCase();
9336
- return a === b || withoutDuplicateSuffix(a) === withoutDuplicateSuffix(b);
10908
+ return a3 === b || withoutDuplicateSuffix(a3) === withoutDuplicateSuffix(b);
9337
10909
  }
9338
10910
  var splitSegments = (path3) => path3.split(/[\\/]+/).filter((s) => s !== "" && s !== "." && s !== "~");
9339
10911
  function suffixScore(path3, wanted) {
@@ -9397,8 +10969,8 @@ async function resolveInput(input, opts) {
9397
10969
  return void 0;
9398
10970
  });
9399
10971
  if (found.length === 0) throw notFound(input, roots);
9400
- found.sort((a, b) => b.score - a.score || b.mtimeMs - a.mtimeMs);
9401
- const strip = ({ score: _s, mtimeMs: _m, isDirectory: _d, ...c }) => c;
10972
+ found.sort((a3, b) => b.score - a3.score || b.mtimeMs - a3.mtimeMs);
10973
+ const strip = ({ score: _s, mtimeMs: _m, isDirectory: _d, ...c2 }) => c2;
9402
10974
  const [best, ...rest] = found;
9403
10975
  return {
9404
10976
  path: best.path,
@@ -9455,7 +11027,7 @@ async function findFiles(opts, find = {}) {
9455
11027
  });
9456
11028
  return void 0;
9457
11029
  });
9458
- const files = [...found.values()].sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, find.limit ?? 20).map(({ mtimeMs: _m, ...c }) => c);
11030
+ const files = [...found.values()].sort((a3, b) => b.mtimeMs - a3.mtimeMs).slice(0, find.limit ?? 20).map(({ mtimeMs: _m, ...c2 }) => c2);
9459
11031
  return { files, searched: roots, complete };
9460
11032
  }
9461
11033
 
@@ -9582,8 +11154,8 @@ ${listing(servers)}`,
9582
11154
  // src/mcp.ts
9583
11155
  var LOGIN_HINT = `Not logged in to Fling. Call fling_login (it opens the browser to sign in), or ask the user to run \`${NPX_COMMAND} login\` in a terminal (in Claude Code: \`! ${NPX_COMMAND} login\`), then try again.`;
9584
11156
  var NO_SERVER_HINT = `No Fling server is set up on this computer. Ask the user for their Fling's address, then call fling_login with it as \`server\` (or ask them to run \`${NPX_COMMAND} login <url>\` in a terminal; in Claude Code: \`! ${NPX_COMMAND} login <url>\`), then try again.`;
9585
- var mcpLocalInstructions = (w, opts = {}) => [
9586
- `${w.name} publishes static sites (HTML/CSS/JS, images, documents) at ${w.sitesPattern}. This server runs on the user's computer.`,
11157
+ var mcpLocalInstructions = (w2, opts = {}) => [
11158
+ `${w2.name} publishes static sites (HTML/CSS/JS, images, documents) at ${w2.sitesPattern}. This server runs on the user's computer.`,
9587
11159
  ...opts.newerRelease ? [mcpUpdateNote(opts.newerRelease)] : [],
9588
11160
  ...[serversInstructions(opts.servers ?? [])].filter((p) => p !== void 0),
9589
11161
  "Content you created in this conversation (an HTML page, a report, a small app): call fling_publish with every file inline (text as utf8, binary as base64). Never pass file paths from your sandbox (e.g. /mnt/user-data/outputs/\u2026, /sessions/\u2026) \u2014 this computer cannot see them \u2014 and never curl or upload from the sandbox.",
@@ -9593,12 +11165,13 @@ var mcpLocalInstructions = (w, opts = {}) => [
9593
11165
  "When there is no index.html but there are HTML pages, fling_deploy and fling_publish do not publish: ask the user whether to generate an index page listing the pages (`listHtml: true`) or publish without one (`listHtml: false`, the root URL 404s), then retry.",
9594
11166
  NEVER_PUBLISHED,
9595
11167
  "Not logged in? Call fling_login, let the user finish signing in in the browser, then retry.",
9596
- `${ACCESS_NOTE(w)} Use fling_share for a link people who cannot sign in can open. ${opts.comments ? "Always give the user the links that come back: the review link first, as the one to share for feedback, then the site URL." : "Always give the user the URL that comes back."}`,
9597
- ...opts.comments ? [COMMENTS_NOTE(w, { forms: opts.forms })] : [],
11168
+ `${ACCESS_NOTE(w2)} Use fling_share for a link people who cannot sign in can open. ${opts.comments ? "Always give the user the links that come back: the review link first, as the one to share for feedback, then the site URL." : "Always give the user the URL that comes back."}`,
11169
+ ...opts.comments ? [COMMENTS_NOTE(w2, { forms: opts.forms })] : [],
9598
11170
  ...opts.comments && opts.forms ? [
9599
- `${FORMS_NOTE(w)} A folder deployed with fling_deploy takes its forms from a ${FORMS_FILE} at its top.`
11171
+ `${FORMS_NOTE(w2)} A folder deployed with fling_deploy takes its forms from a ${FORMS_FILE} at its top.`
9600
11172
  ] : [],
9601
- ...opts.notifications ? [NOTIFICATIONS_NOTE(w)] : []
11173
+ ...opts.notifications ? [NOTIFICATIONS_NOTE(w2)] : [],
11174
+ ...[GUIDE_NOTE(w2)].filter((p) => p !== void 0)
9602
11175
  ].join("\n\n");
9603
11176
  var PUBLISHING_TOOLS = /* @__PURE__ */ new Set(["fling_publish", "fling_deploy"]);
9604
11177
  function newestRelease(servers) {
@@ -9620,7 +11193,7 @@ function createMcpServer(deps = {}) {
9620
11193
  const several = servers.length > 1;
9621
11194
  const wording = mcpWording(several ? null : servers[0]?.instance);
9622
11195
  const mcpTools2 = mcpToolsFor(wording);
9623
- const serverArg = z20.string().min(1).max(500).optional().describe(serverArgDescription(servers));
11196
+ const serverArg = z22.string().min(1).max(500).optional().describe(serverArgDescription(servers));
9624
11197
  const note = serverToolNote(servers);
9625
11198
  const serverTool = (def, description = def.description) => ({
9626
11199
  title: def.title,
@@ -9930,13 +11503,13 @@ ${formsHint2}` : ""),
9930
11503
  title: "Deploy a file or folder from this computer",
9931
11504
  description: `Fling something that is on the user's computer and return its stable URL (${wording.sitesPattern}): a folder of static files (e.g. a build output like dist/), a single .html file (served as the site's index.html), a .zip of a site (extracted; a single top-level folder is unwrapped), or any other single file (.pdf, .svg, .png\u2026, served next to a generated page that shows it). \`path\` can be absolute, relative to the working directory, or just a file name ("Pitch Deck.html"): names are looked up, newest first, in Downloads, Desktop, Documents/Claude and Claude Desktop output folders, and the result says where the file was found. Never pass paths from your own sandbox (/mnt/user-data/\u2026, /sessions/\u2026): for content you created, use fling_publish. Without \`name\`, a name is generated: from the file name for files ("Pitch Deck (1).html" \u2192 pitch-deck), from the project and folder for folders (~/work/rocketpod/docs \u2192 rocketpod-docs). Site names are one global namespace, first come first served \u2014 confirm the name with the user first (fling_check_name with \`path\` shows the generated one). If the name is taken it fails with free suggestions \u2014 ask the user to pick one, then retry with \`name\`. If there is no index.html but there are HTML pages, it does not deploy: ask the user whether to generate an index page listing them (\`listHtml: true\`) or deploy without one (\`listHtml: false\`), then retry. Re-deploying identical content is a no-op. ${ACCESS_NOTE(wording)} ${PATH_PUBLISH_NOTE.replace("With `path`", "With `sitePath`")} A folder made by fling_pull publishes to the site and Fling it was pulled from, on the version pulled: only what changed is sent, and if someone published the site since, it stops (base_changed) rather than replace their work; \`force: true\` replaces it anyway (only when the user says so). A ${FORMS_FILE} at the top of the folder is never published: it is the site's forms, for structured feedback (labels, ratings, scores, eval judgements) on the review page; \`forms\` passes one inline instead (fling_forms_template). ${NEVER_PUBLISHED}${note}`,
9932
11505
  inputSchema: {
9933
- path: z20.string().min(1).describe(
11506
+ path: z22.string().min(1).describe(
9934
11507
  "File or folder on this computer: absolute, relative to the working directory, or just its name (looked up in Downloads, Desktop and Claude output folders)"
9935
11508
  ),
9936
- name: z20.string().optional().describe(
11509
+ name: z22.string().optional().describe(
9937
11510
  "Site name (lowercase letters, digits, single hyphens; max 50). Defaults to a name generated from the file or folder"
9938
11511
  ),
9939
- sitePath: z20.string().min(1).max(1024).optional().describe(
11512
+ sitePath: z22.string().min(1).max(1024).optional().describe(
9940
11513
  'Publish as the Path at this top-level folder of the site, e.g. "PAY-412" (served at <site>/PAY-412/); the rest of the site is untouched. Needs `name`. Omit to publish the site itself'
9941
11514
  ),
9942
11515
  spa: spa2,
@@ -9945,7 +11518,7 @@ ${formsHint2}` : ""),
9945
11518
  groups: groups2,
9946
11519
  public: isPublic,
9947
11520
  listHtml: listHtml2,
9948
- force: z20.boolean().optional().describe(
11521
+ force: z22.boolean().optional().describe(
9949
11522
  "A folder made by fling_pull: publish it without a base, replacing whatever is live even if someone published since. Only when the user says so"
9950
11523
  ),
9951
11524
  forms: formsArg.describe(
@@ -10011,15 +11584,15 @@ ${formsHint2}` : ""),
10011
11584
  title: "Download a site's files to change them",
10012
11585
  description: `Download a site's files into a folder on this computer, to change some or all of them and publish again: by default ~/Documents/Claude/fling/<name>. Then edit the files there and call fling_deploy with the folder: it publishes on the version pulled, sending only what changed. Anyone who can open the site may pull it; publishing needs an owner or publisher. \`path\` pulls one folder of the site (its files at the top of the folder); deploying it keeps the rest of the site. If the folder is not empty it stops, unless \`force\` (it then writes over what is there). When fling_deploy says base_changed, someone published in between: pull again into another folder and redo the changes there.` + note,
10013
11586
  inputSchema: {
10014
- name: z20.string().min(1).max(200).describe("Site name"),
10015
- dir: z20.string().min(1).optional().describe(
11587
+ name: z22.string().min(1).max(200).describe("Site name"),
11588
+ dir: z22.string().min(1).optional().describe(
10016
11589
  "Folder to write the files to (absolute, or relative to the working directory). Default ~/Documents/Claude/fling/<name>"
10017
11590
  ),
10018
- versionId: z20.string().min(1).max(100).optional().describe(
11591
+ versionId: z22.string().min(1).max(100).optional().describe(
10019
11592
  "Another version than the live one (owners and publishers; ids from fling_info)"
10020
11593
  ),
10021
- path: z20.string().min(1).max(1024).optional().describe('Only this Path of the site, e.g. "PAY-412"'),
10022
- force: z20.boolean().optional().describe("Write into the folder even if it is not empty"),
11594
+ path: z22.string().min(1).max(1024).optional().describe('Only this Path of the site, e.g. "PAY-412"'),
11595
+ force: z22.boolean().optional().describe("Write into the folder even if it is not empty"),
10023
11596
  server: serverArg
10024
11597
  },
10025
11598
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
@@ -10079,7 +11652,7 @@ ${formsHint2}` : ""),
10079
11652
  const files = [
10080
11653
  ...read,
10081
11654
  ...tooLarge.map(({ url: _url, ...f }) => ({ ...f, tooLarge: true }))
10082
- ].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
11655
+ ].sort((a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0);
10083
11656
  const result = {
10084
11657
  name: args.name,
10085
11658
  versionId: pulled.versionId,
@@ -10097,9 +11670,9 @@ ${formsHint2}` : ""),
10097
11670
  title: "Find files to fling",
10098
11671
  description: "List recent things on this computer that could be flung, newest first: .html/.htm and .zip files, and folders containing an index.html, from the working directory, Downloads, Desktop, Documents/Claude, ~/Claude and Claude Desktop output folders. Each has its path, where it was found, size and modified time. Use it when the user refers to a file they downloaded or that Claude Desktop saved, then pass the chosen path (or name) to fling_deploy.",
10099
11672
  inputSchema: {
10100
- query: z20.string().optional().describe('Only names containing this text (case-insensitive), e.g. "deck"'),
10101
- limit: z20.number().int().min(1).max(100).optional().describe("Max results (default 20)"),
10102
- days: z20.number().int().min(1).max(3650).optional().describe("Only things modified in the last N days (default 14)")
11673
+ query: z22.string().optional().describe('Only names containing this text (case-insensitive), e.g. "deck"'),
11674
+ limit: z22.number().int().min(1).max(100).optional().describe("Max results (default 20)"),
11675
+ days: z22.number().int().min(1).max(3650).optional().describe("Only things modified in the last N days (default 14)")
10103
11676
  },
10104
11677
  annotations: { readOnlyHint: true, openWorldHint: false }
10105
11678
  },
@@ -10171,8 +11744,8 @@ ${JSON.stringify(data, null, 2)}`);
10171
11744
  ...serverTool(mcpTools2.checkName),
10172
11745
  description: `${mcpTools2.checkName.description} Pass \`path\` instead of \`name\` to see the name fling_deploy would generate for a file or folder on this computer (same lookup as fling_deploy), so you can confirm it with the user.${note}`,
10173
11746
  inputSchema: {
10174
- name: z20.string().min(1).max(200).optional().describe("Site name to check"),
10175
- path: z20.string().optional().describe("File or folder whose generated default name to check (path or file name)"),
11747
+ name: z22.string().min(1).max(200).optional().describe("Site name to check"),
11748
+ path: z22.string().optional().describe("File or folder whose generated default name to check (path or file name)"),
10176
11749
  server: serverArg
10177
11750
  }
10178
11751
  },
@@ -10213,7 +11786,7 @@ ${JSON.stringify(data, null, 2)}`);
10213
11786
  title: "Sign in to Fling",
10214
11787
  description: `Sign the user in to ${several ? "a Fling" : wording.name}: opens their browser to sign in with ${wording.signIn} and stores the key on this computer (shared with the fling CLI). Waits up to ~30 seconds; if sign-in is not finished by then, it keeps waiting in the background for up to 5 minutes \u2014 tell the user to finish signing in in the browser, then retry what you were doing. Call it when another tool says the user is not logged in. Pass \`server\` (its address) to sign in to another Fling, including one not set up on this computer yet: it is remembered, and becomes the current one only when none is.` + note,
10215
11788
  inputSchema: {
10216
- server: z20.string().min(1).max(500).optional().describe(
11789
+ server: z22.string().min(1).max(500).optional().describe(
10217
11790
  `The Fling to sign in to: its address (e.g. "https://fling.example.com"), or the host of one set up on this computer. ${several ? `Required while several Flings are set up (${servers.map((s) => serverLabel(s.url)).join(", ")})` : `Omit it to use ${servers[0] ? serverLabel(servers[0].url) : "the one this computer knows"}`}`
10218
11791
  )
10219
11792
  },
@@ -10320,7 +11893,7 @@ ${JSON.stringify({ ok, checks }, null, 2)}`);
10320
11893
  title: "List the Flings on this computer",
10321
11894
  description: `List the Flings set up on this computer, read now: each one's address, name, who is signed in (or "signed out") and which is current, the user's usual one. Call it when unsure which Fling the user means or which exist; the list may have changed since this conversation started. Pass \`use\` to make one the current Fling, the same as running \`${NPX_COMMAND} use <server>\`: it changes the default of the fling CLI too, so only do it when the user asks. It does not replace passing \`server\` to the other tools while several Flings are set up.`,
10322
11895
  inputSchema: {
10323
- use: z20.string().min(1).max(500).optional().describe(
11896
+ use: z22.string().min(1).max(500).optional().describe(
10324
11897
  "Make this Fling current (address, host or unique part of it), like `fling use`"
10325
11898
  )
10326
11899
  },