seed-vault-dir-to-hub.mjs
112 lines 3.6 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 2 days ago
1 #!/usr/bin/env node
2 /**
3 * Upload all Markdown files under a vault subdirectory to a Hub backend (local Node Hub or hosted gateway → canister).
4 *
5 * Usage (from repo root):
6 * KNOWTATION_HUB_URL="http://localhost:3333" KNOWTATION_HUB_TOKEN="<jwt>" npm run seed:hosted-showcase
7 * KNOWTATION_HUB_URL="https://knowtation-gateway.netlify.app" KNOWTATION_HUB_TOKEN="<jwt>" npm run seed:hosted-showcase
8 *
9 * Optional:
10 * KNOWTATION_SEED_DIR=showcase/other — folder under vault/ (default: showcase)
11 * KNOWTATION_VAULT_ID=default — X-Vault-Id header (default: default)
12 *
13 * JWT: after login, copy from localStorage hub_token or from ?token= in the URL.
14 */
15 import { readdir, readFile, stat } from 'fs/promises';
16 import path from 'path';
17 import { fileURLToPath } from 'url';
18
19 const __dirname = path.dirname(fileURLToPath(import.meta.url));
20 const REPO_ROOT = path.join(__dirname, '..');
21 const VAULT_ROOT = path.join(REPO_ROOT, 'vault');
22
23 const hubUrl = (process.env.KNOWTATION_HUB_URL || process.env.HUB_URL || '').replace(/\/$/, '');
24 const token = process.env.KNOWTATION_HUB_TOKEN || process.env.HUB_TOKEN || '';
25 const vaultId = process.env.KNOWTATION_VAULT_ID || 'default';
26 const subdir = (process.env.KNOWTATION_SEED_DIR || process.argv[2] || 'showcase').replace(/^\/+|\/+$/g, '');
27
28 if (!hubUrl) {
29 console.error('Missing KNOWTATION_HUB_URL (e.g. http://localhost:3333 or https://knowtation-gateway.netlify.app)');
30 process.exit(2);
31 }
32 if (!token) {
33 console.error('Missing KNOWTATION_HUB_TOKEN (JWT from Hub after login)');
34 process.exit(2);
35 }
36
37 const sourceDir = path.join(VAULT_ROOT, subdir);
38 try {
39 const st = await stat(sourceDir);
40 if (!st.isDirectory()) {
41 console.error(`Not a directory: ${sourceDir}`);
42 process.exit(2);
43 }
44 } catch {
45 console.error(`Missing folder: ${sourceDir}`);
46 process.exit(2);
47 }
48
49 /** @returns {AsyncGenerator<string>} */
50 async function* walkMd(dir) {
51 const entries = await readdir(dir, { withFileTypes: true });
52 entries.sort((a, b) => a.name.localeCompare(b.name));
53 for (const e of entries) {
54 if (e.name.startsWith('.')) continue;
55 const full = path.join(dir, e.name);
56 if (e.isDirectory()) yield* walkMd(full);
57 else if (e.isFile() && e.name.endsWith('.md')) yield full;
58 }
59 }
60
61 /** @param {string} fileAbs */
62 function vaultRelativePath(fileAbs) {
63 const rel = path.relative(VAULT_ROOT, fileAbs);
64 if (rel.startsWith('..')) {
65 throw new Error(`Path outside vault: ${fileAbs}`);
66 }
67 return rel.split(path.sep).join('/');
68 }
69
70 /**
71 * @param {string} notePath
72 * @param {string} body
73 */
74 async function postNote(notePath, body) {
75 const headers = {
76 Authorization: `Bearer ${token}`,
77 'Content-Type': 'application/json',
78 'X-Vault-Id': vaultId,
79 };
80 const r = await fetch(`${hubUrl}/api/v1/notes`, {
81 method: 'POST',
82 headers,
83 body: JSON.stringify({ path: notePath, body }),
84 });
85 const text = await r.text();
86 if (!r.ok) {
87 throw new Error(`POST /api/v1/notes failed (${r.status}) for ${notePath}: ${text}`);
88 }
89 return text;
90 }
91
92 const paths = [];
93 for await (const file of walkMd(sourceDir)) {
94 paths.push(file);
95 }
96
97 if (paths.length === 0) {
98 console.error(`No .md files under ${sourceDir}`);
99 process.exit(1);
100 }
101
102 console.log(`Seeding ${paths.length} note(s) from vault/${subdir}/ → ${hubUrl} (vault_id=${vaultId})`);
103
104 for (const file of paths) {
105 const notePath = vaultRelativePath(file);
106 process.stdout.write(` ${notePath} ... `);
107 const body = await readFile(file, 'utf8');
108 await postNote(notePath, body);
109 process.stdout.write('ok\n');
110 }
111
112 console.log('\nDone. Open the Hub → Notes and browse the showcase folder.');
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 2 days ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 2 days ago