2026-06-21 17:04:44 -05:00
|
|
|
/**
|
2026-07-07 07:30:52 -05:00
|
|
|
* Copy docs/ tree into meshchatx/src/frontend/public/meshchatx-docs/ for in-app serving.
|
2026-06-21 17:04:44 -05:00
|
|
|
* Source of truth: docs/ at repo root.
|
2026-08-12 20:44:46 -05:00
|
|
|
* Agent guidance lives under .agents/ at repo root, not under docs/.
|
2026-06-21 17:04:44 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const fs = require("fs");
|
|
|
|
|
const path = require("path");
|
|
|
|
|
|
|
|
|
|
const root = path.resolve(__dirname, "..");
|
|
|
|
|
const srcDir = path.join(root, "docs");
|
|
|
|
|
const destDir = path.join(root, "meshchatx", "src", "frontend", "public", "meshchatx-docs");
|
|
|
|
|
|
2026-07-07 07:30:52 -05:00
|
|
|
const COPY_EXTENSIONS = new Set([".md", ".txt", ".json"]);
|
2026-08-12 20:44:46 -05:00
|
|
|
const SKIP_TOP_LEVEL_DIRS = new Set();
|
2026-07-07 07:30:52 -05:00
|
|
|
|
2026-07-10 00:57:53 -05:00
|
|
|
function walkSync(dir, callback, relBase = "") {
|
2026-07-07 07:30:52 -05:00
|
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
2026-07-10 00:57:53 -05:00
|
|
|
const rel = relBase ? path.join(relBase, entry.name) : entry.name;
|
|
|
|
|
if (!relBase && entry.isDirectory() && SKIP_TOP_LEVEL_DIRS.has(entry.name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-07-07 07:30:52 -05:00
|
|
|
const fullPath = path.join(dir, entry.name);
|
|
|
|
|
if (entry.isDirectory()) {
|
2026-07-10 00:57:53 -05:00
|
|
|
walkSync(fullPath, callback, rel);
|
2026-07-07 07:30:52 -05:00
|
|
|
} else {
|
|
|
|
|
callback(fullPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function relativeFromDocs(filePath) {
|
|
|
|
|
return path.relative(srcDir, filePath);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 17:04:44 -05:00
|
|
|
if (!fs.existsSync(srcDir)) {
|
|
|
|
|
console.error(`Missing docs directory: ${srcDir}`);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs.mkdirSync(destDir, { recursive: true });
|
|
|
|
|
|
2026-07-07 07:30:52 -05:00
|
|
|
const sourceRelPaths = new Set();
|
2026-06-21 17:04:44 -05:00
|
|
|
|
2026-07-07 07:30:52 -05:00
|
|
|
walkSync(srcDir, (filePath) => {
|
|
|
|
|
const ext = path.extname(filePath);
|
|
|
|
|
const base = path.basename(filePath);
|
|
|
|
|
if (base !== "manifest.json" && !COPY_EXTENSIONS.has(ext)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const rel = relativeFromDocs(filePath);
|
|
|
|
|
sourceRelPaths.add(rel);
|
|
|
|
|
const dest = path.join(destDir, rel);
|
|
|
|
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
|
|
|
const content = fs.readFileSync(filePath);
|
2026-06-21 17:04:44 -05:00
|
|
|
const prev = fs.existsSync(dest) ? fs.readFileSync(dest) : null;
|
|
|
|
|
if (!prev || !prev.equals(content)) {
|
|
|
|
|
fs.writeFileSync(dest, content);
|
2026-07-07 07:30:52 -05:00
|
|
|
console.log(`Synced meshchatx-docs/${rel.replace(/\\/g, "/")}`);
|
2026-06-21 17:04:44 -05:00
|
|
|
}
|
2026-07-07 07:30:52 -05:00
|
|
|
});
|
2026-06-21 17:04:44 -05:00
|
|
|
|
2026-07-07 07:30:52 -05:00
|
|
|
function walkDest(dir, relBase = "") {
|
|
|
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
|
|
|
const rel = relBase ? path.join(relBase, entry.name) : entry.name;
|
|
|
|
|
const full = path.join(dir, entry.name);
|
|
|
|
|
if (entry.isDirectory()) {
|
|
|
|
|
walkDest(full, rel);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const ext = path.extname(entry.name);
|
|
|
|
|
const base = entry.name;
|
|
|
|
|
if (base !== "manifest.json" && !COPY_EXTENSIONS.has(ext)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!sourceRelPaths.has(rel)) {
|
|
|
|
|
fs.unlinkSync(full);
|
|
|
|
|
console.log(`Removed stale meshchatx-docs/${rel.replace(/\\/g, "/")}`);
|
|
|
|
|
}
|
2026-06-21 17:04:44 -05:00
|
|
|
}
|
|
|
|
|
}
|
2026-07-07 07:30:52 -05:00
|
|
|
|
|
|
|
|
walkDest(destDir);
|