gdrive.mjs
72 lines 2.8 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Google Drive import. Accepts a folder of Markdown files (e.g. from export, Takeout conversion, or sync script).
3 * One note per file; frontmatter: source: gdrive, source_id from filename or path.
4 */
5
6 import fs from 'fs';
7 import path from 'path';
8 import { writeNote } from '../write.mjs';
9 import { parseFrontmatterAndBody, normalizeSlug } from '../vault.mjs';
10
11 /**
12 * @param {string} input - Path to folder containing .md files
13 * @param {{ vaultPath: string, outputBase: string, project?: string, tags: string[], dryRun: boolean }} ctx
14 * @returns {Promise<{ imported: { path: string, source_id?: string }[], count: number }>}
15 */
16 export async function importGDrive(input, ctx) {
17 const { vaultPath, outputBase, project, tags, dryRun } = ctx;
18 const absInput = path.isAbsolute(input) ? input : path.resolve(process.cwd(), input);
19 if (!fs.existsSync(absInput)) {
20 throw new Error(`Input not found: ${input}. Use a folder of Markdown files (e.g. exported from Google Docs).`);
21 }
22 if (fs.statSync(absInput).isFile()) {
23 throw new Error('GDrive import expects a folder of .md files. Export Docs as Markdown or use a sync script, then pass the folder path.');
24 }
25
26 const files = [];
27 walkMarkdown(absInput, absInput, '', files);
28 if (files.length === 0) {
29 throw new Error('No .md files found in folder. Add Markdown files (e.g. from Google Docs export or pandoc conversion).');
30 }
31
32 const imported = [];
33 const now = new Date().toISOString().slice(0, 10);
34
35 for (const { fullPath, relPath } of files) {
36 const content = fs.readFileSync(fullPath, 'utf8');
37 const { frontmatter, body } = parseFrontmatterAndBody(content);
38 const date = (frontmatter.date && String(frontmatter.date).slice(0, 10)) || now;
39 const outputRel = path.join(outputBase, relPath).replace(/\\/g, '/');
40 const sourceId = frontmatter.source_id || path.basename(relPath, '.md');
41 const merged = {
42 ...frontmatter,
43 source: 'gdrive',
44 source_id: sourceId,
45 date,
46 ...(project && { project: normalizeSlug(project) }),
47 ...(tags.length && { tags }),
48 };
49
50 if (!dryRun) {
51 writeNote(vaultPath, outputRel, {
52 body,
53 frontmatter: Object.fromEntries(Object.entries(merged).filter(([, v]) => v !== undefined && v !== null && v !== '')),
54 });
55 }
56 imported.push({ path: outputRel, source_id: sourceId });
57 }
58
59 return { imported, count: imported.length };
60 }
61
62 function walkMarkdown(rootDir, dir, relDir, out) {
63 const entries = fs.readdirSync(dir, { withFileTypes: true });
64 for (const e of entries) {
65 const rel = relDir ? `${relDir}/${e.name}` : e.name;
66 if (e.isDirectory()) {
67 walkMarkdown(rootDir, path.join(dir, e.name), rel, out);
68 } else if (e.name.endsWith('.md')) {
69 out.push({ fullPath: path.join(dir, e.name), relPath: rel.replace(/\\/g, '/') });
70 }
71 }
72 }
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago