@ai-matrx/content-ir 0.11.6 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1266,18 +1266,18 @@ var KindStreamParser = class {
1266
1266
  completeTypedObject(path, objectValue, at) {
1267
1267
  const pathKey = this.pathKey(path);
1268
1268
  if (this.rawObjectPaths.has(pathKey)) return;
1269
- const declaredKind = readObjectKind(objectValue);
1269
+ const declaredKind2 = readObjectKind(objectValue);
1270
1270
  const committedKind = this.objectKinds.get(pathKey);
1271
1271
  if (committedKind && this.pendingSchemaPaths.get(committedKind)?.has(pathKey)) {
1272
1272
  this.closedPendingPaths.add(pathKey);
1273
1273
  return;
1274
1274
  }
1275
- if (!declaredKind && committedKind && this.speculativeKinds.has(pathKey)) {
1275
+ if (!declaredKind2 && committedKind && this.speculativeKinds.has(pathKey)) {
1276
1276
  this.speculativeKinds.delete(pathKey);
1277
1277
  this.finalizeSpeculatedObject(path, objectValue, committedKind, at);
1278
1278
  return;
1279
1279
  }
1280
- if (path.length === 0 && !declaredKind && !committedKind && this.rootSurfaceKind) {
1280
+ if (path.length === 0 && !declaredKind2 && !committedKind && this.rootSurfaceKind) {
1281
1281
  const surfaceKind = this.rootSurfaceKind;
1282
1282
  this.rootSurfaceKind = null;
1283
1283
  this.objectKinds.set(pathKey, surfaceKind);
@@ -1293,7 +1293,7 @@ var KindStreamParser = class {
1293
1293
  this.finalizeSpeculatedObject(path, objectValue, surfaceKind, at);
1294
1294
  return;
1295
1295
  }
1296
- if (!declaredKind) {
1296
+ if (!declaredKind2) {
1297
1297
  this.emitRawObject(
1298
1298
  path,
1299
1299
  objectValue,
@@ -3209,8 +3209,8 @@ function refToObjectField(resolved, path, ctx) {
3209
3209
  function isAnyValueSchema(node) {
3210
3210
  return node.type === void 0 && node.enum === void 0 && node.const === void 0 && node.properties === void 0 && node.items === void 0 && node.additionalProperties === void 0 && node.anyOf === void 0 && node.oneOf === void 0 && node.allOf === void 0 && node.$ref === void 0;
3211
3211
  }
3212
- function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3213
- if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind)) return;
3212
+ function registerDeclaredKindDraft(declaredKind2, objectNode, path, ctx) {
3213
+ if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind2)) return;
3214
3214
  if (!isRecord4(objectNode.properties)) return;
3215
3215
  const memberRequired = new Set(
3216
3216
  Array.isArray(objectNode.required) ? objectNode.required.filter((k) => typeof k === "string") : []
@@ -3228,8 +3228,8 @@ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
3228
3228
  );
3229
3229
  }
3230
3230
  ctx.blockSchemas.push({
3231
- slug: declaredKind,
3232
- label: formatBlockLabel(declaredKind),
3231
+ slug: declaredKind2,
3232
+ label: formatBlockLabel(declaredKind2),
3233
3233
  fields
3234
3234
  });
3235
3235
  }
@@ -4973,6 +4973,1421 @@ function asKindInstance(item, kind) {
4973
4973
  return { [KIND_KEY]: resolved, ...item };
4974
4974
  }
4975
4975
 
4976
+ // source/offsets.ts
4977
+ function isHigh(code) {
4978
+ return code >= 55296 && code <= 56319;
4979
+ }
4980
+ function isLow(code) {
4981
+ return code >= 56320 && code <= 57343;
4982
+ }
4983
+ function splitsSurrogatePair(text, offset) {
4984
+ if (offset <= 0 || offset >= text.length) return false;
4985
+ return isHigh(text.charCodeAt(offset - 1)) && isLow(text.charCodeAt(offset));
4986
+ }
4987
+ function buildCodePointIndex(text) {
4988
+ const pairStarts = [];
4989
+ for (let i = 0; i < text.length - 1; i++) {
4990
+ if (isHigh(text.charCodeAt(i)) && isLow(text.charCodeAt(i + 1))) {
4991
+ pairStarts.push(i);
4992
+ i++;
4993
+ }
4994
+ }
4995
+ const countBelow = (limit) => {
4996
+ let lo = 0;
4997
+ let hi = pairStarts.length;
4998
+ while (lo < hi) {
4999
+ const mid = lo + hi >>> 1;
5000
+ if (pairStarts[mid] < limit) lo = mid + 1;
5001
+ else hi = mid;
5002
+ }
5003
+ return lo;
5004
+ };
5005
+ const toCodePoint = (utf16) => {
5006
+ return utf16 - countBelow(utf16 - 1);
5007
+ };
5008
+ const toUtf16 = (codePoint) => {
5009
+ let lo = 0;
5010
+ let hi = pairStarts.length;
5011
+ while (lo < hi) {
5012
+ const mid = lo + hi >>> 1;
5013
+ const start = pairStarts[mid];
5014
+ if (start - mid < codePoint) lo = mid + 1;
5015
+ else hi = mid;
5016
+ }
5017
+ return codePoint + lo;
5018
+ };
5019
+ return {
5020
+ toCodePoint,
5021
+ toUtf16,
5022
+ lengthCp: text.length - pairStarts.length
5023
+ };
5024
+ }
5025
+ function toCodePointOffset(text, utf16) {
5026
+ return buildCodePointIndex(text).toCodePoint(utf16);
5027
+ }
5028
+ function toUtf16Offset(text, codePoint) {
5029
+ return buildCodePointIndex(text).toUtf16(codePoint);
5030
+ }
5031
+
5032
+ // source/constants.ts
5033
+ var XML_TAG_BLOCK_NAMES = [
5034
+ "thinking",
5035
+ "think",
5036
+ "reasoning",
5037
+ "info",
5038
+ "task",
5039
+ "database",
5040
+ "private",
5041
+ "plan",
5042
+ "event",
5043
+ "tool",
5044
+ "questionnaire",
5045
+ "flashcards",
5046
+ "cooking_recipe",
5047
+ "timeline",
5048
+ "progress_tracker",
5049
+ "troubleshooting",
5050
+ "resources",
5051
+ "research"
5052
+ ];
5053
+ var THINKING_FAMILY = ["thinking", "think", "reasoning"];
5054
+ var ATTRIBUTE_XML_NAMES = [
5055
+ "decision",
5056
+ "artifact",
5057
+ "editor_error",
5058
+ "editor_code_snippet",
5059
+ "audiocite"
5060
+ ];
5061
+ var KNOWN_XML_TAG_NAMES = /* @__PURE__ */ new Set([
5062
+ ...XML_TAG_BLOCK_NAMES,
5063
+ ...ATTRIBUTE_XML_NAMES
5064
+ ]);
5065
+ var ALLOWED_RAW_HTML_TAGS = /* @__PURE__ */ new Set([
5066
+ "img",
5067
+ "a",
5068
+ "br",
5069
+ "hr",
5070
+ "span",
5071
+ "p",
5072
+ "strong",
5073
+ "b",
5074
+ "em",
5075
+ "i",
5076
+ "u",
5077
+ "s",
5078
+ "del",
5079
+ "ins",
5080
+ "sup",
5081
+ "sub",
5082
+ "mark",
5083
+ "kbd",
5084
+ "abbr",
5085
+ "small",
5086
+ "code",
5087
+ "pre",
5088
+ "ul",
5089
+ "ol",
5090
+ "li",
5091
+ "blockquote",
5092
+ "h1",
5093
+ "h2",
5094
+ "h3",
5095
+ "h4",
5096
+ "h5",
5097
+ "h6",
5098
+ "table",
5099
+ "thead",
5100
+ "tbody",
5101
+ "tfoot",
5102
+ "tr",
5103
+ "th",
5104
+ "td",
5105
+ "caption",
5106
+ "colgroup",
5107
+ "col",
5108
+ "figure",
5109
+ "figcaption"
5110
+ ]);
5111
+ var HTML_BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
5112
+ "p",
5113
+ "hr",
5114
+ "ul",
5115
+ "ol",
5116
+ "li",
5117
+ "blockquote",
5118
+ "h1",
5119
+ "h2",
5120
+ "h3",
5121
+ "h4",
5122
+ "h5",
5123
+ "h6",
5124
+ "table",
5125
+ "thead",
5126
+ "tbody",
5127
+ "tfoot",
5128
+ "tr",
5129
+ "th",
5130
+ "td",
5131
+ "caption",
5132
+ "colgroup",
5133
+ "col",
5134
+ "figure",
5135
+ "figcaption"
5136
+ ]);
5137
+ var SPECIAL_CODE_LANGUAGES = /* @__PURE__ */ new Set([
5138
+ "transcript",
5139
+ "tasks",
5140
+ "structured_info",
5141
+ "questionnaire",
5142
+ "flashcards",
5143
+ "cooking_recipe",
5144
+ "mermaid",
5145
+ "svg",
5146
+ "chart",
5147
+ "map",
5148
+ "stats",
5149
+ "diff",
5150
+ "html",
5151
+ "react",
5152
+ "matrx"
5153
+ ]);
5154
+ var CODE_LANGUAGE_ALIASES = {
5155
+ mmd: "mermaid",
5156
+ jsx: "react",
5157
+ tsx: "react"
5158
+ };
5159
+ var TYPED_JSON_ROOT_KEYS = {
5160
+ quiz_title: "quiz",
5161
+ presentation: "presentation",
5162
+ decision_tree: "decision_tree",
5163
+ comparison: "comparison_table",
5164
+ diagram: "diagram",
5165
+ math_problem: "math_problem",
5166
+ item_presentation: "item_presentation",
5167
+ name: "schema_proposal"
5168
+ };
5169
+ var TREE_GLYPHS = /[├└│┌┐┘┬┴┤┼─]/;
5170
+ var PINNED_ANCHOR_RE = /^<!--@a:([A-Za-z0-9_-]+)-->$/;
5171
+ var STRICT_VARIABLE_RE = /^\{\{([a-zA-Z_][a-zA-Z0-9_.]*)\}\}$/;
5172
+ var CITE_RE = /^<matrxcite\s+n="(\d+)"\s*\/>/;
5173
+ function normalizeFenceLanguage(language) {
5174
+ const lower = language.toLowerCase();
5175
+ return CODE_LANGUAGE_ALIASES[lower] ?? lower;
5176
+ }
5177
+
5178
+ // source/math.ts
5179
+ var TEX_SIGNAL = /\\[A-Za-z]+|[\\^_{}=<>+]/;
5180
+ var LONE_VARIABLE = /^[A-Za-z](?:'|[0-9])?$/;
5181
+ function isSingleDollarMath(content, after) {
5182
+ if (!content || content.length > 400) return false;
5183
+ if (/^\s/.test(content) || /\s$/.test(content)) return false;
5184
+ if (after !== void 0 && /[0-9]/.test(after)) return false;
5185
+ if (LONE_VARIABLE.test(content)) return true;
5186
+ if (/^[0-9]/.test(content)) return /\\[A-Za-z]+|[\\^_{}]/.test(content);
5187
+ return TEX_SIGNAL.test(content);
5188
+ }
5189
+ function singleDollarMathEnd(text, open, limit = text.length) {
5190
+ let close = -1;
5191
+ for (let k = open + 1; k < limit; k += 1) {
5192
+ const c = text[k];
5193
+ if (c === "\n") break;
5194
+ if (c === "\\") {
5195
+ k += 1;
5196
+ continue;
5197
+ }
5198
+ if (c === "$") {
5199
+ close = k;
5200
+ break;
5201
+ }
5202
+ }
5203
+ if (close === -1 || text[close + 1] === "$") return -1;
5204
+ const content = text.slice(open + 1, close);
5205
+ return isSingleDollarMath(content, text[close + 1]) ? close + 1 : -1;
5206
+ }
5207
+
5208
+ // source/xml-tag.ts
5209
+ var XML_NAME_START = /[A-Za-z_]/;
5210
+ var XML_NAME_CHARACTER = /[\w.:-]/;
5211
+ var WHITESPACE = /\s/;
5212
+ function readXmlTag(content, start) {
5213
+ let cursor = start + 1;
5214
+ const isClosing = content[cursor] === "/";
5215
+ if (isClosing) cursor++;
5216
+ if (!XML_NAME_START.test(content[cursor] ?? "")) return null;
5217
+ const nameStart = cursor;
5218
+ while (XML_NAME_CHARACTER.test(content[cursor] ?? "")) cursor++;
5219
+ const tagName = content.slice(nameStart, cursor);
5220
+ const attributes = [];
5221
+ if (isClosing) {
5222
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5223
+ if (content[cursor] !== ">") return null;
5224
+ return {
5225
+ tagName,
5226
+ raw: content.slice(start, cursor + 1),
5227
+ isClosing,
5228
+ isSelfClosing: false,
5229
+ attributes
5230
+ };
5231
+ }
5232
+ while (cursor < content.length) {
5233
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5234
+ if (content[cursor] === ">")
5235
+ return {
5236
+ tagName,
5237
+ raw: content.slice(start, cursor + 1),
5238
+ isClosing,
5239
+ isSelfClosing: false,
5240
+ attributes
5241
+ };
5242
+ if (content[cursor] === "/") {
5243
+ cursor++;
5244
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5245
+ if (content[cursor] !== ">") return null;
5246
+ return {
5247
+ tagName,
5248
+ raw: content.slice(start, cursor + 1),
5249
+ isClosing,
5250
+ isSelfClosing: true,
5251
+ attributes
5252
+ };
5253
+ }
5254
+ if (!XML_NAME_START.test(content[cursor] ?? "")) return null;
5255
+ const attributeStart = cursor;
5256
+ while (XML_NAME_CHARACTER.test(content[cursor] ?? "")) cursor++;
5257
+ const name = content.slice(attributeStart, cursor);
5258
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5259
+ if (content[cursor] !== "=") return null;
5260
+ cursor++;
5261
+ while (WHITESPACE.test(content[cursor] ?? "")) cursor++;
5262
+ const quote = content[cursor];
5263
+ if (quote !== '"' && quote !== "'") return null;
5264
+ const valueStart = ++cursor;
5265
+ while (cursor < content.length && content[cursor] !== quote) cursor++;
5266
+ if (cursor === content.length) return null;
5267
+ attributes.push({ name, value: content.slice(valueStart, cursor) });
5268
+ cursor++;
5269
+ }
5270
+ return null;
5271
+ }
5272
+ function isEscapedBacktick(line, offset) {
5273
+ let slashes = 0;
5274
+ for (let i = offset - 1; line[i] === "\\"; i--) slashes++;
5275
+ return slashes % 2 === 1;
5276
+ }
5277
+ var XmlContainerTracker = class {
5278
+ constructor(rootTag) {
5279
+ this.rootTag = rootTag;
5280
+ }
5281
+ rootTag;
5282
+ depth = 0;
5283
+ inComment = false;
5284
+ inCdata = false;
5285
+ inlineTicks = 0;
5286
+ fenceMarker = null;
5287
+ consumeLine(line, startOffset = 0) {
5288
+ const fence = /^[ \t]*(`{3,}|~{3,})(.*)$/.exec(line);
5289
+ if (!this.inComment && !this.inCdata && this.inlineTicks === 0 && fence) {
5290
+ const marker = fence[1];
5291
+ const char = marker[0];
5292
+ const suffix = fence[2];
5293
+ if (marker.length >= 3) {
5294
+ if (!this.fenceMarker) {
5295
+ this.fenceMarker = { char, ticks: marker.length };
5296
+ return null;
5297
+ }
5298
+ if (char === this.fenceMarker.char && marker.length >= this.fenceMarker.ticks && suffix.trim() === "") {
5299
+ this.fenceMarker = null;
5300
+ }
5301
+ return null;
5302
+ }
5303
+ }
5304
+ if (this.fenceMarker) return null;
5305
+ for (let i = startOffset; i < line.length; i++) {
5306
+ if (this.inlineTicks > 0) {
5307
+ if (line[i] === "`") {
5308
+ let end = i;
5309
+ while (line[end] === "`") end++;
5310
+ if (end - i === this.inlineTicks) this.inlineTicks = 0;
5311
+ i = end - 1;
5312
+ }
5313
+ continue;
5314
+ }
5315
+ if (this.inComment) {
5316
+ const end = line.indexOf("-->", i);
5317
+ if (end === -1) return null;
5318
+ this.inComment = false;
5319
+ i = end + 2;
5320
+ continue;
5321
+ }
5322
+ if (this.inCdata) {
5323
+ const end = line.indexOf("]]>", i);
5324
+ if (end === -1) return null;
5325
+ this.inCdata = false;
5326
+ i = end + 2;
5327
+ continue;
5328
+ }
5329
+ if (line.startsWith("<!--", i)) {
5330
+ this.inComment = true;
5331
+ i += 3;
5332
+ continue;
5333
+ }
5334
+ if (line.startsWith("<![CDATA[", i)) {
5335
+ this.inCdata = true;
5336
+ i += 8;
5337
+ continue;
5338
+ }
5339
+ if (line[i] === "`" && !isEscapedBacktick(line, i)) {
5340
+ let end = i;
5341
+ while (line[end] === "`") end++;
5342
+ this.inlineTicks = end - i;
5343
+ i = end - 1;
5344
+ continue;
5345
+ }
5346
+ if (line[i] !== "<") continue;
5347
+ const tag = readXmlTag(line, i);
5348
+ if (!tag) continue;
5349
+ const tagEnd = i + tag.raw.length;
5350
+ if (tag.tagName === this.rootTag) {
5351
+ if (tag.isClosing) this.depth--;
5352
+ else if (!tag.isSelfClosing) this.depth++;
5353
+ if (this.depth === 0) return tagEnd;
5354
+ }
5355
+ i = tagEnd - 1;
5356
+ }
5357
+ return null;
5358
+ }
5359
+ };
5360
+
5361
+ // source/tokenize.ts
5362
+ var NOT_WHITESPACE = /\S/;
5363
+ function countStructuralBraces(source) {
5364
+ let opens = 0;
5365
+ let closes = 0;
5366
+ let inString = false;
5367
+ let escaped = false;
5368
+ for (let i = 0; i < source.length; i++) {
5369
+ const char = source[i];
5370
+ if (inString) {
5371
+ if (escaped) escaped = false;
5372
+ else if (char === "\\") escaped = true;
5373
+ else if (char === '"') inString = false;
5374
+ continue;
5375
+ }
5376
+ if (char === '"') inString = true;
5377
+ else if (char === "{") opens++;
5378
+ else if (char === "}") closes++;
5379
+ }
5380
+ return { opens, closes };
5381
+ }
5382
+ function firstJsonKey(content) {
5383
+ const match = /^\{\s*"([^"]+)"/.exec(content.trimStart());
5384
+ return match ? match[1] : null;
5385
+ }
5386
+ function jsonMeta(content) {
5387
+ const meta = {};
5388
+ const key = firstJsonKey(content);
5389
+ if (key) meta.firstKey = key;
5390
+ try {
5391
+ const parsed = JSON.parse(content.trim());
5392
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
5393
+ const kind = parsed.__kind;
5394
+ if (typeof kind === "string" && kind.trim()) meta.kind = kind;
5395
+ }
5396
+ } catch {
5397
+ const head = /^\{\s*"__kind"\s*:\s*"([^"]*)"/.exec(content.trimStart());
5398
+ if (head) meta.kind = head[1];
5399
+ }
5400
+ if (typeof meta.kind === "string" && meta.kind.startsWith("directive_v")) {
5401
+ meta.directive = true;
5402
+ }
5403
+ if (key === "matrx_version") meta.directive = true;
5404
+ if (key && TYPED_JSON_ROOT_KEYS[key]) meta.typed = TYPED_JSON_ROOT_KEYS[key];
5405
+ return meta;
5406
+ }
5407
+ function isRecognizedJsonHead(content) {
5408
+ const key = firstJsonKey(content);
5409
+ if (!key) return false;
5410
+ return key === "__kind" || key === "matrx_version" || key in TYPED_JSON_ROOT_KEYS;
5411
+ }
5412
+ function matchingJsonObjectEnd(source, start, limit) {
5413
+ if (source[start] !== "{") return null;
5414
+ const stack = ["{"];
5415
+ let inString = false;
5416
+ let escaped = false;
5417
+ for (let index = start + 1; index < limit; index++) {
5418
+ const char = source[index];
5419
+ if (inString) {
5420
+ if (escaped) escaped = false;
5421
+ else if (char === "\\") escaped = true;
5422
+ else if (char === '"') inString = false;
5423
+ continue;
5424
+ }
5425
+ if (char === '"') {
5426
+ inString = true;
5427
+ continue;
5428
+ }
5429
+ if (char === "{" || char === "[") {
5430
+ stack.push(char);
5431
+ continue;
5432
+ }
5433
+ if (char !== "}" && char !== "]") continue;
5434
+ const opening = stack.pop();
5435
+ if (char === "}" && opening !== "{" || char === "]" && opening !== "[") return null;
5436
+ if (stack.length === 0) return index + 1;
5437
+ }
5438
+ return null;
5439
+ }
5440
+ function declaredKind(candidate) {
5441
+ try {
5442
+ const parsed = JSON.parse(candidate);
5443
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
5444
+ const kind = parsed.__kind;
5445
+ return typeof kind === "string" && kind.trim() ? kind : null;
5446
+ } catch {
5447
+ return null;
5448
+ }
5449
+ }
5450
+ function isUnclosedGenericXmlOpening(source) {
5451
+ const text = source.trimStart();
5452
+ const prefix = /^<([A-Za-z_][\w.:-]*)(?=\s|\/|$)/.exec(text);
5453
+ if (!prefix || KNOWN_XML_TAG_NAMES.has(prefix[1]) || ALLOWED_RAW_HTML_TAGS.has(prefix[1].toLowerCase()))
5454
+ return false;
5455
+ let quote = null;
5456
+ for (let i = prefix[0].length; i < text.length; i++) {
5457
+ if (quote) {
5458
+ if (text[i] === quote) quote = null;
5459
+ } else if (text[i] === "'" || text[i] === '"') quote = text[i];
5460
+ else if (text[i] === ">") return false;
5461
+ }
5462
+ return true;
5463
+ }
5464
+ function jsonStringState(line, from, upTo, state) {
5465
+ let { inString, escaped } = state;
5466
+ for (let idx = from; idx < upTo; idx++) {
5467
+ const ch = line[idx];
5468
+ if (escaped) {
5469
+ escaped = false;
5470
+ continue;
5471
+ }
5472
+ if (ch === "\\" && inString) {
5473
+ escaped = true;
5474
+ continue;
5475
+ }
5476
+ if (ch === '"') inString = !inString;
5477
+ }
5478
+ return { inString, escaped };
5479
+ }
5480
+ function backtickRunLength(str2, pos) {
5481
+ let n = 0;
5482
+ while (pos + n < str2.length && str2[pos + n] === "`") n++;
5483
+ return n;
5484
+ }
5485
+ var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
5486
+ var Tokenizer = class {
5487
+ constructor(text) {
5488
+ this.text = text;
5489
+ this.n = text.length;
5490
+ let start = 0;
5491
+ for (let i = 0; i < text.length; i++) {
5492
+ if (text.charCodeAt(i) === 10) {
5493
+ this.lineStarts.push(start);
5494
+ this.contentEnds.push(i > start && text.charCodeAt(i - 1) === 13 ? i - 1 : i);
5495
+ this.lineEnds.push(i + 1);
5496
+ start = i + 1;
5497
+ }
5498
+ }
5499
+ if (start < text.length || text.length === 0) {
5500
+ this.lineStarts.push(start);
5501
+ this.contentEnds.push(text.length);
5502
+ this.lineEnds.push(text.length);
5503
+ }
5504
+ }
5505
+ text;
5506
+ n;
5507
+ lineStarts = [];
5508
+ contentEnds = [];
5509
+ lineEnds = [];
5510
+ blocks = [];
5511
+ blockCache = /* @__PURE__ */ new Map();
5512
+ /** Lazily built: for line i, first line j >= i where brace net from i drops to <= 0. */
5513
+ braceStop = null;
5514
+ braceNet = null;
5515
+ get lineCount() {
5516
+ return this.lineStarts.length;
5517
+ }
5518
+ lineOf(pos) {
5519
+ let lo = 0;
5520
+ let hi = this.lineStarts.length - 1;
5521
+ while (lo < hi) {
5522
+ const mid = lo + hi + 1 >>> 1;
5523
+ if (this.lineStarts[mid] <= pos) lo = mid;
5524
+ else hi = mid - 1;
5525
+ }
5526
+ return lo;
5527
+ }
5528
+ isBlank(from, to) {
5529
+ return !NOT_WHITESPACE.test(this.text.slice(from, to));
5530
+ }
5531
+ lineIsBlank(li) {
5532
+ return this.isBlank(this.lineStarts[li], this.contentEnds[li]);
5533
+ }
5534
+ lineText(li) {
5535
+ return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
5536
+ }
5537
+ run() {
5538
+ let pos = 0;
5539
+ while (pos < this.n) {
5540
+ const li = this.lineOf(pos);
5541
+ const ce = this.contentEnds[li];
5542
+ if (this.isBlank(pos, ce)) {
5543
+ pos = this.gap(pos, li);
5544
+ continue;
5545
+ }
5546
+ const island = this.detectBlock(pos, li, true);
5547
+ if (island) {
5548
+ this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
5549
+ pos = island.end;
5550
+ continue;
5551
+ }
5552
+ pos = this.paragraph(pos, li);
5553
+ }
5554
+ return this.blocks;
5555
+ }
5556
+ push(block) {
5557
+ if (block.end <= block.start) return;
5558
+ if (block.kind === "prose" && this.isBlank(block.start, block.end)) {
5559
+ block = { kind: "gap", start: block.start, end: block.end, island: null, inlines: [] };
5560
+ }
5561
+ const last = this.blocks[this.blocks.length - 1];
5562
+ if (block.kind === "gap" && last && last.kind === "gap" && last.end === block.start) {
5563
+ last.end = block.end;
5564
+ return;
5565
+ }
5566
+ this.blocks.push(block);
5567
+ }
5568
+ gap(pos, li) {
5569
+ let end = this.lineEnds[li];
5570
+ let k = li + 1;
5571
+ while (k < this.lineCount && this.lineIsBlank(k)) {
5572
+ end = this.lineEnds[k];
5573
+ k++;
5574
+ }
5575
+ this.push({ kind: "gap", start: pos, end, island: null, inlines: [] });
5576
+ return end;
5577
+ }
5578
+ // ── block detection ────────────────────────────────────────────────────
5579
+ detectBlock(p, li, atParaStart) {
5580
+ const cacheKey = atParaStart ? -1 - p : p;
5581
+ if (this.blockCache.has(cacheKey)) return this.blockCache.get(cacheKey) ?? null;
5582
+ const found = this.detectBlockUncached(p, li, atParaStart);
5583
+ this.blockCache.set(cacheKey, found);
5584
+ return found;
5585
+ }
5586
+ detectBlockUncached(p, li, atParaStart) {
5587
+ const ce = this.contentEnds[li];
5588
+ const seg = this.text.slice(p, ce);
5589
+ const t = seg.trimStart();
5590
+ const indent = seg.length - t.length;
5591
+ const tp = p + indent;
5592
+ if (p === 0) {
5593
+ const fm = this.frontMatter(li, t);
5594
+ if (fm) return fm;
5595
+ }
5596
+ if (t.startsWith("```")) return this.backtickFence(p, li, t);
5597
+ if (indent <= 3 && t.startsWith("~~~")) {
5598
+ const tilde = this.tildeFence(p, li, t);
5599
+ if (tilde) return tilde;
5600
+ }
5601
+ if (t.startsWith("$$")) {
5602
+ const math = this.mathBlock(p, tp);
5603
+ if (math) return math;
5604
+ }
5605
+ if (t.startsWith("<")) {
5606
+ const attr = this.attributeXml(p, tp, t);
5607
+ if (attr) return attr;
5608
+ const region = this.xmlRegion(p, tp, t);
5609
+ if (region) return region;
5610
+ const container = this.genericXml(p, li, seg, indent);
5611
+ if (container) return container;
5612
+ if (t.startsWith("<!--")) {
5613
+ const comment = this.blockComment(p, tp, li);
5614
+ if (comment) return comment;
5615
+ }
5616
+ const html = this.htmlBlock(p, li, t, tp, atParaStart);
5617
+ if (html) return html;
5618
+ }
5619
+ if (t.startsWith("{")) {
5620
+ const json = this.bareJson(p, li, tp);
5621
+ if (json) return json;
5622
+ }
5623
+ if (TREE_GLYPHS.test(t)) {
5624
+ const tree = this.tree(p, li);
5625
+ if (tree) return tree;
5626
+ }
5627
+ return null;
5628
+ }
5629
+ island(type, start, end, complete, meta = {}) {
5630
+ return { type, start, end, complete, meta };
5631
+ }
5632
+ frontMatter(li, t) {
5633
+ if (this.lineText(li) !== "---" || t !== "---") return null;
5634
+ let sawContent = false;
5635
+ for (let k = li + 1; k < this.lineCount; k++) {
5636
+ const line = this.lineText(k);
5637
+ if (line === "---" || line === "...") {
5638
+ return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true) : null;
5639
+ }
5640
+ if (!NOT_WHITESPACE.test(line)) continue;
5641
+ if (!/^(?:[A-Za-z0-9_"'-][^:]*:(?:\s|$)|\s+\S|-\s)/.test(line)) return null;
5642
+ sawContent = true;
5643
+ }
5644
+ return null;
5645
+ }
5646
+ /** Backtick fence — the splitter's close rules, JSON-string aware for ```json. */
5647
+ backtickFence(p, li, t) {
5648
+ const openTicks = backtickRunLength(t, 0);
5649
+ const info = t.slice(openTicks).trim();
5650
+ const lang = info.split(/\s/)[0] ?? "";
5651
+ const isJson = lang === "json";
5652
+ const normalized = normalizeFenceLanguage(lang);
5653
+ const meta = { fence: "`", ticks: openTicks, lang };
5654
+ if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
5655
+ let state = { inString: false, escaped: false };
5656
+ for (let k = li + 1; k < this.lineCount; k++) {
5657
+ const line = this.lineText(k);
5658
+ const trimmedLine = line.trim();
5659
+ if (trimmedLine.startsWith("```")) {
5660
+ const at2 = line.indexOf("```");
5661
+ if (isJson) {
5662
+ const probe = jsonStringState(line, 0, at2, state);
5663
+ if (probe.inString) {
5664
+ state = jsonStringState(line, at2, line.length, probe);
5665
+ continue;
5666
+ }
5667
+ }
5668
+ const closeTicks = backtickRunLength(trimmedLine, 0);
5669
+ const isBare = trimmedLine.slice(closeTicks).trim() === "";
5670
+ if (isBare && closeTicks >= openTicks) {
5671
+ return this.fenceIsland(p, this.contentEnds[k], true, meta, li, k, isJson);
5672
+ }
5673
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5674
+ continue;
5675
+ }
5676
+ const at = line.indexOf("```");
5677
+ if (at !== -1) {
5678
+ if (isJson) {
5679
+ const probe = jsonStringState(line, 0, at, state);
5680
+ if (probe.inString) {
5681
+ state = jsonStringState(line, at, line.length, probe);
5682
+ continue;
5683
+ }
5684
+ }
5685
+ const closeTicks = backtickRunLength(line, at);
5686
+ const after = line.slice(at + closeTicks).trim();
5687
+ if (closeTicks >= openTicks && after === "") {
5688
+ return this.fenceIsland(p, this.contentEnds[k], true, meta, li, k, isJson);
5689
+ }
5690
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5691
+ continue;
5692
+ }
5693
+ if (isJson) state = jsonStringState(line, 0, line.length, state);
5694
+ }
5695
+ return this.fenceIsland(p, this.n, false, meta, li, this.lineCount, isJson);
5696
+ }
5697
+ fenceIsland(p, end, complete, meta, openLine, closeLine, isJson) {
5698
+ if (isJson && openLine + 1 < this.lineCount) {
5699
+ const bodyEnd = closeLine < this.lineCount ? this.lineStarts[closeLine] : this.n;
5700
+ const body = this.text.slice(this.lineStarts[openLine + 1], Math.max(bodyEnd, this.lineStarts[openLine + 1]));
5701
+ if (body.trimStart().startsWith("{")) Object.assign(meta, jsonMeta(body));
5702
+ }
5703
+ return this.island("fence", p, end, complete, meta);
5704
+ }
5705
+ tildeFence(p, li, t) {
5706
+ const open = /^(~{3,})(.*)$/.exec(t);
5707
+ if (!open) return null;
5708
+ const ticks = open[1].length;
5709
+ const lang = open[2].trim().split(/\s/)[0] ?? "";
5710
+ const meta = { fence: "~", ticks, lang };
5711
+ const normalized = normalizeFenceLanguage(lang);
5712
+ if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
5713
+ const close = new RegExp(`^ {0,3}~{${ticks},}[ \\t]*$`);
5714
+ for (let k = li + 1; k < this.lineCount; k++) {
5715
+ if (close.test(this.lineText(k))) {
5716
+ return this.island("fence", p, this.contentEnds[k], true, meta);
5717
+ }
5718
+ }
5719
+ return this.island("fence", p, this.n, false, meta);
5720
+ }
5721
+ mathBlock(p, tp) {
5722
+ const li = this.lineOf(tp);
5723
+ const ce = this.contentEnds[li];
5724
+ const sameLine = this.text.indexOf("$$", tp + 2);
5725
+ if (sameLine !== -1 && sameLine + 2 <= ce) {
5726
+ if (!this.isBlank(sameLine + 2, ce)) return null;
5727
+ if (sameLine === tp + 2) return null;
5728
+ return this.island("math_block", p, sameLine + 2, true, { delimiter: "$$" });
5729
+ }
5730
+ const close = this.text.indexOf("$$", tp + 2);
5731
+ if (close === -1) return this.island("math_block", p, this.n, false, { delimiter: "$$" });
5732
+ return this.island("math_block", p, close + 2, true, { delimiter: "$$" });
5733
+ }
5734
+ /** `<artifact …>`, `<decision …>`, … at the start of a line. */
5735
+ attributeXml(p, tp, t) {
5736
+ for (const name of ATTRIBUTE_XML_NAMES) {
5737
+ const prefix = `<${name}`;
5738
+ if (!t.startsWith(prefix)) continue;
5739
+ const next = t[prefix.length];
5740
+ if (next !== " " && next !== ">" && next !== "/" && next !== " ") continue;
5741
+ return this.attributeElement(name, p, tp, "xml_attr");
5742
+ }
5743
+ return null;
5744
+ }
5745
+ /** Opening tag at `tp` through its `</name>` (or to EOF when still streaming). */
5746
+ attributeElement(name, p, tp, type) {
5747
+ const li = this.lineOf(tp);
5748
+ const ce = this.contentEnds[li];
5749
+ const tag = readXmlTag(this.text, tp);
5750
+ let openEnd;
5751
+ if (tag && !tag.isClosing) {
5752
+ if (tag.isSelfClosing) {
5753
+ return this.island(type, p, tp + tag.raw.length, true, { tag: name, selfClosing: true });
5754
+ }
5755
+ openEnd = tp + tag.raw.length;
5756
+ } else {
5757
+ const gt = this.text.indexOf(">", tp);
5758
+ if (gt === -1) return this.island(type, p, this.n, false, { tag: name });
5759
+ if (gt >= ce) return null;
5760
+ openEnd = gt + 1;
5761
+ }
5762
+ const closer = `</${name}>`;
5763
+ const close = this.text.indexOf(closer, openEnd);
5764
+ if (close === -1) return this.island(type, p, this.n, false, { tag: name });
5765
+ return this.island(type, p, close + closer.length, true, { tag: name });
5766
+ }
5767
+ /** `<thinking>`, `<flashcards>`, … — exact attribute-less openers. */
5768
+ xmlRegion(p, tp, t) {
5769
+ for (const name of XML_TAG_BLOCK_NAMES) {
5770
+ const opener = `<${name}>`;
5771
+ if (!t.startsWith(opener)) continue;
5772
+ const closer = `</${name}>`;
5773
+ const close = this.text.indexOf(closer, tp + opener.length);
5774
+ if (close === -1) return this.island("xml_region", p, this.n, false, { tag: name });
5775
+ return this.island("xml_region", p, close + closer.length, true, { tag: name });
5776
+ }
5777
+ return null;
5778
+ }
5779
+ /** Line-leading unknown XML element — balanced by the renderer's own tracker. */
5780
+ genericXml(p, li, seg, indent) {
5781
+ const first = seg.slice(indent);
5782
+ const opening = readXmlTag(first, 0);
5783
+ if (opening && !opening.isClosing) {
5784
+ const root = opening.tagName;
5785
+ if (KNOWN_XML_TAG_NAMES.has(root) || ALLOWED_RAW_HTML_TAGS.has(root.toLowerCase())) {
5786
+ return null;
5787
+ }
5788
+ const tracker = new XmlContainerTracker(root);
5789
+ const firstEnd = tracker.consumeLine(seg, indent);
5790
+ if (firstEnd !== null) {
5791
+ return this.island("xml_container", p, p + firstEnd, true, { tag: root });
5792
+ }
5793
+ for (let k = li + 1; k < this.lineCount; k++) {
5794
+ const end = tracker.consumeLine(this.lineText(k));
5795
+ if (end !== null) {
5796
+ return this.island("xml_container", p, this.lineStarts[k] + end, true, {
5797
+ tag: root
5798
+ });
5799
+ }
5800
+ }
5801
+ return this.island("xml_container", p, this.n, false, { tag: root });
5802
+ }
5803
+ if (isUnclosedGenericXmlOpening(seg)) {
5804
+ return this.island("xml_container", p, this.n, false, {});
5805
+ }
5806
+ return null;
5807
+ }
5808
+ blockComment(p, tp, li) {
5809
+ const close = this.text.indexOf("-->", tp + 4);
5810
+ if (close === -1) return this.island("html_comment", p, this.n, false);
5811
+ const end = close + 3;
5812
+ const raw = this.text.slice(tp, end);
5813
+ const anchor = PINNED_ANCHOR_RE.exec(raw);
5814
+ const ce = this.contentEnds[li];
5815
+ if (anchor) {
5816
+ if (end <= ce && !this.isBlank(end, ce)) return null;
5817
+ return this.island("anchor", p, end, true, { id: anchor[1] });
5818
+ }
5819
+ return this.island("html_comment", p, end, true);
5820
+ }
5821
+ htmlBlock(p, li, t, tp, atParaStart) {
5822
+ const tag = readXmlTag(t, 0);
5823
+ if (!tag) return null;
5824
+ const name = tag.tagName.toLowerCase();
5825
+ if (!ALLOWED_RAW_HTML_TAGS.has(name)) return null;
5826
+ if (name === "pre" && !tag.isClosing) {
5827
+ const closer = /<\/pre\s*>/gi;
5828
+ closer.lastIndex = tp;
5829
+ const close = closer.exec(this.text);
5830
+ if (!close) return this.island("html_block", p, this.n, false, { tag: name });
5831
+ return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
5832
+ }
5833
+ const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
5834
+ const typeSeven = atParaStart && t.trimEnd() === tag.raw;
5835
+ if (!typeSix && !typeSeven) return null;
5836
+ let end = this.contentEnds[li];
5837
+ for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
5838
+ end = this.contentEnds[k];
5839
+ }
5840
+ return this.island("html_block", p, end, true, { tag: name });
5841
+ }
5842
+ buildBraceTables() {
5843
+ const count = this.lineCount;
5844
+ const prefix = new Int32Array(count + 1);
5845
+ for (let i = 0; i < count; i++) {
5846
+ const { opens, closes } = countStructuralBraces(this.lineText(i));
5847
+ prefix[i + 1] = prefix[i] + opens - closes;
5848
+ }
5849
+ const stop = new Int32Array(count).fill(-1);
5850
+ const stack = [];
5851
+ for (let m = 0; m <= count; m++) {
5852
+ const value = prefix[m];
5853
+ while (stack.length && prefix[stack[stack.length - 1]] >= value) {
5854
+ const i = stack.pop();
5855
+ if (i < count) stop[i] = m - 1;
5856
+ }
5857
+ stack.push(m);
5858
+ }
5859
+ this.braceNet = prefix;
5860
+ this.braceStop = stop;
5861
+ }
5862
+ /** A line-leading bare JSON object — the splitter's structural brace walk. */
5863
+ bareJson(p, li, tp) {
5864
+ let lastLine = null;
5865
+ let net = 0;
5866
+ if (p === this.lineStarts[li]) {
5867
+ if (!this.braceStop || !this.braceNet) this.buildBraceTables();
5868
+ const stop = this.braceStop[li];
5869
+ if (stop !== -1) {
5870
+ lastLine = stop;
5871
+ net = this.braceNet[stop + 1] - this.braceNet[li];
5872
+ }
5873
+ } else {
5874
+ let running = 0;
5875
+ for (let k = li; k < this.lineCount; k++) {
5876
+ const line = k === li ? this.text.slice(tp, this.contentEnds[li]) : this.lineText(k);
5877
+ const { opens, closes } = countStructuralBraces(line);
5878
+ running += opens - closes;
5879
+ if (running <= 0) {
5880
+ lastLine = k;
5881
+ net = running;
5882
+ break;
5883
+ }
5884
+ }
5885
+ }
5886
+ if (lastLine === null) {
5887
+ const partial = this.text.slice(tp);
5888
+ if (isRecognizedJsonHead(partial)) {
5889
+ return this.island("json", p, this.n, false, jsonMeta(partial));
5890
+ }
5891
+ return null;
5892
+ }
5893
+ if (net !== 0) return null;
5894
+ const end = this.contentEnds[lastLine];
5895
+ const content = this.text.slice(tp, end).trim();
5896
+ try {
5897
+ const parsed = JSON.parse(content);
5898
+ if (parsed === null || typeof parsed !== "object") return null;
5899
+ } catch {
5900
+ return null;
5901
+ }
5902
+ return this.island("json", p, end, true, jsonMeta(content));
5903
+ }
5904
+ tree(p, li) {
5905
+ let treeLines = 0;
5906
+ let lastTree = li;
5907
+ let k = li;
5908
+ while (k < this.lineCount) {
5909
+ if (this.lineIsBlank(k)) {
5910
+ k++;
5911
+ continue;
5912
+ }
5913
+ if (!TREE_GLYPHS.test(this.lineText(k))) break;
5914
+ treeLines++;
5915
+ lastTree = k;
5916
+ k++;
5917
+ }
5918
+ if (treeLines < 3) return null;
5919
+ return this.island("tree", p, this.contentEnds[lastTree], true);
5920
+ }
5921
+ // ── prose ──────────────────────────────────────────────────────────────
5922
+ paragraph(pos, li) {
5923
+ let end = this.contentEnds[li];
5924
+ for (let k = li + 1; k < this.lineCount; k++) {
5925
+ if (this.lineIsBlank(k)) break;
5926
+ if (this.detectBlock(this.lineStarts[k], k, false)) break;
5927
+ end = this.contentEnds[k];
5928
+ }
5929
+ const scan = this.scanInline(pos, end);
5930
+ if (!scan.breakIsland) {
5931
+ this.push({ kind: "prose", start: pos, end, island: null, inlines: scan.inlines });
5932
+ return end;
5933
+ }
5934
+ const br = scan.breakIsland;
5935
+ if (scan.orphan) {
5936
+ let start = pos;
5937
+ while (this.blocks.length) {
5938
+ const last = this.blocks[this.blocks.length - 1];
5939
+ if (last.kind === "island") break;
5940
+ this.blocks.pop();
5941
+ start = last.start;
5942
+ }
5943
+ const island = { ...br, start };
5944
+ this.push({ kind: "island", start, end: island.end, island, inlines: [] });
5945
+ return island.end;
5946
+ }
5947
+ this.push({
5948
+ kind: "prose",
5949
+ start: pos,
5950
+ end: br.start,
5951
+ island: null,
5952
+ inlines: scan.inlines.filter((inline) => inline.end <= br.start)
5953
+ });
5954
+ this.push({ kind: "island", start: br.start, end: br.end, island: br, inlines: [] });
5955
+ return br.end;
5956
+ }
5957
+ scanInline(ps, pe) {
5958
+ const text = this.text;
5959
+ const inlines = [];
5960
+ const hasKind = text.slice(ps, pe).includes("__kind");
5961
+ const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
5962
+ let i = ps;
5963
+ while (i < pe) {
5964
+ const ch = text[i];
5965
+ if (ch === "\\") {
5966
+ const next = text[i + 1];
5967
+ if (next === "(" || next === "[") {
5968
+ const closer = next === "(" ? "\\)" : "\\]";
5969
+ const close = text.indexOf(closer, i + 2);
5970
+ if (close !== -1 && close + 2 <= pe) {
5971
+ inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: next === "(" ? "\\(" : "\\[" }));
5972
+ i = close + 2;
5973
+ continue;
5974
+ }
5975
+ }
5976
+ i += 2;
5977
+ continue;
5978
+ }
5979
+ if (ch === "`") {
5980
+ const n = backtickRunLength(text, i);
5981
+ const run = "`".repeat(n);
5982
+ let k = i + n;
5983
+ let close = -1;
5984
+ while (k < pe) {
5985
+ const idx = text.indexOf(run, k);
5986
+ if (idx === -1 || idx >= pe) break;
5987
+ if (text[idx + n] === "`") {
5988
+ let m = idx;
5989
+ while (text[m] === "`") m++;
5990
+ k = m;
5991
+ continue;
5992
+ }
5993
+ close = idx;
5994
+ break;
5995
+ }
5996
+ i = close === -1 ? i + n : close + n;
5997
+ continue;
5998
+ }
5999
+ if (ch === "$") {
6000
+ if (text[i + 1] === "$") {
6001
+ const close = text.indexOf("$$", i + 2);
6002
+ if (close !== -1 && close + 2 <= pe && close > i + 2) {
6003
+ inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: "$$" }));
6004
+ i = close + 2;
6005
+ } else {
6006
+ i += 2;
6007
+ }
6008
+ continue;
6009
+ }
6010
+ const end = singleDollarMathEnd(text, i, pe);
6011
+ if (end > 0) {
6012
+ inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
6013
+ i = end;
6014
+ continue;
6015
+ }
6016
+ i++;
6017
+ continue;
6018
+ }
6019
+ if (ch === "{") {
6020
+ if (text[i + 1] === "{") {
6021
+ const close = text.indexOf("}}", i + 2);
6022
+ if (close !== -1 && close + 2 <= pe && close - i <= 200 && !text.slice(i, close).includes("\n")) {
6023
+ const raw = text.slice(i, close + 2);
6024
+ const strict = STRICT_VARIABLE_RE.exec(raw);
6025
+ inlines.push(
6026
+ this.island("variable", i, close + 2, true, strict ? { name: strict[1] } : { template: true })
6027
+ );
6028
+ i = close + 2;
6029
+ continue;
6030
+ }
6031
+ i += 2;
6032
+ continue;
6033
+ }
6034
+ if (hasKind) {
6035
+ const end = matchingJsonObjectEnd(text, i, pe);
6036
+ if (end !== null) {
6037
+ const kind = declaredKind(text.slice(i, end));
6038
+ if (kind) {
6039
+ inlines.push(this.island("kind_json", i, end, true, jsonMeta(text.slice(i, end))));
6040
+ i = end;
6041
+ continue;
6042
+ }
6043
+ }
6044
+ }
6045
+ i++;
6046
+ continue;
6047
+ }
6048
+ if (ch === "[") {
6049
+ const media = MEDIA_REF_PREFIXES.find((prefix) => text.startsWith(prefix, i));
6050
+ if (media) {
6051
+ const close = text.indexOf("]", i + media.length);
6052
+ if (close !== -1 && close < pe && !text.slice(i, close).includes("\n")) {
6053
+ inlines.push(this.island("media_ref", i, close + 1, true, { media: media.slice(1, 6).toLowerCase() }));
6054
+ i = close + 1;
6055
+ continue;
6056
+ }
6057
+ }
6058
+ i++;
6059
+ continue;
6060
+ }
6061
+ if (ch === "<") {
6062
+ if (text.startsWith("<!--", i)) {
6063
+ const close = text.indexOf("-->", i + 4);
6064
+ if (close === -1) return stop(this.island("html_comment", i, this.n, false));
6065
+ const end = close + 3;
6066
+ const anchor = PINNED_ANCHOR_RE.exec(text.slice(i, end));
6067
+ const type = anchor ? "anchor" : "html_comment";
6068
+ const meta = anchor ? { id: anchor[1] } : {};
6069
+ if (end > pe) return stop(this.island(type, i, end, true, meta));
6070
+ inlines.push(this.island(type, i, end, true, meta));
6071
+ i = end;
6072
+ continue;
6073
+ }
6074
+ const cite = CITE_RE.exec(text.slice(i, i + 64));
6075
+ if (cite) {
6076
+ inlines.push(this.island("cite", i, i + cite[0].length, true, { n: Number(cite[1]) }));
6077
+ i += cite[0].length;
6078
+ continue;
6079
+ }
6080
+ const tag = readXmlTag(text, i);
6081
+ if (tag && i + tag.raw.length <= pe) {
6082
+ const name = tag.tagName;
6083
+ const tagEnd = i + tag.raw.length;
6084
+ const isAttr = ATTRIBUTE_XML_NAMES.includes(name);
6085
+ const isThinking = THINKING_FAMILY.includes(name) && tag.raw === `<${name}>`;
6086
+ if (!tag.isClosing && (isAttr || isThinking)) {
6087
+ if (tag.isSelfClosing) {
6088
+ inlines.push(this.island("xml_inline", i, tagEnd, true, { tag: name, selfClosing: true }));
6089
+ i = tagEnd;
6090
+ continue;
6091
+ }
6092
+ const closer = `</${name}>`;
6093
+ const close = text.indexOf(closer, tagEnd);
6094
+ const blockType = isAttr ? "xml_attr" : "xml_region";
6095
+ if (close === -1) return stop(this.island(blockType, i, this.n, false, { tag: name }));
6096
+ const end = close + closer.length;
6097
+ if (end > pe) return stop(this.island(blockType, i, end, true, { tag: name }));
6098
+ inlines.push(this.island("xml_inline", i, end, true, { tag: name }));
6099
+ i = end;
6100
+ continue;
6101
+ }
6102
+ if (tag.isClosing && THINKING_FAMILY.includes(name)) {
6103
+ return stop(this.island("xml_region", i, tagEnd, true, { tag: name, continuation: true }), true);
6104
+ }
6105
+ const lower = name.toLowerCase();
6106
+ inlines.push(
6107
+ this.island(ALLOWED_RAW_HTML_TAGS.has(lower) ? "html_tag" : "xml_tag", i, tagEnd, true, {
6108
+ tag: name
6109
+ })
6110
+ );
6111
+ i = tagEnd;
6112
+ continue;
6113
+ }
6114
+ const pending = ATTRIBUTE_XML_NAMES.find(
6115
+ (name) => text.startsWith(`<${name}`, i) && /\s/.test(text[i + name.length + 1] ?? "")
6116
+ );
6117
+ if (pending && text.indexOf(">", i) === -1) {
6118
+ return stop(this.island("xml_attr", i, this.n, false, { tag: pending }));
6119
+ }
6120
+ i++;
6121
+ continue;
6122
+ }
6123
+ i++;
6124
+ }
6125
+ return { inlines, breakIsland: null, orphan: false };
6126
+ }
6127
+ };
6128
+ function tokenizeSource(text) {
6129
+ const raw = new Tokenizer(text).run();
6130
+ const cp = buildCodePointIndex(text);
6131
+ const inline = (island) => ({
6132
+ islandType: island.type,
6133
+ inline: true,
6134
+ complete: island.complete,
6135
+ meta: island.meta,
6136
+ start: island.start,
6137
+ end: island.end,
6138
+ startCp: cp.toCodePoint(island.start),
6139
+ endCp: cp.toCodePoint(island.end),
6140
+ raw: text.slice(island.start, island.end)
6141
+ });
6142
+ return raw.map(
6143
+ (block) => ({
6144
+ kind: block.kind,
6145
+ islandType: block.island?.type ?? null,
6146
+ complete: block.island ? block.island.complete : true,
6147
+ meta: block.island?.meta ?? {},
6148
+ inlines: block.inlines.map(inline),
6149
+ start: block.start,
6150
+ end: block.end,
6151
+ startCp: cp.toCodePoint(block.start),
6152
+ endCp: cp.toCodePoint(block.end),
6153
+ raw: text.slice(block.start, block.end)
6154
+ })
6155
+ );
6156
+ }
6157
+ function joinSource(blocks) {
6158
+ let out = "";
6159
+ for (const block of blocks) out += block.raw;
6160
+ return out;
6161
+ }
6162
+ function listIslands(blocks) {
6163
+ const out = [];
6164
+ for (const block of blocks) {
6165
+ if (block.kind === "island" && block.islandType) {
6166
+ out.push({
6167
+ islandType: block.islandType,
6168
+ inline: false,
6169
+ complete: block.complete,
6170
+ meta: block.meta,
6171
+ start: block.start,
6172
+ end: block.end,
6173
+ startCp: block.startCp,
6174
+ endCp: block.endCp,
6175
+ raw: block.raw
6176
+ });
6177
+ } else {
6178
+ out.push(...block.inlines);
6179
+ }
6180
+ }
6181
+ return out;
6182
+ }
6183
+ function blockAt(blocks, offset) {
6184
+ let lo = 0;
6185
+ let hi = blocks.length - 1;
6186
+ while (lo <= hi) {
6187
+ const mid = lo + hi >>> 1;
6188
+ const block = blocks[mid];
6189
+ if (offset < block.start) hi = mid - 1;
6190
+ else if (offset >= block.end) lo = mid + 1;
6191
+ else return block;
6192
+ }
6193
+ return null;
6194
+ }
6195
+
6196
+ // source/splice.ts
6197
+ var SourceSpliceError = class extends Error {
6198
+ constructor(code, message) {
6199
+ super(message);
6200
+ this.code = code;
6201
+ this.name = "SourceSpliceError";
6202
+ }
6203
+ code;
6204
+ };
6205
+ function blockEdit(block, text) {
6206
+ return { start: block.start, end: block.end, text };
6207
+ }
6208
+ function blockRangeEdit(first, last, text) {
6209
+ return { start: first.start, end: last.end, text };
6210
+ }
6211
+ function commonPrefix(a, b) {
6212
+ const max = Math.min(a.length, b.length);
6213
+ let i = 0;
6214
+ while (i < max && a.charCodeAt(i) === b.charCodeAt(i)) i++;
6215
+ if (i > 0 && (splitsSurrogatePair(a, i) || splitsSurrogatePair(b, i))) i--;
6216
+ return i;
6217
+ }
6218
+ function commonSuffix(a, b, prefix) {
6219
+ const max = Math.min(a.length, b.length) - prefix;
6220
+ let i = 0;
6221
+ while (i < max && a.charCodeAt(a.length - 1 - i) === b.charCodeAt(b.length - 1 - i)) i++;
6222
+ if (i > 0 && (splitsSurrogatePair(a, a.length - i) || splitsSurrogatePair(b, b.length - i))) i--;
6223
+ return i;
6224
+ }
6225
+ function spliceSave(original, edits, options = {}) {
6226
+ const blocks = options.blocks ?? tokenizeSource(original);
6227
+ if (options.blocks && joinSource(blocks) !== original) {
6228
+ throw new SourceSpliceError("stale_blocks", "the blocks passed in were not cut from this original text");
6229
+ }
6230
+ const boundaries = /* @__PURE__ */ new Set([0, original.length]);
6231
+ for (const block of blocks) {
6232
+ boundaries.add(block.start);
6233
+ boundaries.add(block.end);
6234
+ }
6235
+ const sorted = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
6236
+ let previousEnd = -1;
6237
+ for (const edit of sorted) {
6238
+ if (edit.start < 0 || edit.end > original.length || edit.start > edit.end) {
6239
+ throw new SourceSpliceError("out_of_range", `edit [${edit.start}, ${edit.end}) is outside the text`);
6240
+ }
6241
+ if (!boundaries.has(edit.start) || !boundaries.has(edit.end)) {
6242
+ throw new SourceSpliceError(
6243
+ "misaligned",
6244
+ `edit [${edit.start}, ${edit.end}) does not start and end on block boundaries`
6245
+ );
6246
+ }
6247
+ if (edit.start < previousEnd) {
6248
+ throw new SourceSpliceError("overlap", `edit [${edit.start}, ${edit.end}) overlaps the previous edit`);
6249
+ }
6250
+ previousEnd = edit.end;
6251
+ }
6252
+ const effective = [];
6253
+ for (const edit of sorted) {
6254
+ const old = original.slice(edit.start, edit.end);
6255
+ if (old === edit.text) continue;
6256
+ const prefix = commonPrefix(old, edit.text);
6257
+ const suffix = commonSuffix(old, edit.text, prefix);
6258
+ effective.push({
6259
+ blockStart: edit.start,
6260
+ blockEnd: edit.end,
6261
+ oldStart: edit.start + prefix,
6262
+ oldEnd: edit.end - suffix,
6263
+ replacement: edit.text.slice(prefix, edit.text.length - suffix)
6264
+ });
6265
+ }
6266
+ if (effective.length === 0) {
6267
+ return {
6268
+ text: original,
6269
+ changed: false,
6270
+ changes: [],
6271
+ integrity: { ok: true, bytesOutsideEditsIdentical: true, disturbed: [] },
6272
+ blocks
6273
+ };
6274
+ }
6275
+ let text = "";
6276
+ let cursor = 0;
6277
+ let delta = 0;
6278
+ const pending = [];
6279
+ for (const edit of effective) {
6280
+ text += original.slice(cursor, edit.oldStart);
6281
+ const newStart = edit.oldStart + delta;
6282
+ text += edit.replacement;
6283
+ const newEnd = newStart + edit.replacement.length;
6284
+ pending.push({
6285
+ blockStart: edit.blockStart,
6286
+ blockEnd: edit.blockEnd,
6287
+ oldStart: edit.oldStart,
6288
+ oldEnd: edit.oldEnd,
6289
+ newStart,
6290
+ newEnd
6291
+ });
6292
+ delta += edit.replacement.length - (edit.oldEnd - edit.oldStart);
6293
+ cursor = edit.oldEnd;
6294
+ }
6295
+ text += original.slice(cursor);
6296
+ const oldCp = buildCodePointIndex(original);
6297
+ const newCp = buildCodePointIndex(text);
6298
+ const changes = pending.map((change) => ({
6299
+ ...change,
6300
+ oldStartCp: oldCp.toCodePoint(change.oldStart),
6301
+ oldEndCp: oldCp.toCodePoint(change.oldEnd),
6302
+ newStartCp: newCp.toCodePoint(change.newStart),
6303
+ newEndCp: newCp.toCodePoint(change.newEnd)
6304
+ }));
6305
+ let bytesOutsideEditsIdentical = true;
6306
+ let oldCursor = 0;
6307
+ let newCursor = 0;
6308
+ for (const change of changes) {
6309
+ if (original.slice(oldCursor, change.oldStart) !== text.slice(newCursor, change.newStart)) {
6310
+ bytesOutsideEditsIdentical = false;
6311
+ }
6312
+ oldCursor = change.oldEnd;
6313
+ newCursor = change.newEnd;
6314
+ }
6315
+ if (original.slice(oldCursor) !== text.slice(newCursor)) bytesOutsideEditsIdentical = false;
6316
+ const newBlocks = tokenizeSource(text);
6317
+ const newIslandsByStart = /* @__PURE__ */ new Map();
6318
+ for (const island of listIslands(newBlocks)) {
6319
+ const list = newIslandsByStart.get(island.start);
6320
+ if (list) list.push(island.raw);
6321
+ else newIslandsByStart.set(island.start, [island.raw]);
6322
+ }
6323
+ const disturbed = [];
6324
+ for (const island of listIslands(blocks)) {
6325
+ const touched = effective.some(
6326
+ (edit) => island.start < edit.blockEnd && island.end > edit.blockStart
6327
+ );
6328
+ if (touched) continue;
6329
+ const mappedStart = mapPosition(changes, island.start, { assoc: 1 }).pos;
6330
+ const candidates = newIslandsByStart.get(mappedStart);
6331
+ if (!candidates || !candidates.includes(island.raw)) {
6332
+ disturbed.push({
6333
+ islandType: island.islandType,
6334
+ inline: island.inline,
6335
+ start: island.start,
6336
+ end: island.end,
6337
+ mappedStart
6338
+ });
6339
+ }
6340
+ }
6341
+ const integrity = {
6342
+ ok: bytesOutsideEditsIdentical && disturbed.length === 0,
6343
+ bytesOutsideEditsIdentical,
6344
+ disturbed
6345
+ };
6346
+ if (options.requireIntegrity && !integrity.ok) {
6347
+ throw new SourceSpliceError(
6348
+ "integrity",
6349
+ `the edit disturbed ${disturbed.length} protected island(s) outside the edited blocks`
6350
+ );
6351
+ }
6352
+ return { text, changed: true, changes, integrity, blocks: newBlocks };
6353
+ }
6354
+ function mapPosition(changes, pos, options = {}) {
6355
+ const assoc = options.assoc ?? 1;
6356
+ const cp = options.unit === "codepoint";
6357
+ let delta = 0;
6358
+ for (const change of changes) {
6359
+ const oldStart = cp ? change.oldStartCp : change.oldStart;
6360
+ const oldEnd = cp ? change.oldEndCp : change.oldEnd;
6361
+ const newStart = cp ? change.newStartCp : change.newStart;
6362
+ const newEnd = cp ? change.newEndCp : change.newEnd;
6363
+ if (pos < oldStart) break;
6364
+ if (pos > oldEnd) {
6365
+ delta = newEnd - oldEnd;
6366
+ continue;
6367
+ }
6368
+ if (oldStart === oldEnd) {
6369
+ return { pos: assoc < 0 ? newStart : newEnd, deleted: false };
6370
+ }
6371
+ if (pos === oldStart) return { pos: newStart, deleted: false };
6372
+ if (pos === oldEnd) return { pos: newEnd, deleted: false };
6373
+ return { pos: assoc < 0 ? newStart : newEnd, deleted: true };
6374
+ }
6375
+ return { pos: pos + delta, deleted: false };
6376
+ }
6377
+ function mapRange(changes, start, end, unit = "utf16") {
6378
+ const cp = unit === "codepoint";
6379
+ const mappedStart = mapPosition(changes, start, { assoc: 1, unit });
6380
+ const mappedEnd = mapPosition(changes, end, { assoc: -1, unit });
6381
+ const touched = changes.some((change) => {
6382
+ const oldStart = cp ? change.oldStartCp : change.oldStart;
6383
+ const oldEnd = cp ? change.oldEndCp : change.oldEnd;
6384
+ return oldStart < end && oldEnd > start;
6385
+ });
6386
+ const newStart = mappedStart.pos;
6387
+ const newEnd = Math.max(newStart, mappedEnd.pos);
6388
+ return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
6389
+ }
6390
+
4976
6391
  exports.ACTION_BY_CLASS = ACTION_BY_CLASS;
