@skill-map/cli 0.22.0 → 0.23.1

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.
@@ -100,7 +100,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
100
100
  // package.json
101
101
  var package_default = {
102
102
  name: "@skill-map/cli",
103
- version: "0.22.0",
103
+ version: "0.23.1",
104
104
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
105
105
  license: "MIT",
106
106
  type: "module",
@@ -167,16 +167,16 @@ var package_default = {
167
167
  },
168
168
  dependencies: {
169
169
  "@hono/node-server": "2.0.1",
170
- "@skill-map/spec": "0.22.0",
170
+ "@skill-map/spec": "0.23.0",
171
171
  ajv: "8.18.0",
172
172
  "ajv-formats": "3.0.1",
173
173
  chokidar: "5.0.0",
174
174
  clipanion: "4.0.0-rc.4",
175
- hono: "4.12.16",
175
+ hono: "4.12.18",
176
176
  ignore: "7.0.5",
177
177
  "js-tiktoken": "1.0.21",
178
178
  "js-yaml": "4.1.1",
179
- kysely: "0.28.16",
179
+ kysely: "0.28.17",
180
180
  semver: "7.7.4",
181
181
  typanion: "3.14.0",
182
182
  ws: "8.20.0"
@@ -271,8 +271,8 @@ import { Ajv2020 as Ajv20202 } from "ajv/dist/2020.js";
271
271
 
272
272
  // kernel/i18n/plugin-store.texts.ts
273
273
  var PLUGIN_STORE_TEXTS = {
274
- kvValidationFailed: "plugin '{{pluginId}}' ctx.store.set('{{key}}', value): value violates declared schema ({{schemaPath}}) \u2014 {{errors}}",
275
- dedicatedValidationFailed: "plugin '{{pluginId}}' ctx.store.write('{{table}}', row): row violates declared schema ({{schemaPath}}) \u2014 {{errors}}"
274
+ kvValidationFailed: "plugin '{{pluginId}}' ctx.store.set('{{key}}', value): value violates declared schema ({{schemaPath}}): {{errors}}",
275
+ dedicatedValidationFailed: "plugin '{{pluginId}}' ctx.store.write('{{table}}', row): row violates declared schema ({{schemaPath}}): {{errors}}"
276
276
  };
277
277
 
278
278
  // kernel/adapters/plugin-store.ts
@@ -360,6 +360,27 @@ import { readFileSync as readFileSync3 } from "fs";
360
360
  import { dirname, resolve as resolve4 } from "path";
361
361
  import { createRequire as createRequire2 } from "module";
362
362
  import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
363
+
364
+ // kernel/types/view-catalog.ts
365
+ var ALL_SLOT_NAMES = [
366
+ "card.title.right",
367
+ "card.subtitle.left",
368
+ "card.footer.left",
369
+ "card.footer.right",
370
+ "graph.node.alert",
371
+ "inspector.header.badge.counter",
372
+ "inspector.header.badge.tag",
373
+ "inspector.body.panel.breakdown",
374
+ "inspector.body.panel.records",
375
+ "inspector.body.panel.tree",
376
+ "inspector.body.panel.key-values",
377
+ "inspector.body.panel.link-list",
378
+ "inspector.body.panel.markdown",
379
+ "topbar.nav.start"
380
+ ];
381
+ var KNOWN_SLOT_NAMES = new Set(ALL_SLOT_NAMES);
382
+
383
+ // kernel/adapters/schema-validators.ts
363
384
  var SCHEMA_FILES = {
364
385
  node: "schemas/node.schema.json",
365
386
  link: "schemas/link.schema.json",
@@ -427,24 +448,8 @@ function buildSchemaValidators() {
427
448
  });
428
449
  const contributionValidators = /* @__PURE__ */ new Map();
429
450
  const VIEW_SLOTS_ID = "https://skill-map.dev/spec/v0/view-slots.schema.json";
430
- const KNOWN_SLOTS = /* @__PURE__ */ new Set([
431
- "card.title.right",
432
- "card.subtitle.left",
433
- "card.footer.left",
434
- "card.footer.right",
435
- "graph.node.alert",
436
- "inspector.header.badge.counter",
437
- "inspector.header.badge.tag",
438
- "inspector.body.panel.breakdown",
439
- "inspector.body.panel.records",
440
- "inspector.body.panel.tree",
441
- "inspector.body.panel.key-values",
442
- "inspector.body.panel.link-list",
443
- "inspector.body.panel.markdown",
444
- "topbar.nav.start"
445
- ]);
446
451
  function getContributionValidator(slot) {
447
- if (!KNOWN_SLOTS.has(slot)) return null;
452
+ if (!KNOWN_SLOT_NAMES.has(slot)) return null;
448
453
  const existing = contributionValidators.get(slot);
449
454
  if (existing) return existing;
450
455
  const ref = `${VIEW_SLOTS_ID}#/$defs/payloads/${slot}`;
@@ -542,7 +547,7 @@ function resolveSpecRoot() {
542
547
  return dirname(indexPath);
543
548
  } catch {
544
549
  throw new Error(
545
- "@skill-map/spec not resolvable \u2014 ensure the workspace is linked or the package is installed."
550
+ "@skill-map/spec not resolvable: ensure the workspace is linked or the package is installed."
546
551
  );
547
552
  }
548
553
  }
@@ -675,13 +680,14 @@ function buildHookContext(_hook, trigger, event) {
675
680
  // kernel/i18n/orchestrator.texts.ts
676
681
  var ORCHESTRATOR_TEXTS = {
677
682
  frontmatterInvalid: "Frontmatter for {{path}} ({{kind}}) failed schema validation: {{errors}}",
678
- frontmatterMalformedPasteWithIndent: "Frontmatter fence in {{path}} appears indented; YAML frontmatter MUST start with `---` at column 0. The file was scanned as body-only \u2014 the metadata block was silently lost. Move the `---` lines to the start of the line.",
683
+ frontmatterMalformedPasteWithIndent: "Frontmatter fence in {{path}} appears indented; YAML frontmatter MUST start with `---` at column 0. The file was scanned as body-only; the metadata block was silently lost. Move the `---` lines to the start of the line.",
679
684
  frontmatterMalformedByteOrderMark: "Frontmatter fence in {{path}} is preceded by a UTF-8 byte-order mark (BOM); the file was scanned as body-only. Re-save the file as UTF-8 without BOM. The metadata block was silently lost.",
680
- frontmatterMalformedMissingClose: "Frontmatter in {{path}} opens with `---` but never closes \u2014 no matching `---` line at column 0 was found. The file was scanned as body-only and every metadata field was silently lost. Add a closing `---` line below the metadata block.",
685
+ frontmatterMalformedMissingClose: "Frontmatter in {{path}} opens with `---` but never closes (no matching `---` line at column 0 was found). The file was scanned as body-only and every metadata field was silently lost. Add a closing `---` line below the metadata block.",
681
686
  extensionErrorLinkKindNotDeclared: 'Extractor "{{extractorId}}" emitted a link of kind "{{linkKind}}" outside its declared `emitsLinkKinds` set [{{declaredKinds}}]. Link dropped.',
682
687
  extensionErrorIssueInvalidSeverity: `Rule "{{analyzerId}}" emitted an issue with invalid severity {{severity}} (allowed: 'error' | 'warn' | 'info'). Issue dropped.`,
683
688
  extensionErrorContributionUnknownId: 'Extractor "{{extractorId}}" emitted contribution "{{contributionId}}" on {{nodePath}} but did not declare it in its `viewContributions` map. Contribution dropped.',
684
689
  extensionErrorContributionPayloadInvalid: 'Extractor "{{extractorId}}" emitted contribution "{{contributionId}}" on {{nodePath}}; payload failed the "{{slot}}" schema: {{errors}}. Contribution dropped.',
690
+ extensionErrorRecommendedActionMissing: 'Analyzer "{{analyzerId}}" declares recommendedAction "{{actionId}}" but no Action is registered under that qualified id. The analyzer stays registered; the recommendation will not surface in the inspector.',
685
691
  runScanRootEmptyArray: "runScan: roots must contain at least one path (spec requires minItems: 1)",
686
692
  runScanRootMissing: "runScan: root path '{{root}}' does not exist or is not a directory"
687
693
  };
@@ -870,10 +876,11 @@ function isExternalUrlLink(link) {
870
876
  }
871
877
 
872
878
  // kernel/orchestrator/analyzers.ts
873
- async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, emitter, hookDispatcher) {
879
+ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher) {
874
880
  const issues = [];
875
881
  const contributions = [];
876
882
  const validators = loadSchemaValidators();
883
+ validateRecommendedActions(analyzers, registeredActionIds, emitter);
877
884
  const analyzerOrphans = orphanSidecars.map((o) => ({
878
885
  relativePath: o.relativePath,
879
886
  expectedMdPath: o.expectedMdPath
@@ -945,6 +952,27 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
945
952
  }
946
953
  return { issues, contributions };
947
954
  }
955
+ function validateRecommendedActions(analyzers, registeredActionIds, emitter) {
956
+ for (const analyzer of analyzers) {
957
+ const refs = analyzer.recommendedActions;
958
+ if (refs === void 0 || refs.length === 0) continue;
959
+ const analyzerId = qualifiedExtensionId(analyzer.pluginId, analyzer.id);
960
+ for (const actionId of refs) {
961
+ if (registeredActionIds.has(actionId)) continue;
962
+ emitter.emit(
963
+ makeEvent("extension.error", {
964
+ kind: "recommended-action-missing",
965
+ extensionId: analyzerId,
966
+ actionId,
967
+ message: tx(ORCHESTRATOR_TEXTS.extensionErrorRecommendedActionMissing, {
968
+ analyzerId,
969
+ actionId
970
+ })
971
+ })
972
+ );
973
+ }
974
+ }
975
+ }
948
976
  function validateIssue(analyzer, issue, emitter) {
949
977
  const severity = issue.severity;
950
978
  if (severity !== "error" && severity !== "warn" && severity !== "info") {
@@ -994,9 +1022,20 @@ function indexPriorLinks(links, priorNodePaths, byOriginating) {
994
1022
  else byOriginating.set(key, [link]);
995
1023
  }
996
1024
  }
1025
+ var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
1026
+ "frontmatter-invalid",
1027
+ "frontmatter-malformed",
1028
+ // Audit L1: parser parse-error is emitted by
1029
+ // `buildFreshNodeAndValidateFrontmatter` from `raw.parseIssues`. The
1030
+ // raw.parseIssues only flows through the non-cache path; a cached
1031
+ // node skips the rebuild, so the prior issue MUST survive the
1032
+ // incremental scan or the warning silently disappears on a clean
1033
+ // re-scan of an unchanged file.
1034
+ "frontmatter-parse-error"
1035
+ ]);
997
1036
  function indexPriorFrontmatterIssues(issues, byNode) {
998
1037
  for (const issue of issues) {
999
- if (issue.analyzerId !== "frontmatter-invalid" && issue.analyzerId !== "frontmatter-malformed") continue;
1038
+ if (!FRONTMATTER_ISSUE_ANALYZERS.has(issue.analyzerId)) continue;
1000
1039
  if (issue.nodeIds.length !== 1) continue;
1001
1040
  const path = issue.nodeIds[0];
1002
1041
  const list = byNode.get(path);
@@ -1195,7 +1234,7 @@ function flagAmbiguousRenames(opts) {
1195
1234
  analyzerId: "auto-rename-ambiguous",
1196
1235
  severity: "warn",
1197
1236
  nodeIds: [toPath],
1198
- message: `Auto-rename ambiguous: ${toPath} matches ${remaining.length} prior frontmatters \u2014 pick one with \`sm orphans undo-rename ${toPath} --from <old.path>\`.`,
1237
+ message: `Auto-rename ambiguous: ${toPath} matches ${remaining.length} prior frontmatters; pick one with \`sm orphans undo-rename ${toPath} --from <old.path>\`.`,
1199
1238
  data: { to: toPath, candidates: remaining }
1200
1239
  });
1201
1240
  }
@@ -1252,7 +1291,7 @@ function detectRenamesAndOrphans(prior, current, issues) {
1252
1291
  }
1253
1292
 
1254
1293
  // kernel/scan/walk-content.ts
1255
- import { readFile, readdir, stat } from "fs/promises";
1294
+ import { readFile, readdir, lstat } from "fs/promises";
1256
1295
  import { join as join2, relative as relative2, sep } from "path";
1257
1296
 
1258
1297
  // kernel/scan/ignore.ts
@@ -1310,8 +1349,30 @@ function readDefaultsFromDisk() {
1310
1349
 
1311
1350
  // built-in-plugins/parsers/frontmatter-yaml/index.ts
1312
1351
  import yaml from "js-yaml";
1352
+
1353
+ // kernel/util/strip-prototype-pollution.ts
1354
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
1355
+ "__proto__",
1356
+ "constructor",
1357
+ "prototype"
1358
+ ]);
1359
+ function stripPrototypePollution(value) {
1360
+ return strip(value);
1361
+ }
1362
+ function strip(value) {
1363
+ if (value === null || value === void 0) return value;
1364
+ if (typeof value !== "object") return value;
1365
+ if (Array.isArray(value)) return value.map(strip);
1366
+ const out = {};
1367
+ for (const [k, v] of Object.entries(value)) {
1368
+ if (FORBIDDEN_KEYS.has(k)) continue;
1369
+ out[k] = strip(v);
1370
+ }
1371
+ return out;
1372
+ }
1373
+
1374
+ // built-in-plugins/parsers/frontmatter-yaml/index.ts
1313
1375
  var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
1314
- var FORBIDDEN_FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1315
1376
  var frontmatterYamlParser = {
1316
1377
  id: "frontmatter-yaml",
1317
1378
  parse(raw, _path) {
@@ -1319,20 +1380,30 @@ var frontmatterYamlParser = {
1319
1380
  if (!match) return { frontmatterRaw: "", frontmatter: {}, body: raw };
1320
1381
  const frontmatterRaw = match[1];
1321
1382
  const body = match[2];
1322
- const parsed = {};
1383
+ let parsed = {};
1384
+ const issues = [];
1323
1385
  try {
1324
1386
  const doc = yaml.load(frontmatterRaw, { schema: yaml.JSON_SCHEMA });
1325
1387
  if (doc && typeof doc === "object" && !Array.isArray(doc)) {
1326
- for (const [k, v] of Object.entries(doc)) {
1327
- if (FORBIDDEN_FRONTMATTER_KEYS.has(k)) continue;
1328
- parsed[k] = v;
1329
- }
1388
+ parsed = stripPrototypePollution(doc);
1330
1389
  }
1331
- } catch {
1390
+ } catch (err) {
1391
+ issues.push({
1392
+ code: "frontmatter-parse-error",
1393
+ message: sanitiseParseErrorMessage(err)
1394
+ });
1332
1395
  }
1333
- return { frontmatterRaw, frontmatter: parsed, body };
1396
+ const out = { frontmatterRaw, frontmatter: parsed, body };
1397
+ if (issues.length > 0) {
1398
+ return { ...out, issues };
1399
+ }
1400
+ return out;
1334
1401
  }
1335
1402
  };
1403
+ function sanitiseParseErrorMessage(err) {
1404
+ const raw = err instanceof Error ? err.message : String(err);
1405
+ return raw.replace(/[-]+/g, " ").replace(/\s+/g, " ").trim();
1406
+ }
1336
1407
 
1337
1408
  // built-in-plugins/parsers/plain/index.ts
1338
1409
  var plainParser = {
@@ -1378,7 +1449,12 @@ async function* walkContent(roots, options) {
1378
1449
  path: relPath,
1379
1450
  body: parsed.body,
1380
1451
  frontmatterRaw: parsed.frontmatterRaw,
1381
- frontmatter: parsed.frontmatter
1452
+ frontmatter: parsed.frontmatter,
1453
+ // Audit L1: forward parser diagnostics (e.g. malformed YAML)
1454
+ // through the IRawNode surface so the orchestrator can
1455
+ // convert them into warn-level kernel `Issue` rows. Omitted
1456
+ // when the parser reported no issues (happy path).
1457
+ ...parsed.issues && parsed.issues.length > 0 ? { parseIssues: parsed.issues } : {}
1382
1458
  };
1383
1459
  }
1384
1460
  }
@@ -1400,7 +1476,7 @@ async function* walkRoot(root, current, filter, extensions) {
1400
1476
  yield* walkRoot(root, full, filter, extensions);
1401
1477
  } else if (entry.isFile() && hasMatchingExtension(name, extensions)) {
1402
1478
  try {
1403
- const s = await stat(full);
1479
+ const s = await lstat(full);
1404
1480
  if (s.isFile()) yield full;
1405
1481
  } catch {
1406
1482
  }
@@ -1466,6 +1542,7 @@ function readSidecarFor(mdAbsolutePath) {
1466
1542
  issues: [{ message: `malformed YAML in ${sidecarPath}: ${err.message}` }]
1467
1543
  };
1468
1544
  }
1545
+ parsedYaml = stripPrototypePollution(parsedYaml);
1469
1546
  if (!isPlainObject(parsedYaml)) {
1470
1547
  return {
1471
1548
  parsed: null,
@@ -1531,7 +1608,7 @@ function resolveSpecRoot2() {
1531
1608
  return dirname3(indexPath);
1532
1609
  } catch {
1533
1610
  throw new Error(
1534
- "@skill-map/spec not resolvable \u2014 sidecar reader cannot load schemas."
1611
+ "@skill-map/spec not resolvable: sidecar reader cannot load schemas."
1535
1612
  );
1536
1613
  }
1537
1614
  }
@@ -1588,17 +1665,32 @@ function safeIsFile(path) {
1588
1665
  }
1589
1666
 
1590
1667
  // kernel/sidecar/store.ts
1591
- import { existsSync as existsSync7, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
1668
+ import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
1592
1669
  import { dirname as dirname5, resolve as resolve9 } from "path";
1593
1670
  import { createRequire as createRequire4 } from "module";
1594
1671
  import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
1595
1672
  import yaml3 from "js-yaml";
1596
1673
 
1674
+ // core/config/atomic-write.ts
1675
+ import {
1676
+ closeSync,
1677
+ constants as fsConstants,
1678
+ existsSync as existsSync5,
1679
+ mkdirSync,
1680
+ openSync,
1681
+ readFileSync as readFileSync6,
1682
+ renameSync,
1683
+ unlinkSync,
1684
+ writeSync
1685
+ } from "fs";
1686
+ import { randomBytes } from "crypto";
1687
+ import { dirname as dirname4 } from "path";
1688
+
1597
1689
  // core/config/helper.ts
1598
1690
  import { isAbsolute as isAbsolute2, resolve as resolve8 } from "path";
1599
1691
 
1600
1692
  // kernel/config/loader.ts
1601
- import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
1693
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
1602
1694
 
1603
1695
  // kernel/util/skill-map-paths.ts
1604
1696
  import { join as join5 } from "path";
@@ -1614,17 +1706,6 @@ var GITIGNORE_ENTRIES = [
1614
1706
  `${SKILL_MAP_DIR}/${DB_FILENAME}`
1615
1707
  ];
1616
1708
 
1617
- // core/config/atomic-write.ts
1618
- import {
1619
- existsSync as existsSync6,
1620
- mkdirSync,
1621
- readFileSync as readFileSync7,
1622
- renameSync,
1623
- unlinkSync,
1624
- writeFileSync
1625
- } from "fs";
1626
- import { dirname as dirname4 } from "path";
1627
-
1628
1709
  // kernel/orchestrator/node-build.ts
1629
1710
  import { createHash } from "crypto";
1630
1711
  import { existsSync as existsSync8 } from "fs";
@@ -1773,11 +1854,11 @@ function resolveSidecarOverlay(relativePath, nodePathForIssue, roots, liveBodyHa
1773
1854
  liveFrontmatterHash
1774
1855
  });
1775
1856
  return {
1776
- // R15 closure (2026-05-07) surface the full parsed root on the
1857
+ // R15 closure (2026-05-07), surface the full parsed root on the
1777
1858
  // overlay so BFF consumers (UI inspector audit / plugin-contributions
1778
1859
  // / debug panels) can read `for.*`, `audit.*`, `settings.*`, and
1779
1860
  // plugin-namespaced sub-keys without re-reading the file. The
1780
- // `annotations` field above stays it duplicates `root.annotations`
1861
+ // `annotations` field above stays, it duplicates `root.annotations`
1781
1862
  // by design so existing consumers keep working unchanged.
1782
1863
  overlay: {
1783
1864
  present: true,
@@ -1821,6 +1902,16 @@ function buildFreshNodeAndValidateFrontmatter(opts) {
1821
1902
  encoder: opts.encoder
1822
1903
  });
1823
1904
  const frontmatterIssues = [];
1905
+ if (opts.raw.parseIssues && opts.raw.parseIssues.length > 0) {
1906
+ for (const pi of opts.raw.parseIssues) {
1907
+ frontmatterIssues.push({
1908
+ analyzerId: pi.code,
1909
+ severity: opts.strict ? "error" : "warn",
1910
+ nodeIds: [opts.raw.path],
1911
+ message: pi.message
1912
+ });
1913
+ }
1914
+ }
1824
1915
  if (opts.raw.frontmatterRaw.length > 0) {
1825
1916
  const fmIssue = validateFrontmatter(
1826
1917
  opts.providerFrontmatter,
@@ -1847,10 +1938,9 @@ function mergeNodeWithEnrichments(node, enrichments, opts = {}) {
1847
1938
  }
1848
1939
  return base;
1849
1940
  }
1850
- var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1851
1941
  function assignSafe(target, source) {
1852
- for (const [k, v] of Object.entries(source)) {
1853
- if (FORBIDDEN_MERGE_KEYS.has(k)) continue;
1942
+ const safe = stripPrototypePollution(source);
1943
+ for (const [k, v] of Object.entries(safe)) {
1854
1944
  target[k] = v;
1855
1945
  }
1856
1946
  }
@@ -2129,6 +2219,9 @@ async function runScanInternal(_kernel, options) {
2129
2219
  recomputeLinkCounts(walked.nodes, walked.internalLinks);
2130
2220
  recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
2131
2221
  await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
2222
+ const registeredActionIds = new Set(
2223
+ _kernel.registry.all("action").map((a) => qualifiedExtensionId(a.pluginId, a.id))
2224
+ );
2132
2225
  const analyzerResult = await runAnalyzers(
2133
2226
  exts.analyzers,
2134
2227
  walked.nodes,
@@ -2140,6 +2233,7 @@ async function runScanInternal(_kernel, options) {
2140
2233
  options.orphanJobFiles ?? [],
2141
2234
  options.referenceablePaths,
2142
2235
  options.cwd,
2236
+ registeredActionIds,
2143
2237
  emitter,
2144
2238
  hookDispatcher
2145
2239
  );
@@ -2261,7 +2355,8 @@ function createChokidarWatcher(opts) {
2261
2355
  const watcher = chokidar.watch(absRoots, {
2262
2356
  ignoreInitial: true,
2263
2357
  persistent: true,
2264
- ...ignored ? { ignored } : {}
2358
+ ...ignored ? { ignored } : {},
2359
+ ...opts.depth !== void 0 ? { depth: opts.depth } : {}
2265
2360
  });
2266
2361
  let pending = [];
2267
2362
  let timer = null;