daftari 1.19.0 → 1.20.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.
@@ -646,6 +646,425 @@ export async function vaultDeprecate(vaultRoot, args, access) {
646
646
  });
647
647
  }
648
648
  // ---------------------------------------------------------------------------
649
+ // vault_set_confidence (§11.4)
650
+ // ---------------------------------------------------------------------------
651
+ // Changes only a document's `confidence`, leaving status and body untouched.
652
+ // A narrow tool so a calibration nudge never rides a full-document overwrite.
653
+ // A reason is mandatory — a confidence change is a claim about the document's
654
+ // trustworthiness and earns an audit trail.
655
+ export async function vaultSetConfidence(vaultRoot, args, access) {
656
+ const ready = requireIndexReady();
657
+ if (!ready.ok)
658
+ return ready;
659
+ const path = requireString(args, "path", "vault_set_confidence");
660
+ if (!path.ok)
661
+ return path;
662
+ const agent = requireString(args, "agent", "vault_set_confidence");
663
+ if (!agent.ok)
664
+ return agent;
665
+ const reason = requireString(args, "reason", "vault_set_confidence");
666
+ if (!reason.ok)
667
+ return reason;
668
+ const confidence = requireString(args, "confidence", "vault_set_confidence");
669
+ if (!confidence.ok)
670
+ return confidence;
671
+ if (!CONFIDENCES.includes(confidence.value)) {
672
+ return err(new Error(`vault_set_confidence: 'confidence' must be one of: ${CONFIDENCES.join(", ")}`));
673
+ }
674
+ const baseVersion = readBaseVersion(args, "vault_set_confidence");
675
+ if (!baseVersion.ok)
676
+ return baseVersion;
677
+ const resolved = resolveVaultPath(vaultRoot, path.value);
678
+ if (!resolved.ok)
679
+ return resolved;
680
+ const existing = await readFile(resolved.value);
681
+ if (!existing.ok) {
682
+ return err(new Error(`vault_set_confidence: document not found: ${path.value}`));
683
+ }
684
+ const parsed = parseDocument(existing.value);
685
+ if (!parsed.ok)
686
+ return parsed;
687
+ const config = loadConfig(vaultRoot);
688
+ if (!config.ok)
689
+ return config;
690
+ const extensions = config.value.schemaExtensions;
691
+ const oldFrontmatter = parsed.value.frontmatter;
692
+ if (access) {
693
+ const collection = collectionOf(path.value, oldFrontmatter);
694
+ if (!canWrite(access.role, collection)) {
695
+ return err(new Error(`access denied: role '${access.roleName}' cannot write to ` +
696
+ `collection '${collection}'`));
697
+ }
698
+ }
699
+ // No-op guard: a confidence already at the target would churn a commit for no
700
+ // change. Surface it as an error so a redundant staged confidence-up does not
701
+ // silently no-op (and a caller learns the value was already set). Compare
702
+ // against the *raw* on-disk value, not the validated frontmatter — the
703
+ // validator defaults a missing confidence to "low", so comparing the
704
+ // validated value would wrongly reject set_confidence(…, "low") on a doc that
705
+ // never declared one and never write the field (the trap vault_promote dodges
706
+ // the same way, via parsed.value.raw.confidence).
707
+ const rawConfidence = parsed.value.raw.confidence;
708
+ const currentConfidence = typeof rawConfidence === "string" && CONFIDENCES.includes(rawConfidence)
709
+ ? rawConfidence
710
+ : undefined;
711
+ if (currentConfidence === confidence.value) {
712
+ return err(new Error(`vault_set_confidence: ${path.value} confidence is already '${confidence.value}'`));
713
+ }
714
+ const newFrontmatter = {
715
+ ...oldFrontmatter,
716
+ confidence: confidence.value,
717
+ updated: todayISO(),
718
+ updated_by: agent.value,
719
+ };
720
+ return performWrite({
721
+ vaultRoot,
722
+ relPath: path.value,
723
+ absPath: resolved.value,
724
+ agent: agent.value,
725
+ tool: "vault_set_confidence",
726
+ action: "confidence-set",
727
+ fileText: serializeDocument(newFrontmatter, parsed.value.content, extensions, parsed.value.raw),
728
+ newFrontmatter,
729
+ oldFrontmatter,
730
+ validation: parsed.value.validation,
731
+ commitMessage: `vault_set_confidence: ${path.value} ${oldFrontmatter.confidence}→${confidence.value} ` +
732
+ `by ${agent.value} — ${reason.value}`,
733
+ autoCommit: config.value.autoCommit,
734
+ baseVersion: baseVersion.value,
735
+ });
736
+ }
737
+ // ---------------------------------------------------------------------------
738
+ // vault_supersede (§11.4)
739
+ // ---------------------------------------------------------------------------
740
+ // Marks a document explicitly superseded by a named successor. Distinct from
741
+ // vault_deprecate: deprecate sets status="deprecated" with an *optional*
742
+ // successor; supersede sets status="superseded" and *requires* a successor that
743
+ // must already exist. Permissive on source status in v1 (last-write-wins).
744
+ export async function vaultSupersede(vaultRoot, args, access) {
745
+ const ready = requireIndexReady();
746
+ if (!ready.ok)
747
+ return ready;
748
+ const oldPath = requireString(args, "old_path", "vault_supersede");
749
+ if (!oldPath.ok)
750
+ return oldPath;
751
+ const newPath = requireString(args, "new_path", "vault_supersede");
752
+ if (!newPath.ok)
753
+ return newPath;
754
+ const agent = requireString(args, "agent", "vault_supersede");
755
+ if (!agent.ok)
756
+ return agent;
757
+ const baseVersion = readBaseVersion(args, "vault_supersede");
758
+ if (!baseVersion.ok)
759
+ return baseVersion;
760
+ let reason;
761
+ if (args.reason !== undefined && args.reason !== null) {
762
+ if (typeof args.reason !== "string") {
763
+ return err(new Error("vault_supersede: 'reason' must be a string"));
764
+ }
765
+ const trimmed = args.reason.trim();
766
+ if (trimmed.length > 0)
767
+ reason = trimmed;
768
+ }
769
+ if (oldPath.value === newPath.value) {
770
+ return err(new Error("vault_supersede: a document cannot supersede itself"));
771
+ }
772
+ const resolvedOld = resolveVaultPath(vaultRoot, oldPath.value);
773
+ if (!resolvedOld.ok)
774
+ return resolvedOld;
775
+ const resolvedNew = resolveVaultPath(vaultRoot, newPath.value);
776
+ if (!resolvedNew.ok)
777
+ return resolvedNew;
778
+ const existing = await readFile(resolvedOld.value);
779
+ if (!existing.ok) {
780
+ return err(new Error(`vault_supersede: document not found: ${oldPath.value}`));
781
+ }
782
+ // The successor must be a real document — superseded_by must never dangle.
783
+ const successor = await readFile(resolvedNew.value);
784
+ if (!successor.ok) {
785
+ return err(new Error(`vault_supersede: successor not found: ${newPath.value}`));
786
+ }
787
+ const parsed = parseDocument(existing.value);
788
+ if (!parsed.ok)
789
+ return parsed;
790
+ const config = loadConfig(vaultRoot);
791
+ if (!config.ok)
792
+ return config;
793
+ const extensions = config.value.schemaExtensions;
794
+ const oldFrontmatter = parsed.value.frontmatter;
795
+ if (access) {
796
+ const collection = collectionOf(oldPath.value, oldFrontmatter);
797
+ if (!canWrite(access.role, collection)) {
798
+ return err(new Error(`access denied: role '${access.roleName}' cannot write to ` +
799
+ `collection '${collection}'`));
800
+ }
801
+ }
802
+ const newFrontmatter = {
803
+ ...oldFrontmatter,
804
+ status: "superseded",
805
+ superseded_by: newPath.value,
806
+ updated: todayISO(),
807
+ updated_by: agent.value,
808
+ };
809
+ return performWrite({
810
+ vaultRoot,
811
+ relPath: oldPath.value,
812
+ absPath: resolvedOld.value,
813
+ agent: agent.value,
814
+ tool: "vault_supersede",
815
+ action: "supersede",
816
+ fileText: serializeDocument(newFrontmatter, parsed.value.content, extensions, parsed.value.raw),
817
+ newFrontmatter,
818
+ oldFrontmatter,
819
+ validation: parsed.value.validation,
820
+ commitMessage: `vault_supersede: ${oldPath.value} superseded by ${newPath.value} ` +
821
+ `by ${agent.value}${reason ? ` — ${reason}` : ""}`,
822
+ autoCommit: config.value.autoCommit,
823
+ baseVersion: baseVersion.value,
824
+ });
825
+ }
826
+ // Combines two source documents into a target and supersedes both sources to
827
+ // point at it. Mechanical, not generative: the merged body is supplied by the
828
+ // caller (a human at ratification, or the loop) — vault_merge never synthesizes
829
+ // prose (that would be an LLM call; the write layer is LLM-free).
830
+ //
831
+ // Unlike the single-file write tools this touches up to three files, so it does
832
+ // not use performWrite. It mirrors the backfill apply pattern: write each file,
833
+ // index each, then one git commit for the whole set (src/backfill/apply.ts). A
834
+ // source that *is* the target is written once (with the merged body), not also
835
+ // superseded. base_version optimistic concurrency is not offered for merge.
836
+ export async function vaultMerge(vaultRoot, args, access) {
837
+ const ready = requireIndexReady();
838
+ if (!ready.ok)
839
+ return ready;
840
+ const pathA = requireString(args, "path_a", "vault_merge");
841
+ if (!pathA.ok)
842
+ return pathA;
843
+ const pathB = requireString(args, "path_b", "vault_merge");
844
+ if (!pathB.ok)
845
+ return pathB;
846
+ const targetPath = requireString(args, "target_path", "vault_merge");
847
+ if (!targetPath.ok)
848
+ return targetPath;
849
+ const agent = requireString(args, "agent", "vault_merge");
850
+ if (!agent.ok)
851
+ return agent;
852
+ const body = args.body;
853
+ if (typeof body !== "string" || body.trim().length === 0) {
854
+ return err(new Error("vault_merge requires a non-empty string 'body' argument"));
855
+ }
856
+ if (args.frontmatter !== undefined && args.frontmatter !== null) {
857
+ if (typeof args.frontmatter !== "object") {
858
+ return err(new Error("vault_merge: 'frontmatter' must be an object"));
859
+ }
860
+ }
861
+ const frontmatterOverrides = args.frontmatter && typeof args.frontmatter === "object"
862
+ ? args.frontmatter
863
+ : {};
864
+ // Resolve all three paths up front and run every identity check against the
865
+ // resolved absolute paths, never the raw caller strings: `pricing/a.md` and
866
+ // `./pricing/a.md` name the same file but differ as strings, which would
867
+ // otherwise defeat the path_a≠path_b guard and the source-is-target skip
868
+ // below (writing one file twice in a single commit and superseding it against
869
+ // itself).
870
+ const resolvedA = resolveVaultPath(vaultRoot, pathA.value);
871
+ if (!resolvedA.ok)
872
+ return resolvedA;
873
+ const resolvedB = resolveVaultPath(vaultRoot, pathB.value);
874
+ if (!resolvedB.ok)
875
+ return resolvedB;
876
+ const resolvedTarget = resolveVaultPath(vaultRoot, targetPath.value);
877
+ if (!resolvedTarget.ok)
878
+ return resolvedTarget;
879
+ if (resolvedA.value === resolvedB.value) {
880
+ return err(new Error("vault_merge: path_a and path_b must differ"));
881
+ }
882
+ const existingA = await readFile(resolvedA.value);
883
+ if (!existingA.ok)
884
+ return err(new Error(`vault_merge: document not found: ${pathA.value}`));
885
+ const existingB = await readFile(resolvedB.value);
886
+ if (!existingB.ok)
887
+ return err(new Error(`vault_merge: document not found: ${pathB.value}`));
888
+ const parsedA = parseDocument(existingA.value);
889
+ if (!parsedA.ok)
890
+ return parsedA;
891
+ const parsedB = parseDocument(existingB.value);
892
+ if (!parsedB.ok)
893
+ return parsedB;
894
+ const config = loadConfig(vaultRoot);
895
+ if (!config.ok)
896
+ return config;
897
+ const extensions = config.value.schemaExtensions;
898
+ // RBAC: a merge writes/mutates all three docs, so the caller needs write on
899
+ // each one's collection.
900
+ if (access) {
901
+ // The target's collection is the override, else path_a's *raw* collection
902
+ // (the value actually serialized into the target below — not the validated
903
+ // frontmatter, which may differ if path_a's raw collection is malformed),
904
+ // else the target path's top-level dir. Deriving it from the same source
905
+ // the write uses keeps the gate and the write in agreement.
906
+ const rawACollection = parsedA.value.raw.collection;
907
+ const collections = [
908
+ collectionOf(pathA.value, parsedA.value.frontmatter),
909
+ collectionOf(pathB.value, parsedB.value.frontmatter),
910
+ typeof frontmatterOverrides.collection === "string" && frontmatterOverrides.collection
911
+ ? frontmatterOverrides.collection
912
+ : typeof rawACollection === "string" && rawACollection
913
+ ? rawACollection
914
+ : (targetPath.value.split("/")[0] ?? ""),
915
+ ];
916
+ for (const collection of collections) {
917
+ if (!canWrite(access.role, collection)) {
918
+ return err(new Error(`access denied: role '${access.roleName}' cannot write to ` +
919
+ `collection '${collection}'`));
920
+ }
921
+ }
922
+ }
923
+ // Target frontmatter: inherit path_a's raw frontmatter, apply caller
924
+ // overrides, stamp provenance/updated/updated_by. If the target file already
925
+ // exists, preserve its `created` (the vault_write update idiom); otherwise
926
+ // inherit path_a's. The supplied body replaces whatever was there.
927
+ const existingTarget = await readFile(resolvedTarget.value);
928
+ let targetOldFrontmatter = null;
929
+ let targetCreated = parsedA.value.frontmatter.created;
930
+ if (existingTarget.ok) {
931
+ const parsedTarget = parseDocument(existingTarget.value);
932
+ if (parsedTarget.ok) {
933
+ targetOldFrontmatter = parsedTarget.value.frontmatter;
934
+ targetCreated = parsedTarget.value.frontmatter.created;
935
+ }
936
+ }
937
+ const targetRaw = {
938
+ ...parsedA.value.raw,
939
+ provenance: "synthesized",
940
+ ...frontmatterOverrides,
941
+ created: targetCreated,
942
+ updated: todayISO(),
943
+ updated_by: agent.value,
944
+ };
945
+ const { frontmatter: targetFm, report: targetReport } = validateFrontmatter(targetRaw, extensions);
946
+ if (!targetReport.valid) {
947
+ const summary = targetReport.issues.map((i) => `${i.field}: ${i.message}`).join("; ");
948
+ return err(new Error(`vault_merge: target frontmatter is invalid: ${summary}`));
949
+ }
950
+ const stampedTarget = {
951
+ ...targetFm,
952
+ created: targetCreated,
953
+ updated: todayISO(),
954
+ updated_by: agent.value,
955
+ };
956
+ // Build the write set. The target is always written. Each source that is NOT
957
+ // the target is superseded to point at the target.
958
+ const writes = [];
959
+ writes.push({
960
+ relPath: targetPath.value,
961
+ absPath: resolvedTarget.value,
962
+ fileText: serializeDocument(stampedTarget, body, extensions, applyExtensionDefaults(targetRaw, extensions)),
963
+ newFrontmatter: stampedTarget,
964
+ oldFrontmatter: targetOldFrontmatter,
965
+ action: "merge",
966
+ });
967
+ for (const source of [
968
+ { path: pathA.value, abs: resolvedA.value, parsed: parsedA.value },
969
+ { path: pathB.value, abs: resolvedB.value, parsed: parsedB.value },
970
+ ]) {
971
+ // Compare resolved absolute paths, not raw strings: a source that aliases
972
+ // the target (e.g. target `./pricing/a.md`, source `pricing/a.md`) is the
973
+ // fold-into-A case — write it once with the merged body, never supersede it.
974
+ if (source.abs === resolvedTarget.value)
975
+ continue;
976
+ const supersededFm = {
977
+ ...source.parsed.frontmatter,
978
+ status: "superseded",
979
+ superseded_by: targetPath.value,
980
+ updated: todayISO(),
981
+ updated_by: agent.value,
982
+ };
983
+ writes.push({
984
+ relPath: source.path,
985
+ absPath: source.abs,
986
+ fileText: serializeDocument(supersededFm, source.parsed.content, extensions, source.parsed.raw),
987
+ newFrontmatter: supersededFm,
988
+ oldFrontmatter: source.parsed.frontmatter,
989
+ action: "supersede",
990
+ });
991
+ }
992
+ // Acquire file locks on every distinct path, in a deterministic sorted order
993
+ // (defensive against self-deadlock if two merges ever overlapped — the
994
+ // one-process invariant makes that theoretical). Release all in finally.
995
+ const lockDbResult = openLockDb(vaultRoot);
996
+ if (!lockDbResult.ok)
997
+ return lockDbResult;
998
+ const lockDb = lockDbResult.value;
999
+ const lockPaths = [...new Set(writes.map((w) => w.relPath))].sort();
1000
+ const held = [];
1001
+ try {
1002
+ for (const relPath of lockPaths) {
1003
+ const lock = acquireLock(lockDb, relPath, agent.value);
1004
+ if (!lock.ok)
1005
+ return lock;
1006
+ held.push(relPath);
1007
+ }
1008
+ // Write all files, then a single git commit. This is NOT crash-atomic on
1009
+ // the disk-write phase: like the single-file write path (performWrite), a
1010
+ // throw mid-loop — or a commit() failure after the files are on disk —
1011
+ // leaves the working tree dirty and uncommitted. For merge the dirty state
1012
+ // can be a *partial* merge (target written, a source not yet superseded),
1013
+ // which a later reindex/watcher would pick up. The git commit itself is
1014
+ // atomic, and the one-process invariant plus human-gated ratification keep
1015
+ // this window small; a full pre-write snapshot/rollback is deferred.
1016
+ for (const w of writes) {
1017
+ await mkdir(dirname(w.absPath), { recursive: true });
1018
+ await writeFile(w.absPath, w.fileText, "utf-8");
1019
+ }
1020
+ let commitHash = null;
1021
+ if (config.value.autoCommit) {
1022
+ const committed = await commit(vaultRoot, writes.map((w) => w.relPath), `vault_merge: ${pathA.value} + ${pathB.value} → ${targetPath.value} by ${agent.value}`, agent.value);
1023
+ if (!committed.ok)
1024
+ return committed;
1025
+ commitHash = committed.value.hash;
1026
+ }
1027
+ // Index each written doc and log provenance per file. Both are best-effort
1028
+ // (the index is a rebuildable cache; the log is advisory) so a failure here
1029
+ // does not unwind the durable commit. noteSelfWrite runs here, after the
1030
+ // index lands, so the fs.watch reactive indexer drops the redundant change
1031
+ // event for our own write (mirrors performWrite's ordering).
1032
+ let allIndexed = true;
1033
+ for (const w of writes) {
1034
+ const indexed = await indexDocument(vaultRoot, w.relPath);
1035
+ if (!indexed.ok)
1036
+ allIndexed = false;
1037
+ noteSelfWrite(w.absPath);
1038
+ await recordProvenance(vaultRoot, {
1039
+ tool: "vault_merge",
1040
+ file: w.relPath,
1041
+ agent: agent.value,
1042
+ action: w.action,
1043
+ frontmatter_diff: frontmatterDiff(w.oldFrontmatter, w.newFrontmatter),
1044
+ });
1045
+ }
1046
+ return ok({
1047
+ path: targetPath.value,
1048
+ action: "merge",
1049
+ commit: commitHash,
1050
+ committed: config.value.autoCommit,
1051
+ status: stampedTarget.status,
1052
+ updated: stampedTarget.updated,
1053
+ validation: targetReport,
1054
+ indexUpdated: allIndexed,
1055
+ });
1056
+ }
1057
+ catch (e) {
1058
+ const reason = e instanceof Error ? e.message : String(e);
1059
+ return err(new Error(`vault_merge failed: ${reason}`));
1060
+ }
1061
+ finally {
1062
+ for (const relPath of held)
1063
+ releaseLock(lockDb, relPath, agent.value);
1064
+ lockDb.close();
1065
+ }
1066
+ }
1067
+ // ---------------------------------------------------------------------------
649
1068
  // MCP tool definitions