4977
6392
  exports.CAPABILITY_BY_CLASS = CAPABILITY_BY_CLASS;
4978
6393
  exports.CLASSES = CLASSES;
@@ -4996,9 +6411,15 @@ exports.ROOT_STORAGE_NAME = ROOT_STORAGE_NAME;
4996
6411
  exports.RUN_RESULT_KIND = RUN_RESULT_KIND;
4997
6412
  exports.SIDE_EFFECT_CLASSES = SIDE_EFFECT_CLASSES;
4998
6413
  exports.SLUG_PREFIX = SLUG_PREFIX;
6414
+ exports.SourceSpliceError = SourceSpliceError;
6415
+ exports.XmlContainerTracker = XmlContainerTracker;
4999
6416
  exports.advancePartialKind = advancePartialKind;
5000
6417
  exports.asKindInstance = asKindInstance;
6418
+ exports.blockAt = blockAt;
6419
+ exports.blockEdit = blockEdit;
6420
+ exports.blockRangeEdit = blockRangeEdit;
5001
6421
  exports.buildAgentSchemaWithRenderBlockSupport = buildAgentSchemaWithRenderBlockSupport;
6422
+ exports.buildCodePointIndex = buildCodePointIndex;
5002
6423
  exports.buildCompliantKindSnapshot = buildCompliantKindSnapshot;
