@blacksmithers/vaultforge 1.0.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/LICENSE +21 -0
- package/README.md +464 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +705 -0
- package/dist/index.js.map +1 -0
- package/dist/tool-handlers.d.ts +79 -0
- package/dist/tool-handlers.d.ts.map +1 -0
- package/dist/tool-handlers.js +326 -0
- package/dist/tool-handlers.js.map +1 -0
- package/dist/tools/canvas/canvas-create.d.ts +4 -0
- package/dist/tools/canvas/canvas-create.d.ts.map +1 -0
- package/dist/tools/canvas/canvas-create.js +243 -0
- package/dist/tools/canvas/canvas-create.js.map +1 -0
- package/dist/tools/canvas/canvas-patch.d.ts +4 -0
- package/dist/tools/canvas/canvas-patch.d.ts.map +1 -0
- package/dist/tools/canvas/canvas-patch.js +225 -0
- package/dist/tools/canvas/canvas-patch.js.map +1 -0
- package/dist/tools/canvas/canvas-read.d.ts +4 -0
- package/dist/tools/canvas/canvas-read.d.ts.map +1 -0
- package/dist/tools/canvas/canvas-read.js +97 -0
- package/dist/tools/canvas/canvas-read.js.map +1 -0
- package/dist/tools/canvas/canvas-relayout.d.ts +4 -0
- package/dist/tools/canvas/canvas-relayout.d.ts.map +1 -0
- package/dist/tools/canvas/canvas-relayout.js +152 -0
- package/dist/tools/canvas/canvas-relayout.js.map +1 -0
- package/dist/tools/canvas/canvas-utils.d.ts +40 -0
- package/dist/tools/canvas/canvas-utils.d.ts.map +1 -0
- package/dist/tools/canvas/canvas-utils.js +141 -0
- package/dist/tools/canvas/canvas-utils.js.map +1 -0
- package/dist/tools/canvas/layout-engine.d.ts +34 -0
- package/dist/tools/canvas/layout-engine.d.ts.map +1 -0
- package/dist/tools/canvas/layout-engine.js +75 -0
- package/dist/tools/canvas/layout-engine.js.map +1 -0
- package/dist/tools/canvas/types.d.ts +71 -0
- package/dist/tools/canvas/types.d.ts.map +1 -0
- package/dist/tools/canvas/types.js +2 -0
- package/dist/tools/canvas/types.js.map +1 -0
- package/dist/tools/files/batch-rename.d.ts +4 -0
- package/dist/tools/files/batch-rename.d.ts.map +1 -0
- package/dist/tools/files/batch-rename.js +140 -0
- package/dist/tools/files/batch-rename.js.map +1 -0
- package/dist/tools/files/delete-folder.d.ts +17 -0
- package/dist/tools/files/delete-folder.d.ts.map +1 -0
- package/dist/tools/files/delete-folder.js +100 -0
- package/dist/tools/files/delete-folder.js.map +1 -0
- package/dist/tools/files/prune-empty-dirs.d.ts +17 -0
- package/dist/tools/files/prune-empty-dirs.d.ts.map +1 -0
- package/dist/tools/files/prune-empty-dirs.js +106 -0
- package/dist/tools/files/prune-empty-dirs.js.map +1 -0
- package/dist/tools/intelligence/clustering.d.ts +15 -0
- package/dist/tools/intelligence/clustering.d.ts.map +1 -0
- package/dist/tools/intelligence/clustering.js +93 -0
- package/dist/tools/intelligence/clustering.js.map +1 -0
- package/dist/tools/intelligence/tfidf.d.ts +19 -0
- package/dist/tools/intelligence/tfidf.d.ts.map +1 -0
- package/dist/tools/intelligence/tfidf.js +68 -0
- package/dist/tools/intelligence/tfidf.js.map +1 -0
- package/dist/tools/intelligence/vault-suggest.d.ts +7 -0
- package/dist/tools/intelligence/vault-suggest.d.ts.map +1 -0
- package/dist/tools/intelligence/vault-suggest.js +307 -0
- package/dist/tools/intelligence/vault-suggest.js.map +1 -0
- package/dist/tools/intelligence/vault-themes.d.ts +30 -0
- package/dist/tools/intelligence/vault-themes.d.ts.map +1 -0
- package/dist/tools/intelligence/vault-themes.js +88 -0
- package/dist/tools/intelligence/vault-themes.js.map +1 -0
- package/dist/tools/links/backlinks.d.ts +4 -0
- package/dist/tools/links/backlinks.d.ts.map +1 -0
- package/dist/tools/links/backlinks.js +50 -0
- package/dist/tools/links/backlinks.js.map +1 -0
- package/dist/tools/links/link-utils.d.ts +23 -0
- package/dist/tools/links/link-utils.d.ts.map +1 -0
- package/dist/tools/links/link-utils.js +63 -0
- package/dist/tools/links/link-utils.js.map +1 -0
- package/dist/tools/links/update-links.d.ts +16 -0
- package/dist/tools/links/update-links.d.ts.map +1 -0
- package/dist/tools/links/update-links.js +88 -0
- package/dist/tools/links/update-links.js.map +1 -0
- package/dist/tools/metadata/frontmatter.d.ts +12 -0
- package/dist/tools/metadata/frontmatter.d.ts.map +1 -0
- package/dist/tools/metadata/frontmatter.js +190 -0
- package/dist/tools/metadata/frontmatter.js.map +1 -0
- package/dist/tools/notes/edit-regex.d.ts +4 -0
- package/dist/tools/notes/edit-regex.d.ts.map +1 -0
- package/dist/tools/notes/edit-regex.js +142 -0
- package/dist/tools/notes/edit-regex.js.map +1 -0
- package/dist/tools/search/markdown-parser.d.ts +12 -0
- package/dist/tools/search/markdown-parser.d.ts.map +1 -0
- package/dist/tools/search/markdown-parser.js +64 -0
- package/dist/tools/search/markdown-parser.js.map +1 -0
- package/dist/tools/search/orama-engine.d.ts +76 -0
- package/dist/tools/search/orama-engine.d.ts.map +1 -0
- package/dist/tools/search/orama-engine.js +152 -0
- package/dist/tools/search/orama-engine.js.map +1 -0
- package/dist/tools/search/search-reindex.d.ts +7 -0
- package/dist/tools/search/search-reindex.d.ts.map +1 -0
- package/dist/tools/search/search-reindex.js +34 -0
- package/dist/tools/search/search-reindex.js.map +1 -0
- package/dist/tools/search/smart-search.d.ts +7 -0
- package/dist/tools/search/smart-search.d.ts.map +1 -0
- package/dist/tools/search/smart-search.js +102 -0
- package/dist/tools/search/smart-search.js.map +1 -0
- package/dist/vault-index.d.ts +95 -0
- package/dist/vault-index.d.ts.map +1 -0
- package/dist/vault-index.js +432 -0
- package/dist/vault-index.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { VaultIndex } from "../../vault-index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Core link-update logic, exported so batch_rename can call it directly.
|
|
5
|
+
*/
|
|
6
|
+
export declare function updateWikilinks(vaultPath: string, vault: VaultIndex, oldPath: string, newPath: string, dryRun: boolean): Promise<{
|
|
7
|
+
filesScanned: number;
|
|
8
|
+
filesUpdated: number;
|
|
9
|
+
totalLinks: number;
|
|
10
|
+
results: Array<{
|
|
11
|
+
path: string;
|
|
12
|
+
links_updated: number;
|
|
13
|
+
}>;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function registerUpdateLinks(server: McpServer, vaultPath: string, vault: VaultIndex): void;
|
|
16
|
+
//# sourceMappingURL=update-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-links.d.ts","sourceRoot":"","sources":["../../../src/tools/links/update-links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA6DtI;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,GAChB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { escapeRegex, extractStem, getAllMdFiles } from "./link-utils.js";
|
|
5
|
+
/**
|
|
6
|
+
* Core link-update logic, exported so batch_rename can call it directly.
|
|
7
|
+
*/
|
|
8
|
+
export async function updateWikilinks(vaultPath, vault, oldPath, newPath, dryRun) {
|
|
9
|
+
const oldRef = oldPath.replace(/\.md$/, "");
|
|
10
|
+
const newRef = newPath.replace(/\.md$/, "");
|
|
11
|
+
const oldStem = extractStem(oldPath);
|
|
12
|
+
const newStem = extractStem(newPath);
|
|
13
|
+
const escapedRef = escapeRegex(oldRef);
|
|
14
|
+
const escapedStem = escapeRegex(oldStem);
|
|
15
|
+
// Build replacement patterns (full path first, then stem)
|
|
16
|
+
const patterns = [
|
|
17
|
+
{
|
|
18
|
+
regex: new RegExp(`(!?\\[\\[)${escapedRef}(#[^\\]|]*)?(?:\\|([^\\]]*))?\\]\\]`, "g"),
|
|
19
|
+
newBase: newRef,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
if (oldStem !== newStem) {
|
|
23
|
+
patterns.push({
|
|
24
|
+
regex: new RegExp(`(!?\\[\\[)${escapedStem}(#[^\\]|]*)?(?:\\|([^\\]]*))?\\]\\]`, "g"),
|
|
25
|
+
newBase: newStem,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const allFiles = getAllMdFiles(vault);
|
|
29
|
+
const results = [];
|
|
30
|
+
let totalLinks = 0;
|
|
31
|
+
for (const filePath of allFiles) {
|
|
32
|
+
if (filePath === newPath)
|
|
33
|
+
continue;
|
|
34
|
+
const fullPath = path.join(vaultPath, filePath);
|
|
35
|
+
let content;
|
|
36
|
+
try {
|
|
37
|
+
content = await readFile(fullPath, "utf-8");
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
let newContent = content;
|
|
43
|
+
let matchCount = 0;
|
|
44
|
+
for (const { regex, newBase } of patterns) {
|
|
45
|
+
newContent = newContent.replace(regex, (_match, prefix, heading, alias) => {
|
|
46
|
+
matchCount++;
|
|
47
|
+
const h = heading || "";
|
|
48
|
+
const a = alias !== undefined ? `|${alias}` : "";
|
|
49
|
+
return `${prefix}${newBase}${h}${a}]]`;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (matchCount > 0) {
|
|
53
|
+
totalLinks += matchCount;
|
|
54
|
+
results.push({ path: filePath, links_updated: matchCount });
|
|
55
|
+
if (!dryRun) {
|
|
56
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { filesScanned: allFiles.length, filesUpdated: results.length, totalLinks, results };
|
|
61
|
+
}
|
|
62
|
+
export function registerUpdateLinks(server, vaultPath, vault) {
|
|
63
|
+
server.tool("update_links", "Update all wikilinks across vault after moving/renaming a file. Handles all link forms: stem, path, alias, heading, embed. Dry run by default.", {
|
|
64
|
+
old_path: z.string().describe("File path before the move/rename"),
|
|
65
|
+
new_path: z.string().describe("File path after the move/rename"),
|
|
66
|
+
dry_run: z.boolean().default(true).describe("Preview changes without writing (default: true)"),
|
|
67
|
+
}, async ({ old_path, new_path, dry_run }) => {
|
|
68
|
+
await vault.waitReady();
|
|
69
|
+
const result = await updateWikilinks(vaultPath, vault, old_path, new_path, dry_run);
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: JSON.stringify({
|
|
75
|
+
old_path,
|
|
76
|
+
new_path,
|
|
77
|
+
files_scanned: result.filesScanned,
|
|
78
|
+
files_updated: result.filesUpdated,
|
|
79
|
+
total_links_updated: result.totalLinks,
|
|
80
|
+
dry_run,
|
|
81
|
+
results: result.results,
|
|
82
|
+
}, null, 2),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=update-links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-links.js","sourceRoot":"","sources":["../../../src/tools/links/update-links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { VaultIndex } from "../../vault-index.js";
|
|
3
|
+
interface ParsedFrontmatter {
|
|
4
|
+
frontmatter: Record<string, any>;
|
|
5
|
+
body: string;
|
|
6
|
+
hasFrontmatter: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function parseFrontmatter(content: string): ParsedFrontmatter;
|
|
9
|
+
export declare function serializeFrontmatter(fm: Record<string, any>): string;
|
|
10
|
+
export declare function registerFrontmatter(server: McpServer, vaultPath: string, vault: VaultIndex): void;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/tools/metadata/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,UAAU,iBAAiB;IACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CA6DnE;AAUD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAUpE;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,GAChB,IAAI,CA+HN"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export function parseFrontmatter(content) {
|
|
5
|
+
// Normalize CRLF → LF for cross-platform compatibility
|
|
6
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
7
|
+
const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
8
|
+
if (!match)
|
|
9
|
+
return { frontmatter: {}, body: content, hasFrontmatter: false };
|
|
10
|
+
const fm = {};
|
|
11
|
+
let currentKey = null;
|
|
12
|
+
let listItems = [];
|
|
13
|
+
let inList = false;
|
|
14
|
+
for (const line of match[1].split("\n")) {
|
|
15
|
+
// YAML list item (- value)
|
|
16
|
+
if (inList && /^\s+-\s+(.*)$/.test(line)) {
|
|
17
|
+
const itemMatch = line.match(/^\s+-\s+(.*)$/);
|
|
18
|
+
if (itemMatch) {
|
|
19
|
+
listItems.push(parseYamlValue(itemMatch[1].trim()));
|
|
20
|
+
}
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
// If we were collecting list items, save them
|
|
24
|
+
if (inList && currentKey) {
|
|
25
|
+
fm[currentKey] = listItems;
|
|
26
|
+
inList = false;
|
|
27
|
+
listItems = [];
|
|
28
|
+
currentKey = null;
|
|
29
|
+
}
|
|
30
|
+
const kv = line.match(/^([\w][\w-]*):\s*(.*)$/);
|
|
31
|
+
if (!kv)
|
|
32
|
+
continue;
|
|
33
|
+
const key = kv[1];
|
|
34
|
+
const rawValue = kv[2].trim();
|
|
35
|
+
// Check if this is the start of a YAML list
|
|
36
|
+
if (rawValue === "") {
|
|
37
|
+
currentKey = key;
|
|
38
|
+
inList = true;
|
|
39
|
+
listItems = [];
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Inline array: [val1, val2]
|
|
43
|
+
if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
|
|
44
|
+
fm[key] = rawValue
|
|
45
|
+
.slice(1, -1)
|
|
46
|
+
.split(",")
|
|
47
|
+
.map((v) => parseYamlValue(v.trim()))
|
|
48
|
+
.filter((v) => v !== "");
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
fm[key] = parseYamlValue(rawValue);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Final list collection
|
|
55
|
+
if (inList && currentKey) {
|
|
56
|
+
fm[currentKey] = listItems;
|
|
57
|
+
}
|
|
58
|
+
return { frontmatter: fm, body: match[2], hasFrontmatter: true };
|
|
59
|
+
}
|
|
60
|
+
function parseYamlValue(value) {
|
|
61
|
+
if (/^\d+(\.\d+)?$/.test(value))
|
|
62
|
+
return Number(value);
|
|
63
|
+
if (value === "true")
|
|
64
|
+
return true;
|
|
65
|
+
if (value === "false")
|
|
66
|
+
return false;
|
|
67
|
+
// Strip surrounding quotes
|
|
68
|
+
return value.replace(/^["']|["']$/g, "");
|
|
69
|
+
}
|
|
70
|
+
export function serializeFrontmatter(fm) {
|
|
71
|
+
const lines = [];
|
|
72
|
+
for (const [key, value] of Object.entries(fm)) {
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
lines.push(`${key}: [${value.join(", ")}]`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
lines.push(`${key}: ${value}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return `---\n${lines.join("\n")}\n---`;
|
|
81
|
+
}
|
|
82
|
+
export function registerFrontmatter(server, vaultPath, vault) {
|
|
83
|
+
server.tool("frontmatter", "Read/write/merge YAML frontmatter as structured data. No string parsing needed. Actions: read, set, merge, delete_keys.", {
|
|
84
|
+
path: z.string().describe("File path or stem"),
|
|
85
|
+
action: z.enum(["read", "set", "merge", "delete_keys"]).describe("Operation to perform"),
|
|
86
|
+
data: z.record(z.string(), z.any()).optional().describe("Data for set/merge actions"),
|
|
87
|
+
keys: z.array(z.string()).optional().describe("Keys to remove for delete_keys action"),
|
|
88
|
+
}, async ({ path: filePath, action, data, keys }) => {
|
|
89
|
+
await vault.waitReady();
|
|
90
|
+
const resolved = vault.resolve(filePath);
|
|
91
|
+
const rel = resolved?.rel ?? filePath;
|
|
92
|
+
const fullPath = path.join(vaultPath, rel);
|
|
93
|
+
let content;
|
|
94
|
+
try {
|
|
95
|
+
content = await readFile(fullPath, "utf-8");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
if (action === "read") {
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: `ERROR: File not found: ${rel}` }],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// For write actions, start with empty content
|
|
105
|
+
content = "";
|
|
106
|
+
}
|
|
107
|
+
const parsed = parseFrontmatter(content);
|
|
108
|
+
switch (action) {
|
|
109
|
+
case "read": {
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: JSON.stringify({
|
|
115
|
+
path: rel,
|
|
116
|
+
frontmatter: parsed.frontmatter,
|
|
117
|
+
has_frontmatter: parsed.hasFrontmatter,
|
|
118
|
+
}, null, 2),
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
case "set": {
|
|
124
|
+
if (!data) {
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: "text", text: "ERROR: 'data' is required for 'set' action" }],
|
|
127
|
+
isError: true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const before = { ...parsed.frontmatter };
|
|
131
|
+
const newContent = serializeFrontmatter(data) + "\n" + parsed.body;
|
|
132
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
133
|
+
return {
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: "text",
|
|
137
|
+
text: JSON.stringify({ path: rel, action: "set", before, after: data }, null, 2),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case "merge": {
|
|
143
|
+
if (!data) {
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: "text", text: "ERROR: 'data' is required for 'merge' action" }],
|
|
146
|
+
isError: true,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const before = { ...parsed.frontmatter };
|
|
150
|
+
const merged = { ...parsed.frontmatter, ...data };
|
|
151
|
+
const newContent = serializeFrontmatter(merged) + "\n" + parsed.body;
|
|
152
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
153
|
+
return {
|
|
154
|
+
content: [
|
|
155
|
+
{
|
|
156
|
+
type: "text",
|
|
157
|
+
text: JSON.stringify({ path: rel, action: "merge", before, after: merged }, null, 2),
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
case "delete_keys": {
|
|
163
|
+
if (!keys || keys.length === 0) {
|
|
164
|
+
return {
|
|
165
|
+
content: [{ type: "text", text: "ERROR: 'keys' is required for 'delete_keys' action" }],
|
|
166
|
+
isError: true,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const before = { ...parsed.frontmatter };
|
|
170
|
+
const updated = { ...parsed.frontmatter };
|
|
171
|
+
for (const key of keys) {
|
|
172
|
+
delete updated[key];
|
|
173
|
+
}
|
|
174
|
+
const newContent = Object.keys(updated).length > 0
|
|
175
|
+
? serializeFrontmatter(updated) + "\n" + parsed.body
|
|
176
|
+
: parsed.body;
|
|
177
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
178
|
+
return {
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: "text",
|
|
182
|
+
text: JSON.stringify({ path: rel, action: "delete_keys", keys_deleted: keys, before, after: updated }, null, 2),
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../src/tools/metadata/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { VaultIndex } from "../../vault-index.js";
|
|
3
|
+
export declare function registerEditRegex(server: McpServer, vaultPath: string, vault: VaultIndex): void;
|
|
4
|
+
//# sourceMappingURL=edit-regex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-regex.d.ts","sourceRoot":"","sources":["../../../src/tools/notes/edit-regex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,GAChB,IAAI,CA+JN"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export function registerEditRegex(server, vaultPath, vault) {
|
|
5
|
+
server.tool("edit_regex", "Regex find-and-replace. Single file or grep-sub across a directory. Supports capture groups ($1, $2). Dry run by default.", {
|
|
6
|
+
path: z.string().optional().describe("Single file path (mutually exclusive with search_paths)"),
|
|
7
|
+
search_paths: z
|
|
8
|
+
.object({
|
|
9
|
+
directory: z.string().describe("Directory to search"),
|
|
10
|
+
recursive: z.boolean().default(false).describe("Include subdirectories"),
|
|
11
|
+
pattern_filter: z.string().default("*.md").describe("Glob pattern to filter files (default: *.md)"),
|
|
12
|
+
})
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Multi-file mode: search across directory"),
|
|
15
|
+
match: z.string().describe("Regex pattern to find"),
|
|
16
|
+
replace: z.string().describe("Replacement string ($1, $2 for capture groups)"),
|
|
17
|
+
flags: z.string().default("g").describe("Regex flags (default: 'g')"),
|
|
18
|
+
max_replacements: z.number().optional().describe("Safety cap: max replacements per file"),
|
|
19
|
+
dry_run: z.boolean().default(true).describe("Preview changes without writing (default: true)"),
|
|
20
|
+
}, async ({ path: filePath, search_paths, match, replace, flags, max_replacements, dry_run }) => {
|
|
21
|
+
await vault.waitReady();
|
|
22
|
+
// Validate regex
|
|
23
|
+
let regex;
|
|
24
|
+
try {
|
|
25
|
+
regex = new RegExp(match, flags);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: `ERROR: Invalid regex: ${err.message}` }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Build file list
|
|
34
|
+
let filePaths = [];
|
|
35
|
+
if (filePath) {
|
|
36
|
+
const resolved = vault.resolve(filePath);
|
|
37
|
+
filePaths = [resolved?.rel ?? filePath];
|
|
38
|
+
}
|
|
39
|
+
else if (search_paths) {
|
|
40
|
+
const dir = search_paths.directory;
|
|
41
|
+
let files = search_paths.recursive
|
|
42
|
+
? vault.searchPaths(dir === "." ? "" : dir)
|
|
43
|
+
: vault.listDir(dir);
|
|
44
|
+
// Apply glob filter
|
|
45
|
+
if (search_paths.pattern_filter && search_paths.pattern_filter !== "*") {
|
|
46
|
+
const extMatch = search_paths.pattern_filter.match(/^\*(\.\w+)$/);
|
|
47
|
+
if (extMatch) {
|
|
48
|
+
files = files.filter((f) => f.ext === extMatch[1]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
filePaths = files.map((f) => f.rel);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: "text", text: "ERROR: Provide either 'path' or 'search_paths'" }],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const results = [];
|
|
60
|
+
let totalMatches = 0;
|
|
61
|
+
let totalReplacements = 0;
|
|
62
|
+
// Ensure 'g' flag for matchAll
|
|
63
|
+
const matchAllFlags = flags.includes("g") ? flags : flags + "g";
|
|
64
|
+
const matchAllRegex = new RegExp(match, matchAllFlags);
|
|
65
|
+
for (const fp of filePaths) {
|
|
66
|
+
const fullPath = path.join(vaultPath, fp);
|
|
67
|
+
let content;
|
|
68
|
+
try {
|
|
69
|
+
content = await readFile(fullPath, "utf-8");
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// Skip binary-looking files
|
|
75
|
+
if (content.includes("\0"))
|
|
76
|
+
continue;
|
|
77
|
+
const matches = [...content.matchAll(matchAllRegex)];
|
|
78
|
+
if (matches.length === 0)
|
|
79
|
+
continue;
|
|
80
|
+
let effectiveMatches = matches;
|
|
81
|
+
if (max_replacements && matches.length > max_replacements) {
|
|
82
|
+
effectiveMatches = matches.slice(0, max_replacements);
|
|
83
|
+
}
|
|
84
|
+
const replacementsCount = effectiveMatches.length;
|
|
85
|
+
totalMatches += matches.length;
|
|
86
|
+
totalReplacements += replacementsCount;
|
|
87
|
+
// Generate preview (first 3 matches)
|
|
88
|
+
const singleRegex = new RegExp(match, flags.replace("g", ""));
|
|
89
|
+
const preview = effectiveMatches.slice(0, 3).map((m) => {
|
|
90
|
+
const start = Math.max(0, m.index - 30);
|
|
91
|
+
const end = Math.min(content.length, m.index + m[0].length + 30);
|
|
92
|
+
return {
|
|
93
|
+
original: m[0],
|
|
94
|
+
replaced: m[0].replace(singleRegex, replace),
|
|
95
|
+
context: content.slice(start, end),
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
results.push({
|
|
99
|
+
path: fp,
|
|
100
|
+
matches_found: matches.length,
|
|
101
|
+
replacements_made: replacementsCount,
|
|
102
|
+
preview,
|
|
103
|
+
});
|
|
104
|
+
if (!dry_run) {
|
|
105
|
+
let newContent;
|
|
106
|
+
if (max_replacements) {
|
|
107
|
+
// Limited replacements: replace only up to max
|
|
108
|
+
let count = 0;
|
|
109
|
+
newContent = content.replace(regex, (match, ...args) => {
|
|
110
|
+
if (count >= max_replacements)
|
|
111
|
+
return match;
|
|
112
|
+
count++;
|
|
113
|
+
// Reconstruct replacement with capture groups
|
|
114
|
+
return match.replace(singleRegex, replace);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
newContent = content.replace(regex, replace);
|
|
119
|
+
}
|
|
120
|
+
if (newContent !== content) {
|
|
121
|
+
await writeFile(fullPath, newContent, "utf-8");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
content: [
|
|
127
|
+
{
|
|
128
|
+
type: "text",
|
|
129
|
+
text: JSON.stringify({
|
|
130
|
+
files_searched: filePaths.length,
|
|
131
|
+
files_matched: results.length,
|
|
132
|
+
total_matches: totalMatches,
|
|
133
|
+
total_replacements: totalReplacements,
|
|
134
|
+
dry_run,
|
|
135
|
+
results,
|
|
136
|
+
}, null, 2),
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=edit-regex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-regex.js","sourceRoot":"","sources":["../../../src/tools/notes/edit-regex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown parsing utilities for search indexing.
|
|
3
|
+
* Strips syntax for BM25 scoring, extracts frontmatter and headings.
|
|
4
|
+
*/
|
|
5
|
+
export declare function stripMarkdown(content: string): string;
|
|
6
|
+
export declare function extractFrontmatter(content: string): {
|
|
7
|
+
tags: string;
|
|
8
|
+
aliases: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function extractHeadings(content: string): string;
|
|
11
|
+
export declare function extractSnippet(content: string, query: string, maxLength?: number): string;
|
|
12
|
+
//# sourceMappingURL=markdown-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-parser.d.ts","sourceRoot":"","sources":["../../../src/tools/search/markdown-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAerD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYrF;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,MAAM,CA6B9F"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown parsing utilities for search indexing.
|
|
3
|
+
* Strips syntax for BM25 scoring, extracts frontmatter and headings.
|
|
4
|
+
*/
|
|
5
|
+
export function stripMarkdown(content) {
|
|
6
|
+
return content
|
|
7
|
+
.replace(/^---[\s\S]*?---/m, "") // frontmatter
|
|
8
|
+
.replace(/```[\s\S]*?```/g, "") // code blocks
|
|
9
|
+
.replace(/`[^`]+`/g, "") // inline code
|
|
10
|
+
.replace(/!\[.*?\]\(.*?\)/g, "") // images
|
|
11
|
+
.replace(/\[([^\]]+)\]\(.*?\)/g, "$1") // links → text only
|
|
12
|
+
.replace(/#{1,6}\s/g, "") // heading markers
|
|
13
|
+
.replace(/[*_~]{1,3}/g, "") // bold/italic/strikethrough
|
|
14
|
+
.replace(/>\s/g, "") // blockquotes
|
|
15
|
+
.replace(/[-*+]\s/g, "") // list markers
|
|
16
|
+
.replace(/\d+\.\s/g, "") // numbered lists
|
|
17
|
+
.replace(/\|.*\|/g, "") // tables
|
|
18
|
+
.replace(/\n{3,}/g, "\n\n") // collapse newlines
|
|
19
|
+
.trim();
|
|
20
|
+
}
|
|
21
|
+
export function extractFrontmatter(content) {
|
|
22
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
23
|
+
if (!match)
|
|
24
|
+
return { tags: "", aliases: "" };
|
|
25
|
+
const yaml = match[1];
|
|
26
|
+
const tagsMatch = yaml.match(/tags:\s*\[?(.*?)\]?\s*\n/);
|
|
27
|
+
const tags = tagsMatch ? tagsMatch[1].replace(/[,\[\]"']/g, " ").trim() : "";
|
|
28
|
+
const aliasMatch = yaml.match(/aliases:\s*\[?(.*?)\]?\s*\n/);
|
|
29
|
+
const aliases = aliasMatch ? aliasMatch[1].replace(/[,\[\]"']/g, " ").trim() : "";
|
|
30
|
+
return { tags, aliases };
|
|
31
|
+
}
|
|
32
|
+
export function extractHeadings(content) {
|
|
33
|
+
const headings = content.match(/^#{1,6}\s+(.+)$/gm);
|
|
34
|
+
return headings ? headings.map((h) => h.replace(/^#{1,6}\s+/, "")).join(" ") : "";
|
|
35
|
+
}
|
|
36
|
+
export function extractSnippet(content, query, maxLength = 200) {
|
|
37
|
+
const terms = query.toLowerCase().split(/\s+/);
|
|
38
|
+
const lower = content.toLowerCase();
|
|
39
|
+
let bestPos = 0;
|
|
40
|
+
let bestScore = 0;
|
|
41
|
+
// Sample positions rather than scanning every character
|
|
42
|
+
const step = Math.max(1, Math.floor(lower.length / 500));
|
|
43
|
+
for (let i = 0; i < lower.length; i += step) {
|
|
44
|
+
let score = 0;
|
|
45
|
+
for (const term of terms) {
|
|
46
|
+
const idx = lower.indexOf(term, i);
|
|
47
|
+
if (idx !== -1 && idx < i + maxLength)
|
|
48
|
+
score++;
|
|
49
|
+
}
|
|
50
|
+
if (score > bestScore) {
|
|
51
|
+
bestScore = score;
|
|
52
|
+
bestPos = i;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const start = Math.max(0, bestPos - 40);
|
|
56
|
+
const end = Math.min(content.length, start + maxLength);
|
|
57
|
+
let snippet = content.slice(start, end).replace(/\n/g, " ").trim();
|
|
58
|
+
if (start > 0)
|
|
59
|
+
snippet = "..." + snippet;
|
|
60
|
+
if (end < content.length)
|
|
61
|
+
snippet = snippet + "...";
|
|
62
|
+
return snippet;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=markdown-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../../src/tools/search/markdown-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,OAAO;SACX,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAS,cAAc;SACtD,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAW,cAAc;SACvD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAkB,cAAc;SACvD,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAU,SAAS;SAClD,OAAO,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAI,oBAAoB;SAC7D,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAiB,kBAAkB;SAC3D,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAc,4BAA4B;SACpE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAsB,cAAc;SACvD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAkB,eAAe;SACxD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAiB,iBAAiB;SACzD,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAkB,SAAS;SACjD,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAc,oBAAoB;SAC5D,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7E,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAElF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,KAAa,EAAE,YAAoB,GAAG;IACpF,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAEpC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,wDAAwD;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;IACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,SAAS;gBAAE,KAAK,EAAE,CAAC;QACjD,CAAC;QACD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAC;YAClB,OAAO,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,EAAE,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC;IACxD,IAAI,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAEnE,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IACzC,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM;QAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;IAEpD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|