650
1069
  // ---------------------------------------------------------------------------
651
1070
  const agentProperty = {
@@ -844,5 +1263,108 @@ export const writeTools = [
844
1263
  },
845
1264
  handler: (vaultRoot, args, access) => vaultDeprecate(vaultRoot, args, access),
846
1265
  },
1266
+ {
1267
+ name: "vault_set_confidence",
1268
+ title: "Set a document's confidence",
1269
+ annotations: { destructiveHint: true },
1270
+ description: "Change only a document's confidence level (low | medium | high), leaving " +
1271
+ "its status and body untouched. A reason is required and recorded. Rejects " +
1272
+ "if the confidence is already at the target. Auto-commits.",
1273
+ inputSchema: {
1274
+ type: "object",
1275
+ properties: {
1276
+ path: {
1277
+ type: "string",
1278
+ description: "Vault-relative path of the document",
1279
+ },
1280
+ confidence: {
1281
+ type: "string",
1282
+ enum: [...CONFIDENCES],
1283
+ description: "The new confidence level",
1284
+ },
1285
+ reason: {
1286
+ type: "string",
1287
+ description: "Why the confidence is changing (recorded in the commit and provenance)",
1288
+ },
1289
+ agent: agentProperty,
1290
+ base_version: baseVersionProperty,
1291
+ },
1292
+ required: ["path", "confidence", "reason", "agent"],
1293
+ additionalProperties: false,
1294
+ },
1295
+ handler: (vaultRoot, args, access) => vaultSetConfidence(vaultRoot, args, access),
1296
+ },
1297
+ {
1298
+ name: "vault_supersede",
1299
+ title: "Supersede a document",
1300
+ annotations: { destructiveHint: true },
1301
+ description: "Mark a document superseded by a named successor. Sets status=superseded " +
1302
+ "and superseded_by; the successor must already exist. Distinct from " +
1303
+ "vault_deprecate (which sets status=deprecated with an optional " +
1304
+ "successor). Auto-commits.",
1305
+ inputSchema: {
1306
+ type: "object",
1307
+ properties: {
1308
+ old_path: {
1309
+ type: "string",
1310
+ description: "Vault-relative path of the document being superseded",
1311
+ },
1312
+ new_path: {
1313
+ type: "string",
1314
+ description: "Vault-relative path of the successor that replaces it (must exist)",
1315
+ },
1316
+ reason: {
1317
+ type: "string",
1318
+ description: "Optional reason recorded in the commit message",
1319
+ },
1320
+ agent: agentProperty,
1321
+ base_version: baseVersionProperty,
1322
+ },
1323
+ required: ["old_path", "new_path", "agent"],
1324
+ additionalProperties: false,
1325
+ },
1326
+ handler: (vaultRoot, args, access) => vaultSupersede(vaultRoot, args, access),
1327
+ },
1328
+ {
1329
+ name: "vault_merge",
1330
+ title: "Merge two documents into one",
1331
+ annotations: { destructiveHint: true },
1332
+ description: "Combine two source documents into a target and supersede both sources to " +
1333
+ "point at it, all in one commit. The merged body is supplied by the caller " +
1334
+ "— vault_merge does not synthesize prose. target_path may equal path_a (to " +
1335
+ "fold B into A) or be a new path. The target's frontmatter inherits " +
1336
+ "path_a's (provenance becomes 'synthesized') unless overridden. Auto-commits.",
1337
+ inputSchema: {
1338
+ type: "object",
1339
+ properties: {
1340
+ path_a: {
1341
+ type: "string",
1342
+ description: "Vault-relative path of the first source document",
1343
+ },
1344
+ path_b: {
1345
+ type: "string",
1346
+ description: "Vault-relative path of the second source document",
1347
+ },
1348
+ target_path: {
1349
+ type: "string",
1350
+ description: "Vault-relative path of the merge target (may equal path_a, or be new)",
1351
+ },
1352
+ body: {
1353
+ type: "string",
1354
+ description: "The merged markdown body for the target (no frontmatter)",
1355
+ },
1356
+ frontmatter: {
1357
+ type: "object",
1358
+ description: "Optional frontmatter overrides for the target. Defaults to path_a's " +
1359
+ "frontmatter with provenance set to 'synthesized'.",
1360
+ additionalProperties: true,
1361
+ },
1362
+ agent: agentProperty,
1363
+ },
1364
+ required: ["path_a", "path_b", "target_path", "body", "agent"],
1365
+ additionalProperties: false,
1366
+ },
1367
+ handler: (vaultRoot, args, access) => vaultMerge(vaultRoot, args, access),
1368
+ },
847
1369
  ];
848
1370
  //# sourceMappingURL=write.js.map