5003
6424
  exports.buildDirectiveSlug = buildDirectiveSlug;
5004
6425
  exports.buildKindDirective = buildKindDirective;
@@ -5043,17 +6464,22 @@ exports.isLegacyShell = isLegacyShell;
5043
6464
  exports.isProvisionalKind = isProvisionalKind;
5044
6465
  exports.isReservedDirectiveSlug = isReservedDirectiveSlug;
5045
6466
  exports.isScalarArrayType = isScalarArrayType;
6467
+ exports.isSingleDollarMath = isSingleDollarMath;
5046
6468
  exports.isTerminalKindEvent = isTerminalKindEvent;
5047
6469
  exports.itemFacts = itemFacts;
5048
6470
  exports.itemSubtitle = itemSubtitle;
5049
6471
  exports.itemTitle = itemTitle;
6472
+ exports.joinSource = joinSource;
5050
6473
  exports.kindSchemaFromJsonSchema = kindSchemaFromJsonSchema;
5051
6474
  exports.kindSchemaToJsonSchema = kindSchemaToJsonSchema;
5052
6475
  exports.kindSchemaToStorage = kindSchemaToStorage;
5053
6476
  exports.kindVerdictOf = kindVerdictOf;
5054
6477
  exports.legacyShellUses = legacyShellUses;
