@fenglimg/fabric-shared 2.2.0-rc.1 → 2.2.0-rc.3

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.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  normalizeLocale,
9
9
  resolveFabricLocale,
10
10
  zhCNMessages
11
- } from "./chunk-7TZ2PMVH.js";
11
+ } from "./chunk-QSD4PN4W.js";
12
12
  import {
13
13
  FabExtractKnowledgeInputSchema,
14
14
  FabExtractKnowledgeInputShape,
@@ -56,7 +56,7 @@ import {
56
56
  recallInputSchema,
57
57
  recallOutputSchema,
58
58
  structuredWarningSchema
59
- } from "./chunk-JEXTOQVV.js";
59
+ } from "./chunk-355LUDLW.js";
60
60
  import {
61
61
  BOOTSTRAP_CANONICAL,
62
62
  BOOTSTRAP_MARKER_BEGIN,
@@ -65,7 +65,7 @@ import {
65
65
  LEGACY_KB_MARKER_BEGIN,
66
66
  LEGACY_KB_MARKER_END,
67
67
  LEGACY_KB_REGEX
68
- } from "./chunk-TX2XZ7AW.js";
68
+ } from "./chunk-AFT7DB4P.js";
69
69
 
70
70
  // src/schemas/agents-meta.ts
71
71
  import { z } from "zod";
