@hraness/wordcell 0.22.4 → 0.23.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.
- package/README.md +63 -22
- package/dist/authoring.js +2 -2
- package/dist/{authority-06eqhqam.js → authority-35cbvp1x.js} +2 -2
- package/dist/benchmark.js +3 -3
- package/dist/capture.js +6 -6
- package/dist/cli.js +26 -24
- package/dist/clip/acquire.js +3 -3
- package/dist/clip/args.js +1 -1
- package/dist/clip/cli.js +6 -6
- package/dist/clip/doctor.js +4 -4
- package/dist/evaluation-builder.js +10 -10
- package/dist/evaluation-kb.js +10 -10
- package/dist/graph-authority.js +4 -4
- package/dist/graph-percolation.js +6 -6
- package/dist/graph.js +5 -1
- package/dist/{index-bcknqxrq.js → index-0eacgvpv.js} +9 -1
- package/dist/{index-xv80vzfp.js → index-1er88ckw.js} +4 -4
- package/dist/{index-233z9wmn.js → index-1s8mc4hz.js} +13 -5
- package/dist/{index-de2w8crk.js → index-2fmnttca.js} +82 -15
- package/dist/{index-vnybgywh.js → index-ahyhryb8.js} +1 -1
- package/dist/{index-ecqpgr5y.js → index-b0khj0h5.js} +164 -9
- package/dist/{index-jk1sgx36.js → index-bdwcjvr4.js} +1 -1
- package/dist/{index-dfag79p7.js → index-byz4kzww.js} +3 -0
- package/dist/{index-hgve9rh2.js → index-cd75vky9.js} +96 -1
- package/dist/{index-rr9kzq4n.js → index-fp732bgg.js} +2 -2
- package/dist/{index-qbssx940.js → index-jvb7w0gg.js} +227 -9
- package/dist/{index-f984hw45.js → index-k86wepd8.js} +1 -1
- package/dist/{index-1k595z6v.js → index-mnq2wy34.js} +2 -2
- package/dist/{index-n386evxj.js → index-nn67kzwa.js} +1 -1
- package/dist/{index-fc4dr114.js → index-nwrehke7.js} +1 -1
- package/dist/{index-76dbn6pe.js → index-p70t8j13.js} +1 -1
- package/dist/{index-tf4wzjew.js → index-pgtm2nhf.js} +1 -1
- package/dist/{index-054mb7d3.js → index-qfqjfxaa.js} +10 -9
- package/dist/{index-pnt9wr59.js → index-r0m5taz2.js} +2 -2
- package/dist/{index-bqtqeak3.js → index-r4qs6vq4.js} +4 -4
- package/dist/{index-djrcc1yf.js → index-tcaq1c7f.js} +4 -4
- package/dist/{index-q7tbg07z.js → index-tvd2sqrx.js} +7 -7
- package/dist/{index-9h7zh0wt.js → index-vtwbapjr.js} +3814 -162
- package/dist/{index-g5vsqmdy.js → index-xwxy71ew.js} +190 -4
- package/dist/index.js +22 -14
- package/dist/pdf.js +3 -3
- package/dist/percolate.js +2 -2
- package/dist/portfolio.js +10 -10
- package/dist/publish.js +3 -3
- package/dist/sdk.js +9 -9
- package/dist/search.js +2 -2
- package/dist/semantic.js +4 -4
- package/dist/{support-m3t917ev.js → support-c8hy7qfa.js} +25 -23
- package/dist/url-intelligence.js +1 -1
- package/dist/workflows/decision-context.js +10 -10
- package/dist/workflows/index.js +10 -10
- package/package.json +12 -4
- package/skills/wordcell/AGENTS.md +1 -0
- package/skills/wordcell/SKILL.md +5 -3
- package/skills/wordcell/references/plan-structure.md +1 -1
- package/skills/wordcell/references/query.md +35 -1
- package/skills/wordcell/references/session-memory.md +207 -0
- package/skills/wordcell/references/url-platforms.md +1 -1
- package/src/authoring-import.ts +32 -0
- package/src/authoring-model.ts +185 -2
- package/src/authoring-program.ts +19 -7
- package/src/cli-help.ts +893 -0
- package/src/cli-intro.ts +1 -1
- package/src/cli-program.ts +575 -82
- package/src/cli-style.ts +132 -0
- package/src/clip/acquire.ts +20 -0
- package/src/clip/args.ts +3 -0
- package/src/clip/cli.ts +82 -5
- package/src/clip/cookie-permission.ts +241 -0
- package/src/clip/url-metadata-cli.ts +6 -5
- package/src/clip/url-metadata.ts +14 -0
- package/src/graph.ts +88 -13
- package/src/import-supermemory.ts +1629 -0
- package/src/mcp-server.ts +415 -0
- package/src/mcp-tools.ts +1122 -0
- package/src/mention-index.ts +194 -0
- package/src/pdf/cli.ts +5 -4
- package/src/support-profile.ts +1 -1
- package/src/support.ts +3 -0
- package/src/vault.ts +26 -2
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/** Finite UTF-16 multi-pattern matching for complete vault analysis. */
|
|
2
|
+
export type MentionIndexLimits = {
|
|
3
|
+
readonly maxNodes?: number;
|
|
4
|
+
readonly maxWork?: number;
|
|
5
|
+
readonly maxMatches?: number;
|
|
6
|
+
readonly maxInputCodeUnits?: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const MENTION_INDEX_LIMITS = {
|
|
10
|
+
maxNodes: 262_144,
|
|
11
|
+
maxWork: 64 * 1_024 * 1_024,
|
|
12
|
+
maxMatches: 1_000_000,
|
|
13
|
+
maxInputCodeUnits: 256 * 1_024 * 1_024,
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export type MentionIndexBudgetKind =
|
|
17
|
+
| "mention-index-nodes"
|
|
18
|
+
| "mention-index-work"
|
|
19
|
+
| "mention-matches"
|
|
20
|
+
| "mention-input-code-units";
|
|
21
|
+
|
|
22
|
+
export class MentionIndexBudgetError extends RangeError {
|
|
23
|
+
readonly kind: MentionIndexBudgetKind;
|
|
24
|
+
readonly limit: number;
|
|
25
|
+
|
|
26
|
+
constructor(kind: MentionIndexBudgetKind, limit: number) {
|
|
27
|
+
super(`Vault analysis exceeds the ${limit} ${kind} limit.`);
|
|
28
|
+
this.kind = kind;
|
|
29
|
+
this.limit = limit;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function checkedLimits(options: MentionIndexLimits): Record<keyof MentionIndexLimits, number> {
|
|
34
|
+
const limits: Record<keyof MentionIndexLimits, number> = { ...MENTION_INDEX_LIMITS };
|
|
35
|
+
for (const name of Object.keys(MENTION_INDEX_LIMITS) as (keyof MentionIndexLimits)[]) {
|
|
36
|
+
const value = options[name] ?? MENTION_INDEX_LIMITS[name];
|
|
37
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > MENTION_INDEX_LIMITS[name]) {
|
|
38
|
+
throw new RangeError(`${name} must be a safe integer from 0 through ${MENTION_INDEX_LIMITS[name]}.`);
|
|
39
|
+
}
|
|
40
|
+
limits[name] = value;
|
|
41
|
+
}
|
|
42
|
+
return limits;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Admit original strings before trimming, normalizing, or indexing any phrase. */
|
|
46
|
+
export function preflightMentionInput(inputs: Iterable<string>, options: MentionIndexLimits): { rawInputCodeUnits: number; work: number } {
|
|
47
|
+
const limits = checkedLimits(options);
|
|
48
|
+
let rawInputCodeUnits = 0, work = 0;
|
|
49
|
+
for (const input of inputs) {
|
|
50
|
+
rawInputCodeUnits += input.length;
|
|
51
|
+
if (rawInputCodeUnits > limits.maxInputCodeUnits) throw new MentionIndexBudgetError("mention-input-code-units", limits.maxInputCodeUnits);
|
|
52
|
+
work += input.length + 1;
|
|
53
|
+
if (work > limits.maxWork) throw new MentionIndexBudgetError("mention-index-work", limits.maxWork);
|
|
54
|
+
}
|
|
55
|
+
return { rawInputCodeUnits, work };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type MentionPattern = {
|
|
59
|
+
readonly targetId: string;
|
|
60
|
+
readonly phrase: string;
|
|
61
|
+
readonly lowerPhrase: string;
|
|
62
|
+
readonly rank: number;
|
|
63
|
+
};
|
|
64
|
+
export type IndexedMention = { readonly pattern: MentionPattern; readonly offset: number };
|
|
65
|
+
type TrieNode = {
|
|
66
|
+
readonly next: Map<number, number>;
|
|
67
|
+
failure: number;
|
|
68
|
+
output: number;
|
|
69
|
+
pattern: MentionPattern | undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** The legacy matcher uses ASCII word boundaries, even for Unicode phrases. */
|
|
73
|
+
export function cleanMentionBoundary(text: string, phrase: string, offset: number): boolean {
|
|
74
|
+
const word = (value: string): boolean => /[A-Za-z0-9]/.test(value);
|
|
75
|
+
return (!word(phrase[0] ?? "") || !word(text[offset - 1] ?? ""))
|
|
76
|
+
&& (!word(phrase.at(-1) ?? "") || !word(text[offset + phrase.length] ?? ""));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class MentionMatcher {
|
|
80
|
+
private readonly limits: Record<keyof MentionIndexLimits, number>;
|
|
81
|
+
private readonly nodes: TrieNode[] = [];
|
|
82
|
+
private work = 0;
|
|
83
|
+
private matches = 0;
|
|
84
|
+
private input = 0;
|
|
85
|
+
|
|
86
|
+
constructor(patterns: readonly MentionPattern[], options: MentionIndexLimits = {}, rawInputCodeUnits = 0, preflightWork = 0) {
|
|
87
|
+
this.limits = checkedLimits(options);
|
|
88
|
+
if (!Number.isSafeInteger(preflightWork) || preflightWork < 0) throw new RangeError("Invalid mention preflight work.");
|
|
89
|
+
if (preflightWork > this.limits.maxWork) this.fail("mention-index-work", this.limits.maxWork);
|
|
90
|
+
this.work = preflightWork;
|
|
91
|
+
if (!Number.isSafeInteger(rawInputCodeUnits) || rawInputCodeUnits < 0) throw new RangeError("Invalid mention input length.");
|
|
92
|
+
if (rawInputCodeUnits > this.limits.maxInputCodeUnits) this.fail("mention-input-code-units", this.limits.maxInputCodeUnits);
|
|
93
|
+
this.node();
|
|
94
|
+
for (const pattern of patterns) {
|
|
95
|
+
this.inputUnits(pattern.lowerPhrase.length);
|
|
96
|
+
let state = 0;
|
|
97
|
+
for (let index = 0; index < pattern.lowerPhrase.length; index += 1) {
|
|
98
|
+
this.step();
|
|
99
|
+
const character = pattern.lowerPhrase.charCodeAt(index);
|
|
100
|
+
let next = this.nodes[state]!.next.get(character);
|
|
101
|
+
if (next === undefined) {
|
|
102
|
+
next = this.node();
|
|
103
|
+
this.nodes[state]!.next.set(character, next);
|
|
104
|
+
}
|
|
105
|
+
state = next;
|
|
106
|
+
}
|
|
107
|
+
if (pattern.lowerPhrase.length === 0 || this.nodes[state]!.pattern !== undefined) {
|
|
108
|
+
throw new TypeError("Mention index requires nonempty, uniquely owned normalized phrases.");
|
|
109
|
+
}
|
|
110
|
+
this.nodes[state]!.pattern = pattern;
|
|
111
|
+
}
|
|
112
|
+
const queue = [...this.nodes[0]!.next.values()];
|
|
113
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
114
|
+
const state = queue[cursor]!;
|
|
115
|
+
for (const [character, child] of this.nodes[state]!.next) {
|
|
116
|
+
this.step();
|
|
117
|
+
let fallback = this.nodes[state]!.failure;
|
|
118
|
+
while (fallback !== 0 && !this.nodes[fallback]!.next.has(character)) {
|
|
119
|
+
this.step();
|
|
120
|
+
fallback = this.nodes[fallback]!.failure;
|
|
121
|
+
}
|
|
122
|
+
const failure = this.nodes[fallback]!.next.get(character) ?? 0;
|
|
123
|
+
this.nodes[child]!.failure = failure;
|
|
124
|
+
this.nodes[child]!.output = this.nodes[failure]!.pattern === undefined
|
|
125
|
+
? this.nodes[failure]!.output : failure;
|
|
126
|
+
queue.push(child);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private fail(kind: MentionIndexBudgetKind, limit: number): never { throw new MentionIndexBudgetError(kind, limit); }
|
|
132
|
+
private step(): void {
|
|
133
|
+
if (this.work >= this.limits.maxWork) this.fail("mention-index-work", this.limits.maxWork);
|
|
134
|
+
this.work += 1;
|
|
135
|
+
}
|
|
136
|
+
private node(): number {
|
|
137
|
+
if (this.nodes.length >= this.limits.maxNodes) this.fail("mention-index-nodes", this.limits.maxNodes);
|
|
138
|
+
this.nodes.push({ next: new Map(), failure: 0, output: -1, pattern: undefined });
|
|
139
|
+
return this.nodes.length - 1;
|
|
140
|
+
}
|
|
141
|
+
private inputUnits(count: number): void {
|
|
142
|
+
this.input += count;
|
|
143
|
+
if (this.input > this.limits.maxInputCodeUnits) this.fail("mention-input-code-units", this.limits.maxInputCodeUnits);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
newlineOffsets(originalText: string): readonly number[] {
|
|
147
|
+
const offsets: number[] = [];
|
|
148
|
+
for (let index = 0; index < originalText.length; index += 1) {
|
|
149
|
+
this.step();
|
|
150
|
+
if (originalText.charCodeAt(index) === 10) offsets.push(index);
|
|
151
|
+
}
|
|
152
|
+
return offsets;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
lineAt(offsets: readonly number[], offset: number): number {
|
|
156
|
+
let low = 0, high = offsets.length;
|
|
157
|
+
while (low < high) {
|
|
158
|
+
this.step();
|
|
159
|
+
const middle = low + Math.floor((high - low) / 2);
|
|
160
|
+
if (offsets[middle]! < offset) low = middle + 1;
|
|
161
|
+
else high = middle;
|
|
162
|
+
}
|
|
163
|
+
return low + 1;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
scan(lowerText: string): ReadonlyMap<string, IndexedMention> {
|
|
167
|
+
this.inputUnits(lowerText.length);
|
|
168
|
+
const result = new Map<string, IndexedMention>();
|
|
169
|
+
let state = 0;
|
|
170
|
+
for (let index = 0; index < lowerText.length; index += 1) {
|
|
171
|
+
this.step();
|
|
172
|
+
const character = lowerText.charCodeAt(index);
|
|
173
|
+
while (state !== 0 && !this.nodes[state]!.next.has(character)) {
|
|
174
|
+
this.step();
|
|
175
|
+
state = this.nodes[state]!.failure;
|
|
176
|
+
}
|
|
177
|
+
state = this.nodes[state]!.next.get(character) ?? 0;
|
|
178
|
+
let output = this.nodes[state]!.pattern === undefined ? this.nodes[state]!.output : state;
|
|
179
|
+
while (output !== -1) {
|
|
180
|
+
if (this.matches >= this.limits.maxMatches) this.fail("mention-matches", this.limits.maxMatches);
|
|
181
|
+
this.matches += 1; // Count overlapping/repeated outputs before deduplication or boundary filtering.
|
|
182
|
+
const pattern = this.nodes[output]!.pattern!;
|
|
183
|
+
const offset = index + 1 - pattern.lowerPhrase.length;
|
|
184
|
+
const existing = result.get(pattern.targetId);
|
|
185
|
+
if (cleanMentionBoundary(lowerText, pattern.lowerPhrase, offset)
|
|
186
|
+
&& (existing === undefined || pattern.rank < existing.pattern.rank)) {
|
|
187
|
+
result.set(pattern.targetId, { pattern, offset });
|
|
188
|
+
}
|
|
189
|
+
output = this.nodes[output]!.output;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
}
|
package/src/pdf/cli.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { lstatSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { redactSensitiveText } from "../clip/persist.js";
|
|
5
|
+
import { renderFailure, sentence, stderrStyle, terminalOutput } from "../cli-style.js";
|
|
5
6
|
import { sanitizeTerminalLine, sanitizeTerminalText } from "../clip/terminal.js";
|
|
6
7
|
import { parsePdfArguments, pdfUsage } from "./args.js";
|
|
7
8
|
import { runPdfCapture } from "./capture.js";
|
|
@@ -19,10 +20,10 @@ export type PdfCliOutput = {
|
|
|
19
20
|
readonly stderr: (value: string) => void;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
const defaultOutput: PdfCliOutput = {
|
|
23
|
+
const defaultOutput: PdfCliOutput = terminalOutput({
|
|
23
24
|
stdout: (value) => process.stdout.write(value),
|
|
24
25
|
stderr: (value) => process.stderr.write(value),
|
|
25
|
-
};
|
|
26
|
+
});
|
|
26
27
|
|
|
27
28
|
export type PdfCliDependencies = {
|
|
28
29
|
readonly runPdfCapture?: typeof runPdfCapture;
|
|
@@ -89,7 +90,7 @@ export async function main(
|
|
|
89
90
|
): Promise<number> {
|
|
90
91
|
const parsed = parsePdfArguments(rawArguments, environment);
|
|
91
92
|
if (!parsed.ok) {
|
|
92
|
-
output.stderr(
|
|
93
|
+
output.stderr(renderFailure(sentence(safe(parsed.message)), "wordcell pdf --help", stderrStyle(environment, output)));
|
|
93
94
|
return 2;
|
|
94
95
|
}
|
|
95
96
|
const arguments_ = parsed.value;
|
|
@@ -149,7 +150,7 @@ export async function main(
|
|
|
149
150
|
} catch (error) {
|
|
150
151
|
const message = safe(error instanceof Error ? error.message : String(error));
|
|
151
152
|
if (arguments_.json) output.stdout(terminalSafeJson({ ok: false, error: message }));
|
|
152
|
-
else output.stderr(
|
|
153
|
+
else output.stderr(renderFailure(message, "wordcell doctor", stderrStyle(environment, output)));
|
|
153
154
|
return 1;
|
|
154
155
|
} finally {
|
|
155
156
|
preparedSource?.dispose();
|
package/src/support-profile.ts
CHANGED
package/src/support.ts
CHANGED
|
@@ -52,6 +52,9 @@ export function isUsefulSupportResult(args: readonly string[], environment: Read
|
|
|
52
52
|
const metadata = parseUrlMetadataArguments(command.arguments, environment);
|
|
53
53
|
return metadata.ok && metadata.value.kind === "backfill";
|
|
54
54
|
}
|
|
55
|
+
case "mcp":
|
|
56
|
+
// stdout belongs to JSON-RPC frames, so a long-running server never invites.
|
|
57
|
+
return false;
|
|
55
58
|
default:
|
|
56
59
|
return false;
|
|
57
60
|
}
|
package/src/vault.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
analyzeVault,
|
|
16
|
+
analyzeVaultComplete,
|
|
16
17
|
isCanonicalNoteId,
|
|
17
18
|
lookupNote,
|
|
18
19
|
MAX_ANALYZED_NOTES,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
renderCatalog,
|
|
22
23
|
replaceCatalog,
|
|
23
24
|
type AnalyzeVaultOptions,
|
|
25
|
+
type CompleteAnalyzeVaultOptions,
|
|
24
26
|
type Note,
|
|
25
27
|
type VaultAnalysis,
|
|
26
28
|
} from "./graph.js";
|
|
@@ -90,6 +92,8 @@ export type ScanVaultOptions = Omit<AnalyzeVaultOptions, "mentionScope"> & {
|
|
|
90
92
|
readonly mentionScope?: string | false;
|
|
91
93
|
};
|
|
92
94
|
|
|
95
|
+
export type CompleteScanVaultOptions = ScanVaultOptions & Pick<CompleteAnalyzeVaultOptions, "mentionIndexLimits">;
|
|
96
|
+
|
|
93
97
|
export async function markdownFiles(
|
|
94
98
|
directory: string,
|
|
95
99
|
ignoredDirectories: ReadonlySet<string> = defaultIgnoredDirectories,
|
|
@@ -520,8 +524,9 @@ async function atomicReplace(
|
|
|
520
524
|
|
|
521
525
|
async function snapshot(
|
|
522
526
|
rootInput: string,
|
|
523
|
-
options:
|
|
527
|
+
options: CompleteScanVaultOptions,
|
|
524
528
|
writeIndex: boolean,
|
|
529
|
+
completeMentions = false,
|
|
525
530
|
): Promise<VaultSnapshot> {
|
|
526
531
|
const requestedRoot = resolve(rootInput);
|
|
527
532
|
const root = await realpath(requestedRoot);
|
|
@@ -613,7 +618,7 @@ async function snapshot(
|
|
|
613
618
|
catalogMode,
|
|
614
619
|
index,
|
|
615
620
|
notes,
|
|
616
|
-
analysis: analyzeVault(notes, {
|
|
621
|
+
analysis: (completeMentions ? analyzeVaultComplete : analyzeVault)(notes, {
|
|
617
622
|
catalogNoteId,
|
|
618
623
|
...(options.includeInSuggestions === undefined
|
|
619
624
|
? {}
|
|
@@ -631,6 +636,9 @@ async function snapshot(
|
|
|
631
636
|
...(options.maxMentions === undefined
|
|
632
637
|
? {}
|
|
633
638
|
: { maxMentions: options.maxMentions }),
|
|
639
|
+
...(!completeMentions || options.mentionIndexLimits === undefined
|
|
640
|
+
? {}
|
|
641
|
+
: { mentionIndexLimits: options.mentionIndexLimits }),
|
|
634
642
|
}),
|
|
635
643
|
};
|
|
636
644
|
}
|
|
@@ -648,3 +656,19 @@ export async function refreshVault(
|
|
|
648
656
|
): Promise<VaultSnapshot> {
|
|
649
657
|
return snapshot(root, options, true);
|
|
650
658
|
}
|
|
659
|
+
|
|
660
|
+
/** Read every admitted note and compute the full graph through the phrase index. */
|
|
661
|
+
export async function scanVaultComplete(
|
|
662
|
+
root = ".",
|
|
663
|
+
options: CompleteScanVaultOptions = {},
|
|
664
|
+
): Promise<VaultSnapshot> {
|
|
665
|
+
return snapshot(root, options, false, true);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** Refresh the configured catalog while retaining complete indexed analysis. */
|
|
669
|
+
export async function refreshVaultComplete(
|
|
670
|
+
root = ".",
|
|
671
|
+
options: CompleteScanVaultOptions = {},
|
|
672
|
+
): Promise<VaultSnapshot> {
|
|
673
|
+
return snapshot(root, options, true, true);
|
|
674
|
+
}
|