@ai-matrx/chat 0.4.9 → 0.4.12

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 (123) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/agents/components/context-items/bodies/ContextInputBody.js +1 -1
  3. package/dist/agents/components/context-items/bodies/GenericBody.js +1 -1
  4. package/dist/agents/components/conversation-actions/conversation-verbs.js +1 -1
  5. package/dist/agents/components/inputs/smart-input/RunSkillPicker.js +1 -1
  6. package/dist/agents/components/live-run/LiveRunDisplay.js +1 -1
  7. package/dist/agents/components/live-run/LiveRunProgress.js +1 -1
  8. package/dist/agents/components/live-run/RunSetDisplay.js +1 -1
  9. package/dist/agents/components/messages-display/assistant/AgentAssistantMessage.js +2 -2
  10. package/dist/agents/components/messages-display/assistant/InPlaceAnswerEditor.js +1 -1
  11. package/dist/agents/components/messages-display/conversation-tools/find-in-conversation.js +1 -1
  12. package/dist/agents/components/messages-display/message-options/buildTaskSeedFromMessage.js +1 -1
  13. package/dist/agents/components/messages-display/user/AgentUserMessage.js +1 -1
  14. package/dist/agents/components/messages-display/user/FirstTurnVariables.js +1 -1
  15. package/dist/agents/components/run/AgentStatusIndicator.js +1 -1
  16. package/dist/agents/components/run/RunJobWorkingLine.js +1 -1
  17. package/dist/agents/components/shared/AgentNewRunButton.js +1 -1
  18. package/dist/agents/components/shared/AgentPlanningIndicator.js +1 -1
  19. package/dist/agents/conversation-export/conversation-transfer.js +1 -1
  20. package/dist/agents/conversation-export/document-markdown.js +1 -1
  21. package/dist/agents/hooks/useConversationRoutePromotion.js +1 -1
  22. package/dist/agents/hooks/useModelControls.js +1 -1
  23. package/dist/agents/redux/agent-definition/converters.js +1 -1
  24. package/dist/agents/redux/agent-definition/slice.js +1 -1
  25. package/dist/agents/redux/conversation-list/conversation-list.thunks.js +1 -1
  26. package/dist/agents/redux/execution-system/active-requests/active-requests.selectors.js +1 -1
  27. package/dist/agents/redux/execution-system/instance-context/sync-canvas-item-context.thunk.js +1 -1
  28. package/dist/agents/redux/execution-system/thunks/process-stream.js +1 -1
  29. package/dist/agents/redux/execution-system/thunks/resolve-base-url.js +17 -0
  30. package/dist/agents/redux/execution-system/thunks/run-ai-stream.d.ts +7 -0
  31. package/dist/agents/redux/execution-system/thunks/run-ai-stream.js +13 -0
  32. package/dist/agents/redux/execution-system/thunks/run-headless-agent-json.js +14 -2
  33. package/dist/agents/redux/execution-system/utils/assemble-cx-content-blocks.js +1 -1
  34. package/dist/agents/redux/execution-system/utils/normalize-content-blocks.js +1 -1
  35. package/dist/agents/redux/execution-system/utils/output-contract-guard.js +1 -1
  36. package/dist/agents/redux/execution-system/utils/stream-block-accumulator.js +8 -8
  37. package/dist/agents/routing/confidential-routing.d.ts +52 -0
  38. package/dist/agents/routing/confidential-routing.js +38 -0
  39. package/dist/agents/utils/canvasItemContext.js +1 -1
  40. package/dist/canvas/workspace/ChatPanelTitleMenu.js +1 -1
  41. package/dist/canvas/workspace/useCanvasWorkspaceConversation.js +1 -1
  42. package/dist/cx-chat/components/SsrSidebarChats.js +1 -1
  43. package/dist/cx-chat/components/core/ChatConversationClient.js +1 -1
  44. package/dist/cx-chat/components/messages/AssistantMessage.js +1 -1
  45. package/dist/cx-chat/hooks/useInstanceBootstrap.js +1 -1
  46. package/dist/cx-conversation/AssistantMessage.js +1 -1
  47. package/dist/host/configure.js +4 -1
  48. package/dist/host/contract.d.ts +14 -1
  49. package/dist/host/index.d.ts +1 -0
  50. package/dist/host/index.js +1 -0
  51. package/dist/mandates/llm-params.d.ts +1 -1
  52. package/dist/mandates/output-contract.js +1 -1
  53. package/dist/mandates/service.d.ts +1 -1
  54. package/dist/mandates/service.js +1 -1
  55. package/dist/mandates/test-run-core.js +1 -1
  56. package/dist/public-chat/components/PublicMessageOptionsMenu.js +1 -1
  57. package/dist/surfaces/services/surface-config.service.js +1 -1
  58. package/dist/tool-call-visualization/components/ToolCallBatch.js +1 -1
  59. package/dist/tool-call-visualization/components/ToolCallVisualization.js +1 -1
  60. package/dist/tool-call-visualization/renderers/agent-call/AgentCallInline.js +1 -1
  61. package/dist/tool-call-visualization/renderers/agent-call/CollabCallCard.js +1 -1
  62. package/dist/tool-call-visualization/renderers/agent-call/collab-subtitle.js +3 -3
  63. package/dist/tool-call-visualization/renderers/skill/SkillInline.js +1 -1
  64. package/dist/tool-call-visualization/result-fields/KeyValueGrid.js +1 -1
  65. package/dist/tool-call-visualization/result-fields/ResultValue.js +1 -1
  66. package/dist/tool-call-visualization/result-fields/shape.js +1 -1
  67. package/dist/tool-call-visualization/utils/cxToolCallToLifecycleEntry.js +2 -2
  68. package/dist/tool-call-visualization/utils/human-copy.js +3 -3
  69. package/dist/ui/mandates-storage/provision-shapes.d.ts +1 -1
  70. package/dist/ui/mandates-storage/provision-shapes.js +1 -1
  71. package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +1 -1
  72. package/dist/ui/treatment-shape.d.ts +1 -1
  73. package/dist/ui/treatment-shape.js +1 -1
  74. package/dist/voice-agent/relay/useVoiceRelaySession.js +1 -1
  75. package/package.json +26 -9
  76. package/dist/agents/hooks/useWarmAgent.d.ts +0 -8
  77. package/dist/agents/hooks/useWarmAgent.js +0 -25
  78. package/dist/agents/utils/artifactId.d.ts +0 -34
  79. package/dist/agents/utils/artifactId.js +0 -15
  80. package/dist/ui/ShimmerText.d.ts +0 -5
  81. package/dist/ui/ShimmerText.js +0 -21
  82. package/dist/ui/addressWithoutNavigating.d.ts +0 -68
  83. package/dist/ui/addressWithoutNavigating.js +0 -60
  84. package/dist/utils/content-ir/decision-answers-ids.d.ts +0 -3
  85. package/dist/utils/content-ir/decision-answers-ids.js +0 -6
  86. package/dist/utils/content-ir/envelope-parity.d.ts +0 -12
  87. package/dist/utils/content-ir/envelope-parity.js +0 -32
  88. package/dist/utils/content-ir/instance-title.d.ts +0 -26
  89. package/dist/utils/content-ir/instance-title.js +0 -39
  90. package/dist/utils/content-ir/kinds/kind-markdown-utils.d.ts +0 -84
  91. package/dist/utils/content-ir/kinds/kind-markdown-utils.js +0 -233
  92. package/dist/utils/content-ir/kinds/kind-value-markdown.d.ts +0 -5
  93. package/dist/utils/content-ir/kinds/kind-value-markdown.js +0 -17
  94. package/dist/utils/content-ir/legacy-quiz-envelope.d.ts +0 -3
  95. package/dist/utils/content-ir/legacy-quiz-envelope.js +0 -45
  96. package/dist/utils/content-ir/surfaces/embedded-kind-json.d.ts +0 -140
  97. package/dist/utils/content-ir/surfaces/embedded-kind-json.js +0 -527
  98. package/dist/utils/content-ir/surfaces/json-kind-signal.d.ts +0 -307
  99. package/dist/utils/content-ir/surfaces/json-kind-signal.js +0 -945
  100. package/dist/utils/content-ir/surfaces/kind-image-alt.d.ts +0 -27
  101. package/dist/utils/content-ir/surfaces/kind-image-alt.js +0 -117
  102. package/dist/utils/content-ir/surfaces/kind-one-line.d.ts +0 -67
  103. package/dist/utils/content-ir/surfaces/kind-one-line.js +0 -209
  104. package/dist/utils/content-ir/surfaces/kind-text-label.d.ts +0 -20
  105. package/dist/utils/content-ir/surfaces/kind-text-label.js +0 -50
  106. package/dist/utils/content-ir/surfaces/kind-text-to-markdown.d.ts +0 -47
  107. package/dist/utils/content-ir/surfaces/kind-text-to-markdown.js +0 -399
  108. package/dist/utils/content-ir/surfaces/markdown-escaped-kind.d.ts +0 -54
  109. package/dist/utils/content-ir/surfaces/markdown-escaped-kind.js +0 -128
  110. package/dist/utils/content-ir/surfaces/quoted-kind-lift.d.ts +0 -61
  111. package/dist/utils/content-ir/surfaces/quoted-kind-lift.js +0 -215
  112. package/dist/utils/inline-decision/decision-options.d.ts +0 -21
  113. package/dist/utils/inline-decision/decision-options.js +0 -32
  114. package/dist/utils/json.d.ts +0 -63
  115. package/dist/utils/json.js +0 -22
  116. package/dist/utils/markdown/plain-title.d.ts +0 -25
  117. package/dist/utils/markdown/plain-title.js +0 -51
  118. package/dist/utils/rendered-find.d.ts +0 -9
  119. package/dist/utils/rendered-find.js +0 -68
  120. package/dist/utils/rich-editor/core/caret-context.d.ts +0 -24
  121. package/dist/utils/rich-editor/core/caret-context.js +0 -73
  122. package/dist/utils/rich-editor/in-place/caret-handoff.d.ts +0 -3
  123. package/dist/utils/rich-editor/in-place/caret-handoff.js +0 -15
