@open-agent-toolkit/cli 0.2.19 → 0.2.21

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 (66) hide show
  1. package/assets/config/dispatch-matrix-recommendation.json +15 -5
  2. package/assets/docs/cli-utilities/configuration.md +10 -5
  3. package/assets/docs/contributing/index.md +1 -0
  4. package/assets/docs/contributing/verifying-cursor-pins.md +282 -0
  5. package/assets/docs/workflows/projects/artifacts.md +1 -1
  6. package/assets/docs/workflows/projects/dispatch-ceiling.md +50 -4
  7. package/assets/docs/workflows/skills/explainer-kit.md +188 -23
  8. package/assets/docs/workflows/skills/index.md +1 -1
  9. package/assets/public-package-versions.json +4 -4
  10. package/assets/skills/explainer-kit/SKILL.md +87 -25
  11. package/assets/skills/explainer-kit/briefs/deep-dive.md +35 -0
  12. package/assets/skills/explainer-kit/briefs/engineer-tour.md +45 -0
  13. package/assets/skills/explainer-kit/briefs/program-recap.md +41 -0
  14. package/assets/skills/explainer-kit/briefs/project-explainer.md +38 -0
  15. package/assets/skills/explainer-kit/briefs/project-page.md +38 -0
  16. package/assets/skills/explainer-kit/briefs/project-recap.md +47 -0
  17. package/assets/skills/explainer-kit/briefs/supporting-diagram.md +28 -0
  18. package/assets/skills/explainer-kit/briefs/walkthrough-deck.md +35 -0
  19. package/assets/skills/explainer-kit/examples/project-recap/content.md +57 -14
  20. package/assets/skills/explainer-kit/examples/project-recap/fact-base.json +104 -0
  21. package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +26 -4
  22. package/assets/skills/explainer-kit/recipes/engineer-tour.json +27 -10
  23. package/assets/skills/explainer-kit/recipes/program-recap.json +35 -11
  24. package/assets/skills/explainer-kit/recipes/project-explainer.json +27 -10
  25. package/assets/skills/explainer-kit/recipes/project-recap.json +43 -11
  26. package/assets/skills/explainer-kit/references/contracts.md +45 -19
  27. package/assets/skills/explainer-kit/schemas/author-request.v2.schema.json +41 -0
  28. package/assets/skills/explainer-kit/schemas/author-result.v2.schema.json +52 -0
  29. package/assets/skills/explainer-kit/scripts/lib/browser-runtime.mjs +442 -0
  30. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +223 -10
  31. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +28 -43
  32. package/assets/skills/explainer-kit/scripts/lib/diagram.mjs +237 -0
  33. package/assets/skills/explainer-kit/scripts/lib/html-safety.mjs +680 -0
  34. package/assets/skills/explainer-kit/scripts/lib/markdown.mjs +414 -0
  35. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +309 -10
  36. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +313 -41
  37. package/assets/skills/explainer-kit/scripts/lib/records.mjs +61 -0
  38. package/assets/skills/explainer-kit/scripts/lib/render.mjs +166 -12
  39. package/assets/skills/explainer-kit/scripts/render-qa.mjs +147 -2
  40. package/assets/skills/explainer-kit/scripts/run.mjs +796 -272
  41. package/assets/skills/explainer-kit/templates/deck-shell.html +25 -5
  42. package/assets/skills/explainer-kit/templates/diagram-shell.html +29 -7
  43. package/assets/skills/explainer-kit/templates/engineer-tour.html +133 -9
  44. package/assets/skills/explainer-kit/templates/house-style.html +82 -0
  45. package/assets/skills/oat-explainer-kit/SKILL.md +16 -9
  46. package/assets/skills/oat-explainer-kit/references/author-callback.md +51 -0
  47. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +10 -8
  48. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +14 -0
  49. package/assets/skills/oat-explainer-kit/scripts/run.mjs +7 -11
  50. package/assets/skills/oat-project-complete/SKILL.md +18 -2
  51. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  52. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +7 -1
  53. package/assets/skills/oat-wave-execute/SKILL.md +12 -19
  54. package/assets/skills/oat-wave-program/SKILL.md +12 -13
  55. package/assets/skills/subagent-orchestration/SKILL.md +1 -1
  56. package/assets/skills/subagent-orchestration/references/evidence-and-refresh.md +153 -15
  57. package/assets/skills/subagent-orchestration/references/model-selection-principles.md +75 -3
  58. package/assets/skills/subagent-orchestration/references/provider-claude.md +95 -35
  59. package/assets/skills/subagent-orchestration/references/provider-codex.md +36 -10
  60. package/assets/skills/subagent-orchestration/references/provider-cursor.md +91 -15
  61. package/dist/providers/cursor/codec/catalog.d.ts +19 -1
  62. package/dist/providers/cursor/codec/catalog.d.ts.map +1 -1
  63. package/dist/providers/cursor/codec/catalog.js +54 -0
  64. package/package.json +2 -2
  65. package/assets/skills/explainer-kit/schemas/author-request.schema.json +0 -85
  66. package/assets/skills/explainer-kit/schemas/author-result.schema.json +0 -65
