@productbrain/mcp 0.0.1-beta.8779 → 0.0.1-beta.8789

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.
@@ -1303,8 +1303,7 @@ var GENERIC_PROFILE = {
1303
1303
  governedDraft: false,
1304
1304
  descriptionField: null,
1305
1305
  // TEN-3704 F4: never a hard-coded "description" — see resolveGenericDescriptionField
1306
- defaults: [],
1307
- recommendedRelationTypes: ["related_to", "references"]
1306
+ defaults: []
1308
1307
  };
1309
1308
  async function buildRuntimeProfile(slug, fieldsOverride) {
1310
1309
  const col = await getCollectionBySlug(slug);
@@ -1313,8 +1312,7 @@ async function buildRuntimeProfile(slug, fieldsOverride) {
1313
1312
  return {
1314
1313
  governedDraft: col.governed === true,
1315
1314
  descriptionField,
1316
- defaults: [],
1317
- recommendedRelationTypes: GENERIC_PROFILE.recommendedRelationTypes
1315
+ defaults: []
1318
1316
  };
1319
1317
  }
1320
1318
  var profileCache = new ScopedCache(COLLECTION_CACHE_TTL_MS);
@@ -1334,41 +1332,6 @@ async function getProfile(slug, fieldsOverride) {
1334
1332
  function invalidateProfileCacheForScope() {
1335
1333
  profileCache.delete(cacheScope());
1336
1334
  }
1337
- function extractSearchTerms(name, description) {
1338
- const text = `${name} ${description}`;
1339
- return text.replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 3).slice(0, 8).join(" ");
1340
- }
1341
- var hubCache = new ScopedCache(COLLECTION_CACHE_TTL_MS);
1342
- async function populateHubCache() {
1343
- const scope = cacheScope();
1344
- const hit = hubCache.get(scope);
1345
- if (hit) return hit;
1346
- const cols = await getCollections();
1347
- const set = new Set(
1348
- cols.filter((c) => c.governanceRole === "steering" || c.thinkingLayer === "strategy").map((c) => c.slug)
1349
- );
1350
- hubCache.set(scope, set);
1351
- return set;
1352
- }
1353
- function invalidateHubCacheForScope() {
1354
- hubCache.delete(cacheScope());
1355
- }
1356
- function buildScoreLinkCandidatesJob(candidates, sourceName, sourceDescription, sourceCollection) {
1357
- return {
1358
- candidates: candidates.map((c) => ({ name: c.name, collectionId: c.collectionId })),
1359
- sourceName,
1360
- sourceDescription,
1361
- sourceCollection
1362
- };
1363
- }
1364
- function inferRelationType(_sourceCollection, _targetCollection, profile) {
1365
- const type = profile.recommendedRelationTypes[0] ?? "related_to";
1366
- const reason = `profile default (${type})`;
1367
- return { type, reason };
1368
- }
1369
- var AUTO_LINK_CONFIDENCE_THRESHOLD = 35;
1370
- var MAX_AUTO_LINKS = 5;
1371
- var MAX_SUGGESTIONS = 5;
1372
1335
  var SPINE_FLOOR_SENTENCE = "kept as a draft; it can be accepted once its spine above is accepted \u2014 the promote door checks the whole spine and names the first missing rung.";
1373
1336
  var SPINE_FLOOR_EXEMPT_SENTENCE = "kept as a draft, though this workspace is not yet enforcing the spine above it \u2014 it can be accepted as-is.";
1374
1337
  var BR_STD_ENTRY_ID_REGEX = /^(BR|STD)-\d+$/;
@@ -1386,7 +1349,7 @@ var captureSchema = z4.object({
1386
1349
  links: z4.array(z4.object({
1387
1350
  to: z4.string().describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
1388
1351
  type: z4.string().describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
1389
- })).optional().describe("Relations to create after capture. Skips auto-link discovery when provided."),
1352
+ })).optional().describe("Relations to create after capture. Without links, a capture writes no relations."),
1390
1353
  sourceRef: z4.string().optional().describe("URI or path of the source document backing this entry (e.g. 'meeting-2026-03-28.md', 'import://batch-5'). Stored as top-level entry field, not in data."),
