@rubytech/create-maxy-code 0.1.138 → 0.1.140
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/obsidian-parser/dist/index.d.ts +98 -0
- package/payload/platform/lib/obsidian-parser/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/obsidian-parser/dist/index.js +480 -0
- package/payload/platform/lib/obsidian-parser/dist/index.js.map +1 -0
- package/payload/platform/lib/obsidian-parser/src/index.ts +572 -0
- package/payload/platform/lib/obsidian-parser/tsconfig.json +8 -0
- package/payload/platform/neo4j/schema.cypher +6 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +10 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
- package/payload/platform/plugins/memory/PLUGIN.md +3 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +89 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +64 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +258 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts +127 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js +477 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js.map +1 -0
- package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/notion-import/PLUGIN.md +27 -0
- package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +110 -0
- package/payload/platform/plugins/notion-import/skills/notion-import/references/attachments.md +55 -0
- package/payload/platform/plugins/notion-import/skills/notion-import/references/databases.md +81 -0
- package/payload/platform/plugins/notion-import/skills/notion-import/references/page-tree.md +61 -0
- package/payload/platform/plugins/notion-import/skills/notion-import/references/workspace-export.md +41 -0
- package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/obsidian-import/PLUGIN.md +39 -0
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +92 -0
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/attachments.md +80 -0
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +31 -0
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/vault-structure.md +46 -0
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/wikilinks.md +70 -0
- package/payload/platform/templates/specialists/agents/database-operator.md +13 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { walkVault, buildVaultIndex, resolveWikilinkInVault, normalizeTag, makeImportId, } from "../../../../../lib/obsidian-parser/dist/index.js";
|
|
4
|
+
import { levenshtein } from "../../../../../lib/graph-mcp/dist/schema-cypher-parser.js";
|
|
5
|
+
import { getSession } from "../lib/neo4j.js";
|
|
6
|
+
import { memoryArchiveWrite, } from "./memory-archive-write.js";
|
|
7
|
+
const FUZZY_MATCH_THRESHOLD = 2;
|
|
8
|
+
const SUPPORTED_ATTACHMENT_MIME = {
|
|
9
|
+
".png": "image/png",
|
|
10
|
+
".jpg": "image/jpeg",
|
|
11
|
+
".jpeg": "image/jpeg",
|
|
12
|
+
".gif": "image/gif",
|
|
13
|
+
".webp": "image/webp",
|
|
14
|
+
".svg": "image/svg+xml",
|
|
15
|
+
".pdf": "application/pdf",
|
|
16
|
+
".mp3": "audio/mpeg",
|
|
17
|
+
".mp4": "video/mp4",
|
|
18
|
+
".mov": "video/quicktime",
|
|
19
|
+
".wav": "audio/wav",
|
|
20
|
+
".m4a": "audio/mp4",
|
|
21
|
+
".webm": "video/webm",
|
|
22
|
+
};
|
|
23
|
+
export async function obsidianVaultImport(params) {
|
|
24
|
+
const importId = params.importId ?? makeImportId();
|
|
25
|
+
const threshold = params.selectiveIngestThreshold ?? 100;
|
|
26
|
+
const startedMs = Date.now();
|
|
27
|
+
await assertExtractedDir(params.extractedDir);
|
|
28
|
+
const walkOpts = {
|
|
29
|
+
folderPrefixes: params.filters?.folderPrefixes,
|
|
30
|
+
tagFilter: params.filters?.tags?.map(normalizeTag),
|
|
31
|
+
modifiedSinceMs: toEpochMs(params.filters?.modifiedSince),
|
|
32
|
+
};
|
|
33
|
+
const allPages = await walkVault(params.extractedDir, {});
|
|
34
|
+
const pagesDiscovered = allPages.length;
|
|
35
|
+
// Re-walk with filters for the "eligible" set so the plan honours the
|
|
36
|
+
// operator's selective-ingest choices.
|
|
37
|
+
const eligiblePages = walkOpts.folderPrefixes || walkOpts.tagFilter || walkOpts.modifiedSinceMs
|
|
38
|
+
? await walkVault(params.extractedDir, walkOpts)
|
|
39
|
+
: allPages;
|
|
40
|
+
const vaultIndex = buildVaultIndex(eligiblePages);
|
|
41
|
+
const knownPaths = new Set(eligiblePages.map((p) => p.obsidianPath));
|
|
42
|
+
const session = getSession();
|
|
43
|
+
let resolved;
|
|
44
|
+
try {
|
|
45
|
+
resolved = await resolveAllWikilinks(eligiblePages, vaultIndex, knownPaths, params.accountId, session);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await session.close();
|
|
49
|
+
}
|
|
50
|
+
const tagCount = countDistinct(eligiblePages.flatMap((p) => p.tags.map(normalizeTag)));
|
|
51
|
+
const attachmentCount = countDistinct(eligiblePages.flatMap((p) => p.attachments.map((a) => a.resolvedPath)));
|
|
52
|
+
// Idempotency: query existing contentHashes for these paths and mark
|
|
53
|
+
// unchanged. Only the dry-run plan reports the count; the commit phase
|
|
54
|
+
// uses the same map to filter rows before write.
|
|
55
|
+
const idemSession = getSession();
|
|
56
|
+
let unchangedSet;
|
|
57
|
+
try {
|
|
58
|
+
unchangedSet = await findUnchangedPages(idemSession, params.accountId, eligiblePages);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await idemSession.close();
|
|
62
|
+
}
|
|
63
|
+
const ambiguities = resolved.ambiguities;
|
|
64
|
+
const plan = {
|
|
65
|
+
importId,
|
|
66
|
+
mode: params.mode,
|
|
67
|
+
pagesDiscovered,
|
|
68
|
+
pagesEligible: eligiblePages.length,
|
|
69
|
+
pagesUnchanged: unchangedSet.size,
|
|
70
|
+
wikilinks: {
|
|
71
|
+
page: resolved.counts.page,
|
|
72
|
+
entity: resolved.counts.entity,
|
|
73
|
+
stub: resolved.counts.stub,
|
|
74
|
+
ambiguous: ambiguities.length,
|
|
75
|
+
},
|
|
76
|
+
tagCount,
|
|
77
|
+
attachmentCount,
|
|
78
|
+
ambiguities,
|
|
79
|
+
selectiveIngestSuggested: eligiblePages.length > threshold &&
|
|
80
|
+
!walkOpts.folderPrefixes &&
|
|
81
|
+
!walkOpts.tagFilter &&
|
|
82
|
+
!walkOpts.modifiedSinceMs,
|
|
83
|
+
};
|
|
84
|
+
process.stderr.write(`[obsidian-import] event=dry-run-complete importId=${importId}` +
|
|
85
|
+
` pages=${eligiblePages.length} unchanged=${unchangedSet.size}` +
|
|
86
|
+
` wikilinks-page=${resolved.counts.page} wikilinks-entity=${resolved.counts.entity}` +
|
|
87
|
+
` wikilinks-stub=${resolved.counts.stub} wikilinks-ambiguous=${ambiguities.length}` +
|
|
88
|
+
` tags=${tagCount} attachments=${attachmentCount}` +
|
|
89
|
+
` ms=${Date.now() - startedMs}\n`);
|
|
90
|
+
if (params.mode === "dry-run")
|
|
91
|
+
return plan;
|
|
92
|
+
// Commit phase — refuse if unresolved ambiguities remain.
|
|
93
|
+
const resolutions = params.resolutions ?? {};
|
|
94
|
+
const missing = ambiguities.filter((a) => !(a.id in resolutions));
|
|
95
|
+
if (missing.length > 0) {
|
|
96
|
+
throw new Error(`obsidian-vault-import commit refused: ${missing.length} unresolved ambiguities. Re-run dry-run, surface to operator, supply resolutions.`);
|
|
97
|
+
}
|
|
98
|
+
const accountDir = resolveAccountDir(params.accountId);
|
|
99
|
+
const importArchiveDir = path.join(accountDir, "archive", "obsidian", importId);
|
|
100
|
+
await fs.mkdir(importArchiveDir, { recursive: true });
|
|
101
|
+
let attachmentsCopied = 0;
|
|
102
|
+
const rows = [];
|
|
103
|
+
for (const page of eligiblePages) {
|
|
104
|
+
if (unchangedSet.has(page.obsidianPath))
|
|
105
|
+
continue;
|
|
106
|
+
const pageWikilinks = resolveWithOverrides(page, resolved.byPage.get(page.obsidianPath) ?? [], resolutions);
|
|
107
|
+
const pageAttachments = await stageAttachments(page, params.extractedDir, importArchiveDir, (n) => {
|
|
108
|
+
attachmentsCopied += n;
|
|
109
|
+
});
|
|
110
|
+
rows.push({
|
|
111
|
+
obsidianPath: page.obsidianPath,
|
|
112
|
+
title: page.title,
|
|
113
|
+
aliases: page.aliases,
|
|
114
|
+
tags: page.tags.map(normalizeTag),
|
|
115
|
+
body: page.body,
|
|
116
|
+
contentHash: page.contentHash,
|
|
117
|
+
noteDate: page.noteDate,
|
|
118
|
+
mtimeMs: page.mtimeMs,
|
|
119
|
+
wikilinks: pageWikilinks,
|
|
120
|
+
attachments: pageAttachments,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
let written = {
|
|
124
|
+
createdPages: 0,
|
|
125
|
+
mergedPages: 0,
|
|
126
|
+
createdTags: 0,
|
|
127
|
+
createdTagEdges: 0,
|
|
128
|
+
createdAttachments: 0,
|
|
129
|
+
createdAttachmentEdges: 0,
|
|
130
|
+
createdWikilinkEdges: 0,
|
|
131
|
+
};
|
|
132
|
+
const errors = [];
|
|
133
|
+
if (rows.length > 0) {
|
|
134
|
+
const result = await memoryArchiveWrite({
|
|
135
|
+
archiveType: "obsidian-vault",
|
|
136
|
+
ownerNodeId: params.ownerNodeId,
|
|
137
|
+
accountId: params.accountId,
|
|
138
|
+
rows,
|
|
139
|
+
sessionId: params.sessionId,
|
|
140
|
+
});
|
|
141
|
+
written = {
|
|
142
|
+
createdPages: result.counters.createdPages ?? 0,
|
|
143
|
+
mergedPages: result.counters.mergedPages ?? 0,
|
|
144
|
+
createdTags: result.counters.createdTags ?? 0,
|
|
145
|
+
createdTagEdges: result.counters.createdTagEdges ?? 0,
|
|
146
|
+
createdAttachments: result.counters.createdAttachments ?? 0,
|
|
147
|
+
createdAttachmentEdges: result.counters.createdAttachmentEdges ?? 0,
|
|
148
|
+
createdWikilinkEdges: result.counters.createdWikilinkEdges ?? 0,
|
|
149
|
+
};
|
|
150
|
+
errors.push(...result.errors);
|
|
151
|
+
}
|
|
152
|
+
const elapsedMs = Date.now() - startedMs;
|
|
153
|
+
const observabilityTag = `[obsidian-import] event=commit-complete importId=${importId}` +
|
|
154
|
+
` pages=${eligiblePages.length} written=${rows.length} skipped=${unchangedSet.size}` +
|
|
155
|
+
` wikilinks=${written.createdWikilinkEdges} tags=${written.createdTags}` +
|
|
156
|
+
` attachments=${attachmentsCopied} errors=${errors.length} ms=${elapsedMs}`;
|
|
157
|
+
process.stderr.write(observabilityTag + "\n");
|
|
158
|
+
return {
|
|
159
|
+
...plan,
|
|
160
|
+
written,
|
|
161
|
+
attachmentsCopied,
|
|
162
|
+
errors,
|
|
163
|
+
observabilityTag,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Helpers
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
async function assertExtractedDir(extractedDir) {
|
|
170
|
+
if (!extractedDir || !path.isAbsolute(extractedDir)) {
|
|
171
|
+
throw new Error(`obsidian-vault-import: extractedDir must be an absolute path; got "${extractedDir}".`);
|
|
172
|
+
}
|
|
173
|
+
const stat = await fs.stat(extractedDir).catch(() => null);
|
|
174
|
+
if (!stat || !stat.isDirectory()) {
|
|
175
|
+
throw new Error(`obsidian-vault-import: extractedDir does not exist or is not a directory: ${extractedDir}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function toEpochMs(modifiedSince) {
|
|
179
|
+
if (!modifiedSince)
|
|
180
|
+
return undefined;
|
|
181
|
+
if (/^\d+$/.test(modifiedSince))
|
|
182
|
+
return Number.parseInt(modifiedSince, 10);
|
|
183
|
+
const t = Date.parse(modifiedSince);
|
|
184
|
+
return Number.isFinite(t) ? t : undefined;
|
|
185
|
+
}
|
|
186
|
+
function countDistinct(values) {
|
|
187
|
+
return new Set(values.filter(Boolean)).size;
|
|
188
|
+
}
|
|
189
|
+
function resolveAccountDir(accountId) {
|
|
190
|
+
// Same convention as memory plugin's attachment-store: lives under the
|
|
191
|
+
// configured DATA_ROOT/accounts/<accountId>/. If neither env is set we
|
|
192
|
+
// throw — fail loud rather than write attachments to an unexpected path.
|
|
193
|
+
const root = process.env.MAXY_DATA_ROOT ??
|
|
194
|
+
process.env.DATA_ROOT ??
|
|
195
|
+
process.env.PLATFORM_DATA_ROOT;
|
|
196
|
+
if (!root) {
|
|
197
|
+
throw new Error("obsidian-vault-import: data root env (MAXY_DATA_ROOT / DATA_ROOT / PLATFORM_DATA_ROOT) is not set; cannot resolve attachment archive directory.");
|
|
198
|
+
}
|
|
199
|
+
return path.join(root, "accounts", accountId);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Build the resolution plan for every wikilink in every eligible page.
|
|
203
|
+
*
|
|
204
|
+
* Resolution order:
|
|
205
|
+
* 1. Intra-vault page (title or alias) — if unique, page target.
|
|
206
|
+
* 2. Existing entity fuzzy match against :Person/:Organization/:Concept
|
|
207
|
+
* with name distance ≤ FUZZY_MATCH_THRESHOLD — if unique, entity target.
|
|
208
|
+
* 3. Otherwise, stub target (the handler creates a :Concept stub at write).
|
|
209
|
+
*
|
|
210
|
+
* Ambiguity: both an intra-vault page AND an existing entity match; or
|
|
211
|
+
* multiple intra-vault candidates; or ≥2 entity candidates within
|
|
212
|
+
* threshold. Stub-only matches are NOT ambiguities — we simply create the
|
|
213
|
+
* stub.
|
|
214
|
+
*/
|
|
215
|
+
async function resolveAllWikilinks(pages, index, knownPaths, accountId, session) {
|
|
216
|
+
const distinctTargets = new Set();
|
|
217
|
+
for (const p of pages) {
|
|
218
|
+
for (const wl of p.wikilinks)
|
|
219
|
+
distinctTargets.add(wl.target);
|
|
220
|
+
}
|
|
221
|
+
const entityIndex = await loadEntityIndex(session, accountId, distinctTargets);
|
|
222
|
+
const byPage = new Map();
|
|
223
|
+
const ambiguities = [];
|
|
224
|
+
const counts = { page: 0, entity: 0, stub: 0 };
|
|
225
|
+
let ambiguityCounter = 0;
|
|
226
|
+
for (const page of pages) {
|
|
227
|
+
const resolved = [];
|
|
228
|
+
for (const wl of page.wikilinks) {
|
|
229
|
+
const pageHits = resolveWikilinkInVault(wl.target, index, knownPaths);
|
|
230
|
+
const entityHits = lookupEntities(wl.target, entityIndex);
|
|
231
|
+
const decision = decideResolution(wl, pageHits, entityHits);
|
|
232
|
+
if (decision.kind === "ambiguous") {
|
|
233
|
+
ambiguityCounter++;
|
|
234
|
+
const id = `amb-${ambiguityCounter}`;
|
|
235
|
+
ambiguities.push({
|
|
236
|
+
id,
|
|
237
|
+
fromPath: page.obsidianPath,
|
|
238
|
+
target: wl.target,
|
|
239
|
+
pageCandidates: decision.pageCandidates,
|
|
240
|
+
entityCandidates: decision.entityCandidates,
|
|
241
|
+
});
|
|
242
|
+
// Provisional resolution for the dry-run summary: stub, until
|
|
243
|
+
// the operator decides. The commit phase overrides via resolutions.
|
|
244
|
+
resolved.push(toResolvedWikilink(wl, { kind: "stub", name: wl.target }, id));
|
|
245
|
+
counts.stub++;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
resolved.push(toResolvedWikilink(wl, decision.target));
|
|
249
|
+
counts[decision.target.kind]++;
|
|
250
|
+
}
|
|
251
|
+
byPage.set(page.obsidianPath, resolved);
|
|
252
|
+
}
|
|
253
|
+
return { byPage, ambiguities, counts };
|
|
254
|
+
}
|
|
255
|
+
async function loadEntityIndex(session, accountId, distinctTargets) {
|
|
256
|
+
if (distinctTargets.size === 0) {
|
|
257
|
+
return { byName: new Map(), allNames: [] };
|
|
258
|
+
}
|
|
259
|
+
const result = await session.run(`MATCH (n)
|
|
260
|
+
WHERE n.accountId = $accountId
|
|
261
|
+
AND (n:Person OR n:Organization OR n:Concept)
|
|
262
|
+
AND NOT n:Trashed
|
|
263
|
+
AND n.name IS NOT NULL
|
|
264
|
+
RETURN elementId(n) AS nodeId, labels(n) AS labels, n.name AS name
|
|
265
|
+
LIMIT 50000`, { accountId });
|
|
266
|
+
const allNames = [];
|
|
267
|
+
const byName = new Map();
|
|
268
|
+
for (const rec of result.records) {
|
|
269
|
+
const labels = rec.get("labels");
|
|
270
|
+
const primary = labels.find((l) => l === "Person" || l === "Organization" || l === "Concept") ?? labels[0];
|
|
271
|
+
const entry = {
|
|
272
|
+
nodeId: rec.get("nodeId"),
|
|
273
|
+
label: primary,
|
|
274
|
+
name: rec.get("name"),
|
|
275
|
+
};
|
|
276
|
+
allNames.push(entry);
|
|
277
|
+
const key = entry.name.toLowerCase();
|
|
278
|
+
const arr = byName.get(key);
|
|
279
|
+
if (arr)
|
|
280
|
+
arr.push(entry);
|
|
281
|
+
else
|
|
282
|
+
byName.set(key, [entry]);
|
|
283
|
+
}
|
|
284
|
+
return { byName, allNames };
|
|
285
|
+
}
|
|
286
|
+
function lookupEntities(target, index) {
|
|
287
|
+
const t = target.toLowerCase().trim();
|
|
288
|
+
if (!t)
|
|
289
|
+
return [];
|
|
290
|
+
const exact = index.byName.get(t);
|
|
291
|
+
if (exact && exact.length > 0) {
|
|
292
|
+
return exact.map((e) => ({ ...e, distance: 0 }));
|
|
293
|
+
}
|
|
294
|
+
const out = [];
|
|
295
|
+
for (const entry of index.allNames) {
|
|
296
|
+
const d = levenshtein(t, entry.name.toLowerCase());
|
|
297
|
+
if (d <= FUZZY_MATCH_THRESHOLD) {
|
|
298
|
+
out.push({ ...entry, distance: d });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
out.sort((a, b) => a.distance - b.distance);
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
function decideResolution(wl, pageHits, entityHits) {
|
|
305
|
+
// Exact entity (distance 0) is treated as a strong hit alongside any page hit.
|
|
306
|
+
const exactEntities = entityHits.filter((e) => e.distance === 0);
|
|
307
|
+
if (pageHits.length === 1 && exactEntities.length === 0 && entityHits.length === 0) {
|
|
308
|
+
return { kind: "resolved", target: { kind: "page", obsidianPath: pageHits[0] } };
|
|
309
|
+
}
|
|
310
|
+
if (pageHits.length === 0 && exactEntities.length === 1) {
|
|
311
|
+
return {
|
|
312
|
+
kind: "resolved",
|
|
313
|
+
target: { kind: "entity", nodeId: exactEntities[0].nodeId, nodeLabel: exactEntities[0].label },
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
// Two or more competing categories or candidates → ambiguous.
|
|
317
|
+
if (pageHits.length >= 1 && exactEntities.length >= 1) {
|
|
318
|
+
return { kind: "ambiguous", pageCandidates: pageHits, entityCandidates: entityHits };
|
|
319
|
+
}
|
|
320
|
+
if (pageHits.length >= 2) {
|
|
321
|
+
return { kind: "ambiguous", pageCandidates: pageHits, entityCandidates: [] };
|
|
322
|
+
}
|
|
323
|
+
if (exactEntities.length >= 2) {
|
|
324
|
+
return { kind: "ambiguous", pageCandidates: [], entityCandidates: exactEntities };
|
|
325
|
+
}
|
|
326
|
+
// Only fuzzy entity matches (distance > 0). Single fuzzy hit → resolve.
|
|
327
|
+
// Multiple fuzzy hits → ambiguous.
|
|
328
|
+
if (pageHits.length === 0 && entityHits.length === 1) {
|
|
329
|
+
return {
|
|
330
|
+
kind: "resolved",
|
|
331
|
+
target: { kind: "entity", nodeId: entityHits[0].nodeId, nodeLabel: entityHits[0].label },
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (pageHits.length === 0 && entityHits.length >= 2) {
|
|
335
|
+
return { kind: "ambiguous", pageCandidates: [], entityCandidates: entityHits };
|
|
336
|
+
}
|
|
337
|
+
// No hits anywhere → stub.
|
|
338
|
+
return { kind: "resolved", target: { kind: "stub", name: wl.target } };
|
|
339
|
+
}
|
|
340
|
+
function toResolvedWikilink(wl, target, ambiguityId) {
|
|
341
|
+
return {
|
|
342
|
+
linkText: wl.target,
|
|
343
|
+
alias: wl.alias,
|
|
344
|
+
anchor: wl.anchor,
|
|
345
|
+
target,
|
|
346
|
+
...(ambiguityId ? { _ambiguityId: ambiguityId } : {}),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function resolveWithOverrides(page, resolvedForPage, resolutions) {
|
|
350
|
+
return resolvedForPage.map((wl) => {
|
|
351
|
+
const tagged = wl;
|
|
352
|
+
if (!tagged._ambiguityId)
|
|
353
|
+
return wl;
|
|
354
|
+
const decision = resolutions[tagged._ambiguityId];
|
|
355
|
+
if (!decision)
|
|
356
|
+
return wl;
|
|
357
|
+
if (decision.kind === "page") {
|
|
358
|
+
return { ...wl, target: { kind: "page", obsidianPath: decision.obsidianPath } };
|
|
359
|
+
}
|
|
360
|
+
if (decision.kind === "entity") {
|
|
361
|
+
// nodeLabel is not strictly required by the Cypher (elementId scopes
|
|
362
|
+
// by accountId guard); pass empty string when not known.
|
|
363
|
+
return { ...wl, target: { kind: "entity", nodeId: decision.nodeId, nodeLabel: "" } };
|
|
364
|
+
}
|
|
365
|
+
return { ...wl, target: { kind: "stub", name: wl.linkText } };
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
async function findUnchangedPages(session, accountId, pages) {
|
|
369
|
+
if (pages.length === 0)
|
|
370
|
+
return new Set();
|
|
371
|
+
const payload = pages.map((p) => ({
|
|
372
|
+
obsidianPath: p.obsidianPath,
|
|
373
|
+
contentHash: p.contentHash,
|
|
374
|
+
}));
|
|
375
|
+
const result = await session.run(`UNWIND $payload AS row
|
|
376
|
+
MATCH (k:KnowledgeDocument {accountId: $accountId, obsidianPath: row.obsidianPath})
|
|
377
|
+
WHERE k.contentHash = row.contentHash AND NOT k:Trashed
|
|
378
|
+
RETURN k.obsidianPath AS p`, { accountId, payload });
|
|
379
|
+
const out = new Set();
|
|
380
|
+
for (const rec of result.records)
|
|
381
|
+
out.add(rec.get("p"));
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
async function stageAttachments(page, vaultRoot, importArchiveDir, onCopied) {
|
|
385
|
+
const staged = [];
|
|
386
|
+
const seen = new Set();
|
|
387
|
+
for (const att of page.attachments) {
|
|
388
|
+
if (seen.has(att.resolvedPath))
|
|
389
|
+
continue;
|
|
390
|
+
seen.add(att.resolvedPath);
|
|
391
|
+
const src = await findAttachmentSource(vaultRoot, page.obsidianPath, att);
|
|
392
|
+
if (!src) {
|
|
393
|
+
process.stderr.write(`[obsidian-import] event=attachment-missing page=${page.obsidianPath} path=${att.resolvedPath}\n`);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
const safeName = sanitizeArchiveName(src.relPath);
|
|
397
|
+
const dest = path.join(importArchiveDir, safeName);
|
|
398
|
+
const destDir = path.dirname(dest);
|
|
399
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
400
|
+
try {
|
|
401
|
+
await fs.copyFile(src.absPath, dest);
|
|
402
|
+
onCopied(1);
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
process.stderr.write(`[obsidian-import] event=attachment-copy-failed page=${page.obsidianPath} path=${att.resolvedPath} reason=${err instanceof Error ? err.message : String(err)}\n`);
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const ext = path.extname(src.relPath).toLowerCase();
|
|
409
|
+
staged.push({
|
|
410
|
+
rawPath: att.rawPath,
|
|
411
|
+
archivePath: dest,
|
|
412
|
+
encodingFormat: SUPPORTED_ATTACHMENT_MIME[ext] ?? "application/octet-stream",
|
|
413
|
+
alt: att.alt,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
return staged;
|
|
417
|
+
}
|
|
418
|
+
async function findAttachmentSource(vaultRoot, pagePath, att) {
|
|
419
|
+
// 1. Vault-root-relative as written.
|
|
420
|
+
const candidates = [att.resolvedPath];
|
|
421
|
+
// 2. Page-relative.
|
|
422
|
+
candidates.push(path.posix.join(path.posix.dirname(pagePath), att.resolvedPath));
|
|
423
|
+
for (const rel of candidates) {
|
|
424
|
+
const abs = path.join(vaultRoot, rel.split("/").join(path.sep));
|
|
425
|
+
try {
|
|
426
|
+
const stat = await fs.stat(abs);
|
|
427
|
+
if (stat.isFile())
|
|
428
|
+
return { absPath: abs, relPath: rel };
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
// try next candidate
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// 3. Bare filename — search the vault for a single match (typical when
|
|
435
|
+
// operator stores attachments in a default folder Obsidian inserts by name).
|
|
436
|
+
const basename = path.posix.basename(att.resolvedPath);
|
|
437
|
+
if (!basename.includes("/")) {
|
|
438
|
+
const hit = await searchByBasename(vaultRoot, basename);
|
|
439
|
+
if (hit)
|
|
440
|
+
return hit;
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
async function searchByBasename(root, basename) {
|
|
445
|
+
const queue = [root];
|
|
446
|
+
while (queue.length > 0) {
|
|
447
|
+
const dir = queue.shift();
|
|
448
|
+
let entries;
|
|
449
|
+
try {
|
|
450
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
for (const entry of entries) {
|
|
456
|
+
if (entry.name.startsWith("."))
|
|
457
|
+
continue;
|
|
458
|
+
const abs = path.join(dir, entry.name);
|
|
459
|
+
if (entry.isDirectory()) {
|
|
460
|
+
queue.push(abs);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (entry.isFile() && entry.name === basename) {
|
|
464
|
+
const rel = path.relative(root, abs).split(path.sep).join("/");
|
|
465
|
+
return { absPath: abs, relPath: rel };
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
function sanitizeArchiveName(rel) {
|
|
472
|
+
return rel
|
|
473
|
+
.split("/")
|
|
474
|
+
.filter((seg) => seg && seg !== "." && seg !== "..")
|
|
475
|
+
.join("/");
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=obsidian-vault-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obsidian-vault-import.js","sourceRoot":"","sources":["../../src/tools/obsidian-vault-import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "notion-import",
|
|
3
|
+
"description": "Import a Notion workspace export (markdown + CSV directory) into the Maxy Neo4j graph. Skill-only plugin owned by the database-operator specialist. Opt-in per brand — not enabled by default.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Rubytech LLC"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: notion-import
|
|
3
|
+
description: "Import a Notion workspace export (markdown + CSV directory) into the Maxy Neo4j graph. Skill-only plugin owned by the database-operator specialist. Opt-in per brand — not enabled by default."
|
|
4
|
+
tools: []
|
|
5
|
+
always: false
|
|
6
|
+
embed: false
|
|
7
|
+
specialist: database-operator
|
|
8
|
+
metadata: {"platform":{"optional":true,"pluginKey":"notion-import"}}
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Notion Import
|
|
12
|
+
|
|
13
|
+
Ingests a Notion workspace export (the native "Export all workspace content" markdown + CSV dump) into the Maxy Neo4j graph. Skill-only plugin — no MCP server, no admin tools added. The skill runs under `specialists:database-operator`, which owns graph-write delegation from admin.
|
|
14
|
+
|
|
15
|
+
## When this applies
|
|
16
|
+
|
|
17
|
+
The admin agent delegates to `specialists:database-operator` when the operator drops a Notion export directory (or zip path) into chat and asks to import it. The specialist runs the skill's import-provenance confirmation flow before any page or row is read, then walks the export.
|
|
18
|
+
|
|
19
|
+
## Intra-plugin growth
|
|
20
|
+
|
|
21
|
+
A Notion export contains pages (`.md`), databases (CSV pairs — schema CSV plus rows CSV), nested page subdirectories, and an `attachments/` tree. The skill ships four references covering the four shapes the export expresses — workspace traversal, database parsing, page-tree hierarchy, attachment copy. Per-database-type references land here as new files under `references/` as operators surface new shapes; they do not become new plugins.
|
|
22
|
+
|
|
23
|
+
## Relationship to other plugins
|
|
24
|
+
|
|
25
|
+
- **memory** — the underlying Cypher-write surface used by the skill (`memory-write`, `memory-update`, `memory-search`). Every node carries `source='notion'` + `createdByAgent='notion-import'` for provenance.
|
|
26
|
+
- **database-operator specialist** — owns execution. See the delegation clause in [database-operator.md](../../templates/specialists/agents/database-operator.md).
|
|
27
|
+
- **linkedin-import** — sibling skill-only import plugin (different specialist owner — `librarian` predates the database-operator delegation doctrine). The two plugins share no code.
|