yamlover 0.3.49 → 0.3.50

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 (38) hide show
  1. package/README.md +2 -2
  2. package/bin/ga4.js +14 -1
  3. package/dist/agent-docs/AGENTS.md +10 -10
  4. package/dist/builtin-taxonomy/$defs/.yo/meta.yo +18 -23
  5. package/dist/builtin-taxonomy/$defs/annotation +6 -6
  6. package/dist/builtin-taxonomy/$defs/board +4 -4
  7. package/dist/builtin-taxonomy/$defs/bullets +2 -2
  8. package/dist/builtin-taxonomy/$defs/chapter +6 -7
  9. package/dist/builtin-taxonomy/$defs/chunk +4 -3
  10. package/dist/builtin-taxonomy/$defs/config +5 -5
  11. package/dist/builtin-taxonomy/$defs/fragment +2 -2
  12. package/dist/builtin-taxonomy/$defs/numbered +2 -2
  13. package/dist/builtin-taxonomy/$defs/{tag → onto} +6 -6
  14. package/dist/builtin-taxonomy/$defs/table +13 -12
  15. package/dist/builtin-taxonomy/$defs/task +6 -6
  16. package/dist/builtin-taxonomy/$defs/workflow +4 -4
  17. package/dist/builtin-taxonomy/ontos/.yo/body.yo +46 -0
  18. package/dist/client/assets/{decoded-D_YQdg1-.js → decoded-5u9KK4Nb.js} +1 -1
  19. package/dist/client/assets/{djvu-Di4fPA-J.js → djvu-CvRKxWcX.js} +1 -1
  20. package/dist/client/assets/{docx-BSduN32X.js → docx-CFqmrRMY.js} +1 -1
  21. package/dist/client/assets/{heic-DOAG7EsW.js → heic-P0RPecFK.js} +1 -1
  22. package/dist/client/assets/{imagemap-B8RthxNE.js → imagemap-BCrt0kPn.js} +1 -1
  23. package/dist/client/assets/index-_gAtxDG4.css +1 -0
  24. package/dist/client/assets/index-l1SxxFJR.js +754 -0
  25. package/dist/client/assets/{map-Cf7ar1_U.js → map-ClMfiQr8.js} +1 -1
  26. package/dist/client/assets/{openable-CCBlc-Ws.js → openable-9ABNW3A9.js} +1 -1
  27. package/dist/client/assets/{paged-bLurvatj.js → paged-UVifI3SC.js} +1 -1
  28. package/dist/client/assets/{pdf-D1ox8M9A.js → pdf-BGgu5LFZ.js} +1 -1
  29. package/dist/client/assets/{psd-AT50x-YR.js → psd-D15IXPVu.js} +1 -1
  30. package/dist/client/assets/{spreadsheet-DeQh5CNF.js → spreadsheet-CeOcWWb2.js} +1 -1
  31. package/dist/client/assets/{tiff-B3-awhzQ.js → tiff-pZPBtPPg.js} +1 -1
  32. package/dist/client/assets/{xyflow-DuQ4jjaq.js → xyflow-uN1JIC1A.js} +1 -1
  33. package/dist/client/index.html +2 -2
  34. package/dist/server.js +1420 -425
  35. package/package.json +1 -1
  36. package/dist/builtin-taxonomy/tags/.yo/body.yo +0 -46
  37. package/dist/client/assets/index-Bf2L7I9e.js +0 -752
  38. package/dist/client/assets/index-N41EyNG2.css +0 -1
