@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.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/config/brand.json +1 -1
  3. package/payload/platform/lib/obsidian-parser/dist/index.d.ts +98 -0
  4. package/payload/platform/lib/obsidian-parser/dist/index.d.ts.map +1 -0
  5. package/payload/platform/lib/obsidian-parser/dist/index.js +480 -0
  6. package/payload/platform/lib/obsidian-parser/dist/index.js.map +1 -0
  7. package/payload/platform/lib/obsidian-parser/src/index.ts +572 -0
  8. package/payload/platform/lib/obsidian-parser/tsconfig.json +8 -0
  9. package/payload/platform/neo4j/schema.cypher +6 -0
  10. package/payload/platform/package.json +2 -2
  11. package/payload/platform/plugins/.claude-plugin/marketplace.json +10 -0
  12. package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
  13. package/payload/platform/plugins/memory/PLUGIN.md +3 -0
  14. package/payload/platform/plugins/memory/mcp/dist/index.js +89 -2
  15. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +64 -1
  17. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +258 -0
  19. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  20. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts +127 -0
  21. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts.map +1 -0
  22. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js +477 -0
  23. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js.map +1 -0
  24. package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +8 -0
  25. package/payload/platform/plugins/notion-import/PLUGIN.md +27 -0
  26. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +110 -0
  27. package/payload/platform/plugins/notion-import/skills/notion-import/references/attachments.md +55 -0
  28. package/payload/platform/plugins/notion-import/skills/notion-import/references/databases.md +81 -0
  29. package/payload/platform/plugins/notion-import/skills/notion-import/references/page-tree.md +61 -0
  30. package/payload/platform/plugins/notion-import/skills/notion-import/references/workspace-export.md +41 -0
  31. package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +8 -0
  32. package/payload/platform/plugins/obsidian-import/PLUGIN.md +39 -0
  33. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +92 -0
  34. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/attachments.md +80 -0
  35. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +31 -0
  36. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/vault-structure.md +46 -0
  37. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/wikilinks.md +70 -0
  38. 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.