diff --git a/scripts/build-portal-runtime.mjs b/scripts/build-portal-runtime.mjs
index f0ccda5..0ea8ddb 100755
--- a/scripts/build-portal-runtime.mjs
+++ b/scripts/build-portal-runtime.mjs
@@ -235,10 +235,6 @@ async function copyMindspacePublicLinkTools() {
path.join(root, 'scripts', 'repair-mindspace-public-downloads.mjs'),
path.join(runtimeRoot, 'scripts', 'repair-mindspace-public-downloads.mjs'),
);
- await fs.copyFile(
- path.join(root, 'mindspace-public-finish-sync.mjs'),
- path.join(runtimeRoot, 'mindspace-public-finish-sync.mjs'),
- );
}
async function writeMetadata() {
diff --git a/scripts/repair-mindspace-public-downloads.mjs b/scripts/repair-mindspace-public-downloads.mjs
index 575d0c1..19e6126 100755
--- a/scripts/repair-mindspace-public-downloads.mjs
+++ b/scripts/repair-mindspace-public-downloads.mjs
@@ -1,29 +1,32 @@
#!/usr/bin/env node
/**
* Repair missing public/*.docx download targets before release link checks.
- * 1) sync from oa/ when a safe source exists
- * 2) remove broken docx anchors from HTML when no source is available
+ * Runtime-safe: no imports from the full MindSpace finish-sync graph.
*/
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
-import { syncPublicDocxDownloads } from '../mindspace-public-finish-sync.mjs';
const DOCX_HREF_RE = /]*\bhref=(["'])([^"']+\.docx)\1[^>]*>[\s\S]*?<\/a>/gi;
const DOCX_HREF_CAPTURE_RE = /]*\bhref=(["'])([^"']+\.docx)\1/gi;
-function listMissingDocxTargets(html, publicDir) {
- const missing = new Set();
+function listDocxHrefBasenames(html) {
+ const basenames = new Set();
let match = DOCX_HREF_CAPTURE_RE.exec(html);
while (match) {
- const docxPath = path.resolve(publicDir, path.basename(String(match[2] ?? '')));
- if (!fs.existsSync(docxPath)) {
- missing.add(path.basename(docxPath).toLowerCase());
- }
+ const base = path.basename(String(match[2] ?? '')).trim();
+ if (base) basenames.add(base);
match = DOCX_HREF_CAPTURE_RE.exec(html);
}
DOCX_HREF_CAPTURE_RE.lastIndex = 0;
- return [...missing];
+ return [...basenames];
+}
+
+function listMissingDocxTargets(html, publicDir) {
+ return listDocxHrefBasenames(html).filter((basename) => {
+ const docxPath = path.join(publicDir, basename);
+ return !fs.existsSync(docxPath);
+ });
}
function stripBrokenDocxAnchors(html, missingBasenames) {
@@ -39,23 +42,39 @@ function stripBrokenDocxAnchors(html, missingBasenames) {
return { html: next, changed };
}
+function tryCopyDocxFromOa(userRoot, publicDir, basename) {
+ const destination = path.join(publicDir, basename);
+ if (fs.existsSync(destination)) return false;
+ const source = path.join(userRoot, 'oa', basename);
+ if (!fs.existsSync(source) || !fs.statSync(source).isFile()) return false;
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
+ fs.copyFileSync(source, destination);
+ return true;
+}
+
export function repairMindspacePublicDownloads({ publishDir } = {}) {
const root = path.resolve(String(publishDir ?? ''));
if (!root || !fs.existsSync(root)) {
- return { synced: [], missing: [], stripped: [] };
+ return { synced: [], stripped: [] };
}
- const syncResult = syncPublicDocxDownloads({ publishDir: root, minCompleteSize: 1024 });
+ const synced = [];
const stripped = [];
for (const userDir of fs.readdirSync(root, { withFileTypes: true })) {
if (!userDir.isDirectory()) continue;
- const publicDir = path.join(root, userDir.name, 'public');
+ const userRoot = path.join(root, userDir.name);
+ const publicDir = path.join(userRoot, 'public');
if (!fs.existsSync(publicDir)) continue;
for (const entry of fs.readdirSync(publicDir, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith('.html')) continue;
const htmlPath = path.join(publicDir, entry.name);
const html = fs.readFileSync(htmlPath, 'utf8');
+ for (const basename of listDocxHrefBasenames(html)) {
+ if (tryCopyDocxFromOa(userRoot, publicDir, basename)) {
+ synced.push(path.join(userDir.name, 'public', basename));
+ }
+ }
const missingBasenames = listMissingDocxTargets(html, publicDir);
const { html: nextHtml, changed } = stripBrokenDocxAnchors(html, missingBasenames);
if (!changed) continue;
@@ -64,11 +83,7 @@ export function repairMindspacePublicDownloads({ publishDir } = {}) {
}
}
- return {
- synced: syncResult.synced,
- missing: syncResult.missing,
- stripped,
- };
+ return { synced, stripped };
}
function main() {