@@ -601,6 +601,30 @@ var fabricConfigSchema = z6.object({
601
601
  // high-contract-criticality projects. Other strategies (time-based,
602
602
  // token-budget) deferred to rc.35 per plan locked-decisions 2026-05-26.
603
603
  cite_evict_interval: z6.number().int().min(0).optional().default(0),
604
+ // v2.1 ⑤ cite-redesign (P5): recall-based cite-accounting hook config. The
605
+ // rc.34 cite_evict_interval turn-counter above is superseded by the
606
+ // PreToolUse(Edit/Write) recall-aware nudge in cite-policy-evict.cjs; the old
607
+ // key is retained for back-compat (inert now that the hook moved off
608
+ // UserPromptSubmit). `cite_recall_nudge` is the master switch (default true =
609
+ // ON); set false to silence the "改前先 fab_recall" nudge entirely (mirrors
610
+ // the cite_evict_interval=0 opt-out convention). `cite_recall_window_minutes`
611
+ // bounds how far back an in-session fab_recall counts as "informing" the edit
612
+ // (default 30; 0 = unbounded).
613
+ cite_recall_nudge: z6.boolean().optional().default(true),
614
+ cite_recall_window_minutes: z6.number().int().min(0).optional().default(30),
615
+ // F2: glob exemptions for the cite nudge (cite-policy-evict.cjs). Edit paths
616
+ // matching any glob skip the "改前先 fab_recall" nudge — meta/orchestration
617
+ // files (e.g. `.workflow/` scratchpads) are not source the cite policy
618
+ // governs. MERGED with the hook's built-in [".workflow/**"] default; an
619
+ // omitted/empty value keeps just that default. `*` = within a path segment,
620
+ // `**` = across segments.
621
+ cite_nudge_ignore_globs: z6.array(z6.string()).optional(),
622
+ // v2.1 ④ conflict-detection (P4): bm25 content-similarity threshold (0..1)
623
+ // for the knowledge-conflict lint (`fabric doctor --lint-conflicts`). A
624
+ // same-(type,layer) pair whose normalized bm25 similarity reaches this floor
625
+ // is surfaced as a candidate (possible duplicate OR conflict). Conservative
626
+ // default 0.5 — raise to reduce noise, lower to catch looser pairs.
627
+ conflict_lint_similarity_threshold: z6.number().min(0).max(1).optional().default(0.5),
604
628
  // v2.0.0-rc.22 Scope A T3: sliding-window retention (in days) for the
605
629
  // event ledger rotation primitive (`rotateEventLedgerIfNeeded`). Lines
606
630
  // whose `ts` is older than `now - fabric_event_retention_days * 86_400_000`
@@ -703,13 +727,25 @@ var fabricConfigSchema = z6.object({
703
727
  // 0..168 (one week).
704
728
  hint_narrow_cooldown_hours: z6.number().int().min(0).max(168).optional().default(0),
705
729
  // v2.0.0-rc.33 W4-B3 (T5 P2): per-maturity inactivity thresholds (days)
706
- // driving orphan_demote. Hardcoded at stable=90/endorsed=30/draft=14 in
730
+ // driving orphan_demote. Hardcoded at proven=90/verified=30/draft=14 in
707
731
  // rc.32; chatty workspaces want them tighter, slow ones want them looser.
708
732
  // Each field optional; absent → defaults inside doctor.ts apply. Ranges
709
733
  // chosen so a typo can't accidentally disable the lint (min 1).
734
+ //
735
+ // v2.2 W3-T5 (F-MATURITY-ENDORSED): the canonical maturity enum is
736
+ // draft/verified/proven (KT-DEC-0005), but these threshold keys historically
737
+ // used the legacy stable/endorsed vocabulary — a config authored with the
738
+ // canonical names could never tune the proven/verified tiers. The canonical
739
+ // keys below are the preferred form; the legacy keys are retained for
740
+ // backward-compat (a config written before this fix keeps working). The
741
+ // loader maps stable→proven / endorsed→verified, canonical taking precedence.
742
+ orphan_demote_proven_days: z6.number().int().min(1).max(3650).optional(),
743
+ orphan_demote_verified_days: z6.number().int().min(1).max(3650).optional(),
744
+ orphan_demote_draft_days: z6.number().int().min(1).max(3650).optional(),
745
+ // Legacy aliases (deprecated; map to proven/verified). Kept so existing
746
+ // configs do not silently lose their tuning.
710
747
  orphan_demote_stable_days: z6.number().int().min(1).max(3650).optional(),
711
748
  orphan_demote_endorsed_days: z6.number().int().min(1).max(3650).optional(),
712
- orphan_demote_draft_days: z6.number().int().min(1).max(3650).optional(),
713
749
  // v2.0.0-rc.33 W4-A3 (T4 P2): per-entry summary truncation length used by
714
750
  // knowledge-hint-{broad,narrow}.cjs. Hard-coded at 80 chars in rc.32 — too
715
751
  // short for entries with parameterized summaries (e.g. "Use bcrypt with
@@ -766,7 +802,25 @@ var fabricConfigSchema = z6.object({
766
802
  // ENFORCES the "vectors supplement, never override lexical relevance"
767
803
  // invariant in the schema rather than leaving it to a comment (W2-REVIEW codex
768
804
  // MED-4). Range 0..49; default 30.
769
- embed_weight: z6.number().int().min(0).max(49).optional().default(30)
805
+ embed_weight: z6.number().int().min(0).max(49).optional().default(30),
806
+ // v2.1 ③ vector-chinese-model (P3): which fastembed model to load. The prior
807
+ // code pinned fastembed's English default (bge-small-en-v1.5) — wrong for the
808
+ // Chinese-heavy zh-CN-hybrid KB. Values are the fastembed@2.x EmbeddingModel
809
+ // enum strings. Default `fast-bge-small-zh-v1.5` (BGESmallZH): light, fast,
810
+ // Chinese-capable (bm25 already covers English/code tokens; the vector term
811
+ // supplements Chinese semantics). `fast-multilingual-e5-large` (MLE5Large) is
812
+ // available for full multilingual recall at a ~1GB download + slower CPU cost.
813
+ // (V1 research: fastembed@2.1.0 has NO multilingual-e5-SMALL — the originally
814
+ // planned pin — so bge-small-zh is the light Chinese choice.)
815
+ embed_model: z6.enum([
816
+ "fast-bge-small-zh-v1.5",
817
+ "fast-multilingual-e5-large",
818
+ "fast-bge-small-en-v1.5",
819
+ "fast-bge-small-en",
820
+ "fast-bge-base-en-v1.5",
821
+ "fast-bge-base-en",
822
+ "fast-all-MiniLM-L6-v2"
823
+ ]).optional().default("fast-bge-small-zh-v1.5")
770
824
  });
771
825
 
772
826
  // src/schemas/fabric-config-introspect.ts
@@ -1503,6 +1557,76 @@ function aggregatePendingAcrossStores(stores) {
1503
1557
  );
1504
1558
  }
1505
1559
 
1560
+ // src/store/global-config-io.ts
1561
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1562
+ import { homedir } from "os";
1563
+ import { join as join3 } from "path";
1564
+ function resolveGlobalRoot() {
1565
+ return join3(process.env.FABRIC_HOME ?? homedir(), ".fabric");
1566
+ }
1567
+ function globalConfigPath(globalRoot = resolveGlobalRoot()) {
1568
+ return join3(globalRoot, "fabric-global.json");
1569
+ }
1570
+ function loadGlobalConfig(globalRoot = resolveGlobalRoot()) {
1571
+ const path = globalConfigPath(globalRoot);
1572
+ if (!existsSync3(path)) {
1573
+ return null;
1574
+ }
1575
+ return globalConfigSchema.parse(JSON.parse(readFileSync2(path, "utf8")));
1576
+ }
1577
+ function saveGlobalConfig(config, globalRoot = resolveGlobalRoot()) {
1578
+ const validated = globalConfigSchema.parse(config);
1579
+ mkdirSync2(globalRoot, { recursive: true });
1580
+ writeFileSync2(globalConfigPath(globalRoot), `${JSON.stringify(validated, null, 2)}
1581
+ `, "utf8");
1582
+ }
1583
+
1584
+ // src/store/project-config-io.ts
1585
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1586
+ import { join as join4 } from "path";
1587
+ function projectConfigPath(projectRoot) {
1588
+ return join4(projectRoot, ".fabric", "fabric-config.json");
1589
+ }
1590
+ function loadProjectConfig(projectRoot) {
1591
+ const path = projectConfigPath(projectRoot);
1592
+ if (!existsSync4(path)) {
1593
+ return null;
1594
+ }
1595
+ return fabricConfigSchema.parse(JSON.parse(readFileSync3(path, "utf8")));
1596
+ }
1597
+ function saveProjectConfig(config, projectRoot) {
1598
+ const validated = fabricConfigSchema.parse(config);
1599
+ mkdirSync3(join4(projectRoot, ".fabric"), { recursive: true });
1600
+ writeFileSync3(projectConfigPath(projectRoot), `${JSON.stringify(validated, null, 2)}
1601
+ `, "utf8");
1602
+ }
1603
+
1604
+ // src/store/resolve-input.ts
1605
+ function buildStoreResolveInput(projectRoot, globalRoot = resolveGlobalRoot()) {
1606
+ const global = loadGlobalConfig(globalRoot);
1607
+ if (global === null) {
1608
+ return null;
1609
+ }
1610
+ const project = loadProjectConfig(projectRoot);
1611
+ return {
1612
+ uid: global.uid,
1613
+ mountedStores: global.stores.map((s) => ({
1614
+ store_uuid: s.store_uuid,
1615
+ alias: s.alias,
1616
+ ...s.remote === void 0 ? {} : { remote: s.remote },
1617
+ writable: s.writable ?? true,
1618
+ personal: s.personal ?? false
1619
+ })),
1620
+ requiredStores: (project?.required_stores ?? []).map(
1621
+ (r) => ({
1622
+ id: r.id,
1623
+ ...r.suggested_remote === void 0 ? {} : { suggested_remote: r.suggested_remote }
1624
+ })
1625
+ ),
1626
+ ...project?.active_write_store === void 0 ? {} : { activeWriteAlias: project.active_write_store }
1627
+ };
1628
+ }
1629
+
1506
1630
  // src/store/secret-scan.ts
1507
1631
  var SECRET_RULES = [
1508
1632
  { rule: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/ },
@@ -1540,6 +1664,10 @@ function redactSecrets(content) {
1540
1664
  return out;
1541
1665
  }
1542
1666
  function scrubRemoteUrl(remote) {
1667
+ const httpStripped = remote.replace(/^(https?:\/\/)[^/@]+@/i, "$1");
1668
+ if (httpStripped !== remote) {
1669
+ return httpStripped;
1670
+ }
1543
1671
  return remote.replace(
1544
1672
  /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)[^/@]*:[^/@]*@/,
1545
1673
  "$1"
@@ -1719,10 +1847,24 @@ var resolvedBindingsSnapshotSchema = z14.object({
1719
1847
  }).strict();
1720
1848
 
1721
1849
  // src/store/bindings.ts
1722
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1723
- import { join as join3 } from "path";
1850
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
1851
+ import { join as join5, resolve, sep } from "path";
1852
+ var SAFE_PROJECT_ID = /^[A-Za-z0-9._-]+$/;
1853
+ function assertSafeProjectId(projectId) {
1854
+ if (!SAFE_PROJECT_ID.test(projectId) || projectId.includes("..")) {
1855
+ throw new Error(
1856
+ `bindingsSnapshotPath: refusing unsafe project_id ${JSON.stringify(projectId)} (must match ${SAFE_PROJECT_ID} and contain no "..")`
1857
+ );
1858
+ }
1859
+ }
1724
1860
  function bindingsSnapshotPath(globalRoot, projectId) {
1725
- return join3(globalRoot, GLOBAL_STATE_DIR, GLOBAL_BINDINGS_DIR, `${projectId}_resolved.json`);
1861
+ assertSafeProjectId(projectId);
1862
+ const bindingsDir = resolve(join5(globalRoot, GLOBAL_STATE_DIR, GLOBAL_BINDINGS_DIR));
1863
+ const path = resolve(join5(bindingsDir, `${projectId}_resolved.json`));
1864
+ if (path !== bindingsDir && !path.startsWith(bindingsDir + sep)) {
1865
+ throw new Error(`bindingsSnapshotPath: resolved path escapes bindings dir for ${JSON.stringify(projectId)}`);
1866
+ }
1867
+ return path;
1726
1868
  }
1727
1869
  function writeBindingsSnapshot(options) {
1728
1870
  const resolver = createStoreResolver();
@@ -1736,18 +1878,18 @@ function writeBindingsSnapshot(options) {
1736
1878
  write_target: target
1737
1879
  });
1738
1880
  const path = bindingsSnapshotPath(options.globalRoot, options.projectId);
1739
- mkdirSync2(join3(path, ".."), { recursive: true });
1740
- writeFileSync2(path, `${JSON.stringify(snapshot, null, 2)}
1881
+ mkdirSync4(join5(path, ".."), { recursive: true });
1882
+ writeFileSync4(path, `${JSON.stringify(snapshot, null, 2)}
1741
1883
  `, "utf8");
1742
1884
  return snapshot;
1743
1885
  }
1744
1886
  function readBindingsSnapshot(globalRoot, projectId) {
1745
1887
  const path = bindingsSnapshotPath(globalRoot, projectId);
1746
- if (!existsSync3(path)) {
1888
+ if (!existsSync5(path)) {
1747
1889
  return null;
1748
1890
  }
1749
1891
  try {
1750
- const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(readFileSync2(path, "utf8")));
1892
+ const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(readFileSync4(path, "utf8")));
1751
1893
  return parsed.success ? parsed.data : null;
1752
1894
  } catch {
1753
1895
  return null;
@@ -2438,6 +2580,15 @@ var assistantTurnObservedEventSchema = z18.object({
2438
2580
  skip_reason: z18.string().nullable()
2439
2581
  })
2440
2582
  ).default([]),
2583
+ // lifecycle-refactor W3-T4 (§2 store 轴 / store-qualified 观测): per-cite store
2584
+ // qualifier, index-aligned with cite_ids. Mirrors the cite-line-parser's
2585
+ // `cite_stores` output (`<alias-or-uuid>:<id>` → the qualifier; a bare id →
2586
+ // null). Persists the store provenance the parser already extracts so
2587
+ // doctor --cite-coverage can break compliance down per store WITHOUT joining
2588
+ // against the store registry. Additive `.optional()` (NOT `.default([])`) so
2589
+ // existing inline event constructors stay valid without supplying it — pre-W3-T4
2590
+ // events parse with the field absent and bucket under the project-local default.
2591
+ cite_stores: z18.array(z18.string().nullable()).optional(),
2441
2592
  client: z18.enum(["cc", "codex", "cursor"]).optional(),
2442
2593
  turn_id: z18.string(),
2443
2594
  envelope_index: z18.number().int().nonnegative().optional(),
@@ -2580,6 +2731,29 @@ var clientCapabilitySnapshotEventSchema = z18.object({
2580
2731
  capabilities: z18.array(z18.string()),
2581
2732
  version: z18.string()
2582
2733
  });
2734
+ var sessionEndedEventSchema = z18.object({
2735
+ ...eventLedgerEnvelopeSchema,
2736
+ event_type: z18.literal("session_ended")
2737
+ });
2738
+ var fileMutatedEventSchema = z18.object({
2739
+ ...eventLedgerEnvelopeSchema,
2740
+ event_type: z18.literal("file_mutated"),
2741
+ path: z18.string(),
2742
+ tool_call_id: z18.string(),
2743
+ tool_name: z18.string().optional(),
2744
+ source_event_id: z18.string().optional(),
2745
+ store_id: z18.string().optional()
2746
+ });
2747
+ var precompactObservedEventSchema = z18.object({
2748
+ ...eventLedgerEnvelopeSchema,
2749
+ event_type: z18.literal("precompact_observed")
2750
+ });
2751
+ var graphEdgeCandidateRequestedEventSchema = z18.object({
2752
+ ...eventLedgerEnvelopeSchema,
2753
+ event_type: z18.literal("graph_edge_candidate_requested"),
2754
+ stable_id: z18.string(),
2755
+ store: z18.string().optional()
2756
+ });
2583
2757
  var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
2584
2758
  knowledgeContextPlannedEventSchema,
2585
2759
  knowledgeSelectionEventSchema,
@@ -2672,7 +2846,12 @@ var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
2672
2846
  skillPhaseTransitionEventSchema,
2673
2847
  skillTriggerCandidateEventSchema,
2674
2848
  llmJudgeRunEventSchema,
2675
- clientCapabilitySnapshotEventSchema
2849
+ clientCapabilitySnapshotEventSchema,
2850
+ // lifecycle-refactor Wave 2 — dormant-hook activation markers.
2851
+ sessionEndedEventSchema,
2852
+ fileMutatedEventSchema,
2853
+ precompactObservedEventSchema,
2854
+ graphEdgeCandidateRequestedEventSchema
2676
2855
  ]);
2677
2856
 
2678
2857
  // src/text-tokenize.ts
@@ -2813,6 +2992,7 @@ export {
2813
2992
  buildDebugBundle,
2814
2993
  buildFailureTrace,
2815
2994
  buildScanRecommendations,
2995
+ buildStoreResolveInput,
2816
2996
  candidateFileEntrySchema,
2817
2997
  citeContractMetricsSchema,
2818
2998
  citeContractPolicyActivatedEventSchema,
@@ -2850,6 +3030,7 @@ export {
2850
3030
  fabricConfigSchema,
2851
3031
  fabricEventSchema,
2852
3032
  fabricLanguageSchema,
3033
+ fileMutatedEventSchema,
2853
3034
  findMountedStore,
2854
3035
  findStoreExecutableViolations,
2855
3036
  forensicAssertionCoverageSchema,
@@ -2866,8 +3047,10 @@ export {
2866
3047
  formatKnowledgeId,
2867
3048
  getPanelFieldByKey,
2868
3049
  getPanelFields,
3050
+ globalConfigPath,
2869
3051
  globalConfigSchema,
2870
3052
  globalRefSchema,
3053
+ graphEdgeCandidateRequestedEventSchema,
2871
3054
  hasSecrets,
2872
3055
  historyStateQuerySchema,
2873
3056
  hookSignalEmittedEventSchema,
@@ -2926,6 +3109,8 @@ export {
2926
3109
  lintCrossStoreReferences,
2927
3110
  listStoreKnowledge,
2928
3111
  llmJudgeRunEventSchema,
3112
+ loadGlobalConfig,
3113
+ loadProjectConfig,
2929
3114
  localKnowledgeIdSchema,
2930
3115
  lockApprovedEventSchema,
2931
3116
  lockDriftEventSchema,
@@ -2956,6 +3141,8 @@ export {
2956
3141
  planContextInputSchema,
2957
3142
  planContextOutputSchema,
2958
3143
  planContextTopKSchema,
3144
+ precompactObservedEventSchema,
3145
+ projectConfigPath,
2959
3146
  projectRootGoldenCaseSchema,
2960
3147
  projectRootGoldenFileSchema,
2961
3148
  projectRootResolutionSchema,
@@ -2977,12 +3164,15 @@ export {
2977
3164
  requiredStoreEntrySchema,
2978
3165
  resolveCandidates,
2979
3166
  resolveFabricLocale,
3167
+ resolveGlobalRoot,
2980
3168
  resolveRetrievalBudget,
2981
3169
  resolveStoreQualifiedId,
2982
3170
  resolvedBindingsSnapshotSchema,
2983
3171
  retrievalBudgetProfile,
2984
3172
  ruleDescriptionIndexItemSchema,
2985
3173
  ruleDescriptionSchema,
3174
+ saveGlobalConfig,
3175
+ saveProjectConfig,
2986
3176
  scanForSecrets,
2987
3177
  scopeCoordinateSchema,
2988
3178
  scopeRoot,
@@ -2990,6 +3180,7 @@ export {
2990
3180
  selectionTokenTtlMsSchema,
2991
3181
  serveLockClearedEventSchema,
2992
3182
  sessionArchiveAttemptedEventSchema,
3183
+ sessionEndedEventSchema,
2993
3184
  skillInvocationCompletedEventSchema,
2994
3185
  skillInvocationStartedEventSchema,
2995
3186
  skillPhaseTransitionEventSchema,
@@ -1,6 +1,7 @@
1
1
  // src/node/atomic-write.ts
2
- import { appendFile, mkdir, open, rename, stat, unlink, writeFile } from "fs/promises";
2
+ import { appendFile, mkdir, open, readFile, rename, stat, unlink, writeFile } from "fs/promises";
3
3
  import { dirname } from "path";
4
+ import { randomUUID } from "crypto";
4
5
  function makeTmpSuffix() {
5
6
  const rand = Math.floor(Math.random() * 65535).toString(16).padStart(4, "0");
6
7
  return `.${process.pid}.${Date.now()}.${rand}.tmp`;
@@ -44,6 +45,7 @@ async function withFileLock(lockPath, fn, opts = {}) {
44
45
  const retryDelayMs = opts.retryDelayMs ?? 20;
45
46
  const maxWaitMs = opts.maxWaitMs ?? 1e4;
46
47
  await mkdir(dirname(lockPath), { recursive: true });
48
+ const token = `${process.pid}.${randomUUID()}`;
47
49
  const start = Date.now();
48
50
  for (; ; ) {
49
51
  let handle;
@@ -54,7 +56,10 @@ async function withFileLock(lockPath, fn, opts = {}) {
54
56
  try {
55
57
  const st = await stat(lockPath);
56
58
  if (Date.now() - st.mtimeMs > staleMs) {
57
- await unlink(lockPath).catch(() => void 0);
59
+ const staleToken = await readFile(lockPath, "utf8").catch(() => null);
60
+ if (staleToken !== null) {
61
+ await unlinkIfToken(lockPath, staleToken);
62
+ }
58
63
  continue;
59
64
  }
60
65
  } catch {
@@ -67,11 +72,21 @@ async function withFileLock(lockPath, fn, opts = {}) {
67
72
  continue;
68
73
  }
69
74
  try {
75
+ await handle.writeFile(token, "utf8");
70
76
  await handle.close();
71
77
  return await fn();
72
78
  } finally {
79
+ await unlinkIfToken(lockPath, token);
80
+ }
81
+ }
82
+ }
83
+ async function unlinkIfToken(lockPath, expected) {
84
+ try {
85
+ const current = await readFile(lockPath, "utf8");
86
+ if (current === expected) {
73
87
  await unlink(lockPath).catch(() => void 0);
74
88
  }
89
+ } catch {
75
90
  }
76
91
  }
77
92
  function createLedgerWriteQueue() {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MCPError
3
- } from "../chunk-3SZRB42B.js";
3
+ } from "../chunk-VW5QGPIN.js";
4
4
 
5
5
  // src/node/mcp-payload-guard.ts
6
6
  var McpPayloadTooLargeError = class extends MCPError {