@@ -1,3 +1,6 @@
1
+ import { findUnpinnedResourceRefs } from './html-safety.mjs';
2
+ import { recipeFloor, recipeRequiredNarrative } from './recipes.mjs';
3
+
1
4
  const VOID_ELEMENTS = new Set([
2
5
  'area',
3
6
  'base',
@@ -14,14 +17,148 @@ const VOID_ELEMENTS = new Set([
14
17
  'track',
15
18
  'wbr',
16
19
  ]);
17
- const EXTERNAL_ASSET_PATTERN =
18
- /<(?:script|iframe|source|img|audio|video|object|embed)\b[^>]*(?:src|data)\s*=\s*["'](?!data:)[^"']+/i;
19
20
  const INLINE_ASSET_VIOLATION_PATTERN =
20
21
  /<link\b|@import\b|url\(\s*["']?(?!data:|#)/i;
21
22
  const TOKEN_PATTERN = /{{\s*[A-Z][A-Z0-9_]*\s*}}/g;
22
23
  const ARROW_KEYS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
24
+ const INLINE_DIAGRAM_PATTERN =
25
+ /<svg\b(?=[^>]*(?:\bclass\s*=\s*["'][^"']*\bdiagram\b|\baria-label\s*=\s*["'][^"']*(?:architecture|diagram)))[^>]*>/i;
26
+ const STRUCTURED_BLOCK_PATTERNS = [
27
+ /<table\b/i,
28
+ /<(?:ul|ol)\b/i,
29
+ /<aside\b[^>]*\bclass\s*=\s*["'][^"']*\bcallout\b/i,
30
+ /<blockquote\b/i,
31
+ /<figure\b/i,
32
+ ];
23
33
 
24
34
  export const REPRESENTATIVE_WIDTHS = Object.freeze([320, 768, 1440]);
35
+ export const GUIDELINE_WARNING_IDS = Object.freeze({
36
+ narrativeCoverage: 'guideline-narrative-coverage-missing',
37
+ architectureDiagram: 'guideline-architecture-diagram-missing',
38
+ structuredDepth: 'guideline-structured-depth-missing',
39
+ expansionProfileLimit: 'expansion-profile-limit-exceeded',
40
+ expansionArtifactLimit: 'expansion-artifact-limit-exceeded',
41
+ expansionTypeLimit: 'expansion-type-limit-exceeded',
42
+ });
43
+ const EXPANSION_WARNING_BY_REJECTION_REASON = new Map([
44
+ ['profile-limit', GUIDELINE_WARNING_IDS.expansionProfileLimit],
45
+ ['recipe-limit', GUIDELINE_WARNING_IDS.expansionArtifactLimit],
46
+ ['type-limit', GUIDELINE_WARNING_IDS.expansionTypeLimit],
47
+ ]);
48
+ export const RENDER_WARNING_IDS = Object.freeze({
49
+ unsupportedDiagram: 'render-unsupported-diagram',
50
+ headingDepthJump: 'render-heading-depth-jump',
51
+ timelineEntryShape: 'render-timeline-entry-shape',
52
+ legacyRawHtmlEscaped: 'render-legacy-raw-html-escaped',
53
+ });
54
+ export const RENDER_QA_WARNING_IDS = Object.freeze({
55
+ documentOverflow: 'render-qa-document-overflow',
56
+ innerContainerOverflow: 'render-qa-inner-container-overflow',
57
+ viewportClipping: 'render-qa-viewport-clipping',
58
+ headingReadability: 'render-qa-heading-unreadable',
59
+ animationsEnabled: 'render-qa-animations-enabled',
60
+ reducedMotion: 'render-qa-reduced-motion',
61
+ keyboardNavigation: 'render-qa-keyboard-navigation',
62
+ themeToggle: 'render-qa-theme-toggle',
63
+ deckNoJsLayout: 'render-qa-deck-no-js-layout',
64
+ deckPrintLayout: 'render-qa-deck-print-layout',
65
+ skippedNoProbe: 'render-qa-skipped-no-probe',
66
+ });
67
+ const RENDER_QA_WARNING_BY_CODE = new Map([
68
+ ['viewport-overflow', RENDER_QA_WARNING_IDS.documentOverflow],
69
+ ['inner-x-overflow', RENDER_QA_WARNING_IDS.innerContainerOverflow],
70
+ ['viewport-clipping', RENDER_QA_WARNING_IDS.viewportClipping],
71
+ ['heading-readability', RENDER_QA_WARNING_IDS.headingReadability],
72
+ ['animations-enabled', RENDER_QA_WARNING_IDS.animationsEnabled],
73
+ ['reduced-motion', RENDER_QA_WARNING_IDS.reducedMotion],
74
+ ['keyboard-navigation', RENDER_QA_WARNING_IDS.keyboardNavigation],
75
+ ['theme-toggle', RENDER_QA_WARNING_IDS.themeToggle],
76
+ ['deck-no-js-layout', RENDER_QA_WARNING_IDS.deckNoJsLayout],
77
+ ['deck-print-layout', RENDER_QA_WARNING_IDS.deckPrintLayout],
78
+ ]);
79
+
80
+ export function renderQaWarningIds(issues) {
81
+ if (!Array.isArray(issues)) {
82
+ throw new TypeError('Render QA issues must be an array.');
83
+ }
84
+ return [
85
+ ...new Set(
86
+ issues
87
+ .map(({ code }) => RENDER_QA_WARNING_BY_CODE.get(code))
88
+ .filter(Boolean),
89
+ ),
90
+ ];
91
+ }
92
+
93
+ // Degradation findings are prefixed rather than looked up so a newly added
94
+ // render warning code surfaces instead of being silently dropped.
95
+ export function renderWarningIds(warnings) {
96
+ if (!Array.isArray(warnings)) {
97
+ throw new TypeError('Render warnings must be an array.');
98
+ }
99
+ if (warnings.some(({ code } = {}) => typeof code !== 'string' || !code)) {
100
+ throw new TypeError('Every render warning requires a string code.');
101
+ }
102
+ return [...new Set(warnings.map(({ code }) => `render-${code}`))];
103
+ }
104
+
105
+ export function checkGuidelines({ recipe, artifacts, expansion } = {}) {
106
+ if (!Array.isArray(artifacts)) {
107
+ throw new TypeError('Guideline checker artifacts must be an array.');
108
+ }
109
+ if (
110
+ artifacts.some(
111
+ (artifact) =>
112
+ !isPlainObject(artifact) ||
113
+ typeof artifactId(artifact) !== 'string' ||
114
+ typeof artifact.type !== 'string' ||
115
+ typeof artifact.html !== 'string',
116
+ )
117
+ ) {
118
+ throw new TypeError(
119
+ 'Guideline checker artifacts require id, type, and HTML.',
120
+ );
121
+ }
122
+
123
+ const floor = recipeFloor(recipe);
124
+ const builtById = new Map(
125
+ artifacts.map((artifact) => [artifactId(artifact), artifact]),
126
+ );
127
+ const narrativeFloor = floor.filter(
128
+ (artifact) => recipeRequiredNarrative(recipe, artifact.id).length > 0,
129
+ );
130
+ const warnings = new Set();
131
+
132
+ const missesNarrative = narrativeFloor.some((floorArtifact) => {
133
+ const built = builtById.get(floorArtifact.id);
134
+ const required = recipeRequiredNarrative(recipe, floorArtifact.id);
135
+ return (
136
+ !built ||
137
+ required.some((sectionId) => !hasElementId(built.html, sectionId))
138
+ );
139
+ });
140
+ if (missesNarrative) {
141
+ warnings.add(GUIDELINE_WARNING_IDS.narrativeCoverage);
142
+ }
143
+
144
+ const hasDiagram =
145
+ artifacts.some(({ type }) => type === 'diagram') ||
146
+ artifacts.some(({ html }) => INLINE_DIAGRAM_PATTERN.test(html));
147
+ if (!hasDiagram) {
148
+ warnings.add(GUIDELINE_WARNING_IDS.architectureDiagram);
149
+ }
150
+
151
+ const hasStructuredDepth = narrativeFloor.some((floorArtifact) => {
152
+ const html = builtById.get(floorArtifact.id)?.html ?? '';
153
+ return STRUCTURED_BLOCK_PATTERNS.some((pattern) => pattern.test(html));
154
+ });
155
+ if (narrativeFloor.length > 0 && !hasStructuredDepth) {
156
+ warnings.add(GUIDELINE_WARNING_IDS.structuredDepth);
157
+ }
158
+
159
+ addExpansionWarnings(warnings, expansion);
160
+ return { valid: true, warnings: [...warnings] };
161
+ }
25
162
 
26
163
  export function checkSourceDumping({
27
164
  authoredText,
@@ -81,24 +218,111 @@ function shingles(value, size) {
81
218
 
82
219
  export const BROWSER_PROBE_EVALUATE = `(() => {
83
220
  const root = document.documentElement;
84
- const clippedX = [...document.querySelectorAll('body *')]
221
+ const elements = [...document.querySelectorAll('body *')];
222
+ const selector = (element) => element.id ? '#' + CSS.escape(element.id) :
223
+ element.classList.length ? '.' + [...element.classList].map(CSS.escape).join('.') :
224
+ element.tagName.toLowerCase();
225
+ const clippedX = elements
85
226
  .filter((element) => {
86
227
  const style = getComputedStyle(element);
87
228
  return element.scrollWidth > element.clientWidth + 2 &&
88
229
  ['hidden', 'clip'].includes(style.overflowX);
89
230
  })
90
231
  .map((element) => ({
91
- selector: element.id ? '#' + CSS.escape(element.id) :
92
- element.classList.length ? '.' + [...element.classList].map(CSS.escape).join('.') :
93
- element.tagName.toLowerCase(),
232
+ selector: selector(element),
94
233
  overflowX: getComputedStyle(element).overflowX,
95
234
  clientWidth: element.clientWidth,
96
235
  scrollWidth: element.scrollWidth
97
236
  }))
98
237
  .slice(0, 20);
238
+ // Ancestry inside a horizontal scroller is not reachability: scrollLeft only
239
+ // ranges over 0..scrollWidth-clientWidth, so content sitting at a negative
240
+ // content offset or past the scrollable extent can never be scrolled into
241
+ // view and stays a genuine clipping defect.
242
+ const TOLERANCE = 2;
243
+ const scrollReachable = (element) => {
244
+ const rect = element.getBoundingClientRect();
245
+ for (let node = element.parentElement; node; node = node.parentElement) {
246
+ const style = getComputedStyle(node);
247
+ if (!['auto', 'scroll'].includes(style.overflowX)) continue;
248
+ if (node.scrollWidth - node.clientWidth <= TOLERANCE) continue;
249
+ const nodeRect = node.getBoundingClientRect();
250
+ const contentLeft =
251
+ rect.left - (nodeRect.left + node.clientLeft) + node.scrollLeft;
252
+ if (contentLeft >= -TOLERANCE &&
253
+ contentLeft + rect.width <= node.scrollWidth + TOLERANCE) return true;
254
+ }
255
+ return false;
256
+ };
257
+ const viewportClipped = elements
258
+ .filter((element) => {
259
+ const rect = element.getBoundingClientRect();
260
+ return rect.width > 0 && rect.height > 0 &&
261
+ (rect.left < -TOLERANCE || rect.right > innerWidth + TOLERANCE) &&
262
+ !scrollReachable(element);
263
+ })
264
+ .map((element) => {
265
+ const rect = element.getBoundingClientRect();
266
+ return {
267
+ selector: selector(element),
268
+ left: rect.left,
269
+ right: rect.right,
270
+ viewportWidth: innerWidth
271
+ };
272
+ })
273
+ .slice(0, 20);
274
+ // A heading in a collapsed panel or an aria-hidden subtree is deliberately
275
+ // not presented, so it is out of scope rather than unreadable. Visually
276
+ // hidden accessibility text still renders a box and stays in scope.
277
+ const presented = (element) => {
278
+ const rendered = typeof element.checkVisibility === 'function'
279
+ ? element.checkVisibility({
280
+ visibilityProperty: true,
281
+ contentVisibilityAuto: true
282
+ })
283
+ : element.getClientRects().length > 0;
284
+ return rendered && element.closest('[aria-hidden="true"]') === null;
285
+ };
286
+ const unreadableHeadings = [...document.querySelectorAll('h1,h2,h3,h4,h5,h6')]
287
+ .filter(presented)
288
+ .filter((heading) => {
289
+ const style = getComputedStyle(heading);
290
+ const rect = heading.getBoundingClientRect();
291
+ const fontSize = Number.parseFloat(style.fontSize);
292
+ return !heading.textContent.trim() || rect.width <= 0 || rect.height <= 0 ||
293
+ !Number.isFinite(fontSize) || fontSize < 12;
294
+ })
295
+ .map((heading) => ({
296
+ selector: selector(heading),
297
+ text: heading.textContent.trim(),
298
+ fontSize: Number.parseFloat(getComputedStyle(heading).fontSize)
299
+ }))
300
+ .slice(0, 20);
301
+ // Reduced-motion styling conventionally collapses transitions to a token
302
+ // 0.01ms rather than 0s so transitionend still fires. That is suppressed
303
+ // motion, not active motion, so anything under a millisecond counts as
304
+ // disabled while a perceptible duration still reports.
305
+ // Motion is just as visible on a generated ::before/::after box as on the
306
+ // element itself, so all three are inspected. A pseudo-element that
307
+ // generates no content cannot animate and is skipped.
308
+ const PERCEPTIBLE_SECONDS = 0.001;
309
+ const motionless = (element, pseudo) => {
310
+ const style = getComputedStyle(element, pseudo);
311
+ if (pseudo && ['none', 'normal'].includes(style.content)) return true;
312
+ const durations = (style.animationDuration + ',' + style.transitionDuration)
313
+ .split(',')
314
+ .map((value) => Number.parseFloat(value) || 0);
315
+ return style.animationName === 'none' &&
316
+ durations.every((value) => value < PERCEPTIBLE_SECONDS);
317
+ };
318
+ const animationsDisabled = elements.every((element) =>
319
+ [null, '::before', '::after'].every((pseudo) => motionless(element, pseudo)));
99
320
  return {
100
321
  pageOverflowX: root.scrollWidth > root.clientWidth + 2,
101
322
  clippedX,
323
+ viewportClipped,
324
+ unreadableHeadings,
325
+ animationsDisabled,
102
326
  reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,
103
327
  deckLayout: document.querySelector('.deck') ? {
104
328
  flow: getComputedStyle(document.querySelector('.deck')).display === 'block' ?
@@ -150,13 +374,12 @@ export function checkHtmlStructure({
150
374
  }
151
375
  }
152
376
 
153
- if (
154
- EXTERNAL_ASSET_PATTERN.test(html) ||
155
- INLINE_ASSET_VIOLATION_PATTERN.test(html)
156
- ) {
377
+ const unpinnedRefs = findUnpinnedResourceRefs(html);
378
+ if (unpinnedRefs.length > 0 || INLINE_ASSET_VIOLATION_PATTERN.test(html)) {
157
379
  add(
158
380
  'external-asset',
159
381
  'Final HTML assets must be inline and self-contained.',
382
+ ...(unpinnedRefs.length > 0 ? [{ refs: unpinnedRefs.slice(0, 10) }] : []),
160
383
  );
161
384
  }
162
385
 
@@ -269,6 +492,9 @@ export async function runBrowserProbes({
269
492
  scenario,
270
493
  viewport: { width, height: representativeHeight(width) },
271
494
  reducedMotion: 'reduce',
495
+ disableAnimations: true,
496
+ injectedCss:
497
+ '*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}',
272
498
  evaluate: BROWSER_PROBE_EVALUATE,
273
499
  keyboard:
274
500
  artifact.type === 'deck' && scenario === 'default'
@@ -314,6 +540,30 @@ export async function runBrowserProbes({
314
540
  details: result.clippedX,
315
541
  });
316
542
  }
543
+ if ((result.viewportClipped ?? []).length > 0) {
544
+ issues.push({
545
+ ...context,
546
+ code: 'viewport-clipping',
547
+ message: 'Rendered content is clipped outside the viewport.',
548
+ details: result.viewportClipped,
549
+ });
550
+ }
551
+ if ((result.unreadableHeadings ?? []).length > 0) {
552
+ issues.push({
553
+ ...context,
554
+ code: 'heading-readability',
555
+ message: 'A heading is not visibly readable.',
556
+ details: result.unreadableHeadings,
557
+ });
558
+ }
559
+ if (result.animationsDisabled === false) {
560
+ issues.push({
561
+ ...context,
562
+ code: 'animations-enabled',
563
+ message:
564
+ 'Render QA observed active animation or transition timing.',
565
+ });
566
+ }
317
567
  if (!result.reducedMotion) {
318
568
  issues.push({
319
569
  ...context,
@@ -532,6 +782,18 @@ function validateProbeResult(result, artifactId, width, request) {
532
782
  `Browser probe for ${artifactId} at ${width}px returned an invalid result.`,
533
783
  );
534
784
  }
785
+ if (
786
+ (result.viewportClipped !== undefined &&
787
+ !Array.isArray(result.viewportClipped)) ||
788
+ (result.unreadableHeadings !== undefined &&
789
+ !Array.isArray(result.unreadableHeadings)) ||
790
+ (result.animationsDisabled !== undefined &&
791
+ typeof result.animationsDisabled !== 'boolean')
792
+ ) {
793
+ throw new TypeError(
794
+ `Browser layout probe for ${artifactId} at ${width}px returned an invalid result.`,
795
+ );
796
+ }
535
797
  if (request.themeToggle && !isPlainObject(result.themeToggle)) {
536
798
  throw new TypeError(
537
799
  `Browser theme probe for ${artifactId} at ${width}px returned an invalid result.`,
@@ -563,6 +825,43 @@ function representativeHeight(width) {
563
825
  return 900;
564
826
  }
565
827
 
828
+ function artifactId(artifact) {
829
+ return artifact?.id ?? artifact?.artifactId;
830
+ }
831
+
832
+ function hasElementId(html, id) {
833
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
834
+ return new RegExp(`\\bid\\s*=\\s*["']${escaped}["']`, 'i').test(html);
835
+ }
836
+
837
+ function addExpansionWarnings(warnings, expansion) {
838
+ if (expansion === undefined) return;
839
+ if (
840
+ !isPlainObject(expansion) ||
841
+ !Array.isArray(expansion.errors) ||
842
+ !Array.isArray(expansion.rejected) ||
843
+ !Array.isArray(expansion.warnings)
844
+ ) {
845
+ throw new TypeError(
846
+ 'Guideline checker expansion must be an evaluated proposal result.',
847
+ );
848
+ }
849
+ if (expansion.valid !== true || expansion.errors.length > 0) {
850
+ throw new TypeError(
851
+ 'Guideline checker cannot convert expansion proposal errors into warnings.',
852
+ );
853
+ }
854
+
855
+ const knownWarnings = new Set(EXPANSION_WARNING_BY_REJECTION_REASON.values());
856
+ for (const warning of expansion.warnings) {
857
+ if (knownWarnings.has(warning)) warnings.add(warning);
858
+ }
859
+ for (const rejected of expansion.rejected) {
860
+ const warning = EXPANSION_WARNING_BY_REJECTION_REASON.get(rejected?.reason);
861
+ if (warning) warnings.add(warning);
862
+ }
863
+ }
864
+
566
865
  function isPlainObject(value) {
567
866
  return typeof value === 'object' && value !== null && !Array.isArray(value);
568
867
  }