1391
1354
  sourceExcerpt: z4.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data."),
1392
1355
  // WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
@@ -1702,7 +1665,7 @@ var captureCompoundSchema = z4.object({
1702
1665
  links: z4.array(z4.object({
1703
1666
  to: z4.string().max(200).describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
1704
1667
  type: z4.string().max(200).describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
1705
- })).max(RELATION_BATCH_MAX).optional().describe("Relations to create after capture. Skips auto-link discovery when provided."),
1668
+ })).max(RELATION_BATCH_MAX).optional().describe("Relations to create after capture. Without links, a capture writes no relations."),
1706
1669
  sourceRef: z4.string().max(2e3).optional().describe("URI or path of the source document backing this entry."),
1707
1670
  sourceExcerpt: z4.string().max(SOURCE_EXCERPT_MAX_CHARS).optional().describe("Verbatim excerpt from the source backing this entry's claims."),
1708
1671
  preview: z4.boolean().optional().describe("If true, validates without writing."),
@@ -1730,14 +1693,14 @@ function registerSmartCaptureTools(server) {
1730
1693
  "capture",
1731
1694
  {
1732
1695
  title: "Capture",
1733
- description: `The tool for creating a single knowledge entry. Creates an entry, auto-links related entries, and returns a quality scorecard \u2014 all in one call. Provide a name and description; \`collection\` is optional \u2014 the classifier auto-routes when omitted. An agent capturing several atoms from one text calls this once per atom.
1696
+ description: `The tool for creating a single knowledge entry. Creates an entry and returns a quality scorecard \u2014 all in one call. Provide a name and description; \`collection\` is optional \u2014 the classifier auto-routes when omitted. An agent capturing several atoms from one text calls this once per atom.
1734
1697
 
1735
1698
  Supported collections with smart profiles: ${SMART_PROFILE_COLLECTIONS.join(", ")}.
1736
1699
  All other collections get an ENT-{random} ID and sensible defaults.
1737
1700
 
1738
1701
  **Explicit data:** When you know the schema, pass \`data: { field: value }\` to set fields directly. Top-level \`name\`/\`description\` win for those fields; \`data\` wins over inference for the rest. Governance entries also require a top-level \`why\`.
1739
1702
 
1740
- **Compound capture:** Pass \`links\` to create relations in the same call (skips auto-link discovery). Entries are always created as \`draft\` \u2014 use \`entries action=commit\` to promote when ready.`,
1703
+ **Compound capture:** Pass \`links\` to create relations in the same call; a capture writes no other relations. Entries are always created as \`draft\` \u2014 use \`entries action=commit\` to promote when ready.`,
1741
1704
  inputSchema: captureCompoundSchema,
1742
1705
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
1743
1706
  },
@@ -1916,7 +1879,6 @@ ${groundingReport.duplicates.map((d) => `- **${d.entryId}** ${d.name} [${d.colle
1916
1879
  data,
1917
1880
  entryId: "",
1918
1881
  linksCreated: [],
1919
- linksSuggested: [],
1920
1882
  collectionFields: col.fields ?? []
1921
1883
  });
1922
1884
  for (const [key, val] of Object.entries(inferred)) {
@@ -1989,9 +1951,7 @@ ${groundingReport.duplicates.map((d) => `- **${d.entryId}** ${d.name} [${d.colle
1989
1951
  // WP-475 E1 (Codex P2 — CLI parity): user links are known UPFRONT, so the
1990
1952
  // post-relations re-evaluation below owns the single LLM run — defer the
1991
1953
  // create-time LLM schedule (deterministic, mirrors `pb capture --link`).
1992
- // Auto-discovered links are unknown here: zero-user-link captures do NOT
1993
- // defer (a link-less capture must keep its LLM run); the supersession
1994
- // guard bounds the auto-link double-run race when timing allows.
1954
+ // A capture without links writes no relations (TASK-599): no defer, it keeps its LLM run.
1995
1955
  // Fail-safe: if the relations batch then creates nothing, the deferred row
1996
1956
  // keeps its delivered heuristic verdict with llmStatus 'skipped' (same
1997
1957
  // accepted shape as the CLI dying between create and re-eval).
@@ -2111,87 +2071,10 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2111
2071
  grounding_ms: groundingElapsedMs
2112
2072
  }).catch(() => void 0);
2113
2073
  const linksCreated = [];
2114
- const linksSuggested = [];
2115
2074
  const userLinkResults = [];
2116
- const advisedLinks = [];
2117
2075
  const pendingRelations = [];
2118
- const skipAutoDiscovery = links && links.length > 0;
2119
- const searchQuery = extractSearchTerms(name, description);
2120
- if (searchQuery && !skipAutoDiscovery) {
2121
- const hubSlugs = await populateHubCache();
2122
- const [searchResults, allCollections] = await Promise.all([
2123
- kernelQuery("chain.searchEntries", { query: searchQuery }),
2124
- getCollections()
2125
- ]);
2126
- const collMap = /* @__PURE__ */ new Map();
2127
- for (const c of allCollections) collMap.set(c._id, c.slug);
2128
- const candidatesFiltered = (searchResults ?? []).filter((r) => r.entryId !== finalEntryId && r._id !== internalId).map((r) => ({
2129
- name: r.name,
2130
- entryId: r.entryId,
2131
- collectionId: r.collectionId,
2132
- preview: extractPreview(r.data, 80)
2133
- }));
2134
- let scores = [];
2135
- if (candidatesFiltered.length > 0) {
2136
- try {
2137
- const scoreJobResults = await kernelQuery("chain.scoreLinkCandidates", {
2138
- collMap: Object.fromEntries(collMap),
2139
- hubSlugs: [...hubSlugs],
2140
- jobs: [
2141
- buildScoreLinkCandidatesJob(
2142
- candidatesFiltered.map((r) => ({ name: r.name, collectionId: r.collectionId })),
2143
- name,
2144
- description,
2145
- resolvedCollection
2146
- )
2147
- ]
2148
- });
2149
- scores = scoreJobResults[0] ?? [];
2150
- } catch {
2151
- }
2152
- }
2153
- const candidates = scores.map((s) => {
2154
- const r = candidatesFiltered[s.index];
2155
- return {
2156
- ...r,
2157
- collSlug: collMap.get(r.collectionId) ?? "unknown",
2158
- confidence: s.score,
2159
- confidenceReason: s.reason
2160
- };
2161
- });
2162
- let autoCount = 0;
2163
- for (const c of candidates) {
2164
- if (autoCount >= MAX_AUTO_LINKS) break;
2165
- if (c.confidence < AUTO_LINK_CONFIDENCE_THRESHOLD) break;
2166
- if (!c.entryId || !finalEntryId) continue;
2167
- const { type: relationType, reason: relationReason } = inferRelationType(resolvedCollection, c.collSlug, profile);
2168
- pendingRelations.push({
2169
- fromEntryId: finalEntryId,
2170
- toEntryId: c.entryId,
2171
- type: relationType,
2172
- // WP-474 E4-REWIRE: auto-defaulted relation (no one chose the type) — mark it
2173
- // as auto-link and carry the numeric confidence structurally.
2174
- proposedBy: "auto-link",
2175
- confidence: c.confidence,
2176
- meta: {
2177
- source: "auto",
2178
- targetName: c.name,
2179
- targetCollection: c.collSlug,
2180
- linkReason: `confidence ${c.confidence} (${c.confidenceReason}) + ${relationReason}`
2181
- }
2182
- });
2183
- autoCount++;
2184
- }
2185
- const autoTargetIds = new Set(pendingRelations.map((r) => r.toEntryId));
2186
- for (const c of candidates) {
2187
- if (linksSuggested.length >= MAX_SUGGESTIONS) break;
2188
- if (c.entryId !== void 0 && autoTargetIds.has(c.entryId)) continue;
2189
- if (c.confidence < 10) continue;
2190
- const reason = c.confidence >= AUTO_LINK_CONFIDENCE_THRESHOLD ? "high relevance (already linked)" : `"${c.name.toLowerCase().split(/\s+/).filter((w) => `${name} ${description}`.toLowerCase().includes(w) && w.length > 3).slice(0, 2).join('", "')}" appears in content`;
2191
- linksSuggested.push({ entryId: c.entryId, name: c.name, collection: c.collSlug, reason, preview: c.preview });
2192
- }
2193
- }
2194
2076
  if (links && links.length > 0 && finalEntryId) {
2077
+ const slugByPrefix = new Map((await getCollections()).filter((c) => c.idPrefix).map((c) => [c.idPrefix, c.slug]));
2195
2078
  for (const link of links) {
2196
2079
  pendingRelations.push({
2197
2080
  fromEntryId: finalEntryId,
@@ -2199,7 +2082,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2199
2082
  type: link.type,
2200
2083
  // WP-474 E4-REWIRE: user-chosen type — mark provenance, NO confidence (human-chosen).
2201
2084
  proposedBy: "user",
2202
- meta: { source: "user", targetName: link.to, targetCollection: "unknown" }
2085
+ meta: { targetName: link.to, targetCollection: slugByPrefix.get(link.to.split("-")[0]) ?? "unknown" }
2203
2086
  });
2204
2087
  }
2205
2088
  }
@@ -2207,18 +2090,17 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2207
2090
  const batchRelationsPromise = pendingRelations.length > 0 ? kernelMutation(
2208
2091
  "chain.createEntryRelations",
2209
2092
  {
2210
- // WP-474 E4-REWIRE: carry provenance + confidence through to the server seam.
2093
+ // WP-474 E4-REWIRE: carry provenance through to the server seam.
2211
2094
  relations: pendingRelations.slice(0, 25).map((r) => ({
2212
2095
  fromEntryId: r.fromEntryId,
2213
2096
  toEntryId: r.toEntryId,
2214
2097
  type: r.type,
2215
- ...r.proposedBy !== void 0 ? { proposedBy: r.proposedBy } : {},
2216
- ...r.confidence !== void 0 ? { confidence: r.confidence } : {}
2098
+ ...r.proposedBy !== void 0 ? { proposedBy: r.proposedBy } : {}
2217
2099
  })),
2218
2100
  sessionId: agentId ?? void 0
2219
2101
  }
2220
2102
  ).catch((err) => {
2221
- entryWarnings.push(`Auto-linking partially failed: ${err instanceof Error ? err.message : "unknown error"}`);
2103
+ entryWarnings.push(`Linking partially failed: ${err instanceof Error ? err.message : "unknown error"}`);
2222
2104
  return null;
2223
2105
  }) : Promise.resolve(null);
2224
2106
  const cardinalityPromise = resolvedCK ? kernelQuery("chain.checkCardinalityWarning", { canonicalKey: resolvedCK, excludeEntryId: internalId }).catch(() => null) : Promise.resolve(null);
@@ -2247,40 +2129,19 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2247
2129
  const pending = pendingRelations[i];
2248
2130
  const result2 = batchResult.results[i];
2249
2131
  if (!result2) continue;
2250
- if (pending.meta.source === "auto") {
2251
- if (result2.ok) {
2252
- linksCreated.push({
2253
- targetEntryId: pending.toEntryId,
2254
- targetName: pending.meta.targetName,
2255
- targetCollection: pending.meta.targetCollection,
2256
- relationType: pending.type,
2257
- linkReason: pending.meta.linkReason
2258
- });
2259
- } else if (result2.status === "advised") {
2260
- advisedLinks.push({
2261
- targetName: pending.meta.targetName,
2262
- targetCollection: pending.meta.targetCollection,
2263
- relationType: pending.type
2264
- });
2265
- }
2132
+ if (result2.ok) {
2133
+ userLinkResults.push({ label: `\u2713 ${pending.type} \u2192 ${pending.toEntryId}`, ok: true });
2134
+ linksCreated.push({
2135
+ targetEntryId: pending.toEntryId,
2136
+ targetName: pending.meta.targetName,
2137
+ targetCollection: pending.meta.targetCollection,
2138
+ relationType: pending.type
2139
+ });
2266
2140
  } else {
2267
- if (result2.ok) {
2268
- userLinkResults.push({ label: `\u2713 ${pending.type} \u2192 ${pending.toEntryId}`, ok: true });
2269
- linksCreated.push({
2270
- targetEntryId: pending.toEntryId,
2271
- targetName: pending.meta.targetName,
2272
- targetCollection: pending.meta.targetCollection,
2273
- relationType: pending.type
2274
- });
2275
- } else {
2276
- userLinkResults.push({ label: `\u2717 ${pending.type} \u2192 ${pending.toEntryId}: ${result2.error ?? "failed"}`, ok: false });
2277
- }
2141
+ userLinkResults.push({ label: `\u2717 ${pending.type} \u2192 ${pending.toEntryId}: ${result2.error ?? "failed"}`, ok: false });
2278
2142
  }
2279
2143
  }
2280
2144
  }
2281
- if (advisedLinks.length > 0) {
2282
- entryWarnings.push(`${advisedLinks.length} auto-link(s) advised, not written (untypeable) \u2014 accept with \`relations action=create\` to promote.`);
2283
- }
2284
2145
  const tAfterQuality = Date.now();
2285
2146
  const cardinalityWarning = cardinalityCheck?.warning ?? null;
2286
2147
  if (contradictionWarnings.length > 0) {
@@ -2358,14 +2219,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2358
2219
  lines.push("");
2359
2220
  lines.push(`**View in Cortex:** ${studioUrl}`);
2360
2221
  }
2361
- if (linksCreated.length > 0) {
2362
- lines.push("");
2363
- lines.push(`## Auto-linked (${linksCreated.length})`);
2364
- for (const link of linksCreated) {
2365
- const reason = link.linkReason ? ` \u2014 because ${link.linkReason}` : "";
2366
- lines.push(`- -> **${link.relationType}** ${link.targetEntryId}: ${link.targetName} [${link.targetCollection}]${reason}`);
2367
- }
2368
- }
2369
2222
  if (userLinkResults.length > 0) {
2370
2223
  lines.push("");
2371
2224
  lines.push("## Requested links");
@@ -2384,15 +2237,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2384
2237
  lines.push(`**${name}** ${spineFloor.exempt ? SPINE_FLOOR_EXEMPT_SENTENCE : SPINE_FLOOR_SENTENCE}`);
2385
2238
  lines.push(`Next: \`entries action=commit entryId="${finalEntryId}"\`.`);
2386
2239
  }
2387
- if (linksSuggested.length > 0) {
2388
- lines.push("");
2389
- lines.push("## Suggested links (review and use `relations action=create`)");
2390
- for (let i = 0; i < linksSuggested.length; i++) {
2391
- const s = linksSuggested[i];
2392
- const preview2 = s.preview ? ` \u2014 ${s.preview}` : "";
2393
- lines.push(`${i + 1}. **${s.entryId ?? "(no ID)"}**: ${s.name} [${s.collection}]${preview2}`);
2394
- }
2395
- }
2396
2240
  if (groundingCaveat) lines.push("", groundingCaveat);
2397
2241
  if (format === "human") {
2398
2242
  const hasDuplicates = groundingReport.duplicates.length > 0;
@@ -6389,7 +6233,6 @@ async function handleUpdate(slug, name, description, purpose, icon, navGroup, fi
6389
6233
  });
6390
6234
  invalidateCollectionCacheForScope();
6391
6235
  invalidateProfileCacheForScope();
6392
- invalidateHubCacheForScope();
6393
6236
  const changes = [name && "name", description && "description", purpose && "purpose", icon && "icon", navGroup && "navGroup", fields && "fields", meta.axis !== void 0 && "axis", meta.stageLabelMap !== void 0 && "stageLabelMap", meta.defaultCanonicalKey !== void 0 && "defaultCanonicalKey", meta.defaultWorkflowStatus !== void 0 && "defaultWorkflowStatus", meta.validWorkflowStatuses !== void 0 && "validWorkflowStatuses", meta.classificationCheck !== void 0 && "classificationCheck", meta.classificationPriority !== void 0 && "classificationPriority", meta.qualityCriteria !== void 0 && "qualityCriteria", meta.usageGuidance !== void 0 && "usageGuidance", meta.statusList !== void 0 && "statusList"].filter(Boolean).join(", ");
6394
6237
  return {
6395
6238
  content: [{
@@ -13427,8 +13270,8 @@ Tags for filtering (e.g. \`severity:high\`), relations via \`entryRelations\`, v
13427
13270
  `## Creating Knowledge
13428
13271
  **Entries:** Use \`capture\` as the primary tool for creating new entries. It handles the full workflow in one call:
13429
13272
  1. Creates the entry with collection-aware defaults (auto-fills dates, infers domains, sets priority)
13430
- 2. Auto-links related entries from across the chain (up to 5 confident matches)
13431
- 3. Returns a quality scorecard (X/10) with actionable improvement suggestions
13273
+ 2. Writes the relations you pass in \`links\` \u2014 and no others; use \`relations action=suggest\` then \`relations action=create\` to add more
13274
+ 3. Returns the server's quality verdict with improvement hints
13432
13275
 
13433
13276
  **Smart profiles** exist for: ${SMART_PROFILE_COLLECTIONS.map((c) => `\`${c}\``).join(", ")}.
13434
13277
  All other collections use the \`ENT-{random}\` fallback profile.
@@ -13444,7 +13287,7 @@ Use \`quality action=check\` to score existing entries retroactively.
13444
13287
  Use \`entries action=update\` for post-creation adjustments (status changes, field updates, deprecation).`
13445
13288
  );
13446
13289
  sections.push(
13447
- "## Where to Go Next\n- **Create entry** \u2192 `capture` tool (auto-links + quality score in one call)\n- **Full context** \u2192 `context action=gather` (by entry ID or task description)\n- **Discover links** \u2192 `relations action=suggest`\n- **Quality audit** \u2192 `quality action=check`\n- **Terminology** \u2192 `name-check` prompt or `productbrain://terminology` resource\n- **Schema details** \u2192 `productbrain://collections` resource or `collections action=list`\n- **Labels** \u2192 `productbrain://labels` resource or `collections action=label-list`\n- **Any collection** \u2192 `productbrain://{slug}/entries` resource\n- **Log a decision** \u2192 `draft-decision-record` prompt\n- **Growth funnel** \u2192 `productbrain://growth-funnel` resource or `entries action=list collection=strategy status=draft`\n- **Session identity** \u2192 `workspace action=whoami`\n- **Health check** \u2192 `workspace action=check`\n- **Debug MCP calls** \u2192 `workspace action=audit`"
13290
+ "## Where to Go Next\n- **Create entry** \u2192 `capture` tool (entry, the links you pass, and a quality verdict in one call)\n- **Full context** \u2192 `context action=gather` (by entry ID or task description)\n- **Discover links** \u2192 `relations action=suggest`\n- **Quality audit** \u2192 `quality action=check`\n- **Terminology** \u2192 `name-check` prompt or `productbrain://terminology` resource\n- **Schema details** \u2192 `productbrain://collections` resource or `collections action=list`\n- **Labels** \u2192 `productbrain://labels` resource or `collections action=label-list`\n- **Any collection** \u2192 `productbrain://{slug}/entries` resource\n- **Log a decision** \u2192 `draft-decision-record` prompt\n- **Growth funnel** \u2192 `productbrain://growth-funnel` resource or `entries action=list collection=strategy status=draft`\n- **Session identity** \u2192 `workspace action=whoami`\n- **Health check** \u2192 `workspace action=check`\n- **Debug MCP calls** \u2192 `workspace action=audit`"
13448
13291
  );
13449
13292
  return sections.join("\n\n---\n\n");
13450
13293
  }
@@ -14133,4 +13976,4 @@ export {
14133
13976
  createProductBrainServer,
14134
13977
  initFeatureFlags
14135
13978
  };
14136
- //# sourceMappingURL=chunk-USZ2527R.js.map
13979
+ //# sourceMappingURL=chunk-X2VLEDPS.js.map