@@ -1,140 +0,0 @@
1
- /**
2
- * Recover complete self-described kind objects from ANY containing text.
3
- *
4
- * Markdown, code fences, and XML are arrival containers, not type authority.
5
- * Once a complete JSON object directly declares a non-empty `__kind`, that
6
- * object is its own Content IR region even when an outer parser already
7
- * classified the surrounding bytes as code, XML, or prose.
8
- *
9
- * Generic XML opts into literal-context exclusion so tag attributes, code,
10
- * comments, and CDATA remain examples owned by their container. Otherwise the
11
- * scanner is syntax-agnostic about the outer container. It only promotes candidates that independently pass JSON.parse and carry a
12
- * direct string discriminator. Failed/malformed candidates remain untouched.
13
- */
14
- export interface EmbeddedKindJsonRegion {
15
- start: number;
16
- end: number;
17
- content: string;
18
- kind: string;
19
- }
20
- export type EmbeddedKindJsonPiece = {
21
- type: "container";
22
- content: string;
23
- } | {
24
- type: "kind";
25
- content: string;
26
- kind: string;
27
- }
28
- /**
29
- * JSON punctuation that only held kinds together — the `[`, `,` and `]` of
30
- * an array of kinds. Kept so the partition stays lossless; never rendered
31
- * (a lone `[` drawn as a JSON card is noise, not content — A6).
32
- */
33
- | {
34
- type: "chrome";
35
- content: string;
36
- }
37
- /**
38
- * The non-kind DATA of a JSON wrapper around kinds (`{"result":{…kind…},
39
- * "note":"x"}`, A7): `content` is the source span it replaces (lossless),
40
- * `json` is the wrapper's value with every kind removed — valid JSON, drawn
41
- * as genuine JSON. A wrapper that holds only kinds has no residual piece.
42
- */
43
- | {
44
- type: "residual";
45
- content: string;
46
- json: string;
47
- };
48
- /**
49
- * For every `{` / `[` in `text`: the end (exclusive) of the string-aware
50
- * balanced JSON value opening there, or -1 (never balances). Each opener's
51
- * reading starts outside a string, exactly as if read alone; one right-to-left
52
- * pass reuses each nested opener's own answer (its reading from inside an
53
- * enclosing value is the same reading), so the whole table is linear — a
54
- * reading per opener was quadratic on thousands of unclosed `{` (round 11, P5).
55
- */
56
- export declare function balancedEnds(text: string): Int32Array;
57
- /** Outermost complete self-described objects, in source order. */
58
- export { frontMatterEnd } from "./json-kind-signal.js";
59
- export interface EmbeddedKindSearchOptions {
60
- /** Generic XML: code, comments, CDATA and tags are literal (the XML card shows them). */
61
- excludeLiteralContexts?: boolean;
62
- /**
63
- * With `excludeLiteralContexts` (an XML TAG — structure, ruling (b) round 3):
64
- * a ```json / ```jsonc / ```json5 / unlabelled fence is NOT literal. A kind
65
- * that is its whole body leaves with the fence's own lines as chrome, so
66
- * the XML pieces around it hold no orphan fence marker.
67
- */
68
- liftJsonFences?: boolean;
69
- /**
70
- * Markdown: inline code spans and non-JSON fences are the model quoting
71
- * source (`quotedSourceRanges`, the owner's ruling 2026-09-30) — never lifted.
72
- */
73
- excludeQuotedSource?: boolean;
74
- }
75
- export declare function findEmbeddedKindJsonRegions(source: string, options?: EmbeddedKindSearchOptions): EmbeddedKindJsonRegion[];
76
- /** Losslessly partition a container around every recovered kind region. */
77
- export declare function splitAroundEmbeddedKindJson(source: string, options?: EmbeddedKindSearchOptions): EmbeddedKindJsonPiece[];
78
- /**
79
- * A recovered PROSE piece, shaped exactly as the live stream shapes the same
80
- * bytes (A5, 2026-09-30): the stream splits `Here: {"__kind":…} after` into
81
- * three lines as it arrives, so its prose blocks are trimmed at the end (every
82
- * text block is) and, after a kind, start where the next character does — the
83
- * spaces after the object and the one line break that ended its line are the
84
- * boundary, not content. Both hosts call this on every text piece, so a live
85
- * message and its reload draw the same blocks.
86
- */
87
- export declare function normalizeRecoveredProsePiece(content: string, followsKind: boolean): string;
88
- /**
89
- * Every recovered container piece, by its container's block type: prose by
90
- * the rule above, code byte-verbatim, and a SECTION (`thinking`, `info`, …)
91
- * trimmed — the live stream splits a kind out of a section as it arrives
92
- * (A8) and each part is a section body, which is trimmed like a whole one.
93
- */
94
- export declare function normalizeRecoveredContainerPiece(content: string, containerType: string, followsKind: boolean): string;
95
- /**
96
- * A complete JSON value (object or array) that holds at least one kind, as
97
- * one region: a recovered kind region widened to the OUTERMOST complete,
98
- * parseable JSON value that contains it — a kindless wrapper
99
- * (`{"result":{…kind…},"note":…}`, A7) or an array of kinds and plain values.
100
- * For DESTINATION transforms (export, copy, speech) that convert the value
101
- * whole; the renderer partitions the same bytes with
102
- * {@link splitAroundEmbeddedKindJson}. Built on THE region finder above.
103
- */
104
- export interface KindCarryingJsonRegion {
105
- start: number;
106
- end: number;
107
- content: string;
108
- value: unknown;
109
- }
110
- export declare function findKindCarryingJsonValues(source: string, options?: {
111
- excludeLiteralContexts?: boolean;
112
- }): KindCarryingJsonRegion[];
113
- /**
114
- * A kind that can never complete as written: [start, end) and the text of
115
- * its region. Two shapes, by the same ownership rule as the finder above:
116
- * - a CLOSED object whose root declares `__kind` but does not parse (the
117
- * finder's malformed owner) — bounded;
118
- * - an UNCLOSED JSON object or array at the tail (a stream cut off, a
119
- * truncated store) holding a `"__kind"` key anywhere — runs to the end,
120
- * from its outermost opener (a kindless wrapper is cut with its kind).
121
- * For destinations that must say "<Kind> did not finish" instead of printing
122
- * the fragment. Complete values (kind or not) are skipped whole.
123
- */
124
- export interface BrokenKindJsonRegion {
125
- start: number;
126
- end: number;
127
- content: string;
128
- }
129
- /**
130
- * Round 10 (C1): a broken region is bounded by its OWN JSON grammar. An opener
131
- * owns a kind key only when its grammar reaches the key; it runs to the end of
132
- * the text only while it is still validly open, else it ends at its cut. A
133
- * stray `[[`, `{"`, `{{`, `["`, an unrelated earlier object or a pasted
134
- * schema never extends a region over the prose after it. A balanced span that
135
- * does not parse is a region only when it reads once trailing commas go.
136
- * Linear: key positions once, each opener's grammar stops at its break.
137
- */
138
- export declare function findBrokenKindJsonRegions(source: string, options?: {
139
- excludeLiteralContexts?: boolean;
140
- }): BrokenKindJsonRegion[];
@@ -1,527 +0,0 @@
1
- import { readXmlTag } from "../../xml/readXmlTag.js";
2
- import { fenceOpenerOf, findCodeRanges } from "@ai-matrx/content-ir/source";
3
- import { frontMatterEnd, isJsonFenceLanguage, kindGrammar, quotedSourceRanges } from "./json-kind-signal.js";
4
- function matchingJsonObjectEnd(source, start) {
5
- if (source[start] !== "{" && source[start] !== "[") return null;
6
- const stack = [source[start]];
7
- let inString = false;
8
- let escaped = false;
9
- for (let index = start + 1; index < source.length; index++) {
10
- const char = source[index];
11
- if (inString) {
12
- if (escaped) {
13
- escaped = false;
14
- } else if (char === "\\") {
15
- escaped = true;
16
- } else if (char === '"') {
17
- inString = false;
18
- }
19
- continue;
20
- }
21
- if (char === '"') {
22
- inString = true;
23
- continue;
24
- }
25
- if (char === "{" || char === "[") {
26
- stack.push(char);
27
- continue;
28
- }
29
- if (char !== "}" && char !== "]") continue;
30
- const opening = stack.pop();
31
- if (char === "}" && opening !== "{" || char === "]" && opening !== "[") {
32
- return null;
33
- }
34
- if (stack.length === 0) return index + 1;
35
- }
36
- return null;
37
- }
38
- function balancedEnds(text) {
39
- const ends = new Int32Array(text.length).fill(-1);
40
- const stack = [];
41
- for (let start = text.length - 1; start >= 0; start--) {
42
- const open = text[start];
43
- if (open !== "{" && open !== "[") continue;
44
- stack.length = 0;
45
- stack.push(open === "{" ? "}" : "]");
46
- let inString = false;
47
- for (let i = start + 1; i < text.length; i++) {
48
- const ch = text[i];
49
- if (inString) {
50
- if (ch === "\\") i++;
51
- else if (ch === '"') inString = false;
52
- continue;
53
- }
54
- if (ch === '"') inString = true;
55
- else if (ch === "{" || ch === "[") {
56
- const end = ends[i];
57
- if (end < 0) break;
58
- i = end - 1;
59
- } else if (ch === "}" || ch === "]") {
60
- if (stack.pop() !== ch) break;
61
- ends[start] = i + 1;
62
- break;
63
- }
64
- }
65
- }
66
- return ends;
67
- }
68
- function lazyJsonEnds(source) {
69
- let table;
70
- return (start) => {
71
- if (source[start] !== "{" && source[start] !== "[") return null;
72
- table ??= balancedEnds(source);
73
- const end = table[start];
74
- return end < 0 ? null : end;
75
- };
76
- }
77
- function skipWhitespace(source, cursor) {
78
- while (/\s/.test(source[cursor] ?? "")) cursor++;
79
- return cursor;
80
- }
81
- function jsonStringEnd(source, start) {
82
- if (source[start] !== '"') return null;
83
- let escaped = false;
84
- for (let cursor = start + 1; cursor < source.length; cursor++) {
85
- const char = source[cursor];
86
- if (escaped) {
87
- escaped = false;
88
- } else if (char === "\\") {
89
- escaped = true;
90
- } else if (char === '"') {
91
- return cursor + 1;
92
- }
93
- }
94
- return null;
95
- }
96
- function jsonValueEnd(source, start) {
97
- const char = source[start];
98
- if (char === '"') return jsonStringEnd(source, start);
99
- if (char === "{" || char === "[") return matchingJsonObjectEnd(source, start);
100
- const end = source.slice(start).search(/[\s,}\]]/);
101
- const tokenEnd = end === -1 ? source.length : start + end;
102
- const token = source.slice(start, tokenEnd);
103
- return /^(?:true|false|null|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)$/.test(
104
- token
105
- ) ? tokenEnd : null;
106
- }
107
- function malformedKindOwnerEnd(source, start, boundary = source.length) {
108
- let cursor = skipWhitespace(source, start + 1);
109
- let kindFound = false;
110
- const ownerEnd = () => kindFound ? boundary : null;
111
- while (cursor < boundary) {
112
- const keyStart = cursor;
113
- const keyEnd = jsonStringEnd(source, keyStart);
114
- if (keyEnd === null || keyEnd > boundary) return ownerEnd();
115
- let key;
116
- try {
117
- key = JSON.parse(source.slice(keyStart, keyEnd));
118
- } catch {
119
- return ownerEnd();
120
- }
121
- cursor = skipWhitespace(source, keyEnd);
122
- if (cursor >= boundary || source[cursor] !== ":") return ownerEnd();
123
- cursor = skipWhitespace(source, cursor + 1);
124
- const valueStart = cursor;
125
- const valueEnd = jsonValueEnd(source, valueStart);
126
- if (valueEnd === null || valueEnd > boundary) return ownerEnd();
127
- if (key === "__kind") {
128
- try {
129
- const value = JSON.parse(source.slice(valueStart, valueEnd));
130
- kindFound ||= typeof value === "string" && value.trim().length > 0;
131
- } catch {
132
- return ownerEnd();
133
- }
134
- }
135
- cursor = skipWhitespace(source, valueEnd);
136
- if (source[cursor] === "}") return kindFound ? cursor + 1 : null;
137
- if (cursor >= boundary || source[cursor] !== ",") return ownerEnd();
138
- cursor = skipWhitespace(source, cursor + 1);
139
- }
140
- return ownerEnd();
141
- }
142
- function jsonStringRanges(source, start, end) {
143
- const ranges = [];
144
- for (let cursor = start; cursor < end; cursor++) {
145
- if (source[cursor] !== '"') continue;
146
- const stringEnd = jsonStringEnd(source, cursor);
147
- if (stringEnd === null || stringEnd > end) break;
148
- ranges.push([cursor, stringEnd]);
149
- cursor = stringEnd - 1;
150
- }
151
- return ranges;
152
- }
153
- function declaredKind(candidate) {
154
- try {
155
- const parsed = JSON.parse(candidate);
156
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
157
- return null;
158
- }
159
- const kind = parsed.__kind;
160
- return typeof kind === "string" && kind.trim() ? kind : null;
161
- } catch {
162
- return null;
163
- }
164
- }
165
- function literalRanges(source, liftJsonFences = false) {
166
- const ranges = [];
167
- const code = liftJsonFences ? findCodeRanges(source).filter((range) => !isJsonFenceRange(source, range)) : findCodeRanges(source);
168
- let next = 0;
169
- let cursor = 0;
170
- while (cursor < source.length) {
171
- while (next < code.length && code[next].start < cursor) next++;
172
- const range = code[next];
173
- if (range && range.start === cursor) {
174
- ranges.push([range.start, range.end]);
175
- cursor = range.end;
176
- next++;
177
- continue;
178
- }
179
- if (source.startsWith("<!--", cursor)) {
180
- const end = source.indexOf("-->", cursor + 4);
181
- const rangeEnd = end === -1 ? source.length : end + 3;
182
- ranges.push([cursor, rangeEnd]);
183
- cursor = rangeEnd;
184
- continue;
185
- }
186
- if (source.startsWith("<![CDATA[", cursor)) {
187
- const end = source.indexOf("]]>", cursor + 9);
188
- const rangeEnd = end === -1 ? source.length : end + 3;
189
- ranges.push([cursor, rangeEnd]);
190
- cursor = rangeEnd;
191
- continue;
192
- }
193
- if (source[cursor] === "<") {
194
- const tag = readXmlTag(source, cursor);
195
- if (tag) {
196
- const end = cursor + tag.raw.length;
197
- ranges.push([cursor, end]);
198
- cursor = end;
199
- continue;
200
- }
201
- if (/^<[A-Za-z_][\w.:-]*\s/.test(source.slice(cursor, cursor + 64)) && !tagCloses(source, cursor)) {
202
- ranges.push([cursor, source.length]);
203
- break;
204
- }
205
- }
206
- cursor++;
207
- }
208
- return ranges;
209
- }
210
- function tagCloses(source, start) {
211
- let quote = null;
212
- for (let i = start + 1; i < source.length; i++) {
213
- const ch = source[i];
214
- if (quote) {
215
- if (ch === quote) quote = null;
216
- } else if (ch === "'" || ch === '"') quote = ch;
217
- else if (ch === ">") return true;
218
- }
219
- return false;
220
- }
221
- function isJsonFenceRange(source, range) {
222
- if (range.kind !== "fence") return false;
223
- const raw = source.slice(range.start, range.end);
224
- const newline = raw.indexOf("\n");
225
- const opener = fenceOpenerOf((newline === -1 ? raw : raw.slice(0, newline)).trimStart());
226
- return opener !== null && isJsonFenceLanguage(opener.lang);
227
- }
228
- function jsonFenceChromeSpans(source, regions) {
229
- const spans = [];
230
- for (const range of findCodeRanges(source)) {
231
- if (!isJsonFenceRange(source, range)) continue;
232
- const inside = regions.filter((r) => r.start >= range.start && r.end <= range.end);
233
- if (inside.length !== 1) continue;
234
- const region = inside[0];
235
- const head = source.slice(range.start, region.start);
236
- const tail = source.slice(region.end, range.end);
237
- if (!/^[^\n]*\n\s*$/.test(head) || !/^\s*(?:[`~]{3,}[ \t]*)?$/.test(tail)) continue;
238
- spans.push([range.start, region.start]);
239
- if (region.end < range.end) spans.push([region.end, range.end]);
240
- }
241
- return spans;
242
- }
243
- import { frontMatterEnd as frontMatterEnd2 } from "./json-kind-signal.js";
244
- function findEmbeddedKindJsonRegions(source, options = {}) {
245
- const regions = [];
246
- const endOf = lazyJsonEnds(source);
247
- const excluded = [
248
- ...options.excludeLiteralContexts ? literalRanges(source, options.liftJsonFences === true) : [],
249
- ...options.excludeQuotedSource ? quotedSourceRanges(source) : []
250
- ].sort((a, b) => a[0] - b[0]);
251
- const jsonStrings = [];
252
- let excludedIndex = 0;
253
- let jsonStringIndex = 0;
254
- for (let start = frontMatterEnd(source); start < source.length; start++) {
255
- while (excludedIndex < excluded.length && excluded[excludedIndex][1] <= start) {
256
- excludedIndex++;
257
- }
258
- while (jsonStringIndex < jsonStrings.length && jsonStrings[jsonStringIndex][1] <= start) {
259
- jsonStringIndex++;
260
- }
261
- if (excludedIndex < excluded.length && start >= excluded[excludedIndex][0] && start < excluded[excludedIndex][1])
262
- continue;
263
- if (jsonStringIndex < jsonStrings.length && start >= jsonStrings[jsonStringIndex][0] && start < jsonStrings[jsonStringIndex][1])
264
- continue;
265
- if (source[start] !== "{") continue;
266
- const end = endOf(start);
267
- if (end === null) {
268
- const verdict = kindGrammar(source, "json", start);
269
- const bound = verdict.status === "broken" ? verdict.cut : source.length;
270
- const ownerEnd = bound > start ? malformedKindOwnerEnd(source, start, bound) : null;
271
- if (ownerEnd !== null) start = ownerEnd - 1;
272
- continue;
273
- }
274
- const content = source.slice(start, end);
275
- const kind = declaredKind(content);
276
- if (!kind) {
277
- const ownerEnd = malformedKindOwnerEnd(source, start, end);
278
- if (ownerEnd !== null) {
279
- start = ownerEnd - 1;
280
- continue;
281
- }
282
- for (const range of jsonStringRanges(source, start, end)) jsonStrings.push(range);
283
- continue;
284
- }
285
- regions.push({ start, end, content, kind });
286
- start = end - 1;
287
- }
288
- return regions;
289
- }
290
- function kindArrayChromeSpans(source, regions) {
291
- const spans = [];
292
- let first = 0;
293
- while (first < regions.length) {
294
- let last = first;
295
- while (last + 1 < regions.length && /^\s*,\s*$/.test(source.slice(regions[last].end, regions[last + 1].start))) {
296
- last++;
297
- }
298
- const before = source.slice(0, regions[first].start);
299
- const open = /\[\s*$/.exec(before);
300
- const after = source.slice(regions[last].end);
301
- const close = /^\s*\]/.exec(after);
302
- if (open && close) {
303
- spans.push([open.index, regions[first].start]);
304
- for (let k = first; k < last; k++) {
305
- spans.push([regions[k].end, regions[k + 1].start]);
306
- }
307
- spans.push([regions[last].end, regions[last].end + close[0].length]);
308
- }
309
- first = last + 1;
310
- }
311
- return spans;
312
- }
313
- function isKindValue(value) {
314
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
315
- return false;
316
- }
317
- const kind = value.__kind;
318
- return typeof kind === "string" && kind.trim().length > 0;
319
- }
320
- function withoutKinds(value) {
321
- if (Array.isArray(value)) {
322
- return value.filter((item) => !isKindValue(item)).map(withoutKinds);
323
- }
324
- if (typeof value === "object" && value !== null) {
325
- const out = {};
326
- for (const [key, item] of Object.entries(value)) {
327
- if (!isKindValue(item)) out[key] = withoutKinds(item);
328
- }
329
- return out;
330
- }
331
- return value;
332
- }
333
- function carriesData(value) {
334
- if (Array.isArray(value)) return value.some(carriesData);
335
- if (typeof value === "object" && value !== null) {
336
- return Object.values(value).some(carriesData);
337
- }
338
- return true;
339
- }
340
- function isPureJsonStructure(span) {
341
- return /^[\s{}[\],:]*$/.test(
342
- span.replace(/"(?:[^"\\]|\\.)*"\s*:/g, "")
343
- );
344
- }
345
- function wrapperPieces(source, regions) {
346
- const trimmed = source.trim();
347
- if (!/^[[{]/.test(trimmed)) return null;
348
- let parsed;
349
- try {
350
- parsed = JSON.parse(trimmed);
351
- } catch {
352
- return null;
353
- }
354
- if (typeof parsed !== "object" || parsed === null || isKindValue(parsed)) {
355
- return null;
356
- }
357
- const residual = withoutKinds(parsed);
358
- const residualJson = carriesData(residual) ? JSON.stringify(residual, null, 2) : null;
359
- const pieces = [];
360
- let residualPlaced = residualJson === null;
361
- const pushSpan = (content) => {
362
- if (!content) return;
363
- if (!residualPlaced && !isPureJsonStructure(content)) {
364
- pieces.push({ type: "residual", content, json: residualJson });
365
- residualPlaced = true;
366
- return;
367
- }
368
- pieces.push({ type: "chrome", content });
369
- };
370
- let cursor = 0;
371
- for (const region of regions) {
372
- pushSpan(source.slice(cursor, region.start));
373
- pieces.push({ type: "kind", content: region.content, kind: region.kind });
374
- cursor = region.end;
375
- }
376
- pushSpan(source.slice(cursor));
377
- if (!residualPlaced) {
378
- pieces.push({ type: "residual", content: "", json: residualJson });
379
- }
380
- return pieces;
381
- }
382
- function splitAroundEmbeddedKindJson(source, options = {}) {
383
- const regions = findEmbeddedKindJsonRegions(source, options);
384
- if (regions.length === 0) return [{ type: "container", content: source }];
385
- const wrapped = wrapperPieces(source, regions);
386
- if (wrapped) return wrapped;
387
- const marks = [
388
- ...regions.map((r) => ({ start: r.start, end: r.end, type: "kind", kind: r.kind })),
389
- ...[
390
- ...kindArrayChromeSpans(source, regions),
391
- ...options.excludeLiteralContexts && options.liftJsonFences ? jsonFenceChromeSpans(source, regions) : []
392
- ].map(([start, end]) => ({
393
- start,
394
- end,
395
- type: "chrome"
396
- }))
397
- ].sort((a, b) => a.start - b.start);
398
- const pieces = [];
399
- let cursor = 0;
400
- for (const mark of marks) {
401
- if (mark.start > cursor) {
402
- pieces.push({
403
- type: "container",
404
- content: source.slice(cursor, mark.start)
405
- });
406
- }
407
- if (mark.end > mark.start) {
408
- pieces.push(
409
- mark.type === "kind" ? { type: "kind", content: source.slice(mark.start, mark.end), kind: mark.kind } : { type: "chrome", content: source.slice(mark.start, mark.end) }
410
- );
411
- }
412
- cursor = Math.max(cursor, mark.end);
413
- }
414
- if (cursor < source.length) {
415
- pieces.push({ type: "container", content: source.slice(cursor) });
416
- }
417
- return pieces;
418
- }
419
- function normalizeRecoveredProsePiece(content, followsKind) {
420
- const start = followsKind ? content.replace(/^[ \t]*(?:\r?\n)?/, "") : content;
421
- return start.trimEnd();
422
- }
423
- function normalizeRecoveredContainerPiece(content, containerType, followsKind) {
424
- if (containerType === "text") {
425
- return normalizeRecoveredProsePiece(content, followsKind);
426
- }
427
- if (containerType === "code") return content;
428
- return content.trim();
429
- }
430
- function findKindCarryingJsonValues(source, options = {}) {
431
- const kinds = findEmbeddedKindJsonRegions(source, options);
432
- if (kinds.length === 0) return [];
433
- const excluded = options.excludeLiteralContexts ? literalRanges(source) : [];
434
- const inLiteral = (index) => excluded.some(([start, end]) => index >= start && index < end);
435
- const ends = balancedEnds(source);
436
- const regions = [];
437
- let floor = frontMatterEnd(source);
438
- for (const region of kinds) {
439
- if (region.start < floor) continue;
440
- let best = { start: region.start, end: region.end, value: JSON.parse(region.content) };
441
- for (let open = floor; open < region.start; open++) {
442
- const char = source[open];
443
- if (char !== "{" && char !== "[" || inLiteral(open)) continue;
444
- const found = ends[open];
445
- if (found < 0 || found < region.end) continue;
446
- const end = found;
447
- try {
448
- best = { start: open, end, value: JSON.parse(source.slice(open, end)) };
449
- break;
450
- } catch {
451
- continue;
452
- }
453
- }
454
- regions.push({ ...best, content: source.slice(best.start, best.end) });
455
- floor = best.end;
456
- }
457
- return regions;
458
- }
459
- const KIND_KEY_TEXT = /(?<!\\)"__kind"\s*:/;
460
- const KIND_KEY_TEXT_G = /(?<!\\)"__kind"\s*:/g;
461
- function findBrokenKindJsonRegions(source, options = {}) {
462
- const broken = [];
463
- if (!KIND_KEY_TEXT.test(source)) return broken;
464
- const endOf = lazyJsonEnds(source);
465
- const keys = [];
466
- KIND_KEY_TEXT_G.lastIndex = 0;
467
- for (let m = KIND_KEY_TEXT_G.exec(source); m; m = KIND_KEY_TEXT_G.exec(source)) keys.push(m.index);
468
- let keyIndex = 0;
469
- const excluded = options.excludeLiteralContexts ? literalRanges(source) : [];
470
- let excludedIndex = 0;
471
- for (let start = frontMatterEnd(source); start < source.length; start++) {
472
- while (excludedIndex < excluded.length && excluded[excludedIndex][1] <= start) {
473
- excludedIndex++;
474
- }
475
- if (excludedIndex < excluded.length && start >= excluded[excludedIndex][0] && start < excluded[excludedIndex][1]) {
476
- start = excluded[excludedIndex][1] - 1;
477
- continue;
478
- }
479
- const char = source[start];
480
- if (char !== "{" && char !== "[") continue;
481
- while (keyIndex < keys.length && keys[keyIndex] < start) keyIndex++;
482
- if (keyIndex >= keys.length) break;
483
- const key = keys[keyIndex];
484
- const verdict = kindGrammar(source, "json", start);
485
- if (verdict.status === "complete") {
486
- try {
487
- JSON.parse(source.slice(start, verdict.end));
488
- start = verdict.end - 1;
489
- } catch {
490
- }
491
- continue;
492
- }
493
- if (verdict.status === "prefix") {
494
- broken.push({ start, end: source.length, content: source.slice(start) });
495
- break;
496
- }
497
- if (verdict.at <= key) continue;
498
- const end = endOf(start);
499
- if (end !== null && lenientJson(source.slice(start, end))) {
500
- broken.push({ start, end, content: source.slice(start, end) });
501
- start = end - 1;
502
- continue;
503
- }
504
- if (verdict.cut <= key) continue;
505
- broken.push({ start, end: verdict.cut, content: source.slice(start, verdict.cut) });
506
- start = verdict.cut - 1;
507
- }
508
- return broken;
509
- }
510
- function lenientJson(span) {
511
- try {
512
- JSON.parse(span.replace(/,(\s*[}\]])/g, "$1"));
513
- return true;
514
- } catch {
515
- return false;
516
- }
517
- }
518
- export {
519
- balancedEnds,
520
- findBrokenKindJsonRegions,
521
- findEmbeddedKindJsonRegions,
522
- findKindCarryingJsonValues,
523
- frontMatterEnd2 as frontMatterEnd,
524
- normalizeRecoveredContainerPiece,
525
- normalizeRecoveredProsePiece,
526
- splitAroundEmbeddedKindJson
527
- };