fix(okr): okf-index saner title/desc + escape klammer + skip innboks/dot (SC index-integritet)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_012HzGPGJ81k1BkUC6UvgX4Y
This commit is contained in:
Kjell Tore Guttormsen 2026-06-30 14:01:19 +02:00
commit dec8a13952
2 changed files with 88 additions and 4 deletions

View file

@ -26,6 +26,13 @@ import { parseFrontmatter } from '../lib/frontmatter.mjs';
export const OKF_VERSION = 'kb-layout-2026-06';
// Drop-zone (raa innboks-filer) + skjulte kataloger (.cache osv.) er ikke nivaaer:
// de skal verken faa egen index.md eller listes som underkatalog-peker. Maa
// filtreres i BEGGE enumererings-steder (subdir-listing + rekursjon).
function isWalkableDir(name) {
return !name.startsWith('.') && name !== 'innboks';
}
// "strategisk-kontekst" -> "Strategisk kontekst"
function titleFromName(name) {
const spaced = name.replace(/[-_]+/g, ' ').trim();
@ -49,16 +56,37 @@ function parseExistingIndex(path) {
return result;
}
// Bygg en enkelt entry-linje paa OKF-form. Tom beskrivelse -> dropp ` - d`.
// Saner en frontmatter-avledet tittel/beskrivelse for trygg, idempotent emit:
// noytraliser markdown-lenker (RAG-injeksjon), strip kontrolltegn + strooe ]/)
// som ville korrumpert round-trip-parsen (parseExistingIndex), kollaps whitespace,
// og cap lengden. Idempotent: sanitizeEntry(sanitizeEntry(x)) === sanitizeEntry(x).
function sanitizeEntry(s) {
if (!s) return '';
return String(s)
.replace(/[\x00-\x1f\x7f]/g, ' ') // kontrolltegn -> mellomrom
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1') // noytraliser markdown-lenker (behold tekst)
.replace(/[\])]/g, '') // strip strooe ] ) som brekker round-trip
.replace(/\s+/g, ' ')
.trim()
.slice(0, 200);
}
// Bygg en enkelt entry-linje paa OKF-form. Tittel/beskrivelse saneres (link
// forblir uroert -- kontrollert filnavn). Tom beskrivelse -> dropp ` - d`.
function entryLine(title, link, desc) {
return desc ? `* [${title}](${link}) - ${desc}` : `* [${title}](${link})`;
const t = sanitizeEntry(title);
const d = sanitizeEntry(desc);
return d ? `* [${t}](${link}) - ${d}` : `* [${t}](${link})`;
}
// Generer og skriv index.md for EN katalog (ikke rekursivt). isRoot styrer okf_version.
function writeIndexFor(dir, isRoot, okfVersion) {
const existing = parseExistingIndex(join(dir, 'index.md'));
const dirents = readdirSync(dir, { withFileTypes: true });
const subdirs = dirents.filter((e) => e.isDirectory()).map((e) => e.name).sort();
const subdirs = dirents
.filter((e) => e.isDirectory() && isWalkableDir(e.name))
.map((e) => e.name)
.sort();
const concepts = dirents
.filter((e) => e.isFile() && e.name.endsWith('.md') && e.name !== 'index.md')
.map((e) => e.name)
@ -95,7 +123,7 @@ export function generateIndexes(root, opts = {}) {
const walk = (dir, isRoot) => {
writeIndexFor(dir, isRoot, okfVersion);
for (const e of readdirSync(dir, { withFileTypes: true })) {
if (e.isDirectory()) walk(join(dir, e.name), false);
if (e.isDirectory() && isWalkableDir(e.name)) walk(join(dir, e.name), false);
}
};
if (!existsSync(root)) throw new Error(`Bundle-rot finnes ikke: ${root}`);