package/dist/server.js CHANGED
@@ -5760,14 +5760,14 @@ var require_gifutil = __commonJS({
5760
5760
  jimpImage.bitmap.data = bitmapImageToShare.bitmap.data;
5761
5761
  return jimpImage;
5762
5762
  };
5763
- exports.write = function(path11, frames, spec, encoder) {
5763
+ exports.write = function(path12, frames, spec, encoder) {
5764
5764
  encoder = encoder || defaultCodec;
5765
- const matches = path11.match(/\.[a-zA-Z]+$/);
5765
+ const matches = path12.match(/\.[a-zA-Z]+$/);
5766
5766
  if (matches !== null && INVALID_SUFFIXES.includes(matches[0].toLowerCase())) {
5767
- throw new Error(`GIF '${path11}' has an unexpected suffix`);
5767
+ throw new Error(`GIF '${path12}' has an unexpected suffix`);
5768
5768
  }
5769
5769
  return encoder.encodeGif(frames, spec).then((gif2) => {
5770
- return _writeBinary(path11, gif2.buffer).then(() => {
5770
+ return _writeBinary(path12, gif2.buffer).then(() => {
5771
5771
  return gif2;
5772
5772
  });
5773
5773
  });
@@ -5839,9 +5839,9 @@ var require_gifutil = __commonJS({
5839
5839
  }
5840
5840
  }
5841
5841
  }
5842
- function _readBinary(path11) {
5842
+ function _readBinary(path12) {
5843
5843
  return new Promise((resolve3, reject) => {
5844
- fs11.readFile(path11, (err, buffer) => {
5844
+ fs11.readFile(path12, (err, buffer) => {
5845
5845
  if (err) {
5846
5846
  return reject(err);
5847
5847
  }
@@ -5849,9 +5849,9 @@ var require_gifutil = __commonJS({
5849
5849
  });
5850
5850
  });
5851
5851
  }
5852
- function _writeBinary(path11, buffer) {
5852
+ function _writeBinary(path12, buffer) {
5853
5853
  return new Promise((resolve3, reject) => {
5854
- fs11.writeFile(path11, buffer, (err) => {
5854
+ fs11.writeFile(path12, buffer, (err) => {
5855
5855
  if (err) {
5856
5856
  return reject(err);
5857
5857
  }
@@ -7861,9 +7861,9 @@ var require_decoder = __commonJS({
7861
7861
  return a2 < 0 ? 0 : a2 > 255 ? 255 : a2;
7862
7862
  }
7863
7863
  constructor.prototype = {
7864
- load: function load(path11) {
7864
+ load: function load(path12) {
7865
7865
  var xhr = new XMLHttpRequest();
7866
- xhr.open("GET", path11, true);
7866
+ xhr.open("GET", path12, true);
7867
7867
  xhr.responseType = "arraybuffer";
7868
7868
  xhr.onload = function() {
7869
7869
  var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
@@ -18725,8 +18725,8 @@ var init_parseUtil = __esm({
18725
18725
  init_errors();
18726
18726
  init_en();
18727
18727
  makeIssue = (params) => {
18728
- const { data, path: path11, errorMaps, issueData } = params;
18729
- const fullPath = [...path11, ...issueData.path || []];
18728
+ const { data, path: path12, errorMaps, issueData } = params;
18729
+ const fullPath = [...path12, ...issueData.path || []];
18730
18730
  const fullIssue = {
18731
18731
  ...issueData,
18732
18732
  path: fullPath
@@ -19034,11 +19034,11 @@ var init_types2 = __esm({
19034
19034
  init_parseUtil();
19035
19035
  init_util();
19036
19036
  ParseInputLazyPath = class {
19037
- constructor(parent, value, path11, key) {
19037
+ constructor(parent, value, path12, key) {
19038
19038
  this._cachedPath = [];
19039
19039
  this.parent = parent;
19040
19040
  this.data = value;
19041
- this._path = path11;
19041
+ this._path = path12;
19042
19042
  this._key = key;
19043
19043
  }
19044
19044
  get path() {
@@ -24036,11 +24036,11 @@ var require_Mime = __commonJS({
24036
24036
  }
24037
24037
  }
24038
24038
  };
24039
- Mime.prototype.getType = function(path11) {
24040
- path11 = String(path11);
24041
- let last = path11.replace(/^.*[/\\]/, "").toLowerCase();
24039
+ Mime.prototype.getType = function(path12) {
24040
+ path12 = String(path12);
24041
+ let last = path12.replace(/^.*[/\\]/, "").toLowerCase();
24042
24042
  let ext = last.replace(/^.*\./, "").toLowerCase();
24043
- let hasPath = last.length < path11.length;
24043
+ let hasPath = last.length < path12.length;
24044
24044
  let hasDot = ext.length < last.length - 1;
24045
24045
  return (hasDot || !hasPath) && this._types[ext] || null;
24046
24046
  };
@@ -30577,8 +30577,8 @@ function isTokenizerStreamBoundsError(error) {
30577
30577
  }
30578
30578
  return /strtok3[/\\]lib[/\\]stream[/\\]/.test(error.stack);
30579
30579
  }
30580
- async function fileTypeFromFile(path11, options) {
30581
- return new FileTypeParser2(options).fromFile(path11, options);
30580
+ async function fileTypeFromFile(path12, options) {
30581
+ return new FileTypeParser2(options).fromFile(path12, options);
30582
30582
  }
30583
30583
  async function fileTypeFromStream(stream, options) {
30584
30584
  return new FileTypeParser2(options).fromStream(stream);
@@ -30609,9 +30609,9 @@ var init_file_type = __esm({
30609
30609
  }
30610
30610
  }
30611
30611
  }
30612
- async fromFile(path11) {
30612
+ async fromFile(path12) {
30613
30613
  this.options.signal?.throwIfAborted();
30614
- const fileHandle = await fs7.open(path11, fileSystemConstants.O_RDONLY | fileSystemConstants.O_NONBLOCK);
30614
+ const fileHandle = await fs7.open(path12, fileSystemConstants.O_RDONLY | fileSystemConstants.O_NONBLOCK);
30615
30615
  const fileStat = await fileHandle.stat();
30616
30616
  if (!fileStat.isFile()) {
30617
30617
  await fileHandle.close();
@@ -30620,7 +30620,7 @@ var init_file_type = __esm({
30620
30620
  const tokenizer = new FileTokenizer(fileHandle, {
30621
30621
  ...this.getTokenizerOptions(),
30622
30622
  fileInfo: {
30623
- path: path11,
30623
+ path: path12,
30624
30624
  size: fileStat.size
30625
30625
  }
30626
30626
  });
@@ -30955,9 +30955,9 @@ function createJimp({ plugins: pluginsArg, formats: formatsArg } = {}) {
30955
30955
  * await image.write("test/output.png");
30956
30956
  * ```
30957
30957
  */
30958
- async write(path11, options) {
30959
- const mimeType = import_lite.default.getType(path11);
30960
- await writeFile(path11, await this.getBuffer(mimeType, options));
30958
+ async write(path12, options) {
30959
+ const mimeType = import_lite.default.getType(path12);
30960
+ await writeFile(path12, await this.getBuffer(mimeType, options));
30961
30961
  }
30962
30962
  /**
30963
30963
  * Clone the image into a new Jimp instance.
@@ -42379,7 +42379,7 @@ var init_simpleXmlToJson_min = __esm({
42379
42379
  });
42380
42380
 
42381
42381
  // ../../node_modules/@jimp/plugin-print/dist/esm/load-bitmap-font.js
42382
- import path7 from "path";
42382
+ import path8 from "path";
42383
42383
  function isBinary(buf) {
42384
42384
  if (typeof buf === "string") {
42385
42385
  return buf.substring(0, 3) === "BMF";
@@ -42470,7 +42470,7 @@ async function processBitmapFont(file, font) {
42470
42470
  ...font,
42471
42471
  chars,
42472
42472
  kernings,
42473
- pages: await Promise.all(font.pages.map(async (page) => CharacterJimp.read(path7.join(path7.dirname(file), page))))
42473
+ pages: await Promise.all(font.pages.map(async (page) => CharacterJimp.read(path8.join(path8.dirname(file), page))))
42474
42474
  };
42475
42475
  }
42476
42476
  var import_parse_bmfont_ascii, import_parse_bmfont_xml, import_parse_bmfont_binary, convertXML, isWebWorker, CharacterJimp, HEADER;
@@ -48594,8 +48594,8 @@ var require_descriptor = __commonJS({
48594
48594
  var sig = (0, psdReader_1.readSignature)(reader);
48595
48595
  (0, psdReader_1.readInt32LE)(reader);
48596
48596
  var charsCount = (0, psdReader_1.readInt32LE)(reader);
48597
- var path11 = (0, psdReader_1.readUnicodeStringWithLengthLE)(reader, charsCount);
48598
- return { sig, path: path11 };
48597
+ var path12 = (0, psdReader_1.readUnicodeStringWithLengthLE)(reader, charsCount);
48598
+ return { sig, path: path12 };
48599
48599
  }
48600
48600
  default:
48601
48601
  throw new Error("Invalid TySh descriptor OSType: ".concat(type2, " at ").concat(reader.offset.toString(16)));
@@ -54366,7 +54366,7 @@ var require_additionalInfo = __commonJS({
54366
54366
  function readVectorMask(reader, vectorMask, width, height, size) {
54367
54367
  var end = reader.offset + size;
54368
54368
  var paths = vectorMask.paths;
54369
- var path11 = void 0;
54369
+ var path12 = void 0;
54370
54370
  while (end - reader.offset >= 26) {
54371
54371
  var selector = (0, psdReader_1.readUint16)(reader);
54372
54372
  switch (selector) {
@@ -54376,21 +54376,21 @@ var require_additionalInfo = __commonJS({
54376
54376
  var boolOp = (0, psdReader_1.readInt16)(reader);
54377
54377
  var flags = (0, psdReader_1.readUint16)(reader);
54378
54378
  (0, psdReader_1.skipBytes)(reader, 18);
54379
- path11 = {
54379
+ path12 = {
54380
54380
  open: selector === 3,
54381
54381
  knots: [],
54382
54382
  fillRule: flags === 2 ? "non-zero" : "even-odd"
54383
54383
  };
54384
54384
  if (boolOp !== -1)
54385
- path11.operation = exports.booleanOperations[boolOp];
54386
- paths.push(path11);
54385
+ path12.operation = exports.booleanOperations[boolOp];
54386
+ paths.push(path12);
54387
54387
  break;
54388
54388
  }
54389
54389
  case 1:
54390
54390
  case 2:
54391
54391
  case 4:
54392
54392
  case 5:
54393
- path11.knots.push({ linked: selector === 1 || selector === 4, points: readBezierKnot(reader, width, height) });
54393
+ path12.knots.push({ linked: selector === 1 || selector === 4, points: readBezierKnot(reader, width, height) });
54394
54394
  break;
54395
54395
  case 6:
54396
54396
  (0, psdReader_1.skipBytes)(reader, 24);
@@ -54450,15 +54450,15 @@ var require_additionalInfo = __commonJS({
54450
54450
  (0, psdWriter_1.writeUint16)(writer, vectorMask.fillStartsWithAllPixels ? 1 : 0);
54451
54451
  (0, psdWriter_1.writeZeros)(writer, 22);
54452
54452
  for (var _i = 0, _b = vectorMask.paths; _i < _b.length; _i++) {
54453
- var path11 = _b[_i];
54454
- (0, psdWriter_1.writeUint16)(writer, path11.open ? 3 : 0);
54455
- (0, psdWriter_1.writeUint16)(writer, path11.knots.length);
54456
- (0, psdWriter_1.writeUint16)(writer, path11.operation ? exports.booleanOperations.indexOf(path11.operation) : -1);
54457
- (0, psdWriter_1.writeUint16)(writer, path11.fillRule === "non-zero" ? 2 : 1);
54453
+ var path12 = _b[_i];
54454
+ (0, psdWriter_1.writeUint16)(writer, path12.open ? 3 : 0);
54455
+ (0, psdWriter_1.writeUint16)(writer, path12.knots.length);
54456
+ (0, psdWriter_1.writeUint16)(writer, path12.operation ? exports.booleanOperations.indexOf(path12.operation) : -1);
54457
+ (0, psdWriter_1.writeUint16)(writer, path12.fillRule === "non-zero" ? 2 : 1);
54458
54458
  (0, psdWriter_1.writeZeros)(writer, 18);
54459
- var linkedKnot = path11.open ? 4 : 1;
54460
- var unlinkedKnot = path11.open ? 5 : 2;
54461
- for (var _c = 0, _d = path11.knots; _c < _d.length; _c++) {
54459
+ var linkedKnot = path12.open ? 4 : 1;
54460
+ var unlinkedKnot = path12.open ? 5 : 2;
54461
+ for (var _c = 0, _d = path12.knots; _c < _d.length; _c++) {
54462
54462
  var _e = _d[_c], linked = _e.linked, points = _e.points;
54463
54463
  (0, psdWriter_1.writeUint16)(writer, linked ? linkedKnot : unlinkedKnot);
54464
54464
  writeBezierKnot(writer, points, width, height);
@@ -56177,12 +56177,12 @@ var require_additionalInfo = __commonJS({
56177
56177
  _name: "",
56178
56178
  _classID: "PaCm",
56179
56179
  shapeOperation: "shapeOperation.".concat(c3.shapeOperation),
56180
- SbpL: c3.paths.map(function(path11) {
56180
+ SbpL: c3.paths.map(function(path12) {
56181
56181
  return {
56182
56182
  _name: "",
56183
56183
  _classID: "Sbpl",
56184
- Clsp: path11.closed,
56185
- "Pts ": path11.points.map(function(pt) {
56184
+ Clsp: path12.closed,
56185
+ "Pts ": path12.points.map(function(pt) {
56186
56186
  return {
56187
56187
  _name: "",
56188
56188
  _classID: "Pthp",
@@ -59210,11 +59210,11 @@ var init_webp_dec = __esm({
59210
59210
  var ENVIRONMENT_IS_WORKER = typeof importScripts == "function";
59211
59211
  var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string";
59212
59212
  var scriptDirectory = "";
59213
- function locateFile(path11) {
59213
+ function locateFile(path12) {
59214
59214
  if (Module3["locateFile"]) {
59215
- return Module3["locateFile"](path11, scriptDirectory);
59215
+ return Module3["locateFile"](path12, scriptDirectory);
59216
59216
  }
59217
- return scriptDirectory + path11;
59217
+ return scriptDirectory + path12;
59218
59218
  }
59219
59219
  var read_, readAsync, readBinary2, setWindowTitle;
59220
59220
  if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
@@ -60650,11 +60650,11 @@ var init_avif_dec = __esm({
60650
60650
  var ENVIRONMENT_IS_WORKER = typeof importScripts == "function";
60651
60651
  var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string";
60652
60652
  var scriptDirectory = "";
60653
- function locateFile(path11) {
60653
+ function locateFile(path12) {
60654
60654
  if (Module3["locateFile"]) {
60655
- return Module3["locateFile"](path11, scriptDirectory);
60655
+ return Module3["locateFile"](path12, scriptDirectory);
60656
60656
  }
60657
- return scriptDirectory + path11;
60657
+ return scriptDirectory + path12;
60658
60658
  }
60659
60659
  var read_, readAsync, readBinary2;
60660
60660
  if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
@@ -62171,17 +62171,17 @@ var require_ignore = __commonJS({
62171
62171
  var throwError = (message, Ctor) => {
62172
62172
  throw new Ctor(message);
62173
62173
  };
62174
- var checkPath = (path11, originalPath, doThrow) => {
62175
- if (!isString(path11)) {
62174
+ var checkPath = (path12, originalPath, doThrow) => {
62175
+ if (!isString(path12)) {
62176
62176
  return doThrow(
62177
62177
  `path must be a string, but got \`${originalPath}\``,
62178
62178
  TypeError
62179
62179
  );
62180
62180
  }
62181
- if (!path11) {
62181
+ if (!path12) {
62182
62182
  return doThrow(`path must not be empty`, TypeError);
62183
62183
  }
62184
- if (checkPath.isNotRelative(path11)) {
62184
+ if (checkPath.isNotRelative(path12)) {
62185
62185
  const r2 = "`path.relative()`d";
62186
62186
  return doThrow(
62187
62187
  `path should be a ${r2} string, but got "${originalPath}"`,
@@ -62190,7 +62190,7 @@ var require_ignore = __commonJS({
62190
62190
  }
62191
62191
  return true;
62192
62192
  };
62193
- var isNotRelative = (path11) => REGEX_TEST_INVALID_PATH.test(path11);
62193
+ var isNotRelative = (path12) => REGEX_TEST_INVALID_PATH.test(path12);
62194
62194
  checkPath.isNotRelative = isNotRelative;
62195
62195
  checkPath.convert = (p2) => p2;
62196
62196
  var Ignore = class {
@@ -62249,7 +62249,7 @@ var require_ignore = __commonJS({
62249
62249
  // setting `checkUnignored` to `false` could reduce additional
62250
62250
  // path matching.
62251
62251
  // @returns {TestResult} true if a file is ignored
62252
- _testOne(path11, checkUnignored) {
62252
+ _testOne(path12, checkUnignored) {
62253
62253
  let ignored = false;
62254
62254
  let unignored = false;
62255
62255
  this._rules.forEach((rule) => {
@@ -62257,7 +62257,7 @@ var require_ignore = __commonJS({
62257
62257
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
62258
62258
  return;
62259
62259
  }
62260
- const matched = rule.regex.test(path11);
62260
+ const matched = rule.regex.test(path12);
62261
62261
  if (matched) {
62262
62262
  ignored = !negative;
62263
62263
  unignored = negative;
@@ -62270,24 +62270,24 @@ var require_ignore = __commonJS({
62270
62270
  }
62271
62271
  // @returns {TestResult}
62272
62272
  _test(originalPath, cache, checkUnignored, slices) {
62273
- const path11 = originalPath && checkPath.convert(originalPath);
62273
+ const path12 = originalPath && checkPath.convert(originalPath);
62274
62274
  checkPath(
62275
- path11,
62275
+ path12,
62276
62276
  originalPath,
62277
62277
  this._allowRelativePaths ? RETURN_FALSE : throwError
62278
62278
  );
62279
- return this._t(path11, cache, checkUnignored, slices);
62279
+ return this._t(path12, cache, checkUnignored, slices);
62280
62280
  }
62281
- _t(path11, cache, checkUnignored, slices) {
62282
- if (path11 in cache) {
62283
- return cache[path11];
62281
+ _t(path12, cache, checkUnignored, slices) {
62282
+ if (path12 in cache) {
62283
+ return cache[path12];
62284
62284
  }
62285
62285
  if (!slices) {
62286
- slices = path11.split(SLASH);
62286
+ slices = path12.split(SLASH);
62287
62287
  }
62288
62288
  slices.pop();
62289
62289
  if (!slices.length) {
62290
- return cache[path11] = this._testOne(path11, checkUnignored);
62290
+ return cache[path12] = this._testOne(path12, checkUnignored);
62291
62291
  }
62292
62292
  const parent = this._t(
62293
62293
  slices.join(SLASH) + SLASH,
@@ -62295,24 +62295,24 @@ var require_ignore = __commonJS({
62295
62295
  checkUnignored,
62296
62296
  slices
62297
62297
  );
62298
- return cache[path11] = parent.ignored ? parent : this._testOne(path11, checkUnignored);
62298
+ return cache[path12] = parent.ignored ? parent : this._testOne(path12, checkUnignored);
62299
62299
  }
62300
- ignores(path11) {
62301
- return this._test(path11, this._ignoreCache, false).ignored;
62300
+ ignores(path12) {
62301
+ return this._test(path12, this._ignoreCache, false).ignored;
62302
62302
  }
62303
62303
  createFilter() {
62304
- return (path11) => !this.ignores(path11);
62304
+ return (path12) => !this.ignores(path12);
62305
62305
  }
62306
62306
  filter(paths) {
62307
62307
  return makeArray(paths).filter(this.createFilter());
62308
62308
  }
62309
62309
  // @returns {TestResult}
62310
- test(path11) {
62311
- return this._test(path11, this._testCache, true);
62310
+ test(path12) {
62311
+ return this._test(path12, this._testCache, true);
62312
62312
  }
62313
62313
  };
62314
62314
  var factory = (options) => new Ignore(options);
62315
- var isPathValid = (path11) => checkPath(path11 && checkPath.convert(path11), path11, RETURN_FALSE);
62315
+ var isPathValid = (path12) => checkPath(path12 && checkPath.convert(path12), path12, RETURN_FALSE);
62316
62316
  factory.isPathValid = isPathValid;
62317
62317
  factory.default = factory;
62318
62318
  module.exports = factory;
@@ -62323,13 +62323,13 @@ var require_ignore = __commonJS({
62323
62323
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
62324
62324
  checkPath.convert = makePosix;
62325
62325
  const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
62326
- checkPath.isNotRelative = (path11) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path11) || isNotRelative(path11);
62326
+ checkPath.isNotRelative = (path12) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path12) || isNotRelative(path12);
62327
62327
  }
62328
62328
  }
62329
62329
  });
62330
62330
 
62331
62331
  // src/server/engine-api.ts
62332
- import path10 from "node:path";
62332
+ import path11 from "node:path";
62333
62333
  import fs10 from "node:fs";
62334
62334
  import os from "node:os";
62335
62335
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -62535,7 +62535,7 @@ function portionName(p2) {
62535
62535
  }
62536
62536
  function renderPointer(p2, opts = {}) {
62537
62537
  const spaced = opts.spaced !== false;
62538
- const sep2 = spaced ? ": " : ":";
62538
+ const sep3 = spaced ? ": " : ":";
62539
62539
  const toks = [];
62540
62540
  for (const st of p2.steps) {
62541
62541
  if (st.sel === "parent") {
@@ -62562,18 +62562,18 @@ function renderPointer(p2, opts = {}) {
62562
62562
  if (toks.length > 0) toks[toks.length - 1] += t3;
62563
62563
  else toks.push(t3);
62564
62564
  }
62565
- const body = toks.join(sep2);
62565
+ const body = toks.join(sep3);
62566
62566
  switch (p2.base.scope) {
62567
62567
  case "current":
62568
62568
  return body;
62569
62569
  case "parent":
62570
- return body === "" ? ".." : ".." + sep2 + body;
62570
+ return body === "" ? ".." : ".." + sep3 + body;
62571
62571
  case "document":
62572
62572
  return ":" + (body === "" ? "" : (spaced ? " " : "") + body);
62573
62573
  case "link": {
62574
62574
  const ladder = p2.base.world === true ? ":::" : "::";
62575
62575
  const auth = colonSegment(p2.base.authority);
62576
- return ladder + (spaced ? " " : "") + auth + (body === "" ? "" : sep2 + body);
62576
+ return ladder + (spaced ? " " : "") + auth + (body === "" ? "" : sep3 + body);
62577
62577
  }
62578
62578
  }
62579
62579
  }
@@ -62590,21 +62590,21 @@ function makeAnchor(body, fail, yaml = false) {
62590
62590
  if (body.endsWith("[]") && !body.endsWith("\\[]")) {
62591
62591
  fail(`the "[]" append was removed \u2014 write a trailing ": -" segment (a bookmark's keyless membership)`);
62592
62592
  }
62593
- const path11 = parsePointer(body, yaml, { allowAppend: true });
62594
- if (path11.steps.some((s2) => s2.sel === "relindex")) fail('a bookmark may not claim a position \u2014 "[.\xB1k]" is link-only');
62593
+ const path12 = parsePointer(body, yaml, { allowAppend: true });
62594
+ if (path12.steps.some((s2) => s2.sel === "relindex")) fail('a bookmark may not claim a position \u2014 "[.\xB1k]" is link-only');
62595
62595
  let ordinal = false;
62596
- const last = path11.steps[path11.steps.length - 1];
62596
+ const last = path12.steps[path12.steps.length - 1];
62597
62597
  if (last?.sel === "append") {
62598
62598
  ordinal = true;
62599
- path11.steps = path11.steps.slice(0, -1);
62599
+ path12.steps = path12.steps.slice(0, -1);
62600
62600
  }
62601
- if (path11.steps.some((s2) => s2.sel === "append")) fail('a mid-path "-" segment is reserved \u2014 only the trailing append is defined');
62601
+ if (path12.steps.some((s2) => s2.sel === "append")) fail('a mid-path "-" segment is reserved \u2014 only the trailing append is defined');
62602
62602
  if (!ordinal) {
62603
62603
  if (last === void 0) fail('a bookmark path needs a key segment (or a trailing ": -" for keyless membership)');
62604
62604
  if (last.sel === "nullkey") fail("a bookmark cannot create the null key");
62605
62605
  if (last.sel !== "key") fail('a bookmark may not claim a position \u2014 use a trailing ": -" for keyless membership');
62606
62606
  }
62607
- return { path: path11, ...ordinal ? { ordinal: true } : {} };
62607
+ return { path: path12, ...ordinal ? { ordinal: true } : {} };
62608
62608
  }
62609
62609
 
62610
62610
  // ../parser/ts/src/pathseg.ts
@@ -62617,13 +62617,13 @@ function pathOfSegs(segs) {
62617
62617
  if (segs.length === 0) return ":";
62618
62618
  return segs.map((s2) => ":" + segToken(s2)).join("");
62619
62619
  }
62620
- function childSeg(path11, seg) {
62621
- return (path11 === ":" ? "" : path11) + ":" + segToken(seg);
62620
+ function childSeg(path12, seg) {
62621
+ return (path12 === ":" ? "" : path12) + ":" + segToken(seg);
62622
62622
  }
62623
- function segsOfPath(path11, opts = {}) {
62623
+ function segsOfPath(path12, opts = {}) {
62624
62624
  const segs = [];
62625
62625
  let i2 = 0;
62626
- const s2 = path11;
62626
+ const s2 = path12;
62627
62627
  while (i2 < s2.length) {
62628
62628
  const c3 = s2[i2];
62629
62629
  if (c3 === ":") {
@@ -62707,6 +62707,233 @@ function safeDecode(s2) {
62707
62707
  }
62708
62708
  }
62709
62709
 
62710
+ // ../parser/ts/src/marklower-links.ts
62711
+ var LABEL = String.raw`(?:[^\[\]]|\[[^\]]*\])*?`;
62712
+ var TOKEN = new RegExp(
62713
+ "(`{3,})[\\s\\S]*?\\1|" + // 1: fenced block — atomic, never re-interpreted
62714
+ String.raw`\$\$([\s\S]+?)\$\$|` + // 2: math
62715
+ "`([^`]+?)`|" + // 3: code
62716
+ String.raw`\[(${LABEL})\]\(([^)]+?)\)`,
62717
+ // 4,5: link
62718
+ "g"
62719
+ );
62720
+ var ATOMIC = new RegExp(
62721
+ "(`{3,})[\\s\\S]*?\\1|" + // 1: fenced block
62722
+ String.raw`\$\$([\s\S]+?)\$\$|` + // 2: math
62723
+ "`([^`]+?)`",
62724
+ // 3: code
62725
+ "g"
62726
+ );
62727
+ function unquoteScalar(t3) {
62728
+ if (t3.length >= 2 && t3[0] === "'" && t3[t3.length - 1] === "'") return t3.slice(1, -1).replace(/''/g, "'");
62729
+ if (t3.length >= 2 && t3[0] === '"' && t3[t3.length - 1] === '"') {
62730
+ try {
62731
+ return JSON.parse(t3);
62732
+ } catch {
62733
+ return t3.slice(1, -1);
62734
+ }
62735
+ }
62736
+ return t3;
62737
+ }
62738
+ function parseLabel(label) {
62739
+ const bookmarks = [];
62740
+ let rest = label;
62741
+ for (; ; ) {
62742
+ const t3 = rest.replace(/^\s+/, "");
62743
+ if (!t3.startsWith("&")) {
62744
+ rest = t3;
62745
+ break;
62746
+ }
62747
+ if (t3[1] === "'") {
62748
+ const close = t3.indexOf("'", 2);
62749
+ if (close < 0) {
62750
+ rest = t3;
62751
+ break;
62752
+ }
62753
+ bookmarks.push(t3.slice(0, close + 1));
62754
+ rest = t3.slice(close + 1).replace(/^\s*:?\s*/, "");
62755
+ } else {
62756
+ const m = /^&[^,]*?:\s*-\s*(?=:|$)/.exec(t3);
62757
+ if (!m) {
62758
+ rest = t3;
62759
+ break;
62760
+ }
62761
+ bookmarks.push(m[0].replace(/\s+/g, " ").trim());
62762
+ rest = t3.slice(m[0].length).replace(/^\s*:?\s*/, "");
62763
+ }
62764
+ }
62765
+ return { bookmarks, valueRaw: rest.trim() };
62766
+ }
62767
+ function splitFields(inner) {
62768
+ const out = [];
62769
+ let depth = 0;
62770
+ let quote = null;
62771
+ let start = 0;
62772
+ for (let i2 = 0; i2 < inner.length; i2++) {
62773
+ const ch = inner[i2];
62774
+ if (quote) {
62775
+ if (ch === quote) quote = null;
62776
+ continue;
62777
+ }
62778
+ if (ch === "'" || ch === '"') quote = ch;
62779
+ else if (ch === "(" || ch === "[" || ch === "{") depth++;
62780
+ else if (ch === ")" || ch === "]" || ch === "}") depth--;
62781
+ else if (ch === "," && depth === 0) {
62782
+ out.push({ text: inner.slice(start, i2), at: start });
62783
+ start = i2 + 1;
62784
+ }
62785
+ }
62786
+ out.push({ text: inner.slice(start), at: start });
62787
+ return out;
62788
+ }
62789
+ function readFragToken(src, at) {
62790
+ let i2 = at + 1;
62791
+ let depth = 0;
62792
+ let quote = null;
62793
+ for (; i2 < src.length; i2++) {
62794
+ const ch = src[i2];
62795
+ if (quote) {
62796
+ if (ch === quote) quote = null;
62797
+ continue;
62798
+ }
62799
+ if (ch === "'" || ch === '"') quote = ch;
62800
+ else if (ch === "[") {
62801
+ if (depth > 0) return null;
62802
+ depth++;
62803
+ } else if (ch === "]") {
62804
+ if (depth > 0) {
62805
+ depth--;
62806
+ continue;
62807
+ }
62808
+ break;
62809
+ } else if (ch === "\n") return null;
62810
+ }
62811
+ if (i2 >= src.length || src[i2] !== "]" || src[i2 + 1] !== "(") return null;
62812
+ const label = src.slice(at + 1, i2);
62813
+ let j = i2 + 2;
62814
+ depth = 0;
62815
+ quote = null;
62816
+ for (; j < src.length; j++) {
62817
+ const ch = src[j];
62818
+ if (quote) {
62819
+ if (ch === quote) quote = null;
62820
+ continue;
62821
+ }
62822
+ if (ch === "'" || ch === '"') quote = ch;
62823
+ else if (ch === "(") depth++;
62824
+ else if (ch === ")") {
62825
+ if (depth > 0) {
62826
+ depth--;
62827
+ continue;
62828
+ }
62829
+ break;
62830
+ }
62831
+ }
62832
+ if (j >= src.length || src[j] !== ")") return null;
62833
+ const parens = src.slice(i2 + 2, j);
62834
+ const end = j + 1;
62835
+ const { bookmarks, valueRaw } = parseLabel(label);
62836
+ const value = unquoteScalar(valueRaw);
62837
+ let link = null;
62838
+ let linkStart = -1;
62839
+ let linkEnd = -1;
62840
+ let plainLink = false;
62841
+ const fields = [];
62842
+ const parensAbs = i2 + 2;
62843
+ const trimmed = parens.trim();
62844
+ if (trimmed !== "") {
62845
+ if (parseLinkTarget(trimmed).kind !== "unresolved") {
62846
+ link = trimmed;
62847
+ linkStart = parensAbs + (parens.length - parens.replace(/^\s+/, "").length);
62848
+ linkEnd = linkStart + trimmed.length;
62849
+ plainLink = true;
62850
+ } else {
62851
+ for (const part of splitFields(parens)) {
62852
+ const pt = part.text.trim();
62853
+ if (!pt) continue;
62854
+ if (link === null && parseLinkTarget(pt).kind !== "unresolved") {
62855
+ link = pt;
62856
+ linkStart = parensAbs + part.at + (part.text.length - part.text.replace(/^\s+/, "").length);
62857
+ linkEnd = linkStart + pt.length;
62858
+ continue;
62859
+ }
62860
+ const kv = /^([A-Za-z0-9_][A-Za-z0-9_-]*)\s*:\s*([\s\S]*)$/.exec(pt);
62861
+ if (kv) fields.push({ key: kv[1], raw: kv[2] });
62862
+ }
62863
+ }
62864
+ }
62865
+ return {
62866
+ kind: "frag",
62867
+ start: at,
62868
+ end,
62869
+ raw: src.slice(at, end),
62870
+ label,
62871
+ parens,
62872
+ bookmarks,
62873
+ value,
62874
+ valueRaw,
62875
+ link,
62876
+ linkStart,
62877
+ linkEnd,
62878
+ fields,
62879
+ plainLink
62880
+ };
62881
+ }
62882
+ function scanMarklower(src) {
62883
+ const out = [];
62884
+ ATOMIC.lastIndex = 0;
62885
+ let i2 = 0;
62886
+ let m = ATOMIC.exec(src);
62887
+ while (i2 < src.length) {
62888
+ while (m && m.index < i2) m = ATOMIC.exec(src);
62889
+ let frag = null;
62890
+ const limit = m ? m.index : src.length;
62891
+ for (let k = src.indexOf("[", i2); k >= 0 && k < limit; k = src.indexOf("[", k + 1)) {
62892
+ const f2 = readFragToken(src, k);
62893
+ if (f2) {
62894
+ frag = f2;
62895
+ break;
62896
+ }
62897
+ }
62898
+ if (frag) {
62899
+ out.push(frag);
62900
+ i2 = frag.end;
62901
+ continue;
62902
+ }
62903
+ if (!m) break;
62904
+ const kind = m[1] !== void 0 ? "fence" : m[2] !== void 0 ? "math" : "code";
62905
+ out.push({ kind, start: m.index, end: m.index + m[0].length, raw: m[0], body: m[2] ?? m[3] ?? m[0] });
62906
+ i2 = m.index + m[0].length;
62907
+ m = ATOMIC.exec(src);
62908
+ }
62909
+ return out;
62910
+ }
62911
+ function linkTargets(src) {
62912
+ const out = [];
62913
+ for (const t3 of scanMarklower(src)) {
62914
+ if (t3.kind !== "frag" || t3.link === null) continue;
62915
+ out.push({ target: t3.link, raw: t3.raw, start: t3.start, end: t3.end, targetStart: t3.linkStart, targetEnd: t3.linkEnd });
62916
+ }
62917
+ return out;
62918
+ }
62919
+ var hasScheme = (s2) => /^[a-z][a-z0-9+.-]*:(?!\s|$)/i.test(s2);
62920
+ function parseLinkTarget(target) {
62921
+ const raw = target.trim();
62922
+ if (!raw) return { kind: "unresolved" };
62923
+ if (raw.startsWith("&")) return { kind: "anchor", raw };
62924
+ if (raw.startsWith("*") || raw.startsWith(":")) {
62925
+ const expr = raw.startsWith("*") ? raw.slice(1) : raw;
62926
+ try {
62927
+ return { kind: "pointer", ptr: parsePointer(expr), sigiled: raw.startsWith("*") };
62928
+ } catch {
62929
+ return { kind: "unresolved" };
62930
+ }
62931
+ }
62932
+ if (raw.startsWith("//") || raw.startsWith("/")) return { kind: "legacy-slash", raw };
62933
+ if (hasScheme(raw)) return { kind: "external", href: raw };
62934
+ return { kind: "unresolved" };
62935
+ }
62936
+
62710
62937
  // ../engine/ts/src/boundary.ts
62711
62938
  var BOUNDARY_FORMATS = /* @__PURE__ */ new Set(["x-yamlover-xyflow"]);
62712
62939
  function tagFormat(node) {
@@ -62918,6 +63145,100 @@ function buildChains(root) {
62918
63145
  walk(root, []);
62919
63146
  return m;
62920
63147
  }
63148
+ var PROSE_TEXT_FORMATS = /* @__PURE__ */ new Set([void 0, "text/marklower"]);
63149
+ var PRESENTATIONAL_FORMATS = /* @__PURE__ */ new Set(["x-yamlover-bullets", "x-yamlover-numbered", "x-yamlover-table"]);
63150
+ function textLinkPath(ptr3, holder, docRoot) {
63151
+ let base;
63152
+ switch (ptr3.base.scope) {
63153
+ case "link":
63154
+ base = ptr3.base.world ? "" : ":" + segToken(ptr3.base.authority);
63155
+ break;
63156
+ case "document":
63157
+ base = docRoot;
63158
+ break;
63159
+ case "current":
63160
+ base = holder;
63161
+ break;
63162
+ case "parent": {
63163
+ const segs = segsOfPath(holder);
63164
+ if (segs.length === 0) return null;
63165
+ base = pathOfSegs(segs.slice(0, -1));
63166
+ break;
63167
+ }
63168
+ }
63169
+ if (ptr3.base.scope === "link" && ptr3.base.world) return null;
63170
+ let p2 = base === ":" ? "" : base;
63171
+ for (const st of ptr3.steps) {
63172
+ if (st.sel === "parent") {
63173
+ const segs = segsOfPath(p2 === "" ? ":" : p2);
63174
+ if (segs.length === 0) return null;
63175
+ p2 = pathOfSegs(segs.slice(0, -1));
63176
+ if (p2 === ":") p2 = "";
63177
+ } else if (st.sel === "key") p2 += ":" + segToken(st.name);
63178
+ else if (st.sel === "index") p2 += ":" + st.n;
63179
+ else if (st.sel === "nullkey") p2 += ":~";
63180
+ else return null;
63181
+ }
63182
+ return p2 === "" ? ":" : p2;
63183
+ }
63184
+ function scanTextLinks(doc) {
63185
+ const out = [];
63186
+ const walk = (node, base, parent, docRoot, uri, entrySpan, inPres) => {
63187
+ const dr = isDocumentBoundary(node) ? base : docRoot;
63188
+ const u2 = node.meta?.span?.uri ?? uri;
63189
+ const fmt = node.meta?.derivedFormat;
63190
+ const pres = PRESENTATIONAL_FORMATS.has(fmt) || inPres && fmt === void 0;
63191
+ if (node.kind === "scalar" && typeof node.value === "string" && PROSE_TEXT_FORMATS.has(node.meta?.derivedFormat)) {
63192
+ const span = node.meta?.span ?? entrySpan;
63193
+ const holder = node.entries && !pres ? base : parent;
63194
+ for (const l2 of linkTargets(node.value)) {
63195
+ const t3 = parseLinkTarget(l2.target);
63196
+ if (t3.kind === "pointer") {
63197
+ out.push({
63198
+ from: base,
63199
+ holder,
63200
+ docRoot: dr,
63201
+ ptr: t3.ptr,
63202
+ sigiled: t3.sigiled,
63203
+ anchor: false,
63204
+ target: textLinkPath(t3.ptr, holder, dr),
63205
+ raw: l2.raw,
63206
+ uri: u2,
63207
+ span
63208
+ });
63209
+ } else if (t3.kind === "anchor") {
63210
+ let ptr3 = null;
63211
+ try {
63212
+ ptr3 = parsePointer(t3.raw.slice(1));
63213
+ } catch {
63214
+ }
63215
+ if (ptr3 !== null) {
63216
+ out.push({
63217
+ from: base,
63218
+ holder,
63219
+ docRoot: dr,
63220
+ ptr: ptr3,
63221
+ sigiled: true,
63222
+ anchor: true,
63223
+ target: textLinkPath(ptr3, holder, dr),
63224
+ raw: l2.raw,
63225
+ uri: u2,
63226
+ span
63227
+ });
63228
+ }
63229
+ }
63230
+ }
63231
+ }
63232
+ const prefix = base === ":" ? "" : base;
63233
+ const frame = pres ? parent : base;
63234
+ node.entries?.forEach((e3, i2) => {
63235
+ if (isPointer(e3.value)) return;
63236
+ walk(e3.value, prefix + ":" + segToken(e3.nullKey === true ? null : e3.key ?? i2), frame, dr, u2, e3.meta?.span ?? null, pres);
63237
+ });
63238
+ };
63239
+ walk(doc.root, ":", ":", ":", doc.source?.uri ?? null, null, false);
63240
+ return out;
63241
+ }
62921
63242
  function pathOf(chain) {
62922
63243
  let s2 = "";
62923
63244
  for (let i2 = 1; i2 < chain.length; i2++) {
@@ -62935,7 +63256,7 @@ function pathOf(chain) {
62935
63256
 
62936
63257
  // ../engine/ts/src/store.ts
62937
63258
  import { DatabaseSync } from "node:sqlite";
62938
- var SCHEMA_VERSION = 11;
63259
+ var SCHEMA_VERSION = 13;
62939
63260
  var SCHEMA = `
62940
63261
  CREATE TABLE IF NOT EXISTS node (
62941
63262
  path TEXT PRIMARY KEY,
@@ -63027,7 +63348,7 @@ var Store = class {
63027
63348
  try {
63028
63349
  this.db.exec("DELETE FROM node; DELETE FROM edge; DELETE FROM dangling;");
63029
63350
  if (files) this.db.exec("DELETE FROM file;");
63030
- walkNodes(doc.root, ":", (path11, node, parent, label, pos, labelNull) => {
63351
+ walkNodes(doc.root, ":", (path12, node, parent, label, pos, labelNull) => {
63031
63352
  const meta = node.meta ? JSON.stringify(node.meta) : null;
63032
63353
  const owned = node.entries?.filter((e3) => e3.edge !== "back") ?? [];
63033
63354
  const isArray = node.array || node.kind === "mapping" && owned.length > 0 && owned.every((e3) => e3.key === null && e3.nullKey !== true);
@@ -63035,8 +63356,8 @@ var Store = class {
63035
63356
  const format = node.kind === "blob" ? node.format : formatFromMeta(node);
63036
63357
  const hash = node.kind === "blob" ? node.contentHash : null;
63037
63358
  const size = node.kind === "blob" ? node.size : null;
63038
- insNode.run(path11, node.kind, format, value, hash, size, isArray ? 1 : 0, meta);
63039
- if (parent !== null) insEdge.run(parent, path11, label, labelNull ? 1 : 0, "contain", pos);
63359
+ insNode.run(path12, node.kind, format, value, hash, size, isArray ? 1 : 0, meta);
63360
+ if (parent !== null) insEdge.run(parent, path12, label, labelNull ? 1 : 0, "contain", pos);
63040
63361
  });
63041
63362
  const insDangling = this.db.prepare(INSERT_DANGLING);
63042
63363
  for (const r2 of resolveDocument(doc)) {
@@ -63174,7 +63495,7 @@ var Store = class {
63174
63495
  * fresh `/tags` has no rows yet), then the tag's subtree and its containment edge. Approximate
63175
63496
  * by design — the next reconcile re-walks the edited taxonomy body and trues everything up;
63176
63497
  * these rows only have to answer queries until then. */
63177
- addTag(taxonomyStorePath, name, pos, node) {
63498
+ addOnto(taxonomyStorePath, name, pos, node) {
63178
63499
  const insNode = this.db.prepare(
63179
63500
  `INSERT OR REPLACE INTO node (path, type, format, value, content_hash, size, is_array, meta)
63180
63501
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
@@ -63271,24 +63592,24 @@ var Store = class {
63271
63592
  }));
63272
63593
  }
63273
63594
  /** A node's attributes (null if no such path). */
63274
- node(path11) {
63275
- const row = this.db.prepare("SELECT * FROM node WHERE path = ?").get(path11);
63595
+ node(path12) {
63596
+ const row = this.db.prepare("SELECT * FROM node WHERE path = ?").get(path12);
63276
63597
  return row ? rowToNode(row) : null;
63277
63598
  }
63278
63599
  /** Direct containment children of a node, in source order (by `pos`). */
63279
- children(path11) {
63280
- return this.db.prepare("SELECT to_path, label, pos FROM edge WHERE from_path = ? AND kind = 'contain' ORDER BY pos").all(path11).map((r2) => ({ to: r2.to_path, label: r2.label ?? null, pos: r2.pos ?? null }));
63600
+ children(path12) {
63601
+ return this.db.prepare("SELECT to_path, label, pos FROM edge WHERE from_path = ? AND kind = 'contain' ORDER BY pos").all(path12).map((r2) => ({ to: r2.to_path, label: r2.label ?? null, pos: r2.pos ?? null }));
63281
63602
  }
63282
63603
  /** ALL of a node's entries in source order — containment children AND `*`/`~` pointer
63283
63604
  * entries (ref/back). Unlike {@link children} this keeps positional pointers (`- *file`)
63284
63605
  * in place, so an array that mixes inline values and pointers (e.g. a chapter's `chunks`)
63285
63606
  * projects in full. `kind` says whether `to` is an owned child (contain) or a pointer target. */
63286
- entries(path11) {
63287
- return this.db.prepare("SELECT to_path, label, pos, kind FROM edge WHERE from_path = ? AND kind IN ('contain','ref','back') ORDER BY pos").all(path11).map((r2) => ({ to: r2.to_path, label: r2.label ?? null, pos: r2.pos ?? null, kind: r2.kind }));
63607
+ entries(path12) {
63608
+ return this.db.prepare("SELECT to_path, label, pos, kind FROM edge WHERE from_path = ? AND kind IN ('contain','ref','back') ORDER BY pos").all(path12).map((r2) => ({ to: r2.to_path, label: r2.label ?? null, pos: r2.pos ?? null, kind: r2.kind }));
63288
63609
  }
63289
63610
  /** Whether a node has any containment children (expandable in the TOC). */
63290
- hasChildren(path11) {
63291
- const r2 = this.db.prepare("SELECT 1 FROM edge WHERE from_path = ? AND kind = 'contain' LIMIT 1").get(path11);
63611
+ hasChildren(path12) {
63612
+ const r2 = this.db.prepare("SELECT 1 FROM edge WHERE from_path = ? AND kind = 'contain' LIMIT 1").get(path12);
63292
63613
  return r2 != null;
63293
63614
  }
63294
63615
  /** The containment subtree rooted at `path`, up to `depth` levels (TOC). A recursive CTE
@@ -63296,7 +63617,7 @@ var Store = class {
63296
63617
  * (`meta.hidden` — the `.yo` overlay, the grafted `yamlover` self-import) are plumbing,
63297
63618
  * not contents: they are pruned here with their whole subtrees, so every TOC consumer gets the
63298
63619
  * same view without re-filtering. */
63299
- toc(path11 = ":", depth = Infinity) {
63620
+ toc(path12 = ":", depth = Infinity) {
63300
63621
  const rows = this.db.prepare(
63301
63622
  `WITH RECURSIVE sub(from_path, to_path, label, pos, lvl) AS (
63302
63623
  SELECT e.from_path, e.to_path, e.label, e.pos, 1 FROM edge e
@@ -63313,10 +63634,10 @@ var Store = class {
63313
63634
  SELECT s.to_path AS path, s.from_path AS parent, s.label, s.pos, n.type, n.format
63314
63635
  FROM sub s JOIN node n ON n.path = s.to_path
63315
63636
  ORDER BY s.lvl, s.from_path, s.pos`
63316
- ).all(path11, depth === Infinity ? Number.MAX_SAFE_INTEGER : depth);
63637
+ ).all(path12, depth === Infinity ? Number.MAX_SAFE_INTEGER : depth);
63317
63638
  const byPath = /* @__PURE__ */ new Map();
63318
- const root = { path: path11, label: null, type: this.node(path11)?.type ?? "mapping", format: null, children: [] };
63319
- byPath.set(path11, root);
63639
+ const root = { path: path12, label: null, type: this.node(path12)?.type ?? "mapping", format: null, children: [] };
63640
+ byPath.set(path12, root);
63320
63641
  for (const r2 of rows) {
63321
63642
  const tn = {
63322
63643
  path: r2.path,
@@ -63332,9 +63653,9 @@ var Store = class {
63332
63653
  }
63333
63654
  /** Edges in/out of a node, by kind. `derived` inverses are computed here on demand (never
63334
63655
  * stored) per ENGINE.md — for each ref/back into/out of the node, the reverse direction. */
63335
- relationships(path11) {
63336
- const out = this.db.prepare("SELECT * FROM edge WHERE from_path = ? AND kind != 'contain'").all(path11).map(rowToEdge);
63337
- const inc = this.db.prepare("SELECT * FROM edge WHERE to_path = ? AND kind != 'contain'").all(path11).map(rowToEdge);
63656
+ relationships(path12) {
63657
+ const out = this.db.prepare("SELECT * FROM edge WHERE from_path = ? AND kind != 'contain'").all(path12).map(rowToEdge);
63658
+ const inc = this.db.prepare("SELECT * FROM edge WHERE to_path = ? AND kind != 'contain'").all(path12).map(rowToEdge);
63338
63659
  const derivedIn = inc.filter((e3) => e3.kind === "ref" || e3.kind === "back").map((e3) => ({ from: e3.to, to: e3.from, label: e3.label, kind: "derived", pos: null }));
63339
63660
  return { out, in: [...inc, ...derivedIn] };
63340
63661
  }
@@ -63346,13 +63667,13 @@ function insDanglingRef(stmt, r2) {
63346
63667
  const reason = r2.target.kind === "external" ? r2.target.authority : r2.target.reason;
63347
63668
  stmt.run(r2.from, r2.raw, reason, r2.anchor ? "" : r2.holder, r2.label, r2.pos, r2.edge, ext ? 1 : 0);
63348
63669
  }
63349
- function walkNodes(node, path11, visit2, parent = null, label = null, pos = null, labelNull = false) {
63350
- visit2(path11, node, parent, label, pos, labelNull);
63670
+ function walkNodes(node, path12, visit2, parent = null, label = null, pos = null, labelNull = false) {
63671
+ visit2(path12, node, parent, label, pos, labelNull);
63351
63672
  if (!node.entries) return;
63352
63673
  node.entries.forEach((e3, i2) => {
63353
63674
  if (isPointer(e3.value)) return;
63354
- const childPath2 = childSeg(path11, e3.nullKey === true ? null : e3.key ?? i2);
63355
- walkNodes(e3.value, childPath2, visit2, path11, e3.key, i2, e3.nullKey === true);
63675
+ const childPath2 = childSeg(path12, e3.nullKey === true ? null : e3.key ?? i2);
63676
+ walkNodes(e3.value, childPath2, visit2, path12, e3.key, i2, e3.nullKey === true);
63356
63677
  });
63357
63678
  }
63358
63679
  function formatFromMeta(node) {
@@ -63608,9 +63929,9 @@ function parseYamlover(src, uri = "<yamlover>", opts = {}) {
63608
63929
  const yaml = opts.yaml === true;
63609
63930
  const raw = [];
63610
63931
  const lineStarts = [];
63611
- const sep2 = /\r\n|\r|\n/g;
63932
+ const sep3 = /\r\n|\r|\n/g;
63612
63933
  let at = 0;
63613
- for (let m = sep2.exec(src); m !== null; m = sep2.exec(src)) {
63934
+ for (let m = sep3.exec(src); m !== null; m = sep3.exec(src)) {
63614
63935
  raw.push(src.slice(at, m.index));
63615
63936
  lineStarts.push(at);
63616
63937
  at = m.index + m[0].length;
@@ -63765,8 +64086,14 @@ var Block = class {
63765
64086
  body = quotedScalar(text.slice(1, j + 1)).value;
63766
64087
  tokenLen = j + 1;
63767
64088
  } else if (hasSeparatorColon(inline ? text.slice(1).split(/[ \t]/, 1)[0] : text.slice(1))) {
63768
- body = text.slice(1).trim();
63769
- tokenLen = text.length;
64089
+ if (inline && !this.yaml) {
64090
+ tokenLen = this.anchorChainEnd(text);
64091
+ body = text.slice(1, tokenLen).trim();
64092
+ if (body.endsWith(":")) body = body.slice(0, -1).trimEnd();
64093
+ } else {
64094
+ body = text.slice(1).trim();
64095
+ tokenLen = text.length;
64096
+ }
63770
64097
  } else {
63771
64098
  let j = 1;
63772
64099
  while (j < text.length && text[j] !== " " && text[j] !== " ") {
@@ -63781,6 +64108,60 @@ var Block = class {
63781
64108
  const a2 = adv(text, tokenLen, col);
63782
64109
  return { anchor, rest: a2.rest, col: a2.col };
63783
64110
  }
64111
+ /** Where an INLINE colon-form anchor chain ends (docs/language/flattening combinations):
64112
+ * the scope colons and the FIRST name always belong; each further `: `-terminated portion
64113
+ * extends the chain; a lone `-` portion (the keyless-membership suffix) belongs too. The
64114
+ * chain stops before the next `&` (another bookmark) and before any other colon-less
64115
+ * token (the value). Returns the index in `text` just past the chain (text[0] is `&`). */
64116
+ anchorChainEnd(text) {
64117
+ let i2 = 1;
64118
+ while (text[i2] === ":") i2++;
64119
+ let end = i2;
64120
+ let first = true;
64121
+ for (; ; ) {
64122
+ let j = end;
64123
+ while (text[j] === " " || text[j] === " ") j++;
64124
+ if (j >= text.length) return text.length;
64125
+ if (text[j] === "&" && !first) return end;
64126
+ if (text[j] === "*") return end;
64127
+ let q = null;
64128
+ let k = j;
64129
+ let sawColon = false;
64130
+ for (; k < text.length; k++) {
64131
+ const c3 = text[k];
64132
+ if (q !== null) {
64133
+ if (c3 !== q) continue;
64134
+ if (q === "'" && text[k + 1] === "'") {
64135
+ k++;
64136
+ continue;
64137
+ }
64138
+ q = null;
64139
+ continue;
64140
+ }
64141
+ if (c3 === "'" || c3 === '"') {
64142
+ q = c3;
64143
+ continue;
64144
+ }
64145
+ if (c3 === ":" && (text[k + 1] === void 0 || text[k + 1] === " " || text[k + 1] === " ")) {
64146
+ sawColon = true;
64147
+ break;
64148
+ }
64149
+ if (c3 === " " || c3 === " ") break;
64150
+ }
64151
+ const token = text.slice(j, k);
64152
+ if (sawColon) {
64153
+ end = k + 1;
64154
+ first = false;
64155
+ continue;
64156
+ }
64157
+ if (first || token === "-") {
64158
+ end = k;
64159
+ first = false;
64160
+ continue;
64161
+ }
64162
+ return end;
64163
+ }
64164
+ }
63784
64165
  /** Attach anchors to a (non-pointer) node's meta, appending to any it already has. */
63785
64166
  attachAnchors(value, anchors) {
63786
64167
  if (anchors.length === 0) return;
@@ -63801,6 +64182,104 @@ var Block = class {
63801
64182
  this.attachAnchors(out, cont.meta?.anchors ?? []);
63802
64183
  return out;
63803
64184
  }
64185
+ /** Is this residue a FLAT-row continuation (docs/language/flattening) — itself a keyed or
64186
+ * `-:` line, so the fold unrolls one more level? `!!<`, `*`, `&`, block indicators and
64187
+ * `~` open VALUES/decorations, never path segments; quotes are decided by splitKV (a
64188
+ * quoted KEY has a top-level `: `, a quoted VALUE does not). Never in .yaml mode. */
64189
+ flatTail(rest) {
64190
+ if (this.yaml || rest === "") return false;
64191
+ if (/^(!!|\*|&|[|>~])/.test(rest)) return false;
64192
+ if (seqMarkLen(rest, false) === 2) return true;
64193
+ if (isSeqLine(rest, false)) return false;
64194
+ const kv = splitKV(rest);
64195
+ return kv !== null && kv.key !== "" && kv.key !== "~" && !kv.key.startsWith(":");
64196
+ }
64197
+ /** THE PAVING (docs/language/flattening: rows are commands): a FLAT spine merges into the
64198
+ * sibling it addresses — a named segment pairs with the LAST same-key sibling, a middle
64199
+ * `-` with the LAST keyless one (and never adds). Returns false when the row simply
64200
+ * CREATES (the plain push). */
64201
+ paveMerge(list, e3) {
64202
+ if (this.yaml) return false;
64203
+ const child = this.spineChild(e3.value);
64204
+ if (e3.key === null) {
64205
+ if (e3.nullKey === true || e3.edge === "back" || child === null) return false;
64206
+ const t4 = [...list].reverse().find((x2) => x2.key === null && x2.nullKey !== true && x2.edge !== "back");
64207
+ if (!t4) this.fail('a middle "-" segment addresses the LAST keyless element - none exists here');
64208
+ this.paveInto(t4, child);
64209
+ return true;
64210
+ }
64211
+ if (e3.meta?.keyConcrete === void 0 && child === null) return false;
64212
+ const t3 = [...list].reverse().find((x2) => x2.key === e3.key && x2.edge !== "back");
64213
+ if (!t3) {
64214
+ this.validateFreshSpine(e3);
64215
+ return false;
64216
+ }
64217
+ if (child === null) {
64218
+ this.paveValue(t3, e3.value);
64219
+ return true;
64220
+ }
64221
+ this.paveInto(t3, child);
64222
+ return true;
64223
+ }
64224
+ /** A spine about to be CREATED fresh may not contain a MIDDLE `-` — the middle segment
64225
+ * addresses an existing element and never adds one, so with nothing to address it fails
64226
+ * here rather than silently minting an element. */
64227
+ validateFreshSpine(e3) {
64228
+ for (let c3 = this.spineChild(e3.value); c3 !== null; c3 = this.spineChild(c3.value)) {
64229
+ if (c3.key === null && c3.nullKey !== true && this.spineChild(c3.value) !== null) {
64230
+ this.fail('a middle "-" segment addresses the LAST keyless element - none exists here');
64231
+ }
64232
+ }
64233
+ }
64234
+ /** The next flat segment of a spine, when the fold continues below `v` — a mapping whose
64235
+ * single entry wears the flat concrete. A continuation BLOCK's entries are first
64236
+ * segments of their own lines (unmarked), so the spine detection stops there. */
64237
+ spineChild(v) {
64238
+ if (isPointer(v) || v.kind !== "mapping") return null;
64239
+ const ents = v.entries ?? [];
64240
+ if (ents.length !== 1 || ents[0].meta?.keyConcrete !== "yamlover/key/flat") return null;
64241
+ if ((v.meta?.anchors ?? []).length > 0) return null;
64242
+ return ents[0];
64243
+ }
64244
+ /** Pave the spine's next segment INTO an existing node — the child-adding walk (a valued
64245
+ * scalar grows fields: the omni). Paving through a reference is refused: an edge is not
64246
+ * a node. */
64247
+ paveInto(t3, seg) {
64248
+ if (isPointer(t3.value)) this.fail("cannot pave through a reference - a pointer is an edge, not a node");
64249
+ const v = t3.value;
64250
+ if (v.kind === "blob") this.fail("cannot pave into a blob");
64251
+ if (v.entries === void 0) v.entries = [];
64252
+ if (!this.paveMerge(v.entries, seg)) v.entries.push(seg);
64253
+ const owned = v.entries.filter((x2) => x2.edge !== "back");
64254
+ v.array = owned.length > 0 && owned.every((x2) => x2.key === null && x2.nullKey !== true);
64255
+ }
64256
+ /** Land a flat row's PAYLOAD on the existing node it addressed — THE WRITE-ONCE LAW: a
64257
+ * scalar value may change only while the node is null-valued AND childless. A block
64258
+ * continuation is child-adding and merges (mergeCont enforces the one-value law). */
64259
+ paveValue(t3, val) {
64260
+ if (!isPointer(val) && val.kind === "mapping") {
64261
+ if (isPointer(t3.value)) this.fail("a reference is exclusive - it takes no continuation block");
64262
+ t3.value = this.mergeCont(t3.value, val);
64263
+ return;
64264
+ }
64265
+ const freshNull = !isPointer(val) && val.kind === "scalar" && val.value === null && (val.raw ?? "") === "" && (val.entries?.length ?? 0) === 0 && val.meta?.anchors === void 0 && val.meta?.schema === void 0;
64266
+ if (freshNull) return;
64267
+ if (isPointer(t3.value)) this.fail("the flat row would overwrite a reference - a value may land only on a null-valued, childless node (write-once)");
64268
+ const old = t3.value;
64269
+ const oldNull = old.kind === "scalar" && old.value === null && (old.raw ?? "") === "";
64270
+ const oldChildless = (old.entries?.length ?? 0) === 0;
64271
+ if (!oldNull || !oldChildless) {
64272
+ this.fail("the flat row would overwrite - a value may land only on a null-valued, childless node (write-once)");
64273
+ }
64274
+ const oldAnchors = old.meta?.anchors ?? [];
64275
+ t3.value = val;
64276
+ if (isPointer(val)) {
64277
+ if (oldAnchors.length > 0) this.fail("a reference is exclusive - it may not carry the bookmarks paved before it");
64278
+ t3.edge = "ref";
64279
+ } else if (oldAnchors.length > 0) {
64280
+ this.attachAnchors(val, oldAnchors);
64281
+ }
64282
+ }
63804
64283
  fail(msg) {
63805
64284
  const l2 = this.lines[this.i] ?? this.lines[this.i - 1];
63806
64285
  const where = l2 ? `${this.uri}:${l2.n + 1}` : this.uri;
@@ -63856,15 +64335,16 @@ var Block = class {
63856
64335
  for (; ; ) {
63857
64336
  const l2 = this.peek();
63858
64337
  if (!l2 || l2.indent !== indent) break;
64338
+ const lCol = l2.col ?? l2.indent;
63859
64339
  const startLineN = l2.n;
63860
- const startCol = l2.indent;
64340
+ const startCol = lCol;
63861
64341
  const startBlank = l2.blankBefore === true;
63862
64342
  let value;
63863
64343
  let entry;
63864
64344
  if (l2.text.startsWith("&")) {
63865
64345
  if (keylessOnly) break;
63866
64346
  this.i++;
63867
- let { rest, col } = { rest: l2.text, col: l2.indent };
64347
+ let { rest, col } = { rest: l2.text, col: lCol };
63868
64348
  while (rest.startsWith("&")) {
63869
64349
  const r2 = this.anchorToken(rest, l2.n, col);
63870
64350
  anchors.push(r2.anchor);
@@ -63891,22 +64371,26 @@ var Block = class {
63891
64371
  this.i++;
63892
64372
  const afterDash = l2.text.slice(mark);
63893
64373
  const lead = afterDash.length - afterDash.trimStart().length;
63894
- const contentCol = l2.indent + mark + lead;
64374
+ const contentCol = lCol + mark + lead;
63895
64375
  const rest = afterDash.trim();
63896
- if (rest === "") {
63897
- value = this.node(indent + 1) ?? nul();
64376
+ if (mark === 2 && this.flatTail(rest)) {
64377
+ this.i--;
64378
+ this.lines[this.i] = { indent: indent + 1, col: contentCol, text: rest, n: l2.n, flat: true, base: l2.base ?? indent };
64379
+ value = this.container(indent + 1);
64380
+ } else if (rest === "") {
64381
+ value = this.node((l2.base ?? indent) + 1) ?? nul();
63898
64382
  } else if (isSeqLine(rest, this.yaml) || !/^(!!<|\*|&)/.test(rest) && splitKV(rest)) {
63899
64383
  this.i--;
63900
64384
  this.lines[this.i] = { indent: contentCol, text: rest, n: l2.n };
63901
64385
  value = this.container(contentCol);
63902
64386
  } else {
63903
- value = this.valueAfter(rest, indent, l2.n, contentCol);
64387
+ value = this.valueAfter(rest, l2.base ?? indent, l2.n, contentCol);
63904
64388
  }
63905
64389
  entry = { key: null, edge: isPointer(value) ? "ref" : "contain", value };
63906
64390
  } else if (isBackSeqLine(l2.text)) {
63907
64391
  if (keylessOnly) break;
63908
64392
  this.i++;
63909
- const a2 = adv(l2.text, 2, l2.indent);
64393
+ const a2 = adv(l2.text, 2, lCol);
63910
64394
  const rest = a2.rest;
63911
64395
  if (!rest.startsWith("*")) this.fail('a "~-" entry needs a pointer value (the container that holds this node)');
63912
64396
  const ptr3 = parsePointer(rest.slice(1).trim());
@@ -63929,7 +64413,7 @@ var Block = class {
63929
64413
  /*allowBlock*/
63930
64414
  false,
63931
64415
  l2.n,
63932
- l2.indent
64416
+ lCol
63933
64417
  );
63934
64418
  if (isPointer(iv) || iv.kind !== "scalar") this.fail("unexpected content (expected an entry, an anchor, or a scalar value line)");
63935
64419
  v = iv;
@@ -63947,7 +64431,13 @@ var Block = class {
63947
64431
  back = true;
63948
64432
  rawKey = rawKey.slice(1);
63949
64433
  }
63950
- value = this.valueAfter(kv.rest, indent, l2.n, l2.indent + kv.restCol);
64434
+ if (!nullKey && !back && this.flatTail(kv.rest)) {
64435
+ this.i--;
64436
+ this.lines[this.i] = { indent: indent + 1, col: lCol + kv.restCol, text: kv.rest, n: l2.n, flat: true, base: l2.base ?? indent };
64437
+ value = this.container(indent + 1);
64438
+ } else {
64439
+ value = this.valueAfter(kv.rest, l2.base ?? indent, l2.n, lCol + kv.restCol);
64440
+ }
63951
64441
  if (nullKey) {
63952
64442
  entry = { key: null, nullKey: true, edge: isPointer(value) ? "ref" : "contain", value };
63953
64443
  } else {
@@ -63961,9 +64451,11 @@ var Block = class {
63961
64451
  }
63962
64452
  const endLine = this.lines[this.i - 1];
63963
64453
  const start = (this.lineStarts[startLineN] ?? 0) + startCol;
63964
- const end = endLine ? (this.lineStarts[endLine.n] ?? 0) + endLine.indent + endLine.text.length : start;
64454
+ const end = endLine ? (this.lineStarts[endLine.n] ?? 0) + (endLine.col ?? endLine.indent) + endLine.text.length : start;
63965
64455
  entry.meta = { ...entry.meta, span: { uri: this.uri, start, end }, ...startBlank ? { blankBefore: true } : {} };
63966
- entries.push(entry);
64456
+ if (l2.flat === true) entry.meta = { ...entry.meta, keyConcrete: "yamlover/key/flat" };
64457
+ if (l2.flat !== true && this.paveMerge(entries, entry)) {
64458
+ } else entries.push(entry);
63967
64459
  }
63968
64460
  const owned = entries.filter((e3) => e3.edge !== "back");
63969
64461
  const array = owned.length > 0 && owned.every((e3) => e3.key === null && e3.nullKey !== true);
@@ -64009,6 +64501,9 @@ var Block = class {
64009
64501
  }
64010
64502
  break;
64011
64503
  }
64504
+ if (anchors.length > 0 && rest.startsWith("*")) {
64505
+ this.fail("a reference is exclusive - no bookmark may share its row (a pointer is an edge, not a node)");
64506
+ }
64012
64507
  let value;
64013
64508
  if (/^[|>][+-]?\d*$/.test(rest)) {
64014
64509
  value = this.blockScalar(rest, parentIndent, srcLineN);
@@ -64849,9 +65344,9 @@ function loadBundledTaxonomy() {
64849
65344
  if (!dir) return cached = null;
64850
65345
  const defsRoot = walkTree(path.join(dir, "$defs"), { noGraft: true }).doc.root;
64851
65346
  const entries = [{ key: "$defs", edge: "contain", value: defsRoot }];
64852
- const tagsDir = path.join(dir, "tags");
64853
- if (fs.existsSync(tagsDir)) {
64854
- entries.push({ key: "tags", edge: "contain", value: walkTree(tagsDir, { noGraft: true }).doc.root });
65347
+ const ontosDir = path.join(dir, "ontos");
65348
+ if (fs.existsSync(ontosDir)) {
65349
+ entries.push({ key: "ontos", edge: "contain", value: walkTree(ontosDir, { noGraft: true }).doc.root });
64855
65350
  }
64856
65351
  const defs = defsMap(defsRoot);
64857
65352
  return cached = { node: { kind: "mapping", array: false, entries }, defs };
@@ -64916,17 +65411,17 @@ async function walkTreeAsync(absDir, opts = {}) {
64916
65411
  }
64917
65412
  return r2.value;
64918
65413
  }
64919
- var BUILTIN_TAG_SCHEMA = "type: object\nformat: x-yamlover-tag\nproperties:\n color:\n type: string\nadditionalProperties: *:: yamlover: $defs: tag\n";
65414
+ var BUILTIN_ONTO_SCHEMA = "type: variant\nformat: x-yamlover-onto\nmembers:\n color:\n type: string\nothers: *:: yamlover: $defs: onto\n";
64920
65415
  var BUILTIN_FRAGMENT_SCHEMA = "type: object\nformat: x-yamlover-fragment\n";
64921
65416
  var BUILTIN_ANNOTATION_SCHEMA = "type: variant\nformat: x-yamlover-annotation\n";
64922
- var BUILTIN_TAGS_BODY = '!!<*yamlover:$defs:tag>\ncolors: The palette\n yellow:\n color: "#f9e2af"\n green:\n color: "#a6e3a1"\n sky:\n color: "#89dceb"\n mauve:\n color: "#cba6f7"\n pink:\n color: "#f5c2e7"\n peach:\n color: "#fab387"\n';
65417
+ var BUILTIN_ONTOS_BODY = '!!<*yamlover:$defs:onto>\ncolors: The palette\n yellow:\n color: "#f9e2af"\n green:\n color: "#a6e3a1"\n sky:\n color: "#89dceb"\n mauve:\n color: "#cba6f7"\n pink:\n color: "#f5c2e7"\n peach:\n color: "#fab387"\n';
64923
65418
  var builtinTemplate = null;
64924
65419
  function builtinYamloverGraft() {
64925
65420
  builtinTemplate ??= {
64926
- tag: parseYamlover(BUILTIN_TAG_SCHEMA, "$defs/tag").root,
64927
- tags: parseYamlover(BUILTIN_TAGS_BODY, "tags/.yo/body.yo").root
65421
+ onto: parseYamlover(BUILTIN_ONTO_SCHEMA, "$defs/onto").root,
65422
+ ontos: parseYamlover(BUILTIN_ONTOS_BODY, "ontos/.yo/body.yo").root
64928
65423
  };
64929
- const tagCopy = structuredClone(builtinTemplate.tag);
65424
+ const tagCopy = structuredClone(builtinTemplate.onto);
64930
65425
  const fragCopy = parseYamlover(BUILTIN_FRAGMENT_SCHEMA, "$defs/fragment").root;
64931
65426
  const annCopy = parseYamlover(BUILTIN_ANNOTATION_SCHEMA, "$defs/annotation").root;
64932
65427
  const node = {
@@ -64940,16 +65435,16 @@ function builtinYamloverGraft() {
64940
65435
  kind: "mapping",
64941
65436
  array: false,
64942
65437
  entries: [
64943
- { key: "tag", edge: "contain", value: tagCopy },
65438
+ { key: "onto", edge: "contain", value: tagCopy },
64944
65439
  { key: "fragment", edge: "contain", value: fragCopy },
64945
65440
  { key: "annotation", edge: "contain", value: annCopy }
64946
65441
  ]
64947
65442
  }
64948
65443
  },
64949
- { key: "tags", edge: "contain", value: structuredClone(builtinTemplate.tags) }
65444
+ { key: "ontos", edge: "contain", value: structuredClone(builtinTemplate.ontos) }
64950
65445
  ]
64951
65446
  };
64952
- return { node, defs: /* @__PURE__ */ new Map([["tag", tagCopy], ["fragment", fragCopy], ["annotation", annCopy]]) };
65447
+ return { node, defs: /* @__PURE__ */ new Map([["onto", tagCopy], ["fragment", fragCopy], ["annotation", annCopy]]) };
64953
65448
  }
64954
65449
  function* walkTreeGen(absDir, opts = {}) {
64955
65450
  const ctx = { root: path2.resolve(absDir), opts, files: /* @__PURE__ */ new Map(), count: 0, open: opts.snapshot ? [] : void 0 };
@@ -64975,8 +65470,8 @@ function* walkTreeGen(absDir, opts = {}) {
64975
65470
  let node;
64976
65471
  if (fs2.existsSync(defsDir)) {
64977
65472
  const shared = [{ key: "$defs", edge: "contain", value: yield* dirNode(defsDir, ctx) }];
64978
- const tagsDir = path2.join(defsRoot, "tags");
64979
- if (fs2.existsSync(tagsDir)) shared.push({ key: "tags", edge: "contain", value: yield* dirNode(tagsDir, ctx) });
65473
+ const ontosDir = path2.join(defsRoot, "ontos");
65474
+ if (fs2.existsSync(ontosDir)) shared.push({ key: "ontos", edge: "contain", value: yield* dirNode(ontosDir, ctx) });
64980
65475
  node = { kind: "mapping", entries: shared, array: false };
64981
65476
  } else {
64982
65477
  const built = graftTaxonomy() ?? builtinYamloverGraft();
@@ -65058,7 +65553,7 @@ async function reindexPathAsync(store, absDir, cachedDoc, changedRel, opts = {})
65058
65553
  const yi = parts.indexOf(YAMLOVER_DIR);
65059
65554
  const dirSegs = yi >= 0 ? parts.slice(0, yi) : parts.slice(0, -1);
65060
65555
  if (dirSegs.length === 0) return null;
65061
- if (dirSegs[0] === "$defs" || dirSegs[0] === "tags") return null;
65556
+ if (dirSegs[0] === "$defs" || dirSegs[0] === "ontos") return null;
65062
65557
  let entries = cachedDoc.root.entries;
65063
65558
  let target = null;
65064
65559
  for (let d2 = 0; d2 < dirSegs.length; d2++) {
@@ -65230,18 +65725,45 @@ function readTracked(ctx, abs) {
65230
65725
  record(ctx, abs, hashBytes(bytes), stat.size, stat.mtimeMs);
65231
65726
  return bytes;
65232
65727
  }
65728
+ function parseClauses(plain) {
65729
+ const meta = { exact: {}, patterns: [] };
65730
+ let badPattern;
65731
+ const clause = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
65732
+ const p2 = plain;
65733
+ for (const src of [clause(p2?.properties), clause(p2?.members)]) {
65734
+ for (const [key, entry] of Object.entries(src)) {
65735
+ if (entry && typeof entry === "object" && entry.pattern) {
65736
+ try {
65737
+ meta.patterns.push({ re: new RegExp(key), entry });
65738
+ } catch {
65739
+ badPattern ??= key;
65740
+ }
65741
+ } else {
65742
+ meta.exact[key] = entry;
65743
+ }
65744
+ }
65745
+ }
65746
+ return { meta, badPattern };
65747
+ }
65748
+ function metaFor(meta, name) {
65749
+ if (!meta) return void 0;
65750
+ if (Object.prototype.hasOwnProperty.call(meta.exact, name)) return meta.exact[name];
65751
+ return meta.patterns.find((p2) => p2.re.test(name))?.entry;
65752
+ }
65233
65753
  function loadMeta(dir, ctx) {
65234
65754
  const file = path2.join(dir, YAMLOVER_DIR, "meta.yo");
65235
- if (!fs2.existsSync(file)) return { props: {} };
65755
+ if (!fs2.existsSync(file)) return { props: { exact: {}, patterns: [] } };
65236
65756
  try {
65237
65757
  const plain = toPlain(parseYamlover(readTracked(ctx, file).toString("utf8"), file).root);
65238
- const props = plain?.properties ?? {};
65239
- return { props: props && typeof props === "object" ? props : {} };
65758
+ const { meta, badPattern } = parseClauses(plain);
65759
+ if (badPattern !== void 0)
65760
+ return { props: meta, error: noteFileError(ctx, file, new Error(`pattern clause is not a valid regexp: ${badPattern}`)) };
65761
+ return { props: meta };
65240
65762
  } catch (e3) {
65241
- return { props: {}, error: noteFileError(ctx, file, e3) };
65763
+ return { props: { exact: {}, patterns: [] }, error: noteFileError(ctx, file, e3) };
65242
65764
  }
65243
65765
  }
65244
- function* dirNode(dir, ctx) {
65766
+ function* dirNode(dir, ctx, inherited) {
65245
65767
  const { props: meta, error: metaError } = loadMeta(dir, ctx);
65246
65768
  const overlay2 = overlayFile(dir);
65247
65769
  const consumesIndex = overlay2 !== null && path2.basename(overlay2) === INDEX_FILE;
@@ -65258,13 +65780,13 @@ function* dirNode(dir, ctx) {
65258
65780
  }
65259
65781
  continue;
65260
65782
  }
65261
- const child = yield* childNode(abs, meta[name], ctx);
65783
+ const child = yield* childNode(abs, metaFor(meta, name) ?? metaFor(inherited, name), ctx);
65262
65784
  entries.push({ key: name, edge: "contain", value: child });
65263
65785
  yield { done: ++ctx.count, path: rel(ctx, abs) };
65264
65786
  }
65265
65787
  ctx.open?.pop();
65266
65788
  const node = { kind: "mapping", entries, array: false };
65267
- const merged = applyMeta(applyBody(overlay2, node, ctx), meta);
65789
+ const merged = applyMeta(applyBody(overlay2, node, ctx), meta, inherited);
65268
65790
  return metaError && !merged.meta?.parseError ? { ...merged, meta: { ...merged.meta, parseError: metaError } } : merged;
65269
65791
  }
65270
65792
  function* yamloverDirNode(absYamlover, ctx) {
@@ -65288,9 +65810,16 @@ function* yamloverDirNode(absYamlover, ctx) {
65288
65810
  }
65289
65811
  function* childNode(abs, m, ctx) {
65290
65812
  const stat = fs2.statSync(abs);
65291
- if (stat.isDirectory()) return yield* dirNode(abs, ctx);
65813
+ if (stat.isDirectory()) {
65814
+ const nested = m && (m.members ?? m.properties) != null ? parseClauses(m).meta : void 0;
65815
+ return yield* dirNode(abs, ctx, nested);
65816
+ }
65292
65817
  const ext = path2.extname(abs).toLowerCase();
65293
65818
  const fmt = m?.format ?? EXT_FORMAT[ext] ?? null;
65819
+ if (m?.concrete) {
65820
+ const decoded = decodeConcrete(abs, m.concrete, m.format ?? null, stat, ctx);
65821
+ if (decoded) return decoded;
65822
+ }
65294
65823
  if (m?.type === "binary") return blob(abs, fmt ?? "application/octet-stream", ctx);
65295
65824
  if (fmt && (DOC_FORMATS[fmt] || TEXT_FORMATS.has(fmt))) {
65296
65825
  if (stat.size > MAX_DOC_BYTES) return blob(abs, fmt, ctx);
@@ -65301,10 +65830,59 @@ function* childNode(abs, m, ctx) {
65301
65830
  if (looksBinary(abs)) return blob(abs, "application/octet-stream", ctx);
65302
65831
  return parsedScalar(abs, ext, ctx);
65303
65832
  }
65304
- function applyMeta(node, meta) {
65833
+ function decodeConcrete(abs, concrete, format, stat, ctx) {
65834
+ const stamp = (n2) => ({ ...n2, meta: { ...n2.meta, concrete } });
65835
+ const lang = DOC_CONCRETES[concrete];
65836
+ if (lang) {
65837
+ if (stat.size > MAX_DOC_BYTES) return stamp(blob(abs, format ?? "application/octet-stream", ctx));
65838
+ return stamp(parsedDoc(abs, lang, ctx));
65839
+ }
65840
+ if (concrete === "base64") {
65841
+ return stamp(blob(abs, format ?? "application/octet-stream", ctx));
65842
+ }
65843
+ const codec = /^binary\/int(8|16|32|64)\/(le|be)$/.exec(concrete);
65844
+ if (codec) {
65845
+ const bytes = readTracked(ctx, abs);
65846
+ const width = Number(codec[1]) / 8;
65847
+ const le = codec[2] === "le";
65848
+ const refuse = (why) => stamp({
65849
+ ...blob(abs, format ?? "application/octet-stream", ctx),
65850
+ meta: { parseError: noteFileError(ctx, abs, new Error(`${concrete}: ${why}`)) }
65851
+ });
65852
+ if (bytes.length !== width) return refuse(`expected ${width} bytes, found ${bytes.length}`);
65853
+ const dv2 = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
65854
+ const value = width === 1 ? dv2.getInt8(0) : width === 2 ? dv2.getInt16(0, le) : width === 4 ? dv2.getInt32(0, le) : Number(dv2.getBigInt64(0, le));
65855
+ if (!Number.isSafeInteger(value)) return refuse("value exceeds the safe integer range");
65856
+ return stamp({
65857
+ kind: "scalar",
65858
+ value,
65859
+ raw: String(value),
65860
+ ...format ? { meta: { derivedFormat: format } } : {}
65861
+ });
65862
+ }
65863
+ if (concrete.startsWith("text/")) {
65864
+ let decoder;
65865
+ try {
65866
+ decoder = new TextDecoder(concrete.slice("text/".length), { fatal: false });
65867
+ } catch {
65868
+ return null;
65869
+ }
65870
+ if (stat.size > MAX_DOC_BYTES) return stamp(blob(abs, format ?? "text/plain", ctx));
65871
+ const text = decoder.decode(readTracked(ctx, abs));
65872
+ const span = decoder.encoding === "utf-8" ? { span: { uri: abs, start: 0, end: text.length } } : {};
65873
+ return stamp({
65874
+ kind: "scalar",
65875
+ value: text,
65876
+ raw: text,
65877
+ meta: { ...format ? { derivedFormat: format } : {}, ...span }
65878
+ });
65879
+ }
65880
+ return null;
65881
+ }
65882
+ function applyMeta(node, meta, inherited) {
65305
65883
  for (const e3 of node.entries ?? []) {
65306
65884
  if (e3.key == null || isPointer(e3.value)) continue;
65307
- const m = meta[e3.key];
65885
+ const m = metaFor(meta, e3.key) ?? metaFor(inherited, e3.key);
65308
65886
  if (!m) continue;
65309
65887
  if (m.uniqueItems) e3.value = { ...e3.value, meta: { ...e3.value.meta, set: true } };
65310
65888
  if (e3.value.kind === "blob") continue;
@@ -65327,7 +65905,7 @@ function blob(abs, format, ctx) {
65327
65905
  }
65328
65906
  function textScalar(abs, format, ctx) {
65329
65907
  const text = readTracked(ctx, abs).toString("utf8");
65330
- return { kind: "scalar", value: text, raw: text, meta: { derivedFormat: format } };
65908
+ return { kind: "scalar", value: text, raw: text, meta: { derivedFormat: format, span: { uri: abs, start: 0, end: text.length } } };
65331
65909
  }
65332
65910
  function parsedScalar(abs, ext, ctx) {
65333
65911
  const lang = ext === ".json" || ext === ".json5" || ext === ".json5p" ? "json5p" : ext === ".yaml" || ext === ".yml" ? "yaml" : "yamlover";
@@ -65387,14 +65965,17 @@ function applySchemas(root, defsRoot, builtinDefs) {
65387
65965
  }
65388
65966
  return { name: null, node: v };
65389
65967
  };
65390
- const isContainerSchema = (n2) => !!field(n2, "properties") || !!field(n2, "items") || !!field(n2, "allOf") || ["object", "variant", "mixed", "array"].includes(str(n2, "type") ?? "");
65391
- const OVERLAY_KEYS = /* @__PURE__ */ new Set(["yamlover-annotations", "yamlover-fragments"]);
65968
+ const isContainerSchema = (n2) => !!field(n2, "members") || !!field(n2, "others") || !!field(n2, "properties") || !!field(n2, "items") || !!field(n2, "allOf") || ["object", "variant", "omni", "mixed", "kseq", "array"].includes(str(n2, "type") ?? "");
65969
+ const OVERLAY_KEYS = /* @__PURE__ */ new Set(["yo"]);
65392
65970
  const elemIsContainer = (el) => el.kind === "mapping" || el.meta?.dirBacked === true || (el.entries ?? []).some((e3) => e3.key == null || !OVERLAY_KEYS.has(e3.key));
65393
- const applyItems = (inst, items, depth) => {
65971
+ const ordinalElems = (inst) => {
65972
+ const anchoredKeys = new Set(inst.meta?.anchored ?? []);
65973
+ return (inst.entries ?? []).filter((e3) => (e3.key == null || anchoredKeys.has(e3.key)) && !isPointer(e3.value) && e3.value.meta?.yo !== true && !(e3.value.meta?.schema && isPointer(e3.value.meta.schema)));
65974
+ };
65975
+ const applyItems = (inst, items, depth, skip = 0) => {
65394
65976
  const { node: itemsNode } = resolveSchema(items);
65395
65977
  const anyOf = itemsNode ? field(itemsNode, "anyOf") : null;
65396
- const anchoredKeys = new Set(inst.meta?.anchored ?? []);
65397
- const elems = (inst.entries ?? []).filter((e3) => (e3.key == null || anchoredKeys.has(e3.key)) && !isPointer(e3.value) && e3.value.meta?.yo !== true && !(e3.value.meta?.schema && isPointer(e3.value.meta.schema)));
65978
+ const elems = ordinalElems(inst).slice(skip);
65398
65979
  if (anyOf && !isPointer(anyOf) && anyOf.entries) {
65399
65980
  const branches = anyOf.entries.map((e3) => e3.value).map((b) => ({ ptr: b, ...resolveSchema(b) }));
65400
65981
  for (const e3 of elems) {
@@ -65411,22 +65992,33 @@ function applySchemas(root, defsRoot, builtinDefs) {
65411
65992
  const { name, node: s2 } = resolveSchema(schema);
65412
65993
  if (!s2 || isPointer(s2)) return;
65413
65994
  const stype = str(s2, "type");
65414
- const named = name && (stype === "object" || stype === "variant" || stype === "mixed" || !!field(s2, "allOf"));
65995
+ const named = name && (stype === "object" || stype === "variant" || stype === "omni" || stype === "mixed" || stype === "kseq" || !!field(s2, "allOf"));
65415
65996
  const fmt = str(s2, "format") ?? (named ? `x-yamlover-${name}` : null);
65416
65997
  if (fmt && !hasFormat(inst)) inst.meta = { ...inst.meta, derivedFormat: fmt };
65417
- if (stype === "object" || stype === "variant" || stype === "mixed" || stype === "array" || field(s2, "items")) {
65998
+ const members = field(s2, "members");
65999
+ const membersNode = members && !isPointer(members) ? members : null;
66000
+ const others = field(s2, "others");
66001
+ const keylessClauses = (membersNode?.entries ?? []).filter((e3) => e3.key == null).map((e3) => e3.value);
66002
+ if (stype === "object" || stype === "variant" || stype === "omni" || stype === "mixed" || stype === "kseq" || stype === "array" || membersNode || others || field(s2, "items")) {
65418
66003
  const props = field(s2, "properties");
65419
66004
  const addl = field(s2, "additionalProperties");
65420
66005
  for (const e3 of inst.entries ?? []) {
65421
66006
  if (e3.key == null || isPointer(e3.value)) continue;
65422
66007
  if (e3.value.meta?.schema && isPointer(e3.value.meta.schema)) continue;
65423
66008
  if (e3.value.meta?.yo === true) continue;
65424
- const declared = props && !isPointer(props) ? field(props, e3.key) : null;
65425
- const sub = declared ?? addl;
66009
+ const declared = (membersNode ? field(membersNode, e3.key) : null) ?? (props && !isPointer(props) ? field(props, e3.key) : null);
66010
+ const sub = declared ?? (others && !OVERLAY_KEYS.has(e3.key) ? others : null) ?? addl;
65426
66011
  if (sub) apply(e3.value, sub, depth + 1);
65427
66012
  }
65428
- const items = field(s2, "items");
65429
- if (items) applyItems(inst, items, depth);
66013
+ if (keylessClauses.length) {
66014
+ const elems = ordinalElems(inst);
66015
+ keylessClauses.forEach((cl, i2) => {
66016
+ const e3 = elems[i2];
66017
+ if (e3) apply(e3.value, cl, depth + 1);
66018
+ });
66019
+ }
66020
+ const sweep = others ?? field(s2, "items");
66021
+ if (sweep) applyItems(inst, sweep, depth, keylessClauses.length);
65430
66022
  }
65431
66023
  const allOf = field(s2, "allOf");
65432
66024
  if (allOf && !isPointer(allOf) && allOf.entries) {
@@ -65445,6 +66037,16 @@ function overlayFile(dir) {
65445
66037
  const index = path2.join(dir, INDEX_FILE);
65446
66038
  return fs2.existsSync(index) ? index : null;
65447
66039
  }
66040
+ function ownerNodePath(absRoot, relPath) {
66041
+ const parts = relPath.split("/");
66042
+ const base = parts[parts.length - 1];
66043
+ if (base === BODY_FILE && parts[parts.length - 2] === YAMLOVER_DIR && parts.length > 2) return parts.slice(0, -2).join("/");
66044
+ if (base === INDEX_FILE && parts.length > 1) {
66045
+ const dirRel = parts.slice(0, -1).join("/");
66046
+ if (overlayFile(path2.join(absRoot, dirRel)) === path2.join(absRoot, dirRel, INDEX_FILE)) return dirRel;
66047
+ }
66048
+ return relPath;
66049
+ }
65448
66050
  function applyBody(file, node, ctx) {
65449
66051
  if (file === null) return node;
65450
66052
  let bodyDoc;
@@ -65603,6 +66205,20 @@ var DOC_FORMATS = {
65603
66205
  "json5p/meta": "json5p",
65604
66206
  "json/schema": "json5p"
65605
66207
  };
66208
+ var DOC_CONCRETES = {
66209
+ "yamlover/stream": "yamlover",
66210
+ "yamlover/code": "yamlover",
66211
+ "yamlover/meta": "yamlover",
66212
+ "yaml/stream": "yaml",
66213
+ "yaml/code": "yaml",
66214
+ "yaml/meta": "yaml",
66215
+ "json/code": "json5p",
66216
+ "json5/code": "json5p",
66217
+ "json5p/code": "json5p",
66218
+ "json/meta": "json5p",
66219
+ "json5/meta": "json5p",
66220
+ "json5p/meta": "json5p"
66221
+ };
65606
66222
 
65607
66223
  // ../engine/ts/src/rewrite.ts
65608
66224
  import * as path3 from "node:path";
@@ -65832,11 +66448,35 @@ var Emitter2 = class {
65832
66448
  this.seqItem(e3.value, indent);
65833
66449
  } else {
65834
66450
  const head = (e3.edge === "back" ? "~" : "") + (authoredKey(e3) ?? keyText(e3.key)) + ":";
65835
- this.keyed(head, e3.value, indent);
66451
+ if (e3.edge !== "back" && this.canFold(e3.value) && ents.filter((s2) => s2.key === e3.key).length === 1) {
66452
+ for (const c3 of e3.value.entries) this.flatChild([head], c3, indent);
66453
+ } else {
66454
+ this.keyed(head, e3.value, indent);
66455
+ }
65836
66456
  }
65837
66457
  if (this.comments) this.emitTrailing(e3, indent, before);
65838
66458
  }
65839
66459
  }
66460
+ /** Can this value still emit as FLAT rows losslessly? Delegates to {@link emitsFlat}. */
66461
+ canFold(v) {
66462
+ return emitsFlat(v);
66463
+ }
66464
+ /** One FLAT segment: descend while the fold stays lossless, else emit the LEAF row — the
66465
+ * joined prefix through the ordinary pair machinery at the ROW's own indent, so the leaf's
66466
+ * continuation block lands ONE STEP under the row, exactly as a normal key's block would
66467
+ * (the one-step indentation law — flattening does real re-indentation work, it is never a
66468
+ * pure line fold). A keyless element with container content takes this leaf path too: the
66469
+ * trailing `-:` row plus its block — the only APPEND spelling (inline `-` before key
66470
+ * segments would read back as the MIDDLE address). */
66471
+ flatChild(prefix, e3, indent) {
66472
+ const seg = e3.key === null ? "-" : authoredKey(e3) ?? keyText(e3.key);
66473
+ const head = seg + ":";
66474
+ if (e3.key !== null && this.canFold(e3.value)) {
66475
+ for (const c3 of e3.value.entries) this.flatChild([...prefix, head], c3, indent);
66476
+ return;
66477
+ }
66478
+ this.keyed(prefix.join(" ") + " " + head, e3.value, indent);
66479
+ }
65840
66480
  /** A `trailing` comment rides the entry's line when the entry emitted a single line;
65841
66481
  * otherwise (a block scalar / nested block) it falls to its own line below — never lost. */
65842
66482
  emitTrailing(e3, indent, before) {
@@ -65903,14 +66543,14 @@ var Emitter2 = class {
65903
66543
  } else if (value.kind === "scalar") {
65904
66544
  const block = typeof value.value === "string" ? blockOf(value) : null;
65905
66545
  if (block !== null) {
65906
- const inner = indent + STEP2 + (kept.length > 0 ? STEP2 : 0);
66546
+ const inner = indent + STEP2 + (kept.length > 0 || this.anchorTokens(value).length > 0 ? STEP2 : 0);
65907
66547
  this.out.push(joinLine(pad + head, [...parts, block.header]));
65908
66548
  for (const l2 of block.lines) this.out.push(l2 === "" ? "" : " ".repeat(inner) + l2);
65909
66549
  } else {
65910
66550
  const tok = this.inline(
65911
66551
  value,
65912
66552
  /*needToken*/
65913
- kept.length > 0 || parts.length > 0
66553
+ kept.length > 0 || parts.length > 0 || value.value != null && this.anchorTokens(value).length > 0
65914
66554
  );
65915
66555
  this.out.push(joinLine(pad + head, tok === "" ? parts : [...parts, tok]));
65916
66556
  }
@@ -66043,6 +66683,26 @@ function schemaText(v) {
66043
66683
  function schemaTagToken(v) {
66044
66684
  return `!!<${schemaText(v)}>`;
66045
66685
  }
66686
+ function emitsFlat(v) {
66687
+ if (isPointer(v) || v.kind !== "mapping") return false;
66688
+ const m = v.meta ?? {};
66689
+ if (m.schema !== void 0 || m.set === true || m.yo === true || m.style !== void 0) return false;
66690
+ if (m.concrete !== void 0) return false;
66691
+ if ((m.anchors ?? []).length > 0 || (m.comments ?? []).length > 0) return false;
66692
+ const ents = v.entries ?? [];
66693
+ if (ents.length === 0) return false;
66694
+ const seen = /* @__PURE__ */ new Set();
66695
+ for (const e3 of ents) {
66696
+ if (e3.meta?.keyConcrete !== "yamlover/key/flat") return false;
66697
+ if (e3.nullKey === true || e3.edge !== "contain" && e3.edge !== "ref") return false;
66698
+ if ((e3.meta?.comments ?? []).length > 0 || e3.meta?.blankBefore === true) return false;
66699
+ if (e3.key !== null) {
66700
+ if (seen.has(e3.key)) return false;
66701
+ seen.add(e3.key);
66702
+ }
66703
+ }
66704
+ return true;
66705
+ }
66046
66706
  function leadingOf2(e3) {
66047
66707
  return (e3.meta?.comments ?? []).filter((c3) => c3.placement === "leading");
66048
66708
  }
@@ -66319,8 +66979,9 @@ function planRewrites(doc, edges, oldStore, newStore, opts = {}) {
66319
66979
  break;
66320
66980
  }
66321
66981
  }
66982
+ if (cPtr === null) cPtr = linkPtr(container);
66322
66983
  if (cPtr === null) {
66323
- miss("anchor container left the holder's document");
66984
+ miss("anchor container has no project-root spelling");
66324
66985
  continue;
66325
66986
  }
66326
66987
  const newBody = e3.label != null ? renderPointer(ptr2(cPtr.base, [...cPtr.steps, { sel: "key", name: e3.label }]), { spaced: false }) : renderPointer(cPtr, { spaced: false }) + ":-";
@@ -66347,30 +67008,13 @@ function planRewrites(doc, edges, oldStore, newStore, opts = {}) {
66347
67008
  const holder = mapPath(e3.holder);
66348
67009
  const docRoot = mapPath(e3.docRoot);
66349
67010
  const target = mapPath(e3.target.path);
66350
- let newPtr = null;
66351
- switch (e3.ptr.base.scope) {
66352
- case "link":
66353
- newPtr = linkPtr(target);
66354
- break;
66355
- case "document":
66356
- newPtr = under(target, docRoot) ? docPtr(docRoot, target) : null;
66357
- break;
66358
- case "current":
66359
- if (under(target, holder) && target !== holder) newPtr = ptr2({ scope: "current" }, stepsBelow(holder, target));
66360
- else if (under(target, docRoot)) newPtr = docPtr(docRoot, target);
66361
- break;
66362
- case "parent": {
66363
- const p2 = parentOf(holder);
66364
- if (p2 !== null && under(target, p2)) newPtr = ptr2({ scope: "parent" }, stepsBelow(p2, target));
66365
- else if (under(target, docRoot)) newPtr = docPtr(docRoot, target);
66366
- break;
66367
- }
66368
- }
67011
+ const newPtr = retarget(e3.ptr.base.scope, holder, docRoot, target) ?? linkPtr(target);
66369
67012
  if (newPtr === null) {
66370
- miss("target left the holder's document");
67013
+ miss("target has no project-root spelling");
66371
67014
  continue;
66372
67015
  }
66373
- const newRaw = renderPointer(newPtr);
67016
+ const spaced = e3.raw.includes(": ") || !e3.raw.includes(":");
67017
+ const newRaw = renderPointer(newPtr, { spaced });
66374
67018
  if (newRaw === e3.raw) continue;
66375
67019
  const token = isJson5pUri(span.uri) ? json5pToken(newRaw) : pointerToken(newRaw);
66376
67020
  const list = plan.edits.get(span.uri) ?? [];
@@ -66378,8 +67022,78 @@ function planRewrites(doc, edges, oldStore, newStore, opts = {}) {
66378
67022
  plan.edits.set(span.uri, list);
66379
67023
  plan.rewritten.push({ file: span.uri, from: e3.from, oldRaw: e3.raw, newRaw });
66380
67024
  }
67025
+ const groups = /* @__PURE__ */ new Map();
67026
+ for (const t3 of opts.textLinks ?? []) {
67027
+ if (t3.target === null || !under(t3.target, oldStore)) continue;
67028
+ const key = JSON.stringify([t3.span?.uri, t3.span?.start, t3.raw]);
67029
+ const g = groups.get(key);
67030
+ if (g) g.n++;
67031
+ else groups.set(key, { t: t3, n: 1 });
67032
+ }
67033
+ for (const { t: t3, n: n2 } of groups.values()) {
67034
+ const missLink = (reason) => {
67035
+ plan.unrewritten.push({ file: t3.span?.uri ?? t3.uri ?? "<unknown>", from: t3.from, raw: t3.raw, reason });
67036
+ };
67037
+ const holder = mapPath(t3.holder);
67038
+ const docRoot = mapPath(t3.docRoot);
67039
+ const target = mapPath(t3.target);
67040
+ const newPtr = retarget(t3.ptr.base.scope, holder, docRoot, target) ?? linkPtr(target);
67041
+ if (newPtr === null) {
67042
+ missLink("target has no project-root spelling");
67043
+ continue;
67044
+ }
67045
+ if (renderPointer(newPtr, { spaced: false }) === renderPointer(t3.ptr, { spaced: false })) continue;
67046
+ if (t3.anchor) {
67047
+ missLink("&-target link is stale \u2014 reserved spelling, not rewritten (annotations refactor TODO)");
67048
+ continue;
67049
+ }
67050
+ const spelling = "*" + renderPointer(newPtr, { spaced: false });
67051
+ if (t3.span === null || opts.read === void 0) {
67052
+ missLink("marklower prose link \u2014 no source span/reader (report only)");
67053
+ continue;
67054
+ }
67055
+ if (opts.root !== void 0 && path3.relative(opts.root, t3.span.uri).startsWith("..")) {
67056
+ missLink("source file is outside the served root (grafted)");
67057
+ continue;
67058
+ }
67059
+ let text;
67060
+ try {
67061
+ text = opts.read(t3.span.uri);
67062
+ } catch {
67063
+ missLink("source file unreadable");
67064
+ continue;
67065
+ }
67066
+ const slice = text.slice(t3.span.start, t3.span.end);
67067
+ const hits = linkTargets(slice).filter((h) => h.raw === t3.raw);
67068
+ if (hits.length === 0) {
67069
+ missLink("link token not found verbatim in source (folded or escaped)");
67070
+ continue;
67071
+ }
67072
+ const list = plan.edits.get(t3.span.uri) ?? [];
67073
+ for (const h of hits) list.push({ start: t3.span.start + h.targetStart, end: t3.span.start + h.targetEnd, text: spelling });
67074
+ plan.edits.set(t3.span.uri, list);
67075
+ const newRaw = t3.raw.slice(0, hits[0].targetStart - hits[0].start) + spelling + ")";
67076
+ plan.rewritten.push({ file: t3.span.uri, from: t3.from, oldRaw: t3.raw, newRaw });
67077
+ if (hits.length < n2) missLink(`only ${hits.length} of ${n2} occurrences found verbatim (folded or escaped)`);
67078
+ }
66381
67079
  return plan;
66382
67080
  }
67081
+ function retarget(scope, holder, docRoot, target) {
67082
+ switch (scope) {
67083
+ case "link":
67084
+ return linkPtr(target);
67085
+ case "document":
67086
+ return under(target, docRoot) ? docPtr(docRoot, target) : null;
67087
+ case "current":
67088
+ if (under(target, holder) && target !== holder) return ptr2({ scope: "current" }, stepsBelow(holder, target));
67089
+ return under(target, docRoot) ? docPtr(docRoot, target) : null;
67090
+ case "parent": {
67091
+ const p2 = parentOf(holder);
67092
+ if (p2 !== null && under(target, p2)) return ptr2({ scope: "parent" }, stepsBelow(p2, target));
67093
+ return under(target, docRoot) ? docPtr(docRoot, target) : null;
67094
+ }
67095
+ }
67096
+ }
66383
67097
  function applyEdits(text, edits) {
66384
67098
  const sorted = [...edits].sort((a2, b) => b.start - a2.start);
66385
67099
  for (let i2 = 1; i2 < sorted.length; i2++) {
@@ -66473,7 +67187,7 @@ function mv(absRoot, fromRel, toRel, opts = {}) {
66473
67187
  }
66474
67188
  const { doc } = walkTree(root, opts);
66475
67189
  const edges = resolveDocument(doc);
66476
- const plan = planRewrites(doc, edges, storeOf(relFrom), storeOf(relTo), { root });
67190
+ const plan = planRewrites(doc, edges, storeOf(relFrom), storeOf(relTo), { root, textLinks: scanTextLinks(doc), read: fileReader() });
66477
67191
  const editedFiles = [];
66478
67192
  for (const [uri, edits] of plan.edits) {
66479
67193
  fs3.writeFileSync(uri, applyEdits(fs3.readFileSync(uri, "utf8"), edits));
@@ -66481,15 +67195,88 @@ function mv(absRoot, fromRel, toRel, opts = {}) {
66481
67195
  }
66482
67196
  fs3.mkdirSync(path4.dirname(absTo), { recursive: true });
66483
67197
  fs3.renameSync(absFrom, absTo);
66484
- return { from: relFrom, to: relTo, rewritten: plan.rewritten, unrewritten: plan.unrewritten, editedFiles };
67198
+ const report = { from: relFrom, to: relTo, rewritten: plan.rewritten, unrewritten: plan.unrewritten, editedFiles };
67199
+ if (bodyOrdersChild(doc, relFrom)) {
67200
+ const r2 = relinkRenamed(absRoot, [{ from: storeOf(relFrom), to: storeOf(relTo) }], opts);
67201
+ report.rewritten = [...report.rewritten, ...r2.rewritten];
67202
+ const seen = new Set(report.unrewritten.map((u2) => JSON.stringify([u2.file, u2.from, u2.raw])));
67203
+ report.unrewritten = [...report.unrewritten, ...r2.unrewritten.filter((u2) => !seen.has(JSON.stringify([u2.file, u2.from, u2.raw])))];
67204
+ report.editedFiles = [.../* @__PURE__ */ new Set([...report.editedFiles, ...r2.editedFiles])];
67205
+ }
67206
+ return report;
67207
+ }
67208
+ function bodyOrdersChild(doc, relFrom) {
67209
+ const segs = relFrom.split("/");
67210
+ let node = doc.root;
67211
+ for (const s2 of segs.slice(0, -1)) {
67212
+ const e3 = node?.entries?.find((en) => en.key === s2);
67213
+ node = e3 !== void 0 && !isPointer(e3.value) ? e3.value : void 0;
67214
+ }
67215
+ const anchored = node?.meta?.anchored;
67216
+ return Array.isArray(anchored) && anchored.includes(segs[segs.length - 1]);
67217
+ }
67218
+ function fileReader() {
67219
+ const cache = /* @__PURE__ */ new Map();
67220
+ return (uri) => {
67221
+ let t3 = cache.get(uri);
67222
+ if (t3 === void 0) {
67223
+ t3 = fs3.readFileSync(uri, "utf8");
67224
+ cache.set(uri, t3);
67225
+ }
67226
+ return t3;
67227
+ };
66485
67228
  }
66486
67229
  function relinkMoved(absRoot, moved, opts = {}) {
66487
- return relinkRenamed(absRoot, moved.map((m) => ({ from: storeOf(m.from), to: storeOf(m.to) })), opts);
67230
+ const root = path4.resolve(absRoot);
67231
+ const pairs = coalesceMoved(root, collapseOwners(root, moved));
67232
+ return relinkRenamed(absRoot, pairs.map((m) => ({ from: storeOf(m.from), to: storeOf(m.to) })), opts);
67233
+ }
67234
+ function collapseOwners(root, moved) {
67235
+ return moved.map((m) => {
67236
+ const ownerTo = ownerNodePath(root, m.to);
67237
+ if (ownerTo === m.to) return m;
67238
+ const tail = m.to.slice(ownerTo.length);
67239
+ if (!m.from.endsWith(tail)) return m;
67240
+ return { from: m.from.slice(0, -tail.length), to: ownerTo };
67241
+ });
67242
+ }
67243
+ function coalesceMoved(root, pairs) {
67244
+ const m = new Map(pairs.map((p2) => [p2.from, p2.to]));
67245
+ for (let changed = true; changed; ) {
67246
+ changed = false;
67247
+ const groups = /* @__PURE__ */ new Map();
67248
+ for (const [from, to2] of m) {
67249
+ const pf = parentPath(from);
67250
+ const pt = parentPath(to2);
67251
+ if (pf === null || pt === null) continue;
67252
+ const k = pf + "\0" + pt;
67253
+ groups.set(k, [...groups.get(k) ?? [], { from, to: to2 }]);
67254
+ }
67255
+ for (const [k, g] of groups) {
67256
+ const [pf, pt] = k.split("\0");
67257
+ if (!g.every((e3) => baseName(e3.from) === baseName(e3.to))) continue;
67258
+ if (fs3.existsSync(path4.join(root, pf))) continue;
67259
+ for (const e3 of g) m.delete(e3.from);
67260
+ m.set(pf, pt);
67261
+ changed = true;
67262
+ break;
67263
+ }
67264
+ }
67265
+ return [...m].map(([from, to2]) => ({ from, to: to2 }));
67266
+ }
67267
+ function parentPath(rel2) {
67268
+ const i2 = rel2.lastIndexOf("/");
67269
+ return i2 < 0 ? null : rel2.slice(0, i2);
67270
+ }
67271
+ function baseName(rel2) {
67272
+ return rel2.slice(rel2.lastIndexOf("/") + 1);
66488
67273
  }
66489
67274
  function relinkRenamed(absRoot, moved, opts = {}) {
66490
67275
  const root = path4.resolve(absRoot);
66491
67276
  const { doc } = walkTree(root, opts);
66492
67277
  const edges = resolveDocument(doc);
67278
+ const textLinks = scanTextLinks(doc);
67279
+ const read2 = fileReader();
66493
67280
  const rewritten = [];
66494
67281
  const unrewritten = [];
66495
67282
  const merged = /* @__PURE__ */ new Map();
@@ -66501,7 +67288,7 @@ function relinkRenamed(absRoot, moved, opts = {}) {
66501
67288
  return nom !== null && under(nom, oldStore);
66502
67289
  });
66503
67290
  const shimmed = stale.map((e3) => ({ ...e3, target: { kind: "node", node: doc.root, path: nominalPath(doc, e3) } }));
66504
- const plan = planRewrites(doc, shimmed, oldStore, m.to, { root });
67291
+ const plan = planRewrites(doc, shimmed, oldStore, m.to, { root, textLinks, read: read2 });
66505
67292
  for (const [uri, edits] of plan.edits) merged.set(uri, [...merged.get(uri) ?? [], ...edits]);
66506
67293
  rewritten.push(...plan.rewritten);
66507
67294
  unrewritten.push(...plan.unrewritten);
@@ -66583,7 +67370,7 @@ var DEFAULT_SETTINGS = {
66583
67370
  uri: void 0,
66584
67371
  exports: [],
66585
67372
  annotations: ":annotations",
66586
- tags: ":tags",
67373
+ ontos: ":ontos",
66587
67374
  sidecars: "per-directory",
66588
67375
  width: void 0,
66589
67376
  theme: void 0
@@ -66597,7 +67384,7 @@ var DEFAULT_SETTINGS_SOURCE = `# .yo/settings.yo \u2014 project settings for thi
66597
67384
  !!<*yamlover:$defs:config>
66598
67385
 
66599
67386
  annotations: *:: annotations # create new annotations in :annotations
66600
- tags: *:: tags # create new tags in :tags
67387
+ ontos: *:: ontos # create new ontos in :ontos
66601
67388
  sidecars: per-directory # where derived thumbnail/crop blobs go (enum, not a path)
66602
67389
  # width: 100 # reading width (ch) for prose views; browser settings override it
66603
67390
  `;
@@ -66622,7 +67409,7 @@ function loadSettings(absRoot) {
66622
67409
  uri: uriSetting(valueAt(root, "uri")),
66623
67410
  exports: exportsSetting(valueAt(root, "exports")),
66624
67411
  annotations: locationSetting(valueAt(root, "annotations"), DEFAULT_SETTINGS.annotations),
66625
- tags: locationSetting(valueAt(root, "tags"), DEFAULT_SETTINGS.tags),
67412
+ ontos: locationSetting(valueAt(root, "ontos"), DEFAULT_SETTINGS.ontos),
66626
67413
  sidecars: sidecarLocation(valueAt(root, "sidecars"), DEFAULT_SETTINGS.sidecars),
66627
67414
  width: intSetting(valueAt(root, "width"), 20, 400),
66628
67415
  theme: enumSetting(valueAt(root, "theme"), ["dark", "light"])
@@ -67058,6 +67845,7 @@ function metaOk(s2, p2, t3) {
67058
67845
  case "boolean":
67059
67846
  return row.type === "scalar" && typeof row.value === "boolean";
67060
67847
  case "variant":
67848
+ case "omni":
67061
67849
  return row.type === "scalar" && hasOwnChild(s2, p2);
67062
67850
  default:
67063
67851
  return false;
@@ -67081,9 +67869,43 @@ function compact(xs) {
67081
67869
  return xs.filter((x2) => x2 !== null);
67082
67870
  }
67083
67871
 
67872
+ // src/server/link-check.ts
67873
+ import * as path7 from "node:path";
67874
+ function deadLinkDiagnostics(doc, store, dataRoot) {
67875
+ const out = [];
67876
+ for (const l2 of scanTextLinks(doc)) {
67877
+ if (l2.anchor) continue;
67878
+ if (l2.target === null) continue;
67879
+ if (store.node(l2.target) !== null) continue;
67880
+ out.push({
67881
+ code: "link/dead-target",
67882
+ severity: "warning",
67883
+ message: `prose link ${l2.raw} addresses ${l2.target}, which names no node`,
67884
+ path: l2.from,
67885
+ ...l2.uri ? { fsPath: path7.relative(dataRoot, l2.uri).split(path7.sep).join("/") } : {}
67886
+ });
67887
+ }
67888
+ return out;
67889
+ }
67890
+ function deadLinkTargets(doc, store) {
67891
+ const out = /* @__PURE__ */ new Set();
67892
+ for (const l2 of scanTextLinks(doc)) {
67893
+ if (l2.anchor || l2.target === null) continue;
67894
+ if (store.node(l2.target) === null) out.add(l2.target);
67895
+ }
67896
+ return [...out];
67897
+ }
67898
+ function logDeadLinks(found, log, max = 8) {
67899
+ for (const d2 of found.slice(0, max)) {
67900
+ log(`validate ${d2.severity}: ${d2.code} at ${d2.path ?? d2.fsPath ?? "?"} \u2014 ${d2.message}`);
67901
+ }
67902
+ if (found.length > max) log(`validate warning: link/dead-target \u2014 and ${found.length - max} more (GET /api/doctor lists all)`);
67903
+ }
67904
+
67084
67905
  // src/server/embed.ts
67085
67906
  var ANNOTATIONS_KEY = "yamlover-annotations";
67086
- var FRAGMENTS_KEY = "yamlover-fragments";
67907
+ var YO_KEY = "yo";
67908
+ var FRAGMENTS_SUBKEY = "fragments";
67087
67909
  var THUMBNAILS_KEY = "yamlover-thumbnails";
67088
67910
  var indentOf = (line) => {
67089
67911
  let i2 = 0;
@@ -67194,20 +68016,6 @@ function seqItemLines(lines, region, key) {
67194
68016
  }
67195
68017
  return { keyLine, items, end: trimBack(lines, end, region.hi) };
67196
68018
  }
67197
- function appendAnnotation(text, within, render) {
67198
- const lines = text.replace(/\n$/, "").split("\n");
67199
- appendAnnotationAt(lines, reachBody(lines, within), render);
67200
- return lines.join("\n") + "\n";
67201
- }
67202
- function appendAnnotationAt(lines, region, render) {
67203
- const seq = seqItemLines(lines, region, ANNOTATIONS_KEY);
67204
- if (!seq) {
67205
- const at = trimBack(lines, region.lo - 1, region.hi);
67206
- lines.splice(at, 0, `${" ".repeat(region.indent)}${ANNOTATIONS_KEY}:`, ...render(region.indent));
67207
- } else {
67208
- lines.splice(seq.end, 0, ...render(region.indent));
67209
- }
67210
- }
67211
68019
  function upsertMapEntry(text, within, mapKey, entryKey, render) {
67212
68020
  const lines = text.replace(/\n$/, "").split("\n");
67213
68021
  upsertMapEntryAt(lines, reachBody(lines, within), mapKey, entryKey, render);
@@ -67232,14 +68040,70 @@ function upsertMapEntryAt(lines, region, mapKey, entryKey, render) {
67232
68040
  }
67233
68041
  }
67234
68042
  function upsertFragment(text, within, slug, render) {
67235
- return upsertMapEntry(text, within, FRAGMENTS_KEY, slug, render);
68043
+ return upsertMapEntry(text, [...within, YO_KEY], FRAGMENTS_SUBKEY, slug, render);
68044
+ }
68045
+ function pruneEmptyKeyAt(lines, region, key) {
68046
+ const L2 = findKeyLine(lines, region.lo, region.hi, region.indent, key);
68047
+ if (L2 < 0) return false;
68048
+ const t3 = lines[L2].trim();
68049
+ if (t3 !== `${key}:` && t3 !== `${keyToken(key)}:`) return false;
68050
+ const body = bodyUnder(lines, L2, region.hi, region.indent);
68051
+ for (let i2 = body.lo; i2 < body.hi; i2++) if (isContentLine(lines[i2])) return false;
68052
+ lines.splice(L2, Math.max(1, body.hi - L2));
68053
+ return true;
67236
68054
  }
67237
- function upsertThumbnail(text, within, resKey, render) {
67238
- return upsertMapEntry(text, within, THUMBNAILS_KEY, resKey, render);
68055
+ var isBookmarkLine = (line) => line.trim().startsWith("&");
68056
+ function appendBookmarkAt(lines, region, tokens) {
68057
+ const at = trimBack(lines, region.lo - 1, region.hi);
68058
+ lines.splice(at, 0, ...tokens.map((t3) => `${" ".repeat(region.indent)}${t3}`));
67239
68059
  }
67240
- function annotationsRemain(text, within) {
68060
+ function appendBookmark(text, within, tokens) {
67241
68061
  const lines = text.replace(/\n$/, "").split("\n");
67242
- return annotationsRemainAt(lines, reachBody(lines, within));
68062
+ appendBookmarkAt(lines, reachBody(lines, within), tokens);
68063
+ return lines.join("\n") + "\n";
68064
+ }
68065
+ function removeBookmarkAt(lines, region, predicate) {
68066
+ let removed = false;
68067
+ for (; ; ) {
68068
+ const r2 = region();
68069
+ let hit = -1;
68070
+ for (let i2 = r2.lo; i2 < r2.hi; i2++) {
68071
+ if (isContentLine(lines[i2]) && indentOf(lines[i2]) === r2.indent && isBookmarkLine(lines[i2]) && predicate(lines[i2].trim())) {
68072
+ hit = i2;
68073
+ break;
68074
+ }
68075
+ }
68076
+ if (hit < 0) break;
68077
+ lines.splice(hit, 1);
68078
+ removed = true;
68079
+ }
68080
+ return removed;
68081
+ }
68082
+ function removeBookmark(text, within, predicate) {
68083
+ const lines = text.replace(/\n$/, "").split("\n");
68084
+ const region = findBody(lines, within);
68085
+ if (!region) return text;
68086
+ return removeBookmarkAt(lines, () => findBody(lines, within) ?? region, predicate) ? lines.join("\n") + "\n" : text;
68087
+ }
68088
+ function bookmarksRemainAt(lines, region) {
68089
+ for (let i2 = region.lo; i2 < region.hi; i2++) {
68090
+ if (isContentLine(lines[i2]) && indentOf(lines[i2]) === region.indent && isBookmarkLine(lines[i2])) return true;
68091
+ }
68092
+ return false;
68093
+ }
68094
+ function bookmarksRemain(text, within) {
68095
+ const lines = text.replace(/\n$/, "").split("\n");
68096
+ const region = findBody(lines, within);
68097
+ return region !== null && bookmarksRemainAt(lines, region);
68098
+ }
68099
+ function pruneEmptyYo(text, within) {
68100
+ const lines = text.replace(/\n$/, "").split("\n");
68101
+ const region = findBody(lines, within);
68102
+ if (!region) return text;
68103
+ return pruneEmptyKeyAt(lines, region, YO_KEY) ? lines.join("\n") + "\n" : text;
68104
+ }
68105
+ function upsertThumbnail(text, within, resKey, render) {
68106
+ return upsertMapEntry(text, within, THUMBNAILS_KEY, resKey, render);
67243
68107
  }
67244
68108
  function annotationsRemainAt(lines, region) {
67245
68109
  const seq = seqItemLines(lines, region, ANNOTATIONS_KEY);
@@ -67304,27 +68168,6 @@ function removeMapEntryAt(lines, region, mapKey, entryKey) {
67304
68168
  if (!hasChild) lines.splice(mapLine, blockEnd(lines, mapLine + 1, lines.length, region.indent + 1) - mapLine);
67305
68169
  return true;
67306
68170
  }
67307
- function removeAnnotation(text, within, predicate) {
67308
- const lines = text.replace(/\n$/, "").split("\n");
67309
- return removeAnnotationAt(lines, () => reachBody(lines, within), predicate) ? lines.join("\n") + "\n" : text;
67310
- }
67311
- function removeAnnotationAt(lines, region, predicate) {
67312
- let removed = false;
67313
- for (; ; ) {
67314
- const seq = seqItemLines(lines, region(), ANNOTATIONS_KEY);
67315
- if (!seq) break;
67316
- const k = seq.items.findIndex((i3) => {
67317
- const t3 = lines[i3].trim();
67318
- return predicate(stripSeqMark(t3) ?? t3);
67319
- });
67320
- if (k < 0) break;
67321
- const i2 = seq.items[k];
67322
- const next = k + 1 < seq.items.length ? seq.items[k + 1] : seq.end;
67323
- lines.splice(i2, next - i2);
67324
- removed = true;
67325
- }
67326
- return removed;
67327
- }
67328
68171
 
67329
68172
  // src/concrete.ts
67330
68173
  var OVERLAY_DIR = ".yo";
@@ -67415,7 +68258,7 @@ var psdExtractor = {
67415
68258
 
67416
68259
  // src/server/extract/wasm.ts
67417
68260
  import fs8 from "node:fs";
67418
- import path8 from "node:path";
68261
+ import path9 from "node:path";
67419
68262
  import { fileURLToPath as fileURLToPath2 } from "node:url";
67420
68263
  import { createRequire } from "node:module";
67421
68264
  var require2 = createRequire(import.meta.url);
@@ -67424,7 +68267,7 @@ async function loadWasm(npmSpecifier, prodFile) {
67424
68267
  try {
67425
68268
  bytes = fs8.readFileSync(require2.resolve(npmSpecifier));
67426
68269
  } catch {
67427
- bytes = fs8.readFileSync(path8.join(path8.dirname(fileURLToPath2(import.meta.url)), "wasm", prodFile));
68270
+ bytes = fs8.readFileSync(path9.join(path9.dirname(fileURLToPath2(import.meta.url)), "wasm", prodFile));
67428
68271
  }
67429
68272
  return WebAssembly.compile(new Uint8Array(bytes));
67430
68273
  }
@@ -67496,7 +68339,7 @@ async function renderThumbnail(bytes, format, w, h) {
67496
68339
  // src/server/gitignore.ts
67497
68340
  var import_ignore = __toESM(require_ignore(), 1);
67498
68341
  import fs9 from "node:fs";
67499
- import path9 from "node:path";
68342
+ import path10 from "node:path";
67500
68343
  function buildGitIgnore(dataRoot) {
67501
68344
  const gitRoot = findGitRoot(dataRoot) ?? dataRoot;
67502
68345
  const cache = /* @__PURE__ */ new Map();
@@ -67504,7 +68347,7 @@ function buildGitIgnore(dataRoot) {
67504
68347
  if (!cache.has(dir)) {
67505
68348
  let ig = null;
67506
68349
  try {
67507
- const gi = path9.join(dir, ".gitignore");
68350
+ const gi = path10.join(dir, ".gitignore");
67508
68351
  if (fs9.statSync(gi).isFile()) ig = (0, import_ignore.default)().add(fs9.readFileSync(gi, "utf-8"));
67509
68352
  } catch {
67510
68353
  }
@@ -67513,25 +68356,25 @@ function buildGitIgnore(dataRoot) {
67513
68356
  return cache.get(dir);
67514
68357
  };
67515
68358
  return (absPath) => {
67516
- const fromRoot = path9.relative(gitRoot, absPath);
67517
- if (fromRoot === ".git" || fromRoot.startsWith(".git" + path9.sep)) return true;
68359
+ const fromRoot = path10.relative(gitRoot, absPath);
68360
+ if (fromRoot === ".git" || fromRoot.startsWith(".git" + path10.sep)) return true;
67518
68361
  let isDir = false;
67519
68362
  try {
67520
68363
  isDir = fs9.statSync(absPath).isDirectory();
67521
68364
  } catch {
67522
68365
  }
67523
- const rel2 = path9.relative(gitRoot, path9.dirname(absPath));
67524
- const segs = rel2 === "" ? [] : rel2.split(path9.sep);
68366
+ const rel2 = path10.relative(gitRoot, path10.dirname(absPath));
68367
+ const segs = rel2 === "" ? [] : rel2.split(path10.sep);
67525
68368
  let dir = gitRoot;
67526
68369
  const dirs = [gitRoot];
67527
68370
  for (const s2 of segs) {
67528
- dir = path9.join(dir, s2);
68371
+ dir = path10.join(dir, s2);
67529
68372
  dirs.push(dir);
67530
68373
  }
67531
68374
  for (const d2 of dirs) {
67532
68375
  const ig = matcherFor(d2);
67533
68376
  if (!ig) continue;
67534
- const relToDir = path9.relative(d2, absPath);
68377
+ const relToDir = path10.relative(d2, absPath);
67535
68378
  if (!relToDir) continue;
67536
68379
  if (ig.ignores(relToDir) || isDir && ig.ignores(relToDir + "/")) return true;
67537
68380
  }
@@ -67539,15 +68382,15 @@ function buildGitIgnore(dataRoot) {
67539
68382
  };
67540
68383
  }
67541
68384
  function findGitRoot(start) {
67542
- let dir = path9.resolve(start);
68385
+ let dir = path10.resolve(start);
67543
68386
  try {
67544
- if (!fs9.statSync(dir).isDirectory()) dir = path9.dirname(dir);
68387
+ if (!fs9.statSync(dir).isDirectory()) dir = path10.dirname(dir);
67545
68388
  } catch {
67546
68389
  return null;
67547
68390
  }
67548
68391
  for (; ; ) {
67549
- if (fs9.existsSync(path9.join(dir, ".git"))) return dir;
67550
- const parent = path9.dirname(dir);
68392
+ if (fs9.existsSync(path10.join(dir, ".git"))) return dir;
68393
+ const parent = path10.dirname(dir);
67551
68394
  if (parent === dir) return null;
67552
68395
  dir = parent;
67553
68396
  }
@@ -67888,7 +68731,10 @@ var UNSAFE_SEG = /[\\/:*?"<>|]/;
67888
68731
  var hasControlChar = (s2) => [...s2].some((c3) => c3.charCodeAt(0) < 32);
67889
68732
  var ITEM_NAME = /^item\d+(?:-\d+)*$/;
67890
68733
  var TITLE_NAME = /^\d+(?:-\d+)*(?:-.*)?$/;
67891
- var DEFAULT_SEVERITY = { "layout/off-scheme-name": "warning" };
68734
+ var DEFAULT_SEVERITY = {
68735
+ "layout/off-scheme-name": "warning",
68736
+ "link/dead-target": "warning"
68737
+ };
67892
68738
  var d = (code, message, where) => ({
67893
68739
  code,
67894
68740
  severity: DEFAULT_SEVERITY[code] ?? "error",
@@ -68195,12 +69041,21 @@ function displayKind(s2, p2, row) {
68195
69041
  if (anchored.size) return ents.some((e3) => !isOrdinalEntry(anchored, e3.label)) ? "mix" : "array";
68196
69042
  return ents.some((e3) => e3.label === null) ? "mix" : "object";
68197
69043
  }
69044
+ function cubeName(f2, empty) {
69045
+ const v = f2.valueType !== null;
69046
+ if (v && f2.hasKeyed && f2.hasOrdinal) return "omni";
69047
+ if (v && f2.hasKeyed) return "vmap";
69048
+ if (v && f2.hasOrdinal) return "vseq";
69049
+ if (f2.hasKeyed && f2.hasOrdinal) return "kseq";
69050
+ if (f2.hasKeyed) return "map";
69051
+ if (f2.hasOrdinal) return "seq";
69052
+ return empty;
69053
+ }
68198
69054
  function typeName(s2, p2, row) {
68199
69055
  const k = displayKind(s2, p2, row);
68200
69056
  if (k === "scalar") return scalarType(row.value);
68201
- if (k === "mix") return "mixed";
68202
- if (k === "omni") return "variant";
68203
- return k;
69057
+ if (k === "binary") return "binary";
69058
+ return cubeName(facetsOf(s2, p2, row), row.is_array ? "seq" : "map");
68204
69059
  }
68205
69060
  function scalarType(v) {
68206
69061
  if (v === null) return "null";
@@ -68285,10 +69140,10 @@ var REF_KEY = "$yamloverRef";
68285
69140
  var NUM_KEY = "$yamloverNum";
68286
69141
  var wireScalar = (v) => typeof v === "number" && !Number.isFinite(v) ? { [NUM_KEY]: String(v) } : v;
68287
69142
  function createHandlers(dataRoot, opts = {}) {
68288
- const rootName = path10.basename(path10.resolve(dataRoot)) || "/";
68289
- const dbPath = path10.join(dataRoot, ".yo", "index.db");
68290
- const settingsFile = path10.join(dataRoot, ".yo", "settings.yo");
68291
- const settingsRel = path10.relative(dataRoot, settingsFile).split(path10.sep).join("/");
69143
+ const rootName = path11.basename(path11.resolve(dataRoot)) || "/";
69144
+ const dbPath = path11.join(dataRoot, ".yo", "index.db");
69145
+ const settingsFile = path11.join(dataRoot, ".yo", "settings.yo");
69146
+ const settingsRel = path11.relative(dataRoot, settingsFile).split(path11.sep).join("/");
68292
69147
  if (opts.ensureSettings) {
68293
69148
  try {
68294
69149
  ensureSettingsFile(dataRoot);
@@ -68299,7 +69154,7 @@ function createHandlers(dataRoot, opts = {}) {
68299
69154
  }
68300
69155
  let settings = loadSettings(dataRoot);
68301
69156
  const ignore2 = opts.gitignore === false ? void 0 : buildGitIgnore(dataRoot);
68302
- mkdirInside(dataRoot, path10.dirname(dbPath), { recursive: true });
69157
+ mkdirInside(dataRoot, path11.dirname(dbPath), { recursive: true });
68303
69158
  const store0 = new Store(dbPath);
68304
69159
  const store = () => store0;
68305
69160
  let cachedDoc = null;
@@ -68410,7 +69265,7 @@ function createHandlers(dataRoot, opts = {}) {
68410
69265
  const next = pending[0];
68411
69266
  const total = done + pending.length;
68412
69267
  h.progress(done, total, next.path);
68413
- const abs = path10.join(dataRoot, ...next.path.split("/"));
69268
+ const abs = path11.join(dataRoot, ...next.path.split("/"));
68414
69269
  const big = next.size >= BIG_FILE_BYTES;
68415
69270
  if (big) log(`hashing ${next.path} (${gib(next.size)} GiB)\u2026`);
68416
69271
  const tFile = Date.now();
@@ -68451,7 +69306,7 @@ function createHandlers(dataRoot, opts = {}) {
68451
69306
  };
68452
69307
  const doReindexFile = async (absFile) => {
68453
69308
  if (cachedDoc) {
68454
- const rel2 = path10.relative(dataRoot, absFile).split(path10.sep).join("/");
69309
+ const rel2 = path11.relative(dataRoot, absFile).split(path11.sep).join("/");
68455
69310
  try {
68456
69311
  const res = await reindexPathAsync(store0, dataRoot, cachedDoc, rel2, walkOpts);
68457
69312
  if (res) {
@@ -68481,6 +69336,7 @@ function createHandlers(dataRoot, opts = {}) {
68481
69336
  cachedDoc = doc;
68482
69337
  h.done();
68483
69338
  log(`${label}: +${diff2.added.length} ~${diff2.changed.length} \u2212${diff2.removed.length} \u2192${diff2.moved.length}`);
69339
+ logDeadLinks(deadLinkDiagnostics(doc, store0, dataRoot), log);
68484
69340
  broadcast(diff2);
68485
69341
  scheduleHasher();
68486
69342
  return diff2;
@@ -68492,7 +69348,7 @@ function createHandlers(dataRoot, opts = {}) {
68492
69348
  const SELF_WRITE_TTL_MS = 5e3;
68493
69349
  const selfWrites = /* @__PURE__ */ new Map();
68494
69350
  const noteSelfWrite = (absFile) => {
68495
- selfWrites.set(path10.relative(dataRoot, absFile).split(path10.sep).join("/"), Date.now());
69351
+ selfWrites.set(path11.relative(dataRoot, absFile).split(path11.sep).join("/"), Date.now());
68496
69352
  if (selfWrites.size > 1e3) {
68497
69353
  const cutoff = Date.now() - SELF_WRITE_TTL_MS;
68498
69354
  for (const [k, t3] of selfWrites) if (t3 < cutoff) selfWrites.delete(k);
@@ -68516,6 +69372,7 @@ function createHandlers(dataRoot, opts = {}) {
68516
69372
  }
68517
69373
  h.done();
68518
69374
  log(`reconcile: +${diff2.added.length} ~${diff2.changed.length} \u2212${diff2.removed.length} \u2192${diff2.moved.length}`);
69375
+ if (cachedDoc) logDeadLinks(deadLinkDiagnostics(cachedDoc, store0, dataRoot), log);
68519
69376
  broadcast(diff2);
68520
69377
  scheduleHasher();
68521
69378
  return diff2;
@@ -68530,7 +69387,7 @@ function createHandlers(dataRoot, opts = {}) {
68530
69387
  const spuriousEvent = (rel2) => {
68531
69388
  const rec = store0.file(rel2);
68532
69389
  if (!rec) return false;
68533
- const st = fs10.statSync(path10.join(dataRoot, ...rel2.split("/")), { throwIfNoEntry: false });
69390
+ const st = fs10.statSync(path11.join(dataRoot, ...rel2.split("/")), { throwIfNoEntry: false });
68534
69391
  if (!st || !st.isFile()) return false;
68535
69392
  return st.size === rec.size && st.mtimeMs === rec.mtimeMs;
68536
69393
  };
@@ -68573,7 +69430,17 @@ function createHandlers(dataRoot, opts = {}) {
68573
69430
  if (url.pathname === "/api/doctor") {
68574
69431
  try {
68575
69432
  const v = validateTree(scanTree(dataRoot, ignore2));
68576
- sendJson(res, 200, { allowed: v.allowed, diagnostics: v.diagnostics });
69433
+ const doc = cachedDoc ?? walkTree(dataRoot, walkOpts).doc;
69434
+ sendJson(res, 200, { allowed: v.allowed, diagnostics: [...v.diagnostics, ...deadLinkDiagnostics(doc, s2, dataRoot)] });
69435
+ } catch (e3) {
69436
+ sendJson(res, 500, { error: String(e3.message || e3) });
69437
+ }
69438
+ return;
69439
+ }
69440
+ if (url.pathname === "/api/dead-links") {
69441
+ try {
69442
+ const doc = cachedDoc ?? walkTree(dataRoot, walkOpts).doc;
69443
+ sendJson(res, 200, { targets: deadLinkTargets(doc, s2) });
68577
69444
  } catch (e3) {
68578
69445
  sendJson(res, 500, { error: String(e3.message || e3) });
68579
69446
  }
@@ -68653,7 +69520,7 @@ function createHandlers(dataRoot, opts = {}) {
68653
69520
  throw new Error("annotation needs a `tag` naming an existing node");
68654
69521
  }
68655
69522
  if (tagSegs.length === 0) throw new Error("the root cannot be a tag");
68656
- const bodyFile = embedAnnotation(dataRoot, s2, a2);
69523
+ const bodyFile = embedAnnotation(dataRoot, s2, settings.sidecars, a2);
68657
69524
  broadcast(await doReindexFile(bodyFile));
68658
69525
  scheduleHasher();
68659
69526
  return { ok: true };
@@ -68677,9 +69544,16 @@ function createHandlers(dataRoot, opts = {}) {
68677
69544
  if (req.method === "DELETE" && url.pathname === "/api/annotate") {
68678
69545
  const target = url.searchParams.get("target") ?? "";
68679
69546
  const tag = url.searchParams.get("tag") || "";
69547
+ const selRaw = url.searchParams.get("selector");
69548
+ let sel;
69549
+ try {
69550
+ sel = selRaw ? JSON.parse(selRaw) : void 0;
69551
+ } catch {
69552
+ sel = void 0;
69553
+ }
68680
69554
  enqueue(async () => {
68681
69555
  if (!tag) throw new Error("delete needs a `tag`");
68682
- const bodyFile = unembedAnnotation(dataRoot, s2, target, tag);
69556
+ const bodyFile = unembedAnnotation(dataRoot, s2, target, tag, sel);
68683
69557
  broadcast(await doReindexFile(bodyFile));
68684
69558
  }).then(() => sendJson(res, 200, { ok: true })).catch((e3) => sendJson(res, 400, { error: String(e3.message || e3) }));
68685
69559
  return;
@@ -68689,17 +69563,17 @@ function createHandlers(dataRoot, opts = {}) {
68689
69563
  (data) => enqueue(async () => {
68690
69564
  const name = String(data?.name ?? "").trim();
68691
69565
  if (!name) throw new Error("tag needs a non-empty name");
68692
- const segs2 = [...strToSegs(settings.tags), name];
69566
+ const segs2 = [...strToSegs(settings.ontos), name];
68693
69567
  const tagPath = segsToStr(segs2);
68694
69568
  const existing = s2.node(storePath(segs2));
68695
69569
  if (existing) {
68696
- if (existing.format !== TAG_FORMAT) throw new Error(`a node already exists at ${tagPath} and is not a tag`);
69570
+ if (existing.format !== ONTO_FORMAT) throw new Error(`a node already exists at ${tagPath} and is not a tag`);
68697
69571
  const color = s2.node(storePath(segs2) + ":color")?.value;
68698
69572
  return { path: tagPath, name, color: typeof color === "string" ? color : null, created: false };
68699
69573
  }
68700
- const written = writeTag(dataRoot, s2, settings.tags, name);
68701
- s2.addTag(storePath(strToSegs(settings.tags)), name, written.pos, written.node);
68702
- if (s2.node(storePath(segs2))?.format !== TAG_FORMAT) throw new Error(`the created tag did not index as a tag: ${tagPath}`);
69574
+ const written = writeOnto(dataRoot, s2, settings.ontos, name);
69575
+ s2.addOnto(storePath(strToSegs(settings.ontos)), name, written.pos, written.node);
69576
+ if (s2.node(storePath(segs2))?.format !== ONTO_FORMAT) throw new Error(`the created tag did not index as a tag: ${tagPath}`);
68703
69577
  await doReindexFile(written.file);
68704
69578
  announce(written.createdFile ? { added: [written.file] } : { changed: [written.file] });
68705
69579
  return { path: tagPath, name, color: null, created: true };
@@ -68713,7 +69587,7 @@ function createHandlers(dataRoot, opts = {}) {
68713
69587
  const b = data;
68714
69588
  const lanes = Array.isArray(b?.lanes) ? b.lanes.map((lane) => Array.isArray(lane) ? lane.map((p3) => String(p3)) : []) : [];
68715
69589
  const { bodyFile } = hostFor(dataRoot, s2, strToSegs(b?.path || ":"));
68716
- mkdirInside(dataRoot, path10.dirname(bodyFile), { recursive: true });
69590
+ mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
68717
69591
  const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
68718
69592
  writeBody(dataRoot, s2, bodyFile, writeBoardLanes(src, lanes));
68719
69593
  broadcast(await doReindex());
@@ -68867,7 +69741,7 @@ function createHandlers(dataRoot, opts = {}) {
68867
69741
  const oldKey = String(segs2[segs2.length - 1]);
68868
69742
  if (newKey === oldKey) return { path: reqPath, unchanged: true };
68869
69743
  if (s2.node(storePath([...parentSegs, newKey]))) throw new Error(`the key \`${newKey}\` already exists in the node`);
68870
- const abs = segs2.every((g) => typeof g === "string") ? path10.resolve(dataRoot, ...segs2.map(String)) : null;
69744
+ const abs = segs2.every((g) => typeof g === "string") ? path11.resolve(dataRoot, ...segs2.map(String)) : null;
68871
69745
  if (abs && fs10.existsSync(abs)) {
68872
69746
  const from = segs2.map(String).join("/");
68873
69747
  const to2 = [...parentSegs.map(String), newKey].join("/");
@@ -68896,7 +69770,7 @@ function createHandlers(dataRoot, opts = {}) {
68896
69770
  const files = [];
68897
69771
  let wrote = false;
68898
69772
  for (const doc of loadAgentDocs()) {
68899
- const target = path10.resolve(dataRoot, doc.name);
69773
+ const target = path11.resolve(dataRoot, doc.name);
68900
69774
  const existing = fs10.existsSync(target) ? fs10.readFileSync(target, "utf8") : null;
68901
69775
  const { text, status } = mergeAgentDoc(existing, doc.content);
68902
69776
  if (status !== "exists") {
@@ -68943,7 +69817,7 @@ function createHandlers(dataRoot, opts = {}) {
68943
69817
  return;
68944
69818
  }
68945
69819
  if (url.pathname === "/api/blob") {
68946
- const file = path10.join(dataRoot, ...segs.map(String));
69820
+ const file = path11.join(dataRoot, ...segs.map(String));
68947
69821
  if (!fs10.existsSync(file) || fs10.statSync(file).isDirectory()) return notFound(res, url);
68948
69822
  res.statusCode = 200;
68949
69823
  res.setHeader("Content-Type", blobContentType(s2.node(p2)?.format ?? formatFromExt(file)));
@@ -68955,7 +69829,7 @@ function createHandlers(dataRoot, opts = {}) {
68955
69829
  }
68956
69830
  if (url.pathname === "/api/thumb") {
68957
69831
  const sourceRow = s2.node(p2);
68958
- const sourceAbs = path10.join(dataRoot, ...segs.map(String));
69832
+ const sourceAbs = path11.join(dataRoot, ...segs.map(String));
68959
69833
  if (!sourceRow || !fs10.existsSync(sourceAbs) || fs10.statSync(sourceAbs).isDirectory()) return notFound(res, url);
68960
69834
  const w = clampThumbDim(url.searchParams.get("w"), 256);
68961
69835
  const h = clampThumbDim(url.searchParams.get("h"), w);
@@ -69033,17 +69907,17 @@ function dirNames(absDir) {
69033
69907
  }
69034
69908
  }
69035
69909
  function dirConcreteOf(absDir) {
69036
- return dirConcreteFor(dirNames(absDir), fs10.existsSync(path10.join(absDir, OVERLAY_DIR, BODY_FILE2)));
69910
+ return dirConcreteFor(dirNames(absDir), fs10.existsSync(path11.join(absDir, OVERLAY_DIR, BODY_FILE2)));
69037
69911
  }
69038
69912
  function dirBodyFile(absDir) {
69039
- return path10.join(absDir, ...overlaySegs(dirConcreteOf(absDir)));
69913
+ return path11.join(absDir, ...overlaySegs(dirConcreteOf(absDir)));
69040
69914
  }
69041
69915
  function memberFlavor(absDir) {
69042
69916
  return dirConcreteOf(absDir) === "dir/index.yo" ? "dir/index.yo" : "dir/.yo";
69043
69917
  }
69044
69918
  function concreteOf(s2, dataRoot, segs, row) {
69045
69919
  if (segs.every((g) => typeof g === "string")) {
69046
- const abs = path10.resolve(dataRoot, ...segs.map(String));
69920
+ const abs = path11.resolve(dataRoot, ...segs.map(String));
69047
69921
  let st;
69048
69922
  try {
69049
69923
  st = fs10.statSync(abs);
@@ -69052,7 +69926,7 @@ function concreteOf(s2, dataRoot, segs, row) {
69052
69926
  if (st?.isDirectory()) return dirConcreteOf(abs);
69053
69927
  if (st?.isFile()) return dataFileConcrete(abs) ?? (row.type === "blob" ? "file/binary" : "file/yaml");
69054
69928
  }
69055
- const docAbs = path10.resolve(dataRoot, ...documentRootSegs(s2, segs).map(String));
69929
+ const docAbs = path11.resolve(dataRoot, ...documentRootSegs(s2, segs).map(String));
69056
69930
  try {
69057
69931
  if (fs10.statSync(docAbs).isFile()) return interiorOf(dataFileConcrete(docAbs) ?? "file/yaml");
69058
69932
  } catch {
@@ -69159,7 +70033,7 @@ function linkMarker(dataRoot, s2, segs) {
69159
70033
  } else {
69160
70034
  info.count = ownedEntries(s2, p2).filter((e3) => !(e3.kind === "contain" && isHidden(s2, e3.to))).length;
69161
70035
  }
69162
- if (row.format === TAG_FORMAT) {
70036
+ if (row.format === ONTO_FORMAT) {
69163
70037
  const c3 = s2.node(p2 + ":color")?.value;
69164
70038
  if (typeof c3 === "string") info.color = c3;
69165
70039
  }
@@ -69202,7 +70076,7 @@ function buildRelations(dataRoot, s2, segs) {
69202
70076
  for (const src of upstream.values()) {
69203
70077
  const segs2 = storePathToSegs(src);
69204
70078
  const key = scopedPath(s2, segs2, currentDoc);
69205
- put(key, s2.node(src)?.format === TAG_FORMAT ? linkMarker(dataRoot, s2, segs2) : refMarker(key, segsToStr(segs2)));
70079
+ put(key, s2.node(src)?.format === ONTO_FORMAT ? linkMarker(dataRoot, s2, segs2) : refMarker(key, segsToStr(segs2)));
69206
70080
  }
69207
70081
  return out;
69208
70082
  }
@@ -69278,10 +70152,10 @@ function firstChunkText(s2, p2) {
69278
70152
  }
69279
70153
  return null;
69280
70154
  }
69281
- var TAG_FORMAT = "x-yamlover-tag";
70155
+ var ONTO_FORMAT = "x-yamlover-onto";
69282
70156
  var FRAGMENT_FORMAT = "x-yamlover-fragment";
69283
- var ANN_KEY = "yamlover-annotations";
69284
- var FRAG_KEY = "yamlover-fragments";
70157
+ var YO_KEY2 = "yo";
70158
+ var FRAGS_SUBKEY = "fragments";
69285
70159
  var CROP_SUBDIR = "fragments";
69286
70160
  var THUMB_SUBDIR = "thumbnails";
69287
70161
  var childPath = (parent, key) => (parent === ":" ? "" : parent) + ":" + key;
@@ -69298,42 +70172,36 @@ function displayNameOf(s2, p2) {
69298
70172
  return titleOf(s2, p2);
69299
70173
  }
69300
70174
  function readAnnotations(s2, hostStore) {
69301
- const arr = childPath(hostStore, ANN_KEY);
69302
- if (!s2.node(arr)) return [];
69303
70175
  const out = [];
69304
- for (const e3 of s2.entries(arr)) {
69305
- if (e3.kind === "ref") {
69306
- const tag = projectTag(s2, e3.to);
69307
- if (tag) out.push({ tag });
69308
- } else if (e3.kind === "contain") {
69309
- const tagEdge = s2.relationships(e3.to).out.find((o2) => o2.kind === "ref" && o2.label === "tag");
69310
- const tag = tagEdge ? projectTag(s2, tagEdge.to) : null;
69311
- if (!tag) continue;
69312
- const params = {};
69313
- let description;
69314
- for (const c3 of s2.children(e3.to)) {
69315
- const v = s2.node(c3.to)?.value;
69316
- if (c3.label === "description") description = v == null ? void 0 : String(v);
69317
- else if (c3.label) params[c3.label] = v;
69318
- }
69319
- out.push({ tag, description, params: Object.keys(params).length ? params : void 0 });
69320
- }
70176
+ for (const e3 of s2.relationships(hostStore).out) {
70177
+ if (e3.kind !== "back" || e3.label != null) continue;
70178
+ const tag = projectTag(s2, e3.to);
70179
+ if (tag) out.push({ tag });
69321
70180
  }
69322
70181
  return out;
69323
70182
  }
69324
70183
  function readFragments(s2, hostStore) {
69325
- const frags = childPath(hostStore, FRAG_KEY);
70184
+ const frags = childPath(childPath(hostStore, YO_KEY2), FRAGS_SUBKEY);
69326
70185
  if (!s2.node(frags)) return [];
69327
70186
  const out = [];
69328
70187
  for (const fc of s2.children(frags)) {
69329
70188
  if (!fc.label) continue;
69330
70189
  const selector = {};
70190
+ let description;
70191
+ const self2 = s2.node(fc.to)?.value;
70192
+ if (self2 != null) selector.exact = String(self2);
69331
70193
  for (const c3 of s2.children(fc.to)) {
69332
- if (c3.label && c3.label !== ANN_KEY && c3.label !== "created") selector[c3.label] = s2.node(c3.to)?.value;
70194
+ if (!c3.label || c3.label === "created") continue;
70195
+ if (c3.label === "description") {
70196
+ const v = s2.node(c3.to)?.value;
70197
+ description = v == null ? void 0 : String(v);
70198
+ continue;
70199
+ }
70200
+ selector[c3.label] = s2.node(c3.to)?.value;
69333
70201
  }
69334
70202
  const imgEdge = s2.relationships(fc.to).out.find((o2) => o2.kind === "ref" && o2.label === "image");
69335
70203
  const imageUrl = imgEdge ? `/api/blob?path=${encodeURIComponent(segsToStr(storePathToSegs(imgEdge.to)))}` : void 0;
69336
- out.push({ slug: fc.label, node: fc.to, selector, imageUrl });
70204
+ out.push({ slug: fc.label, node: fc.to, selector, description, imageUrl });
69337
70205
  }
69338
70206
  return out;
69339
70207
  }
@@ -69342,9 +70210,34 @@ function annotationsFor(dataRoot, s2, segs) {
69342
70210
  const out = [];
69343
70211
  const gather = (hostStore, nodeClient) => {
69344
70212
  for (const a2 of readAnnotations(s2, hostStore)) out.push({ ...a2, node: nodeClient });
70213
+ const row = s2.node(hostStore);
70214
+ if (row?.type === "scalar" && typeof row.value === "string" && row.value.includes("[")) {
70215
+ const text = row.value;
70216
+ for (const t3 of scanMarklower(text)) {
70217
+ if (t3.kind !== "frag" || t3.bookmarks.length === 0) continue;
70218
+ const selector = {
70219
+ type: "text",
70220
+ exact: t3.value,
70221
+ prefix: text.slice(Math.max(0, t3.start - 24), t3.start).replace(/\n/g, " "),
70222
+ suffix: text.slice(t3.end, t3.end + 24).replace(/\n/g, " ")
70223
+ };
70224
+ for (const b of t3.bookmarks) {
70225
+ const bsegs = bookmarkSegs(b);
70226
+ const tag = bsegs ? projectTag(s2, storePath(bsegs)) : null;
70227
+ if (tag) out.push({ tag, node: nodeClient, selector, inline: true });
70228
+ }
70229
+ }
70230
+ }
69345
70231
  for (const f2 of readFragments(s2, hostStore)) {
69346
70232
  for (const a2 of readAnnotations(s2, f2.node)) {
69347
- out.push({ ...a2, node: nodeClient, selector: f2.selector, fragmentSlug: f2.slug, ...f2.imageUrl ? { imageUrl: f2.imageUrl } : {} });
70233
+ out.push({
70234
+ ...a2,
70235
+ node: nodeClient,
70236
+ selector: f2.selector,
70237
+ fragmentSlug: f2.slug,
70238
+ ...f2.description ? { description: f2.description } : {},
70239
+ ...f2.imageUrl ? { imageUrl: f2.imageUrl } : {}
70240
+ });
69348
70241
  }
69349
70242
  }
69350
70243
  };
@@ -69356,14 +70249,14 @@ function annotationsFor(dataRoot, s2, segs) {
69356
70249
  return out;
69357
70250
  }
69358
70251
  function taggedMaterials(dataRoot, s2, tagStorePath) {
69359
- const legacyDirect = s2.node(tagStorePath)?.format === TAG_FORMAT;
69360
70252
  const seen = /* @__PURE__ */ new Set();
69361
70253
  const out = [];
69362
- const ins = s2.relationships(tagStorePath).in.filter((e3) => (e3.kind === "ref" || e3.kind === "back") && e3.from).sort((a2, b) => a2.from < b.from ? -1 : a2.from > b.from ? 1 : 0);
69363
- for (const e3 of ins) {
69364
- const arrOwner = e3.from.replace(/(?::\d+|\[\d+\])$/, "").match(/^(.*):yamlover-annotations$/);
69365
- if (!arrOwner && !legacyDirect) continue;
69366
- const owner = arrOwner ? arrOwner[1] || ":" : e3.from;
70254
+ const rel2 = s2.relationships(tagStorePath);
70255
+ const members = [
70256
+ ...rel2.in.filter((e3) => e3.kind === "back" && e3.label == null && e3.from).map((e3) => e3.from),
70257
+ ...rel2.out.filter((e3) => e3.kind === "ref" && e3.label == null).map((e3) => e3.to)
70258
+ ].sort();
70259
+ for (const owner of members) {
69367
70260
  if (owner === tagStorePath || seen.has(owner) || !s2.node(owner) || inHiddenSubtree(s2, owner)) continue;
69368
70261
  seen.add(owner);
69369
70262
  out.push(linkMarker(dataRoot, s2, storePathToSegs(owner)));
@@ -69395,15 +70288,15 @@ function writeBoardLanes(src, lanes) {
69395
70288
  return lines.join("\n") + "\n";
69396
70289
  }
69397
70290
  function overlaidDir(bodyFile) {
69398
- if (bodyFile.endsWith(path10.join(OVERLAY_DIR, BODY_FILE2))) return path10.dirname(path10.dirname(bodyFile));
69399
- return path10.basename(bodyFile) === INDEX_FILE2 ? path10.dirname(bodyFile) : null;
70291
+ if (bodyFile.endsWith(path11.join(OVERLAY_DIR, BODY_FILE2))) return path11.dirname(path11.dirname(bodyFile));
70292
+ return path11.basename(bodyFile) === INDEX_FILE2 ? path11.dirname(bodyFile) : null;
69400
70293
  }
69401
70294
  function sidecarTarget(dataRoot, mode, subdir, bodyFile) {
69402
70295
  const hostDir = overlaidDir(bodyFile);
69403
70296
  if (mode === "per-directory" && hostDir !== null) {
69404
- return { dir: path10.join(hostDir, OVERLAY_DIR, subdir), scope: "document" };
70297
+ return { dir: path11.join(hostDir, OVERLAY_DIR, subdir), scope: "document" };
69405
70298
  }
69406
- return { dir: path10.join(dataRoot, OVERLAY_DIR, subdir), scope: "project" };
70299
+ return { dir: path11.join(dataRoot, OVERLAY_DIR, subdir), scope: "project" };
69407
70300
  }
69408
70301
  function sidecarPointerRaw(subdir, name, scope) {
69409
70302
  const body = [".yo", subdir, name].map(colonSegment).join(":");
@@ -69415,7 +70308,7 @@ function yScalar(v) {
69415
70308
  function hostFor(dataRoot, s2, segs) {
69416
70309
  for (let i2 = segs.length; i2 >= 0; i2--) {
69417
70310
  const sub = segs.slice(0, i2);
69418
- const abs = path10.resolve(dataRoot, ...sub.map(String));
70311
+ const abs = path11.resolve(dataRoot, ...sub.map(String));
69419
70312
  let st;
69420
70313
  try {
69421
70314
  st = fs10.statSync(abs);
@@ -69428,31 +70321,107 @@ function hostFor(dataRoot, s2, segs) {
69428
70321
  if (node?.meta?.documentRoot && node.type === "mapping" && !node.is_array) {
69429
70322
  return { bodyFile: abs, within: segs.slice(i2).map(String) };
69430
70323
  }
69431
- const dir = path10.resolve(dataRoot, ...sub.slice(0, -1).map(String));
70324
+ const dir = path11.resolve(dataRoot, ...sub.slice(0, -1).map(String));
69432
70325
  return { bodyFile: dirBodyFile(dir), within: segs.slice(i2 - 1).map(String) };
69433
70326
  }
69434
70327
  }
69435
70328
  return { bodyFile: dirBodyFile(dataRoot), within: segs.map(String) };
69436
70329
  }
69437
- function annotationItemLines(a2, indent) {
69438
- const pad = " ".repeat(indent);
69439
- const ptr3 = pointerToken(pointerRaw(a2.tag));
69440
- const params = { ...a2.params ?? {} };
69441
- if (a2.description != null && a2.description !== "") params.description = a2.description;
69442
- const keys = Object.keys(params);
69443
- if (keys.length === 0) return [`${pad}- ${ptr3}`];
69444
- return [`${pad}- tag: ${ptr3}`, ...keys.map((k) => `${pad} ${keyToken(k)}: ${yScalar(params[k])}`)];
69445
- }
69446
70330
  function fragmentBlockLines(slug, selector, imagePtr, indent) {
69447
70331
  const pad = " ".repeat(indent);
69448
- const lines = [`${pad}${keyToken(slug)}: !!<*::yamlover:$defs:fragment>`];
69449
- for (const [k, v] of Object.entries(selector)) lines.push(`${pad} ${keyToken(k)}: ${yScalar(v)}`);
70332
+ const { exact, ...fields } = selector;
70333
+ const self2 = exact != null ? ` ${yScalar(exact)}` : "";
70334
+ const lines = [`${pad}${keyToken(slug)}: !!<*::yamlover:$defs:fragment>${self2}`];
70335
+ for (const [k, v] of Object.entries(fields)) lines.push(`${pad} ${keyToken(k)}: ${yScalar(v)}`);
69450
70336
  if (imagePtr) lines.push(`${pad} image: ${imagePtr}`);
69451
70337
  lines.push(`${pad} created: ${(/* @__PURE__ */ new Date()).toISOString()}`);
69452
70338
  return lines;
69453
70339
  }
69454
- function embedAnnotation(dataRoot, s2, a2) {
70340
+ var isFragmentSegs = (segs) => segs.length >= 3 && segs[segs.length - 3] === YO_KEY2 && segs[segs.length - 2] === FRAGS_SUBKEY;
70341
+ var labelToken = (v) => /[:\[\]()&'"\n]|^\s|\s$/.test(v) ? "'" + v.replace(/'/g, "''") + "'" : v;
70342
+ function locateExact(text, sel) {
70343
+ const needle = String(sel.exact ?? "");
70344
+ if (!needle) return null;
70345
+ const norm = text.replace(/\n/g, " ");
70346
+ const pre = String(sel.prefix ?? "").replace(/\n/g, " ");
70347
+ const suf = String(sel.suffix ?? "").replace(/\n/g, " ");
70348
+ let at = -1;
70349
+ for (let f2 = norm.indexOf(needle); f2 >= 0; f2 = norm.indexOf(needle, f2 + 1)) {
70350
+ if (pre && !norm.slice(0, f2).endsWith(pre)) continue;
70351
+ if (suf && !norm.slice(f2 + needle.length).startsWith(suf)) continue;
70352
+ at = f2;
70353
+ break;
70354
+ }
70355
+ if (at < 0) at = norm.indexOf(needle);
70356
+ if (at < 0) return null;
70357
+ const b = at + needle.length;
70358
+ if (text.slice(at, b).includes("\n")) return null;
70359
+ for (const t3 of scanMarklower(text)) {
70360
+ if (at < t3.end && b > t3.start) return null;
70361
+ }
70362
+ return { a: at, b };
70363
+ }
70364
+ var blockPayload = (text) => {
70365
+ const strip = !text.endsWith("\n");
70366
+ const body = (strip ? text : text.slice(0, -1)).split("\n").map((l2) => " " + l2).join("\n");
70367
+ return (strip ? "|-\n" : "|\n") + body;
70368
+ };
70369
+ function rewriteInlineFragment(dataRoot, s2, segs, sel, mutate) {
70370
+ const row = s2.node(storePath(segs));
70371
+ if (!row || row.type !== "scalar" || typeof row.value !== "string") return false;
70372
+ const text = row.value;
70373
+ const exact = String(sel.exact ?? "");
70374
+ let existing = null;
70375
+ for (const t3 of scanMarklower(text)) {
70376
+ if (t3.kind === "frag" && t3.link === null && t3.value === exact) {
70377
+ existing = t3;
70378
+ break;
70379
+ }
70380
+ }
70381
+ let next;
70382
+ if (existing) {
70383
+ const replacement = mutate(existing);
70384
+ if (replacement === false) return false;
70385
+ next = text.slice(0, existing.start) + (replacement ?? existing.value) + text.slice(existing.end);
70386
+ } else {
70387
+ const where = locateExact(text, sel);
70388
+ if (!where) return false;
70389
+ const replacement = mutate(null);
70390
+ if (replacement === false || replacement === null) return false;
70391
+ next = text.slice(0, where.a) + replacement + text.slice(where.b);
70392
+ }
70393
+ applyEdits2(dataRoot, s2, [{ path: segsToStr(segs), op: "emplace", yamlover: blockPayload(next) }]);
70394
+ return true;
70395
+ }
70396
+ function fragTokenText(bookmarks, value, parens) {
70397
+ const head = bookmarks.length ? bookmarks.join(": ") + ": " : "";
70398
+ return `[${head}${labelToken(value)}](${parens})`;
70399
+ }
70400
+ function bookmarkSegs(body) {
70401
+ try {
70402
+ const p2 = parsePointer(body.replace(/^&/, "").replace(/:\s*-\s*$/, ""));
70403
+ const segs = [p2.base?.authority, ...(p2.steps ?? []).map((st) => st.name)].filter((x2) => typeof x2 === "string");
70404
+ return segs.length ? segs : null;
70405
+ } catch {
70406
+ return null;
70407
+ }
70408
+ }
70409
+ function embedAnnotation(dataRoot, s2, mode, a2) {
69455
70410
  const segs = strToSegs(a2.target || ":");
70411
+ const params = { ...a2.params ?? {} };
70412
+ if (a2.description != null && a2.description !== "") params.description = a2.description;
70413
+ const sel = a2.selector;
70414
+ if (sel && typeof sel === "object" && sel.type === "text" && Object.keys(params).length === 0 && isChunkTarget(s2, segs)) {
70415
+ const btoken = `&${pointerRaw(a2.tag)}:-`;
70416
+ const ok = rewriteInlineFragment(dataRoot, s2, segs, sel, (t3) => t3 ? fragTokenText([...t3.bookmarks, btoken], t3.value, t3.parens) : fragTokenText([btoken], String(sel.exact ?? ""), ""));
70417
+ if (ok) return chapterSource(dataRoot, s2, segs).bodyFile;
70418
+ const made = embedFragment(dataRoot, s2, mode, { target: a2.target, selector: sel });
70419
+ return embedAnnotation(dataRoot, s2, mode, { target: made.fragmentPath, tag: a2.tag });
70420
+ }
70421
+ if (Object.keys(params).length && !isFragmentSegs(segs)) {
70422
+ throw new Error("annotation parameters live on a fragment (docs/annotations/applications)");
70423
+ }
70424
+ const tokens = [`&${pointerRaw(a2.tag)}:-`, ...Object.entries(params).map(([k, v]) => `${keyToken(k)}: ${yScalar(v)}`)];
69456
70425
  if (isChunkTarget(s2, segs)) {
69457
70426
  const { docSegs, bodyFile: bodyFile2 } = chapterSource(dataRoot, s2, segs);
69458
70427
  const { indices, keys } = splitChunkWithin(segs.slice(docSegs.length));
@@ -69463,14 +70432,14 @@ function embedAnnotation(dataRoot, s2, a2) {
69463
70432
  /*ensureOmni*/
69464
70433
  true
69465
70434
  ), keys);
69466
- appendAnnotationAt(lines, region, (indent) => annotationItemLines(a2, indent));
70435
+ appendBookmarkAt(lines, region, tokens);
69467
70436
  writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
69468
70437
  return bodyFile2;
69469
70438
  }
69470
70439
  const { bodyFile, within } = hostFor(dataRoot, s2, segs);
69471
- mkdirInside(dataRoot, path10.dirname(bodyFile), { recursive: true });
70440
+ mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
69472
70441
  const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
69473
- writeBody(dataRoot, s2, bodyFile, appendAnnotation(src, within, (indent) => annotationItemLines(a2, indent)));
70442
+ writeBody(dataRoot, s2, bodyFile, appendBookmark(src, within, tokens));
69474
70443
  return bodyFile;
69475
70444
  }
69476
70445
  function embedFragment(dataRoot, s2, mode, f2) {
@@ -69488,9 +70457,9 @@ function embedFragment(dataRoot, s2, mode, f2) {
69488
70457
  /*ensureOmni*/
69489
70458
  true
69490
70459
  );
69491
- upsertMapEntryAt(lines, region, FRAG_KEY, slug, (indent) => fragmentBlockLines(slug, f2.selector, null, indent));
70460
+ upsertMapEntryAt(lines, reachBodyAt(lines, region, [YO_KEY2]), FRAGS_SUBKEY, slug, (indent) => fragmentBlockLines(slug, f2.selector, null, indent));
69492
70461
  writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
69493
- return { slug, fragmentPath: segsToStr([...segs, FRAG_KEY, slug]) };
70462
+ return { slug, fragmentPath: segsToStr([...segs, YO_KEY2, FRAGS_SUBKEY, slug]) };
69494
70463
  }
69495
70464
  const { bodyFile, within } = hostFor(dataRoot, s2, segs);
69496
70465
  let imagePtr = null;
@@ -69504,10 +70473,10 @@ function embedFragment(dataRoot, s2, mode, f2) {
69504
70473
  imagePtr = pointerToken(sidecarPointerRaw(CROP_SUBDIR, cropName, scope));
69505
70474
  }
69506
70475
  }
69507
- mkdirInside(dataRoot, path10.dirname(bodyFile), { recursive: true });
70476
+ mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
69508
70477
  const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
69509
70478
  writeBody(dataRoot, s2, bodyFile, upsertFragment(src, within, slug, (indent) => fragmentBlockLines(slug, f2.selector, imagePtr, indent)));
69510
- return { slug, fragmentPath: segsToStr([...segs, FRAG_KEY, slug]) };
70479
+ return { slug, fragmentPath: segsToStr([...segs, YO_KEY2, FRAGS_SUBKEY, slug]) };
69511
70480
  }
69512
70481
  var thumbResKey = (w, h) => `[${w}, ${h}]`;
69513
70482
  var thumbName = (hash, w, h) => `${hash.replace(/:/g, "-")}-${w}x${h}.jpg`;
@@ -69515,13 +70484,13 @@ function existingThumb(dataRoot, s2, mode, segs, row, w, h) {
69515
70484
  if (!row.content_hash) return null;
69516
70485
  const { bodyFile } = hostFor(dataRoot, s2, segs);
69517
70486
  const { dir } = sidecarTarget(dataRoot, mode, THUMB_SUBDIR, bodyFile);
69518
- const abs = path10.join(dir, thumbName(row.content_hash, w, h));
70487
+ const abs = path11.join(dir, thumbName(row.content_hash, w, h));
69519
70488
  return fs10.existsSync(abs) ? abs : null;
69520
70489
  }
69521
70490
  function embedThumbnail(dataRoot, s2, mode, segs, w, h, name, onWrite) {
69522
70491
  const { bodyFile, within } = hostFor(dataRoot, s2, segs);
69523
70492
  const { scope } = sidecarTarget(dataRoot, mode, THUMB_SUBDIR, bodyFile);
69524
- mkdirInside(dataRoot, path10.dirname(bodyFile), { recursive: true });
70493
+ mkdirInside(dataRoot, path11.dirname(bodyFile), { recursive: true });
69525
70494
  const src = fs10.existsSync(bodyFile) ? fs10.readFileSync(bodyFile, "utf8") : "";
69526
70495
  const ptr3 = pointerToken(sidecarPointerRaw(THUMB_SUBDIR, name, scope));
69527
70496
  const key = thumbResKey(w, h);
@@ -69529,11 +70498,11 @@ function embedThumbnail(dataRoot, s2, mode, segs, w, h, name, onWrite) {
69529
70498
  onWrite?.(bodyFile);
69530
70499
  }
69531
70500
  async function ensureThumbnail(dataRoot, s2, mode, segs, row, w, h, hash, onWrite) {
69532
- const sourceAbs = path10.join(dataRoot, ...segs.map(String));
70501
+ const sourceAbs = path11.join(dataRoot, ...segs.map(String));
69533
70502
  const name = thumbName(hash, w, h);
69534
70503
  const { bodyFile } = hostFor(dataRoot, s2, segs);
69535
70504
  const { dir } = sidecarTarget(dataRoot, mode, THUMB_SUBDIR, bodyFile);
69536
- const abs = path10.join(dir, name);
70505
+ const abs = path11.join(dir, name);
69537
70506
  if (fs10.existsSync(abs)) return abs;
69538
70507
  const thumb = await renderThumbnail(fs10.readFileSync(sourceAbs), row.format ?? formatFromExt(sourceAbs), w, h);
69539
70508
  if (!thumb) return null;
@@ -69543,9 +70512,23 @@ async function ensureThumbnail(dataRoot, s2, mode, segs, row, w, h, hash, onWrit
69543
70512
  embedThumbnail(dataRoot, s2, mode, segs, w, h, name, onWrite);
69544
70513
  return abs;
69545
70514
  }
69546
- function unembedAnnotation(dataRoot, s2, target, tag) {
70515
+ function unembedAnnotation(dataRoot, s2, target, tag, sel) {
69547
70516
  const segs = strToSegs(target || ":");
69548
70517
  const needle = (":" + pointerRaw(tag).replace(/^:+/, "")).replace(/\s+/g, "");
70518
+ const pred = (line) => {
70519
+ const t3 = line.replace(/\s+/g, "");
70520
+ return t3.startsWith("&") && t3.includes(needle) && /:-$/.test(t3);
70521
+ };
70522
+ if (sel && sel.type === "text" && isChunkTarget(s2, segs)) {
70523
+ const ok = rewriteInlineFragment(dataRoot, s2, segs, sel, (t3) => {
70524
+ if (!t3) return false;
70525
+ const kept = t3.bookmarks.filter((b) => !pred(b));
70526
+ if (kept.length === t3.bookmarks.length) return false;
70527
+ if (kept.length === 0 && t3.fields.length === 0 && t3.link === null) return null;
70528
+ return fragTokenText(kept, t3.value, t3.parens);
70529
+ });
70530
+ if (ok) return chapterSource(dataRoot, s2, segs).bodyFile;
70531
+ }
69549
70532
  if (isChunkTarget(s2, segs)) {
69550
70533
  const { docSegs, bodyFile: bodyFile2 } = chapterSource(dataRoot, s2, segs);
69551
70534
  if (!fs10.existsSync(bodyFile2)) return bodyFile2;
@@ -69557,12 +70540,12 @@ function unembedAnnotation(dataRoot, s2, target, tag) {
69557
70540
  /*ensureOmni*/
69558
70541
  false
69559
70542
  ), keys);
69560
- removeAnnotationAt(lines, fragRegion, (t3) => t3.replace(/\s+/g, "").includes(needle));
69561
- if (keys.length >= 2 && keys[keys.length - 2] === FRAG_KEY && !annotationsRemainAt(lines, fragRegion())) {
69562
- removeMapEntryAt(lines, reachBodyAt(lines, chunkFieldRegion(lines, indices, false), keys.slice(0, -2)), FRAG_KEY, keys[keys.length - 1]);
70543
+ removeBookmarkAt(lines, fragRegion, pred);
70544
+ if (isFragmentSegs(keys) && !bookmarksRemainAt(lines, fragRegion())) {
70545
+ removeMapEntryAt(lines, reachBodyAt(lines, chunkFieldRegion(lines, indices, false), keys.slice(0, -2)), FRAGS_SUBKEY, keys[keys.length - 1]);
70546
+ pruneEmptyKeyAt(lines, chunkFieldRegion(lines, indices, false), YO_KEY2);
69563
70547
  collapseChunkOmni(lines, indices);
69564
- } else if (keys.length === 0 && !annotationsRemainAt(lines, fragRegion())) {
69565
- pruneEmptyAnnotationsAt(lines, fragRegion());
70548
+ } else if (keys.length === 0 && !bookmarksRemainAt(lines, fragRegion())) {
69566
70549
  collapseChunkOmni(lines, indices);
69567
70550
  }
69568
70551
  writeBody(dataRoot, s2, bodyFile2, lines.join("\n") + "\n");
@@ -69570,27 +70553,28 @@ function unembedAnnotation(dataRoot, s2, target, tag) {
69570
70553
  }
69571
70554
  const { bodyFile, within } = hostFor(dataRoot, s2, segs);
69572
70555
  if (!fs10.existsSync(bodyFile)) return bodyFile;
69573
- let src = removeAnnotation(fs10.readFileSync(bodyFile, "utf8"), within, (itemText) => itemText.replace(/\s+/g, "").includes(needle));
70556
+ let src = removeBookmark(fs10.readFileSync(bodyFile, "utf8"), within, pred);
69574
70557
  const overlay2 = overlaidDir(bodyFile) !== null;
69575
- if (within.length >= 2 && within[within.length - 2] === FRAG_KEY && !annotationsRemain(src, within)) {
69576
- src = removeMapEntry(src, within.slice(0, -2), FRAG_KEY, within[within.length - 1]);
69577
- src = pruneEmptyAnnotations(src, within.slice(0, -2), overlay2);
70558
+ if (isFragmentSegs(within) && !bookmarksRemain(src, within)) {
70559
+ src = removeMapEntry(src, within.slice(0, -2), FRAGS_SUBKEY, within[within.length - 1]);
70560
+ src = pruneEmptyYo(src, within.slice(0, -3));
70561
+ src = pruneEmptyAnnotations(src, within.slice(0, -3), overlay2);
69578
70562
  } else {
69579
70563
  src = pruneEmptyAnnotations(src, within, overlay2);
69580
70564
  }
69581
70565
  writeBody(dataRoot, s2, bodyFile, src);
69582
70566
  return bodyFile;
69583
70567
  }
69584
- function writeTag(dataRoot, s2, location, name) {
70568
+ function writeOnto(dataRoot, s2, location, name) {
69585
70569
  if (/[/\\\r\n:]/.test(name)) throw new Error("a tag name cannot contain '/', '\\', ':' or line breaks");
69586
- const root = path10.resolve(dataRoot);
69587
- const file = dirBodyFile(path10.resolve(dataRoot, ...strToSegs(location).map(String)));
69588
- if (!file.startsWith(root + path10.sep)) throw new Error("tags location escapes the data root");
69589
- const dir = path10.dirname(file);
70570
+ const root = path11.resolve(dataRoot);
70571
+ const file = dirBodyFile(path11.resolve(dataRoot, ...strToSegs(location).map(String)));
70572
+ if (!file.startsWith(root + path11.sep)) throw new Error("tags location escapes the data root");
70573
+ const dir = path11.dirname(file);
69590
70574
  const createdFile = !fs10.existsSync(file);
69591
70575
  const head = "# Named tags created from the annotation picker (settings.yo: tags.location).\n";
69592
70576
  const existing = createdFile ? head : fs10.readFileSync(file, "utf8");
69593
- const body = (existing === "" || existing.endsWith("\n") ? existing : existing + "\n") + `${name}: !!<*::yamlover:$defs:tag>
70577
+ const body = (existing === "" || existing.endsWith("\n") ? existing : existing + "\n") + `${name}: !!<*::yamlover:$defs:onto>
69594
70578
  `;
69595
70579
  const entries = parseYamlover(body, file).root.entries ?? [];
69596
70580
  const pos = entries.findIndex((e3) => e3.key === name);
@@ -69632,7 +70616,7 @@ function handlePaste(dataRoot, s2, input) {
69632
70616
  if (intoChapter && !input.inline) return pasteIntoChapter(dataRoot, s2, segs, name, bytes);
69633
70617
  const dirSegs = nearestDirSegs(dataRoot, segs);
69634
70618
  if (!dirSegs) throw new Error("no enclosing directory to paste into");
69635
- const dir = path10.resolve(dataRoot, ...dirSegs.map(String));
70619
+ const dir = path11.resolve(dataRoot, ...dirSegs.map(String));
69636
70620
  const final = uniqueName(dir, name);
69637
70621
  writeInside(dataRoot, dir, final, bytes);
69638
70622
  return { path: segsToStr([...dirSegs, final]), dir: segsToStr(dirSegs), open: !input.inline && dirSegs.length !== segs.length };
@@ -69640,7 +70624,7 @@ function handlePaste(dataRoot, s2, input) {
69640
70624
  function nearestDirSegs(dataRoot, segs) {
69641
70625
  for (let i2 = segs.length; i2 >= 0; i2--) {
69642
70626
  const sub = segs.slice(0, i2);
69643
- const abs = path10.resolve(dataRoot, ...sub.map(String));
70627
+ const abs = path11.resolve(dataRoot, ...sub.map(String));
69644
70628
  if (fs10.existsSync(abs) && fs10.statSync(abs).isDirectory()) return sub;
69645
70629
  }
69646
70630
  return null;
@@ -69650,7 +70634,7 @@ var BLOCK_YAML = /\.(ya?ml|yo|yamlover)$/i;
69650
70634
  var JSON_FILE = /\.(json|json5|json5p)$/i;
69651
70635
  function resolveBacking(dataRoot, s2, segs) {
69652
70636
  const docSegs = documentRootSegs(s2, segs);
69653
- const docFs = path10.resolve(dataRoot, ...docSegs.map(String));
70637
+ const docFs = path11.resolve(dataRoot, ...docSegs.map(String));
69654
70638
  const dirBacked = fs10.existsSync(docFs) && fs10.statSync(docFs).isDirectory();
69655
70639
  const bodyFile = dirBacked ? dirBodyFile(docFs) : docFs;
69656
70640
  return { docSegs, bodyFile, dirBacked };
@@ -69719,7 +70703,7 @@ function memberNeighbors(bodyFile, within, index) {
69719
70703
  function pasteIntoChapter(dataRoot, s2, segs, name, bytes) {
69720
70704
  const { docSegs, bodyFile, dirBacked } = chapterSource(dataRoot, s2, segs);
69721
70705
  const writeDirSegs = dirBacked ? docSegs : docSegs.slice(0, -1);
69722
- const writeDir = path10.resolve(dataRoot, ...writeDirSegs.map(String));
70706
+ const writeDir = path11.resolve(dataRoot, ...writeDirSegs.map(String));
69723
70707
  const final = uniqueName(writeDir, name);
69724
70708
  writeInside(dataRoot, writeDir, final, bytes);
69725
70709
  const fileSegs = [...writeDirSegs, final];
@@ -69739,7 +70723,7 @@ function pasteTextIntoChapter(dataRoot, s2, segs, text) {
69739
70723
  function pasteTextAsChapterFile(dataRoot, segs, text) {
69740
70724
  const dirSegs = nearestDirSegs(dataRoot, segs);
69741
70725
  if (!dirSegs) throw new Error("no enclosing directory to paste into");
69742
- const dir = path10.resolve(dataRoot, ...dirSegs.map(String));
70726
+ const dir = path11.resolve(dataRoot, ...dirSegs.map(String));
69743
70727
  const title = titleFromText(text);
69744
70728
  const final = uniqueName(dir, chapterFileName(title));
69745
70729
  const src = ["!!<*::yamlover:$defs:chapter>", JSON.stringify(title), ...textChunkLines(text, 0), ""].join("\n");
@@ -69792,7 +70776,7 @@ function richBodyLines(rich, indent, pointerFor) {
69792
70776
  function pasteRichIntoChapter(dataRoot, s2, segs, rich) {
69793
70777
  const { docSegs, bodyFile, dirBacked } = chapterSource(dataRoot, s2, segs);
69794
70778
  const writeDirSegs = dirBacked ? docSegs : docSegs.slice(0, -1);
69795
- const writeDir = path10.resolve(dataRoot, ...writeDirSegs.map(String));
70779
+ const writeDir = path11.resolve(dataRoot, ...writeDirSegs.map(String));
69796
70780
  const files = [];
69797
70781
  const pointerFor = (name, bytes) => {
69798
70782
  const final = uniqueName(writeDir, name);
@@ -69809,7 +70793,7 @@ function pasteRichIntoChapter(dataRoot, s2, segs, rich) {
69809
70793
  function pasteRichAsChapter(dataRoot, segs, rich) {
69810
70794
  const dirSegs = nearestDirSegs(dataRoot, segs);
69811
70795
  if (!dirSegs) throw new Error("no enclosing directory to paste into");
69812
- const dir = path10.resolve(dataRoot, ...dirSegs.map(String));
70796
+ const dir = path11.resolve(dataRoot, ...dirSegs.map(String));
69813
70797
  if (!rich.title && rich.chunks.length === 0 && rich.children.length === 1) rich = rich.children[0];
69814
70798
  const firstText = rich.chunks.find((c3) => "text" in c3);
69815
70799
  const title = rich.title ?? (firstText ? titleFromText(firstText.text) : rich.children[0]?.title ?? "Pasted content");
@@ -69822,10 +70806,10 @@ function pasteRichAsChapter(dataRoot, segs, rich) {
69822
70806
  return { path: segsToStr([...dirSegs, final]), dir: segsToStr(dirSegs), open: dirSegs.length !== segs.length };
69823
70807
  }
69824
70808
  const name = uniqueName(dir, chapterFileName(title).replace(/\.yo$/, ""));
69825
- const chDir = path10.join(dir, name);
69826
- if (!path10.resolve(chDir).startsWith(path10.resolve(dataRoot) + path10.sep)) throw new Error("target escapes the data root");
70809
+ const chDir = path11.join(dir, name);
70810
+ if (!path11.resolve(chDir).startsWith(path11.resolve(dataRoot) + path11.sep)) throw new Error("target escapes the data root");
69827
70811
  const overlay2 = overlaySegs(memberFlavor(dir));
69828
- const overlayDir = path10.join(chDir, ...overlay2.slice(0, -1));
70812
+ const overlayDir = path11.join(chDir, ...overlay2.slice(0, -1));
69829
70813
  mkdirInside(dataRoot, overlayDir, { recursive: true });
69830
70814
  const pointerFor = (fname, bytes) => {
69831
70815
  const final = uniqueName(chDir, fname);
@@ -69861,7 +70845,7 @@ function writeObject(dataRoot, dir, base, concrete, src) {
69861
70845
  if (isOverlayDirConcrete(concrete)) {
69862
70846
  const final2 = uniqueName(dir, base);
69863
70847
  const segs = overlaySegs(concrete);
69864
- const overlayDir = path10.join(dir, final2, ...segs.slice(0, -1));
70848
+ const overlayDir = path11.join(dir, final2, ...segs.slice(0, -1));
69865
70849
  mkdirInside(dataRoot, overlayDir, { recursive: true });
69866
70850
  writeInside(dataRoot, overlayDir, segs[segs.length - 1], Buffer.from(src, "utf8"));
69867
70851
  return final2;
@@ -69873,9 +70857,9 @@ function writeObject(dataRoot, dir, base, concrete, src) {
69873
70857
  function ensureDirBody(dataRoot, absDir) {
69874
70858
  const body = dirBodyFile(absDir);
69875
70859
  if (!fs10.existsSync(body)) {
69876
- const overlayDir = path10.dirname(body);
70860
+ const overlayDir = path11.dirname(body);
69877
70861
  mkdirInside(dataRoot, overlayDir, { recursive: true });
69878
- writeInside(dataRoot, overlayDir, path10.basename(body), Buffer.from("", "utf8"));
70862
+ writeInside(dataRoot, overlayDir, path11.basename(body), Buffer.from("", "utf8"));
69879
70863
  }
69880
70864
  return body;
69881
70865
  }
@@ -69898,7 +70882,7 @@ function writeDirMemberTree(dataRoot, absDir, key, valueSrc, meta, flavor = memb
69898
70882
  if (!name || name === INDEX_FILE2 || name !== name.trim() || name.startsWith(".") || /[\\/:*?"<>|\u0000-\u001f]/.test(name)) {
69899
70883
  throw new Error(`\`${name}\` cannot name a directory member`);
69900
70884
  }
69901
- const dir = path10.join(absDir, name);
70885
+ const dir = path11.join(absDir, name);
69902
70886
  if (fs10.existsSync(dir)) throw new Error(`member \`${name}\` already exists in the directory`);
69903
70887
  mkdirInside(dataRoot, dir);
69904
70888
  const f2 = payloadFacets(valueSrc);
@@ -69928,7 +70912,7 @@ function writeDirMemberTree(dataRoot, absDir, key, valueSrc, meta, flavor = memb
69928
70912
  if (selfAt >= 0 && !emittedSelf) emitSelf();
69929
70913
  if (bodyLines.length) {
69930
70914
  const segs = overlaySegs(flavor);
69931
- const overlayDir = path10.join(dir, ...segs.slice(0, -1));
70915
+ const overlayDir = path11.join(dir, ...segs.slice(0, -1));
69932
70916
  mkdirInside(dataRoot, overlayDir, { recursive: true });
69933
70917
  writeInside(dataRoot, overlayDir, segs[segs.length - 1], Buffer.from(bodyLines.join("\n").replace(/\n*$/, "") + "\n", "utf8"));
69934
70918
  }
@@ -69938,20 +70922,20 @@ function chapterFileName(title) {
69938
70922
  return `${base || "pasted"}.yo`;
69939
70923
  }
69940
70924
  function sanitizeName(raw) {
69941
- const base = path10.basename(String(raw || "")).replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "");
70925
+ const base = path11.basename(String(raw || "")).replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "");
69942
70926
  return base || "pasted";
69943
70927
  }
69944
70928
  function uniqueName(dir, name) {
69945
- if (!fs10.existsSync(path10.join(dir, name))) return name;
69946
- const ext = path10.extname(name);
70929
+ if (!fs10.existsSync(path11.join(dir, name))) return name;
70930
+ const ext = path11.extname(name);
69947
70931
  const stem = name.slice(0, name.length - ext.length);
69948
70932
  for (let i2 = 1; ; i2++) {
69949
70933
  const cand = `${stem}-${i2}${ext}`;
69950
- if (!fs10.existsSync(path10.join(dir, cand))) return cand;
70934
+ if (!fs10.existsSync(path11.join(dir, cand))) return cand;
69951
70935
  }
69952
70936
  }
69953
70937
  function relPosix(dataRoot, abs) {
69954
- return path10.relative(dataRoot, abs).split(path10.sep).join("/");
70938
+ return path11.relative(dataRoot, abs).split(path11.sep).join("/");
69955
70939
  }
69956
70940
  function scanTree(dataRoot, ignore2) {
69957
70941
  const nodes = [];
@@ -69965,12 +70949,12 @@ function scanTree(dataRoot, ignore2) {
69965
70949
  const names3 = entries.map((d2) => d2.name);
69966
70950
  nodes.push({
69967
70951
  path: segsToStr(segs),
69968
- concrete: dirConcreteFor(names3, fs10.existsSync(path10.join(abs, OVERLAY_DIR, BODY_FILE2))),
70952
+ concrete: dirConcreteFor(names3, fs10.existsSync(path11.join(abs, OVERLAY_DIR, BODY_FILE2))),
69969
70953
  fsPath: segs.join("/"),
69970
70954
  names: names3
69971
70955
  });
69972
70956
  for (const d2 of entries) {
69973
- const childAbs = path10.join(abs, d2.name);
70957
+ const childAbs = path11.join(abs, d2.name);
69974
70958
  if (ignore2?.(childAbs)) continue;
69975
70959
  if (d2.name.startsWith(".") && d2.name !== ".yo") continue;
69976
70960
  const childSegs = [...segs, d2.name];
@@ -69978,7 +70962,7 @@ function scanTree(dataRoot, ignore2) {
69978
70962
  else if (d2.isFile()) nodes.push({ path: segsToStr(childSegs), concrete: dataFileConcrete(childAbs), fsPath: childSegs.join("/") });
69979
70963
  }
69980
70964
  };
69981
- visit2(path10.resolve(dataRoot), []);
70965
+ visit2(path11.resolve(dataRoot), []);
69982
70966
  return { nodes };
69983
70967
  }
69984
70968
  var validationLog = () => {
@@ -70001,9 +70985,9 @@ function guardPath(dataRoot, abs) {
70001
70985
  }
70002
70986
  function writeInside(dataRoot, dir, name, bytes) {
70003
70987
  if (readOnlyWrites) throw new Error("refused: server is read-only");
70004
- const root = path10.resolve(dataRoot);
70005
- const target = path10.resolve(dir, name);
70006
- if (target !== root && !target.startsWith(root + path10.sep)) throw new Error("target escapes the data root");
70988
+ const root = path11.resolve(dataRoot);
70989
+ const target = path11.resolve(dir, name);
70990
+ if (target !== root && !target.startsWith(root + path11.sep)) throw new Error("target escapes the data root");
70007
70991
  guardPath(dataRoot, target);
70008
70992
  fs10.writeFileSync(target, bytes);
70009
70993
  }
@@ -70023,13 +71007,13 @@ function writeBody(dataRoot, s2, bodyFile, src) {
70023
71007
  throw new Error(`cannot edit ${segsToStr(owner)}: its source failed to parse and is shown degraded (${rel2}: ${pe.message ?? "syntax error"}) \u2014 fix the file on disk first`);
70024
71008
  }
70025
71009
  }
70026
- writeInside(dataRoot, path10.dirname(bodyFile), path10.basename(bodyFile), Buffer.from(src, "utf8"));
71010
+ writeInside(dataRoot, path11.dirname(bodyFile), path11.basename(bodyFile), Buffer.from(src, "utf8"));
70027
71011
  }
70028
71012
  function mkdirInside(dataRoot, abs, opts) {
70029
71013
  guardPath(dataRoot, abs);
70030
71014
  fs10.mkdirSync(abs, opts);
70031
71015
  }
70032
- var AGENT_DOCS_DIR = path10.join(path10.dirname(fileURLToPath3(import.meta.url)), "agent-docs");
71016
+ var AGENT_DOCS_DIR = path11.join(path11.dirname(fileURLToPath3(import.meta.url)), "agent-docs");
70033
71017
  function loadAgentDocs() {
70034
71018
  let names3;
70035
71019
  try {
@@ -70038,7 +71022,7 @@ function loadAgentDocs() {
70038
71022
  throw new Error(`agent-docs resources not found at ${AGENT_DOCS_DIR}`);
70039
71023
  }
70040
71024
  if (names3.length === 0) throw new Error(`no agent-docs resources at ${AGENT_DOCS_DIR}`);
70041
- return names3.map((name) => ({ name, content: fs10.readFileSync(path10.join(AGENT_DOCS_DIR, name), "utf8") }));
71025
+ return names3.map((name) => ({ name, content: fs10.readFileSync(path11.join(AGENT_DOCS_DIR, name), "utf8") }));
70042
71026
  }
70043
71027
  var DOC_BEGIN = "<!-- BEGIN yamlover agent guide (auto-managed by `npx yamlover` \u2014 regenerated on reinstall) -->";
70044
71028
  var DOC_END = "<!-- END yamlover agent guide -->";
@@ -70050,8 +71034,8 @@ ${DOC_END}
70050
71034
  if (existing === null) return { text: block, status: "created" };
70051
71035
  const b = existing.indexOf(DOC_BEGIN);
70052
71036
  if (b === -1) {
70053
- const sep2 = existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
70054
- return { text: existing + sep2 + block, status: "appended" };
71037
+ const sep3 = existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
71038
+ return { text: existing + sep3 + block, status: "appended" };
70055
71039
  }
70056
71040
  const e3 = existing.indexOf(DOC_END, b);
70057
71041
  const end = e3 === -1 ? existing.length : e3 + DOC_END.length;
@@ -70307,11 +71291,15 @@ function preferPlainScalar(src) {
70307
71291
  }
70308
71292
  return src;
70309
71293
  }
70310
- function renderNode(f2, indent, marker, tag) {
71294
+ function renderNode(f2, indent, marker, tag, flat) {
70311
71295
  const pad = " ".repeat(indent);
70312
71296
  const childPad = " ".repeat(indent + 2);
70313
71297
  const groups = orderedGroups(f2);
70314
71298
  const child = (g) => g.map((l2) => l2.trim().length ? childPad + l2 : "");
71299
+ if (flat === true && !marker.startsWith("-") && f2.scalar === void 0 && !tag && f2.keyed.length === 1 && (f2.ordinal ?? []).length === 0) {
71300
+ const [g0] = groups;
71301
+ return [`${pad}${marker}${g0[0]}`, ...child(g0.slice(1))];
71302
+ }
70315
71303
  const selfAt = f2.scalar !== void 0 ? Math.min(f2.selfAt ?? 0, groups.length) : 0;
70316
71304
  if (f2.scalar !== void 0 && selfAt > 0) {
70317
71305
  const selfLines = child(preferPlainScalar(f2.scalar).split("\n"));
@@ -70378,14 +71366,14 @@ function trailingCommentOf(line) {
70378
71366
  }
70379
71367
  return null;
70380
71368
  }
70381
- function assignAt(lines, r2, seg, op, valueSrc, meta, key, at) {
71369
+ function assignAt(lines, r2, seg, op, valueSrc, meta, key, at, flat) {
70382
71370
  const marker = (s2) => typeof s2 === "string" ? `${keyToken(s2)}: ` : s2 === null ? "~: " : "- ";
70383
71371
  if (op === "insert") {
70384
71372
  if (typeof seg !== "number" && seg !== void 0) throw new Error("`insert` needs a positional target (a path ending in a bare index, or the node itself)");
70385
71373
  const entries = chapterEntries(lines, r2);
70386
71374
  const entry2 = seg === void 0 ? void 0 : entries[seg];
70387
71375
  const at2 = entry2 ? entry2.start : seg !== void 0 && entries.length ? entries[entries.length - 1].end : bodyAppendPoint(lines, r2);
70388
- lines.splice(at2, 0, ...renderNode(payloadFacets(valueSrc), r2.indent, key !== void 0 ? `${keyToken(key)}: ` : "- ", metaTag(meta, void 0, false)));
71376
+ lines.splice(at2, 0, ...renderNode(payloadFacets(valueSrc), r2.indent, key !== void 0 ? `${keyToken(key)}: ` : "- ", metaTag(meta, void 0, false), key !== void 0 && flat === true));
70389
71377
  return;
70390
71378
  }
70391
71379
  if (seg === void 0) throw new Error(`\`${op}\` needs a key or index target`);
@@ -70452,9 +71440,15 @@ function assignAt(lines, r2, seg, op, valueSrc, meta, key, at) {
70452
71440
  lines[entry.start] = (inlineKey ? `${pad}- ${tag ? tag + " " : ""}${inlineKey}: ${next.scalar ?? '""'}` : `${pad}- - ${tag ? tag + " " : ""}${next.scalar ?? '""'}`) + (headTrail ?? "");
70453
71441
  return;
70454
71442
  }
71443
+ const anchorLines = op === "emplace" ? lines.slice(entry.start + 1, entry.end).filter((l2) => isContentLine2(l2) && indentOf2(l2) === r2.indent + 2 && l2.trim().startsWith("&")) : [];
70455
71444
  const rendered = renderNode(next, r2.indent, marker(seg), tag);
70456
71445
  if (headTrail !== null && rendered.length > 0 && trailingCommentOf(rendered[0]) === null) rendered[0] += headTrail;
70457
- lines.splice(entry.start, entry.end - entry.start, ...rendered);
71446
+ const payloadHasAnchors = rendered.some((l2) => isContentLine2(l2) && l2.trim().startsWith("&"));
71447
+ const carried = payloadHasAnchors ? [] : anchorLines;
71448
+ if (carried.length && rendered.length > 1 && /[|>][+-]?\s*$/.test(rendered[0].replace(/\s+#.*$/, ""))) {
71449
+ for (let i2 = 1; i2 < rendered.length; i2++) if (rendered[i2].trim()) rendered[i2] = " " + rendered[i2];
71450
+ }
71451
+ lines.splice(entry.start, entry.end - entry.start, ...rendered, ...carried);
70458
71452
  }
70459
71453
  function reachChapterItem(lines, indices) {
70460
71454
  const parent = reachChapter(lines, indices.slice(0, -1));
@@ -70730,11 +71724,11 @@ function editFlowRowCell(lines, row, cellIdx, op, valueSrc) {
70730
71724
  lines[row.start] = raw.slice(0, cell.start) + lead + flowCellToken(text) + raw.slice(cell.end);
70731
71725
  return true;
70732
71726
  }
70733
- function editChapterSource(src, within, op, valueSrc, meta, key, at) {
71727
+ function editChapterSource(src, within, op, valueSrc, meta, key, at, flat) {
70734
71728
  const lines = src.split("\n");
70735
71729
  if (within.length === 0) {
70736
71730
  if (op === "insert") {
70737
- assignAt(lines, reachChapter(lines, []), void 0, op, valueSrc, meta, key);
71731
+ assignAt(lines, reachChapter(lines, []), void 0, op, valueSrc, meta, key, void 0, flat);
70738
71732
  return lines.join("\n");
70739
71733
  }
70740
71734
  if (op === "emplace") {
@@ -70781,7 +71775,7 @@ function editChapterSource(src, within, op, valueSrc, meta, key, at) {
70781
71775
  return lines.join("\n");
70782
71776
  }
70783
71777
  }
70784
- assignAt(lines, reachChapter(lines, within.slice(0, -1)), within[within.length - 1], op, valueSrc, meta, key, at);
71778
+ assignAt(lines, reachChapter(lines, within.slice(0, -1)), within[within.length - 1], op, valueSrc, meta, key, at, flat);
70785
71779
  return lines.join("\n");
70786
71780
  }
70787
71781
  function jsonValueSpan(src, es, ee) {
@@ -70834,14 +71828,14 @@ function fsDocRootSegs(dataRoot, segs) {
70834
71828
  for (let i2 = segs.length; i2 >= 0; i2--) {
70835
71829
  const sub = segs.slice(0, i2);
70836
71830
  if (!sub.every((g) => typeof g === "string")) continue;
70837
- const body = dirBodyFile(path10.resolve(dataRoot, ...sub.map(String)));
71831
+ const body = dirBodyFile(path11.resolve(dataRoot, ...sub.map(String)));
70838
71832
  if (fs10.existsSync(body)) return { docSegs: sub, bodyFile: body };
70839
71833
  }
70840
71834
  return null;
70841
71835
  }
70842
71836
  function isPlainDir(dataRoot, s2, segs) {
70843
71837
  if (!segs.every((g) => typeof g === "string")) return false;
70844
- const abs = path10.resolve(dataRoot, ...segs.map(String));
71838
+ const abs = path11.resolve(dataRoot, ...segs.map(String));
70845
71839
  if (!fs10.existsSync(abs) || !fs10.statSync(abs).isDirectory()) return false;
70846
71840
  try {
70847
71841
  chapterSource(dataRoot, s2, segs);
@@ -70868,7 +71862,7 @@ function canonSegs(s2, segs, keepLast) {
70868
71862
  }
70869
71863
  function bornAsDocument(dataRoot, e3, tag, neighbors = {}) {
70870
71864
  const writeDirSegs = e3.dirBacked ? e3.docSegs : e3.docSegs.slice(0, -1);
70871
- const writeDir = path10.resolve(dataRoot, ...writeDirSegs.map(String));
71865
+ const writeDir = path11.resolve(dataRoot, ...writeDirSegs.map(String));
70872
71866
  const src = [...tag ? [tag] : [], e3.valueSrc, ""].join("\n");
70873
71867
  const title = String(e3.name || "object");
70874
71868
  const base = isOverlayDirConcrete(e3.concrete) ? nextMemberName(fs10.existsSync(writeDir) ? fs10.readdirSync(writeDir) : [], "title", { ...neighbors, title }) : pointerSafeName(title);
@@ -70905,7 +71899,7 @@ function applyEdits2(dataRoot, s2, edits) {
70905
71899
  return "";
70906
71900
  }
70907
71901
  try {
70908
- for (const o2 of byFile.get(bodyFile) ?? []) src = editChapterSource(src, o2.within, o2.op, o2.valueSrc, o2.meta, o2.key, o2.at);
71902
+ for (const o2 of byFile.get(bodyFile) ?? []) src = editChapterSource(src, o2.within, o2.op, o2.valueSrc, o2.meta, o2.key, o2.at, o2.flat);
70909
71903
  } catch {
70910
71904
  return src;
70911
71905
  }
@@ -70915,7 +71909,7 @@ function applyEdits2(dataRoot, s2, edits) {
70915
71909
  const editSegs = applyRemap(canonSegs(s2, strToSegs(e3.path ?? ""), true));
70916
71910
  const op = String(e3.op ?? "");
70917
71911
  if (op === "insert" && (e3.concrete === "file/yamlover" || isOverlayDirConcrete(e3.concrete)) && isPlainDir(dataRoot, s2, editSegs)) {
70918
- const dir = path10.resolve(dataRoot, ...editSegs.map(String));
71912
+ const dir = path11.resolve(dataRoot, ...editSegs.map(String));
70919
71913
  const src = [...metaTag(e3.meta, void 0, false) ? [metaTag(e3.meta, void 0, false)] : [], String(e3.yamlover ?? ""), ""].join("\n");
70920
71914
  if (e3.yamlover) parseYamlover(String(e3.yamlover), "<edit>");
70921
71915
  const final = writeObject(dataRoot, dir, objectBaseName(String(e3.name || "new")), String(e3.concrete), src);
@@ -70924,16 +71918,16 @@ function applyEdits2(dataRoot, s2, edits) {
70924
71918
  }
70925
71919
  if (op === "insert" && e3.concrete === "dir") {
70926
71920
  if (!editSegs.every((g) => typeof g === "string")) throw new Error("a folder needs a directory parent");
70927
- const abs = path10.resolve(dataRoot, ...editSegs.map(String));
71921
+ const abs = path11.resolve(dataRoot, ...editSegs.map(String));
70928
71922
  if (!fs10.existsSync(abs) || !fs10.statSync(abs).isDirectory()) throw new Error("a folder can only be created inside a directory");
70929
71923
  const final = uniqueName(abs, objectBaseName(String(e3.name || "New Folder")));
70930
- mkdirInside(dataRoot, path10.join(abs, final));
71924
+ mkdirInside(dataRoot, path11.join(abs, final));
70931
71925
  created.push(segsToStr([...editSegs, final]));
70932
71926
  continue;
70933
71927
  }
70934
71928
  {
70935
71929
  const stripped = op === "insert" && typeof editSegs[editSegs.length - 1] === "number" ? editSegs.slice(0, -1) : editSegs;
70936
- const absDir = stripped.every((g) => typeof g === "string") ? path10.resolve(dataRoot, ...stripped.map(String)) : null;
71930
+ const absDir = stripped.every((g) => typeof g === "string") ? path11.resolve(dataRoot, ...stripped.map(String)) : null;
70937
71931
  const isDirTarget = absDir !== null && fs10.existsSync(absDir) && fs10.statSync(absDir).isDirectory();
70938
71932
  if (isDirTarget) {
70939
71933
  const bodyFile2 = dirBodyFile(absDir);
@@ -70974,7 +71968,7 @@ function applyEdits2(dataRoot, s2, edits) {
70974
71968
  route,
70975
71969
  explicitConcrete: e3.concrete ?? null,
70976
71970
  memberName,
70977
- writes: memberName ? [{ kind: "dir", fsPath: relPosix(dataRoot, path10.join(absDir, memberName)), concrete: memberConcrete }, ...route === "dir-seq" ? [bodySplice] : []] : [bodySplice]
71971
+ writes: memberName ? [{ kind: "dir", fsPath: relPosix(dataRoot, path11.join(absDir, memberName)), concrete: memberConcrete }, ...route === "dir-seq" ? [bodySplice] : []] : [bodySplice]
70978
71972
  };
70979
71973
  logDiagnostics(enforce(validateWrite(snap), validationMode()));
70980
71974
  if (route === "dir") {
@@ -71016,7 +72010,7 @@ function applyEdits2(dataRoot, s2, edits) {
71016
72010
  const inlineKeyed = typeof nodeKey === "string" && nodeSegs.every((g) => typeof g === "string") && inlineHere;
71017
72011
  const inlineOrdinal = typeof nodeKey === "number" && inlineHere && nBack.docSegs.every((g) => typeof g === "string");
71018
72012
  const docRow = inlineKeyed || inlineOrdinal ? s2.node(storePath(nBack.docSegs)) : null;
71019
- const encConcrete = docRow ? concreteOf(s2, dataRoot, nBack.docSegs, docRow) : nBack.dirBacked ? dirConcreteOf(path10.resolve(dataRoot, ...nBack.docSegs.map(String))) : "yamlover";
72013
+ const encConcrete = docRow ? concreteOf(s2, dataRoot, nBack.docSegs, docRow) : nBack.dirBacked ? dirConcreteOf(path11.resolve(dataRoot, ...nBack.docSegs.map(String))) : "yamlover";
71020
72014
  if ((inlineKeyed || inlineOrdinal) && subchapterMaterializes(encConcrete)) {
71021
72015
  let memberSrc = null;
71022
72016
  let memberMeta;
@@ -71077,7 +72071,7 @@ function applyEdits2(dataRoot, s2, edits) {
71077
72071
  const enc = memberSrc === null ? "body" : deriveMemberEncoding({ keyed: inlineKeyed, container: true, tagged: typeof memberMeta === "string" || rootIsYo(memberSrc), insideContent });
71078
72072
  if (enc !== "body") {
71079
72073
  if (memberSrc && !isPointerValue(memberSrc)) parseYamlover(memberSrc, "<edit>");
71080
- const docAbs = path10.resolve(dataRoot, ...nBack.docSegs.map(String));
72074
+ const docAbs = path11.resolve(dataRoot, ...nBack.docSegs.map(String));
71081
72075
  const within = nodeSegs.slice(nBack.docSegs.length);
71082
72076
  const idx = within[within.length - 1];
71083
72077
  const names3 = fs10.readdirSync(docAbs);
@@ -71091,7 +72085,7 @@ function applyEdits2(dataRoot, s2, edits) {
71091
72085
  route: enc,
71092
72086
  memberName,
71093
72087
  writes: [
71094
- { kind: "dir", fsPath: relPosix(dataRoot, path10.join(docAbs, memberName)), concrete: memberConcrete },
72088
+ { kind: "dir", fsPath: relPosix(dataRoot, path11.join(docAbs, memberName)), concrete: memberConcrete },
71095
72089
  { kind: "splice", fsPath: relPosix(dataRoot, nBack.bodyFile) }
71096
72090
  ]
71097
72091
  }),
@@ -71147,11 +72141,11 @@ function applyEdits2(dataRoot, s2, edits) {
71147
72141
  } catch {
71148
72142
  }
71149
72143
  if (detach === null) {
71150
- const memberAbs2 = path10.resolve(dataRoot, ...editSegs.map(String));
71151
- const trashDir = path10.join(path10.dirname(memberAbs2), ".yo", ".trash");
72144
+ const memberAbs2 = path11.resolve(dataRoot, ...editSegs.map(String));
72145
+ const trashDir = path11.join(path11.dirname(memberAbs2), ".yo", ".trash");
71152
72146
  fs10.mkdirSync(trashDir, { recursive: true });
71153
- let dest = path10.join(trashDir, memberName);
71154
- for (let n2 = 2; fs10.existsSync(dest); n2++) dest = path10.join(trashDir, `${memberName}-${n2}`);
72147
+ let dest = path11.join(trashDir, memberName);
72148
+ for (let n2 = 2; fs10.existsSync(dest); n2++) dest = path11.join(trashDir, `${memberName}-${n2}`);
71155
72149
  console.warn(`[/api/edit] remove of ORPHANED member ${segsToStr(editSegs)}: archived ${memberAbs2} -> ${dest}`);
71156
72150
  fs10.renameSync(memberAbs2, dest);
71157
72151
  movedStorage = true;
@@ -71160,7 +72154,7 @@ function applyEdits2(dataRoot, s2, edits) {
71160
72154
  const list2 = byFile.get(detachFile) ?? [];
71161
72155
  list2.push(detach);
71162
72156
  byFile.set(detachFile, list2);
71163
- const memberAbs = path10.resolve(dataRoot, ...editSegs.map(String));
72157
+ const memberAbs = path11.resolve(dataRoot, ...editSegs.map(String));
71164
72158
  if (fs10.existsSync(memberAbs)) pendingArchives.push({ abs: memberAbs, name: memberName });
71165
72159
  continue;
71166
72160
  }
@@ -71182,6 +72176,7 @@ function applyEdits2(dataRoot, s2, edits) {
71182
72176
  name: e3.name ? String(e3.name) : void 0,
71183
72177
  key: e3.key === void 0 ? void 0 : String(e3.key),
71184
72178
  at: typeof e3.at === "number" && Number.isFinite(e3.at) && e3.at >= 0 ? Math.floor(e3.at) : void 0,
72179
+ flat: e3.flat === true ? true : void 0,
71185
72180
  docSegs,
71186
72181
  dirBacked
71187
72182
  };
@@ -71210,7 +72205,7 @@ function applyEdits2(dataRoot, s2, edits) {
71210
72205
  for (const o2 of ops) {
71211
72206
  const { valueSrc, meta } = o2;
71212
72207
  if (valueSrc && !isPointerValue(valueSrc)) parseYamlover(valueSrc, "<edit>");
71213
- src = editChapterSource(src, o2.within, o2.op, valueSrc, meta, o2.key, o2.at);
72208
+ src = editChapterSource(src, o2.within, o2.op, valueSrc, meta, o2.key, o2.at, o2.flat);
71214
72209
  }
71215
72210
  parseYamlover(src, bodyFile);
71216
72211
  pendingWrites.push([bodyFile, src]);
@@ -71228,20 +72223,20 @@ function applyEdits2(dataRoot, s2, edits) {
71228
72223
  }
71229
72224
  for (const a2 of pendingArchives) {
71230
72225
  if (!fs10.existsSync(a2.abs)) continue;
71231
- const trashDir = path10.join(path10.dirname(a2.abs), ".yo", ".trash");
72226
+ const trashDir = path11.join(path11.dirname(a2.abs), ".yo", ".trash");
71232
72227
  fs10.mkdirSync(trashDir, { recursive: true });
71233
- let dest = path10.join(trashDir, a2.name);
71234
- for (let n2 = 2; fs10.existsSync(dest); n2++) dest = path10.join(trashDir, `${a2.name}-${n2}`);
72228
+ let dest = path11.join(trashDir, a2.name);
72229
+ for (let n2 = 2; fs10.existsSync(dest); n2++) dest = path11.join(trashDir, `${a2.name}-${n2}`);
71235
72230
  console.warn(`[/api/edit] remove of member: archived ${a2.abs} -> ${dest}`);
71236
72231
  fs10.renameSync(a2.abs, dest);
71237
72232
  movedStorage = true;
71238
72233
  }
71239
72234
  return { touched, created, appended, movedStorage };
71240
72235
  }
71241
- var PREVIEW_ROOT = path10.join(os.tmpdir(), ".yo-preview-nonexistent");
72236
+ var PREVIEW_ROOT = path11.join(os.tmpdir(), ".yo-preview-nonexistent");
71242
72237
  function envelopeDeps(s2, dataRoot, membersOnDisk) {
71243
72238
  return {
71244
- memberExists: (sg) => membersOnDisk && sg.every((x2) => typeof x2 === "string") && fs10.existsSync(path10.resolve(dataRoot, ...sg.map(String))),
72239
+ memberExists: (sg) => membersOnDisk && sg.every((x2) => typeof x2 === "string") && fs10.existsSync(path11.resolve(dataRoot, ...sg.map(String))),
71245
72240
  formatAt: (sg) => s2.node(storePath(sg))?.format ?? null,
71246
72241
  stub: (sg) => s2.node(storePath(sg)) ? linkMarker(dataRoot, s2, sg) : null,
71247
72242
  refTargetAt: (holder, pos) => {
@@ -71424,7 +72419,7 @@ var EXT_CT = {
71424
72419
  ".epub": "application/epub+zip"
71425
72420
  };
71426
72421
  function formatFromExt(file) {
71427
- return EXT_CT[path10.extname(file).toLowerCase()] ?? null;
72422
+ return EXT_CT[path11.extname(file).toLowerCase()] ?? null;
71428
72423
  }
71429
72424
  var UTF8_CT = /* @__PURE__ */ new Set([
71430
72425
  "text/html",
@@ -71449,8 +72444,8 @@ function defaultDepth(s2, dataRoot, segs, row, kind) {
71449
72444
  if (kind === "binary") return 1;
71450
72445
  return isDirConcrete(concreteOf(s2, dataRoot, segs, row)) ? 1 : Infinity;
71451
72446
  }
71452
- function refMarker(text, path11) {
71453
- return { [REF_KEY]: { text, path: path11 } };
72447
+ function refMarker(text, path12) {
72448
+ return { [REF_KEY]: { text, path: path12 } };
71454
72449
  }
71455
72450
  function clampThumbDim(raw, def) {
71456
72451
  const n2 = raw == null ? NaN : Math.round(Number(raw));