6478
+ exports.listIslands = listIslands;
5055
6479
  exports.looksLikeDirectiveHead = looksLikeDirectiveHead;
5056
6480
  exports.makePartialKindStalenessGate = makePartialKindStalenessGate;
6481
+ exports.mapPosition = mapPosition;
6482
+ exports.mapRange = mapRange;
5057
6483
  exports.mergeResidueIntoValue = mergeResidueIntoValue;
5058
6484
  exports.normalizeAiSchemaInput = normalizeAiSchemaInput;
5059
6485
  exports.normalizeJsonRegion = normalizeJsonRegion;
@@ -5068,6 +6494,7 @@ exports.readObjectKind = readObjectKind;
5068
6494
  exports.readOutputRef = readOutputRef;
5069
6495
  exports.readPartialKindEvent = readPartialKindEvent;
5070
6496
  exports.readRunResultValue = readRunResultValue;
6497
+ exports.readXmlTag = readXmlTag;
5071
6498
  exports.reconstructRegionValue = reconstructRegionValue;
5072
6499
  exports.rehydrateNodeOutcome = rehydrateNodeOutcome;
5073
6500
  exports.rehydrateRunResult = rehydrateRunResult;
@@ -5082,9 +6509,15 @@ exports.scalarArrayItemType = scalarArrayItemType;
5082
6509
  exports.schemaLayoutMode = schemaLayoutMode;
5083
6510
  exports.schemaStructureDepth = schemaStructureDepth;
5084
6511
  exports.setJsonRootKeyLookup = setJsonRootKeyLookup;
6512
+ exports.singleDollarMathEnd = singleDollarMathEnd;
6513
+ exports.spliceSave = spliceSave;
6514
+ exports.splitsSurrogatePair = splitsSurrogatePair;
5085
6515
  exports.storageToKindSchema = storageToKindSchema;
5086
6516
  exports.stripKindDeep = stripKindDeep;
5087
6517
  exports.titleCaseToken = titleCaseToken;
6518
+ exports.toCodePointOffset = toCodePointOffset;
6519
+ exports.toUtf16Offset = toUtf16Offset;
6520
+ exports.tokenizeSource = tokenizeSource;
5088
6521
  exports.tryDecodeDirective = tryDecodeDirective;
5089
6522
  exports.tryDecodeDirectiveContent = tryDecodeDirectiveContent;
5090
6523
  exports.validateBlockSchemaSavePlan = validateBlockSchemaSavePlan;