llm_meta_widget 0.13.1 → 0.15.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/README.md +22 -11
- data/app/assets/javascripts/llm_meta_widget/element.js +5 -1
- data/app/assets/javascripts/llm_meta_widget/llm-meta-widget.js +32 -16
- data/app/assets/javascripts/llm_meta_widget/orchestrator.js +50 -29
- data/lib/llm_meta_widget/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8797cb824bc5421990348a5de7fabd7eb95a0ec0c10f8e2d579d29d3483e7b29
|
|
4
|
+
data.tar.gz: 8151a9ab5e27e0e1bd1f46d62750e2a41137660d65c501713e9a10e94269858f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12d33498cb17917ebc7f6a5950185b003267c52eab06f50e9632d36e5fd7e9c1bfe54d18134be7bc5e9082ff4c5e087769b0235983ff72aa6ec3dbd8461641af
|
|
7
|
+
data.tar.gz: 0f2975b8f85714bb11e64b43192755e26b61f90a9a80e6f20871895a76e292bfbb3f245c7e7f679e81331f1ab9be7d0362e91b8ce4e32b96d16ac10ce9eb8ded
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,64 @@
|
|
|
3
3
|
This file starts at 0.8.0, the first release with a breaking change worth
|
|
4
4
|
calling out. Earlier releases are in the git history (`git log --oneline v0.7.6`).
|
|
5
5
|
|
|
6
|
+
## 0.15.0
|
|
7
|
+
|
|
8
|
+
### The declared global is resolved when a handler is needed, not at startup
|
|
9
|
+
|
|
10
|
+
A page card is parsed from the DOM before the page's own scripts have
|
|
11
|
+
necessarily run, and a consumer may be injected before them. Until now the
|
|
12
|
+
widget looked up the global named by the card's `page-global` transport once, at
|
|
13
|
+
startup, and kept the result: a page whose handler script ran later — with
|
|
14
|
+
`defer`, as an ES module, or from a `<script>` near the end of the document —
|
|
15
|
+
got no handlers at all for the rest of its life, with only a console warning to
|
|
16
|
+
explain it.
|
|
17
|
+
|
|
18
|
+
The lookup now happens each time a handler is wanted, so script order no longer
|
|
19
|
+
matters. A global defined after the card was read is found; a global that
|
|
20
|
+
disappears falls back to the older globals again instead of serving a stale map.
|
|
21
|
+
|
|
22
|
+
The "declares a global the page never defines" message moved with it. At startup
|
|
23
|
+
it was a false alarm, because the defining script may simply not have run yet;
|
|
24
|
+
it is now said when a handler is actually wanted, and said once rather than on
|
|
25
|
+
every lookup.
|
|
26
|
+
|
|
27
|
+
This is what SEP-0000 asks of a consumer: handler availability is a runtime
|
|
28
|
+
binding, and the burden sits on the consumer, which is the side that can know
|
|
29
|
+
its own injection timing.
|
|
30
|
+
|
|
31
|
+
### Two smaller fixes from the same conformance audit
|
|
32
|
+
|
|
33
|
+
- A transport type declared twice was reported as "two blocks declare different
|
|
34
|
+
globals" even when a single block declared it twice. The message now covers
|
|
35
|
+
both cases.
|
|
36
|
+
- A card addressed by `page_card_id:` — the escape hatch for a host that cannot
|
|
37
|
+
set the media type — was read without the merge step, which is where a
|
|
38
|
+
duplicated transport is caught. It was therefore the one path where that
|
|
39
|
+
authoring error went unreported. It now goes through the same check.
|
|
40
|
+
|
|
41
|
+
Nothing a conformant page declares behaves differently, and no card needs
|
|
42
|
+
changing.
|
|
43
|
+
|
|
44
|
+
## 0.14.0
|
|
45
|
+
|
|
46
|
+
### Breaking: a transport declared in top-level `remotes` is no longer read
|
|
47
|
+
|
|
48
|
+
0.13.0 moved the declaration into
|
|
49
|
+
`_meta["io.modelcontextprotocol/static-primitives"].transports` and kept reading
|
|
50
|
+
the old top-level `remotes` list, with a warning, so that a page and a widget
|
|
51
|
+
could be updated in either order. That transition is over.
|
|
52
|
+
|
|
53
|
+
**If your page card still declares its transport in `remotes`, move it to
|
|
54
|
+
`transports` before taking this release.** A card that still carries the old
|
|
55
|
+
spelling gets no handlers from the card: the widget falls back to
|
|
56
|
+
`window.aiActions`, `window.aiPrompts` and `window.aiResources`, which is
|
|
57
|
+
nothing at all for a page that does not define them. The widget reports the
|
|
58
|
+
situation in the browser console rather than leaving you to find it, but it
|
|
59
|
+
cannot dispatch.
|
|
60
|
+
|
|
61
|
+
Nothing else changed. If your card already declares `transports`, this release
|
|
62
|
+
behaves exactly like 0.13.1.
|
|
63
|
+
|
|
6
64
|
## 0.13.1
|
|
7
65
|
|
|
8
66
|
### Documentation: the README caught up with 0.12.x and 0.13.0
|
data/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Option 3 if it does not.
|
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
63
|
# Gemfile
|
|
64
|
-
gem "llm_meta_widget", "~> 0.
|
|
64
|
+
gem "llm_meta_widget", "~> 0.15.0"
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
```bash
|
|
@@ -152,26 +152,25 @@ The widget is a custom element in a single self-contained ES module, so the
|
|
|
152
152
|
whole integration is two lines of HTML:
|
|
153
153
|
|
|
154
154
|
```html
|
|
155
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@aibranch/llm-meta-widget@0.
|
|
155
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@aibranch/llm-meta-widget@0.15"></script>
|
|
156
156
|
<llm-meta-widget llm-url="https://your-meta-server.example"
|
|
157
157
|
model="gpt-oss-120b"
|
|
158
158
|
greeting="Hi — ask me anything about this page."></llm-meta-widget>
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
**`@0.
|
|
161
|
+
**`@0.15` is a version range, and it stops at 0.15.x on purpose.** You receive
|
|
162
162
|
bug fixes without editing your page, and a release that breaks your page cannot
|
|
163
163
|
arrive on its own.
|
|
164
164
|
|
|
165
|
-
Moving to 0.
|
|
165
|
+
Moving to 0.16 is therefore a change you make yourself. Read
|
|
166
166
|
[CHANGELOG.md](CHANGELOG.md) before you do, because this is where what your page
|
|
167
167
|
must provide can change. For example, 0.10.0 changed how the widget finds a page
|
|
168
168
|
card: by media type rather than by element id. A page that declared its card the
|
|
169
169
|
new way while still loading `@0.9` lost every tool, prompt and resource it had
|
|
170
170
|
declared. Nothing failed, anywhere. The CHANGELOG entry for 0.10.0 describes it.
|
|
171
171
|
|
|
172
|
-
0.13.0
|
|
173
|
-
|
|
174
|
-
afterwards.
|
|
172
|
+
0.13.0 moved where a page declares its transport, and 0.14.0 stopped reading
|
|
173
|
+
the old spelling. Move your card to `transports` before taking 0.14.x.
|
|
175
174
|
|
|
176
175
|
A Rails app is protected from that mismatch, because the `Gemfile` will not
|
|
177
176
|
resolve a widget version the page cannot use. A page that loads the widget from
|
|
@@ -312,10 +311,10 @@ widget supports today. Leave `transports` out and the widget reads
|
|
|
312
311
|
`window.aiActions`, `window.aiPrompts` and `window.aiResources` instead — see
|
|
313
312
|
"Say where your handlers live".
|
|
314
313
|
|
|
315
|
-
Widgets
|
|
316
|
-
level of the card
|
|
317
|
-
|
|
318
|
-
|
|
314
|
+
Widgets from 0.11.1 to 0.12.2 read this declaration from a `remotes` list at the
|
|
315
|
+
top level of the card, and 0.13.x read either spelling. From 0.14.0 the old one
|
|
316
|
+
is not read at all: a card that still carries it gets no handlers, and the
|
|
317
|
+
widget reports that in the browser console. Write `transports`.
|
|
319
318
|
|
|
320
319
|
A page may declare `prompts` in the same block. See [The page card](#the-page-card)
|
|
321
320
|
for prompts, for the size and volatility hints on a resource, and for what
|
|
@@ -603,6 +602,18 @@ so no other consumer can rely on them. Each kind falls back on its own, so you
|
|
|
603
602
|
can move tools into the declared global and leave prompts and resources where
|
|
604
603
|
they are.
|
|
605
604
|
|
|
605
|
+
**Script order does not matter.** The widget looks up your global at the moment
|
|
606
|
+
it needs a handler, not when it reads the card. The script that defines
|
|
607
|
+
`window.mcp` may therefore run before or after the widget loads: a `defer`
|
|
608
|
+
attribute, an ES module, or a `<script>` near the end of the page are all fine.
|
|
609
|
+
If a handler is wanted while the global is still undefined, the widget says so
|
|
610
|
+
in the browser console once, and falls back to the older globals for that call.
|
|
611
|
+
|
|
612
|
+
Before 0.15.0 the lookup happened once at startup, so a page whose handler
|
|
613
|
+
script ran later got no handlers at all for the rest of its life, with only a
|
|
614
|
+
console warning to say why. If you are pinned below 0.15.0, define your global
|
|
615
|
+
before the widget's own script tag.
|
|
616
|
+
|
|
606
617
|
**The card is found by its media type.** A client matches
|
|
607
618
|
`script[type="application/mcp-static-primitives+json"]`, so the element needs no
|
|
608
619
|
`id`. This is how a client that was never told about your page can still read
|
|
@@ -387,7 +387,11 @@ function boot(cfg) {
|
|
|
387
387
|
}));
|
|
388
388
|
} else {
|
|
389
389
|
var pageCardEl = document.getElementById(PAGE_CARD_ID);
|
|
390
|
-
|
|
390
|
+
// Through the merge as well, with one card: that is where a transport
|
|
391
|
+
// declared twice is caught, and the escape hatch should not be the one
|
|
392
|
+
// path where an authoring error goes unreported.
|
|
393
|
+
pageCard = mergeStaticPrimitivesCards(
|
|
394
|
+
[ readStaticPrimitivesCard(pageCardEl ? pageCardEl.textContent : null) ]);
|
|
391
395
|
}
|
|
392
396
|
// Where the page's handlers live. The card may declare a global, which is
|
|
393
397
|
// the only form an outside consumer can discover; the three legacy globals
|
|
@@ -701,35 +701,49 @@ function declaredPageGlobal(card, warn = console.warn) {
|
|
|
701
701
|
warn("[llm-meta-widget] page card declares transports " + JSON.stringify(declared.map((t) => t && t.type)) + ", none of which this widget supports; not dispatching to the page");
|
|
702
702
|
return null;
|
|
703
703
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
if (typeof remote.global === "string" && remote.global.trim() !== "") {
|
|
707
|
-
warn(`[llm-meta-widget] page card declares its transport in top-level "remotes", which is deprecated; move it to _meta["${STATIC_PRIMITIVES_META}"].transports`);
|
|
708
|
-
return remote.global.trim();
|
|
709
|
-
}
|
|
704
|
+
if ((card && card.remotes || []).some((r) => r && r.type === PAGE_GLOBAL_TRANSPORT)) {
|
|
705
|
+
warn(`[llm-meta-widget] page card declares its transport in top-level "remotes", which is no longer read. Move it to _meta["${STATIC_PRIMITIVES_META}"].transports`);
|
|
710
706
|
}
|
|
711
707
|
return null;
|
|
712
708
|
}
|
|
713
709
|
function pageHandlers({ card, scope = {}, legacy = {}, warn = console.warn } = {}) {
|
|
714
710
|
const name = declaredPageGlobal(card, warn);
|
|
715
|
-
const declared = name ? scope[name] : null;
|
|
716
|
-
if (name && !declared) {
|
|
717
|
-
warn(`[llm-meta-widget] the page card declares global "${name}", but window.${name} is not defined \u2014 is the script that defines it loaded, and did it run?`);
|
|
718
|
-
}
|
|
719
711
|
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
712
|
+
const said = /* @__PURE__ */ new Set();
|
|
713
|
+
const sayOnce = (key, message) => {
|
|
714
|
+
if (said.has(key)) return;
|
|
715
|
+
said.add(key);
|
|
716
|
+
warn(message);
|
|
717
|
+
};
|
|
720
718
|
const pick = (kind, legacyName) => {
|
|
719
|
+
const declared = name ? scope[name] : null;
|
|
720
|
+
if (name && !declared) {
|
|
721
|
+
sayOnce(
|
|
722
|
+
"missing",
|
|
723
|
+
`[llm-meta-widget] the page card declares global "${name}", but window.${name} is not defined \u2014 is the script that defines it loaded, and did it run?`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
721
726
|
const fromGlobal = declared ? declared[kind] : void 0;
|
|
722
727
|
if (isMap(fromGlobal)) return fromGlobal;
|
|
723
728
|
if (declared && fromGlobal !== void 0 && !isMap(fromGlobal)) {
|
|
724
|
-
|
|
729
|
+
sayOnce(
|
|
730
|
+
`shape:${kind}`,
|
|
731
|
+
`[llm-meta-widget] window.${name}.${kind} is ${Array.isArray(fromGlobal) ? "an array" : typeof fromGlobal}; it must be an object keyed by ${kind === "resources" ? "uri" : "name"}`
|
|
732
|
+
);
|
|
725
733
|
}
|
|
726
734
|
return legacyName && scope[legacyName] || {};
|
|
727
735
|
};
|
|
728
736
|
return {
|
|
729
737
|
global: name,
|
|
730
|
-
tools
|
|
731
|
-
|
|
732
|
-
|
|
738
|
+
get tools() {
|
|
739
|
+
return pick("tools", legacy.tools);
|
|
740
|
+
},
|
|
741
|
+
get prompts() {
|
|
742
|
+
return pick("prompts", legacy.prompts);
|
|
743
|
+
},
|
|
744
|
+
get resources() {
|
|
745
|
+
return pick("resources", legacy.resources);
|
|
746
|
+
}
|
|
733
747
|
};
|
|
734
748
|
}
|
|
735
749
|
function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
@@ -740,7 +754,7 @@ function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
|
740
754
|
if (!entry || typeof entry.type !== "string") continue;
|
|
741
755
|
const clash = merged[kind].find((r) => r.type === entry.type && r.global !== entry.global);
|
|
742
756
|
if (clash) {
|
|
743
|
-
warn(`[llm-meta-widget]
|
|
757
|
+
warn(`[llm-meta-widget] the ${entry.type} transport is declared more than once, with different globals ("${clash.global}" and "${entry.global}"); using "${clash.global}". One block may declare it twice, or two blocks may disagree`);
|
|
744
758
|
continue;
|
|
745
759
|
}
|
|
746
760
|
if (!merged[kind].some((r) => r.type === entry.type && r.global === entry.global)) {
|
|
@@ -4167,7 +4181,9 @@ function boot(cfg) {
|
|
|
4167
4181
|
);
|
|
4168
4182
|
} else {
|
|
4169
4183
|
var pageCardEl = document.getElementById(PAGE_CARD_ID);
|
|
4170
|
-
pageCard =
|
|
4184
|
+
pageCard = mergeStaticPrimitivesCards(
|
|
4185
|
+
[readStaticPrimitivesCard(pageCardEl ? pageCardEl.textContent : null)]
|
|
4186
|
+
);
|
|
4171
4187
|
}
|
|
4172
4188
|
var handlers = pageHandlers({
|
|
4173
4189
|
card: pageCard,
|
|
@@ -1130,10 +1130,9 @@ export const PAGE_GLOBAL_TRANSPORT = "page-global"
|
|
|
1130
1130
|
// `page-postmessage`, `page-jsonrpc` and `page-worker` are reserved, and a card
|
|
1131
1131
|
// declaring only those gets no handlers rather than the wrong ones.
|
|
1132
1132
|
//
|
|
1133
|
-
// Top-level `remotes` is the pre-d44bd25a shape that 0.11.1
|
|
1134
|
-
//
|
|
1135
|
-
//
|
|
1136
|
-
// knows to move.
|
|
1133
|
+
// Top-level `remotes` is the pre-d44bd25a shape that 0.11.1 to 0.12.2 read and
|
|
1134
|
+
// 0.13.x accepted. It is no longer read, but a card still carrying it is
|
|
1135
|
+
// reported, because the alternative is a page that quietly stops working.
|
|
1137
1136
|
export function declaredPageGlobal(card, warn = console.warn) {
|
|
1138
1137
|
const declared = (card && card.transports) || []
|
|
1139
1138
|
for (const transport of declared) {
|
|
@@ -1149,14 +1148,14 @@ export function declaredPageGlobal(card, warn = console.warn) {
|
|
|
1149
1148
|
return null
|
|
1150
1149
|
}
|
|
1151
1150
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1151
|
+
// No longer read. Reporting it is still worth a few lines: without this a
|
|
1152
|
+
// card that declares its transport only in the old place gets no handlers,
|
|
1153
|
+
// falls through to the legacy globals, and a page that deliberately defines
|
|
1154
|
+
// none — as PubDictionaries does — simply stops working with nothing said.
|
|
1155
|
+
if (((card && card.remotes) || []).some((r) => r && r.type === PAGE_GLOBAL_TRANSPORT)) {
|
|
1156
|
+
warn('[llm-meta-widget] page card declares its transport in top-level ' +
|
|
1157
|
+
'"remotes", which is no longer read. Move it to ' +
|
|
1158
|
+
`_meta["${STATIC_PRIMITIVES_META}"].transports`)
|
|
1160
1159
|
}
|
|
1161
1160
|
return null
|
|
1162
1161
|
}
|
|
@@ -1166,19 +1165,36 @@ export function declaredPageGlobal(card, warn = console.warn) {
|
|
|
1166
1165
|
// keeps working instead of losing the primitives it has not moved yet.
|
|
1167
1166
|
export function pageHandlers({ card, scope = {}, legacy = {}, warn = console.warn } = {}) {
|
|
1168
1167
|
const name = declaredPageGlobal(card, warn)
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
//
|
|
1172
|
-
//
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1168
|
+
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v)
|
|
1169
|
+
|
|
1170
|
+
// Each said at most once. These now fire on dispatch rather than at mount, so
|
|
1171
|
+
// a page that never defines its global would otherwise repeat them every turn.
|
|
1172
|
+
const said = new Set()
|
|
1173
|
+
const sayOnce = (key, message) => {
|
|
1174
|
+
if (said.has(key)) return
|
|
1175
|
+
said.add(key)
|
|
1176
|
+
warn(message)
|
|
1178
1177
|
}
|
|
1179
1178
|
|
|
1180
|
-
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v)
|
|
1181
1179
|
const pick = (kind, legacyName) => {
|
|
1180
|
+
// Resolved HERE, when a handler is wanted, not when the card was read. The
|
|
1181
|
+
// card is parsed from the DOM before the page's own scripts have
|
|
1182
|
+
// necessarily run, and a consumer may be injected before them, so a global
|
|
1183
|
+
// that is missing at discovery may well be defined by the time a tool is
|
|
1184
|
+
// called. Caching that first lookup turned a load-order detail into a page
|
|
1185
|
+
// that silently had no handlers for the rest of its life.
|
|
1186
|
+
const declared = name ? scope[name] : null
|
|
1187
|
+
|
|
1188
|
+
// A card that names a global the page never defines is almost always a load
|
|
1189
|
+
// order problem, or a script that threw before it got there. Falling back in
|
|
1190
|
+
// silence hides that: the page then behaves as if it had declared nothing,
|
|
1191
|
+
// and the first symptom is a prompt or tool that "has no handler".
|
|
1192
|
+
if (name && !declared) {
|
|
1193
|
+
sayOnce("missing",
|
|
1194
|
+
`[llm-meta-widget] the page card declares global "${name}", but window.${name} ` +
|
|
1195
|
+
"is not defined — is the script that defines it loaded, and did it run?")
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1182
1198
|
// `declared ? … : undefined`, not `declared && …`: the second yields null
|
|
1183
1199
|
// when nothing is declared, and `typeof null === "object"`, so the check
|
|
1184
1200
|
// below then warned about "window.null.tools" on every page with no card.
|
|
@@ -1187,16 +1203,20 @@ export function pageHandlers({ card, scope = {}, legacy = {}, warn = console.war
|
|
|
1187
1203
|
// An array is the mistake worth naming: it passes a typeof check, so it
|
|
1188
1204
|
// would be used as a map and answer every lookup with undefined.
|
|
1189
1205
|
if (declared && fromGlobal !== undefined && !isMap(fromGlobal)) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1206
|
+
sayOnce(`shape:${kind}`,
|
|
1207
|
+
`[llm-meta-widget] window.${name}.${kind} is ${Array.isArray(fromGlobal) ? "an array" : typeof fromGlobal}; ` +
|
|
1208
|
+
`it must be an object keyed by ${kind === "resources" ? "uri" : "name"}`)
|
|
1192
1209
|
}
|
|
1193
1210
|
return (legacyName && scope[legacyName]) || {}
|
|
1194
1211
|
}
|
|
1212
|
+
|
|
1213
|
+
// Getters, so each dispatch re-resolves. The call sites read
|
|
1214
|
+
// `handlers.tools` at the moment they need it, which is what makes this work.
|
|
1195
1215
|
return {
|
|
1196
1216
|
global: name,
|
|
1197
|
-
tools
|
|
1198
|
-
prompts
|
|
1199
|
-
resources
|
|
1217
|
+
get tools() { return pick("tools", legacy.tools) },
|
|
1218
|
+
get prompts() { return pick("prompts", legacy.prompts) },
|
|
1219
|
+
get resources() { return pick("resources", legacy.resources) }
|
|
1200
1220
|
}
|
|
1201
1221
|
}
|
|
1202
1222
|
|
|
@@ -1225,8 +1245,9 @@ export function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
|
1225
1245
|
if (!entry || typeof entry.type !== "string") continue
|
|
1226
1246
|
const clash = merged[kind].find((r) => r.type === entry.type && r.global !== entry.global)
|
|
1227
1247
|
if (clash) {
|
|
1228
|
-
warn(`[llm-meta-widget]
|
|
1229
|
-
`("${clash.global}" and "${entry.global}"); using
|
|
1248
|
+
warn(`[llm-meta-widget] the ${entry.type} transport is declared more than once, ` +
|
|
1249
|
+
`with different globals ("${clash.global}" and "${entry.global}"); using ` +
|
|
1250
|
+
`"${clash.global}". One block may declare it twice, or two blocks may disagree`)
|
|
1230
1251
|
continue
|
|
1231
1252
|
}
|
|
1232
1253
|
if (!merged[kind].some((r) => r.type === entry.type && r.global === entry.global)) {
|